diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index dacc61e..e209b3e 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -481,7 +481,6 @@ class LlmRequest(BaseModel): input: str | list[Block] # 易变内容(断点之后) stream: bool = False output_schema: type[BaseModel] | None = None # 需结构化输出时(Pydantic 模型/instructor) - thinking: bool = False # 是否启用思考/推理(有则启用) max_tokens: int | None = None scope: "Scope" # {project_id; user_id 原型可固定} diff --git a/memory/contracts.md b/memory/contracts.md index d4372b3..ec5f521 100644 --- a/memory/contracts.md +++ b/memory/contracts.md @@ -10,7 +10,7 @@ - 消费方:编排器、所有 Agent(经 `Gateway.run` / `Gateway.stream`)。 - 关键不变量:agent 只传 `tier`(writer/analyst/light),不传具体 model。 - **已实现(`packages/llm_gateway/ww_llm_gateway`)**: - - 类型 `types.py`:`Block(text,cache=False)`、`Scope(user_id,project_id?)`、`LlmRequest(tier,input:str|list[Block],system:list[Block],stream,output_schema?,thinking,max_tokens?,scope)`、`Usage(provider,model,input_tokens,output_tokens,cache_read_tokens,cost_minor,currency)`、`ServedBy(provider,model,fell_back)`、`LlmResponse(text,parsed?,usage,served_by)`、`Delta(text)`、`Tier`。 + - 类型 `types.py`:`Block(text,cache=False)`、`Scope(user_id,project_id?)`、`LlmRequest(tier,input:str|list[Block],system:list[Block],stream,output_schema?,max_tokens?,scope)`、`Usage(provider,model,input_tokens,output_tokens,cache_read_tokens,cost_minor,currency)`、`ServedBy(provider,model,fell_back)`、`LlmResponse(text,parsed?,usage,served_by)`、`Delta(text)`、`Tier`。 - `Gateway(adapters:dict[str,ProviderAdapter], ledger:LedgerSink, resolver=resolve_route)`:`async run(req)->LlmResponse`、`stream(req)->AsyncIterator[Delta]`。每次调用落 **1 条** `usage_ledger`(经 `LedgerSink`,可注入内存替身)。 - 适配器 `ProviderAdapter`(Protocol):`provider`、`capabilities()->Capabilities`、`async complete(req,model)->ProviderResult`、`stream(req,model)->AsyncIterator[StreamChunk]`。M1 实现 `OpenAICompatAdapter(provider, client:AsyncOpenAI)`(DeepSeek,注入 client 便于测试)。 - 档位路由 `resolve_route(tier)->Route(provider,model)` 读 `config.tier_defaults`(M1 仅全局默认;回退/熔断属 M5/T5.4,**未实现**)。 diff --git a/packages/llm_gateway/tests/test_types.py b/packages/llm_gateway/tests/test_types.py new file mode 100644 index 0000000..266e240 --- /dev/null +++ b/packages/llm_gateway/tests/test_types.py @@ -0,0 +1,22 @@ +"""C1 类型契约不变量(`LlmRequest` 字段集)单测。""" + +from __future__ import annotations + +from ww_llm_gateway.adapters.base import Capabilities +from ww_llm_gateway.types import LlmRequest + + +def test_llm_request_has_no_thinking_field() -> None: + # CR-H5:删除从未被任何适配器/网关读取的死字段 `LlmRequest.thinking`(YAGNI)。 + assert "thinking" not in LlmRequest.model_fields + assert set(LlmRequest.model_fields) == { + "tier", + "input", + "system", + "stream", + "output_schema", + "max_tokens", + "scope", + } + # 同名但另一处 live 字段 `Capabilities.thinking`(适配器能力矩阵)不受影响。 + assert "thinking" in Capabilities.model_fields diff --git a/packages/llm_gateway/ww_llm_gateway/types.py b/packages/llm_gateway/ww_llm_gateway/types.py index 25d8df5..c498782 100644 --- a/packages/llm_gateway/ww_llm_gateway/types.py +++ b/packages/llm_gateway/ww_llm_gateway/types.py @@ -38,7 +38,6 @@ class LlmRequest(BaseModel): system: list[Block] = Field(default_factory=list) stream: bool = False output_schema: type[BaseModel] | None = None - thinking: bool = False max_tokens: int | None = None scope: Scope