[{"data":1,"prerenderedAt":324},["ShallowReactive",2],{"navigation_docs":3,"-hosts-ai-sdk":52,"-hosts-ai-sdk-surround":263,"host-views":266},[4,28],{"title":5,"path":6,"stem":7,"children":8,"icon":27},"Guide","\u002Fguide","1.guide\u002F01.index",[9,11,15,19,23],{"title":10,"path":6,"stem":7},"Getting Started",{"title":12,"path":13,"stem":14},"Defining Tools","\u002Fguide\u002Fdefining-tools","1.guide\u002F02.defining-tools",{"title":16,"path":17,"stem":18},"Validation and Errors","\u002Fguide\u002Fvalidation","1.guide\u002F03.validation",{"title":20,"path":21,"stem":22},"CLI","\u002Fguide\u002Fcli","1.guide\u002F04.cli",{"title":24,"path":25,"stem":26},"Moving a Package Over","\u002Fguide\u002Fmigrating","1.guide\u002F05.migrating","i-lucide-book-open",{"title":29,"path":30,"stem":31,"children":32,"icon":51},"Hosts","\u002Fhosts","2.hosts\u002F00.index",[33,35,39,43,47],{"title":34,"path":30,"stem":31},"Every host",{"title":36,"path":37,"stem":38},"MCP","\u002Fhosts\u002Fmcp","2.hosts\u002F01.mcp",{"title":40,"path":41,"stem":42},"Pi","\u002Fhosts\u002Fpi","2.hosts\u002F02.pi",{"title":44,"path":45,"stem":46},"OMP","\u002Fhosts\u002Fomp","2.hosts\u002F03.omp",{"title":48,"path":49,"stem":50},"AI SDK","\u002Fhosts\u002Fai-sdk","2.hosts\u002F04.ai-sdk","i-lucide-table",{"id":53,"title":48,"body":54,"description":257,"extension":258,"links":259,"meta":260,"navigation":115,"path":49,"seo":261,"stem":50,"__hash__":262},"docs\u002F2.hosts\u002F04.ai-sdk.md",{"type":55,"value":56,"toc":251},"minimark",[57,61,156,164,169,187,198,202,212,216,233,237,247],[58,59],"host-facts",{"name":60},"ai",[62,63,69],"pre",{"className":64,"code":65,"filename":66,"language":67,"meta":68,"style":68},"language-ts shiki shiki-themes tools tools tools","import { toAiTool, toAiTools } from \"@agntn\u002Ftools\u002Fai\";\nimport { slugTool, tools } from \".\u002Ftools.ts\";\n\nconst one = toAiTool(slugTool);\nconst all = toAiTools(tools); \u002F\u002F keyed by tool name\n","agent.ts","ts","",[70,71,72,95,110,117,136],"code",{"__ignoreMap":68},[73,74,77,81,85,88,92],"span",{"class":75,"line":76},"line",1,[73,78,80],{"class":79},"skH_V","import",[73,82,84],{"class":83},"s38Sx"," { toAiTool, toAiTools } ",[73,86,87],{"class":79},"from",[73,89,91],{"class":90},"shU9J"," \"@agntn\u002Ftools\u002Fai\"",[73,93,94],{"class":83},";\n",[73,96,98,100,103,105,108],{"class":75,"line":97},2,[73,99,80],{"class":79},[73,101,102],{"class":83}," { slugTool, tools } ",[73,104,87],{"class":79},[73,106,107],{"class":90}," \".\u002Ftools.ts\"",[73,109,94],{"class":83},[73,111,113],{"class":75,"line":112},3,[73,114,116],{"emptyLinePlaceholder":115},true,"\n",[73,118,120,123,126,129,133],{"class":75,"line":119},4,[73,121,122],{"class":79},"const",[73,124,125],{"class":83}," one ",[73,127,128],{"class":79},"=",[73,130,132],{"class":131},"sK71F"," toAiTool",[73,134,135],{"class":83},"(slugTool);\n",[73,137,139,141,144,146,149,152],{"class":75,"line":138},5,[73,140,122],{"class":79},[73,142,143],{"class":83}," all ",[73,145,128],{"class":79},[73,147,148],{"class":131}," toAiTools",[73,150,151],{"class":83},"(tools); ",[73,153,155],{"class":154},"scIB-","\u002F\u002F keyed by tool name\n",[157,158,159,160,163],"p",{},"The schema goes through the AI SDK's ",[70,161,162],{},"jsonSchema()"," with the core's validator attached. So the model sees the same JSON Schema every other host sees, and a bad input gets refused with the same lines. No second schema in Zod. That used to be the fourth copy.",[165,166,168],"h2",{"id":167},"the-output","The output",[157,170,171,174,175,178,179,182,183,186],{},[70,172,173],{},"execute"," returns the details with the text added: ",[70,176,177],{},"{ ...details, text }",". The AI SDK hands that object to the model as JSON, so it gets the structured facts and the sentence a human would read. When ",[70,180,181],{},"details"," isn't an object, you get ",[70,184,185],{},"{ details, text }",".",[157,188,189,190,193,194,197],{},"A details object with its own ",[70,191,192],{},"text"," field would lose it under the spread, so the adapter throws a ",[70,195,196],{},"ToolDefinitionError"," instead of guessing. Rename the field.",[165,199,201],{"id":200},"failures","Failures",[157,203,204,205,207,208,211],{},"A bad input is refused by the input schema before ",[70,206,173],{},". A result with ",[70,209,210],{},"isError"," throws its text, and the AI SDK turns any throw into a tool error the model can read.",[165,213,215],{"id":214},"progress","Progress",[157,217,218,219,221,222,225,226,228,229,232],{},"There's nowhere to put it. ",[70,220,214],{}," is ",[70,223,224],{},"undefined"," in ",[70,227,173],{},", and a tool that calls it with ",[70,230,231],{},"?."," just keeps going.",[165,234,236],{"id":235},"types","Types",[157,238,239,242,243,246],{},[70,240,241],{},"toAiTool"," keeps the input and details types. When you export the tool from a package, annotate it with your own types, ",[70,244,245],{},"Tool\u003CSearchParams, AiToolOutput\u003CSearchDetails>>",". The inferred type points into the bundled TypeBox, and your declaration build can't name it.",[248,249,250],"style",{},"html pre.shiki code .skH_V, html code.shiki .skH_V{--shiki-light:var(--shiki-token-keyword);--shiki-default:var(--shiki-token-keyword);--shiki-dark:var(--shiki-token-keyword)}html pre.shiki code .s38Sx, html code.shiki .s38Sx{--shiki-light:var(--ui-text-highlighted);--shiki-default:var(--ui-text-highlighted);--shiki-dark:var(--ui-text-highlighted)}html pre.shiki code .shU9J, html code.shiki .shU9J{--shiki-light:var(--shiki-token-string);--shiki-default:var(--shiki-token-string);--shiki-dark:var(--shiki-token-string)}html pre.shiki code .sK71F, html code.shiki .sK71F{--shiki-light:var(--shiki-token-function);--shiki-default:var(--shiki-token-function);--shiki-dark:var(--shiki-token-function)}html pre.shiki code .scIB-, html code.shiki .scIB-{--shiki-light:var(--shiki-token-comment);--shiki-default:var(--shiki-token-comment);--shiki-dark:var(--shiki-token-comment)}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":68,"searchDepth":97,"depth":97,"links":252},[253,254,255,256],{"id":167,"depth":97,"text":168},{"id":200,"depth":97,"text":201},{"id":214,"depth":97,"text":215},{"id":235,"depth":97,"text":236},"toAiTool turns a definition into an AI SDK tool. The TypeBox schema goes in as it is and nobody writes it again in Zod","md",null,{},{"title":48,"description":257},"u2HpgSyjRaQGGJljMPcrvr3IXxICDIgugrNxKIc-40k",[264,259],{"title":44,"path":45,"stem":46,"description":265,"children":-1},"registerOmpTools puts every tool on OMP with an approval tier and a status line. Built around the TypeBox rewrite OMP does behind your back",[267,286,301,314],{"key":268,"rows":269,"registration":282,"fields":283},"mcp",[270,273,276,279],{"label":271,"value":272},"title","Text Slug",{"label":274,"value":275,"accent":115},"hints","readOnly, idempotent",{"label":277,"value":278},"inputSchema","text, separator",{"label":280,"value":281},"failure","isError: true","{\n  \"name\": \"text_slug\",\n  \"title\": \"Text Slug\",\n  \"description\": \"Turn a title into a lowercase URL slug. Letters and digits stay, accents lose their marks, the rest becomes the separator.\",\n  \"inputSchema\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"text\": {\n        \"type\": \"string\",\n        \"minLength\": 1,\n        \"maxLength\": 200,\n        \"pattern\": \"\\\\S\",\n        \"description\": \"Title to slug\"\n      },\n      \"separator\": {\n        \"enum\": [\n          \"-\",\n          \"_\",\n          \".\"\n        ],\n        \"description\": \"Joins the words. '-' when omitted\"\n      }\n    },\n    \"required\": [\n      \"text\"\n    ],\n    \"additionalProperties\": false\n  },\n  \"annotations\": {\n    \"title\": \"Text Slug\",\n    \"readOnlyHint\": true,\n    \"destructiveHint\": false,\n    \"idempotentHint\": true,\n    \"openWorldHint\": false\n  }\n}",{"name":284,"label":271,"schema":277,"effect":285,"prompt":259,"run":259},"name","annotations",{"key":287,"rows":288,"registration":298,"fields":299},"pi",[289,291,294,296],{"label":290,"value":272},"label",{"label":292,"value":293,"accent":115},"prompt","snippet, 1 rule",{"label":295,"value":278},"parameters",{"label":280,"value":297},"thrown","{\n  \"name\": \"text_slug\",\n  \"label\": \"Text Slug\",\n  \"description\": \"Turn a title into a lowercase URL slug. Letters and digits stay, accents lose their marks, the rest becomes the separator.\",\n  \"promptSnippet\": \"Use text_slug to turn a title into a URL slug.\",\n  \"promptGuidelines\": [\n    \"Pass separator '_' for identifiers. The default '-' is for URLs.\"\n  ],\n  \"parameters\": {\n    \"type\": \"object\",\n    \"required\": [\n      \"text\"\n    ],\n    \"properties\": {\n      \"text\": {\n        \"type\": \"string\",\n        \"minLength\": 1,\n        \"maxLength\": 200,\n        \"pattern\": \"\\\\S\",\n        \"description\": \"Title to slug\"\n      },\n      \"separator\": {\n        \"enum\": [\n          \"-\",\n          \"_\",\n          \".\"\n        ],\n        \"description\": \"Joins the words. '-' when omitted\"\n      }\n    },\n    \"additionalProperties\": false\n  },\n  \"execute\": \"[function]\"\n}",{"name":284,"label":290,"schema":295,"effect":259,"prompt":300,"run":173},"promptSnippet",{"key":302,"rows":303,"registration":312,"fields":313},"omp",[304,305,308,310],{"label":290,"value":272},{"label":306,"value":307,"accent":115},"approval","read",{"label":295,"value":309},"Type.Unsafe(json)",{"label":280,"value":311},"isError or thrown","{\n  \"name\": \"text_slug\",\n  \"label\": \"Text Slug\",\n  \"description\": \"Turn a title into a lowercase URL slug. Letters and digits stay, accents lose their marks, the rest becomes the separator.\",\n  \"parameters\": {\n    \"unsafe\": {\n      \"type\": \"object\",\n      \"required\": [\n        \"text\"\n      ],\n      \"properties\": {\n        \"text\": {\n          \"type\": \"string\",\n          \"minLength\": 1,\n          \"maxLength\": 200,\n          \"pattern\": \"\\\\S\",\n          \"description\": \"Title to slug\"\n        },\n        \"separator\": {\n          \"enum\": [\n            \"-\",\n            \"_\",\n            \".\"\n          ],\n          \"description\": \"Joins the words. '-' when omitted\"\n        }\n      },\n      \"additionalProperties\": false\n    }\n  },\n  \"approval\": \"read\",\n  \"execute\": \"[function]\",\n  \"renderCall\": \"[function]\",\n  \"renderResult\": \"[function]\"\n}",{"name":284,"label":290,"schema":295,"effect":306,"prompt":259,"run":173},{"key":60,"rows":315,"registration":322,"fields":323},[316,317,318,321],{"label":271,"value":272},{"label":277,"value":162,"accent":115},{"label":319,"value":320},"output","details + text",{"label":280,"value":297},"{\n  \"title\": \"Text Slug\",\n  \"description\": \"Turn a title into a lowercase URL slug. Letters and digits stay, accents lose their marks, the rest becomes the separator.\",\n  \"inputSchema\": {\n    \"type\": \"object\",\n    \"required\": [\n      \"text\"\n    ],\n    \"properties\": {\n      \"text\": {\n        \"type\": \"string\",\n        \"minLength\": 1,\n        \"maxLength\": 200,\n        \"pattern\": \"\\\\S\",\n        \"description\": \"Title to slug\"\n      },\n      \"separator\": {\n        \"enum\": [\n          \"-\",\n          \"_\",\n          \".\"\n        ],\n        \"description\": \"Joins the words. '-' when omitted\"\n      }\n    },\n    \"additionalProperties\": false\n  },\n  \"execute\": \"[function]\"\n}",{"name":259,"label":271,"schema":277,"effect":259,"prompt":259,"run":173},1791469407217]