diff --git a/crates/llm-worker/src/llm_client/scheme/openai_responses/request.rs b/crates/llm-worker/src/llm_client/scheme/openai_responses/request.rs index 27ad62b7..8752add1 100644 --- a/crates/llm-worker/src/llm_client/scheme/openai_responses/request.rs +++ b/crates/llm-worker/src/llm_client/scheme/openai_responses/request.rs @@ -62,9 +62,6 @@ pub(crate) struct ResponsesRequest { pub(crate) struct ReasoningConfig { #[serde(skip_serializing_if = "Option::is_none")] pub effort: Option, - /// API 側の reasoning retention policy。Insomnia はこの値を送るが、 - /// persisted reasoning item の client-side filtering はしない。 - pub context: &'static str, /// summary の出力制御。`"auto"` 固定で summary_text を受け取る。 pub summary: &'static str, } @@ -196,7 +193,6 @@ impl OpenAIResponsesScheme { ReasoningControl::Effort(effort) => Some(effort.as_str().to_string()), ReasoningControl::BudgetTokens(_) => None, }, - context: "current_turn", summary: "auto", }) .filter(|reasoning| reasoning.effort.is_some()); @@ -507,7 +503,7 @@ mod tests { } #[test] - fn current_turn_reasoning_is_kept_across_function_call_loop() { + fn reasoning_is_kept_across_function_call_loop() { let scheme = OpenAIResponsesScheme::new(); let req = Request::new() .user("run tool") @@ -523,18 +519,6 @@ mod tests { )); } - #[test] - fn reasoning_request_uses_current_turn_context() { - let scheme = OpenAIResponsesScheme::new(); - let mut req = Request::new().user("hi"); - req.config.reasoning = Some(ReasoningControl::Effort(ReasoningEffort::Medium)); - let body = scheme.build_request("gpt-5", &req, &cap_with_reasoning()); - let reasoning = body.reasoning.expect("reasoning should be set"); - assert_eq!(reasoning.context, "current_turn"); - let json = serde_json::to_value(reasoning).unwrap(); - assert_eq!(json["context"], "current_turn"); - } - #[test] fn reasoning_summary_field_is_always_serialized() { // Responses API は reasoning item に `summary` を必須で要求する。 @@ -566,8 +550,12 @@ mod tests { let body = scheme.build_request("gpt-5", &req, &cap_with_reasoning()); let reasoning = body.reasoning.expect("reasoning should be set"); assert_eq!(reasoning.effort.as_deref(), Some("high")); - assert_eq!(reasoning.context, "current_turn"); assert_eq!(reasoning.summary, "auto"); + let json = serde_json::to_value(reasoning).unwrap(); + assert!( + json.get("context").is_none(), + "reasoning.context must not be serialized, got: {json}" + ); } #[test] diff --git a/crates/llm-worker/src/llm_client/transport.rs b/crates/llm-worker/src/llm_client/transport.rs index 26d4f9f3..ae0b7cc2 100644 --- a/crates/llm-worker/src/llm_client/transport.rs +++ b/crates/llm-worker/src/llm_client/transport.rs @@ -289,11 +289,6 @@ fn request_body_shape_payload(body: &Value) -> Value { json!(reasoning_encrypted_content_bytes), ); } - let reasoning_context = body - .get("reasoning") - .and_then(|reasoning| reasoning.get("context")) - .and_then(Value::as_str); - map.insert("reasoning_context".to_string(), json!(reasoning_context)); Value::Object(map) } @@ -683,7 +678,7 @@ mod tests { #[test] fn request_body_shape_counts_reasoning_encrypted_content() { let payload = request_body_shape_payload(&json!({ - "reasoning": { "context": "current_turn" }, + "reasoning": { "summary": "auto" }, "input": [ { "type": "message", "role": "user", "content": [] }, { "type": "reasoning", "encrypted_content": "abc", "summary": [] }, @@ -694,7 +689,6 @@ mod tests { assert_eq!(payload["reasoning_items"], 2); assert_eq!(payload["reasoning_encrypted_content_count"], 2); assert_eq!(payload["reasoning_encrypted_content_bytes"], 8); - assert_eq!(payload["reasoning_context"], "current_turn"); assert!(payload["items_json_bytes"].as_u64().unwrap() > 0); } diff --git a/docs/ref/model-reasoning-context.md b/docs/ref/model-reasoning-context.md index ca9ec64d..076f1739 100644 --- a/docs/ref/model-reasoning-context.md +++ b/docs/ref/model-reasoning-context.md @@ -85,7 +85,7 @@ reasoning トークンは各ターンの後に破棄される。次ターンに 1. `previous_response_id` パラメータで過去のレスポンスを参照 2. `response.output` の全アイテムを次の `input` に手動で渡す -ステートレス利用(`store=false`、ZDR組織)の場合は `include=["reasoning.encrypted_content"]` を指定すれば暗号化された推論コンテンツを受け取り、次リクエストに渡すことで推論を引き継げる。Insomnia は Responses リクエストに `reasoning.context="current_turn"` を明示するが、このパラメータの正確な履歴境界 semantics は provider 側の責務として扱い、履歴から復元した reasoning item を client 側でターン境界に基づいて削除しない。 +ステートレス利用(`store=false`、ZDR組織)の場合は `include=["reasoning.encrypted_content"]` を指定すれば暗号化された推論コンテンツを受け取り、次リクエストに渡すことで推論を引き継げる。Insomnia は履歴から復元した reasoning item を通常の API message として扱い、独自の turn-boundary filtering はしない。 同一ターン内の function-call loop でも、`reasoning item → function_call → function_call_output → 次の Responses request` の連続性を保つため、履歴上の reasoning item は通常の API message として保持する。ToolResult は wire 上で user 側 item に見えるが、reasoning item の削除境界としては扱わない。 @@ -187,7 +187,7 @@ Ollamaはローカル実行プラットフォームで、モデルごとに思 **ChatGPT を使うとき** - 新規実装は **Responses API** を選ぶ(Chat Completions は推論引き継ぎが弱い) -- ZDR組織でも `reasoning.encrypted_content` で推論を引き継げる。Insomnia は `reasoning.context="current_turn"` を送るが、履歴上の reasoning item は通常の API message として扱い、独自の turn-boundary filtering はしない +- ZDR組織でも `reasoning.encrypted_content` で推論を引き継げる。履歴上の reasoning item は通常の API message として扱い、独自の turn-boundary filtering はしない - raw reasoning の抽出を試みない(規約違反の可能性) **Ollama を使うとき**