6.5 KiB
OpenAI Responses scheme の新設 — レビュー
前提・要件の再確認
チケット本体の 9 要件 + 2 設計課題を前提に、実装が意図と整合しているかを確認した。cargo check(warning 1 / 旧由来)・cargo test --workspace(全 pass)通過。変更量: 新規 5 ファイル(1407 行)+ 既存 5 ファイル微修正。
要件達成度
| # | 要件 | 状況 | メモ |
|---|---|---|---|
| 1 | scheme/openai_responses 新設、HttpTransport<S> に差し込める |
✓ | Scheme trait 実装完了 |
| 2 | Request body: tool_choice: "auto" / parallel_tool_calls: true / store: false / include / stream: true 固定、reasoning 投影 |
✓ | ResponsesRequest 構造体に全項目、build_request で capability 照合して reasoning 投影 |
| 3 | SSE event パース (response.* 一式) | ✓ + α | ticket 列挙に加えて response.content_part.done / response.reasoning_summary_part.added/done / top-level error もカバー |
| 4 | BlockType / DeltaContent 対応(text は content_part.added、tool_use は output_item.added で BlockStart) |
✓ | OpenAIResponsesState の 3 種 SlotKey(OutputItem / ContentPart / Summary)で (output_index, content_index) → flat index を管理 |
| 5 | Item::Reasoning 拡張(text + summary + encrypted_content) |
✓ | with_reasoning_summary / with_encrypted_content ビルダー追加、既存コンストラクタは空値で互換 |
| 6 | AuthRef::ApiKey / Authorization: Bearer / base_url https://api.openai.com / パス /v1/responses |
✓ | scheme_impl.rs の required_auth / default_base_url / path |
| 7 | Usage 正規化 | ✓ | response.completed の usage を UsageEvent に変換、total_tokens 未提供時は input+output で補完 |
| 8 | capability 共通判定関数 | ✓ | openai_chat/capability.rs::classify -> OpenAiFamily を pub(crate) で公開、openai_responses/capability.rs::lookup が共有 |
| 9 | 完了時動作 | ✓ | provider/lib.rs::build_client の OpenaiResponses アームが SchemeNotImplemented から実装に差し替え済み |
設計決定への反映
| 決定 | 反映 |
|---|---|
store / include[] を OpenAIResponsesScheme フィールドで override 可能、ModelCapability には入れない |
✓ with_store / with_include_encrypted_content ビルダー、デフォルトは stateless + ZDR 相当 |
ReasoningSupport::Effort / Both 対応時のみ reasoning 送信 |
✓ build_request で capability と request.config.reasoning.effort の両方が揃う時のみ投影 |
Responses 未使用パラメータ (service_tier / prompt_cache_key / text.verbosity) は予約のみ |
✓ ResponsesRequest 構造体には入れず、必要時に追加できる構造 |
アーキテクチャ評価
良い点
ensure_and_deltaによる防御的設計:content_part.addedが欠落しても delta 単独で BlockStart + Delta を発行できる。delta_without_prior_start_recoversテストで確認済OpenAIResponsesStateの 3 種 SlotKey:OutputItem(tool 全体) /ContentPart { output, content }(text/reasoning) /Summary { output, summary }(reasoning 要約) で Responses の 2 次元座標を flat index に自然にマップ。parallel_output_items_get_distinct_indicesで並列 tool call の独立性を検証- テストの充実: request 12 ケース (scheme defaults / tool_choice 固定 / role 別 content 型 / reasoning 有無 / round-trip / serialize shape)、events 10 ケース (text / function_call / custom_tool / reasoning_text / summary / 並列 / failed / unknown / 防御)
- capability の一次情報共有:
OpenAiFamilyenum をopenai_chatに置いて両 scheme で共有、DRY と結合度のバランスが良い Item::Reasoning拡張の互換性:Vec::is_empty/Option::is_noneでの skip_serializing、既存Item::reasoning()コンストラクタは空値で互換。他 scheme のrequest.rsはItem::Reasoning { text, .. }で..省略しており、追加フィールドで壊れない
指摘事項
優先度: 低
1. tool 引数 delta 先行時の空メタデータ
ensure_and_delta が function_call_arguments.delta / custom_tool_call_input.delta で BlockStart 未発行の場合、BlockMetadata::ToolUse { id: String::new(), name: String::new() } を合成する。実運用では output_item.added が先行するはずで発動しないが、仮に発火すると後段で空 call_id を使うリスクがある。
対応案:
ToolUseではensure_and_deltaを使わず、output_item.added必須で、欠落時は warning ログ + Delta 破棄- もしくは現状維持で「防御コードとして warning」出す
現状、output_item.added が保証されている Responses API の仕様に依存しており、実害は薄い。
2. tools[].strict: false ハードコード
ResponseTool::strict: false を常時送信。Responses の strict: true は JSON Schema 準拠を強制する。ModelCapability::structured_output == JsonSchema のときに strict: true に昇格させる余地があるが、本チケットではスコープ外として許容範囲。
優先度: 極低(構造的なスコープ内)
3. summary / encrypted_content が他 scheme で落ちる
Item::Reasoning { text, .. } で .. 省略されている他 scheme(Anthropic / OpenAI Chat / Gemini)の request.rs は summary と encrypted_content を送信しない。ただし:
- Anthropic は独自の
signatureが別途必要で将来拡張 - OpenAI Chat と Gemini は reasoning を first-class では送らない
- scheme をまたいだ履歴引き継ぎは現状想定外
構造的には設計通り、問題なし。
4. OpenAIResponsesScheme の override が build_client から届かない
with_store / with_include_encrypted_content は存在するが、build_client 経由では常に OpenAIResponsesScheme::new() デフォルト。ZDR 非対応環境で store=true にする場合は provider 側で新しい経路が必要。
チケットの設計課題 1 で「将来対応」と明示されており、スコープ通り。
総合判定
close 可能。9 要件すべて達成、設計決定も正確に反映、テストも充実。指摘事項はいずれも実害が薄いか、チケット設計課題として明示されたスコープ内の将来対応。
tickets/llm-auth-codex-oauth.md (次のチケット) を進められる状態。