From 803be7fef01c8af72305ef69ca7ea060b129695c Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Wed, 5 Mar 2025 13:13:43 -0800 Subject: [PATCH 01/18] Updates to draft 1.0 --- RFC.md | 389 ++++++++++----- .../http/1.0/execute_tool_request.schema.json | 73 --- .../1.0/execute_tool_response.schema.json | 153 ------ specification/http/1.0/openapi.json | 456 ++++++++++++++++++ .../http/1.0/tool_definition.schema.json | 207 -------- 5 files changed, 724 insertions(+), 554 deletions(-) delete mode 100644 specification/http/1.0/execute_tool_request.schema.json delete mode 100644 specification/http/1.0/execute_tool_response.schema.json create mode 100644 specification/http/1.0/openapi.json delete mode 100644 specification/http/1.0/tool_definition.schema.json diff --git a/RFC.md b/RFC.md index 4341597..e606bc3 100644 --- a/RFC.md +++ b/RFC.md @@ -4,148 +4,164 @@ ## Abstract -This document specifies the Open Tool Calling Standard, a comprehensive communication layer for agents calling tools. It defines the structures and protocols used to describe tools, initiate tool calls, and process responses. The standard is based on a set of JSON schemas that govern tool definitions, tool requests, and tool responses. It aims to provide a unified, extensible, and interoperable framework for agent-to-tool interactions. +This document specifies the Open Tool Calling (OTC) standard, a comprehensive communication protocol for AI agents (clients) calling tools. It defines the structures and protocols used to describe tools, initiate tool calls, and process responses. The standard is comprised of JSON and OpenAPI schemas that govern tool definitions, tool requests, and tool responses. It aims to provide a unified, extensible, and interoperable framework for client-to-tool interactions. + +## Editors + +- Nate Barbettini ([@nbarbettini](https://github.com/nbarbettini)) +- Eugene Yurtsev ([@eyurtsev](https://github.com/eyurtsev)) +- Sam Partee ([@spartee](https://github.com/spartee)) --- ## Table of Contents -1. [Introduction](#introduction) -2. [Terminology](#terminology) -3. [Architecture Overview](#architecture-overview) -4. [Schema Definitions](#schema-definitions) - - [Tool Definition Schema](#tool-definition-schema) - - [Tool Request Schema](#tool-request-schema) - - [Tool Response Schema](#tool-response-schema) -5. [Communication Flow](#communication-flow) -6. [Security and Authorization](#security-and-authorization) -7. [Extensibility and Versioning](#extensibility-and-versioning) -8. [Conclusion](#conclusion) -9. [References](#references) +1. [Introduction](#1-introduction) +2. [Terminology](#2-terminology) +3. [Architecture Overview](#3-architecture-overview) +4. [Schema Definitions](#4-schema-definitions) + - [Tool Definition Schema](#41-tool-definition-schema) + - [Tool Request Schema](#42-tool-request-schema) + - [Tool Response Schema](#43-tool-response-schema) +5. [Communication Flows](#5-communication-flows) +6. [Security and Authorization](#6-security-and-authorization) +7. [Extensibility and Versioning](#7-extensibility-and-versioning) +8. [Conclusion](#8-conclusion) +9. [References](#9-references) --- ## 1. Introduction -The Open Tool Calling Standard establishes a set of protocols and formats to facilitate communication between agents (clients) and tools (services) in distributed systems. It ensures that tool definitions, requests, and responses adhere to a structured and open standard. This RFC presents detailed JSON schema specifications that serve as the backbone for this standard, enabling uniform interpretation and execution of tool interactions. - ---- +The Open Tool Calling standard establishes a set of protocols and formats to facilitate communication between agents (clients) and tools (functions or services) in distributed systems. It ensures that tool definitions, requests, and responses adhere to a structured and open standard. This RFC presents detailed JSON and OpenAPI schema specifications that serve as the backbone for this standard, enabling uniform interpretation and execution of tool interactions. ## 2. Terminology -- **Agent:** An entity that issues requests to tools for performing specific tasks. -- **Tool:** A service or function that can be invoked by an agent using the defined protocols. +- **Client:** An entity that issues requests to tools for performing specific tasks. +- **Tool:** A service or function that can be executed (called) by a client using the defined protocols. - **Schema:** A formal description of the data structure, typically expressed in JSON Schema, used to validate data formats. -- **RFC:** Request for Comments; a document that describes methods, behaviors, research, or innovations applicable to the Internet. - **Toolkit:** A collection of tools grouped under a common framework and versioned accordingly. - **JSON Schema:** A vocabulary that allows you to annotate and validate JSON documents. ---- - ## 3. Architecture Overview -The Open Tool Calling Standard is designed around three key components: +The Open Tool Calling standard is designed around three key components: -1. **Tool Definition:** A schema that specifies how a tool is described. It includes metadata such as the tool's name, fully qualified name, toolkit information, and the input/output specifications. +1. **Tool Definition:** A schema that specifies how a tool is described. It includes metadata such as the tool's name, unique identifier, toolkit information, and the input/output specifications. 2. **Tool Request:** A schema that details the structure of a tool call. It encompasses the run identifier, execution context, tool metadata, and input parameters. 3. **Tool Response:** A schema that outlines the structure of the response returned after a tool execution. It provides details on execution status, duration, and the actual output (or errors) of the tool call. -These components ensure consistent communication between agents and tools, regardless of the implementation details of each tool. +These components ensure consistent communication between clients and tools, regardless of the implementation details of each tool. ```mermaid sequenceDiagram - participant A as Agent - participant R as Registry + participant C as Client + participant S as OTC Server participant T as Tool - %% Tool Registration - A->>R: Submit Tool Definition (JSON Schema) - R-->>A: Acknowledge Registration + ## Health check + C->>S: Request health check + S-->>C: Health check response - %% Tool Invocation - A->>T: Send Tool Request (run_id, execution_id, inputs, context) - T->>T: Validate Request & Process Execution - Note right of T: Includes authorization and secrets handling - T-->>A: Return Tool Response (success, value/error/artifact, duration) + %% Tool discovery + C->>S: Request tool list + S-->>C: List of available tools - %% Post Execution - A->>R: Optionally update tool status/log (if applicable) + %% Tool execution + C->>S: Send execution request + Note left of C: Resolve requirements (such as authorization) + S->>T: Execute tool (function) + T-->>S: Return tool response + S-->>C: Return tool response ``` ---- - ## 4. Schema Definitions ### 4.1 Tool Definition Schema The Tool Definition Schema establishes the properties and required fields to describe a tool. It consists of the following sections: -- **Metadata:** +#### Metadata - - **`$schema`**: URI defining the JSON Schema version. - - **`name`**: A human-readable name for the tool. - - **`fully_qualified_name`**: A unique identifier for the tool. - - **`description`**: A human-readable explanation of the tool's purpose. +- **`id`**: A unique identifier for the tool, in the following format: `ToolkitName.ToolName@Version`. For example, `MyToolkit.MyTool@1.0.0`. +- **`name`**: A human-readable name for the tool. For example, 'MyTool'. +- **`description`**: A human-readable explanation of the tool's purpose. This field can be used by both humans and AI models. -- **Toolkit Information:** +#### Toolkit Information - - **`toolkit`**: Contains the toolkit’s name, description, and version. +- **`toolkit`**: Contains the toolkit's name, description, and version. -- **Input Schema:** +#### Input Schema - - **`input`**: Describes the parameters accepted by the tool. - - Each parameter includes: - - **`name`**: Parameter name. - - **`required`**: Boolean indicating whether the parameter is mandatory. - - **`description`**: Explanation of the parameter. - - **`value_schema`**: Data type and structure details (including support for arrays with inner type definitions). - - **`inferrable`**: (Optional) Indicates if the value can be inferred automatically. +**`input`**: Describes the input parameters for the tool. -- **Output Schema:** +- **`parameters`**: A JSON Schema object that describes the input parameters for the tool. +- **`non_inferrable_parameters`** (optional): A list of parameter names that MUST NOT be inferred by a model. If this array is empty, it is assumed that all parameters are inferrable. - - **`output`**: Specifies the expected result of the tool execution. - - **`available_modes`**: A list of modes such as `value`, `error`, `artifact`, etc. - - **`description`**: Human-readable explanation of the output. - - **`value_schema`**: Defines the data type and structure of the output value. +`non_inferrable_parameters` allows tool developers to "hide" certain parameters from an AI model. For example, a tool that has an `is_admin` parameter can indicate that this parameter is required but that a model should not be trusted to infer its value. In this case, the client is still responsible for passing the parameter. -- **Requirements:** - - **`requirements`**: Describes authorization or secret requirements. - - **`secrets`**: Array of secret definitions. - - **`authorization`**: Specifies required authorization methods (e.g., token-based). +#### Output Schema -The complete JSON Schema ensures that every tool adheres to a well-defined structure, facilitating consistent tool registration and discovery. +- **`output`** (optional): Specifies the expected result of the tool execution. ---- + - **`available_modes`**: A list of modes such as `value`, `error`, `null`, etc. If `value` is present, the `output.value` field MUST be present. + - **`description`** (optional): Human-readable explanation of the output. + - **`value`** (optional): A JSON Schema object that describes the output parameters for the tool. + +#### Requirements + +**`requirements`** (optional): Describes any requirements or prerequisites needed for the tool to execute (e.g. authorization, secrets, etc.) + +The `requirements` field describes tool requirements that are not strictly input parameters, such as the API key needed to call a target API. If the `requirements` field is not present, the client must assume that the tool can be executed without passing any additional information. + +**`requirements.authorization`** (optional): Declares one or more required authorization methods. + +Each required authorization method is described as an object with the following properties: + +- **`id`**: A unique identifier for the authorization method or authorization provider. +- **`oauth2`** (optional): For tools that require OAuth 2.0-based authorization, this field contains the OAuth 2.0-specific authorization details. + - **`scopes`**: A list of scopes that must be granted for the tool to execute properly. + +**`requirements.secrets`** (optional): Declares one or more secrets that are required for the tool to execute. + +Each required secret is described as an object with the following properties: + +- **`id`**: A unique identifier for the secret. + +#### Non-Normative Examples + +TODO ### 4.2 Tool Request Schema -The Tool Request Schema is designed to encapsulate the details of a tool invocation: +The Tool Request Schema is designed to encapsulate the details of a tool execution (tool call): - **Run and Execution Identification:** - - **`run_id`**: Globally unique identifier for the overall run. - - **`execution_id`**: Unique identifier for the specific tool execution. - - **`created_at`**: Timestamp indicating when the request was created. + - **`execution_id`**: Globally unique identifier for this tool execution. + - **`trace_id`** (optional): Unique identifier for the trace of the tool execution, if supplied by the client. - **Tool Metadata:** - - **`tool`**: Contains the tool's name, the toolkit to which it belongs, and the toolkit version. + - **`tool_id`**: The unique identifier of the tool to call. - **Input Parameters:** - - **`inputs`**: An object containing the parameters needed by the tool. This field supports additional properties to accommodate various tool-specific inputs. + - **`inputs`**: An unconstrained object containing the parameters needed by the tool. - **Context:** - **`context`**: Provides additional execution context including: - - **`authorization`**: Contains tokens for authentication. - - **`secrets`**: Secret information required for execution. - - **`user_id`**: Unique user identifier. - - **`user_info`**: Supplementary information provided by the authorization server. + - **`authorization`** (optional): Contains tokens for authentication. + - **`secrets`** (optional): Secret information required for execution. + - **`user_id`** (optional): Unique user identifier. + - **`user_info`** (optional): Supplementary information provided by the authorization server. This schema guarantees that every tool call is uniquely identifiable and that the necessary parameters and context for execution are clearly provided. ---- +#### Non-Normative Examples + +TODO ### 4.3 Tool Response Schema @@ -154,9 +170,8 @@ The Tool Response Schema defines the structure of the data returned after a tool - **Execution Metadata:** - **`execution_id`**: The globally unique execution identifier. - - **`duration`**: Execution time in milliseconds. - - **`finished_at`**: Timestamp marking the completion of the execution. - **`success`**: Boolean flag indicating the success or failure of the execution. + - **`duration`** (optional): Execution time in milliseconds. - **Output Content:** The output can take one of several forms: @@ -165,86 +180,218 @@ The Tool Response Schema defines the structure of the data returned after a tool 2. **Error Response:** - Contains an `error` object with: - **`message`**: A user-facing error message. - - **`developer_message`**: Detailed error information for internal debugging. - - **`can_retry`**: Indicates if the request is retryable. - - **`additional_prompt_content`**: Extra content to be used for retry prompts. - - **`retry_after_ms`**: Suggested delay before retrying. - 3. **Authorization Response:** - - Contains a `requires_authorization` object detailing: - - **`id`**: Identifier for tracking authorization status. - - **`url`**: Redirect URL for obtaining authorization. - - **`scopes`**: Array of authorization scopes required. - - **`status`**: Current authorization status. - 4. **Artifact Response:** - - Contains an `artifact` object describing: - - **`url`**: Location of the stored artifact. - - **`content_type`**: MIME type of the artifact. - - **`size`**: Size of the artifact in bytes. - - **`meta`**: Metadata including a human-readable description. + - **`developer_message`** (optional): Detailed error information for internal debugging. + - **`can_retry`** (optional): Indicates if the request can be retried by the client. If unspecified, the client MUST assume the request cannot be retried (`false`). + - **`additional_prompt_content`** (optional): Extra content to be used for retry prompts. + - **`retry_after_ms`** (optional): Suggested delay before retrying. The Tool Response Schema ensures that every response provides clear and actionable information regarding the outcome of the tool call. ---- +#### Non-Normative Examples -## 5. Communication Flow +TODO -1. **Tool Registration:** +## 5. Communication Flows - - Tools register themselves using the Tool Definition Schema. - - Registries use this information for tool discovery and client-side validation. +The Open Tool Calling (OTC) standard defines clear communication flows that enable clients to discover available tools and execute them. The flows below follow the definitions in the OpenAPI specification (`specification/http/1.0/openapi.json`), ensuring that all tool interactions are consistent, secure, and standardized. -2. **Invocation:** +### 5.1 Server Health Check - - An agent creates a tool request following the Tool Request Schema. - - The request includes necessary input parameters, context, and unique identifiers for tracking. +An OTC server MUST implement a health check endpoint that returns a 200 OK response if the server is healthy. -3. **Execution:** +#### Flow Details: - - The tool processes the request based on its implementation and the provided schema. - - Execution metrics such as duration and timestamps are recorded. +- **Request:** + - **Method:** GET + - **Endpoint:** `/health` +- **Response:** + - **Status Code:** 200 OK -4. **Response:** - - Upon completion, the tool returns a response conforming to the Tool Response Schema. - - The response provides either a successful output, an error, authorization instructions, or artifact information. +### 5.2 Tool Discovery ---- +Clients retrieve tool definitions from the OTC server using the `/tools` endpoint. This flow provides a catalog of tools that clients can use, all of which conform to the `ToolDefinition` schema. + +#### Flow Details: + +- **Request:** + - **Method:** GET + - **Endpoint:** `/tools` + - **Security:** Servers MAY require bearer authentication (JWT). Servers that are internet-facing SHOULD require authentication. +- **Response:** + - **Status Code:** 200 OK + - **Content:** A JSON object that includes a `$schema` URI reference (indicating the standard version) and a `tools` array. Each element in the array is a complete tool definition. + +#### Non-Normative Example: Tool Discovery + +**Request:** + +```http +GET /tools HTTP/1.1 +Host: api.example.com +Authorization: Bearer +``` + +**Response:** + +```json +{ + "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", + "tools": [ + { + "id": "Calculator.Add@1.0.0", + "name": "Add", + "description": "Add two numbers together", + "toolkit": { + "name": "Calculator", + "description": "A toolkit for performing calculations.", + "version": "1.0.0" + }, + "input": { + "parameters": { + "type": "object", + "properties": { + "a": { + "type": "number", + "description": "The first number to add." + }, + "b": { + "type": "number", + "description": "The second number to add." + } + } + }, + "required": ["a", "b"] + }, + "output": { + "available_modes": ["value", "error"], + "description": "The result produced by the tool.", + "value": { + "parameters": { + "type": "object", + "properties": { + "result": { + "type": "number", + "description": "The sum of the two numbers." + } + } + } + } + } + } + ] +} +``` + +### 5.2 Tool Execution + +Tool execution is initiated by sending a POST request to the `/execute` endpoint. This flow lets clients run a tool and receive its output, with the request and response bodies conforming to the `ExecuteToolRequest` and `ExecuteToolResponse` schemas. + +#### Flow Details: + +- **Request:** + - **Method:** POST + - **Endpoint:** `/execute` + - **Security:** Servers MAY require bearer authentication (JWT). Servers that are internet-facing SHOULD require authentication. + - **Payload:** A JSON document with two main parts: + - **`$schema` Field:** A URI reference to the standard. + - **`request` Object:** Includes: + - **`execution_id`** (required): A unique identifier for this execution. + - **`tool_id`** (required): The unique identifier of the tool to be executed. + - **`input`** (optional): An object providing the necessary input parameters. + - **`context`** (optional): An object containing authorization tokens, secrets (if any), and user-specific data. +- **Response:** + - **Status Code:** 200 OK + - **Content:** A JSON document following the `ExecuteToolResponse` schema, which includes: + - **`execution_id`** (required): Echoes the unique identifier from the request. + - **`success`** (required): A Boolean indicating execution success. + - **`duration`** (optional): The time taken for execution (in milliseconds). + - **`output`** (optional): For tools that return a value, this field contains the value. For tools that return an error, this field contains an `error` object. + +#### Non-Normative Example: Tool Execution + +**Request:** + +```http +POST /execute HTTP/1.1 +Host: api.example.com +Content-Type: application/json +Authorization: Bearer + +{ + "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", + "request": { + "execution_id": "123e4567-e89b-12d3-a456-426614174000", + "tool_id": "Calculator.Add@1.0.0", + "input": { + "a": 1, + "b": 2 + } + } +} +``` + +**Response (Successful Execution):** + +```json +{ + "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", + "execution_id": "123e4567-e89b-12d3-a456-426614174000", + "duration": 2, + "success": true, + "output": { + "value": 3 + } +} +``` + +**Response (Error Case):** + +```json +{ + "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", + "execution_id": "123e4567-e89b-12d3-a456-426614174000", + "success": false, + "output": { + "error": { + "message": "Invalid input parameter", + "developer_message": "Parameter 'b' is missing or formatted incorrectly.", + "can_retry": false + } + } +} +``` ## 6. Security and Authorization -Security is a critical component of the Open Tool Calling Standard. The following measures are incorporated: +Security is a critical component of the Open Tool Calling standard. The following measures are incorporated: - **Authorization:** Tools may require token-based or other forms of authorization, as specified in the `requirements.authorization` field of the Tool Definition Schema. - **Secrets Management:** - Sensitive information is handled via the `requirements.secrets` field. + Sensitive information such as API keys, passwords, and other credentials is handled via the `requirements.secrets` field. - **Contextual Security:** The Tool Request Schema includes contextual information such as user identity and authorization tokens, which help ensure secure execution. -These security measures are intended to protect the integrity of tool interactions and ensure that only authorized agents can invoke tool functions. +These security measures are intended to protect the integrity of tool interactions and ensure that only authorized clients can execute tools. ---- +TODO describe client->server security. ## 7. Extensibility and Versioning - **Extensibility:** - The Open Tool Calling Standard is designed to be extensible. + The Open Tool Calling standard is designed to be extensible. - New parameters or response types can be added as additional properties in the respective schemas. - - The use of JSON Schema allows for backward-compatible extensions. + - The use of JSON-Schema allows for backward-compatible extensions. - **Versioning:** - - Each toolkit and tool definition must include a version identifier. - - The `$schema` field in each schema helps ensure that both agents and tools are interpreting data according to the correct schema version. + - Each server response must include a `$schema` field that references the version of the Open Tool Calling standard that was used to generate the response. Proper versioning guarantees that changes to the standard do not disrupt existing implementations. ---- - ## 8. Conclusion -The Open Tool Calling Standard provides a robust framework for agent-to-tool communications. By standardizing tool definitions, request formats, and response structures, this standard promotes interoperability, consistency, and security in distributed systems. Adoption of this standard will facilitate seamless integration between diverse agents and tools across multiple platforms. - ---- +The Open Tool Calling standard provides a robust framework for client-to-tool communications. By standardizing tool definitions, request formats, and response structures, this standard promotes interoperability, consistency, and security in distributed systems. Adoption of this standard will facilitate seamless integration between diverse clients and tools across multiple platforms. ## 9. References diff --git a/specification/http/1.0/execute_tool_request.schema.json b/specification/http/1.0/execute_tool_request.schema.json deleted file mode 100644 index 48eb0f7..0000000 --- a/specification/http/1.0/execute_tool_request.schema.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "$schema": { - "type": "string", - "format": "uri" - }, - "run_id": { - "type": "string", - "description": "The globally-unique run ID provided by the Engine." - }, - "execution_id": { - "type": "string", - "description": "The globally-unique ID for this tool execution in the run." - }, - "created_at": { - "type": "string", - "format": "date-time" - }, - "tool": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the tool to call (invoke)" - }, - "toolkit": { - "type": "string", - "description": "Name of the toolkit containing the tool to call" - }, - "version": { - "type": "string", - "description": "Version of the toolkit containing the tool to call" - } - }, - "required": ["name", "toolkit", "version"], - "additionalProperties": false - }, - "inputs": { - "type": "object", - "additionalProperties": true - }, - "context": { - "type": "object", - "properties": { - "authorization": { - "type": "object", - "properties": { - "token": { - "type": "string" - }, - "additionalProperties": false - } - }, - "secrets": { - "type": "object", - "additionalProperties": true - }, - "user_id": { - "type": "string", - "description": "A unique ID that identifies the user (if any)" - }, - "user_info": { - "type": "object", - "description": "The user information provided by the authorization server (if any)" - } - } - } - }, - "required": ["run_id", "execution_id", "created_at", "tool", "inputs", "context"], - "additionalProperties": false -} diff --git a/specification/http/1.0/execute_tool_response.schema.json b/specification/http/1.0/execute_tool_response.schema.json deleted file mode 100644 index a17cf8e..0000000 --- a/specification/http/1.0/execute_tool_response.schema.json +++ /dev/null @@ -1,153 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "$schema": { - "type": "string", - "format": "uri" - }, - "execution_id": { - "type": "string", - "description": "The globally-unique ID for this tool execution." - }, - "duration": { - "type": "number", - "description": "The duration of the tool call, in milliseconds" - }, - "finished_at": { - "type": "string", - "format": "date-time", - "description": "The timestamp when the tool execution finished." - }, - "success": { - "type": "boolean", - "description": "Whether the tool execution was successful" - }, - "output": { - "type": "object", - "oneOf": [ - { - "properties": { - "value": { - "description": "The value returned from the function", - "oneOf": [ - { "type": "object", "additionalProperties": true }, - { "type": "number" }, - { "type": "string" }, - { "type": "boolean" } - ] - } - }, - "required": ["value"], - "additionalProperties": false - }, - { - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "An error message that can be shown to the user or the AI model" - }, - "developer_message": { - "type": "string", - "description": "An internal message that will be logged but will not be shown to the user or the AI model" - }, - "can_retry": { - "type": "boolean", - "description": "Whether the tool call can be retried", - "default": false - }, - "additional_prompt_content": { - "type": "string", - "description": "Additional content to be included in the retry prompt" - }, - "retry_after_ms": { - "type": "integer", - "description": "The number of milliseconds (if any) to wait before retrying the tool call" - } - }, - "required": ["message"], - "additionalProperties": false - } - }, - "required": ["error"], - "additionalProperties": false - }, - { - "properties": { - "requires_authorization": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "The ID for checking the status of the authorization" - }, - "url": { - "type": "string", - "format": "uri", - "description": "The URL to redirect the user to for authorization" - }, - "scopes": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The scopes that are required for authorization" - }, - "status": { - "type": "string", - "description": "The status of the authorization" - } - }, - "required": ["id", "status"], - "additionalProperties": false - } - }, - "required": ["requires_authorization"], - "additionalProperties": false - }, - { - "properties": { - "artifact": { - "type": "object", - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "The location of the stored artifact" - }, - "content_type": { - "type": "string", - "description": "The MIME Media Type of the data inside the artifact (e.g. text/csv or application/json)" - }, - "size": { - "type": "integer", - "description": "The size of the artifact, in bytes" - }, - "meta": { - "type": "object", - "properties": { - "description": { - "type": "string", - "description": "A descriptive, human-readable explanation of the data inside the artifact" - } - }, - "required": ["description"], - "additionalProperties": false - } - }, - "required": ["url", "content_type", "size", "meta"], - "additionalProperties": false - } - }, - "required": ["artifact"], - "additionalProperties": false - } - ] - } - }, - "required": ["invocation_id", "finished_at", "success"], - "additionalProperties": false -} diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json new file mode 100644 index 0000000..b320202 --- /dev/null +++ b/specification/http/1.0/openapi.json @@ -0,0 +1,456 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Open Tool Calling Standard", + "version": "1.0.0", + "description": "A standard for calling tools (functions or services) in a distributed system.", + "contact": { + "name": "Arcade.dev", + "url": "https://arcade.dev", + "email": "dev@arcade.dev" + } + }, + "paths": { + "/health": { + "get": { + "summary": "Check health", + "description": "Checks the health status of the server.", + "responses": { + "200": { + "description": "Server is healthy." + } + } + } + }, + "/tools": { + "get": { + "summary": "List tools", + "description": "Returns a list of tool definitions.", + "security": [ + { + "bearerAuth": [] + }, + {} + ], + "responses": { + "200": { + "description": "A list of available tools.", + "content": { + "application/json": { + "schema": { + "properties": { + "$schema": { + "type": "string", + "format": "uri" + }, + "tools": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ToolDefinition" + } + } + } + } + } + } + } + } + } + }, + "/execute": { + "post": { + "summary": "Execute tool", + "description": "Executes a tool with the given parameters.", + "security": [ + { + "bearerAuth": [] + }, + {} + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "properties": { + "$schema": { + "type": "string", + "format": "uri" + }, + "request": { + "$ref": "#/components/schemas/ExecuteToolRequest" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Execution response from tool.", + "content": { + "application/json": { + "schema": { + "properties": { + "$schema": { + "type": "string", + "format": "uri" + }, + "response": { + "$ref": "#/components/schemas/ExecuteToolResponse" + } + } + } + } + } + } + } + } + }, + "components": { + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + }, + "schemas": { + "ToolId": { + "type": "string", + "description": "A tool's unique identifier in the format 'Toolkit.Tool[@version]', where @version is optional.", + "pattern": "^[A-Za-z0-9_]+\\.[A-Za-z0-9_]+(@[A-Za-z0-9_.\\-]+)?$", + "examples": [ + "MyToolkit.MyTool", + "MyToolkit.MyTool@1.0", + "Calculator.Add@latest" + ] + }, + "ToolSecret": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The secret's unique identifier." + }, + "value": { + "type": "string", + "description": "The secret's value." + } + }, + "required": ["id", "value"], + "additionalProperties": false + }, + "SimpleJSONSchema": { + "type": "object", + "properties": { + "type": "object", + "additionalProperties": true, + "not": { + "properties": { + "$ref": {}, + "$defs": {}, + "definitions": {} + } + } + } + }, + "ToolDefinition": { + "type": "object", + "properties": { + "id": { + "$ref": "#/components/schemas/ToolId" + }, + "name": { + "type": "string", + "description": "The tool's name." + }, + "description": { + "type": "string", + "description": "A human-readable explanation of the tool's purpose. This field can be used by both humans and AI models." + }, + "toolkit": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the toolkit." + }, + "description": { + "type": "string", + "description": "A human-readable description of the toolkit." + }, + "version": { + "type": "string", + "description": "An identifier for this version of the toolkit." + } + }, + "required": ["name", "description"], + "additionalProperties": false + }, + "input": { + "type": "object", + "properties": { + "parameters": { + "$ref": "#/components/schemas/SimpleJSONSchema", + "description": "JSON Schema describing the input parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity.", + "additionalProperties": true, + "required": ["name", "description"] + }, + "non_inferrable_parameters": { + "type": "array", + "description": "A list of parameter names that must not be inferred by a model.", + "items": { + "type": "string" + } + } + }, + "required": ["parameters"], + "additionalProperties": false + }, + "output": { + "type": "object", + "properties": { + "available_modes": { + "type": "array", + "items": { + "type": "string", + "enum": ["value", "error", "null"] + } + }, + "description": { + "type": "string", + "description": "A descriptive, human-readable explanation of the function's output." + }, + "value": { + "type": "object", + "properties": { + "parameters": { + "$ref": "#/components/schemas/SimpleJSONSchema", + "description": "JSON Schema describing the output parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity." + } + } + } + }, + "required": ["available_modes"], + "allOf": [ + { + "if": { + "properties": { + "available_modes": { + "contains": { "const": "value" } + } + } + }, + "then": { + "required": ["value"] + } + } + ], + "additionalProperties": false + }, + "requirements": { + "type": "object", + "properties": { + "authorization": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "A provider's unique identifier, allowing the tool to specify a specific authorization provider." + }, + "oauth2": { + "type": "object", + "description": "OAuth 2.0-specific authorization details.", + "properties": { + "scopes": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + } + }, + "required": ["id"], + "additionalProperties": false + }, + "secrets": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The secret's unique identifier." + } + }, + "required": ["id"], + "additionalProperties": false + } + } + }, + "additionalProperties": false + } + }, + "required": ["id", "name", "description", "toolkit"], + "additionalProperties": false + }, + "ExecuteToolRequest": { + "type": "object", + "properties": { + "execution_id": { + "type": "string", + "description": "The globally-unique ID for this tool execution." + }, + "trace_id": { + "type": "string", + "description": "A trace identifier for the tool execution." + }, + "tool_id": { + "$ref": "#/components/schemas/ToolId" + }, + "input": { + "type": "object", + "description": "The input parameters for the tool call.", + "additionalProperties": true + }, + "context": { + "type": "object", + "properties": { + "authorization": { + "type": "array", + "description": "The authorization information for the tool call.", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier for the authorization method or authorization provider." + }, + "token": { + "type": "string", + "description": "The token for the tool call." + } + }, + "required": ["id", "token"], + "additionalProperties": false + } + }, + "secrets": { + "type": "array", + "description": "The secrets for the tool call.", + "items": { + "$ref": "#/components/schemas/ToolSecret" + }, + "additionalProperties": true + }, + "user_id": { + "type": "string", + "description": "A unique ID that identifies the user, if present." + }, + "user_info": { + "type": "object", + "description": "Additional information about the user, if present." + } + }, + "additionalProperties": false + } + }, + "required": ["execution_id", "tool_id"], + "additionalProperties": false + }, + "ExecuteToolResponse": { + "type": "object", + "properties": { + "$schema": { + "type": "string", + "format": "uri" + }, + "execution_id": { + "type": "string", + "description": "The globally-unique ID for this tool execution." + }, + "duration": { + "type": "number", + "description": "The duration of the tool call, in milliseconds" + }, + "success": { + "type": "boolean", + "description": "Whether the tool execution was successful." + }, + "output": { + "type": "object", + "oneOf": [ + { + "properties": { + "value": { + "description": "The value returned from the tool.", + "oneOf": [ + { + "type": "object", + "additionalProperties": true + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + } + }, + "required": ["value"], + "additionalProperties": false + }, + { + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "An error message that can be shown to the user or the AI model." + }, + "developer_message": { + "type": "string", + "description": "An internal message that will be logged but will not be shown to the user or the AI model" + }, + "can_retry": { + "type": "boolean", + "description": "Whether the tool call can be retried by the client.", + "default": false + }, + "additional_prompt_content": { + "type": "string", + "description": "Additional content to be included in the retry prompt." + }, + "retry_after_ms": { + "type": "integer", + "description": "The number of milliseconds (if any) to wait before retrying the tool call." + } + }, + "required": ["message"], + "additionalProperties": false + } + }, + "required": ["error"], + "additionalProperties": false + } + ] + } + }, + "required": ["execution_id", "success"], + "additionalProperties": false + } + } + } + } +} diff --git a/specification/http/1.0/tool_definition.schema.json b/specification/http/1.0/tool_definition.schema.json deleted file mode 100644 index 794a563..0000000 --- a/specification/http/1.0/tool_definition.schema.json +++ /dev/null @@ -1,207 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$defs": { - "primitives": { - "description": "All supported primitive data types", - "type": "string", - "enum": ["string", "integer", "number", "boolean", "json"] - }, - "value_schema": { - "type": "object", - "description": "The schema of a value (e.g. function input parameter value)", - "properties": { - "val_type": { - "oneOf": [{ "$ref": "#/$defs/primitives" }, { "type": "string", "enum": ["array"] }] - }, - "inner_val_type": { - "description": "If the value type is a list, the type of the list values.", - "oneOf": [{ "$ref": "#/$defs/primitives" }, { "type": "null" }] - }, - "enum": { - "oneOf": [ - { "type": "null" }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - } - }, - "required": ["val_type"], - "additionalProperties": false, - "if": { - "properties": { "val_type": { "const": "array" } } - }, - "then": { - "required": ["inner_val_type"] - } - } - }, - "type": "object", - "properties": { - "$schema": { - "type": "string", - "format": "uri" - }, - "name": { - "type": "string", - "description": "The tool name" - }, - "fully_qualified_name": { - "type": "string", - "description": "The tool's fully-qualified name" - }, - "description": { - "type": "string", - "description": "A human-readable description of the tool and when to use it" - }, - "toolkit": { - "type": "object", - "description": "The toolkit that contains the tool", - "properties": { - "name": { - "type": "string", - "description": "The name of the toolkit" - }, - "description": { - "type": "string", - "description": "A human-readable description of the toolkit" - }, - "version": { - "type": "string", - "description": "An identifier for this version of the toolkit" - } - }, - "required": ["name", "version"], - "additionalProperties": false - }, - "input": { - "type": "object", - "properties": { - "parameters": { - "type": "array", - "minItems": 0, - "items": { - "type": "object", - "properties": { - "name": { - "description": "The human-readable name of this parameter.", - "type": "string" - }, - "required": { - "description": "Whether this parameter is required (true) or optional (false).", - "type": "boolean" - }, - "description": { - "description": "A descriptive, human-readable explanation of the parameter.", - "type": "string" - }, - "value_schema": { - "$ref": "#/$defs/value_schema" - }, - "inferrable": { - "type": "boolean", - "description": "Whether a value for this parameter can be inferred by a model. Defaults to `true`.", - "default": true - } - }, - "required": ["name", "required", "value_schema"], - "additionalProperties": false - } - } - }, - "required": ["parameters"], - "additionalProperties": false - }, - "output": { - "type": "object", - "properties": { - "available_modes": { - "type": "array", - "minItems": 1, - "items": { - "type": "string", - "enum": ["value", "error", "null", "artifact", "requires_authorization"] - } - }, - "description": { - "description": "A descriptive, human-readable explanation of the function's output.", - "type": "string" - }, - "value_schema": { - "$ref": "#/$defs/value_schema" - } - }, - "required": ["available_modes"], - "additionalProperties": false - }, - "requirements": { - "type": "object", - "properties": { - "secrets": { - "oneOf": [ - { "type": "null" }, - { - "type": "array", - "items": { - "type": "object", - "properties": { - "key_id": { - "type": "string" - } - }, - "required": ["key_id"], - "additionalProperties": false - } - } - ] - }, - "authorization": { - "oneOf": [ - { "type": "null" }, - { - "type": "string", - "enum": ["none", "token"] - }, - { - "type": "object", - "properties": { - "provider_id": { - "type": "string", - "description": "The provider ID configured in Arcade that acts as an alias to well-known configuration." - }, - "provider_type": { - "type": "string", - "description": "The type of the authorization provider." - }, - "id": { - "type": "string", - "description": "A provider's unique identifier, allowing the tool to specify a specific authorization provider. Recommended for private tools only." - }, - "oauth2": { - "type": "object", - "properties": { - "scopes": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "additionalProperties": false - } - }, - "required": ["provider_type"], - "additionalProperties": false - } - ] - } - }, - "additionalProperties": false - } - }, - "required": ["name", "fully_qualified_name", "toolkit", "input", "output"], - "additionalProperties": false -} From 0a54a3116a1014878aef5f01d5f46654af620468 Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Wed, 5 Mar 2025 13:35:13 -0800 Subject: [PATCH 02/18] Add lint action --- .github/workflows/api-lint.yml | 16 + .redocly.lint-ignore.yaml | 7 + specification/http/1.0/openapi.json | 627 ++++++++++++++-------------- 3 files changed, 348 insertions(+), 302 deletions(-) create mode 100644 .github/workflows/api-lint.yml create mode 100644 .redocly.lint-ignore.yaml diff --git a/.github/workflows/api-lint.yml b/.github/workflows/api-lint.yml new file mode 100644 index 0000000..57c994e --- /dev/null +++ b/.github/workflows/api-lint.yml @@ -0,0 +1,16 @@ +name: API linting + +on: [pull_request] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up node + uses: actions/setup-node@v4 + - name: Install Redocly CLI + run: npm install -g @redocly/cli@latest + - name: Run linting + run: redocly lint specification/http/1.0/openapi.json --format=github-actions diff --git a/.redocly.lint-ignore.yaml b/.redocly.lint-ignore.yaml new file mode 100644 index 0000000..48ffff4 --- /dev/null +++ b/.redocly.lint-ignore.yaml @@ -0,0 +1,7 @@ +# This file instructs Redocly's linter to ignore the rules contained for specific parts of your API. +# See https://redocly.com/docs/cli/ for more information. +specification/http/1.0/openapi.json: + no-empty-servers: + - '#/openapi' + operation-4xx-response: + - '#/paths/~1tools/get/responses' diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index b320202..63691bf 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -1,9 +1,13 @@ { - "openapi": "3.0.3", + "openapi": "3.1.0", "info": { "title": "Open Tool Calling Standard", "version": "1.0.0", "description": "A standard for calling tools (functions or services) in a distributed system.", + "license": { + "name": "MIT", + "url": "https://opensource.org/licenses/MIT" + }, "contact": { "name": "Arcade.dev", "url": "https://arcade.dev", @@ -13,17 +17,26 @@ "paths": { "/health": { "get": { + "operationId": "health-check", "summary": "Check health", "description": "Checks the health status of the server.", + "security": [{}], "responses": { "200": { "description": "Server is healthy." + }, + "400": { + "description": "Server is unhealthy and cannot accept requests." + }, + "500": { + "description": "Server has errored and cannot accept requests." } } } }, "/tools": { "get": { + "operationId": "list-tools", "summary": "List tools", "description": "Returns a list of tool definitions.", "security": [ @@ -59,6 +72,7 @@ }, "/execute": { "post": { + "operationId": "execute-tool", "summary": "Execute tool", "description": "Executes a tool with the given parameters.", "security": [ @@ -103,353 +117,362 @@ } } } + }, + "400": { + "description": "The request is invalid." } } } + } + }, + "components": { + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } }, - "components": { - "securitySchemes": { - "bearerAuth": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } + "schemas": { + "ToolId": { + "type": "string", + "description": "A tool's unique identifier in the format 'Toolkit.Tool[@version]', where @version is optional.", + "pattern": "^[A-Za-z0-9_]+\\.[A-Za-z0-9_]+(@[A-Za-z0-9_.\\-]+)?$", + "example": [ + "MyToolkit.MyTool", + "MyToolkit.MyTool@1.0", + "Calculator.Add@latest" + ] }, - "schemas": { - "ToolId": { - "type": "string", - "description": "A tool's unique identifier in the format 'Toolkit.Tool[@version]', where @version is optional.", - "pattern": "^[A-Za-z0-9_]+\\.[A-Za-z0-9_]+(@[A-Za-z0-9_.\\-]+)?$", - "examples": [ - "MyToolkit.MyTool", - "MyToolkit.MyTool@1.0", - "Calculator.Add@latest" - ] - }, - "ToolSecret": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "The secret's unique identifier." - }, - "value": { - "type": "string", - "description": "The secret's value." - } + "ToolSecret": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The secret's unique identifier." }, - "required": ["id", "value"], - "additionalProperties": false + "value": { + "type": "string", + "description": "The secret's value." + } }, - "SimpleJSONSchema": { - "type": "object", + "required": ["id", "value"], + "additionalProperties": false + }, + "SimpleJSONSchema": { + "type": "object", + "additionalProperties": true, + "not": { "properties": { + "$ref": {}, + "$defs": {}, + "definitions": {} + } + } + }, + "ToolDefinition": { + "type": "object", + "properties": { + "id": { + "$ref": "#/components/schemas/ToolId" + }, + "name": { + "type": "string", + "description": "The tool's name." + }, + "description": { + "type": "string", + "description": "A human-readable explanation of the tool's purpose. This field can be used by both humans and AI models." + }, + "toolkit": { "type": "object", - "additionalProperties": true, - "not": { - "properties": { - "$ref": {}, - "$defs": {}, - "definitions": {} + "properties": { + "name": { + "type": "string", + "description": "The name of the toolkit." + }, + "description": { + "type": "string", + "description": "A human-readable description of the toolkit." + }, + "version": { + "type": "string", + "description": "An identifier for this version of the toolkit." } - } - } - }, - "ToolDefinition": { - "type": "object", - "properties": { - "id": { - "$ref": "#/components/schemas/ToolId" }, - "name": { - "type": "string", - "description": "The tool's name." - }, - "description": { - "type": "string", - "description": "A human-readable explanation of the tool's purpose. This field can be used by both humans and AI models." + "required": ["name", "description"], + "additionalProperties": false + }, + "input": { + "type": "object", + "properties": { + "parameters": { + "$ref": "#/components/schemas/SimpleJSONSchema", + "description": "JSON Schema describing the input parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity.", + "additionalProperties": true, + "required": ["name", "description"] + }, + "non_inferrable_parameters": { + "type": "array", + "description": "A list of parameter names that must not be inferred by a model.", + "items": { + "type": "string" + } + } }, - "toolkit": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the toolkit." - }, - "description": { - "type": "string", - "description": "A human-readable description of the toolkit." - }, - "version": { + "required": ["parameters"], + "additionalProperties": false + }, + "output": { + "type": "object", + "properties": { + "available_modes": { + "type": "array", + "items": { "type": "string", - "description": "An identifier for this version of the toolkit." + "enum": ["value", "error", "null"] } }, - "required": ["name", "description"], - "additionalProperties": false - }, - "input": { - "type": "object", - "properties": { - "parameters": { - "$ref": "#/components/schemas/SimpleJSONSchema", - "description": "JSON Schema describing the input parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity.", - "additionalProperties": true, - "required": ["name", "description"] - }, - "non_inferrable_parameters": { - "type": "array", - "description": "A list of parameter names that must not be inferred by a model.", - "items": { - "type": "string" + "description": { + "type": "string", + "description": "A descriptive, human-readable explanation of the function's output." + }, + "value": { + "type": "object", + "properties": { + "parameters": { + "$ref": "#/components/schemas/SimpleJSONSchema", + "description": "JSON Schema describing the output parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity." } } - }, - "required": ["parameters"], - "additionalProperties": false + } }, - "output": { - "type": "object", - "properties": { - "available_modes": { - "type": "array", - "items": { - "type": "string", - "enum": ["value", "error", "null"] + "required": ["available_modes"], + "allOf": [ + { + "oneOf": [ + { + "properties": { + "available_modes": { + "contains": { "const": "value" } + } + }, + "required": ["value"] + }, + { + "not": { + "properties": { + "available_modes": { + "contains": { "const": "value" } + } + } + } } - }, - "description": { - "type": "string", - "description": "A descriptive, human-readable explanation of the function's output." - }, - "value": { + ] + } + ], + "additionalProperties": false + }, + "requirements": { + "type": "object", + "properties": { + "authorization": { + "type": "array", + "items": { "type": "object", "properties": { - "parameters": { - "$ref": "#/components/schemas/SimpleJSONSchema", - "description": "JSON Schema describing the output parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity." + "id": { + "type": "string", + "description": "A provider's unique identifier, allowing the tool to specify a specific authorization provider." + }, + "oauth2": { + "type": "object", + "description": "OAuth 2.0-specific authorization details.", + "properties": { + "scopes": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false } } - } + }, + "required": ["id"], + "additionalProperties": false }, - "required": ["available_modes"], - "allOf": [ - { - "if": { - "properties": { - "available_modes": { - "contains": { "const": "value" } - } + "secrets": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The secret's unique identifier." } }, - "then": { - "required": ["value"] - } + "required": ["id"], + "additionalProperties": false } - ], - "additionalProperties": false + } }, - "requirements": { - "type": "object", - "properties": { - "authorization": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "A provider's unique identifier, allowing the tool to specify a specific authorization provider." - }, - "oauth2": { - "type": "object", - "description": "OAuth 2.0-specific authorization details.", - "properties": { - "scopes": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "additionalProperties": false - } + "additionalProperties": false + } + }, + "required": ["id", "name", "description", "toolkit"], + "additionalProperties": false + }, + "ExecuteToolRequest": { + "type": "object", + "properties": { + "execution_id": { + "type": "string", + "description": "The globally-unique ID for this tool execution." + }, + "trace_id": { + "type": "string", + "description": "A trace identifier for the tool execution." + }, + "tool_id": { + "$ref": "#/components/schemas/ToolId" + }, + "input": { + "type": "object", + "description": "The input parameters for the tool call.", + "additionalProperties": true + }, + "context": { + "type": "object", + "properties": { + "authorization": { + "type": "array", + "description": "The authorization information for the tool call.", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier for the authorization method or authorization provider." + }, + "token": { + "type": "string", + "description": "The token for the tool call." } }, - "required": ["id"], + "required": ["id", "token"], "additionalProperties": false + } + }, + "secrets": { + "type": "array", + "description": "The secrets for the tool call.", + "items": { + "$ref": "#/components/schemas/ToolSecret" }, - "secrets": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "The secret's unique identifier." + "additionalProperties": true + }, + "user_id": { + "type": "string", + "description": "A unique ID that identifies the user, if present." + }, + "user_info": { + "type": "object", + "description": "Additional information about the user, if present." + } + }, + "additionalProperties": false + } + }, + "required": ["execution_id", "tool_id"], + "additionalProperties": false + }, + "ExecuteToolResponse": { + "type": "object", + "properties": { + "$schema": { + "type": "string", + "format": "uri" + }, + "execution_id": { + "type": "string", + "description": "The globally-unique ID for this tool execution." + }, + "duration": { + "type": "number", + "description": "The duration of the tool call, in milliseconds" + }, + "success": { + "type": "boolean", + "description": "Whether the tool execution was successful." + }, + "output": { + "type": "object", + "oneOf": [ + { + "properties": { + "value": { + "description": "The value returned from the tool.", + "oneOf": [ + { + "type": "object", + "additionalProperties": true + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "boolean" } - }, - "required": ["id"], - "additionalProperties": false + ] } - } + }, + "required": ["value"], + "additionalProperties": false }, - "additionalProperties": false - } - }, - "required": ["id", "name", "description", "toolkit"], - "additionalProperties": false - }, - "ExecuteToolRequest": { - "type": "object", - "properties": { - "execution_id": { - "type": "string", - "description": "The globally-unique ID for this tool execution." - }, - "trace_id": { - "type": "string", - "description": "A trace identifier for the tool execution." - }, - "tool_id": { - "$ref": "#/components/schemas/ToolId" - }, - "input": { - "type": "object", - "description": "The input parameters for the tool call.", - "additionalProperties": true - }, - "context": { - "type": "object", - "properties": { - "authorization": { - "type": "array", - "description": "The authorization information for the tool call.", - "items": { + { + "properties": { + "error": { "type": "object", "properties": { - "id": { + "message": { "type": "string", - "description": "The unique identifier for the authorization method or authorization provider." + "description": "An error message that can be shown to the user or the AI model." }, - "token": { + "developer_message": { "type": "string", - "description": "The token for the tool call." + "description": "An internal message that will be logged but will not be shown to the user or the AI model" + }, + "can_retry": { + "type": "boolean", + "description": "Whether the tool call can be retried by the client.", + "default": false + }, + "additional_prompt_content": { + "type": "string", + "description": "Additional content to be included in the retry prompt." + }, + "retry_after_ms": { + "type": "integer", + "description": "The number of milliseconds (if any) to wait before retrying the tool call." } }, - "required": ["id", "token"], + "required": ["message"], "additionalProperties": false } }, - "secrets": { - "type": "array", - "description": "The secrets for the tool call.", - "items": { - "$ref": "#/components/schemas/ToolSecret" - }, - "additionalProperties": true - }, - "user_id": { - "type": "string", - "description": "A unique ID that identifies the user, if present." - }, - "user_info": { - "type": "object", - "description": "Additional information about the user, if present." - } - }, - "additionalProperties": false - } - }, - "required": ["execution_id", "tool_id"], - "additionalProperties": false + "required": ["error"], + "additionalProperties": false + } + ] + } }, - "ExecuteToolResponse": { - "type": "object", - "properties": { - "$schema": { - "type": "string", - "format": "uri" - }, - "execution_id": { - "type": "string", - "description": "The globally-unique ID for this tool execution." - }, - "duration": { - "type": "number", - "description": "The duration of the tool call, in milliseconds" - }, - "success": { - "type": "boolean", - "description": "Whether the tool execution was successful." - }, - "output": { - "type": "object", - "oneOf": [ - { - "properties": { - "value": { - "description": "The value returned from the tool.", - "oneOf": [ - { - "type": "object", - "additionalProperties": true - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "boolean" - } - ] - } - }, - "required": ["value"], - "additionalProperties": false - }, - { - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "An error message that can be shown to the user or the AI model." - }, - "developer_message": { - "type": "string", - "description": "An internal message that will be logged but will not be shown to the user or the AI model" - }, - "can_retry": { - "type": "boolean", - "description": "Whether the tool call can be retried by the client.", - "default": false - }, - "additional_prompt_content": { - "type": "string", - "description": "Additional content to be included in the retry prompt." - }, - "retry_after_ms": { - "type": "integer", - "description": "The number of milliseconds (if any) to wait before retrying the tool call." - } - }, - "required": ["message"], - "additionalProperties": false - } - }, - "required": ["error"], - "additionalProperties": false - } - ] - } - }, - "required": ["execution_id", "success"], - "additionalProperties": false - } + "required": ["execution_id", "success"], + "additionalProperties": false } } } From d23639c2c02aa91e7429212a2ec4b0fcb8dba0bf Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Wed, 5 Mar 2025 13:37:06 -0800 Subject: [PATCH 03/18] Lint any relevant files --- .github/workflows/api-lint.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/api-lint.yml b/.github/workflows/api-lint.yml index 57c994e..d884b28 100644 --- a/.github/workflows/api-lint.yml +++ b/.github/workflows/api-lint.yml @@ -3,7 +3,7 @@ name: API linting on: [pull_request] jobs: - build: + lint: runs-on: ubuntu-latest steps: - name: Checkout @@ -13,4 +13,4 @@ jobs: - name: Install Redocly CLI run: npm install -g @redocly/cli@latest - name: Run linting - run: redocly lint specification/http/1.0/openapi.json --format=github-actions + run: redocly lint "specification/**/openapi.json" --format=github-actions From 24cd860b6773ed8d71bef47ff2a6c453a5d4edc4 Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Wed, 5 Mar 2025 17:10:01 -0800 Subject: [PATCH 04/18] Tweaks from review --- RFC.md | 15 +++++++++++++-- specification/http/1.0/openapi.json | 28 +++++++++------------------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/RFC.md b/RFC.md index e606bc3..88e5c42 100644 --- a/RFC.md +++ b/RFC.md @@ -78,6 +78,8 @@ sequenceDiagram ## 4. Schema Definitions +TODO: Add toolkit information, including a description of `version` (semver). Consider splitting `toolkit` into its own schema which is referenced from `ToolDefinition`. + ### 4.1 Tool Definition Schema The Tool Definition Schema establishes the properties and required fields to describe a tool. It consists of the following sections: @@ -105,7 +107,10 @@ The Tool Definition Schema establishes the properties and required fields to des - **`output`** (optional): Specifies the expected result of the tool execution. - - **`available_modes`**: A list of modes such as `value`, `error`, `null`, etc. If `value` is present, the `output.value` field MUST be present. + - **`available_modes`**: A list of one or more possible output modes: `value`, `error`, `null`. + - **`value`**: The tool may return a value. If this mode is present, the `value` field MUST be present. + - **`error`**: The tool may return an error. + - **`null`**: The tool may return no value. - **`description`** (optional): Human-readable explanation of the output. - **`value`** (optional): A JSON Schema object that describes the output parameters for the tool. @@ -159,6 +164,10 @@ The Tool Request Schema is designed to encapsulate the details of a tool executi This schema guarantees that every tool call is uniquely identifiable and that the necessary parameters and context for execution are clearly provided. +#### Tool Version Resolution + +TODO - describe how the server will resolve the version of the tool to call, including the special keyword `latest` and the behavior when a version is not specified (also `latest`). + #### Non-Normative Examples TODO @@ -293,7 +302,7 @@ Tool execution is initiated by sending a POST request to the `/execute` endpoint - **Endpoint:** `/execute` - **Security:** Servers MAY require bearer authentication (JWT). Servers that are internet-facing SHOULD require authentication. - **Payload:** A JSON document with two main parts: - - **`$schema` Field:** A URI reference to the standard. + - **`$schema` Field** (optional): A URI reference to the version of the Open Tool Calling standard that was used to generate the request. - **`request` Object:** Includes: - **`execution_id`** (required): A unique identifier for this execution. - **`tool_id`** (required): The unique identifier of the tool to be executed. @@ -307,6 +316,8 @@ Tool execution is initiated by sending a POST request to the `/execute` endpoint - **`duration`** (optional): The time taken for execution (in milliseconds). - **`output`** (optional): For tools that return a value, this field contains the value. For tools that return an error, this field contains an `error` object. +TODO: $schema is not required for the request, but is recommended to ensure compatibility with future versions of the standard. The server must assume the request conforms to the latest version of the standard if `$schema` is not present. + #### Non-Normative Example: Tool Execution **Request:** diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index 63691bf..4b52e99 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -70,7 +70,7 @@ } } }, - "/execute": { + "/tools/execute": { "post": { "operationId": "execute-tool", "summary": "Execute tool", @@ -94,7 +94,8 @@ "request": { "$ref": "#/components/schemas/ExecuteToolRequest" } - } + }, + "required": ["request"] } } } @@ -203,7 +204,7 @@ "required": ["name", "description"], "additionalProperties": false }, - "input": { + "input_schema": { "type": "object", "properties": { "parameters": { @@ -211,19 +212,12 @@ "description": "JSON Schema describing the input parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity.", "additionalProperties": true, "required": ["name", "description"] - }, - "non_inferrable_parameters": { - "type": "array", - "description": "A list of parameter names that must not be inferred by a model.", - "items": { - "type": "string" - } } }, "required": ["parameters"], "additionalProperties": false }, - "output": { + "output_schema": { "type": "object", "properties": { "available_modes": { @@ -329,7 +323,7 @@ "properties": { "execution_id": { "type": "string", - "description": "The globally-unique ID for this tool execution." + "description": "The unique identifier (e.g. UUID) for this tool execution." }, "trace_id": { "type": "string", @@ -376,16 +370,12 @@ "user_id": { "type": "string", "description": "A unique ID that identifies the user, if present." - }, - "user_info": { - "type": "object", - "description": "Additional information about the user, if present." } }, - "additionalProperties": false + "additionalProperties": trueg } }, - "required": ["execution_id", "tool_id"], + "required": ["tool_id"], "additionalProperties": false }, "ExecuteToolResponse": { @@ -397,7 +387,7 @@ }, "execution_id": { "type": "string", - "description": "The globally-unique ID for this tool execution." + "description": "The unique identifier (e.g. UUID) for this tool execution. If an ID is not provided by the client, the server will generate one." }, "duration": { "type": "number", From 28a53fc333de17ae4f7541ce2b08fe7024c2c8cc Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Wed, 5 Mar 2025 17:14:43 -0800 Subject: [PATCH 05/18] Fix typo --- specification/http/1.0/openapi.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index 4b52e99..af4b409 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -372,7 +372,7 @@ "description": "A unique ID that identifies the user, if present." } }, - "additionalProperties": trueg + "additionalProperties": true } }, "required": ["tool_id"], From f0ef2842ad10ebc7d96ea03fa940f20cade3cfdb Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Sun, 9 Mar 2025 17:06:36 -0700 Subject: [PATCH 06/18] Rename execute -> call --- RFC.md | 54 ++++++++++++++--------------- specification/http/1.0/openapi.json | 45 +++++++++++++++--------- 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/RFC.md b/RFC.md index 88e5c42..2271ea0 100644 --- a/RFC.md +++ b/RFC.md @@ -49,7 +49,7 @@ The Open Tool Calling standard is designed around three key components: 1. **Tool Definition:** A schema that specifies how a tool is described. It includes metadata such as the tool's name, unique identifier, toolkit information, and the input/output specifications. 2. **Tool Request:** A schema that details the structure of a tool call. It encompasses the run identifier, execution context, tool metadata, and input parameters. -3. **Tool Response:** A schema that outlines the structure of the response returned after a tool execution. It provides details on execution status, duration, and the actual output (or errors) of the tool call. +3. **Tool Response:** A schema that outlines the structure of the response returned after a tool call. It provides details on execution status, duration, and the actual output (or errors) of the tool call. These components ensure consistent communication between clients and tools, regardless of the implementation details of each tool. @@ -67,10 +67,10 @@ sequenceDiagram C->>S: Request tool list S-->>C: List of available tools - %% Tool execution - C->>S: Send execution request + %% Tool call + C->>S: Send call request Note left of C: Resolve requirements (such as authorization) - S->>T: Execute tool (function) + S->>T: Run tool (function) T-->>S: Return tool response S-->>C: Return tool response @@ -105,7 +105,7 @@ The Tool Definition Schema establishes the properties and required fields to des #### Output Schema -- **`output`** (optional): Specifies the expected result of the tool execution. +- **`output`** (optional): Specifies the expected result of the tool call. - **`available_modes`**: A list of one or more possible output modes: `value`, `error`, `null`. - **`value`**: The tool may return a value. If this mode is present, the `value` field MUST be present. @@ -144,8 +144,8 @@ The Tool Request Schema is designed to encapsulate the details of a tool executi - **Run and Execution Identification:** - - **`execution_id`**: Globally unique identifier for this tool execution. - - **`trace_id`** (optional): Unique identifier for the trace of the tool execution, if supplied by the client. + - **`execution_id`**: Globally unique identifier for this tool call. + - **`trace_id`** (optional): Unique identifier for the trace of the tool call, if supplied by the client. - **Tool Metadata:** @@ -159,7 +159,7 @@ The Tool Request Schema is designed to encapsulate the details of a tool executi - **`context`**: Provides additional execution context including: - **`authorization`** (optional): Contains tokens for authentication. - **`secrets`** (optional): Secret information required for execution. - - **`user_id`** (optional): Unique user identifier. + - **`user_id`** (optional): Unique user identifier. TODO remove? - **`user_info`** (optional): Supplementary information provided by the authorization server. This schema guarantees that every tool call is uniquely identifiable and that the necessary parameters and context for execution are clearly provided. @@ -174,13 +174,13 @@ TODO ### 4.3 Tool Response Schema -The Tool Response Schema defines the structure of the data returned after a tool execution: +The Tool Response Schema defines the structure of the data returned after a tool call: - **Execution Metadata:** - - **`execution_id`**: The globally unique execution identifier. - - **`success`**: Boolean flag indicating the success or failure of the execution. - - **`duration`** (optional): Execution time in milliseconds. + - **`call_id`**: The globally unique call identifier. + - **`success`**: Boolean flag indicating the success or failure of the call. + - **`duration`** (optional): Call time in milliseconds. - **Output Content:** The output can take one of several forms: @@ -202,7 +202,7 @@ TODO ## 5. Communication Flows -The Open Tool Calling (OTC) standard defines clear communication flows that enable clients to discover available tools and execute them. The flows below follow the definitions in the OpenAPI specification (`specification/http/1.0/openapi.json`), ensuring that all tool interactions are consistent, secure, and standardized. +The Open Tool Calling (OTC) standard defines clear communication flows that enable clients to discover available tools and call them. The flows below follow the definitions in the OpenAPI specification (`specification/http/1.0/openapi.json`), ensuring that all tool interactions are consistent, secure, and standardized. ### 5.1 Server Health Check @@ -293,37 +293,37 @@ Authorization: Bearer ### 5.2 Tool Execution -Tool execution is initiated by sending a POST request to the `/execute` endpoint. This flow lets clients run a tool and receive its output, with the request and response bodies conforming to the `ExecuteToolRequest` and `ExecuteToolResponse` schemas. +Tool execution is initiated by sending a POST request to the `/call` endpoint. This flow lets clients run a tool and receive its output, with the request and response bodies conforming to the `CallToolRequest` and `CallToolResponse` schemas. #### Flow Details: - **Request:** - **Method:** POST - - **Endpoint:** `/execute` + - **Endpoint:** `/call` - **Security:** Servers MAY require bearer authentication (JWT). Servers that are internet-facing SHOULD require authentication. - **Payload:** A JSON document with two main parts: - **`$schema` Field** (optional): A URI reference to the version of the Open Tool Calling standard that was used to generate the request. - **`request` Object:** Includes: - - **`execution_id`** (required): A unique identifier for this execution. - - **`tool_id`** (required): The unique identifier of the tool to be executed. + - **`call_id`** (required): A unique identifier for this call. + - **`tool_id`** (required): The unique identifier of the tool to be called. - **`input`** (optional): An object providing the necessary input parameters. - **`context`** (optional): An object containing authorization tokens, secrets (if any), and user-specific data. - **Response:** - **Status Code:** 200 OK - - **Content:** A JSON document following the `ExecuteToolResponse` schema, which includes: - - **`execution_id`** (required): Echoes the unique identifier from the request. - - **`success`** (required): A Boolean indicating execution success. - - **`duration`** (optional): The time taken for execution (in milliseconds). + - **Content:** A JSON document following the `CallToolResponse` schema, which includes: + - **`call_id`** (required): Echoes the unique identifier from the request. + - **`success`** (required): A Boolean indicating call success. + - **`duration`** (optional): The time taken for call (in milliseconds). - **`output`** (optional): For tools that return a value, this field contains the value. For tools that return an error, this field contains an `error` object. TODO: $schema is not required for the request, but is recommended to ensure compatibility with future versions of the standard. The server must assume the request conforms to the latest version of the standard if `$schema` is not present. -#### Non-Normative Example: Tool Execution +#### Non-Normative Example: Tool Call **Request:** ```http -POST /execute HTTP/1.1 +POST /call HTTP/1.1 Host: api.example.com Content-Type: application/json Authorization: Bearer @@ -331,7 +331,7 @@ Authorization: Bearer { "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", "request": { - "execution_id": "123e4567-e89b-12d3-a456-426614174000", + "call_id": "123e4567-e89b-12d3-a456-426614174000", "tool_id": "Calculator.Add@1.0.0", "input": { "a": 1, @@ -346,7 +346,7 @@ Authorization: Bearer ```json { "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", - "execution_id": "123e4567-e89b-12d3-a456-426614174000", + "call_id": "123e4567-e89b-12d3-a456-426614174000", "duration": 2, "success": true, "output": { @@ -360,7 +360,7 @@ Authorization: Bearer ```json { "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", - "execution_id": "123e4567-e89b-12d3-a456-426614174000", + "call_id": "123e4567-e89b-12d3-a456-426614174000", "success": false, "output": { "error": { @@ -383,7 +383,7 @@ Security is a critical component of the Open Tool Calling standard. The followin - **Contextual Security:** The Tool Request Schema includes contextual information such as user identity and authorization tokens, which help ensure secure execution. -These security measures are intended to protect the integrity of tool interactions and ensure that only authorized clients can execute tools. +These security measures are intended to protect the integrity of tool interactions and ensure that only authorized clients can call tools. TODO describe client->server security. diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index af4b409..2560945 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -70,11 +70,11 @@ } } }, - "/tools/execute": { + "/tools/call": { "post": { - "operationId": "execute-tool", - "summary": "Execute tool", - "description": "Executes a tool with the given parameters.", + "operationId": "call-tool", + "summary": "Call tool", + "description": "Calls a tool with the given parameters.", "security": [ { "bearerAuth": [] @@ -92,7 +92,7 @@ "format": "uri" }, "request": { - "$ref": "#/components/schemas/ExecuteToolRequest" + "$ref": "#/components/schemas/CallToolRequest" } }, "required": ["request"] @@ -102,7 +102,7 @@ }, "responses": { "200": { - "description": "Execution response from tool.", + "description": "Response from tool.", "content": { "application/json": { "schema": { @@ -112,7 +112,7 @@ "format": "uri" }, "response": { - "$ref": "#/components/schemas/ExecuteToolResponse" + "$ref": "#/components/schemas/CallToolResponse" } } } @@ -231,6 +231,10 @@ "type": "string", "description": "A descriptive, human-readable explanation of the function's output." }, + "possible_mime_types": { + "type": "string", + "description": "The MIME type of the output." + }, "value": { "type": "object", "properties": { @@ -315,19 +319,26 @@ "additionalProperties": false } }, - "required": ["id", "name", "description", "toolkit"], + "required": [ + "id", + "name", + "description", + "toolkit", + "input_schema", + "output_schema" + ], "additionalProperties": false }, - "ExecuteToolRequest": { + "CallToolRequest": { "type": "object", "properties": { - "execution_id": { + "call_id": { "type": "string", - "description": "The unique identifier (e.g. UUID) for this tool execution." + "description": "The unique identifier (e.g. UUID) for this tool call. Used as an idempotency key." }, "trace_id": { "type": "string", - "description": "A trace identifier for the tool execution." + "description": "An optional trace identifier for the tool call." }, "tool_id": { "$ref": "#/components/schemas/ToolId" @@ -378,16 +389,16 @@ "required": ["tool_id"], "additionalProperties": false }, - "ExecuteToolResponse": { + "CallToolResponse": { "type": "object", "properties": { "$schema": { "type": "string", "format": "uri" }, - "execution_id": { + "call_id": { "type": "string", - "description": "The unique identifier (e.g. UUID) for this tool execution. If an ID is not provided by the client, the server will generate one." + "description": "The unique identifier (e.g. UUID) for this tool call. If an ID is not provided by the client, the server will generate one." }, "duration": { "type": "number", @@ -395,7 +406,7 @@ }, "success": { "type": "boolean", - "description": "Whether the tool execution was successful." + "description": "Whether the tool call was successful." }, "output": { "type": "object", @@ -461,7 +472,7 @@ ] } }, - "required": ["execution_id", "success"], + "required": ["call_id", "success"], "additionalProperties": false } } From a6d4a4617d4bdf2f31d964404e197c1c6216dea8 Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Sun, 9 Mar 2025 17:11:48 -0700 Subject: [PATCH 07/18] Add some todos --- RFC.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/RFC.md b/RFC.md index 2271ea0..36d2e13 100644 --- a/RFC.md +++ b/RFC.md @@ -144,7 +144,7 @@ The Tool Request Schema is designed to encapsulate the details of a tool executi - **Run and Execution Identification:** - - **`execution_id`**: Globally unique identifier for this tool call. + - **`call_id`** (optional): A unique identifier and idempotency key for this tool call. If not provided, the server will generate one. - **`trace_id`** (optional): Unique identifier for the trace of the tool call, if supplied by the client. - **Tool Metadata:** @@ -164,6 +164,10 @@ The Tool Request Schema is designed to encapsulate the details of a tool executi This schema guarantees that every tool call is uniquely identifiable and that the necessary parameters and context for execution are clearly provided. +#### Tool Context + +TODO + #### Tool Version Resolution TODO - describe how the server will resolve the version of the tool to call, including the special keyword `latest` and the behavior when a version is not specified (also `latest`). @@ -178,7 +182,7 @@ The Tool Response Schema defines the structure of the data returned after a tool - **Execution Metadata:** - - **`call_id`**: The globally unique call identifier. + - **`call_id`**: A unique identifier for this call. - **`success`**: Boolean flag indicating the success or failure of the call. - **`duration`** (optional): Call time in milliseconds. @@ -199,6 +203,8 @@ The Tool Response Schema ensures that every response provides clear and actionab #### Non-Normative Examples TODO +TODO - example of error message vs. developer_message +TODO - example of additional_prompt_content ## 5. Communication Flows From 236a09d48bd677a40281971dd99a5166bc6625a8 Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Sun, 9 Mar 2025 17:21:21 -0700 Subject: [PATCH 08/18] Make JSON an explicit output kind --- specification/http/1.0/openapi.json | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index 2560945..be911fa 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -220,22 +220,19 @@ "output_schema": { "type": "object", "properties": { - "available_modes": { + "possible_kinds": { "type": "array", + "description": "The kinds of output that the tool can return: none (a void- or None-returning function), or json (a function that returns a JSON-like value).", "items": { "type": "string", - "enum": ["value", "error", "null"] + "enum": ["none", "json"] } }, "description": { "type": "string", "description": "A descriptive, human-readable explanation of the function's output." }, - "possible_mime_types": { - "type": "string", - "description": "The MIME type of the output." - }, - "value": { + "json": { "type": "object", "properties": { "parameters": { @@ -245,23 +242,23 @@ } } }, - "required": ["available_modes"], + "required": ["possible_kinds"], "allOf": [ { "oneOf": [ { "properties": { - "available_modes": { - "contains": { "const": "value" } + "possible_kinds": { + "contains": { "const": "json" } } }, - "required": ["value"] + "required": ["json"] }, { "not": { "properties": { - "available_modes": { - "contains": { "const": "value" } + "possible_kinds": { + "contains": { "const": "json" } } } } From 6dc4ef955963dccd2844424ea77cbf07491258f8 Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Sun, 9 Mar 2025 17:33:19 -0700 Subject: [PATCH 09/18] Unnest output.value/error --- specification/http/1.0/openapi.json | 143 +++++++++++++++++----------- 1 file changed, 85 insertions(+), 58 deletions(-) diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index be911fa..8c967ba 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -120,7 +120,24 @@ } }, "400": { - "description": "The request is invalid." + "description": "The request is invalid or could not be processed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestResponse" + } + } + } + }, + "422": { + "description": "The tool call is valid, but the parameters are invalid (missing, incorrect type, etc).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationResponse" + } + } + } } } } @@ -403,74 +420,84 @@ }, "success": { "type": "boolean", - "description": "Whether the tool call was successful." + "description": "Whether the tool call was successful. If the `error` field is present, this field will be false." }, - "output": { - "type": "object", + "json": { + "description": "The JSON object returned from the tool.", "oneOf": [ { - "properties": { - "value": { - "description": "The value returned from the tool.", - "oneOf": [ - { - "type": "object", - "additionalProperties": true - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "boolean" - } - ] - } - }, - "required": ["value"], - "additionalProperties": false + "type": "object", + "additionalProperties": true }, { - "properties": { - "error": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "An error message that can be shown to the user or the AI model." - }, - "developer_message": { - "type": "string", - "description": "An internal message that will be logged but will not be shown to the user or the AI model" - }, - "can_retry": { - "type": "boolean", - "description": "Whether the tool call can be retried by the client.", - "default": false - }, - "additional_prompt_content": { - "type": "string", - "description": "Additional content to be included in the retry prompt." - }, - "retry_after_ms": { - "type": "integer", - "description": "The number of milliseconds (if any) to wait before retrying the tool call." - } - }, - "required": ["message"], - "additionalProperties": false - } - }, - "required": ["error"], - "additionalProperties": false + "type": "number" + }, + { + "type": "string" + }, + { + "type": "boolean" } ] + }, + "error": { + "type": "object", + "description": "An error that occurred inside the tool function.", + "properties": { + "message": { + "type": "string", + "description": "An error message that can be shown to the user or the AI model." + }, + "developer_message": { + "type": "string", + "description": "An internal message that will be logged but will not be shown to the user or the AI model" + }, + "can_retry": { + "type": "boolean", + "description": "Whether the tool call can be retried by the client.", + "default": false + }, + "additional_prompt_content": { + "type": "string", + "description": "Additional content to be included in the retry prompt." + }, + "retry_after_ms": { + "type": "integer", + "description": "The number of milliseconds (if any) to wait before retrying the tool call." + } + }, + "required": ["message"], + "additionalProperties": false } }, "required": ["call_id", "success"], "additionalProperties": false + }, + "BadRequestResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "The error message." + } + }, + "required": ["message"], + "additionalProperties": false + }, + "ValidationResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "The error message." + }, + "parameter_errors": { + "type": "object", + "description": "A map of parameter names to error messages, if parameter-level errors are present." + } + }, + "required": ["message"], + "additionalProperties": false } } } From 334bf5f96cfb5f2ca487021fd2d43a468b729b3e Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Mon, 10 Mar 2025 17:18:34 -0700 Subject: [PATCH 10/18] Updates after review --- RFC.md | 18 +-- specification/http/1.0/openapi.json | 200 ++++++++++++++-------------- 2 files changed, 110 insertions(+), 108 deletions(-) diff --git a/RFC.md b/RFC.md index 36d2e13..6c4f8d6 100644 --- a/RFC.md +++ b/RFC.md @@ -89,10 +89,7 @@ The Tool Definition Schema establishes the properties and required fields to des - **`id`**: A unique identifier for the tool, in the following format: `ToolkitName.ToolName@Version`. For example, `MyToolkit.MyTool@1.0.0`. - **`name`**: A human-readable name for the tool. For example, 'MyTool'. - **`description`**: A human-readable explanation of the tool's purpose. This field can be used by both humans and AI models. - -#### Toolkit Information - -- **`toolkit`**: Contains the toolkit's name, description, and version. +- **`version`**: The semantic version of the tool, e.g. `1.0.0`. #### Input Schema @@ -107,10 +104,9 @@ The Tool Definition Schema establishes the properties and required fields to des - **`output`** (optional): Specifies the expected result of the tool call. - - **`available_modes`**: A list of one or more possible output modes: `value`, `error`, `null`. - - **`value`**: The tool may return a value. If this mode is present, the `value` field MUST be present. - - **`error`**: The tool may return an error. - - **`null`**: The tool may return no value. + - **`mime_type`**: The MIME type of the output. Supported values: + - **`none`**: The tool returns no value. + - **`application/json`**: The tool returns a JSON object. - **`description`** (optional): Human-readable explanation of the output. - **`value`** (optional): A JSON Schema object that describes the output parameters for the tool. @@ -170,7 +166,7 @@ TODO #### Tool Version Resolution -TODO - describe how the server will resolve the version of the tool to call, including the special keyword `latest` and the behavior when a version is not specified (also `latest`). +TODO - describe how the server will resolve the version of the tool to call: both simple versions (`@1`) and semantic versions (`@1.0.0`). #### Non-Normative Examples @@ -324,6 +320,8 @@ Tool execution is initiated by sending a POST request to the `/call` endpoint. T TODO: $schema is not required for the request, but is recommended to ensure compatibility with future versions of the standard. The server must assume the request conforms to the latest version of the standard if `$schema` is not present. +TODO: Server errors (before tool is called) must result in 400 or 422. Once the tool is called, the server MUST return a 200 response with an error (`success: false`). + #### Non-Normative Example: Tool Call **Request:** @@ -363,6 +361,8 @@ Authorization: Bearer **Response (Error Case):** +TODO Clean up example + ```json { "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index 8c967ba..32196c7 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -124,7 +124,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/BadRequestResponse" + "$ref": "#/components/schemas/ServerErrorResponse" } } } @@ -134,7 +134,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ValidationResponse" + "$ref": "#/components/schemas/ValidationFailedResponse" } } } @@ -155,13 +155,19 @@ "ToolId": { "type": "string", "description": "A tool's unique identifier in the format 'Toolkit.Tool[@version]', where @version is optional.", - "pattern": "^[A-Za-z0-9_]+\\.[A-Za-z0-9_]+(@[A-Za-z0-9_.\\-]+)?$", + "pattern": "^[A-Za-z0-9_]+\\.[A-Za-z0-9_]+(@([0-9]+|[0-9]+\\.[0-9]+\\.[0-9]+))?$", "example": [ - "MyToolkit.MyTool", - "MyToolkit.MyTool@1.0", - "Calculator.Add@latest" + "Calculator.Add", + "Calculator.Add@1", + "Calculator.Add@1.0.0" ] }, + "ToolVersion": { + "type": "string", + "description": "A tool's semantic version in the format 'x.y.z', where x, y, and z are integers.", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$", + "example": "1.2.3" + }, "ToolSecret": { "type": "object", "properties": { @@ -196,31 +202,17 @@ }, "name": { "type": "string", - "description": "The tool's name." + "description": "The tool's name. Only allows alphanumeric characters, underscores, and dashes.", + "pattern": "^[A-Za-z0-9_-]{1,64}$", + "example": ["Calculator_Add", "Email_GetEmails"] + }, + "version": { + "$ref": "#/components/schemas/ToolVersion" }, "description": { "type": "string", "description": "A human-readable explanation of the tool's purpose. This field can be used by both humans and AI models." }, - "toolkit": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the toolkit." - }, - "description": { - "type": "string", - "description": "A human-readable description of the toolkit." - }, - "version": { - "type": "string", - "description": "An identifier for this version of the toolkit." - } - }, - "required": ["name", "description"], - "additionalProperties": false - }, "input_schema": { "type": "object", "properties": { @@ -237,45 +229,35 @@ "output_schema": { "type": "object", "properties": { - "possible_kinds": { - "type": "array", - "description": "The kinds of output that the tool can return: none (a void- or None-returning function), or json (a function that returns a JSON-like value).", - "items": { - "type": "string", - "enum": ["none", "json"] - } + "mime_type": { + "type": "string", + "description": "The MIME type of the output that the tool returns, or 'none' if the tool returns no value (a void- or None-returning function).", + "enum": ["none", "application/json"] }, "description": { "type": "string", "description": "A descriptive, human-readable explanation of the function's output." - }, - "json": { - "type": "object", - "properties": { - "parameters": { - "$ref": "#/components/schemas/SimpleJSONSchema", - "description": "JSON Schema describing the output parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity." - } - } } }, - "required": ["possible_kinds"], + "required": ["mime_type"], "allOf": [ { "oneOf": [ { "properties": { - "possible_kinds": { - "contains": { "const": "json" } - } - }, - "required": ["json"] + "mime_type": { "enum": ["none"] } + } }, { - "not": { - "properties": { - "possible_kinds": { - "contains": { "const": "json" } + "properties": { + "mime_type": { "enum": ["application/json"] }, + "value": { + "type": "object", + "properties": { + "parameters": { + "$ref": "#/components/schemas/SimpleJSONSchema", + "description": "JSON Schema describing the output parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity." + } } } } @@ -337,7 +319,6 @@ "id", "name", "description", - "toolkit", "input_schema", "output_schema" ], @@ -348,7 +329,7 @@ "properties": { "call_id": { "type": "string", - "description": "The unique identifier (e.g. UUID) for this tool call. Used as an idempotency key." + "description": "A unique identifier (e.g. UUID) for this tool call. Used as an idempotency key. If omitted, the server will generate an ID." }, "trace_id": { "type": "string", @@ -421,59 +402,80 @@ "success": { "type": "boolean", "description": "Whether the tool call was successful. If the `error` field is present, this field will be false." - }, - "json": { - "description": "The JSON object returned from the tool.", - "oneOf": [ - { - "type": "object", - "additionalProperties": true - }, - { - "type": "number" - }, - { - "type": "string" + } + }, + "required": ["call_id", "success"], + "oneOf": [ + { + "properties": { + "success": { "enum": [true] }, + "mime_type": { + "type": "string", + "description": "The MIME type of the output, or 'none' if the tool returns no value (a void- or None-returning function).", + "enum": ["none", "application/json"] }, - { - "type": "boolean" + "value": { + "description": "The value returned from the tool.", + "oneOf": [ + { + "type": "object", + "additionalProperties": true + }, + { + "type": "number" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] } - ] + }, + "required": ["mime_type", "value"], + "not": { "required": ["error"] } }, - "error": { - "type": "object", - "description": "An error that occurred inside the tool function.", + { "properties": { - "message": { - "type": "string", - "description": "An error message that can be shown to the user or the AI model." - }, - "developer_message": { - "type": "string", - "description": "An internal message that will be logged but will not be shown to the user or the AI model" - }, - "can_retry": { - "type": "boolean", - "description": "Whether the tool call can be retried by the client.", - "default": false - }, - "additional_prompt_content": { - "type": "string", - "description": "Additional content to be included in the retry prompt." - }, - "retry_after_ms": { - "type": "integer", - "description": "The number of milliseconds (if any) to wait before retrying the tool call." + "success": { "enum": [false] }, + "error": { + "type": "object", + "description": "An error that occurred inside the tool function.", + "properties": { + "message": { + "type": "string", + "description": "An error message that can be shown to the user or the AI model." + }, + "developer_message": { + "type": "string", + "description": "An internal message that will be logged but will not be shown to the user or the AI model" + }, + "can_retry": { + "type": "boolean", + "description": "Whether the tool call can be retried by the client.", + "default": false + }, + "additional_prompt_content": { + "type": "string", + "description": "Additional content to be included in the retry prompt." + }, + "retry_after_ms": { + "type": "integer", + "description": "The number of milliseconds (if any) to wait before retrying the tool call." + } + }, + "required": ["message"], + "additionalProperties": false } }, - "required": ["message"], - "additionalProperties": false + "required": ["error"], + "not": { "required": ["mime_type", "value"] } } - }, - "required": ["call_id", "success"], + ], "additionalProperties": false }, - "BadRequestResponse": { + "ServerErrorResponse": { "type": "object", "properties": { "message": { @@ -484,7 +486,7 @@ "required": ["message"], "additionalProperties": false }, - "ValidationResponse": { + "ValidationFailedResponse": { "type": "object", "properties": { "message": { From fbf1425bed41e554c6077cea03a3cb90c3a7e66d Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Mon, 10 Mar 2025 19:19:20 -0700 Subject: [PATCH 11/18] Add validator helper script --- .gitignore | 3 ++ package.json | 16 ++++++++ scripts/validate.js | 92 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 .gitignore create mode 100644 package.json create mode 100644 scripts/validate.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d01fca5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +package-lock.json +pnpm-lock.yaml diff --git a/package.json b/package.json new file mode 100644 index 0000000..3ec2bcf --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "open-tool-calling", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "validate": "node scripts/validate.js" + }, + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1" + } +} diff --git a/scripts/validate.js b/scripts/validate.js new file mode 100644 index 0000000..59b1151 --- /dev/null +++ b/scripts/validate.js @@ -0,0 +1,92 @@ +const Ajv = require("ajv"); +const addFormats = require("ajv-formats"); +const fs = require("fs"); + +// Function to validate JSON against a schema from your OpenAPI spec +function validateAgainstSchema(jsonData, schemaName) { + // Load the OpenAPI spec + const openApiSpec = JSON.parse( + fs.readFileSync("./specification/http/1.0/openapi.json", "utf8") + ); + + // Get the schema by name from components.schemas + const schema = openApiSpec.components.schemas[schemaName]; + + if (!schema) { + throw new Error(`Schema "${schemaName}" not found in the OpenAPI spec`); + } + + // Create Ajv instance with the right options for OpenAPI 3.1 + const ajv = new Ajv({ + strict: false, + allErrors: true, + validateFormats: true, + }); + + // Add formats support (uri, email, etc.) + addFormats(ajv); + + // Add all schemas from the spec to allow for references + for (const [name, schemaObj] of Object.entries( + openApiSpec.components.schemas + )) { + ajv.addSchema(schemaObj, `#/components/schemas/${name}`); + } + + // Validate the data against the schema + const validate = ajv.compile(schema); + const valid = validate(jsonData); + + return { + valid, + errors: validate.errors, + }; +} + +// Example usage +const toolDefinition = { + id: "SMS.Send@0.1.2", + name: "SMS_Send", + description: + "Sends SMS messages using Twilio. Requires a valid TWILIO_API_KEY.", + version: "0.1.2", + input_schema: { + parameters: { + type: "object", + properties: { + to: { + type: "string", + description: "Recipient phone number.", + }, + message: { + type: "string", + description: "Message content to send.", + }, + }, + required: ["to", "message"], + }, + }, + output_schema: { + type: "object", + properties: { + status: { + type: "string", + description: "Status of the SMS sending operation.", + }, + }, + required: ["status"], + }, + requirements: { + secrets: [ + { + id: "TWILIO_API_KEY", + }, + ], + }, +}; + +const result = validateAgainstSchema(toolDefinition, "ToolDefinition"); +console.log(result.valid ? "Validation passed!" : "Validation failed!"); +if (!result.valid) { + console.log(JSON.stringify(result.errors, null, 2)); +} From 5ea0b9bd97150598885a886404df073395f8d4bd Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Mon, 10 Mar 2025 19:19:28 -0700 Subject: [PATCH 12/18] Fix schema issues --- RFC.md | 235 ++++++++++++++++++++++++---- specification/http/1.0/openapi.json | 65 ++------ 2 files changed, 220 insertions(+), 80 deletions(-) diff --git a/RFC.md b/RFC.md index 6c4f8d6..6a1313a 100644 --- a/RFC.md +++ b/RFC.md @@ -6,6 +6,8 @@ This document specifies the Open Tool Calling (OTC) standard, a comprehensive communication protocol for AI agents (clients) calling tools. It defines the structures and protocols used to describe tools, initiate tool calls, and process responses. The standard is comprised of JSON and OpenAPI schemas that govern tool definitions, tool requests, and tool responses. It aims to provide a unified, extensible, and interoperable framework for client-to-tool interactions. +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [BCP 14](https://datatracker.ietf.org/doc/html/bcp14) [[RFC2119]](https://datatracker.ietf.org/doc/html/rfc2119) [[RFC8174]](https://datatracker.ietf.org/doc/html/rfc8174) when, and only when, they appear in all capitals, as shown here. + ## Editors - Nate Barbettini ([@nbarbettini](https://github.com/nbarbettini)) @@ -33,30 +35,28 @@ This document specifies the Open Tool Calling (OTC) standard, a comprehensive co ## 1. Introduction -The Open Tool Calling standard establishes a set of protocols and formats to facilitate communication between agents (clients) and tools (functions or services) in distributed systems. It ensures that tool definitions, requests, and responses adhere to a structured and open standard. This RFC presents detailed JSON and OpenAPI schema specifications that serve as the backbone for this standard, enabling uniform interpretation and execution of tool interactions. +The Open Tool Calling standard establishes a set of protocols and formats to facilitate communication between agents (clients) and tools (functions or services) in distributed systems. It ensures that tool definitions, requests, and responses adhere to a structured and open standard. This specification presents detailed JSON and OpenAPI schemas that serve as the backbone for this standard, enabling uniform interpretation and execution of tool interactions. ## 2. Terminology - **Client:** An entity that issues requests to tools for performing specific tasks. +- **Server** (or Tool Server): An entity that hosts a collection of tools and processes tool calls. - **Tool:** A service or function that can be executed (called) by a client using the defined protocols. -- **Schema:** A formal description of the data structure, typically expressed in JSON Schema, used to validate data formats. -- **Toolkit:** A collection of tools grouped under a common framework and versioned accordingly. -- **JSON Schema:** A vocabulary that allows you to annotate and validate JSON documents. ## 3. Architecture Overview The Open Tool Calling standard is designed around three key components: -1. **Tool Definition:** A schema that specifies how a tool is described. It includes metadata such as the tool's name, unique identifier, toolkit information, and the input/output specifications. -2. **Tool Request:** A schema that details the structure of a tool call. It encompasses the run identifier, execution context, tool metadata, and input parameters. -3. **Tool Response:** A schema that outlines the structure of the response returned after a tool call. It provides details on execution status, duration, and the actual output (or errors) of the tool call. +1. **Tool Definition:** A schema that specifies how a tool is described. It includes metadata such as the tool's name, unique identifier, and the input/output specifications. +2. **Tool Request:** A schema that details the structure of a tool call. It encompasses the call identifier, execution context, tool metadata, and input parameters. +3. **Tool Response:** A schema that outlines the structure of the response returned from a tool call. It provides details on execution status, duration, and the actual output (or errors) of the tool call. These components ensure consistent communication between clients and tools, regardless of the implementation details of each tool. ```mermaid sequenceDiagram participant C as Client - participant S as OTC Server + participant S as Tool Server participant T as Tool ## Health check @@ -78,43 +78,36 @@ sequenceDiagram ## 4. Schema Definitions -TODO: Add toolkit information, including a description of `version` (semver). Consider splitting `toolkit` into its own schema which is referenced from `ToolDefinition`. - ### 4.1 Tool Definition Schema The Tool Definition Schema establishes the properties and required fields to describe a tool. It consists of the following sections: #### Metadata -- **`id`**: A unique identifier for the tool, in the following format: `ToolkitName.ToolName@Version`. For example, `MyToolkit.MyTool@1.0.0`. -- **`name`**: A human-readable name for the tool. For example, 'MyTool'. -- **`description`**: A human-readable explanation of the tool's purpose. This field can be used by both humans and AI models. -- **`version`**: The semantic version of the tool, e.g. `1.0.0`. +- **`id`** (required): A unique identifier for the tool, in the following format: `ToolkitName.ToolName@Version`. For example, `Calculator.Add@1.0.0`. The `id` MUST be unique within the scope of the Tool Server. +- **`name`** (required): A human-readable name for the tool. For example, `Add` or `Calculator_Add`. The name MUST contain only alphanumeric characters, underscores, and dashes, and be between 1 and 64 characters in length. +- **`description`** (required): A human-readable explanation of the tool's purpose. This field SHOULD be used by both humans and AI models. +- **`version`** (required): The semantic version of the tool, e.g. `1.0.0`. Multiple versions of the same tool MAY exist. #### Input Schema -**`input`**: Describes the input parameters for the tool. +**`input_schema`** (required): Describes the input parameters for the tool. -- **`parameters`**: A JSON Schema object that describes the input parameters for the tool. -- **`non_inferrable_parameters`** (optional): A list of parameter names that MUST NOT be inferred by a model. If this array is empty, it is assumed that all parameters are inferrable. +- **`parameters`** (required): A JSON Schema object that describes the input parameters for the tool. This schema supports standard JSON Schema validation but excludes `$ref` and nested definitions/schemas for simplicity. The `parameters` field MUST be present, but MAY be an empty object. -`non_inferrable_parameters` allows tool developers to "hide" certain parameters from an AI model. For example, a tool that has an `is_admin` parameter can indicate that this parameter is required but that a model should not be trusted to infer its value. In this case, the client is still responsible for passing the parameter. +If present, each parameter in `parameters` MUST be a valid JSON Schema object and MUST contain a `description` field describing the parameter. #### Output Schema -- **`output`** (optional): Specifies the expected result of the tool call. - - - **`mime_type`**: The MIME type of the output. Supported values: - - **`none`**: The tool returns no value. - - **`application/json`**: The tool returns a JSON object. - - **`description`** (optional): Human-readable explanation of the output. - - **`value`** (optional): A JSON Schema object that describes the output parameters for the tool. +**`output_schema`** (required): A JSON Schema object that describes the output parameters for the tool. `output_schema` MAY be an empty object indicating that the tool can return an unconstrained ("any") JSON value, and MAY be `null` indicating that the tool does not return any output. #### Requirements -**`requirements`** (optional): Describes any requirements or prerequisites needed for the tool to execute (e.g. authorization, secrets, etc.) +**`requirements`** (optional): Describes tool requirements that are not strictly input parameters, such as an API key needed to call a target API, or that a tool requires OAuth 2.0-based authorization. -The `requirements` field describes tool requirements that are not strictly input parameters, such as the API key needed to call a target API. If the `requirements` field is not present, the client must assume that the tool can be executed without passing any additional information. +If the `requirements` field is not present, the server MUST allow the tool to be executed without passing any additional information. + +If the `requirements` field and one or more sub-fields are present, the client MUST pass the required information in the `context` field of the `CallToolRequest` schema. **`requirements.authorization`** (optional): Declares one or more required authorization methods. @@ -132,7 +125,193 @@ Each required secret is described as an object with the following properties: #### Non-Normative Examples -TODO +1. **Calculator.Add** + + A tool that adds two numbers. + + ```json + { + "id": "Calculator.Add@1.0.0", + "name": "Calculator_Add", + "description": "Adds two numbers together.", + "version": "1.0.0", + "input_schema": { + "parameters": { + "type": "object", + "properties": { + "a": { + "type": "number", + "description": "The first number to add." + }, + "b": { + "type": "number", + "description": "The second number to add." + } + }, + "required": ["a", "b"] + } + }, + "output_schema": { + "type": "number", + "description": "The sum of the two numbers." + } + } + ``` + +2. **Doorbell.Ring (No Output)** + + A tool that rings a doorbell but produces no output parameters. + + ```json + { + "id": "Doorbell.Ring@0.1.0", + "name": "Doorbell_Ring", + "description": "Rings a doorbell given a doorbell ID.", + "version": "0.1.0", + "input_schema": { + "parameters": { + "type": "object", + "properties": { + "doorbell_id": { + "type": "string", + "description": "The ID of the doorbell to ring." + } + }, + "required": ["doorbell_id"] + } + }, + "output_schema": null + } + ``` + +3. **System.GetTimestamp (No Input)** + + A tool that requires no input but produces a timestamp output. + + ```json + { + "id": "System.GetTimestamp@1.0.0", + "name": "System_GetTimestamp", + "description": "Retrieves the current system timestamp.", + "version": "1.0.0", + "input_schema": { + "parameters": { + "type": "object" + } + }, + "output_schema": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "date-time", + "description": "The current system timestamp." + } + }, + "required": ["timestamp"] + } + } + ``` + +4. **Gmail.GetEmails (OAuth 2.0 Authorization)** + + A tool that retrieves emails from Gmail using OAuth 2.0 for authorization. + + ```json + { + "id": "Gmail.GetEmails@1.2.0", + "name": "Gmail_GetEmails", + "description": "Retrieves emails from Gmail using OAuth 2.0 authentication.", + "version": "1.2.0", + "input_schema": { + "parameters": { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "Search query for filtering emails." + } + }, + "required": [] + } + }, + "output_schema": { + "type": "object", + "properties": { + "emails": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "subject": { "type": "string" }, + "snippet": { "type": "string" } + }, + "required": ["id", "subject", "snippet"] + }, + "description": "List of retrieved emails." + } + }, + "required": ["emails"] + }, + "requirements": { + "authorization": [ + { + "id": "google", + "oauth2": { + "scopes": ["https://www.googleapis.com/auth/gmail.readonly"] + } + } + ] + } + } + ``` + +5. **SMS.Send (Secret Requirement)** + + A tool that sends SMS messages using Twilio and requires a `TWILIO_API_KEY` secret. + + ```json + { + "id": "SMS.Send@0.1.2", + "name": "SMS_Send", + "description": "Sends SMS messages using Twilio. Requires a valid TWILIO_API_KEY.", + "version": "0.1.2", + "input_schema": { + "parameters": { + "type": "object", + "properties": { + "to": { + "type": "string", + "description": "Recipient phone number." + }, + "message": { + "type": "string", + "description": "Message content to send." + } + }, + "required": ["to", "message"] + } + }, + "output_schema": { + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "Status of the SMS sending operation." + } + }, + "required": ["status"] + }, + "requirements": { + "secrets": [ + { + "id": "TWILIO_API_KEY" + } + ] + } + } + ``` ### 4.2 Tool Request Schema diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index 32196c7..ab2cfd6 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -183,17 +183,6 @@ "required": ["id", "value"], "additionalProperties": false }, - "SimpleJSONSchema": { - "type": "object", - "additionalProperties": true, - "not": { - "properties": { - "$ref": {}, - "$defs": {}, - "definitions": {} - } - } - }, "ToolDefinition": { "type": "object", "properties": { @@ -206,66 +195,38 @@ "pattern": "^[A-Za-z0-9_-]{1,64}$", "example": ["Calculator_Add", "Email_GetEmails"] }, - "version": { - "$ref": "#/components/schemas/ToolVersion" - }, "description": { "type": "string", "description": "A human-readable explanation of the tool's purpose. This field can be used by both humans and AI models." }, + "version": { + "$ref": "#/components/schemas/ToolVersion" + }, "input_schema": { "type": "object", "properties": { "parameters": { - "$ref": "#/components/schemas/SimpleJSONSchema", - "description": "JSON Schema describing the input parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity.", + "type": "object", "additionalProperties": true, - "required": ["name", "description"] + "description": "JSON Schema describing the input parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity." } }, "required": ["parameters"], "additionalProperties": false }, "output_schema": { - "type": "object", - "properties": { - "mime_type": { - "type": "string", - "description": "The MIME type of the output that the tool returns, or 'none' if the tool returns no value (a void- or None-returning function).", - "enum": ["none", "application/json"] + "oneOf": [ + { + "type": "object", + "additionalProperties": true, + "description": "JSON Schema describing the output parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity." }, - "description": { - "type": "string", - "description": "A descriptive, human-readable explanation of the function's output." - } - }, - "required": ["mime_type"], - "allOf": [ { - "oneOf": [ - { - "properties": { - "mime_type": { "enum": ["none"] } - } - }, - { - "properties": { - "mime_type": { "enum": ["application/json"] }, - "value": { - "type": "object", - "properties": { - "parameters": { - "$ref": "#/components/schemas/SimpleJSONSchema", - "description": "JSON Schema describing the output parameters for the tool. Supports standard JSON Schema validation but excludes $ref and definitions/schemas for simplicity." - } - } - } - } - } - ] + "type": "null", + "description": "Null indicates the tool does not return any value." } ], - "additionalProperties": false + "description": "Schema describing the output of the tool. Can be a JSON Schema object or null if the tool doesn't return a value." }, "requirements": { "type": "object", From d9ce07f54f4b6a11ba1b4444d158518a0dff8e8b Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Tue, 11 Mar 2025 07:14:15 -0700 Subject: [PATCH 13/18] More cleanup --- RFC.md | 550 ++++++++++++++---- package.json | 3 +- .../{validate.js => validate-component.js} | 50 +- scripts/validate-request.js | 147 +++++ specification/http/1.0/openapi.json | 60 +- 5 files changed, 638 insertions(+), 172 deletions(-) rename scripts/{validate.js => validate-component.js} (60%) create mode 100644 scripts/validate-request.js diff --git a/RFC.md b/RFC.md index 6a1313a..42c724a 100644 --- a/RFC.md +++ b/RFC.md @@ -111,7 +111,7 @@ If the `requirements` field and one or more sub-fields are present, the client M **`requirements.authorization`** (optional): Declares one or more required authorization methods. -Each required authorization method is described as an object with the following properties: +Each authorization method is described as an object with the following properties: - **`id`**: A unique identifier for the authorization method or authorization provider. - **`oauth2`** (optional): For tools that require OAuth 2.0-based authorization, this field contains the OAuth 2.0-specific authorization details. @@ -262,7 +262,8 @@ Each required secret is described as an object with the following properties: "scopes": ["https://www.googleapis.com/auth/gmail.readonly"] } } - ] + ], + "user_id": true } } ``` @@ -315,105 +316,357 @@ Each required secret is described as an object with the following properties: ### 4.2 Tool Request Schema -The Tool Request Schema is designed to encapsulate the details of a tool execution (tool call): +The `CallToolRequest` schema is designed to encapsulate the details of a tool execution (tool call). + +#### Run and Execution Identification + +- **`tool_id`**: The unique identifier of the tool to call. +- **`call_id`** (optional): A unique identifier and idempotency key for this tool call. If not provided, the server will generate one. +- **`trace_id`** (optional): Unique identifier for the trace of the tool call, if supplied by the client. + +#### Input Parameters -- **Run and Execution Identification:** +- **`inputs`**: An unconstrained object containing the parameters needed by the tool. - - **`call_id`** (optional): A unique identifier and idempotency key for this tool call. If not provided, the server will generate one. - - **`trace_id`** (optional): Unique identifier for the trace of the tool call, if supplied by the client. +#### Context -- **Tool Metadata:** +- **`context`** (optional): Provides additional execution context, e.g. authorization tokens, secrets, user-specific data, etc. - - **`tool_id`**: The unique identifier of the tool to call. +If the `requirements` field is present on a given tool definition, the client MUST provide the required information in the `context` field when calling the tool. -- **Input Parameters:** +**`context.authorization`** (optional): Contains tokens for authentication. - - **`inputs`**: An unconstrained object containing the parameters needed by the tool. +If the `requirements.authorization` field is present on a given tool definition, the client MUST provide the required authorization information in the `context.authorization` field when calling the tool. The client SHOULD obtain authorization tokens itself or through a trusted intermediary. -- **Context:** - - **`context`**: Provides additional execution context including: - - **`authorization`** (optional): Contains tokens for authentication. - - **`secrets`** (optional): Secret information required for execution. - - **`user_id`** (optional): Unique user identifier. TODO remove? - - **`user_info`** (optional): Supplementary information provided by the authorization server. +Each item in the `authorization` array is an object with the following properties: -This schema guarantees that every tool call is uniquely identifiable and that the necessary parameters and context for execution are clearly provided. +- **`id`**: The unique identifier for the authorization method or authorization provider. +- **`token`**: The token for the tool call. -#### Tool Context +**`context.secrets`** (optional): Contains secrets for the tool call. -TODO +If the `requirements.secrets` field is present on a given tool definition, the client MUST provide the required secrets in the `context.secrets` field when calling the tool. The client SHOULD obtain secrets itself or through a trusted intermediary. + +Each item in the `secrets` array is an object with the following properties: + +- **`id`**: The unique identifier for the secret. #### Tool Version Resolution -TODO - describe how the server will resolve the version of the tool to call: both simple versions (`@1`) and semantic versions (`@1.0.0`). +Tools MUST be versioned using semantic versioning. A Tool Server MAY support multiple versions of a given tool, to allow clients to opt-in to new versions while preserving backwards compatibility. + +When a client calls a tool, the server MUST resolve the version of the tool to call. The server MUST use the following rules to resolve the version of the tool to call: + +1. Semantic Versioning: If the `version` field is present on the tool definition and is of the form `x.y.z` where `x`, `y`, and `z` are integers, the server MUST use the exact version specified in the `version` field. For example, `@1.0.0`. +2. Shorthand Versioning: If the `version` field is present on the tool definition and is of the form `x` where `x` is an integer, the server MUST use the version `x.0.0`. For example, `@1` which resolves to `1.0.0`. +3. Implied Latest Version: If the `version` field is not present on the tool definition, the server MUST use the latest version of the tool. #### Non-Normative Examples -TODO +1. **Calculator.Add** + + A tool call request to add two numbers. + + ```json + { + "tool_id": "Calculator.Add@1.0.0", + "call_id": "123e4567-e89b-12d3-a456-426614174000", + "input": { + "a": 10, + "b": 5 + } + } + ``` + +2. **Doorbell.Ring (No Output)** + + A tool call request to ring a doorbell. + + ```json + { + "tool_id": "Doorbell.Ring@0.1.0", + "call_id": "223e4567-e89b-12d3-a456-426614174001", + "input": { + "doorbell_id": "doorbell42" + } + } + ``` + +3. **System.GetTimestamp (No Input)** + + A tool call request to retrieve the current system timestamp. + + ```json + { + "tool_id": "System.GetTimestamp@1.0.0", + "call_id": "323e4567-e89b-12d3-a456-426614174002" + } + ``` + +4. **Gmail.GetEmails (OAuth 2.0 Authorization)** + + A tool call request to retrieve emails from Gmail using OAuth 2.0 for authorization. + + ```json + { + "tool_id": "Gmail.GetEmails@1.2.0", + "call_id": "423e4567-e89b-12d3-a456-426614174003", + "trace_id": "trace_123", + "input": { + "query": "is:unread" + }, + "context": { + "authorization": [ + { + "id": "google", + "token": "ya29.a0AfH6SMC..." + } + ], + "user_id": "user_123" + } + } + ``` + +5. **SMS.Send (Secret Requirement)** + + A tool call request to send an SMS using Twilio, which requires a secret. + + ```json + { + "tool_id": "SMS.Send@0.1.2", + "call_id": "523e4567-e89b-12d3-a456-426614174004", + "input": { + "to": "+1234567890", + "message": "Hello from our service!" + }, + "context": { + "secrets": [ + { + "id": "TWILIO_API_KEY", + "value": "TWILIO_SECRET_VALUE" + } + ] + } + } + ``` ### 4.3 Tool Response Schema -The Tool Response Schema defines the structure of the data returned after a tool call: +The `CallToolResponse` schema defines the structure of the data returned from a tool call. + +#### Execution Metadata + +- **`call_id`**: A unique identifier for this call. +- **`success`**: Boolean flag indicating the success or failure of the call. +- **`duration`** (optional): Call time in milliseconds. -- **Execution Metadata:** +#### Output Content - - **`call_id`**: A unique identifier for this call. - - **`success`**: Boolean flag indicating the success or failure of the call. - - **`duration`** (optional): Call time in milliseconds. +The output can take one of several forms: -- **Output Content:** - The output can take one of several forms: - 1. **Value Response:** - - Contains a `value` field that may be a JSON object, number, string, or boolean. - 2. **Error Response:** - - Contains an `error` object with: - - **`message`**: A user-facing error message. - - **`developer_message`** (optional): Detailed error information for internal debugging. - - **`can_retry`** (optional): Indicates if the request can be retried by the client. If unspecified, the client MUST assume the request cannot be retried (`false`). - - **`additional_prompt_content`** (optional): Extra content to be used for retry prompts. - - **`retry_after_ms`** (optional): Suggested delay before retrying. +1. **Value Response:** + - Contains a `value` field that MUST be a JSON object, number, string, or boolean. +2. **Null Response:** + - Does not contain a `value` field. +3. **Error Response:** + - Contains an `error` object with: + - **`message`**: A user-facing error message. + - **`developer_message`** (optional): Detailed error information for internal debugging. + - **`can_retry`** (optional): Indicates if the request can be retried by the client. If unspecified, the client MUST assume the request cannot be retried (`false`). + - **`additional_prompt_content`** (optional): Extra content to be used for retry prompts. + - **`retry_after_ms`** (optional): Suggested delay before retrying. -The Tool Response Schema ensures that every response provides clear and actionable information regarding the outcome of the tool call. +The `CallToolResponse` schema ensures that every response provides clear and actionable information regarding the outcome of the tool call. + +#### Retrying Errors + +If `can_retry` is `true`, the client SHOULD retry the tool call after the `retry_after_ms` delay. + +If `additional_prompt_content` is present, the client MAY use it to provide additional context to the AI model when prompting it to retry the tool call. For example, the tool may return a list of suggested values that are close to the expected input for the model to evaluate. #### Non-Normative Examples -TODO -TODO - example of error message vs. developer_message -TODO - example of additional_prompt_content +1. **Calculator.Add (Success)** + + A response for a tool call to add two numbers. + + ```json + { + "call_id": "123e4567-e89b-12d3-a456-426614174000", + "duration": 50, + "success": true, + "value": 15 + } + ``` + +2. **Doorbell.Ring (Success, No Output)** + + A response for a tool call to ring a doorbell that does not return any output. + + ```json + { + "call_id": "223e4567-e89b-12d3-a456-426614174001", + "duration": 30, + "success": true, + "value": null + } + ``` + +3. **System.GetTimestamp (Success)** + + A response for a tool call that retrieves the current system timestamp. + + ```json + { + "call_id": "323e4567-e89b-12d3-a456-426614174002", + "duration": 25, + "success": true, + "value": { + "timestamp": "2023-10-05T12:00:00Z" + } + } + ``` + +4. **Gmail.GetEmails (Success)** + + A successful response for a Gmail tool call that returns a list of emails. + + ```json + { + "call_id": "423e4567-e89b-12d3-a456-426614174003", + "duration": 120, + "success": true, + "value": { + "emails": [ + { + "id": "email_1", + "subject": "Welcome to Gmail", + "snippet": "Hello, welcome to your inbox!" + }, + { + "id": "email_2", + "subject": "Your Receipt", + "snippet": "Thank you for your purchase..." + } + ] + } + } + ``` + +5. **SMS.Send (Success)** + + A successful response for a tool call that sends an SMS. + + ```json + { + "call_id": "523e4567-e89b-12d3-a456-426614174004", + "duration": 80, + "success": true, + "value": { + "status": "sent" + } + } + ``` + +6. **Error Response with Message and Developer Message** + + A tool call error response that includes both a user-facing message and an internal developer message. + + ```json + { + "call_id": "623e4567-e89b-12d3-a456-426614174005", + "duration": 40, + "success": false, + "error": { + "message": "Could not reach the server", + "developer_message": "The host api.example.com is not reachable" + } + } + ``` + +7. **Error Response with Additional Prompt Content** + + An error response that offers additional context and retry guidance. + + ```json + { + "call_id": "723e4567-e89b-12d3-a456-426614174006", + "duration": 60, + "success": false, + "error": { + "message": "Doorbell ID not found", + "developer_message": "The doorbell with ID 'doorbell1' does not exist.", + "can_retry": true, + "additional_prompt_content": "ids: doorbell42,doorbell84", + "retry_after_ms": 500 + } + } + ``` ## 5. Communication Flows The Open Tool Calling (OTC) standard defines clear communication flows that enable clients to discover available tools and call them. The flows below follow the definitions in the OpenAPI specification (`specification/http/1.0/openapi.json`), ensuring that all tool interactions are consistent, secure, and standardized. +### Schema Resolution + +The `$schema` field is used in requests and responses to indicate the version of the OTC standard that the client supports. If the `$schema` field is not included, the server MUST assume the client supports the latest version of the OTC standard. + +```json +{ + "$schema": "https://github.com/OpenToolCalling/Specification/tree/main/specification/http/1.0/openapi.json" +} +``` + +The schema URI MUST be a valid URI. + ### 5.1 Server Health Check An OTC server MUST implement a health check endpoint that returns a 200 OK response if the server is healthy. -#### Flow Details: +#### Flow Details - **Request:** - **Method:** GET - **Endpoint:** `/health` + - **Security:** No authentication is required. - **Response:** - **Status Code:** 200 OK +If the server is ready to receive tool calls, the server MUST return a 200 OK response. The server MAY return an HTTP 503 response if it is not ready to receive tool calls. + +#### Non-Normative Example: Server Health Check + +**Request** + +```http +GET /health HTTP/1.1 +``` + +**Response** + +```http +HTTP/1.1 200 OK +``` + ### 5.2 Tool Discovery -Clients retrieve tool definitions from the OTC server using the `/tools` endpoint. This flow provides a catalog of tools that clients can use, all of which conform to the `ToolDefinition` schema. +Clients retrieve tool definitions from the Tool Server using the `/tools` endpoint. This flow provides a catalog of tools that the client can use, all of which conform to the `ToolDefinition` schema. -#### Flow Details: +#### Flow Details - **Request:** - **Method:** GET - **Endpoint:** `/tools` - **Security:** Servers MAY require bearer authentication (JWT). Servers that are internet-facing SHOULD require authentication. + - **Payload:** A JSON document containing: + - **`$schema` Field** (optional): The client MAY include a `$schema` field in the request body to indicate the version of the OTC standard that the client supports. If the `$schema` field is not included, the server MUST assume the client supports the latest version of the OTC standard. - **Response:** - **Status Code:** 200 OK - - **Content:** A JSON object that includes a `$schema` URI reference (indicating the standard version) and a `tools` array. Each element in the array is a complete tool definition. + - **Content:** A JSON object that includes a `$schema` URI reference (indicating the OTC version) and a `tools` array. Each element in the array is a complete tool definition. If there are no tools available, the `tools` array MUST be empty. #### Non-Normative Example: Tool Discovery -**Request:** +**Request** ```http GET /tools HTTP/1.1 @@ -421,7 +674,16 @@ Host: api.example.com Authorization: Bearer ``` -**Response:** +**Response (No Tools)** + +```json +{ + "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", + "tools": [] +} +``` + +**Response (With Tools)** ```json { @@ -429,14 +691,10 @@ Authorization: Bearer "tools": [ { "id": "Calculator.Add@1.0.0", - "name": "Add", - "description": "Add two numbers together", - "toolkit": { - "name": "Calculator", - "description": "A toolkit for performing calculations.", - "version": "1.0.0" - }, - "input": { + "name": "Calculator_Add", + "description": "Adds two numbers together.", + "version": "1.0.0", + "input_schema": { "parameters": { "type": "object", "properties": { @@ -448,62 +706,90 @@ Authorization: Bearer "type": "number", "description": "The second number to add." } - } - }, - "required": ["a", "b"] + }, + "required": ["a", "b"] + } }, - "output": { - "available_modes": ["value", "error"], - "description": "The result produced by the tool.", - "value": { - "parameters": { - "type": "object", - "properties": { - "result": { - "type": "number", - "description": "The sum of the two numbers." - } + "output_schema": { + "type": "number", + "description": "The sum of the two numbers." + } + }, + { + "id": "Doorbell.Ring@0.1.0", + "name": "Doorbell_Ring", + "description": "Rings a doorbell given a doorbell ID.", + "version": "0.1.0", + "input_schema": { + "parameters": { + "type": "object", + "properties": { + "doorbell_id": { + "type": "string", + "description": "The ID of the doorbell to ring." } - } + }, + "required": ["doorbell_id"] } - } + }, + "output_schema": null } ] } ``` -### 5.2 Tool Execution +### 5.3 Tool Execution -Tool execution is initiated by sending a POST request to the `/call` endpoint. This flow lets clients run a tool and receive its output, with the request and response bodies conforming to the `CallToolRequest` and `CallToolResponse` schemas. +Tool execution is initiated by sending a POST request to the `/tools/call` endpoint. This flow lets clients run a tool and receive its output, with the request and response bodies conforming to the `CallToolRequest` and `CallToolResponse` schemas. -#### Flow Details: +#### Flow Details - **Request:** - **Method:** POST - - **Endpoint:** `/call` + - **Endpoint:** `/tools/call` - **Security:** Servers MAY require bearer authentication (JWT). Servers that are internet-facing SHOULD require authentication. - - **Payload:** A JSON document with two main parts: - - **`$schema` Field** (optional): A URI reference to the version of the Open Tool Calling standard that was used to generate the request. - - **`request` Object:** Includes: - - **`call_id`** (required): A unique identifier for this call. - - **`tool_id`** (required): The unique identifier of the tool to be called. - - **`input`** (optional): An object providing the necessary input parameters. - - **`context`** (optional): An object containing authorization tokens, secrets (if any), and user-specific data. -- **Response:** + - **Payload:** A JSON document containing: + - **`$schema` Field** (optional): The client MAY include a `$schema` field in the request body to indicate the version of the OTC standard that the client supports. If the `$schema` field is not included, the server MUST assume the client supports the latest version of the OTC standard. + - **`request` Object:** A JSON document following the `CallToolRequest` schema. +- **Response (Tool Execution):** - **Status Code:** 200 OK - - **Content:** A JSON document following the `CallToolResponse` schema, which includes: - - **`call_id`** (required): Echoes the unique identifier from the request. - - **`success`** (required): A Boolean indicating call success. - - **`duration`** (optional): The time taken for call (in milliseconds). - - **`output`** (optional): For tools that return a value, this field contains the value. For tools that return an error, this field contains an `error` object. + - **Content:** A JSON document following the `CallToolResponse` schema. +- **Response (Server Error):** + - **Status Code:** 400 + - **Content:** A JSON document following the `ServerErrorResponse` schema. +- **Response (Input Validation Error):** + - **Status Code:** 422 + - **Content:** A JSON document following the `ValidationErrorResponse` schema. + +Servers MUST differentiate between: + +1. Errors that occur before the tool is called. +2. Input validation errors. +3. Errors that occur during execution of the tool. + +#### Server Errors -TODO: $schema is not required for the request, but is recommended to ensure compatibility with future versions of the standard. The server must assume the request conforms to the latest version of the standard if `$schema` is not present. +If an error occurs before the tool is called that is not related to input validation, the server MUST return a 400 response conforming to the `ServerErrorResponse` schema. Examples of such errors include: -TODO: Server errors (before tool is called) must result in 400 or 422. Once the tool is called, the server MUST return a 200 response with an error (`success: false`). +- The tool server is temporarily unavailable. +- The requested version of the OTC standard is not supported. +- The requested tool ID is invalid or cannot be found. +- The requested tool version is not available. +- The tool server requires authentication, but the client did not provide valid credentials. + +The `message` field MUST be present and SHOULD be a user-facing error message. The `developer_message` field MAY be present and SHOULD be an internal message that will be logged but will not be shown to the user or the AI model. + +#### Input Validation + +When a valid tool ID and version are provided, servers MUST validate the input parameters against the tool's `input_schema`. If the input parameters are invalid, the server MUST return a 422 response conforming to the `ValidationErrorResponse` schema. Servers MAY return a `parameter_errors` object that maps parameter names to error messages. + +#### Tool Execution Errors + +If an error occurs during execution of a tool, the server MUST return a 200 response conforming to the `CallToolResponse` schema, with a `success: false` and an `error` object. #### Non-Normative Example: Tool Call -**Request:** +**Request** ```http POST /call HTTP/1.1 @@ -524,47 +810,85 @@ Authorization: Bearer } ``` -**Response (Successful Execution):** +**Response (Successful Execution)** + +```http +HTTP/1.1 200 OK +Content-Type: application/json -```json { "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", - "call_id": "123e4567-e89b-12d3-a456-426614174000", - "duration": 2, - "success": true, - "output": { + "result": { + "call_id": "123e4567-e89b-12d3-a456-426614174000", + "duration": 2, + "success": true, "value": 3 } } ``` -**Response (Error Case):** +**Response (Server Error)** -TODO Clean up example +```http +HTTP/1.1 400 Bad Request +Content-Type: application/json -```json { "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", - "call_id": "123e4567-e89b-12d3-a456-426614174000", - "success": false, - "output": { - "error": { - "message": "Invalid input parameter", - "developer_message": "Parameter 'b' is missing or formatted incorrectly.", - "can_retry": false - } + "message": "Tool call failed", + "developer_message": "Calculator.Add@2.0.0 is not available" +} +``` + +**Response (Input Validation Error)** + +```http +HTTP/1.1 422 Unprocessable Entity +Content-Type: application/json + +{ + "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", + "message": "Some input parameters are invalid", + "parameter_errors": { + "a": "Must be a number", + "b": "Must be a number" } } ``` +**Response (Tool Execution Error)** + +```http +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "$schema": "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", + "result": { + "call_id": "723e4567-e89b-12d3-a456-426614174006", + "duration": 60, + "success": false, + "error": { + "message": "Doorbell ID not found", + "developer_message": "The doorbell with ID 'doorbell1' does not exist.", + "can_retry": true, + "additional_prompt_content": "ids: doorbell42,doorbell84", + "retry_after_ms": 500 + } + } +} +``` + ## 6. Security and Authorization Security is a critical component of the Open Tool Calling standard. The following measures are incorporated: -- **Authorization:** - Tools may require token-based or other forms of authorization, as specified in the `requirements.authorization` field of the Tool Definition Schema. -- **Secrets Management:** - Sensitive information such as API keys, passwords, and other credentials is handled via the `requirements.secrets` field. +- **Server-Level Authorization:** + The server MAY require bearer authentication (JWT). Servers that are internet-facing SHOULD require authentication. +- **Tool-Level Authorization:** + Individual tools MAY require token-based or other forms of authorization, as specified in the `requirements.authorization` field of the Tool Definition Schema. +- **Tool-Level Secrets Management:** + Individual tools MAY require sensitive information such as API keys, passwords, and other credentials, which is handled via the `requirements.secrets` field. - **Contextual Security:** The Tool Request Schema includes contextual information such as user identity and authorization tokens, which help ensure secure execution. @@ -592,3 +916,5 @@ The Open Tool Calling standard provides a robust framework for client-to-tool co ## 9. References - JSON Schema Validation Specification, [http://json-schema.org](http://json-schema.org) + +- JSON Schema Validation Specification, [http://json-schema.org](http://json-schema.org) diff --git a/package.json b/package.json index 3ec2bcf..252f705 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "validate": "node scripts/validate.js" + "validate-component": "node scripts/validate-component.js", + "validate-request": "node scripts/validate-request.js" }, "keywords": [], "author": "", diff --git a/scripts/validate.js b/scripts/validate-component.js similarity index 60% rename from scripts/validate.js rename to scripts/validate-component.js index 59b1151..72ab90b 100644 --- a/scripts/validate.js +++ b/scripts/validate-component.js @@ -44,48 +44,20 @@ function validateAgainstSchema(jsonData, schemaName) { } // Example usage -const toolDefinition = { - id: "SMS.Send@0.1.2", - name: "SMS_Send", - description: - "Sends SMS messages using Twilio. Requires a valid TWILIO_API_KEY.", - version: "0.1.2", - input_schema: { - parameters: { - type: "object", - properties: { - to: { - type: "string", - description: "Recipient phone number.", - }, - message: { - type: "string", - description: "Message content to send.", - }, - }, - required: ["to", "message"], - }, - }, - output_schema: { - type: "object", - properties: { - status: { - type: "string", - description: "Status of the SMS sending operation.", - }, - }, - required: ["status"], - }, - requirements: { - secrets: [ - { - id: "TWILIO_API_KEY", - }, - ], +const jsonToValidate = { + call_id: "723e4567-e89b-12d3-a456-426614174006", + duration: 60, + success: false, + error: { + message: "Doorbell ID not found", + developer_message: "The doorbell with ID 'doorbell1' does not exist.", + can_retry: true, + additional_prompt_content: "available_ids: doorbell42,doorbell84", + retry_after_ms: 500, }, }; -const result = validateAgainstSchema(toolDefinition, "ToolDefinition"); +const result = validateAgainstSchema(jsonToValidate, "CallToolResponse"); console.log(result.valid ? "Validation passed!" : "Validation failed!"); if (!result.valid) { console.log(JSON.stringify(result.errors, null, 2)); diff --git a/scripts/validate-request.js b/scripts/validate-request.js new file mode 100644 index 0000000..0f6c9cd --- /dev/null +++ b/scripts/validate-request.js @@ -0,0 +1,147 @@ +const Ajv = require("ajv"); +const addFormats = require("ajv-formats"); +const fs = require("fs"); + +// Function to validate request/response against an API path in the OpenAPI spec +function validateAgainstPath( + requestData, + responseData, + statusCode, + pathUrl, + method +) { + // Load the OpenAPI spec + const openApiSpec = JSON.parse( + fs.readFileSync("./specification/http/1.0/openapi.json", "utf8") + ); + + // Get the path definition + const pathDef = openApiSpec.paths[pathUrl]; + if (!pathDef) { + throw new Error(`Path "${pathUrl}" not found in the OpenAPI spec`); + } + + // Get the method definition + const methodDef = pathDef[method.toLowerCase()]; + if (!methodDef) { + throw new Error(`Method "${method}" not found for path "${pathUrl}"`); + } + + // Create Ajv instance with the right options for OpenAPI 3.1 + const ajv = new Ajv({ + strict: false, + allErrors: true, + validateFormats: true, + }); + + // Add formats support (uri, email, etc.) + addFormats(ajv); + + // Add all schemas from the spec to allow for references + for (const [name, schemaObj] of Object.entries( + openApiSpec.components.schemas + )) { + ajv.addSchema(schemaObj, `#/components/schemas/${name}`); + } + + const result = { + requestValid: true, + responseValid: true, + requestErrors: null, + responseErrors: null, + }; + + // Validate request if there's a requestBody in the spec + if ( + methodDef.requestBody && + methodDef.requestBody.content && + methodDef.requestBody.content["application/json"] && + methodDef.requestBody.content["application/json"].schema + ) { + const requestSchema = + methodDef.requestBody.content["application/json"].schema; + const validateRequest = ajv.compile(requestSchema); + result.requestValid = validateRequest(requestData); + result.requestErrors = validateRequest.errors; + } + + // Validate response if there's a response definition for the status code + if ( + methodDef.responses && + methodDef.responses[statusCode] && + methodDef.responses[statusCode].content && + methodDef.responses[statusCode].content["application/json"] && + methodDef.responses[statusCode].content["application/json"].schema + ) { + const responseSchema = + methodDef.responses[statusCode].content["application/json"].schema; + //console.log("Validating response against schema:", responseSchema); + const validateResponse = ajv.compile(responseSchema); + result.responseValid = validateResponse(responseData); + result.responseErrors = validateResponse.errors; + } else { + throw new Error( + `Response for status code "${statusCode}" not found in the OpenAPI spec for path "${pathUrl}" and method "${method}"` + ); + } + + return result; +} + +// Example usage +const requestToValidate = { + $schema: + "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", + request: { + call_id: "123e4567-e89b-12d3-a456-426614174000", + tool_id: "Calculator.Add@1.0.0", + input: { + a: 1, + b: 2, + }, + }, +}; + +const responseToValidate = { + $schema: + "https://github.com/ArcadeAI/OpenToolCalling/tree/main/specification/http/1.0/openapi.json", + result: { + call_id: "723e4567-e89b-12d3-a456-426614174006", + duration: 60, + success: false, + error: { + message: "Doorbell ID not found", + developer_message: "The doorbell with ID 'doorbell1' does not exist.", + can_retry: true, + additional_prompt_content: "ids: doorbell42,doorbell84", + retry_after_ms: 500, + }, + }, +}; + +const result = validateAgainstPath( + requestToValidate, + responseToValidate, + "200", + "/tools/call", + "POST" +); + +console.log("Request validation:", result.requestValid ? "Passed!" : "Failed!"); +if (!result.requestValid) { + console.log( + "Request validation errors:", + JSON.stringify(result.requestErrors, null, 2) + ); +} + +console.log( + "Response validation:", + result.responseValid ? "Passed!" : "Failed!" +); +if (!result.responseValid) { + console.log( + "Response validation errors:", + JSON.stringify(result.responseErrors, null, 2) + ); +} diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index ab2cfd6..de88378 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -25,11 +25,8 @@ "200": { "description": "Server is healthy." }, - "400": { + "503": { "description": "Server is unhealthy and cannot accept requests." - }, - "500": { - "description": "Server has errored and cannot accept requests." } } } @@ -45,6 +42,21 @@ }, {} ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "properties": { + "$schema": { + "type": "string", + "format": "uri" + } + } + } + } + } + }, "responses": { "200": { "description": "A list of available tools.", @@ -62,7 +74,8 @@ "$ref": "#/components/schemas/ToolDefinition" } } - } + }, + "required": ["tools"] } } } @@ -111,10 +124,11 @@ "type": "string", "format": "uri" }, - "response": { + "result": { "$ref": "#/components/schemas/CallToolResponse" } - } + }, + "required": ["result"] } } } @@ -271,6 +285,10 @@ "required": ["id"], "additionalProperties": false } + }, + "user_id": { + "type": "boolean", + "description": "Whether the tool requires a user ID." } }, "additionalProperties": false @@ -348,17 +366,13 @@ "CallToolResponse": { "type": "object", "properties": { - "$schema": { - "type": "string", - "format": "uri" - }, "call_id": { "type": "string", "description": "The unique identifier (e.g. UUID) for this tool call. If an ID is not provided by the client, the server will generate one." }, "duration": { "type": "number", - "description": "The duration of the tool call, in milliseconds" + "description": "The runtime duration of the tool call, in milliseconds" }, "success": { "type": "boolean", @@ -370,11 +384,6 @@ { "properties": { "success": { "enum": [true] }, - "mime_type": { - "type": "string", - "description": "The MIME type of the output, or 'none' if the tool returns no value (a void- or None-returning function).", - "enum": ["none", "application/json"] - }, "value": { "description": "The value returned from the tool.", "oneOf": [ @@ -394,7 +403,6 @@ ] } }, - "required": ["mime_type", "value"], "not": { "required": ["error"] } }, { @@ -431,17 +439,25 @@ } }, "required": ["error"], - "not": { "required": ["mime_type", "value"] } + "not": { "required": ["value"] } } ], - "additionalProperties": false + "additionalProperties": true }, "ServerErrorResponse": { "type": "object", "properties": { + "$schema": { + "type": "string", + "format": "uri" + }, "message": { "type": "string", "description": "The error message." + }, + "developer_message": { + "type": "string", + "description": "An internal message that will be logged but will not be shown to the user or the AI model" } }, "required": ["message"], @@ -450,6 +466,10 @@ "ValidationFailedResponse": { "type": "object", "properties": { + "$schema": { + "type": "string", + "format": "uri" + }, "message": { "type": "string", "description": "The error message." From b420e2770cf33e9b5de803df0b21aff8ad1227e1 Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Tue, 11 Mar 2025 11:04:50 -0700 Subject: [PATCH 14/18] Morning updates --- scripts/validate-component.js | 14 ++--- specification/http/1.0/openapi.json | 89 ++++++++++++++--------------- 2 files changed, 47 insertions(+), 56 deletions(-) diff --git a/scripts/validate-component.js b/scripts/validate-component.js index 72ab90b..9dcbbc2 100644 --- a/scripts/validate-component.js +++ b/scripts/validate-component.js @@ -45,16 +45,10 @@ function validateAgainstSchema(jsonData, schemaName) { // Example usage const jsonToValidate = { - call_id: "723e4567-e89b-12d3-a456-426614174006", - duration: 60, - success: false, - error: { - message: "Doorbell ID not found", - developer_message: "The doorbell with ID 'doorbell1' does not exist.", - can_retry: true, - additional_prompt_content: "available_ids: doorbell42,doorbell84", - retry_after_ms: 500, - }, + call_id: "123e4567-e89b-12d3-a456-426614174000", + duration: 2, + success: true, + value: 3, }; const result = validateAgainstSchema(jsonToValidate, "CallToolResponse"); diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index de88378..93f6923 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -148,7 +148,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ValidationFailedResponse" + "$ref": "#/components/schemas/ValidationErrorResponse" } } } @@ -354,7 +354,7 @@ }, "user_id": { "type": "string", - "description": "A unique ID that identifies the user, if present." + "description": "A unique ID that identifies the user, if required by the tool." } }, "additionalProperties": true @@ -385,22 +385,16 @@ "properties": { "success": { "enum": [true] }, "value": { - "description": "The value returned from the tool.", - "oneOf": [ - { - "type": "object", - "additionalProperties": true - }, - { - "type": "number" - }, - { - "type": "string" - }, - { - "type": "boolean" - } - ] + "type": [ + "object", + "array", + "string", + "number", + "boolean", + "null" + ], + "additionalProperties": true, + "description": "The value returned from the tool." } }, "not": { "required": ["error"] } @@ -409,33 +403,7 @@ "properties": { "success": { "enum": [false] }, "error": { - "type": "object", - "description": "An error that occurred inside the tool function.", - "properties": { - "message": { - "type": "string", - "description": "An error message that can be shown to the user or the AI model." - }, - "developer_message": { - "type": "string", - "description": "An internal message that will be logged but will not be shown to the user or the AI model" - }, - "can_retry": { - "type": "boolean", - "description": "Whether the tool call can be retried by the client.", - "default": false - }, - "additional_prompt_content": { - "type": "string", - "description": "Additional content to be included in the retry prompt." - }, - "retry_after_ms": { - "type": "integer", - "description": "The number of milliseconds (if any) to wait before retrying the tool call." - } - }, - "required": ["message"], - "additionalProperties": false + "$ref": "#/components/schemas/ToolError" } }, "required": ["error"], @@ -463,7 +431,7 @@ "required": ["message"], "additionalProperties": false }, - "ValidationFailedResponse": { + "ValidationErrorResponse": { "type": "object", "properties": { "$schema": { @@ -481,6 +449,35 @@ }, "required": ["message"], "additionalProperties": false + }, + "ToolError": { + "type": "object", + "description": "An error that occurred inside the tool function.", + "properties": { + "message": { + "type": "string", + "description": "An error message that can be shown to the user or the AI model." + }, + "developer_message": { + "type": "string", + "description": "An internal message that will be logged but will not be shown to the user or the AI model" + }, + "can_retry": { + "type": "boolean", + "description": "Whether the tool call can be retried by the client.", + "default": false + }, + "additional_prompt_content": { + "type": "string", + "description": "Additional content to be included in the retry prompt." + }, + "retry_after_ms": { + "type": "integer", + "description": "The number of milliseconds (if any) to wait before retrying the tool call." + } + }, + "required": ["message"], + "additionalProperties": false } } } From 34e3a37e3e838dfea883ce1196e70a95f2ee1421 Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Tue, 11 Mar 2025 11:09:18 -0700 Subject: [PATCH 15/18] Add lint ignore --- .redocly.lint-ignore.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.redocly.lint-ignore.yaml b/.redocly.lint-ignore.yaml index 48ffff4..f86e5d9 100644 --- a/.redocly.lint-ignore.yaml +++ b/.redocly.lint-ignore.yaml @@ -4,4 +4,5 @@ specification/http/1.0/openapi.json: no-empty-servers: - '#/openapi' operation-4xx-response: + - '#/paths/~1health/get/responses' - '#/paths/~1tools/get/responses' From f6af9d5c536ebf57edbad2e798a0e63648bd15e0 Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Tue, 11 Mar 2025 13:49:16 -0700 Subject: [PATCH 16/18] Allow additional properties --- specification/http/1.0/openapi.json | 30 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index 93f6923..69604e2 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -79,6 +79,9 @@ } } } + }, + "401": { + "description": "Unauthorized. The request requires authentication, but the provided credentials are invalid or missing." } } } @@ -143,6 +146,9 @@ } } }, + "401": { + "description": "Unauthorized. The request requires authentication, but the provided credentials are invalid or missing." + }, "422": { "description": "The tool call is valid, but the parameters are invalid (missing, incorrect type, etc).", "content": { @@ -195,7 +201,7 @@ } }, "required": ["id", "value"], - "additionalProperties": false + "additionalProperties": true }, "ToolDefinition": { "type": "object", @@ -226,7 +232,7 @@ } }, "required": ["parameters"], - "additionalProperties": false + "additionalProperties": true }, "output_schema": { "oneOf": [ @@ -265,12 +271,12 @@ } } }, - "additionalProperties": false + "additionalProperties": true } } }, "required": ["id"], - "additionalProperties": false + "additionalProperties": true }, "secrets": { "type": "array", @@ -283,7 +289,7 @@ } }, "required": ["id"], - "additionalProperties": false + "additionalProperties": true } }, "user_id": { @@ -291,7 +297,7 @@ "description": "Whether the tool requires a user ID." } }, - "additionalProperties": false + "additionalProperties": true } }, "required": [ @@ -341,7 +347,7 @@ } }, "required": ["id", "token"], - "additionalProperties": false + "additionalProperties": true } }, "secrets": { @@ -410,7 +416,7 @@ "not": { "required": ["value"] } } ], - "additionalProperties": true + "additionalProperties": false }, "ServerErrorResponse": { "type": "object", @@ -429,7 +435,7 @@ } }, "required": ["message"], - "additionalProperties": false + "additionalProperties": true }, "ValidationErrorResponse": { "type": "object", @@ -448,7 +454,7 @@ } }, "required": ["message"], - "additionalProperties": false + "additionalProperties": true }, "ToolError": { "type": "object", @@ -460,7 +466,7 @@ }, "developer_message": { "type": "string", - "description": "An internal message that will be logged but will not be shown to the user or the AI model" + "description": "An internal message that will be logged but will not be shown to the user or the AI model." }, "can_retry": { "type": "boolean", @@ -477,7 +483,7 @@ } }, "required": ["message"], - "additionalProperties": false + "additionalProperties": true } } } From 5e1c5b6eb35478f6127e9fab5ff317274d733ee9 Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Tue, 11 Mar 2025 13:52:11 -0700 Subject: [PATCH 17/18] New URL for contact section --- specification/http/1.0/openapi.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/specification/http/1.0/openapi.json b/specification/http/1.0/openapi.json index 69604e2..0afa2ad 100644 --- a/specification/http/1.0/openapi.json +++ b/specification/http/1.0/openapi.json @@ -9,9 +9,7 @@ "url": "https://opensource.org/licenses/MIT" }, "contact": { - "name": "Arcade.dev", - "url": "https://arcade.dev", - "email": "dev@arcade.dev" + "url": "https://opentoolcalling.org" } }, "paths": { From b6113141065b1c5cad49d43f9d17aea5fac94ac1 Mon Sep 17 00:00:00 2001 From: Nate Barbettini Date: Tue, 11 Mar 2025 14:26:49 -0700 Subject: [PATCH 18/18] RFC updates --- RFC.md | 144 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 123 insertions(+), 21 deletions(-) diff --git a/RFC.md b/RFC.md index 42c724a..af7b62c 100644 --- a/RFC.md +++ b/RFC.md @@ -61,18 +61,18 @@ sequenceDiagram ## Health check C->>S: Request health check - S-->>C: Health check response + S->>C: Health check response %% Tool discovery C->>S: Request tool list - S-->>C: List of available tools + S->>C: List of available tools %% Tool call C->>S: Send call request Note left of C: Resolve requirements (such as authorization) S->>T: Run tool (function) - T-->>S: Return tool response - S-->>C: Return tool response + T->>S: Return tool response + S->>C: Return tool response ``` @@ -881,20 +881,128 @@ Content-Type: application/json ## 6. Security and Authorization -Security is a critical component of the Open Tool Calling standard. The following measures are incorporated: +Security is a critical component of the Open Tool Calling standard. -- **Server-Level Authorization:** - The server MAY require bearer authentication (JWT). Servers that are internet-facing SHOULD require authentication. -- **Tool-Level Authorization:** - Individual tools MAY require token-based or other forms of authorization, as specified in the `requirements.authorization` field of the Tool Definition Schema. -- **Tool-Level Secrets Management:** - Individual tools MAY require sensitive information such as API keys, passwords, and other credentials, which is handled via the `requirements.secrets` field. -- **Contextual Security:** - The Tool Request Schema includes contextual information such as user identity and authorization tokens, which help ensure secure execution. +### Server Authentication -These security measures are intended to protect the integrity of tool interactions and ensure that only authorized clients can call tools. +Server authentication describes how the server authenticates the client: which clients are allowed to make OTC protocol requests to the Tool Server. -TODO describe client->server security. +Servers that are internet-facing SHOULD require authentication. + +#### No Authentication + +If a server is configured to not require authentication, the server MUST ignore the `Authorization` header. + +#### API Key Authentication + +A static API key is a simple shared secret that both the client and server know. This method provides simple authentication with minimal implementation complexity. + +Requirements: + +- The client MUST include the API key in the `X-API-Key` HTTP header with each request. +- Servers that support this authentication method MUST validate the API key against their stored value. +- Clients and servers MUST transmit API keys only over secure connections (HTTPS). +- Servers MUST reject requests with missing or invalid API keys with a 401 Unauthorized HTTP response. +- API keys SHOULD be generated with sufficient entropy (recommended minimum 32 bytes) and SHOULD be treated as sensitive information. + +**Non-Normative Example: API Key** + +```http +GET /tools HTTP/1.1 +Host: api.example.com +X-API-Key: ahf62jd81hdk19akqnd62hdka +``` + +#### JWT Bearer Token Authentication + +JSON Web Tokens (JWT) as described in [RFC 7519](https://www.rfc-editor.org/rfc/rfc7519) provide a more secure authentication mechanism that doesn't require sending the shared secret with each request. + +Requirements: + +- The client MUST include a valid JWT in the `Authorization` HTTP header using the Bearer scheme. +- The client MUST sign the JWT using the shared secret key using the HS256 algorithm. +- The server MUST validate the JWT signature using the shared secret key. +- The JWT MUST include the `exp` claim, which SHOULD be no more than 15 minutes in the future. +- The JWT MAY include the `aud` claim. If the `aud` claim is present, the server MUST validate it against the server's allowed client list. +- Servers MUST reject requests with missing, invalid, or expired JWTs with a 401 Unauthorized HTTP response. +- Servers SHOULD enforce a reasonably short expiration time for JWTs to limit potential damage from token exposure. + +**Non-Normative Example: JWT Bearer Token** + +```http +GET /tools HTTP/1.1 +Host: api.example.com +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJvdGNzZXJ2ZXIiLCJleHAiOjE3NDE3MjQyMTl9.FPIFSSUmngbyePKghI54zUJ-dUxCrh4ZnP9TId5zk34 +``` + +#### Selecting an Authentication Method + +Servers MUST document which authentication methods they support. Servers MAY support multiple authentication methods simultaneously. + +Clients SHOULD prefer JWT Bearer token authentication over static API key authentication when both are available, due to its enhanced security properties. + +For highly sensitive operations or production environments, servers SHOULD consider implementing additional security measures beyond these basic authentication methods, such as IP allowlisting, rate limiting, or more sophisticated authentication protocols. + +### Tool Authorization + +Tool authorization describes how the server authorizes the tool call: given a tool's definition, whether the client needs to authorize the user before calling the tool. + +Tools MAY require token-based or other forms of authorization, as specified in the `requirements.authorization` field of the Tool Definition schema. + +When a given tool describes authorization requirements in the `requirements.authorization` field, the client MUST resolve (or delegate to a trusted intermediary) the authorization requirements and provide the necessary credentials (e.g. a token) in the Tool Call Request, before calling the tool. + +If the client does not provide a valid token in the Tool Call Request for a tool that requires authorization, the server MUST return a 400 Bad Request response as described in the Tool Execution (Server Errors) section. + +#### Non-Normative Example: Tool Authorization Flow + +```mermaid +sequenceDiagram + participant U as User + participant C as Client + participant AS as Authorization Server + participant S as Tool Server + participant T as Tool + + U->>C: Input: "Read my recent emails"
user_id: bob@example.com + Note over C: Tool Gmail.GetEmails has an authorization requirement:
id: google
scopes: [https://www.googleapis.com/auth/gmail.readonly] + C-->>AS: OAuth 2.0 request + AS-->>C: Scoped token for user + C->>S: Call tool Gmail.GetEmails with token + S->>T: Run tool (function) + T->>S: Return tool response + S->>C: Return tool response + +``` + +### Tool Secrets Management + +Tool secrets are sensitive information that is required to call a tool, such as API keys, passwords, and other credentials. + +Tools MAY require secrets, as specified in the `requirements.secrets` field of the Tool Definition schema. + +When a tool requires secrets, the client MUST retrieve the secrets (itself or via a trusted intermediary) and provide them in the Tool Call Request, before calling the tool. + +If the client does not provide a secret in the Tool Call Request for a tool that requires a secret, the server MUST return a 400 Bad Request response as described in the Tool Execution (Server Errors) section. + +#### Non-Normative Example: Tool Secrets Management Flow + +```mermaid +sequenceDiagram + participant U as User + participant C as Client + participant SM as Secrets Manager + participant S as Tool Server + participant T as Tool + + U->>C: Input: "Send an SMS to +15556051234567"
user_id: bob@example.com + Note over C: Tool SMS.Send has a secret requirement:
id: TWILIO_API_KEY + C-->>SM: Get secret TWILIO_API_KEY + SM-->>C: TWILIO_API_KEY=abc123... + C->>S: Call tool SMS.Send with TWILIO_API_KEY=abc123... + S->>T: Run tool (function) + T->>S: Return tool response + S->>C: Return tool response +``` ## 7. Extensibility and Versioning @@ -912,9 +1020,3 @@ Proper versioning guarantees that changes to the standard do not disrupt existin ## 8. Conclusion The Open Tool Calling standard provides a robust framework for client-to-tool communications. By standardizing tool definitions, request formats, and response structures, this standard promotes interoperability, consistency, and security in distributed systems. Adoption of this standard will facilitate seamless integration between diverse clients and tools across multiple platforms. - -## 9. References - -- JSON Schema Validation Specification, [http://json-schema.org](http://json-schema.org) - -- JSON Schema Validation Specification, [http://json-schema.org](http://json-schema.org)