From 3a09f00cdb4d040b17b6c567537a702cf369ba61 Mon Sep 17 00:00:00 2001 From: Ashwin Bharambe Date: Mon, 29 Sep 2025 21:29:15 -0700 Subject: [PATCH] feat(files): fix expires_after API shape (#3604) This was just quite incorrect. See source here: https://platform.openai.com/docs/api-reference/files/create --- docs/openapi_generator/pyopenapi/generator.py | 14 +- docs/static/llama-stack-spec.html | 692 +++++++++++------- docs/static/llama-stack-spec.yaml | 377 ++++++---- llama_stack/apis/files/files.py | 7 +- .../providers/inline/files/localfs/files.py | 6 +- .../providers/remote/files/s3/files.py | 11 +- llama_stack/strong_typing/inspection.py | 16 + llama_stack/strong_typing/schema.py | 7 +- tests/unit/providers/files/test_s3_files.py | 23 +- 9 files changed, 705 insertions(+), 448 deletions(-) diff --git a/docs/openapi_generator/pyopenapi/generator.py b/docs/openapi_generator/pyopenapi/generator.py index 758fe7e8f..a38e02e7f 100644 --- a/docs/openapi_generator/pyopenapi/generator.py +++ b/docs/openapi_generator/pyopenapi/generator.py @@ -5,6 +5,7 @@ # the root directory of this source tree. import hashlib +import inspect import ipaddress import types import typing @@ -12,6 +13,7 @@ from dataclasses import make_dataclass from typing import Annotated, Any, Dict, get_args, get_origin, Set, Union from fastapi import UploadFile +from pydantic import BaseModel from llama_stack.apis.datatypes import Error from llama_stack.strong_typing.core import JsonType @@ -632,14 +634,22 @@ class Generator: base_type = get_args(param_type)[0] else: base_type = param_type + + # Check if the type is optional + is_optional = is_type_optional(base_type) + if is_optional: + base_type = unwrap_optional_type(base_type) + if base_type is UploadFile: # File upload properties[name] = {"type": "string", "format": "binary"} else: - # Form field + # All other types - generate schema reference + # This includes enums, BaseModels, and simple types properties[name] = self.schema_builder.classdef_to_ref(base_type) - required_fields.append(name) + if not is_optional: + required_fields.append(name) multipart_schema = { "type": "object", diff --git a/docs/static/llama-stack-spec.html b/docs/static/llama-stack-spec.html index 2072af745..616ebb4fc 100644 --- a/docs/static/llama-stack-spec.html +++ b/docs/static/llama-stack-spec.html @@ -6070,7 +6070,7 @@ "Files" ], "summary": "Upload a file that can be used across various endpoints.", - "description": "Upload a file that can be used across various endpoints.\nThe file upload should be a multipart form request with:\n- file: The File object (not file name) to be uploaded.\n- purpose: The intended purpose of the uploaded file.\n- expires_after: Optional form values describing expiration for the file. Expected expires_after[anchor] = \"created_at\", expires_after[seconds] = {integer}. Seconds must be between 3600 and 2592000 (1 hour to 30 days).", + "description": "Upload a file that can be used across various endpoints.\nThe file upload should be a multipart form request with:\n- file: The File object (not file name) to be uploaded.\n- purpose: The intended purpose of the uploaded file.\n- expires_after: Optional form values describing expiration for the file.", "parameters": [], "requestBody": { "content": { @@ -6085,32 +6085,13 @@ "purpose": { "$ref": "#/components/schemas/OpenAIFilePurpose" }, - "expires_after_anchor": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "expires_after_seconds": { - "oneOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ] + "expires_after": { + "$ref": "#/components/schemas/ExpiresAfter" } }, "required": [ "file", - "purpose", - "expires_after_anchor", - "expires_after_seconds" + "purpose" ] } } @@ -6218,7 +6199,7 @@ "Files" ], "summary": "Upload a file that can be used across various endpoints.", - "description": "Upload a file that can be used across various endpoints.\nThe file upload should be a multipart form request with:\n- file: The File object (not file name) to be uploaded.\n- purpose: The intended purpose of the uploaded file.\n- expires_after: Optional form values describing expiration for the file. Expected expires_after[anchor] = \"created_at\", expires_after[seconds] = {integer}. Seconds must be between 3600 and 2592000 (1 hour to 30 days).", + "description": "Upload a file that can be used across various endpoints.\nThe file upload should be a multipart form request with:\n- file: The File object (not file name) to be uploaded.\n- purpose: The intended purpose of the uploaded file.\n- expires_after: Optional form values describing expiration for the file.", "parameters": [], "requestBody": { "content": { @@ -6233,32 +6214,13 @@ "purpose": { "$ref": "#/components/schemas/OpenAIFilePurpose" }, - "expires_after_anchor": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "expires_after_seconds": { - "oneOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ] + "expires_after": { + "$ref": "#/components/schemas/ExpiresAfter" } }, "required": [ "file", - "purpose", - "expires_after_anchor", - "expires_after_seconds" + "purpose" ] } } @@ -7978,7 +7940,25 @@ "type": "object", "properties": { "strategy": { - "$ref": "#/components/schemas/SamplingStrategy", + "oneOf": [ + { + "$ref": "#/components/schemas/GreedySamplingStrategy" + }, + { + "$ref": "#/components/schemas/TopPSamplingStrategy" + }, + { + "$ref": "#/components/schemas/TopKSamplingStrategy" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "greedy": "#/components/schemas/GreedySamplingStrategy", + "top_p": "#/components/schemas/TopPSamplingStrategy", + "top_k": "#/components/schemas/TopKSamplingStrategy" + } + }, "description": "The sampling strategy." }, "max_tokens": { @@ -8006,27 +7986,6 @@ "title": "SamplingParams", "description": "Sampling parameters." }, - "SamplingStrategy": { - "oneOf": [ - { - "$ref": "#/components/schemas/GreedySamplingStrategy" - }, - { - "$ref": "#/components/schemas/TopPSamplingStrategy" - }, - { - "$ref": "#/components/schemas/TopKSamplingStrategy" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "greedy": "#/components/schemas/GreedySamplingStrategy", - "top_p": "#/components/schemas/TopPSamplingStrategy", - "top_k": "#/components/schemas/TopKSamplingStrategy" - } - } - }, "SystemMessage": { "type": "object", "properties": { @@ -8609,7 +8568,25 @@ "description": "Type of the event" }, "delta": { - "$ref": "#/components/schemas/ContentDelta", + "oneOf": [ + { + "$ref": "#/components/schemas/TextDelta" + }, + { + "$ref": "#/components/schemas/ImageDelta" + }, + { + "$ref": "#/components/schemas/ToolCallDelta" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "text": "#/components/schemas/TextDelta", + "image": "#/components/schemas/ImageDelta", + "tool_call": "#/components/schemas/ToolCallDelta" + } + }, "description": "Content generated since last event. This can be one or more tokens, or a tool call." }, "logprobs": { @@ -8659,27 +8636,6 @@ "title": "ChatCompletionResponseStreamChunk", "description": "A chunk of a streamed chat completion response." }, - "ContentDelta": { - "oneOf": [ - { - "$ref": "#/components/schemas/TextDelta" - }, - { - "$ref": "#/components/schemas/ImageDelta" - }, - { - "$ref": "#/components/schemas/ToolCallDelta" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "text": "#/components/schemas/TextDelta", - "image": "#/components/schemas/ImageDelta", - "tool_call": "#/components/schemas/ToolCallDelta" - } - } - }, "ImageDelta": { "type": "object", "properties": { @@ -9608,7 +9564,37 @@ "type": "object", "properties": { "payload": { - "$ref": "#/components/schemas/AgentTurnResponseEventPayload", + "oneOf": [ + { + "$ref": "#/components/schemas/AgentTurnResponseStepStartPayload" + }, + { + "$ref": "#/components/schemas/AgentTurnResponseStepProgressPayload" + }, + { + "$ref": "#/components/schemas/AgentTurnResponseStepCompletePayload" + }, + { + "$ref": "#/components/schemas/AgentTurnResponseTurnStartPayload" + }, + { + "$ref": "#/components/schemas/AgentTurnResponseTurnCompletePayload" + }, + { + "$ref": "#/components/schemas/AgentTurnResponseTurnAwaitingInputPayload" + } + ], + "discriminator": { + "propertyName": "event_type", + "mapping": { + "step_start": "#/components/schemas/AgentTurnResponseStepStartPayload", + "step_progress": "#/components/schemas/AgentTurnResponseStepProgressPayload", + "step_complete": "#/components/schemas/AgentTurnResponseStepCompletePayload", + "turn_start": "#/components/schemas/AgentTurnResponseTurnStartPayload", + "turn_complete": "#/components/schemas/AgentTurnResponseTurnCompletePayload", + "turn_awaiting_input": "#/components/schemas/AgentTurnResponseTurnAwaitingInputPayload" + } + }, "description": "Event-specific payload containing event data" } }, @@ -9619,39 +9605,6 @@ "title": "AgentTurnResponseEvent", "description": "An event in an agent turn response stream." }, - "AgentTurnResponseEventPayload": { - "oneOf": [ - { - "$ref": "#/components/schemas/AgentTurnResponseStepStartPayload" - }, - { - "$ref": "#/components/schemas/AgentTurnResponseStepProgressPayload" - }, - { - "$ref": "#/components/schemas/AgentTurnResponseStepCompletePayload" - }, - { - "$ref": "#/components/schemas/AgentTurnResponseTurnStartPayload" - }, - { - "$ref": "#/components/schemas/AgentTurnResponseTurnCompletePayload" - }, - { - "$ref": "#/components/schemas/AgentTurnResponseTurnAwaitingInputPayload" - } - ], - "discriminator": { - "propertyName": "event_type", - "mapping": { - "step_start": "#/components/schemas/AgentTurnResponseStepStartPayload", - "step_progress": "#/components/schemas/AgentTurnResponseStepProgressPayload", - "step_complete": "#/components/schemas/AgentTurnResponseStepCompletePayload", - "turn_start": "#/components/schemas/AgentTurnResponseTurnStartPayload", - "turn_complete": "#/components/schemas/AgentTurnResponseTurnCompletePayload", - "turn_awaiting_input": "#/components/schemas/AgentTurnResponseTurnAwaitingInputPayload" - } - } - }, "AgentTurnResponseStepCompletePayload": { "type": "object", "properties": { @@ -9752,7 +9705,25 @@ "description": "Unique identifier for the step within a turn" }, "delta": { - "$ref": "#/components/schemas/ContentDelta", + "oneOf": [ + { + "$ref": "#/components/schemas/TextDelta" + }, + { + "$ref": "#/components/schemas/ImageDelta" + }, + { + "$ref": "#/components/schemas/ToolCallDelta" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "text": "#/components/schemas/TextDelta", + "image": "#/components/schemas/ImageDelta", + "tool_call": "#/components/schemas/ToolCallDelta" + } + }, "description": "Incremental content changes during step execution" } }, @@ -11162,23 +11133,6 @@ "title": "OpenAIResponseOutputMessageMCPListTools", "description": "MCP list tools output message containing available tools from an MCP server." }, - "OpenAIResponseContentPart": { - "oneOf": [ - { - "$ref": "#/components/schemas/OpenAIResponseContentPartOutputText" - }, - { - "$ref": "#/components/schemas/OpenAIResponseContentPartRefusal" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "output_text": "#/components/schemas/OpenAIResponseContentPartOutputText", - "refusal": "#/components/schemas/OpenAIResponseContentPartRefusal" - } - } - }, "OpenAIResponseContentPartOutputText": { "type": "object", "properties": { @@ -11344,7 +11298,21 @@ "description": "Unique identifier of the output item containing this content part" }, "part": { - "$ref": "#/components/schemas/OpenAIResponseContentPart", + "oneOf": [ + { + "$ref": "#/components/schemas/OpenAIResponseContentPartOutputText" + }, + { + "$ref": "#/components/schemas/OpenAIResponseContentPartRefusal" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "output_text": "#/components/schemas/OpenAIResponseContentPartOutputText", + "refusal": "#/components/schemas/OpenAIResponseContentPartRefusal" + } + }, "description": "The content part that was added" }, "sequence_number": { @@ -11381,7 +11349,21 @@ "description": "Unique identifier of the output item containing this content part" }, "part": { - "$ref": "#/components/schemas/OpenAIResponseContentPart", + "oneOf": [ + { + "$ref": "#/components/schemas/OpenAIResponseContentPartOutputText" + }, + { + "$ref": "#/components/schemas/OpenAIResponseContentPartRefusal" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "output_text": "#/components/schemas/OpenAIResponseContentPartOutputText", + "refusal": "#/components/schemas/OpenAIResponseContentPartRefusal" + } + }, "description": "The completed content part" }, "sequence_number": { @@ -11705,7 +11687,37 @@ "description": "Unique identifier of the response containing this output" }, "item": { - "$ref": "#/components/schemas/OpenAIResponseOutput", + "oneOf": [ + { + "$ref": "#/components/schemas/OpenAIResponseMessage" + }, + { + "$ref": "#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall" + }, + { + "$ref": "#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall" + }, + { + "$ref": "#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall" + }, + { + "$ref": "#/components/schemas/OpenAIResponseOutputMessageMCPCall" + }, + { + "$ref": "#/components/schemas/OpenAIResponseOutputMessageMCPListTools" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "message": "#/components/schemas/OpenAIResponseMessage", + "web_search_call": "#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall", + "file_search_call": "#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall", + "function_call": "#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall", + "mcp_call": "#/components/schemas/OpenAIResponseOutputMessageMCPCall", + "mcp_list_tools": "#/components/schemas/OpenAIResponseOutputMessageMCPListTools" + } + }, "description": "The output item that was added (message, tool call, etc.)" }, "output_index": { @@ -11742,7 +11754,37 @@ "description": "Unique identifier of the response containing this output" }, "item": { - "$ref": "#/components/schemas/OpenAIResponseOutput", + "oneOf": [ + { + "$ref": "#/components/schemas/OpenAIResponseMessage" + }, + { + "$ref": "#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall" + }, + { + "$ref": "#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall" + }, + { + "$ref": "#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall" + }, + { + "$ref": "#/components/schemas/OpenAIResponseOutputMessageMCPCall" + }, + { + "$ref": "#/components/schemas/OpenAIResponseOutputMessageMCPListTools" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "message": "#/components/schemas/OpenAIResponseMessage", + "web_search_call": "#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall", + "file_search_call": "#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall", + "function_call": "#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall", + "mcp_call": "#/components/schemas/OpenAIResponseOutputMessageMCPCall", + "mcp_list_tools": "#/components/schemas/OpenAIResponseOutputMessageMCPListTools" + } + }, "description": "The completed output item (message, tool call, etc.)" }, "output_index": { @@ -12095,7 +12137,21 @@ "type": "object", "properties": { "eval_candidate": { - "$ref": "#/components/schemas/EvalCandidate", + "oneOf": [ + { + "$ref": "#/components/schemas/ModelCandidate" + }, + { + "$ref": "#/components/schemas/AgentCandidate" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "model": "#/components/schemas/ModelCandidate", + "agent": "#/components/schemas/AgentCandidate" + } + }, "description": "The candidate to evaluate." }, "scoring_params": { @@ -12118,23 +12174,6 @@ "title": "BenchmarkConfig", "description": "A benchmark configuration for evaluation." }, - "EvalCandidate": { - "oneOf": [ - { - "$ref": "#/components/schemas/ModelCandidate" - }, - { - "$ref": "#/components/schemas/AgentCandidate" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "model": "#/components/schemas/ModelCandidate", - "agent": "#/components/schemas/AgentCandidate" - } - } - }, "LLMAsJudgeScoringFnParams": { "type": "object", "properties": { @@ -12770,7 +12809,33 @@ "type": "object", "properties": { "message": { - "$ref": "#/components/schemas/OpenAIMessageParam", + "oneOf": [ + { + "$ref": "#/components/schemas/OpenAIUserMessageParam" + }, + { + "$ref": "#/components/schemas/OpenAISystemMessageParam" + }, + { + "$ref": "#/components/schemas/OpenAIAssistantMessageParam" + }, + { + "$ref": "#/components/schemas/OpenAIToolMessageParam" + }, + { + "$ref": "#/components/schemas/OpenAIDeveloperMessageParam" + } + ], + "discriminator": { + "propertyName": "role", + "mapping": { + "user": "#/components/schemas/OpenAIUserMessageParam", + "system": "#/components/schemas/OpenAISystemMessageParam", + "assistant": "#/components/schemas/OpenAIAssistantMessageParam", + "tool": "#/components/schemas/OpenAIToolMessageParam", + "developer": "#/components/schemas/OpenAIDeveloperMessageParam" + } + }, "description": "The message from the model" }, "finish_reason": { @@ -13146,23 +13211,6 @@ ], "title": "OpenAICompletionWithInputMessages" }, - "DataSource": { - "oneOf": [ - { - "$ref": "#/components/schemas/URIDataSource" - }, - { - "$ref": "#/components/schemas/RowsDataSource" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "uri": "#/components/schemas/URIDataSource", - "rows": "#/components/schemas/RowsDataSource" - } - } - }, "Dataset": { "type": "object", "properties": { @@ -13202,7 +13250,21 @@ "description": "Purpose of the dataset indicating its intended use" }, "source": { - "$ref": "#/components/schemas/DataSource", + "oneOf": [ + { + "$ref": "#/components/schemas/URIDataSource" + }, + { + "$ref": "#/components/schemas/RowsDataSource" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "uri": "#/components/schemas/URIDataSource", + "rows": "#/components/schemas/RowsDataSource" + } + }, "description": "Data source configuration for the dataset" }, "metadata": { @@ -13531,55 +13593,6 @@ "title": "ObjectType", "description": "Parameter type for object values." }, - "ParamType": { - "oneOf": [ - { - "$ref": "#/components/schemas/StringType" - }, - { - "$ref": "#/components/schemas/NumberType" - }, - { - "$ref": "#/components/schemas/BooleanType" - }, - { - "$ref": "#/components/schemas/ArrayType" - }, - { - "$ref": "#/components/schemas/ObjectType" - }, - { - "$ref": "#/components/schemas/JsonType" - }, - { - "$ref": "#/components/schemas/UnionType" - }, - { - "$ref": "#/components/schemas/ChatCompletionInputType" - }, - { - "$ref": "#/components/schemas/CompletionInputType" - }, - { - "$ref": "#/components/schemas/AgentTurnInputType" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "string": "#/components/schemas/StringType", - "number": "#/components/schemas/NumberType", - "boolean": "#/components/schemas/BooleanType", - "array": "#/components/schemas/ArrayType", - "object": "#/components/schemas/ObjectType", - "json": "#/components/schemas/JsonType", - "union": "#/components/schemas/UnionType", - "chat_completion_input": "#/components/schemas/ChatCompletionInputType", - "completion_input": "#/components/schemas/CompletionInputType", - "agent_turn_input": "#/components/schemas/AgentTurnInputType" - } - } - }, "ScoringFn": { "type": "object", "properties": { @@ -13638,7 +13651,53 @@ } }, "return_type": { - "$ref": "#/components/schemas/ParamType" + "oneOf": [ + { + "$ref": "#/components/schemas/StringType" + }, + { + "$ref": "#/components/schemas/NumberType" + }, + { + "$ref": "#/components/schemas/BooleanType" + }, + { + "$ref": "#/components/schemas/ArrayType" + }, + { + "$ref": "#/components/schemas/ObjectType" + }, + { + "$ref": "#/components/schemas/JsonType" + }, + { + "$ref": "#/components/schemas/UnionType" + }, + { + "$ref": "#/components/schemas/ChatCompletionInputType" + }, + { + "$ref": "#/components/schemas/CompletionInputType" + }, + { + "$ref": "#/components/schemas/AgentTurnInputType" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "string": "#/components/schemas/StringType", + "number": "#/components/schemas/NumberType", + "boolean": "#/components/schemas/BooleanType", + "array": "#/components/schemas/ArrayType", + "object": "#/components/schemas/ObjectType", + "json": "#/components/schemas/JsonType", + "union": "#/components/schemas/UnionType", + "chat_completion_input": "#/components/schemas/ChatCompletionInputType", + "completion_input": "#/components/schemas/CompletionInputType", + "agent_turn_input": "#/components/schemas/AgentTurnInputType" + } + } }, "params": { "$ref": "#/components/schemas/ScoringFnParams" @@ -15548,7 +15607,21 @@ "description": "Event type identifier set to STRUCTURED_LOG" }, "payload": { - "$ref": "#/components/schemas/StructuredLogPayload", + "oneOf": [ + { + "$ref": "#/components/schemas/SpanStartPayload" + }, + { + "$ref": "#/components/schemas/SpanEndPayload" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "span_start": "#/components/schemas/SpanStartPayload", + "span_end": "#/components/schemas/SpanEndPayload" + } + }, "description": "The structured payload data for the log event" } }, @@ -15563,23 +15636,6 @@ "title": "StructuredLogEvent", "description": "A structured log event containing typed payload data." }, - "StructuredLogPayload": { - "oneOf": [ - { - "$ref": "#/components/schemas/SpanStartPayload" - }, - { - "$ref": "#/components/schemas/SpanEndPayload" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "span_start": "#/components/schemas/SpanStartPayload", - "span_end": "#/components/schemas/SpanEndPayload" - } - } - }, "StructuredLogType": { "type": "string", "enum": [ @@ -15864,7 +15920,21 @@ "description": "Key-value attributes associated with the file" }, "chunking_strategy": { - "$ref": "#/components/schemas/VectorStoreChunkingStrategy", + "oneOf": [ + { + "$ref": "#/components/schemas/VectorStoreChunkingStrategyAuto" + }, + { + "$ref": "#/components/schemas/VectorStoreChunkingStrategyStatic" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "auto": "#/components/schemas/VectorStoreChunkingStrategyAuto", + "static": "#/components/schemas/VectorStoreChunkingStrategyStatic" + } + }, "description": "Strategy used for splitting the file into chunks" }, "created_at": { @@ -17677,6 +17747,25 @@ ], "title": "OpenaiUpdateVectorStoreFileRequest" }, + "ExpiresAfter": { + "type": "object", + "properties": { + "anchor": { + "type": "string", + "const": "created_at" + }, + "seconds": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "anchor", + "seconds" + ], + "title": "ExpiresAfter", + "description": "Control expiration of uploaded files.\nParams:\n - anchor, must be \"created_at\"\n - seconds, must be int between 3600 and 2592000 (1 hour to 30 days)" + }, "DPOAlignmentConfig": { "type": "object", "properties": { @@ -18028,7 +18117,21 @@ "type": "object", "properties": { "query_generator_config": { - "$ref": "#/components/schemas/RAGQueryGeneratorConfig", + "oneOf": [ + { + "$ref": "#/components/schemas/DefaultRAGQueryGeneratorConfig" + }, + { + "$ref": "#/components/schemas/LLMRAGQueryGeneratorConfig" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "default": "#/components/schemas/DefaultRAGQueryGeneratorConfig", + "llm": "#/components/schemas/LLMRAGQueryGeneratorConfig" + } + }, "description": "Configuration for the query generator." }, "max_tokens_in_context": { @@ -18066,23 +18169,6 @@ "title": "RAGQueryConfig", "description": "Configuration for the RAG query generation." }, - "RAGQueryGeneratorConfig": { - "oneOf": [ - { - "$ref": "#/components/schemas/DefaultRAGQueryGeneratorConfig" - }, - { - "$ref": "#/components/schemas/LLMRAGQueryGeneratorConfig" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "default": "#/components/schemas/DefaultRAGQueryGeneratorConfig", - "llm": "#/components/schemas/LLMRAGQueryGeneratorConfig" - } - } - }, "RAGSearchMode": { "type": "string", "enum": [ @@ -18664,6 +18750,23 @@ ], "title": "RegisterBenchmarkRequest" }, + "DataSource": { + "oneOf": [ + { + "$ref": "#/components/schemas/URIDataSource" + }, + { + "$ref": "#/components/schemas/RowsDataSource" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "uri": "#/components/schemas/URIDataSource", + "rows": "#/components/schemas/RowsDataSource" + } + } + }, "RegisterDatasetRequest": { "type": "object", "properties": { @@ -18770,6 +18873,55 @@ ], "title": "RegisterModelRequest" }, + "ParamType": { + "oneOf": [ + { + "$ref": "#/components/schemas/StringType" + }, + { + "$ref": "#/components/schemas/NumberType" + }, + { + "$ref": "#/components/schemas/BooleanType" + }, + { + "$ref": "#/components/schemas/ArrayType" + }, + { + "$ref": "#/components/schemas/ObjectType" + }, + { + "$ref": "#/components/schemas/JsonType" + }, + { + "$ref": "#/components/schemas/UnionType" + }, + { + "$ref": "#/components/schemas/ChatCompletionInputType" + }, + { + "$ref": "#/components/schemas/CompletionInputType" + }, + { + "$ref": "#/components/schemas/AgentTurnInputType" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "string": "#/components/schemas/StringType", + "number": "#/components/schemas/NumberType", + "boolean": "#/components/schemas/BooleanType", + "array": "#/components/schemas/ArrayType", + "object": "#/components/schemas/ObjectType", + "json": "#/components/schemas/JsonType", + "union": "#/components/schemas/UnionType", + "chat_completion_input": "#/components/schemas/ChatCompletionInputType", + "completion_input": "#/components/schemas/CompletionInputType", + "agent_turn_input": "#/components/schemas/AgentTurnInputType" + } + } + }, "RegisterScoringFunctionRequest": { "type": "object", "properties": { diff --git a/docs/static/llama-stack-spec.yaml b/docs/static/llama-stack-spec.yaml index 7b51116ba..fe86b0ff0 100644 --- a/docs/static/llama-stack-spec.yaml +++ b/docs/static/llama-stack-spec.yaml @@ -4383,8 +4383,6 @@ paths: - purpose: The intended purpose of the uploaded file. - expires_after: Optional form values describing expiration for the file. - Expected expires_after[anchor] = "created_at", expires_after[seconds] = {integer}. - Seconds must be between 3600 and 2592000 (1 hour to 30 days). parameters: [] requestBody: content: @@ -4397,19 +4395,11 @@ paths: format: binary purpose: $ref: '#/components/schemas/OpenAIFilePurpose' - expires_after_anchor: - oneOf: - - type: string - - type: 'null' - expires_after_seconds: - oneOf: - - type: integer - - type: 'null' + expires_after: + $ref: '#/components/schemas/ExpiresAfter' required: - file - purpose - - expires_after_anchor - - expires_after_seconds required: true /v1/openai/v1/files: get: @@ -4504,8 +4494,6 @@ paths: - purpose: The intended purpose of the uploaded file. - expires_after: Optional form values describing expiration for the file. - Expected expires_after[anchor] = "created_at", expires_after[seconds] = {integer}. - Seconds must be between 3600 and 2592000 (1 hour to 30 days). parameters: [] requestBody: content: @@ -4518,19 +4506,11 @@ paths: format: binary purpose: $ref: '#/components/schemas/OpenAIFilePurpose' - expires_after_anchor: - oneOf: - - type: string - - type: 'null' - expires_after_seconds: - oneOf: - - type: integer - - type: 'null' + expires_after: + $ref: '#/components/schemas/ExpiresAfter' required: - file - purpose - - expires_after_anchor - - expires_after_seconds required: true /v1/openai/v1/models: get: @@ -5763,7 +5743,16 @@ components: type: object properties: strategy: - $ref: '#/components/schemas/SamplingStrategy' + oneOf: + - $ref: '#/components/schemas/GreedySamplingStrategy' + - $ref: '#/components/schemas/TopPSamplingStrategy' + - $ref: '#/components/schemas/TopKSamplingStrategy' + discriminator: + propertyName: type + mapping: + greedy: '#/components/schemas/GreedySamplingStrategy' + top_p: '#/components/schemas/TopPSamplingStrategy' + top_k: '#/components/schemas/TopKSamplingStrategy' description: The sampling strategy. max_tokens: type: integer @@ -5791,17 +5780,6 @@ components: - strategy title: SamplingParams description: Sampling parameters. - SamplingStrategy: - oneOf: - - $ref: '#/components/schemas/GreedySamplingStrategy' - - $ref: '#/components/schemas/TopPSamplingStrategy' - - $ref: '#/components/schemas/TopKSamplingStrategy' - discriminator: - propertyName: type - mapping: - greedy: '#/components/schemas/GreedySamplingStrategy' - top_p: '#/components/schemas/TopPSamplingStrategy' - top_k: '#/components/schemas/TopKSamplingStrategy' SystemMessage: type: object properties: @@ -6248,7 +6226,16 @@ components: - progress description: Type of the event delta: - $ref: '#/components/schemas/ContentDelta' + oneOf: + - $ref: '#/components/schemas/TextDelta' + - $ref: '#/components/schemas/ImageDelta' + - $ref: '#/components/schemas/ToolCallDelta' + discriminator: + propertyName: type + mapping: + text: '#/components/schemas/TextDelta' + image: '#/components/schemas/ImageDelta' + tool_call: '#/components/schemas/ToolCallDelta' description: >- Content generated since last event. This can be one or more tokens, or a tool call. @@ -6291,17 +6278,6 @@ components: title: ChatCompletionResponseStreamChunk description: >- A chunk of a streamed chat completion response. - ContentDelta: - oneOf: - - $ref: '#/components/schemas/TextDelta' - - $ref: '#/components/schemas/ImageDelta' - - $ref: '#/components/schemas/ToolCallDelta' - discriminator: - propertyName: type - mapping: - text: '#/components/schemas/TextDelta' - image: '#/components/schemas/ImageDelta' - tool_call: '#/components/schemas/ToolCallDelta' ImageDelta: type: object properties: @@ -6983,7 +6959,22 @@ components: type: object properties: payload: - $ref: '#/components/schemas/AgentTurnResponseEventPayload' + oneOf: + - $ref: '#/components/schemas/AgentTurnResponseStepStartPayload' + - $ref: '#/components/schemas/AgentTurnResponseStepProgressPayload' + - $ref: '#/components/schemas/AgentTurnResponseStepCompletePayload' + - $ref: '#/components/schemas/AgentTurnResponseTurnStartPayload' + - $ref: '#/components/schemas/AgentTurnResponseTurnCompletePayload' + - $ref: '#/components/schemas/AgentTurnResponseTurnAwaitingInputPayload' + discriminator: + propertyName: event_type + mapping: + step_start: '#/components/schemas/AgentTurnResponseStepStartPayload' + step_progress: '#/components/schemas/AgentTurnResponseStepProgressPayload' + step_complete: '#/components/schemas/AgentTurnResponseStepCompletePayload' + turn_start: '#/components/schemas/AgentTurnResponseTurnStartPayload' + turn_complete: '#/components/schemas/AgentTurnResponseTurnCompletePayload' + turn_awaiting_input: '#/components/schemas/AgentTurnResponseTurnAwaitingInputPayload' description: >- Event-specific payload containing event data additionalProperties: false @@ -6992,23 +6983,6 @@ components: title: AgentTurnResponseEvent description: >- An event in an agent turn response stream. - AgentTurnResponseEventPayload: - oneOf: - - $ref: '#/components/schemas/AgentTurnResponseStepStartPayload' - - $ref: '#/components/schemas/AgentTurnResponseStepProgressPayload' - - $ref: '#/components/schemas/AgentTurnResponseStepCompletePayload' - - $ref: '#/components/schemas/AgentTurnResponseTurnStartPayload' - - $ref: '#/components/schemas/AgentTurnResponseTurnCompletePayload' - - $ref: '#/components/schemas/AgentTurnResponseTurnAwaitingInputPayload' - discriminator: - propertyName: event_type - mapping: - step_start: '#/components/schemas/AgentTurnResponseStepStartPayload' - step_progress: '#/components/schemas/AgentTurnResponseStepProgressPayload' - step_complete: '#/components/schemas/AgentTurnResponseStepCompletePayload' - turn_start: '#/components/schemas/AgentTurnResponseTurnStartPayload' - turn_complete: '#/components/schemas/AgentTurnResponseTurnCompletePayload' - turn_awaiting_input: '#/components/schemas/AgentTurnResponseTurnAwaitingInputPayload' AgentTurnResponseStepCompletePayload: type: object properties: @@ -7087,7 +7061,16 @@ components: description: >- Unique identifier for the step within a turn delta: - $ref: '#/components/schemas/ContentDelta' + oneOf: + - $ref: '#/components/schemas/TextDelta' + - $ref: '#/components/schemas/ImageDelta' + - $ref: '#/components/schemas/ToolCallDelta' + discriminator: + propertyName: type + mapping: + text: '#/components/schemas/TextDelta' + image: '#/components/schemas/ImageDelta' + tool_call: '#/components/schemas/ToolCallDelta' description: >- Incremental content changes during step execution additionalProperties: false @@ -8156,15 +8139,6 @@ components: title: OpenAIResponseOutputMessageMCPListTools description: >- MCP list tools output message containing available tools from an MCP server. - OpenAIResponseContentPart: - oneOf: - - $ref: '#/components/schemas/OpenAIResponseContentPartOutputText' - - $ref: '#/components/schemas/OpenAIResponseContentPartRefusal' - discriminator: - propertyName: type - mapping: - output_text: '#/components/schemas/OpenAIResponseContentPartOutputText' - refusal: '#/components/schemas/OpenAIResponseContentPartRefusal' OpenAIResponseContentPartOutputText: type: object properties: @@ -8272,7 +8246,14 @@ components: description: >- Unique identifier of the output item containing this content part part: - $ref: '#/components/schemas/OpenAIResponseContentPart' + oneOf: + - $ref: '#/components/schemas/OpenAIResponseContentPartOutputText' + - $ref: '#/components/schemas/OpenAIResponseContentPartRefusal' + discriminator: + propertyName: type + mapping: + output_text: '#/components/schemas/OpenAIResponseContentPartOutputText' + refusal: '#/components/schemas/OpenAIResponseContentPartRefusal' description: The content part that was added sequence_number: type: integer @@ -8307,7 +8288,14 @@ components: description: >- Unique identifier of the output item containing this content part part: - $ref: '#/components/schemas/OpenAIResponseContentPart' + oneOf: + - $ref: '#/components/schemas/OpenAIResponseContentPartOutputText' + - $ref: '#/components/schemas/OpenAIResponseContentPartRefusal' + discriminator: + propertyName: type + mapping: + output_text: '#/components/schemas/OpenAIResponseContentPartOutputText' + refusal: '#/components/schemas/OpenAIResponseContentPartRefusal' description: The completed content part sequence_number: type: integer @@ -8593,7 +8581,22 @@ components: description: >- Unique identifier of the response containing this output item: - $ref: '#/components/schemas/OpenAIResponseOutput' + oneOf: + - $ref: '#/components/schemas/OpenAIResponseMessage' + - $ref: '#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall' + - $ref: '#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall' + - $ref: '#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall' + - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPCall' + - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPListTools' + discriminator: + propertyName: type + mapping: + message: '#/components/schemas/OpenAIResponseMessage' + web_search_call: '#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall' + file_search_call: '#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall' + function_call: '#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall' + mcp_call: '#/components/schemas/OpenAIResponseOutputMessageMCPCall' + mcp_list_tools: '#/components/schemas/OpenAIResponseOutputMessageMCPListTools' description: >- The output item that was added (message, tool call, etc.) output_index: @@ -8629,7 +8632,22 @@ components: description: >- Unique identifier of the response containing this output item: - $ref: '#/components/schemas/OpenAIResponseOutput' + oneOf: + - $ref: '#/components/schemas/OpenAIResponseMessage' + - $ref: '#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall' + - $ref: '#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall' + - $ref: '#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall' + - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPCall' + - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPListTools' + discriminator: + propertyName: type + mapping: + message: '#/components/schemas/OpenAIResponseMessage' + web_search_call: '#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall' + file_search_call: '#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall' + function_call: '#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall' + mcp_call: '#/components/schemas/OpenAIResponseOutputMessageMCPCall' + mcp_list_tools: '#/components/schemas/OpenAIResponseOutputMessageMCPListTools' description: >- The completed output item (message, tool call, etc.) output_index: @@ -8952,7 +8970,14 @@ components: type: object properties: eval_candidate: - $ref: '#/components/schemas/EvalCandidate' + oneOf: + - $ref: '#/components/schemas/ModelCandidate' + - $ref: '#/components/schemas/AgentCandidate' + discriminator: + propertyName: type + mapping: + model: '#/components/schemas/ModelCandidate' + agent: '#/components/schemas/AgentCandidate' description: The candidate to evaluate. scoring_params: type: object @@ -8973,15 +8998,6 @@ components: title: BenchmarkConfig description: >- A benchmark configuration for evaluation. - EvalCandidate: - oneOf: - - $ref: '#/components/schemas/ModelCandidate' - - $ref: '#/components/schemas/AgentCandidate' - discriminator: - propertyName: type - mapping: - model: '#/components/schemas/ModelCandidate' - agent: '#/components/schemas/AgentCandidate' LLMAsJudgeScoringFnParams: type: object properties: @@ -9445,7 +9461,20 @@ components: type: object properties: message: - $ref: '#/components/schemas/OpenAIMessageParam' + oneOf: + - $ref: '#/components/schemas/OpenAIUserMessageParam' + - $ref: '#/components/schemas/OpenAISystemMessageParam' + - $ref: '#/components/schemas/OpenAIAssistantMessageParam' + - $ref: '#/components/schemas/OpenAIToolMessageParam' + - $ref: '#/components/schemas/OpenAIDeveloperMessageParam' + discriminator: + propertyName: role + mapping: + user: '#/components/schemas/OpenAIUserMessageParam' + system: '#/components/schemas/OpenAISystemMessageParam' + assistant: '#/components/schemas/OpenAIAssistantMessageParam' + tool: '#/components/schemas/OpenAIToolMessageParam' + developer: '#/components/schemas/OpenAIDeveloperMessageParam' description: The message from the model finish_reason: type: string @@ -9738,15 +9767,6 @@ components: - model - input_messages title: OpenAICompletionWithInputMessages - DataSource: - oneOf: - - $ref: '#/components/schemas/URIDataSource' - - $ref: '#/components/schemas/RowsDataSource' - discriminator: - propertyName: type - mapping: - uri: '#/components/schemas/URIDataSource' - rows: '#/components/schemas/RowsDataSource' Dataset: type: object properties: @@ -9781,7 +9801,14 @@ components: description: >- Purpose of the dataset indicating its intended use source: - $ref: '#/components/schemas/DataSource' + oneOf: + - $ref: '#/components/schemas/URIDataSource' + - $ref: '#/components/schemas/RowsDataSource' + discriminator: + propertyName: type + mapping: + uri: '#/components/schemas/URIDataSource' + rows: '#/components/schemas/RowsDataSource' description: >- Data source configuration for the dataset metadata: @@ -10027,31 +10054,6 @@ components: - type title: ObjectType description: Parameter type for object values. - ParamType: - oneOf: - - $ref: '#/components/schemas/StringType' - - $ref: '#/components/schemas/NumberType' - - $ref: '#/components/schemas/BooleanType' - - $ref: '#/components/schemas/ArrayType' - - $ref: '#/components/schemas/ObjectType' - - $ref: '#/components/schemas/JsonType' - - $ref: '#/components/schemas/UnionType' - - $ref: '#/components/schemas/ChatCompletionInputType' - - $ref: '#/components/schemas/CompletionInputType' - - $ref: '#/components/schemas/AgentTurnInputType' - discriminator: - propertyName: type - mapping: - string: '#/components/schemas/StringType' - number: '#/components/schemas/NumberType' - boolean: '#/components/schemas/BooleanType' - array: '#/components/schemas/ArrayType' - object: '#/components/schemas/ObjectType' - json: '#/components/schemas/JsonType' - union: '#/components/schemas/UnionType' - chat_completion_input: '#/components/schemas/ChatCompletionInputType' - completion_input: '#/components/schemas/CompletionInputType' - agent_turn_input: '#/components/schemas/AgentTurnInputType' ScoringFn: type: object properties: @@ -10090,7 +10092,30 @@ components: - type: array - type: object return_type: - $ref: '#/components/schemas/ParamType' + oneOf: + - $ref: '#/components/schemas/StringType' + - $ref: '#/components/schemas/NumberType' + - $ref: '#/components/schemas/BooleanType' + - $ref: '#/components/schemas/ArrayType' + - $ref: '#/components/schemas/ObjectType' + - $ref: '#/components/schemas/JsonType' + - $ref: '#/components/schemas/UnionType' + - $ref: '#/components/schemas/ChatCompletionInputType' + - $ref: '#/components/schemas/CompletionInputType' + - $ref: '#/components/schemas/AgentTurnInputType' + discriminator: + propertyName: type + mapping: + string: '#/components/schemas/StringType' + number: '#/components/schemas/NumberType' + boolean: '#/components/schemas/BooleanType' + array: '#/components/schemas/ArrayType' + object: '#/components/schemas/ObjectType' + json: '#/components/schemas/JsonType' + union: '#/components/schemas/UnionType' + chat_completion_input: '#/components/schemas/ChatCompletionInputType' + completion_input: '#/components/schemas/CompletionInputType' + agent_turn_input: '#/components/schemas/AgentTurnInputType' params: $ref: '#/components/schemas/ScoringFnParams' additionalProperties: false @@ -11542,7 +11567,14 @@ components: description: >- Event type identifier set to STRUCTURED_LOG payload: - $ref: '#/components/schemas/StructuredLogPayload' + oneOf: + - $ref: '#/components/schemas/SpanStartPayload' + - $ref: '#/components/schemas/SpanEndPayload' + discriminator: + propertyName: type + mapping: + span_start: '#/components/schemas/SpanStartPayload' + span_end: '#/components/schemas/SpanEndPayload' description: >- The structured payload data for the log event additionalProperties: false @@ -11555,15 +11587,6 @@ components: title: StructuredLogEvent description: >- A structured log event containing typed payload data. - StructuredLogPayload: - oneOf: - - $ref: '#/components/schemas/SpanStartPayload' - - $ref: '#/components/schemas/SpanEndPayload' - discriminator: - propertyName: type - mapping: - span_start: '#/components/schemas/SpanStartPayload' - span_end: '#/components/schemas/SpanEndPayload' StructuredLogType: type: string enum: @@ -11772,7 +11795,14 @@ components: description: >- Key-value attributes associated with the file chunking_strategy: - $ref: '#/components/schemas/VectorStoreChunkingStrategy' + oneOf: + - $ref: '#/components/schemas/VectorStoreChunkingStrategyAuto' + - $ref: '#/components/schemas/VectorStoreChunkingStrategyStatic' + discriminator: + propertyName: type + mapping: + auto: '#/components/schemas/VectorStoreChunkingStrategyAuto' + static: '#/components/schemas/VectorStoreChunkingStrategyStatic' description: >- Strategy used for splitting the file into chunks created_at: @@ -13084,6 +13114,25 @@ components: required: - attributes title: OpenaiUpdateVectorStoreFileRequest + ExpiresAfter: + type: object + properties: + anchor: + type: string + const: created_at + seconds: + type: integer + additionalProperties: false + required: + - anchor + - seconds + title: ExpiresAfter + description: >- + Control expiration of uploaded files. + + Params: + - anchor, must be "created_at" + - seconds, must be int between 3600 and 2592000 (1 hour to 30 days) DPOAlignmentConfig: type: object properties: @@ -13369,7 +13418,14 @@ components: type: object properties: query_generator_config: - $ref: '#/components/schemas/RAGQueryGeneratorConfig' + oneOf: + - $ref: '#/components/schemas/DefaultRAGQueryGeneratorConfig' + - $ref: '#/components/schemas/LLMRAGQueryGeneratorConfig' + discriminator: + propertyName: type + mapping: + default: '#/components/schemas/DefaultRAGQueryGeneratorConfig' + llm: '#/components/schemas/LLMRAGQueryGeneratorConfig' description: Configuration for the query generator. max_tokens_in_context: type: integer @@ -13412,15 +13468,6 @@ components: title: RAGQueryConfig description: >- Configuration for the RAG query generation. - RAGQueryGeneratorConfig: - oneOf: - - $ref: '#/components/schemas/DefaultRAGQueryGeneratorConfig' - - $ref: '#/components/schemas/LLMRAGQueryGeneratorConfig' - discriminator: - propertyName: type - mapping: - default: '#/components/schemas/DefaultRAGQueryGeneratorConfig' - llm: '#/components/schemas/LLMRAGQueryGeneratorConfig' RAGSearchMode: type: string enum: @@ -13856,6 +13903,15 @@ components: - dataset_id - scoring_functions title: RegisterBenchmarkRequest + DataSource: + oneOf: + - $ref: '#/components/schemas/URIDataSource' + - $ref: '#/components/schemas/RowsDataSource' + discriminator: + propertyName: type + mapping: + uri: '#/components/schemas/URIDataSource' + rows: '#/components/schemas/RowsDataSource' RegisterDatasetRequest: type: object properties: @@ -13940,6 +13996,31 @@ components: required: - model_id title: RegisterModelRequest + ParamType: + oneOf: + - $ref: '#/components/schemas/StringType' + - $ref: '#/components/schemas/NumberType' + - $ref: '#/components/schemas/BooleanType' + - $ref: '#/components/schemas/ArrayType' + - $ref: '#/components/schemas/ObjectType' + - $ref: '#/components/schemas/JsonType' + - $ref: '#/components/schemas/UnionType' + - $ref: '#/components/schemas/ChatCompletionInputType' + - $ref: '#/components/schemas/CompletionInputType' + - $ref: '#/components/schemas/AgentTurnInputType' + discriminator: + propertyName: type + mapping: + string: '#/components/schemas/StringType' + number: '#/components/schemas/NumberType' + boolean: '#/components/schemas/BooleanType' + array: '#/components/schemas/ArrayType' + object: '#/components/schemas/ObjectType' + json: '#/components/schemas/JsonType' + union: '#/components/schemas/UnionType' + chat_completion_input: '#/components/schemas/ChatCompletionInputType' + completion_input: '#/components/schemas/CompletionInputType' + agent_turn_input: '#/components/schemas/AgentTurnInputType' RegisterScoringFunctionRequest: type: object properties: diff --git a/llama_stack/apis/files/files.py b/llama_stack/apis/files/files.py index d5abb6286..e4cf6283a 100644 --- a/llama_stack/apis/files/files.py +++ b/llama_stack/apis/files/files.py @@ -111,9 +111,7 @@ class Files(Protocol): self, file: Annotated[UploadFile, File()], purpose: Annotated[OpenAIFilePurpose, Form()], - expires_after_anchor: Annotated[str | None, Form(alias="expires_after[anchor]")] = None, - expires_after_seconds: Annotated[int | None, Form(alias="expires_after[seconds]")] = None, - # TODO: expires_after is producing strange openapi spec, params are showing up as a required w/ oneOf being null + expires_after: Annotated[ExpiresAfter | None, Form()] = None, ) -> OpenAIFileObject: """ Upload a file that can be used across various endpoints. @@ -121,10 +119,11 @@ class Files(Protocol): The file upload should be a multipart form request with: - file: The File object (not file name) to be uploaded. - purpose: The intended purpose of the uploaded file. - - expires_after: Optional form values describing expiration for the file. Expected expires_after[anchor] = "created_at", expires_after[seconds] = {integer}. Seconds must be between 3600 and 2592000 (1 hour to 30 days). + - expires_after: Optional form values describing expiration for the file. :param file: The uploaded file object containing content and metadata (filename, content_type, etc.). :param purpose: The intended purpose of the uploaded file (e.g., "assistants", "fine-tune"). + :param expires_after: Optional form values describing expiration for the file. :returns: An OpenAIFileObject representing the uploaded file. """ ... diff --git a/llama_stack/providers/inline/files/localfs/files.py b/llama_stack/providers/inline/files/localfs/files.py index 65cf8d815..6e0c72de3 100644 --- a/llama_stack/providers/inline/files/localfs/files.py +++ b/llama_stack/providers/inline/files/localfs/files.py @@ -14,6 +14,7 @@ from fastapi import File, Form, Response, UploadFile from llama_stack.apis.common.errors import ResourceNotFoundError from llama_stack.apis.common.responses import Order from llama_stack.apis.files import ( + ExpiresAfter, Files, ListOpenAIFileResponse, OpenAIFileDeleteResponse, @@ -86,14 +87,13 @@ class LocalfsFilesImpl(Files): self, file: Annotated[UploadFile, File()], purpose: Annotated[OpenAIFilePurpose, Form()], - expires_after_anchor: Annotated[str | None, Form(alias="expires_after[anchor]")] = None, - expires_after_seconds: Annotated[int | None, Form(alias="expires_after[seconds]")] = None, + expires_after: Annotated[ExpiresAfter | None, Form()] = None, ) -> OpenAIFileObject: """Upload a file that can be used across various endpoints.""" if not self.sql_store: raise RuntimeError("Files provider not initialized") - if expires_after_anchor is not None or expires_after_seconds is not None: + if expires_after is not None: raise NotImplementedError("File expiration is not supported by this provider") file_id = self._generate_file_id() diff --git a/llama_stack/providers/remote/files/s3/files.py b/llama_stack/providers/remote/files/s3/files.py index 8ea96af9e..8520f70b6 100644 --- a/llama_stack/providers/remote/files/s3/files.py +++ b/llama_stack/providers/remote/files/s3/files.py @@ -195,8 +195,7 @@ class S3FilesImpl(Files): self, file: Annotated[UploadFile, File()], purpose: Annotated[OpenAIFilePurpose, Form()], - expires_after_anchor: Annotated[str | None, Form(alias="expires_after[anchor]")] = None, - expires_after_seconds: Annotated[int | None, Form(alias="expires_after[seconds]")] = None, + expires_after: Annotated[ExpiresAfter | None, Form()] = None, ) -> OpenAIFileObject: file_id = f"file-{uuid.uuid4().hex}" @@ -204,14 +203,6 @@ class S3FilesImpl(Files): created_at = self._now() - expires_after = None - if expires_after_anchor is not None or expires_after_seconds is not None: - # we use ExpiresAfter to validate input - expires_after = ExpiresAfter( - anchor=expires_after_anchor, # type: ignore[arg-type] - seconds=expires_after_seconds, # type: ignore[arg-type] - ) - # the default is no expiration. # to implement no expiration we set an expiration beyond the max. # we'll hide this fact from users when returning the file object. diff --git a/llama_stack/strong_typing/inspection.py b/llama_stack/strong_typing/inspection.py index a75a170cf..42713e371 100644 --- a/llama_stack/strong_typing/inspection.py +++ b/llama_stack/strong_typing/inspection.py @@ -567,6 +567,22 @@ def get_class_properties(typ: type) -> Iterable[Tuple[str, type | str]]: if is_dataclass_type(typ): return ((field.name, field.type) for field in dataclasses.fields(typ)) + elif hasattr(typ, "model_fields"): + # Pydantic BaseModel - use model_fields to exclude ClassVar and other non-field attributes + # Reconstruct Annotated type if discriminator exists to preserve metadata + from typing import Annotated, Any, cast + from pydantic.fields import FieldInfo + + def get_field_type(name: str, field: Any) -> type | str: + # If field has discriminator, wrap in Annotated to preserve it for schema generation + if field.discriminator: + field_info = FieldInfo(annotation=None, discriminator=field.discriminator) + # Annotated returns _AnnotatedAlias which isn't a type but is valid here + return Annotated[field.annotation, field_info] # type: ignore[return-value] + # field.annotation can be Union types, Annotated, etc. which aren't type but are valid + return field.annotation # type: ignore[return-value,no-any-return] + + return ((name, get_field_type(name, field)) for name, field in typ.model_fields.items()) else: resolved_hints = get_resolved_hints(typ) return resolved_hints.items() diff --git a/llama_stack/strong_typing/schema.py b/llama_stack/strong_typing/schema.py index 82baddc86..2bfb7033e 100644 --- a/llama_stack/strong_typing/schema.py +++ b/llama_stack/strong_typing/schema.py @@ -92,7 +92,12 @@ def get_class_property_docstrings( :returns: A dictionary mapping property names to descriptions. """ - result = {} + result: Dict[str, str] = {} + # Only try to get MRO if data_type is actually a class + # Special types like Literal, Union, etc. don't have MRO + if not inspect.isclass(data_type): + return result + for base in inspect.getmro(data_type): docstr = docstring.parse_type(base) for param in docstr.params.values(): diff --git a/tests/unit/providers/files/test_s3_files.py b/tests/unit/providers/files/test_s3_files.py index c665bf124..92a45a9f2 100644 --- a/tests/unit/providers/files/test_s3_files.py +++ b/tests/unit/providers/files/test_s3_files.py @@ -228,12 +228,13 @@ class TestS3FilesImpl: mock_now.return_value = 0 + from llama_stack.apis.files import ExpiresAfter + sample_text_file.filename = "test_expired_file" uploaded = await s3_provider.openai_upload_file( file=sample_text_file, purpose=OpenAIFilePurpose.ASSISTANTS, - expires_after_anchor="created_at", - expires_after_seconds=two_hours, + expires_after=ExpiresAfter(anchor="created_at", seconds=two_hours), ) mock_now.return_value = two_hours * 2 # fast forward 4 hours @@ -259,42 +260,44 @@ class TestS3FilesImpl: async def test_unsupported_expires_after_anchor(self, s3_provider, sample_text_file): """Unsupported anchor value should raise ValueError.""" + from llama_stack.apis.files import ExpiresAfter + sample_text_file.filename = "test_unsupported_expires_after_anchor" with pytest.raises(ValueError, match="Input should be 'created_at'"): await s3_provider.openai_upload_file( file=sample_text_file, purpose=OpenAIFilePurpose.ASSISTANTS, - expires_after_anchor="now", - expires_after_seconds=3600, + expires_after=ExpiresAfter(anchor="now", seconds=3600), # type: ignore ) async def test_nonint_expires_after_seconds(self, s3_provider, sample_text_file): """Non-integer seconds in expires_after should raise ValueError.""" + from llama_stack.apis.files import ExpiresAfter + sample_text_file.filename = "test_nonint_expires_after_seconds" with pytest.raises(ValueError, match="should be a valid integer"): await s3_provider.openai_upload_file( file=sample_text_file, purpose=OpenAIFilePurpose.ASSISTANTS, - expires_after_anchor="created_at", - expires_after_seconds="many", + expires_after=ExpiresAfter(anchor="created_at", seconds="many"), # type: ignore ) async def test_expires_after_seconds_out_of_bounds(self, s3_provider, sample_text_file): """Seconds outside allowed range should raise ValueError.""" + from llama_stack.apis.files import ExpiresAfter + with pytest.raises(ValueError, match="greater than or equal to 3600"): await s3_provider.openai_upload_file( file=sample_text_file, purpose=OpenAIFilePurpose.ASSISTANTS, - expires_after_anchor="created_at", - expires_after_seconds=3599, + expires_after=ExpiresAfter(anchor="created_at", seconds=3599), ) with pytest.raises(ValueError, match="less than or equal to 2592000"): await s3_provider.openai_upload_file( file=sample_text_file, purpose=OpenAIFilePurpose.ASSISTANTS, - expires_after_anchor="created_at", - expires_after_seconds=2592001, + expires_after=ExpiresAfter(anchor="created_at", seconds=2592001), )