diff --git a/examples/basic-server-react/server.ts b/examples/basic-server-react/server.ts index abb855c6..6e5db06f 100644 --- a/examples/basic-server-react/server.ts +++ b/examples/basic-server-react/server.ts @@ -4,7 +4,7 @@ import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/s import fs from "node:fs/promises"; import path from "node:path"; import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY } from "@modelcontextprotocol/ext-apps/server"; -import { startServer } from "../shared/server-utils.js"; +import { makeToolResult, startServer } from "../shared/server-utils.js"; const DIST_DIR = path.join(import.meta.dirname, "dist"); const RESOURCE_URI = "ui://get-time/mcp-app.html"; @@ -32,9 +32,7 @@ function createServer(): McpServer { }, async (): Promise => { const time = new Date().toISOString(); - return { - content: [{ type: "text", text: JSON.stringify({ time }) }], - }; + return makeToolResult({ time }); }, ); diff --git a/examples/basic-server-vanillajs/server.ts b/examples/basic-server-vanillajs/server.ts index d3baad23..69d9639d 100644 --- a/examples/basic-server-vanillajs/server.ts +++ b/examples/basic-server-vanillajs/server.ts @@ -4,7 +4,7 @@ import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/s import fs from "node:fs/promises"; import path from "node:path"; import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY } from "@modelcontextprotocol/ext-apps/server"; -import { startServer } from "../shared/server-utils.js"; +import { makeToolResult, startServer } from "../shared/server-utils.js"; const DIST_DIR = path.join(import.meta.dirname, "dist"); const RESOURCE_URI = "ui://get-time/mcp-app.html"; @@ -32,9 +32,7 @@ function createServer(): McpServer { }, async (): Promise => { const time = new Date().toISOString(); - return { - content: [{ type: "text", text: JSON.stringify({ time }) }], - }; + return makeToolResult({ time }); }, ); diff --git a/examples/basic-server-vanillajs/src/mcp-app.ts b/examples/basic-server-vanillajs/src/mcp-app.ts index 88fcfa15..ce8deead 100644 --- a/examples/basic-server-vanillajs/src/mcp-app.ts +++ b/examples/basic-server-vanillajs/src/mcp-app.ts @@ -15,12 +15,23 @@ const log = { function extractTime(result: CallToolResult): string { - const text = result.content! - .filter((c): c is { type: "text"; text: string } => c.type === "text") - .map((c) => c.text) - .join(""); - const { time } = JSON.parse(text) as { time: string }; - return time; + // Prefer structuredContent (STRUCTURED_CONTENT_ONLY mode), fall back to parsing text + let data: { time: string }; + if (result.structuredContent) { + data = result.structuredContent as { time: string }; + } else { + const text = result.content! + .filter((c): c is { type: "text"; text: string } => c.type === "text") + .map((c) => c.text) + .join(""); + try { + data = JSON.parse(text) as { time: string }; + } catch (e) { + log.error("Failed to parse tool result:", text, e); + return "[PARSE ERROR]"; + } + } + return data.time; } diff --git a/examples/budget-allocator-server/server.ts b/examples/budget-allocator-server/server.ts index fd7618ed..452fcb21 100755 --- a/examples/budget-allocator-server/server.ts +++ b/examples/budget-allocator-server/server.ts @@ -14,10 +14,12 @@ import fs from "node:fs/promises"; import path from "node:path"; import { z } from "zod"; import { + registerAppTool, + registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY, } from "@modelcontextprotocol/ext-apps/server"; -import { startServer } from "../shared/server-utils.js"; +import { makeToolResult, startServer } from "../shared/server-utils.js"; const DIST_DIR = path.join(import.meta.dirname, "dist"); @@ -270,14 +272,7 @@ function createServer(): McpServer { }, }; - return { - content: [ - { - type: "text", - text: JSON.stringify(response), - }, - ], - }; + return makeToolResult(response); }, ); diff --git a/examples/budget-allocator-server/src/mcp-app.ts b/examples/budget-allocator-server/src/mcp-app.ts index 9cddc8ad..a1f4d794 100644 --- a/examples/budget-allocator-server/src/mcp-app.ts +++ b/examples/budget-allocator-server/src/mcp-app.ts @@ -606,13 +606,33 @@ const app = new App({ name: "Budget Allocator", version: "1.0.0" }); app.ontoolresult = (result) => { log.info("Received tool result:", result); - const text = result - .content!.filter( - (c): c is { type: "text"; text: string } => c.type === "text", - ) - .map((c) => c.text) - .join(""); - const data = JSON.parse(text) as BudgetDataResponse; + + if (result.isError) { + log.error("Tool returned error:", result); + return; + } + + // Prefer structuredContent (STRUCTURED_CONTENT_ONLY mode), fall back to parsing text + let data: BudgetDataResponse | undefined; + if (result.structuredContent) { + data = result.structuredContent as BudgetDataResponse; + } else { + const text = result + .content!.filter( + (c): c is { type: "text"; text: string } => c.type === "text", + ) + .map((c) => c.text) + .join(""); + if (text) { + try { + data = JSON.parse(text) as BudgetDataResponse; + } catch (e) { + log.error("Failed to parse tool result:", text, e); + return; + } + } + } + if (data?.config && data?.analytics) { initializeUI(data.config, data.analytics); } diff --git a/examples/cohort-heatmap-server/server.ts b/examples/cohort-heatmap-server/server.ts index 9d3c9cb3..5bc8e95d 100644 --- a/examples/cohort-heatmap-server/server.ts +++ b/examples/cohort-heatmap-server/server.ts @@ -5,10 +5,12 @@ import fs from "node:fs/promises"; import path from "node:path"; import { z } from "zod"; import { + registerAppTool, + registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY, } from "@modelcontextprotocol/ext-apps/server"; -import { startServer } from "../shared/server-utils.js"; +import { makeToolResult, startServer } from "../shared/server-utils.js"; const DIST_DIR = path.join(import.meta.dirname, "dist"); @@ -177,9 +179,7 @@ function createServer(): McpServer { maxPeriods, ); - return { - content: [{ type: "text", text: JSON.stringify(data) }], - }; + return makeToolResult(data); }, ); diff --git a/examples/customer-segmentation-server/server.ts b/examples/customer-segmentation-server/server.ts index 0bbbbba8..8af65553 100644 --- a/examples/customer-segmentation-server/server.ts +++ b/examples/customer-segmentation-server/server.ts @@ -8,10 +8,12 @@ import fs from "node:fs/promises"; import path from "node:path"; import { z } from "zod"; import { + registerAppTool, + registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY, } from "@modelcontextprotocol/ext-apps/server"; -import { startServer } from "../shared/server-utils.js"; +import { makeToolResult, startServer } from "../shared/server-utils.js"; import { generateCustomers, generateSegmentSummaries, @@ -81,9 +83,7 @@ function createServer(): McpServer { async ({ segment }): Promise => { const data = getCustomerData(segment); - return { - content: [{ type: "text", text: JSON.stringify(data) }], - }; + return makeToolResult(data); }, ); diff --git a/examples/customer-segmentation-server/src/mcp-app.ts b/examples/customer-segmentation-server/src/mcp-app.ts index 39221584..6e56fbc8 100644 --- a/examples/customer-segmentation-server/src/mcp-app.ts +++ b/examples/customer-segmentation-server/src/mcp-app.ts @@ -375,16 +375,24 @@ async function fetchData(): Promise { arguments: {}, }); - const text = result - .content!.filter( - (c): c is { type: "text"; text: string } => c.type === "text", - ) - .map((c) => c.text) - .join(""); - const data = JSON.parse(text) as { - customers: Customer[]; - segments: SegmentSummary[]; - }; + // Prefer structuredContent (STRUCTURED_CONTENT_ONLY mode), fall back to parsing text + let data: { customers: Customer[]; segments: SegmentSummary[] }; + if (result.structuredContent) { + data = result.structuredContent as typeof data; + } else { + const text = result + .content!.filter( + (c): c is { type: "text"; text: string } => c.type === "text", + ) + .map((c) => c.text) + .join(""); + try { + data = JSON.parse(text); + } catch (e) { + log.error("Failed to parse tool result:", text, e); + return; + } + } state.customers = data.customers; state.segments = data.segments; diff --git a/examples/scenario-modeler-server/server.ts b/examples/scenario-modeler-server/server.ts index c3824939..6746251a 100644 --- a/examples/scenario-modeler-server/server.ts +++ b/examples/scenario-modeler-server/server.ts @@ -8,10 +8,12 @@ import fs from "node:fs/promises"; import path from "node:path"; import { z } from "zod"; import { + registerAppTool, + registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY, } from "@modelcontextprotocol/ext-apps/server"; -import { startServer } from "../shared/server-utils.js"; +import { makeToolResult, startServer } from "../shared/server-utils.js"; const DIST_DIR = path.join(import.meta.dirname, "dist"); @@ -276,19 +278,12 @@ function createServer(): McpServer { ? calculateScenario(args.customInputs) : undefined; - return { - content: [ - { - type: "text", - text: JSON.stringify({ - templates: SCENARIO_TEMPLATES, - defaultInputs: DEFAULT_INPUTS, - customProjections: customScenario?.projections, - customSummary: customScenario?.summary, - }), - }, - ], - }; + return makeToolResult({ + templates: SCENARIO_TEMPLATES, + defaultInputs: DEFAULT_INPUTS, + customProjections: customScenario?.projections, + customSummary: customScenario?.summary, + }); }, ); diff --git a/examples/shared/server-utils.ts b/examples/shared/server-utils.ts index 13e6139a..321048da 100644 --- a/examples/shared/server-utils.ts +++ b/examples/shared/server-utils.ts @@ -7,6 +7,7 @@ */ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; @@ -15,6 +16,32 @@ import cors from "cors"; import { randomUUID } from "node:crypto"; import type { Request, Response } from "express"; +/** + * When true, tool results use structuredContent field instead of JSON-stringified text. + * Set via STRUCTURED_CONTENT_ONLY=true environment variable. + */ +export const STRUCTURED_CONTENT_ONLY = + process.env.STRUCTURED_CONTENT_ONLY === "true"; + +/** + * Helper to create a tool result that optionally uses structuredContent. + * When STRUCTURED_CONTENT_ONLY is true, returns data in structuredContent field. + * Otherwise returns JSON-stringified data in content[0].text (legacy format). + */ +export function makeToolResult(data: Record): CallToolResult { + if (STRUCTURED_CONTENT_ONLY) { + console.log("[makeToolResult] STRUCTURED_CONTENT_ONLY mode:", { structuredContent: data }); + return { + content: [], + structuredContent: data, + }; + } + console.log("[makeToolResult] Legacy mode:", { text: JSON.stringify(data).slice(0, 100) + "..." }); + return { + content: [{ type: "text", text: JSON.stringify(data) }], + }; +} + export interface ServerOptions { /** Port to listen on (required). */ port: number; diff --git a/examples/system-monitor-server/server.ts b/examples/system-monitor-server/server.ts index b439c5ac..e7a53186 100644 --- a/examples/system-monitor-server/server.ts +++ b/examples/system-monitor-server/server.ts @@ -10,10 +10,12 @@ import path from "node:path"; import si from "systeminformation"; import { z } from "zod"; import { + registerAppTool, + registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY, } from "@modelcontextprotocol/ext-apps/server"; -import { startServer } from "../shared/server-utils.js"; +import { makeToolResult, startServer } from "../shared/server-utils.js"; // Schemas - types are derived from these using z.infer const CpuCoreSchema = z.object({ @@ -147,9 +149,7 @@ function createServer(): McpServer { timestamp: new Date().toISOString(), }; - return { - content: [{ type: "text", text: JSON.stringify(stats) }], - }; + return makeToolResult(stats); }, ); diff --git a/examples/system-monitor-server/src/mcp-app.ts b/examples/system-monitor-server/src/mcp-app.ts index 1dc7ff2f..c5956c22 100644 --- a/examples/system-monitor-server/src/mcp-app.ts +++ b/examples/system-monitor-server/src/mcp-app.ts @@ -264,13 +264,24 @@ async function fetchStats(): Promise { arguments: {}, }); - const text = result - .content!.filter( - (c): c is { type: "text"; text: string } => c.type === "text", - ) - .map((c) => c.text) - .join(""); - const stats = JSON.parse(text) as SystemStats; + // Prefer structuredContent (STRUCTURED_CONTENT_ONLY mode), fall back to parsing text + let stats: SystemStats; + if (result.structuredContent) { + stats = result.structuredContent as SystemStats; + } else { + const text = result + .content!.filter( + (c): c is { type: "text"; text: string } => c.type === "text", + ) + .map((c) => c.text) + .join(""); + try { + stats = JSON.parse(text); + } catch (e) { + log.error("Failed to parse tool result:", text, e); + return; + } + } // Initialize chart on first data if needed if (!state.chart && stats.cpu.count > 0) { diff --git a/examples/threejs-server/server.ts b/examples/threejs-server/server.ts index e9208542..2a891a22 100644 --- a/examples/threejs-server/server.ts +++ b/examples/threejs-server/server.ts @@ -10,10 +10,12 @@ import fs from "node:fs/promises"; import path from "node:path"; import { z } from "zod"; import { + registerAppTool, + registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY, } from "@modelcontextprotocol/ext-apps/server"; -import { startServer } from "../shared/server-utils.js"; +import { makeToolResult, startServer } from "../shared/server-utils.js"; const DIST_DIR = path.join(import.meta.dirname, "dist"); @@ -167,20 +169,12 @@ function createServer(): McpServer { _meta: { [RESOURCE_URI_META_KEY]: resourceUri }, }, async ({ code, height }) => { - return { - content: [ - { - type: "text", - text: JSON.stringify({ code, height }), - }, - ], - }; + return makeToolResult({ code, height }); }, ); - // Tool 2: learn_threejs - registerAppTool( - server, + // Tool 2: learn_threejs (not a UI tool, just returns documentation) + server.registerTool( "learn_threejs", { title: "Learn Three.js", diff --git a/examples/wiki-explorer-server/server.ts b/examples/wiki-explorer-server/server.ts index 15c93c26..3409495b 100644 --- a/examples/wiki-explorer-server/server.ts +++ b/examples/wiki-explorer-server/server.ts @@ -9,10 +9,12 @@ import fs from "node:fs/promises"; import path from "node:path"; import { z } from "zod"; import { + registerAppTool, + registerAppResource, RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY, } from "@modelcontextprotocol/ext-apps/server"; -import { startServer } from "../shared/server-utils.js"; +import { makeToolResult, startServer } from "../shared/server-utils.js"; const DIST_DIR = path.join(import.meta.dirname, "dist"); @@ -118,12 +120,10 @@ function createServer(): McpServer { const html = await response.text(); const links = extractWikiLinks(new URL(url), html); - const result = { page: { url, title }, links, error: null }; - return { content: [{ type: "text", text: JSON.stringify(result) }] }; + return makeToolResult({ page: { url, title }, links, error: null }); } catch (err) { const error = err instanceof Error ? err.message : String(err); - const result = { page: { url, title }, links: [], error }; - return { content: [{ type: "text", text: JSON.stringify(result) }] }; + return makeToolResult({ page: { url, title }, links: [], error }); } }, ); diff --git a/examples/wiki-explorer-server/src/mcp-app.ts b/examples/wiki-explorer-server/src/mcp-app.ts index c0cf4b04..5a6be162 100644 --- a/examples/wiki-explorer-server/src/mcp-app.ts +++ b/examples/wiki-explorer-server/src/mcp-app.ts @@ -322,17 +322,28 @@ app.ontoolresult = (result) => { }; function handleToolResultData(result: CallToolResult): void { - if ( - result.isError || - !result.content?.[0] || - result.content[0].type !== "text" - ) { + if (result.isError) { console.error("Tool result error:", result); return; } + // Prefer structuredContent (STRUCTURED_CONTENT_ONLY mode), fall back to parsing text + let response: ToolResponse; + if (result.structuredContent) { + response = result.structuredContent as ToolResponse; + } else if (result.content?.[0]?.type === "text") { + try { + response = JSON.parse(result.content[0].text); + } catch (e) { + console.error("Failed to parse tool result:", result.content[0].text, e); + return; + } + } else { + console.error("No valid content in result:", result); + return; + } + try { - const response: ToolResponse = JSON.parse(result.content[0].text); const { page, links, error } = response; // Ensure the source node exists diff --git a/src/generated/schema.json b/src/generated/schema.json index 91f79688..5af29fe3 100644 --- a/src/generated/schema.json +++ b/src/generated/schema.json @@ -2494,6 +2494,29 @@ "text": { "type": "string" }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, "_meta": { "type": "object", "propertyNames": { @@ -2518,6 +2541,29 @@ "mimeType": { "type": "string" }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, "_meta": { "type": "object", "propertyNames": { @@ -2542,6 +2588,29 @@ "mimeType": { "type": "string" }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, "_meta": { "type": "object", "propertyNames": { @@ -2593,6 +2662,29 @@ "mimeType": { "type": "string" }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, "_meta": { "type": "object", "properties": {}, @@ -2663,6 +2755,29 @@ } ] }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, "_meta": { "type": "object", "propertyNames": { @@ -3752,6 +3867,29 @@ "text": { "type": "string" }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, "_meta": { "type": "object", "propertyNames": { @@ -3776,6 +3914,29 @@ "mimeType": { "type": "string" }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, "_meta": { "type": "object", "propertyNames": { @@ -3800,6 +3961,29 @@ "mimeType": { "type": "string" }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, "_meta": { "type": "object", "propertyNames": { @@ -3851,6 +4035,29 @@ "mimeType": { "type": "string" }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, "_meta": { "type": "object", "properties": {}, @@ -3921,6 +4128,29 @@ } ] }, + "annotations": { + "type": "object", + "properties": { + "audience": { + "type": "array", + "items": { + "type": "string", + "enum": ["user", "assistant"] + } + }, + "priority": { + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "lastModified": { + "type": "string", + "format": "date-time", + "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$" + } + }, + "additionalProperties": false + }, "_meta": { "type": "object", "propertyNames": {