feat(thinking): add per-agent extended thinking with Anthropic, OpenAI, and DashScope support

Implement full thinking mode system: per-agent thinking_level config (off/low/medium/high)
stored in other_config JSONB, per-provider param injection (Anthropic budget_tokens, OpenAI
reasoning_effort, DashScope enable_thinking+thinking_budget), Anthropic extended thinking with
streaming parse and tool use block preservation via RawAssistantContent, thinking token tracking
in trace spans, and Web UI with agent config selector, chat thinking block rendering, and trace
thinking token display. No DB migration needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
viettranxandClaude Opus 4.6 committed 2026-02-28 15:45:34 +07:00
1 parent d913f29c69
commit 552ddc059e
18 files changed
+455 -33

No files matched your search

+17 -5
View File
@@ -100,6 +100,9 @@ type Loop struct {
// Global builtin tool settings (from builtin_tools table, managed mode)
builtinToolSettings tools.BuiltinToolSettings
// Thinking level for extended thinking support
thinkingLevel string
}
// AgentEvent is emitted during agent execution for WS broadcasting.
@@ -162,6 +165,9 @@ type LoopConfig struct {
// Global builtin tool settings (from builtin_tools table, managed mode)
BuiltinToolSettings tools.BuiltinToolSettings
// Thinking level: "off", "low", "medium", "high" (from agent other_config)
ThinkingLevel string
}
func NewLoop(cfg LoopConfig) *Loop {
@@ -220,6 +226,7 @@ func NewLoop(cfg LoopConfig) *Loop {
injectionAction: action,
maxMessageChars: cfg.MaxMessageChars,
builtinToolSettings: cfg.BuiltinToolSettings,
thinkingLevel: cfg.ThinkingLevel,
}
}
@@ -540,10 +547,13 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
Tools: toolDefs,
Model: l.model,
Options: map[string]interface{}{
"max_tokens": 8192,
"temperature": 0.7,
providers.OptMaxTokens: 8192,
providers.OptTemperature: 0.7,
},
}
if l.thinkingLevel != "" && l.thinkingLevel != "off" {
chatReq.Options[providers.OptThinkingLevel] = l.thinkingLevel
}
// Call LLM (streaming or non-streaming)
var resp *providers.ChatResponse
@@ -585,6 +595,7 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
totalUsage.PromptTokens += resp.Usage.PromptTokens
totalUsage.CompletionTokens += resp.Usage.CompletionTokens
totalUsage.TotalTokens += resp.Usage.TotalTokens
totalUsage.ThinkingTokens += resp.Usage.ThinkingTokens
}
// No tool calls → done
@@ -595,9 +606,10 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
// Build assistant message with tool calls
assistantMsg := providers.Message{
Role: "assistant",
Content: resp.Content,
ToolCalls: resp.ToolCalls,
Role: "assistant",
Content: resp.Content,
ToolCalls: resp.ToolCalls,
RawAssistantContent: resp.RawAssistantContent, // preserve thinking blocks for Anthropic passback
}
messages = append(messages, assistantMsg)
pendingMsgs = append(pendingMsgs, assistantMsg)