fix: more work on chat and chat titles
This commit is contained in:
@@ -111,7 +111,8 @@ defmodule BDS.AI.Catalog do
|
||||
def put_model_capabilities(model_id, attrs) when is_binary(model_id) and is_map(attrs) do
|
||||
capabilities = %{
|
||||
supports_attachment: truthy?(BDS.MapUtils.attr(attrs, :supports_attachment)),
|
||||
supports_tool_calls: truthy?(BDS.MapUtils.attr(attrs, :supports_tool_calls))
|
||||
supports_tool_calls: truthy?(BDS.MapUtils.attr(attrs, :supports_tool_calls)),
|
||||
disables_reasoning: truthy?(BDS.MapUtils.attr(attrs, :disables_reasoning))
|
||||
}
|
||||
|
||||
put_setting("ai.model_capabilities.#{model_id}", Jason.encode!(capabilities))
|
||||
@@ -163,7 +164,8 @@ defmodule BDS.AI.Catalog do
|
||||
|
||||
@spec model_capabilities(String.t()) :: %{
|
||||
supports_attachment: boolean(),
|
||||
supports_tool_calls: boolean()
|
||||
supports_tool_calls: boolean(),
|
||||
disables_reasoning: boolean()
|
||||
}
|
||||
def model_capabilities(model_id) do
|
||||
overrides = decode_model_capabilities_override(model_id)
|
||||
@@ -173,7 +175,8 @@ defmodule BDS.AI.Catalog do
|
||||
{:ok, model} ->
|
||||
%{
|
||||
supports_attachment: model.supports_attachment or "image" in model.input_modalities,
|
||||
supports_tool_calls: model.supports_tool_calls
|
||||
supports_tool_calls: model.supports_tool_calls,
|
||||
disables_reasoning: false
|
||||
}
|
||||
|
||||
_other ->
|
||||
@@ -196,7 +199,8 @@ defmodule BDS.AI.Catalog do
|
||||
String.contains?(normalized, "llava"),
|
||||
supports_tool_calls:
|
||||
String.contains?(normalized, "gpt") or String.contains?(normalized, "claude") or
|
||||
String.contains?(normalized, "tool")
|
||||
String.contains?(normalized, "tool"),
|
||||
disables_reasoning: false
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ defmodule BDS.AI.Chat do
|
||||
@moduledoc false
|
||||
|
||||
import Ecto.Query
|
||||
require Logger
|
||||
|
||||
alias BDS.AI
|
||||
alias BDS.AI.Catalog
|
||||
@@ -23,7 +24,7 @@ defmodule BDS.AI.Chat do
|
||||
|
||||
@default_system_prompt "You are the bDS AI backend. Be precise, prefer structured JSON when asked, and avoid inventing blog facts."
|
||||
@default_max_output_tokens 16_384
|
||||
@title_max_output_tokens 20
|
||||
@title_max_output_tokens 256
|
||||
@chat_title_max_length 30
|
||||
@chat_max_tool_rounds 10
|
||||
@default_context_window 128_000
|
||||
@@ -383,7 +384,7 @@ defmodule BDS.AI.Chat do
|
||||
conversation = Repo.get!(ChatConversation, conversation_id)
|
||||
|
||||
cond do
|
||||
chat_user_message_count(conversation_id) != 1 ->
|
||||
chat_user_message_count(conversation_id) < 1 ->
|
||||
{:ok, reply}
|
||||
|
||||
not generated_chat_title?(conversation.title, conversation.model) ->
|
||||
@@ -418,7 +419,25 @@ defmodule BDS.AI.Chat do
|
||||
:ok <- Runtime.validate_target(:chat_title, model, mode),
|
||||
request <- build_chat_title_request(user_content, model),
|
||||
{:ok, response} <- runtime.generate(Runtime.endpoint_with_model(endpoint, model), request, opts) do
|
||||
{:ok, sanitize_chat_title(Map.get(response, :content))}
|
||||
title = sanitize_chat_title(Map.get(response, :content))
|
||||
|
||||
if title == "" do
|
||||
Logger.warning("Chat title generation returned an empty title",
|
||||
model: model,
|
||||
content: inspect(Map.get(response, :content)),
|
||||
usage: inspect(Map.get(response, :usage))
|
||||
)
|
||||
end
|
||||
|
||||
{:ok, title}
|
||||
else
|
||||
{:error, reason} = error ->
|
||||
Logger.warning("Chat title generation failed", reason: inspect(reason))
|
||||
error
|
||||
|
||||
other ->
|
||||
Logger.warning("Chat title generation failed", reason: inspect(other))
|
||||
other
|
||||
end
|
||||
end
|
||||
|
||||
@@ -431,7 +450,7 @@ defmodule BDS.AI.Chat do
|
||||
%{
|
||||
"role" => "system",
|
||||
"content" =>
|
||||
"Generate an ultra-short title (2-3 words, max 25 characters) for this conversation. Focus ONLY on the topic. Ignore any capability disclaimers. Output ONLY the title text."
|
||||
"Generate an ultra-short title (2-3 words, max 25 characters) for this conversation. Focus ONLY on the topic. Ignore any capability disclaimers. Do not include reasoning. Output ONLY the title text."
|
||||
},
|
||||
%{"role" => "user", "content" => "Topic: #{String.slice(user_content, 0, 100)}"}
|
||||
]
|
||||
|
||||
@@ -36,6 +36,7 @@ defmodule BDS.AI.OpenAICompatibleRuntime do
|
||||
"messages" => request.messages,
|
||||
"max_tokens" => request.max_output_tokens
|
||||
}
|
||||
|> maybe_disable_thinking(request.model)
|
||||
|> maybe_put_tools(Map.get(request, :tools, []))
|
||||
|
||||
with {:ok, response} <- HttpClient.post(url, headers, Jason.encode!(payload)),
|
||||
@@ -136,6 +137,18 @@ defmodule BDS.AI.OpenAICompatibleRuntime do
|
||||
|> Map.put("tool_choice", "auto")
|
||||
end
|
||||
|
||||
defp maybe_disable_thinking(payload, model) when is_binary(model) do
|
||||
if BDS.AI.Catalog.model_capabilities(model).disables_reasoning do
|
||||
Map.update(payload, "chat_template_kwargs", %{"enable_thinking" => false}, fn kwargs ->
|
||||
Map.put(kwargs || %{}, "enable_thinking", false)
|
||||
end)
|
||||
else
|
||||
payload
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_disable_thinking(payload, _model), do: payload
|
||||
|
||||
defp normalize_tool_calls(tool_calls) do
|
||||
Enum.map(tool_calls, fn tool_call ->
|
||||
%{
|
||||
|
||||
Reference in New Issue
Block a user