From bef94529079b57f024eb8a5088c226eab42f3bd7 Mon Sep 17 00:00:00 2001 From: Lucas Alvares Gomes Date: Wed, 28 Oct 2026 10:25:48 +0000 Subject: [PATCH] Accept prompt_cache_key in Responses API requests Allow prompt_cache_key in the OpenAI-compatible responses request model and propagate it through internal ResponsesApiParams so it reaches OGX requests. This prevents 422 validation failures for clients that send provider prompt-cache hints. Goose version v1.56 is sending a the prompt_cache_key parameter in the request and lightspeed-stack now handles it. OGX already has it implemented: https://github.com/ogx-ai/ogx/commit/8b3da72b572f2036a34dcbf83d19136fad8a9d60 Resolves: OSPRH-39974 Signed-off-by: Lucas Alvares Gomes --- docs/devel_doc/openapi.json | 27 +++++++++++++++++-- src/models/api/requests/responses_openai.py | 4 +++ .../responses/successful/responses_openai.py | 3 +++ .../common/responses/responses_api_params.py | 5 ++++ .../models/requests/test_responses_request.py | 11 ++++++++ 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/docs/devel_doc/openapi.json b/docs/devel_doc/openapi.json index c582d4272..55c47daca 100644 --- a/docs/devel_doc/openapi.json +++ b/docs/devel_doc/openapi.json @@ -20727,6 +20727,17 @@ ], "title": "Previous Response Id" }, + "prompt_cache_key": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Prompt Cache Key" + }, "prompt": { "anyOf": [ { @@ -20918,13 +20929,14 @@ "input" ], "title": "ResponsesRequest", - "description": "Model representing a request for the Responses API following LCORE specification.\n\nAttributes:\n input: Input text or structured input items containing the query.\n model: Model identifier in format \"provider/model\". Auto-selected if not provided.\n conversation: Conversation ID linking to an existing conversation. Accepts both\n OpenAI and LCORE formats. Mutually exclusive with previous_response_id.\n include: Explicitly specify output item types that are excluded by default but\n should be included in the response.\n instructions: System instructions or guidelines provided to the model (acts as\n the system prompt).\n max_infer_iters: Maximum number of inference iterations the model can perform.\n max_output_tokens: Maximum number of tokens allowed in the response.\n max_tool_calls: Maximum number of tool calls allowed in a single response.\n metadata: Custom metadata dictionary with key-value pairs for tracking or logging.\n parallel_tool_calls: Whether the model can make multiple tool calls in parallel.\n previous_response_id: Identifier of the previous response in a multi-turn\n conversation. Mutually exclusive with conversation.\n prompt: Prompt object containing a template with variables for dynamic\n substitution.\n reasoning: Reasoning configuration for the response.\n safety_identifier: Safety identifier for the response.\n store: Whether to store the response in conversation history. Defaults to True.\n stream: Whether to stream the response as it is generated. Defaults to False.\n temperature: Sampling temperature controlling randomness (typically 0.0\u20132.0).\n text: Text response configuration specifying output format constraints (JSON\n schema, JSON object, or plain text).\n tool_choice: Tool selection strategy (\"auto\", \"required\", \"none\", or specific\n tool configuration).\n tools: List of tools available to the model (file search, web search, function\n calls, MCP tools). Defaults to all tools available to the model.\n generate_topic_summary: LCORE-specific flag indicating whether to generate a\n topic summary for new conversations. Defaults to True.\n shield_ids: LCORE-specific list of configured shield names to apply.\n If None, all configured shields are used.\n solr: Optional Solr inline RAG options (mode, filters) or legacy filter-only dict.", + "description": "Model representing a request for the Responses API following LCORE specification.\n\nAttributes:\n input: Input text or structured input items containing the query.\n model: Model identifier in format \"provider/model\". Auto-selected if not provided.\n conversation: Conversation ID linking to an existing conversation. Accepts both\n OpenAI and LCORE formats. Mutually exclusive with previous_response_id.\n include: Explicitly specify output item types that are excluded by default but\n should be included in the response.\n instructions: System instructions or guidelines provided to the model (acts as\n the system prompt).\n max_infer_iters: Maximum number of inference iterations the model can perform.\n max_output_tokens: Maximum number of tokens allowed in the response.\n max_tool_calls: Maximum number of tool calls allowed in a single response.\n metadata: Custom metadata dictionary with key-value pairs for tracking or logging.\n parallel_tool_calls: Whether the model can make multiple tool calls in parallel.\n previous_response_id: Identifier of the previous response in a multi-turn\n conversation. Mutually exclusive with conversation.\n prompt_cache_key: Prompt cache key used by providers that support prompt\n caching.\n prompt: Prompt object containing a template with variables for dynamic\n substitution.\n reasoning: Reasoning configuration for the response.\n safety_identifier: Safety identifier for the response.\n store: Whether to store the response in conversation history. Defaults to True.\n stream: Whether to stream the response as it is generated. Defaults to False.\n temperature: Sampling temperature controlling randomness (typically 0.0\u20132.0).\n text: Text response configuration specifying output format constraints (JSON\n schema, JSON object, or plain text).\n tool_choice: Tool selection strategy (\"auto\", \"required\", \"none\", or specific\n tool configuration).\n tools: List of tools available to the model (file search, web search, function\n calls, MCP tools). Defaults to all tools available to the model.\n generate_topic_summary: LCORE-specific flag indicating whether to generate a\n topic summary for new conversations. Defaults to True.\n shield_ids: LCORE-specific list of configured shield names to apply.\n If None, all configured shields are used.\n solr: Optional Solr inline RAG options (mode, filters) or legacy filter-only dict.", "examples": [ { "generate_topic_summary": true, "input": "Hello World!", "instructions": "You are a helpful assistant", "model": "openai/gpt-5.6-luna", + "prompt_cache_key": "example-cache-key", "store": true, "stream": false } @@ -21032,6 +21044,17 @@ ], "title": "Previous Response Id" }, + "prompt_cache_key": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Prompt Cache Key" + }, "prompt": { "anyOf": [ { @@ -21298,7 +21321,7 @@ "output_text" ], "title": "ResponsesResponse", - "description": "Model representing a response from the Responses API following LCORE specification.\n\nAttributes:\n created_at: Unix timestamp when the response was created.\n completed_at: Unix timestamp when the response was completed, if applicable.\n error: Error details if the response failed or was blocked.\n id: Unique identifier for this response.\n model: Model identifier in \"provider/model\" format used for generation.\n object: Object type identifier, always \"response\".\n output: List of structured output items containing messages, tool calls, and\n other content. This is the primary response content.\n parallel_tool_calls: Whether the model can make multiple tool calls in parallel.\n previous_response_id: Identifier of the previous response in a multi-turn\n conversation.\n prompt: The input prompt object that was sent to the model.\n status: Current status of the response (e.g., \"completed\", \"blocked\",\n \"in_progress\").\n temperature: Temperature parameter used for generation (controls randomness).\n text: Text response configuration object used for OpenAI responses.\n top_p: Top-p sampling parameter used for generation.\n tools: List of tools available to the model during generation.\n tool_choice: Tool selection strategy used (e.g., \"auto\", \"required\", \"none\").\n truncation: Strategy used for handling content that exceeds context limits.\n usage: Token usage statistics including input_tokens, output_tokens, and\n total_tokens.\n instructions: System instructions or guidelines provided to the model.\n max_tool_calls: Maximum number of tool calls allowed in a single response.\n reasoning: Reasoning configuration (effort level) used for the response.\n max_output_tokens: Upper bound for tokens generated in the response.\n safety_identifier: Safety/guardrail identifier applied to the request.\n metadata: Additional metadata dictionary with custom key-value pairs.\n store: Whether the response was stored.\n conversation: Conversation ID linking this response to a conversation thread\n (LCORE-specific).\n available_quotas: Remaining token quotas for the user (LCORE-specific).\n output_text: Aggregated text output from all output_text items in the\n output array.", + "description": "Model representing a response from the Responses API following LCORE specification.\n\nAttributes:\n created_at: Unix timestamp when the response was created.\n completed_at: Unix timestamp when the response was completed, if applicable.\n error: Error details if the response failed or was blocked.\n id: Unique identifier for this response.\n model: Model identifier in \"provider/model\" format used for generation.\n object: Object type identifier, always \"response\".\n output: List of structured output items containing messages, tool calls, and\n other content. This is the primary response content.\n parallel_tool_calls: Whether the model can make multiple tool calls in parallel.\n previous_response_id: Identifier of the previous response in a multi-turn\n conversation.\n prompt_cache_key: Prompt cache key used by providers that support prompt\n caching.\n prompt: The input prompt object that was sent to the model.\n status: Current status of the response (e.g., \"completed\", \"blocked\",\n \"in_progress\").\n temperature: Temperature parameter used for generation (controls randomness).\n text: Text response configuration object used for OpenAI responses.\n top_p: Top-p sampling parameter used for generation.\n tools: List of tools available to the model during generation.\n tool_choice: Tool selection strategy used (e.g., \"auto\", \"required\", \"none\").\n truncation: Strategy used for handling content that exceeds context limits.\n usage: Token usage statistics including input_tokens, output_tokens, and\n total_tokens.\n instructions: System instructions or guidelines provided to the model.\n max_tool_calls: Maximum number of tool calls allowed in a single response.\n reasoning: Reasoning configuration (effort level) used for the response.\n max_output_tokens: Upper bound for tokens generated in the response.\n safety_identifier: Safety/guardrail identifier applied to the request.\n metadata: Additional metadata dictionary with custom key-value pairs.\n store: Whether the response was stored.\n conversation: Conversation ID linking this response to a conversation thread\n (LCORE-specific).\n available_quotas: Remaining token quotas for the user (LCORE-specific).\n output_text: Aggregated text output from all output_text items in the\n output array.", "examples": [ { "available_quotas": { diff --git a/src/models/api/requests/responses_openai.py b/src/models/api/requests/responses_openai.py index 317b3d6c8..26a98a0f5 100644 --- a/src/models/api/requests/responses_openai.py +++ b/src/models/api/requests/responses_openai.py @@ -42,6 +42,8 @@ class ResponsesRequest(BaseModel): parallel_tool_calls: Whether the model can make multiple tool calls in parallel. previous_response_id: Identifier of the previous response in a multi-turn conversation. Mutually exclusive with conversation. + prompt_cache_key: Prompt cache key used by providers that support prompt + caching. prompt: Prompt object containing a template with variables for dynamic substitution. reasoning: Reasoning configuration for the response. @@ -74,6 +76,7 @@ class ResponsesRequest(BaseModel): metadata: Optional[dict[str, str]] = None parallel_tool_calls: Optional[bool] = None previous_response_id: Optional[str] = None + prompt_cache_key: Optional[str] = None prompt: Optional[Prompt] = None reasoning: Optional[Reasoning] = None safety_identifier: Optional[str] = None @@ -96,6 +99,7 @@ class ResponsesRequest(BaseModel): "input": "Hello World!", "model": "openai/gpt-5.6-luna", "instructions": "You are a helpful assistant", + "prompt_cache_key": "example-cache-key", "store": True, "stream": False, "generate_topic_summary": True, diff --git a/src/models/api/responses/successful/responses_openai.py b/src/models/api/responses/successful/responses_openai.py index 7a152e52c..6aa2d9b37 100644 --- a/src/models/api/responses/successful/responses_openai.py +++ b/src/models/api/responses/successful/responses_openai.py @@ -46,6 +46,8 @@ class ResponsesResponse(AbstractSuccessfulResponse): parallel_tool_calls: Whether the model can make multiple tool calls in parallel. previous_response_id: Identifier of the previous response in a multi-turn conversation. + prompt_cache_key: Prompt cache key used by providers that support prompt + caching. prompt: The input prompt object that was sent to the model. status: Current status of the response (e.g., "completed", "blocked", "in_progress"). @@ -81,6 +83,7 @@ class ResponsesResponse(AbstractSuccessfulResponse): output: list[Output] parallel_tool_calls: bool = True previous_response_id: Optional[str] = None + prompt_cache_key: Optional[str] = None prompt: Optional[Prompt] = None status: str temperature: Optional[float] = None diff --git a/src/models/common/responses/responses_api_params.py b/src/models/common/responses/responses_api_params.py index d47666abf..ab87d7a94 100644 --- a/src/models/common/responses/responses_api_params.py +++ b/src/models/common/responses/responses_api_params.py @@ -33,6 +33,7 @@ "model", "parallel_tool_calls", "previous_response_id", + "prompt_cache_key", "prompt", "reasoning", "safety_identifier", @@ -87,6 +88,10 @@ class ResponsesApiParams(BaseModel): default=None, description="Identifier of the previous response in a multi-turn conversation", ) + prompt_cache_key: Optional[str] = Field( + default=None, + description="Prompt cache key used by providers that support prompt caching", + ) prompt: Optional[Prompt] = Field( default=None, description="Prompt template with variables for dynamic substitution", diff --git a/tests/unit/models/requests/test_responses_request.py b/tests/unit/models/requests/test_responses_request.py index ec5d7ac1c..142fbace9 100644 --- a/tests/unit/models/requests/test_responses_request.py +++ b/tests/unit/models/requests/test_responses_request.py @@ -122,3 +122,14 @@ def test_model_validation_over_limit_reached_threshold(self) -> None: error_text = str(exc_info.value) assert "110000" in error_text assert "100000" in error_text + + def test_prompt_cache_key_accepted(self) -> None: + """A request containing prompt_cache_key must be accepted.""" + req = ResponsesRequest.model_validate( + { + "input": "hello", + "prompt_cache_key": "example-cache-key", + } + ) + + assert req.prompt_cache_key == "example-cache-key"