feat: add DeepSeek extreme reasoning tier
This commit is contained in:
@@ -158,7 +158,7 @@ async def bootstrap() -> None:
|
||||
)
|
||||
model_response.raise_for_status()
|
||||
|
||||
print("Open WebUI bootstrap complete: auth policy, workspace tools, and six fixed Agent entries are ready.")
|
||||
print("Open WebUI bootstrap complete: auth policy, workspace tools, and eight fixed Agent entries are ready.")
|
||||
|
||||
|
||||
def run() -> None:
|
||||
|
||||
@@ -26,6 +26,8 @@ def _float(name: str, default: float) -> float:
|
||||
class Settings:
|
||||
model_api_base_url: str
|
||||
model_api_key: str
|
||||
deepseek_api_base_url: str
|
||||
deepseek_api_key: str
|
||||
openwebui_forward_jwt_secret: str
|
||||
internal_provider_key: str
|
||||
internal_gateway_key: str
|
||||
@@ -49,6 +51,8 @@ class Settings:
|
||||
return cls(
|
||||
model_api_base_url=os.getenv("MODEL_API_BASE_URL", "https://api.k1412.top").rstrip("/"),
|
||||
model_api_key=os.getenv("MODEL_API_KEY", ""),
|
||||
deepseek_api_base_url=os.getenv("DEEPSEEK_API_BASE_URL", "https://api.deepseek.com").rstrip("/"),
|
||||
deepseek_api_key=os.getenv("DEEPSEEK_API_KEY", ""),
|
||||
openwebui_forward_jwt_secret=os.getenv("OPENWEBUI_FORWARD_JWT_SECRET", ""),
|
||||
internal_provider_key=os.getenv("INTERNAL_PROVIDER_KEY", ""),
|
||||
internal_gateway_key=os.getenv("INTERNAL_GATEWAY_KEY", ""),
|
||||
@@ -73,6 +77,7 @@ class Settings:
|
||||
name
|
||||
for name, value in (
|
||||
("MODEL_API_KEY", self.model_api_key),
|
||||
("DEEPSEEK_API_KEY", self.deepseek_api_key),
|
||||
("OPENWEBUI_FORWARD_JWT_SECRET", self.openwebui_forward_jwt_secret),
|
||||
("INTERNAL_PROVIDER_KEY", self.internal_provider_key),
|
||||
("INTERNAL_GATEWAY_KEY", self.internal_gateway_key),
|
||||
|
||||
@@ -4,7 +4,8 @@ from dataclasses import dataclass
|
||||
from typing import Literal
|
||||
|
||||
Mode = Literal["chat", "work"]
|
||||
Strength = Literal["light", "medium", "high"]
|
||||
Strength = Literal["light", "medium", "high", "extreme"]
|
||||
Provider = Literal["k1412", "deepseek"]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@@ -13,15 +14,20 @@ class ModelSpec:
|
||||
display_name: str
|
||||
mode: Mode
|
||||
strength: Strength
|
||||
provider: Provider
|
||||
provider_model: str
|
||||
thinking_enabled: bool
|
||||
reasoning_effort: str | None
|
||||
max_output_tokens: int
|
||||
max_iterations: int
|
||||
context_char_budget: int
|
||||
|
||||
|
||||
_TIERS = {
|
||||
"light": ("轻度", "ChatGPT-5.6:Luna", 8, 120_000),
|
||||
"medium": ("中", "ChatGPT-5.6:Terra", 16, 240_000),
|
||||
"high": ("高", "ChatGPT-5.6:Sol", 24, 400_000),
|
||||
"light": ("轻度", "k1412", "ChatGPT-5.6:Luna", False, None, 4_096, 8, 120_000),
|
||||
"medium": ("中", "k1412", "ChatGPT-5.6:Terra", False, None, 4_096, 16, 240_000),
|
||||
"high": ("高", "k1412", "ChatGPT-5.6:Sol", False, None, 4_096, 24, 400_000),
|
||||
"extreme": ("极高", "deepseek", "deepseek-v4-pro", True, "max", 16_384, 32, 800_000),
|
||||
}
|
||||
|
||||
MODEL_SPECS: dict[str, ModelSpec] = {
|
||||
@@ -30,12 +36,25 @@ MODEL_SPECS: dict[str, ModelSpec] = {
|
||||
display_name=f"{'Chat' if mode == 'chat' else 'Work'} · {label}",
|
||||
mode=mode,
|
||||
strength=strength,
|
||||
provider_model=provider,
|
||||
provider=provider,
|
||||
provider_model=provider_model,
|
||||
thinking_enabled=thinking_enabled,
|
||||
reasoning_effort=reasoning_effort,
|
||||
max_output_tokens=max_output_tokens,
|
||||
max_iterations=max_iterations,
|
||||
context_char_budget=context_budget,
|
||||
)
|
||||
for mode in ("chat", "work")
|
||||
for strength, (label, provider, max_iterations, context_budget) in _TIERS.items()
|
||||
for strength, (
|
||||
label,
|
||||
provider,
|
||||
provider_model,
|
||||
thinking_enabled,
|
||||
reasoning_effort,
|
||||
max_output_tokens,
|
||||
max_iterations,
|
||||
context_budget,
|
||||
) in _TIERS.items()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -160,7 +160,13 @@ def create_app(
|
||||
async def forward_direct():
|
||||
payload = body.model_dump(exclude_none=True)
|
||||
payload["model"] = spec.provider_model
|
||||
response = await app.state.provider.forward(payload)
|
||||
response = await app.state.provider.forward(
|
||||
payload,
|
||||
provider=spec.provider,
|
||||
thinking_enabled=spec.thinking_enabled,
|
||||
reasoning_effort=spec.reasoning_effort,
|
||||
max_output_tokens=spec.max_output_tokens,
|
||||
)
|
||||
if body.stream:
|
||||
passthrough_headers = {
|
||||
key: value
|
||||
|
||||
@@ -599,6 +599,10 @@ class AgentLoop:
|
||||
model=spec.provider_model,
|
||||
messages=messages,
|
||||
tools=available_specs,
|
||||
provider=spec.provider,
|
||||
thinking_enabled=spec.thinking_enabled,
|
||||
reasoning_effort=spec.reasoning_effort,
|
||||
max_output_tokens=spec.max_output_tokens,
|
||||
)
|
||||
choice = response["choices"][0]
|
||||
message = choice.get("message") or {}
|
||||
@@ -648,9 +652,12 @@ class AgentLoop:
|
||||
"completion.rejected",
|
||||
{"reason": failure, "iteration": iteration + 1, "depth": depth},
|
||||
)
|
||||
assistant_checkpoint = {"role": "assistant", "content": candidate}
|
||||
if isinstance(message.get("reasoning_content"), str):
|
||||
assistant_checkpoint["reasoning_content"] = message["reasoning_content"]
|
||||
messages.extend(
|
||||
[
|
||||
{"role": "assistant", "content": candidate},
|
||||
assistant_checkpoint,
|
||||
{"role": "user", "content": recovery_message(failure)},
|
||||
]
|
||||
)
|
||||
@@ -683,6 +690,8 @@ class AgentLoop:
|
||||
"content": message.get("content"),
|
||||
"tool_calls": tool_calls,
|
||||
}
|
||||
if isinstance(message.get("reasoning_content"), str):
|
||||
assistant_message["reasoning_content"] = message["reasoning_content"]
|
||||
messages.append(assistant_message)
|
||||
blocked_call_reasons: dict[str, str] = {}
|
||||
batch_mutation_epoch = 0
|
||||
@@ -801,7 +810,15 @@ class AgentLoop:
|
||||
),
|
||||
}
|
||||
)
|
||||
response = await self.provider.complete(model=spec.provider_model, messages=messages, tools=None)
|
||||
response = await self.provider.complete(
|
||||
model=spec.provider_model,
|
||||
messages=messages,
|
||||
tools=None,
|
||||
provider=spec.provider,
|
||||
thinking_enabled=spec.thinking_enabled,
|
||||
reasoning_effort=spec.reasoning_effort,
|
||||
max_output_tokens=spec.max_output_tokens,
|
||||
)
|
||||
answer = str(response["choices"][0].get("message", {}).get("content") or "").strip()
|
||||
if completion_failure(
|
||||
artifact_required,
|
||||
|
||||
@@ -6,6 +6,7 @@ from typing import Any
|
||||
import httpx
|
||||
|
||||
from agent_platform.config import Settings
|
||||
from agent_platform.models import Provider
|
||||
|
||||
TRANSIENT_COMPLETE_STATUS_CODES = frozenset({408, 425, 429, 500, 502, 503, 504, 524})
|
||||
COMPLETE_MAX_ATTEMPTS = 2
|
||||
@@ -132,11 +133,37 @@ class ModelProvider:
|
||||
|
||||
@property
|
||||
def headers(self) -> dict[str, str]:
|
||||
return self._headers("k1412")
|
||||
|
||||
def _headers(self, provider: Provider) -> dict[str, str]:
|
||||
key = self.settings.deepseek_api_key if provider == "deepseek" else self.settings.model_api_key
|
||||
return {
|
||||
"Authorization": f"Bearer {self.settings.model_api_key}",
|
||||
"Authorization": f"Bearer {key}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
def _base_url(self, provider: Provider) -> str:
|
||||
return self.settings.deepseek_api_base_url if provider == "deepseek" else self.settings.model_api_base_url
|
||||
|
||||
@staticmethod
|
||||
def _provider_payload(
|
||||
payload: dict[str, Any],
|
||||
*,
|
||||
provider: Provider,
|
||||
thinking_enabled: bool,
|
||||
reasoning_effort: str | None,
|
||||
max_output_tokens: int,
|
||||
) -> dict[str, Any]:
|
||||
value = dict(payload)
|
||||
value.pop("thinking", None)
|
||||
value.pop("reasoning_effort", None)
|
||||
value["max_tokens"] = max_output_tokens
|
||||
if provider == "deepseek" and thinking_enabled:
|
||||
value["thinking"] = {"type": "enabled"}
|
||||
if reasoning_effort:
|
||||
value["reasoning_effort"] = reasoning_effort
|
||||
return value
|
||||
|
||||
async def close(self) -> None:
|
||||
if self._owns_client:
|
||||
await self.client.aclose()
|
||||
@@ -148,13 +175,22 @@ class ModelProvider:
|
||||
messages: list[dict[str, Any]],
|
||||
tools: list[dict[str, Any]] | None = None,
|
||||
temperature: float | None = None,
|
||||
provider: Provider = "k1412",
|
||||
thinking_enabled: bool = False,
|
||||
reasoning_effort: str | None = None,
|
||||
max_output_tokens: int = COMPLETE_MAX_TOKENS,
|
||||
) -> dict[str, Any]:
|
||||
payload: dict[str, Any] = {
|
||||
"model": model,
|
||||
"messages": messages,
|
||||
"stream": True,
|
||||
"max_tokens": COMPLETE_MAX_TOKENS,
|
||||
}
|
||||
payload = self._provider_payload(
|
||||
{
|
||||
"model": model,
|
||||
"messages": messages,
|
||||
"stream": True,
|
||||
},
|
||||
provider=provider,
|
||||
thinking_enabled=thinking_enabled,
|
||||
reasoning_effort=reasoning_effort,
|
||||
max_output_tokens=max_output_tokens,
|
||||
)
|
||||
if tools:
|
||||
payload["tools"] = tools
|
||||
payload["tool_choice"] = "auto"
|
||||
@@ -165,8 +201,8 @@ class ModelProvider:
|
||||
try:
|
||||
async with self.client.stream(
|
||||
"POST",
|
||||
completions_url(self.settings.model_api_base_url),
|
||||
headers=self.headers,
|
||||
completions_url(self._base_url(provider)),
|
||||
headers=self._headers(provider),
|
||||
json=payload,
|
||||
) as response:
|
||||
if response.status_code in TRANSIENT_COMPLETE_STATUS_CODES and attempt < COMPLETE_MAX_ATTEMPTS:
|
||||
@@ -184,11 +220,26 @@ class ModelProvider:
|
||||
|
||||
raise RuntimeError("Model provider retry loop exited unexpectedly")
|
||||
|
||||
async def forward(self, payload: dict[str, Any]) -> httpx.Response:
|
||||
async def forward(
|
||||
self,
|
||||
payload: dict[str, Any],
|
||||
*,
|
||||
provider: Provider = "k1412",
|
||||
thinking_enabled: bool = False,
|
||||
reasoning_effort: str | None = None,
|
||||
max_output_tokens: int = COMPLETE_MAX_TOKENS,
|
||||
) -> httpx.Response:
|
||||
payload = self._provider_payload(
|
||||
payload,
|
||||
provider=provider,
|
||||
thinking_enabled=thinking_enabled,
|
||||
reasoning_effort=reasoning_effort,
|
||||
max_output_tokens=max_output_tokens,
|
||||
)
|
||||
request = self.client.build_request(
|
||||
"POST",
|
||||
completions_url(self.settings.model_api_base_url),
|
||||
headers=self.headers,
|
||||
completions_url(self._base_url(provider)),
|
||||
headers=self._headers(provider),
|
||||
json=payload,
|
||||
)
|
||||
response = await self.client.send(request, stream=bool(payload.get("stream")))
|
||||
|
||||
Reference in New Issue
Block a user