Rebase onto upstream (a4d95fd)
#12
@@ -235,6 +235,7 @@ def _make_provider(config: Config):
|
|||||||
api_base=config.get_api_base(model),
|
api_base=config.get_api_base(model),
|
||||||
extra_headers=p.extra_headers if p else None,
|
extra_headers=p.extra_headers if p else None,
|
||||||
provider_name=provider_name,
|
provider_name=provider_name,
|
||||||
|
thinking_budget=config.agents.defaults.thinking_budget,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ class AgentDefaults(Base):
|
|||||||
temperature: float = 0.1
|
temperature: float = 0.1
|
||||||
max_tool_iterations: int = 40
|
max_tool_iterations: int = 40
|
||||||
memory_window: int = 100
|
memory_window: int = 100
|
||||||
|
thinking_budget: int = 0 # 0 = disabled; >0 = token budget for extended thinking
|
||||||
|
|
||||||
|
|
||||||
class AgentsConfig(Base):
|
class AgentsConfig(Base):
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ def create_provider(
|
|||||||
api_base: str | None = None,
|
api_base: str | None = None,
|
||||||
extra_headers: dict[str, str] | None = None,
|
extra_headers: dict[str, str] | None = None,
|
||||||
provider_name: str | None = None,
|
provider_name: str | None = None,
|
||||||
|
thinking_budget: int = 0,
|
||||||
) -> LLMProvider:
|
) -> LLMProvider:
|
||||||
"""Factory function to create appropriate provider.
|
"""Factory function to create appropriate provider.
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ def create_provider(
|
|||||||
oauth_token=api_key,
|
oauth_token=api_key,
|
||||||
default_model=model,
|
default_model=model,
|
||||||
api_base=api_base,
|
api_base=api_base,
|
||||||
|
thinking_budget=thinking_budget,
|
||||||
)
|
)
|
||||||
|
|
||||||
return LiteLLMProvider(
|
return LiteLLMProvider(
|
||||||
|
|||||||
@@ -28,10 +28,12 @@ class AnthropicOAuthProvider(LLMProvider):
|
|||||||
oauth_token: str,
|
oauth_token: str,
|
||||||
default_model: str = "claude-opus-4-5",
|
default_model: str = "claude-opus-4-5",
|
||||||
api_base: str | None = None,
|
api_base: str | None = None,
|
||||||
|
thinking_budget: int = 0,
|
||||||
):
|
):
|
||||||
super().__init__(api_key=None, api_base=api_base)
|
super().__init__(api_key=None, api_base=api_base)
|
||||||
self.oauth_token = oauth_token
|
self.oauth_token = oauth_token
|
||||||
self.default_model = default_model
|
self.default_model = default_model
|
||||||
|
self.thinking_budget = thinking_budget
|
||||||
self._client: httpx.AsyncClient | None = None
|
self._client: httpx.AsyncClient | None = None
|
||||||
|
|
||||||
def _get_headers(self) -> dict[str, str]:
|
def _get_headers(self) -> dict[str, str]:
|
||||||
@@ -93,6 +95,12 @@ class AnthropicOAuthProvider(LLMProvider):
|
|||||||
if role == "assistant" and msg.get("tool_calls"):
|
if role == "assistant" and msg.get("tool_calls"):
|
||||||
# Convert OpenAI tool_calls to Anthropic content blocks
|
# Convert OpenAI tool_calls to Anthropic content blocks
|
||||||
content_blocks: list[dict[str, Any]] = []
|
content_blocks: list[dict[str, Any]] = []
|
||||||
|
# Preserve thinking block if present
|
||||||
|
if msg.get("reasoning_content"):
|
||||||
|
content_blocks.append({
|
||||||
|
"type": "thinking",
|
||||||
|
"thinking": msg["reasoning_content"],
|
||||||
|
})
|
||||||
text = msg.get("content")
|
text = msg.get("content")
|
||||||
if text:
|
if text:
|
||||||
content_blocks.append({"type": "text", "text": text})
|
content_blocks.append({"type": "text", "text": text})
|
||||||
@@ -113,6 +121,17 @@ class AnthropicOAuthProvider(LLMProvider):
|
|||||||
converted.append({"role": "assistant", "content": content_blocks})
|
converted.append({"role": "assistant", "content": content_blocks})
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if role == "assistant" and msg.get("reasoning_content"):
|
||||||
|
# Plain assistant message with thinking (no tool calls)
|
||||||
|
content_blocks = [
|
||||||
|
{"type": "thinking", "thinking": msg["reasoning_content"]},
|
||||||
|
]
|
||||||
|
text = msg.get("content")
|
||||||
|
if text:
|
||||||
|
content_blocks.append({"type": "text", "text": text})
|
||||||
|
converted.append({"role": "assistant", "content": content_blocks})
|
||||||
|
continue
|
||||||
|
|
||||||
if role == "tool":
|
if role == "tool":
|
||||||
# Convert tool result to Anthropic user message with tool_result block
|
# Convert tool result to Anthropic user message with tool_result block
|
||||||
tool_result_block = {
|
tool_result_block = {
|
||||||
@@ -186,9 +205,21 @@ class AnthropicOAuthProvider(LLMProvider):
|
|||||||
"model": model,
|
"model": model,
|
||||||
"messages": messages,
|
"messages": messages,
|
||||||
"max_tokens": max_tokens,
|
"max_tokens": max_tokens,
|
||||||
"temperature": temperature,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Extended thinking: temperature must be 1 when enabled
|
||||||
|
if self.thinking_budget > 0:
|
||||||
|
payload["temperature"] = 1
|
||||||
|
# max_tokens must exceed budget_tokens
|
||||||
|
if max_tokens <= self.thinking_budget:
|
||||||
|
payload["max_tokens"] = self.thinking_budget + 4096
|
||||||
|
payload["thinking"] = {
|
||||||
|
"type": "enabled",
|
||||||
|
"budget_tokens": self.thinking_budget,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
payload["temperature"] = temperature
|
||||||
|
|
||||||
if system:
|
if system:
|
||||||
payload["system"] = system
|
payload["system"] = system
|
||||||
|
|
||||||
@@ -249,10 +280,13 @@ class AnthropicOAuthProvider(LLMProvider):
|
|||||||
content_blocks = response.get("content", [])
|
content_blocks = response.get("content", [])
|
||||||
|
|
||||||
text_content = ""
|
text_content = ""
|
||||||
|
thinking_content = ""
|
||||||
tool_calls = []
|
tool_calls = []
|
||||||
|
|
||||||
for block in content_blocks:
|
for block in content_blocks:
|
||||||
if block.get("type") == "text":
|
if block.get("type") == "thinking":
|
||||||
|
thinking_content += block.get("thinking", "")
|
||||||
|
elif block.get("type") == "text":
|
||||||
text_content += block.get("text", "")
|
text_content += block.get("text", "")
|
||||||
elif block.get("type") == "tool_use":
|
elif block.get("type") == "tool_use":
|
||||||
tool_calls.append(ToolCallRequest(
|
tool_calls.append(ToolCallRequest(
|
||||||
@@ -277,6 +311,7 @@ class AnthropicOAuthProvider(LLMProvider):
|
|||||||
tool_calls=tool_calls,
|
tool_calls=tool_calls,
|
||||||
finish_reason=response.get("stop_reason", "end_turn"),
|
finish_reason=response.get("stop_reason", "end_turn"),
|
||||||
usage=usage,
|
usage=usage,
|
||||||
|
reasoning_content=thinking_content or None,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_default_model(self) -> str:
|
def get_default_model(self) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user