← Vytvářejte agenty na Cloudflare / agents / tools / codemode
Použití služby OpenAPI s Code Mode
Použijte OpenApiConnector ke zpřístupnění služby OpenAPI uvnitř trvalého runtime Code Mode. Konektor odvodí jednu metodu sandboxu pro každou operaci v dokumentu OpenAPI.
Model dokáže zjišťovat metody pomocí codemode.search() a vyžádat si zaměřené typy vstupu pomocí codemode.describe(). Kompletní dokument OpenAPI nemusí vstupovat do kontextu modelu.
Tato stránka popisuje Agenta, který využívá službu OpenAPI. Pokud chcete službu OpenAPI publikovat externím MCP klientům prostřednictvím search a execute, přečtěte si Sestavte server MCP typu vyhledej a spusť.
Předpoklady
Potřebujete projekt s trvalý runtime Code Mode nakonfigurováno. Nastavení runtime poskytuje vazbu Worker Loader a CodemodeRuntime export použitý v tomto průvodci.
Vytvořte konektor OpenAPI
-
Přidejte dokument OpenAPI do svého projektu. Každé operaci přiřaďte jedinečné
operationIdaby vytvářel stabilní název metody sandboxu:src/orders-openapi.jsexport const ordersOpenApiSpec = { openapi: "3.1.0", info: { title: "Orders API", version: "1.0.0" }, paths: { "/orders/{orderId}": { get: { operationId: "get_order", summary: "Get an order by ID.", parameters: [ { name: "orderId", in: "path", required: true, schema: { type: "string" }, }, ], }, }, "/orders": { post: { operationId: "create_order", summary: "Create an order.", requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: { productId: { type: "string" }, quantity: { type: "integer" }, }, required: ["productId", "quantity"], }, }, }, }, }, }, }, };src/orders-openapi.tsexport const ordersOpenApiSpec = { openapi: "3.1.0", info: { title: "Orders API", version: "1.0.0" }, paths: { "/orders/{orderId}": { get: { operationId: "get_order", summary: "Get an order by ID.", parameters: [ { name: "orderId", in: "path", required: true, schema: { type: "string" }, }, ], }, }, "/orders": { post: { operationId: "create_order", summary: "Create an order.", requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: { productId: { type: "string" }, quantity: { type: "integer" }, }, required: ["productId", "quantity"], }, }, }, }, }, }, }, } as const; -
Vytvořte konektor. Implementujte
spec()k vrácení dokumentu arequest()k odesílání ověřených požadavků na straně hostitele:src/orders-connector.jsimport { OpenApiConnector } from "@cloudflare/codemode"; import { ordersOpenApiSpec } from "./orders-openapi"; const API_ORIGIN = "https://api.example.com"; export class OrdersConnector extends OpenApiConnector { name() { return "orders"; } instructions() { return "Use for reading and creating orders."; } spec() { return ordersOpenApiSpec; } async request(options) { if (!options.path.startsWith("/")) { throw new Error("Orders API path must start with a slash"); } const url = new URL(options.path, API_ORIGIN); for (const [key, value] of Object.entries(options.params ?? {})) { if (value !== undefined) { url.searchParams.set(key, String(value)); } } const response = await fetch(url, { method: options.method ?? "GET", headers: { ...(options.body !== undefined ? { "Content-Type": "application/json" } : {}), ...options.headers, Authorization: `Bearer ${this.env.ORDERS_API_TOKEN}`, }, body: options.body === undefined ? undefined : JSON.stringify(options.body), }); if (!response.ok) { throw new Error(`Orders API request failed: ${response.status}`); } if (response.status === 204) return null; return response.json(); } tool(name, tool) { if (name === "create_order") { return { ...tool, requiresApproval: true }; } return tool; } }src/orders-connector.tsimport { OpenApiConnector, type ConnectorTool, type OpenApiRequestOptions, } from "@cloudflare/codemode"; import { ordersOpenApiSpec } from "./orders-openapi"; const API_ORIGIN = "https://api.example.com"; export class OrdersConnector extends OpenApiConnector<Env> { override name() { return "orders"; } protected override instructions() { return "Use for reading and creating orders."; } protected override spec() { return ordersOpenApiSpec; } protected override async request(options: OpenApiRequestOptions) { if (!options.path.startsWith("/")) { throw new Error("Orders API path must start with a slash"); } const url = new URL(options.path, API_ORIGIN); for (const [key, value] of Object.entries(options.params ?? {})) { if (value !== undefined) { url.searchParams.set(key, String(value)); } } const response = await fetch(url, { method: options.method ?? "GET", headers: { ...(options.body !== undefined ? { "Content-Type": "application/json" } : {}), ...options.headers, Authorization: `Bearer ${this.env.ORDERS_API_TOKEN}`, }, body: options.body === undefined ? undefined : JSON.stringify(options.body), }); if (!response.ok) { throw new Error(`Orders API request failed: ${response.status}`); } if (response.status === 204) return null; return response.json(); } protected override tool(name: string, tool: ConnectorTool): ConnectorTool { if (name === "create_order") { return { ...tool, requiresApproval: true }; } return tool; } }Přihlašovací údaje zůstávají v hostitelském Workeru. Kód napsaný modelem dostává metody konektoru a jejich výsledky, nikoli
ORDERS_API_TOKEN.tool()hook dekoruje odvozené operace. Tento příklad vyžaduje schválení předcreate_orderse provede. Pomocí hooku můžete také přidat chování pro přehrání nebo vrácení zpět. -
Importujte konektor a přidejte ho do runtime:
src/server.jsimport { AIChatAgent } from "@cloudflare/ai-chat"; import { createCodemodeRuntime, DynamicWorkerExecutor, } from "@cloudflare/codemode"; import { OrdersConnector } from "./orders-connector"; export class Chat extends AIChatAgent { #runtime() { return createCodemodeRuntime({ ctx: this.ctx, executor: new DynamicWorkerExecutor({ loader: this.env.LOADER }), connectors: [new OrdersConnector(this.ctx, this.env)], }); } async onChatMessage() { const tools = { codemode: this.#runtime().tool() }; // Pass tools to your model call. } }src/server.tsimport { AIChatAgent } from "@cloudflare/ai-chat"; import { createCodemodeRuntime, DynamicWorkerExecutor, } from "@cloudflare/codemode"; import { OrdersConnector } from "./orders-connector"; export class Chat extends AIChatAgent<Env> { #runtime() { return createCodemodeRuntime({ ctx: this.ctx, executor: new DynamicWorkerExecutor({ loader: this.env.LOADER }), connectors: [new OrdersConnector(this.ctx, this.env)], }); } async onChatMessage() { const tools = { codemode: this.#runtime().tool() }; // Pass tools to your model call. } } -
Umožněte modelu objevit operace a volat vygenerované metody konektoru:
async () => { const matches = await codemode.search("get an order by ID"); const docs = await codemode.describe(matches.results[0].path); const order = await orders.get_order({ orderId: "order-123" }); return { docs, order }; };
Chování odvozené metody
OpenApiConnector používá sanitizovaný operationId jako název metody. Pokud operace nemá žádný operationId, odvodí název z metody HTTP a cesty. Definujte jedinečná ID operací, aby názvy metod zůstaly stabilní a nedocházelo ke kolizím.
Každá vygenerovaná metoda přijímá jeden objekt:
- Parametry cesty, dotazu a hlavičky se zobrazují jako pole nejvyšší úrovně.
- Tělo požadavku JSON se zobrazuje pod
body. - Povinné parametry OpenAPI se stávají povinnými poli TypeScript.
- Lokální
$refhodnoty ve vstupních schématech se přeloží dříve, než se vygenerují typy.
Konektor dosadí parametry cesty a předá normalizovaný { path, method, params, body, headers } objekt na request().
Aktuální konektor odvozuje vstupní typy, ale typy odpovědí neodvozuje ze schémat odpovědí OpenAPI. Vygenerované metody proto vracejí unknown pokud vaše aplikace neposkytuje konkrétnější deklarace prostřednictvím jiné implementace konektoru.
Úniková cesta požadavku
Každý konektor OpenAPI navíc zpřístupňuje nízkoúrovňové request() metodu sandboxu. Použijte ji, když dokument OpenAPI nepopisuje operaci, kterou model potřebuje:
const result = await orders.request({
path: "/orders",
method: "GET",
params: { status: "processing" },
});Pokud jsou k dispozici, dávejte přednost metodám odvozených operací. Poskytují objevitelné popisy a generované vstupní typy.
exposeSpec() vrací false ve výchozím nastavení. Přepište ho tak, aby vracel true pouze tehdy, když kód napsaný modelem potřebuje přístup k surovému dokumentu OpenAPI. Velké dokumenty mohou vytvořit velké výsledky a trvalé záznamy v logu.