diff --git a/docs/_static/llama-stack-spec.html b/docs/_static/llama-stack-spec.html index db5c57821..03b0f4152 100644 --- a/docs/_static/llama-stack-spec.html +++ b/docs/_static/llama-stack-spec.html @@ -5588,6 +5588,28 @@ "additionalProperties": { "$ref": "#/components/schemas/ToolParamDefinition" } + }, + "annotations": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "read_only_hint": { + "type": "boolean" + }, + "destructive_hint": { + "type": "boolean" + }, + "idempotent_hint": { + "type": "boolean" + }, + "open_world_hint": { + "type": "boolean" + } + }, + "additionalProperties": false, + "title": "ToolAnnotations" } }, "additionalProperties": false, @@ -6488,6 +6510,28 @@ } ] } + }, + "annotations": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "read_only_hint": { + "type": "boolean" + }, + "destructive_hint": { + "type": "boolean" + }, + "idempotent_hint": { + "type": "boolean" + }, + "open_world_hint": { + "type": "boolean" + } + }, + "additionalProperties": false, + "title": "ToolAnnotations" } }, "additionalProperties": false, @@ -8502,6 +8546,28 @@ }, "description": { "type": "string" + }, + "annotations": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "read_only_hint": { + "type": "boolean" + }, + "destructive_hint": { + "type": "boolean" + }, + "idempotent_hint": { + "type": "boolean" + }, + "open_world_hint": { + "type": "boolean" + } + }, + "additionalProperties": false, + "title": "ToolAnnotations" } }, "additionalProperties": false, @@ -11027,6 +11093,28 @@ } ] } + }, + "annotations": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "read_only_hint": { + "type": "boolean" + }, + "destructive_hint": { + "type": "boolean" + }, + "idempotent_hint": { + "type": "boolean" + }, + "open_world_hint": { + "type": "boolean" + } + }, + "additionalProperties": false, + "title": "ToolAnnotations" } }, "additionalProperties": false, diff --git a/docs/_static/llama-stack-spec.yaml b/docs/_static/llama-stack-spec.yaml index 29ba9dede..05dc70796 100644 --- a/docs/_static/llama-stack-spec.yaml +++ b/docs/_static/llama-stack-spec.yaml @@ -3940,6 +3940,21 @@ components: type: object additionalProperties: $ref: '#/components/schemas/ToolParamDefinition' + annotations: + type: object + properties: + title: + type: string + read_only_hint: + type: boolean + destructive_hint: + type: boolean + idempotent_hint: + type: boolean + open_world_hint: + type: boolean + additionalProperties: false + title: ToolAnnotations additionalProperties: false required: - tool_name @@ -4638,6 +4653,21 @@ components: - type: string - type: array - type: object + annotations: + type: object + properties: + title: + type: string + read_only_hint: + type: boolean + destructive_hint: + type: boolean + idempotent_hint: + type: boolean + open_world_hint: + type: boolean + additionalProperties: false + title: ToolAnnotations additionalProperties: false required: - name @@ -5990,6 +6020,21 @@ components: type: string description: type: string + annotations: + type: object + properties: + title: + type: string + read_only_hint: + type: boolean + destructive_hint: + type: boolean + idempotent_hint: + type: boolean + open_world_hint: + type: boolean + additionalProperties: false + title: ToolAnnotations additionalProperties: false required: - input_schema @@ -7768,6 +7813,21 @@ components: - type: string - type: array - type: object + annotations: + type: object + properties: + title: + type: string + read_only_hint: + type: boolean + destructive_hint: + type: boolean + idempotent_hint: + type: boolean + open_world_hint: + type: boolean + additionalProperties: false + title: ToolAnnotations additionalProperties: false required: - identifier diff --git a/llama_stack/apis/agents/openai_responses.py b/llama_stack/apis/agents/openai_responses.py index 10843a3fe..c4e7e3726 100644 --- a/llama_stack/apis/agents/openai_responses.py +++ b/llama_stack/apis/agents/openai_responses.py @@ -10,6 +10,7 @@ from pydantic import BaseModel, Field from typing_extensions import TypedDict from llama_stack.apis.vector_io import SearchRankingOptions as FileSearchRankingOptions +from llama_stack.models.llama.datatypes import ToolAnnotations from llama_stack.schema_utils import json_schema_type, register_schema # NOTE(ashwin): this file is literally a copy of the OpenAI responses API schema. We should probably @@ -161,6 +162,7 @@ class MCPListToolsTool(BaseModel): input_schema: dict[str, Any] name: str description: str | None = None + annotations: ToolAnnotations | None = None @json_schema_type diff --git a/llama_stack/apis/tools/tools.py b/llama_stack/apis/tools/tools.py index 7d1eeeefb..4cba418cc 100644 --- a/llama_stack/apis/tools/tools.py +++ b/llama_stack/apis/tools/tools.py @@ -12,6 +12,7 @@ from typing_extensions import runtime_checkable from llama_stack.apis.common.content_types import URL, InterleavedContent from llama_stack.apis.resource import Resource, ResourceType +from llama_stack.models.llama.datatypes import ToolAnnotations from llama_stack.providers.utils.telemetry.trace_protocol import trace_protocol from llama_stack.schema_utils import json_schema_type, webmethod @@ -34,6 +35,7 @@ class Tool(Resource): description: str parameters: list[ToolParameter] metadata: dict[str, Any] | None = None + annotations: ToolAnnotations | None = None @json_schema_type @@ -42,6 +44,7 @@ class ToolDef(BaseModel): description: str | None = None parameters: list[ToolParameter] | None = None metadata: dict[str, Any] | None = None + annotations: ToolAnnotations | None = None @json_schema_type diff --git a/llama_stack/distribution/routing_tables/toolgroups.py b/llama_stack/distribution/routing_tables/toolgroups.py index b86f057bd..453e5c2e7 100644 --- a/llama_stack/distribution/routing_tables/toolgroups.py +++ b/llama_stack/distribution/routing_tables/toolgroups.py @@ -74,6 +74,7 @@ class ToolGroupsRoutingTable(CommonRoutingTableImpl, ToolGroups): parameters=t.parameters or [], metadata=t.metadata, provider_id=toolgroup.provider_id, + annotations=t.annotations, ) ) diff --git a/llama_stack/models/llama/datatypes.py b/llama_stack/models/llama/datatypes.py index 7f1ebed55..ffdcd47fb 100644 --- a/llama_stack/models/llama/datatypes.py +++ b/llama_stack/models/llama/datatypes.py @@ -95,10 +95,19 @@ class ToolParamDefinition(BaseModel): default: Any | None = None +class ToolAnnotations(BaseModel): + title: str | None = None + read_only_hint: bool | None = Field(default=None, alias="readOnlyHint") + destructive_hint: bool | None = Field(default=None, alias="destructiveHint") + idempotent_hint: bool | None = Field(default=None, alias="idempotentHint") + open_world_hint: bool | None = Field(default=None, alias="openWorldHint") + + class ToolDefinition(BaseModel): tool_name: BuiltinTool | str description: str | None = None parameters: dict[str, ToolParamDefinition] | None = None + annotations: ToolAnnotations | None = None @field_validator("tool_name", mode="before") @classmethod diff --git a/llama_stack/providers/inline/agents/meta_reference/agent_instance.py b/llama_stack/providers/inline/agents/meta_reference/agent_instance.py index 4d2b9f8bf..b275dff5f 100644 --- a/llama_stack/providers/inline/agents/meta_reference/agent_instance.py +++ b/llama_stack/providers/inline/agents/meta_reference/agent_instance.py @@ -800,6 +800,7 @@ class ChatAgent(ShieldRunnerMixin): ) for param in tool_def.parameters }, + annotations=tool_def.annotations, ) for toolgroup_name_with_maybe_tool_name in agent_config_toolgroups: toolgroup_name, input_tool_name = self._parse_toolgroup_name(toolgroup_name_with_maybe_tool_name) @@ -843,6 +844,7 @@ class ChatAgent(ShieldRunnerMixin): ) for param in tool_def.parameters }, + annotations=tool_def.annotations, ) tool_name_to_args[tool_def.identifier] = toolgroup_to_args.get(toolgroup_name, {}) diff --git a/llama_stack/providers/inline/agents/meta_reference/openai_responses.py b/llama_stack/providers/inline/agents/meta_reference/openai_responses.py index 7eb2b3897..1ea0c419f 100644 --- a/llama_stack/providers/inline/agents/meta_reference/openai_responses.py +++ b/llama_stack/providers/inline/agents/meta_reference/openai_responses.py @@ -671,6 +671,7 @@ class OpenAIResponsesImpl: }, "required": [p.name for p in t.parameters if p.required], }, + annotations=t.annotations, ) ) else: diff --git a/llama_stack/providers/utils/tools/mcp.py b/llama_stack/providers/utils/tools/mcp.py index fbf992c82..e1591daac 100644 --- a/llama_stack/providers/utils/tools/mcp.py +++ b/llama_stack/providers/utils/tools/mcp.py @@ -57,6 +57,7 @@ async def list_mcp_tools(endpoint: str, headers: dict[str, str]) -> ListToolDefs description=param_schema.get("description", ""), ) ) + annotations = getattr(tool, "annotations", None) tools.append( ToolDef( name=tool.name, @@ -65,6 +66,7 @@ async def list_mcp_tools(endpoint: str, headers: dict[str, str]) -> ListToolDefs metadata={ "endpoint": endpoint, }, + annotations=annotations, ) ) return ListToolDefsResponse(data=tools)