diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index e19a547..8a1b61e 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -854,6 +854,7 @@ Ein **Agent** definiert die Persönlichkeit und Fähigkeiten der AI:
| `WebSearchVersion`| Web-Suche aktivieren (z.B. `web_search_20260209`) |
| `AllowUserChoice` | `ask_user_choice`-Tool verfügbar (Default: true) |
| `TaskInstruction` | Aufgabe/Anweisung – optionaler Text, wird als `## Anweisungen`-Block in System-Prompt eingefügt |
+| `Effort` | Reasoning-Effort-Level für Claude. `""` (=high, Default), `low`, `medium`, `high`, `xhigh` (nur Opus 4.7+), `max` (nur Opus 4.6+/Sonnet 4.6). API: als `output_config.effort` gesendet. CLI: via Env-Var `CLAUDE_CODE_EFFORT_LEVEL`. Bei OpenAI-Providern ignoriert. |
| `IsPublic` | Andere User können den Agent in ihren Sessions verwenden (aber nicht bearbeiten) |
### Model-Auflösung
diff --git a/ARCHITECTURE_QUICK.md b/ARCHITECTURE_QUICK.md
index 8cf5c0e..1ad0b82 100644
--- a/ARCHITECTURE_QUICK.md
+++ b/ARCHITECTURE_QUICK.md
@@ -87,7 +87,7 @@ User 1──* TelegramBot 1──* Session (via telegram_bot_id)
|---------|-------|
| `users` | Login, DisplayName, IsAdmin, Persona, Settings (JSON), DefaultPath |
| `tokens` | Auth-Tokens → User |
-| `agents` | AI-Agenten (Model – z.B. `claude-sonnet-4-6` oder `nvidia:model-id`, CustomCommands, AutoCommit, UseSoul/Identity/UserInfo/Memory/AutoContext, UseGitHubSearch, UseSerperSearch, WebSearch, AllowUserChoice, TaskInstruction, AvatarScale/Offset, AvatarSmall, IsPublic) |
+| `agents` | AI-Agenten (Model – z.B. `claude-sonnet-4-6` oder `nvidia:model-id`, CustomCommands, AutoCommit, UseSoul/Identity/UserInfo/Memory/AutoContext, UseGitHubSearch, UseSerperSearch, WebSearch, AllowUserChoice, TaskInstruction, Effort, AvatarScale/Offset, AvatarSmall, IsPublic) |
| `sessions` | Chat-Sessions (Description, Image, ImageSmall, Workspace, Context, CustomCommands, TelegramBotId, TelegramChatId, AvatarScale/Offset, PreparerAgentId, ReviewAgentId, MaxReviewIterations, FinalizerAgentId) |
| `chains` | Ein Request-Response-Zyklus (Tokens, Timing, Iterations, PlanMode, ToolChoice, ToolNames, StreamErrorInfo, ArchiveId) |
| `messages` | Einzelne Nachrichten (text / tool_use / tool_result / error / web_search_result / auto_context), Tag für Sub-Agent-Markierung oder Import-Herkunft (`openclaw-import`), thought_signature (Gemini) |
diff --git a/Endpoints/AgentEndpoint.cs b/Endpoints/AgentEndpoint.cs
index f2ffda3..f028653 100644
--- a/Endpoints/AgentEndpoint.cs
+++ b/Endpoints/AgentEndpoint.cs
@@ -71,6 +71,7 @@ public static class AgentEndpoint
a.WebSearchVersion,
a.AllowUserChoice,
a.TaskInstruction,
+ a.Effort,
a.AvatarScale,
a.AvatarOffsetX,
a.AvatarOffsetY,
@@ -137,6 +138,7 @@ public static class AgentEndpoint
WebSearchVersion = body.TryGetProperty("webSearchVersion", out var wsv2) ? wsv2.GetString() ?? "" : "",
AllowUserChoice = !body.TryGetProperty("allowUserChoice", out var auc) || auc.GetBoolean(),
TaskInstruction = body.TryGetProperty("taskInstruction", out var ti) ? ti.GetString() : null,
+ Effort = body.TryGetProperty("effort", out var ef) ? ef.GetString() ?? "" : "",
AvatarScale = body.TryGetProperty("avatarScale", out var asc) ? asc.GetDouble() : 1.0,
AvatarOffsetX = body.TryGetProperty("avatarOffsetX", out var aox) ? aox.GetDouble() : 0,
AvatarOffsetY = body.TryGetProperty("avatarOffsetY", out var aoy) ? aoy.GetDouble() : 0,
@@ -184,6 +186,7 @@ public static class AgentEndpoint
}
if (body.TryGetProperty("allowUserChoice", out var auc)) agent.AllowUserChoice = auc.GetBoolean();
if (body.TryGetProperty("taskInstruction", out var ti)) agent.TaskInstruction = ti.GetString();
+ if (body.TryGetProperty("effort", out var ef)) agent.Effort = ef.GetString() ?? "";
if (body.TryGetProperty("avatarScale", out var asc)) agent.AvatarScale = asc.GetDouble();
if (body.TryGetProperty("avatarOffsetX", out var aox)) agent.AvatarOffsetX = aox.GetDouble();
if (body.TryGetProperty("avatarOffsetY", out var aoy)) agent.AvatarOffsetY = aoy.GetDouble();
diff --git a/Endpoints/ChatEndpoint.cs b/Endpoints/ChatEndpoint.cs
index 9aea217..7fd8f1f 100644
--- a/Endpoints/ChatEndpoint.cs
+++ b/Endpoints/ChatEndpoint.cs
@@ -261,7 +261,7 @@ public static class ChatEndpoint
if (anthropic.IsCliAvailable)
{
- await anthropic.StreamChatViaCli(res, ctx.ModelId, ctx.SystemPrompt, messages, ctx.ChainId, workspace: ctx.Workspace, allowUserChoice: ctx.Agent?.AllowUserChoice ?? true, planMode: body.PlanMode, webSearch: !string.IsNullOrEmpty(ctx.WebSearchVersion), sessionId: sessionId, agentId: ctx.AgentId, remoteMgr: remoteMgr, unityMcpUrl: ctx.Session?.UnityMcpUrl, unityMcpToken: ctx.Session?.UnityMcpToken, useAutoContext: ctx.Agent?.UseAutoContext ?? true, workCt: workCt, sseCt: sseCt);
+ await anthropic.StreamChatViaCli(res, ctx.ModelId, ctx.SystemPrompt, messages, ctx.ChainId, workspace: ctx.Workspace, allowUserChoice: ctx.Agent?.AllowUserChoice ?? true, planMode: body.PlanMode, webSearch: !string.IsNullOrEmpty(ctx.WebSearchVersion), sessionId: sessionId, agentId: ctx.AgentId, remoteMgr: remoteMgr, unityMcpUrl: ctx.Session?.UnityMcpUrl, unityMcpToken: ctx.Session?.UnityMcpToken, useAutoContext: ctx.Agent?.UseAutoContext ?? true, effort: ctx.Effort, workCt: workCt, sseCt: sseCt);
}
else
{
@@ -271,7 +271,7 @@ public static class ChatEndpoint
return;
}
- await anthropic.StreamChat(res, ctx.ModelId, ctx.SystemPrompt, messages, ctx.ChainId, ctx.Workspace, apiToken: anthropicToken, sessionId: sessionId, agentId: ctx.AgentId, userId: userId, useMemory: ctx.UseMemory, webSearchVersion: ctx.WebSearchVersion, maxIterations: ctx.MaxIterations, toolChoice: effectiveToolChoice, review: ctx.Review, finalizer: ctx.Finalizer, allowUserChoice: ctx.Agent?.AllowUserChoice ?? true, planMode: ctx.PlanMode, useAutoContext: ctx.Agent?.UseAutoContext ?? true, useGitHubSearch: ctx.Agent?.UseGitHubSearch ?? false, useSerperSearch: ctx.Agent?.UseSerperSearch ?? false, workCt: workCt, hardCt: hardCt, sseCt: sseCt, remoteMgr: remoteMgr);
+ await anthropic.StreamChat(res, ctx.ModelId, ctx.SystemPrompt, messages, ctx.ChainId, ctx.Workspace, apiToken: anthropicToken, sessionId: sessionId, agentId: ctx.AgentId, userId: userId, useMemory: ctx.UseMemory, webSearchVersion: ctx.WebSearchVersion, maxIterations: ctx.MaxIterations, toolChoice: effectiveToolChoice, review: ctx.Review, finalizer: ctx.Finalizer, allowUserChoice: ctx.Agent?.AllowUserChoice ?? true, planMode: ctx.PlanMode, useAutoContext: ctx.Agent?.UseAutoContext ?? true, useGitHubSearch: ctx.Agent?.UseGitHubSearch ?? false, useSerperSearch: ctx.Agent?.UseSerperSearch ?? false, effort: ctx.Effort, workCt: workCt, hardCt: hardCt, sseCt: sseCt, remoteMgr: remoteMgr);
}
}
finally
diff --git a/Models/AgentRecord.cs b/Models/AgentRecord.cs
index 9fe1c7a..36d3eb0 100644
--- a/Models/AgentRecord.cs
+++ b/Models/AgentRecord.cs
@@ -23,6 +23,13 @@ public class AgentRecord
public string WebSearchVersion { get; set; } = "";
public bool AllowUserChoice { get; set; } = true;
public string TaskInstruction { get; set; }
+ ///
+ /// Reasoning-Effort-Level für Claude (Opus 4.5+, Sonnet 4.6+).
+ /// Werte: "" (= high, weglassen), "low", "medium", "high", "xhigh" (Opus 4.7+), "max" (Opus 4.6+, Sonnet 4.6).
+ /// API-Pfad: wird als output_config.effort gesendet. CLI-Pfad: wird via CLAUDE_CODE_EFFORT_LEVEL gesetzt.
+ /// Bei OpenAI-Providern (MiniMax/Nvidia/etc.) wird das Feld stillschweigend ignoriert.
+ ///
+ public string Effort { get; set; } = "";
public double AvatarScale { get; set; } = 1.0;
public double AvatarOffsetX { get; set; }
public double AvatarOffsetY { get; set; }
diff --git a/Models/ChatContext.cs b/Models/ChatContext.cs
index cda5d43..dd268b1 100644
--- a/Models/ChatContext.cs
+++ b/Models/ChatContext.cs
@@ -17,6 +17,7 @@ public class ChatContext
public string ToolChoice { get; set; }
public bool UseMemory { get; set; }
public string WebSearchVersion { get; set; }
+ public string Effort { get; set; }
public int MaxIterations { get; set; }
public AgentRecord Agent { get; set; }
public SessionRecord Session { get; set; }
@@ -43,6 +44,7 @@ public class SubAgentContext
public bool UseMemory { get; set; }
public string WebSearchVersion { get; set; }
public string ToolChoice { get; set; }
+ public string Effort { get; set; }
public AgentRecord Agent { get; set; }
// Preparer-spezifisch
diff --git a/Services/AnthropicService.Agents.cs b/Services/AnthropicService.Agents.cs
index 48678d1..2bbdd19 100644
--- a/Services/AnthropicService.Agents.cs
+++ b/Services/AnthropicService.Agents.cs
@@ -77,7 +77,7 @@ public partial class AnthropicService
preparer.Workspace, preparer.UseMemory, preparer.WebSearchVersion,
preparer.ToolChoice, preparerMessages, chainId, sessionId, apiToken, usage,
0, "preparer", preparer.Agent?.Name ?? "Vorbereiter-Agent",
- cancellationToken, cancellationToken);
+ cancellationToken, cancellationToken, preparer.Effort);
}
var result = new PreparerResult { IterationCount = iterations, ResponseText = text };
@@ -185,7 +185,7 @@ public partial class AnthropicService
review.Workspace, review.UseMemory, review.WebSearchVersion,
review.ToolChoice, reviewMessages, chainId, sessionId, apiToken, usage,
baseIterations, "review", review.Agent?.Name ?? "Review-Agent",
- workCt, sseCt);
+ workCt, sseCt, review.Effort);
}
var result = new ReviewResult { ReviewIterationCount = iterations };
@@ -256,7 +256,7 @@ public partial class AnthropicService
finalizer.Workspace, finalizer.UseMemory, finalizer.WebSearchVersion,
finalizer.ToolChoice, finalizerMessages, chainId, sessionId, apiToken, usage,
baseIterations, "finalizer", finalizer.Agent?.Name ?? "Finalizer-Agent",
- workCt, sseCt);
+ workCt, sseCt, finalizer.Effort);
}
await SseHelper.TryWriteSse(response, "finalizer_done", new
@@ -446,7 +446,8 @@ public partial class AnthropicService
int baseIteration,
int maxIterations,
CancellationToken ct,
- NonStreamingLoopCallbacks cb = null)
+ NonStreamingLoopCallbacks cb = null,
+ string effort = null)
{
cb ??= new NonStreamingLoopCallbacks();
int iterations = 0;
@@ -465,6 +466,10 @@ public partial class AnthropicService
["messages"] = messages
};
+ // Reasoning-Effort (Opus 4.5+, Sonnet 4.6+). "" / "high" / null = Default weglassen.
+ if (!string.IsNullOrEmpty(effort) && effort != "high")
+ payload["output_config"] = new { effort };
+
if (systemPrompt is List