[{"data":1,"prerenderedAt":504},["ShallowReactive",2],{"navigation_docs":3,"-hosts-omp":48,"-hosts-omp-surround":441,"host-views":446},[4,24],{"title":5,"path":6,"stem":7,"children":8,"icon":23},"Guide","\u002Fguide","1.guide\u002F01.index",[9,11,15,19],{"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},"Moving a Package Over","\u002Fguide\u002Fmigrating","1.guide\u002F04.migrating","i-lucide-book-open",{"title":25,"path":26,"stem":27,"children":28,"icon":47},"Hosts","\u002Fhosts","2.hosts\u002F00.index",[29,31,35,39,43],{"title":30,"path":26,"stem":27},"Every host",{"title":32,"path":33,"stem":34},"MCP","\u002Fhosts\u002Fmcp","2.hosts\u002F01.mcp",{"title":36,"path":37,"stem":38},"Pi","\u002Fhosts\u002Fpi","2.hosts\u002F02.pi",{"title":40,"path":41,"stem":42},"OMP","\u002Fhosts\u002Fomp","2.hosts\u002F03.omp",{"title":44,"path":45,"stem":46},"AI SDK","\u002Fhosts\u002Fai-sdk","2.hosts\u002F04.ai-sdk","i-lucide-table",{"id":49,"title":40,"body":50,"description":435,"extension":436,"links":437,"meta":438,"navigation":128,"path":41,"seo":439,"stem":42,"__hash__":440},"docs\u002F2.hosts\u002F03.omp.md",{"type":51,"value":52,"toc":430},"minimark",[53,57,216,221,237,264,267,271,295,306,310,325,416,426],[54,55],"host-facts",{"name":56},"omp",[58,59,65],"pre",{"className":60,"code":61,"filename":62,"language":63,"meta":64,"style":64},"language-ts shiki shiki-themes tools tools tools","import type { ExtensionAPI } from \"@oh-my-pi\u002Fpi-coding-agent\";\nimport { Text } from \"@oh-my-pi\u002Fpi-coding-agent\";\nimport { registerOmpTools } from \"@agntn\u002Ftools\u002Fomp\";\n\nexport default async function (pi: ExtensionAPI) {\n  pi.setLabel(\"My package\");\n  const { tools } = await import(\"..\u002F..\u002F..\u002Fsrc\u002Ftools.ts\");\n  registerOmpTools(pi, tools, { Text });\n}\n","packages\u002Fomp\u002Fextensions\u002Fmypackage.ts","ts","",[66,67,68,94,108,123,130,158,176,201,210],"code",{"__ignoreMap":64},[69,70,73,77,80,84,87,91],"span",{"class":71,"line":72},"line",1,[69,74,76],{"class":75},"skH_V","import",[69,78,79],{"class":75}," type",[69,81,83],{"class":82},"s38Sx"," { ExtensionAPI } ",[69,85,86],{"class":75},"from",[69,88,90],{"class":89},"shU9J"," \"@oh-my-pi\u002Fpi-coding-agent\"",[69,92,93],{"class":82},";\n",[69,95,97,99,102,104,106],{"class":71,"line":96},2,[69,98,76],{"class":75},[69,100,101],{"class":82}," { Text } ",[69,103,86],{"class":75},[69,105,90],{"class":89},[69,107,93],{"class":82},[69,109,111,113,116,118,121],{"class":71,"line":110},3,[69,112,76],{"class":75},[69,114,115],{"class":82}," { registerOmpTools } ",[69,117,86],{"class":75},[69,119,120],{"class":89}," \"@agntn\u002Ftools\u002Fomp\"",[69,122,93],{"class":82},[69,124,126],{"class":71,"line":125},4,[69,127,129],{"emptyLinePlaceholder":128},true,"\n",[69,131,133,136,139,142,145,148,151,155],{"class":71,"line":132},5,[69,134,135],{"class":75},"export",[69,137,138],{"class":75}," default",[69,140,141],{"class":75}," async",[69,143,144],{"class":75}," function",[69,146,147],{"class":82}," (pi",[69,149,150],{"class":75},":",[69,152,154],{"class":153},"sK71F"," ExtensionAPI",[69,156,157],{"class":82},") {\n",[69,159,161,164,167,170,173],{"class":71,"line":160},6,[69,162,163],{"class":82},"  pi.",[69,165,166],{"class":153},"setLabel",[69,168,169],{"class":82},"(",[69,171,172],{"class":89},"\"My package\"",[69,174,175],{"class":82},");\n",[69,177,179,182,185,188,191,194,196,199],{"class":71,"line":178},7,[69,180,181],{"class":75},"  const",[69,183,184],{"class":82}," { tools } ",[69,186,187],{"class":75},"=",[69,189,190],{"class":75}," await",[69,192,193],{"class":75}," import",[69,195,169],{"class":82},[69,197,198],{"class":89},"\"..\u002F..\u002F..\u002Fsrc\u002Ftools.ts\"",[69,200,175],{"class":82},[69,202,204,207],{"class":71,"line":203},8,[69,205,206],{"class":153},"  registerOmpTools",[69,208,209],{"class":82},"(pi, tools, { Text });\n",[69,211,213],{"class":71,"line":212},9,[69,214,215],{"class":82},"}\n",[217,218,220],"h2",{"id":219},"the-typebox-rewrite","The TypeBox rewrite",[222,223,224,225,228,229,232,233,236],"p",{},"OMP rewrites every bare ",[66,226,227],{},"typebox"," import in an extension to its own omptype facade. Your schema turns into a function. A ",[66,230,231],{},"Value.Check"," from ",[66,234,235],{},"typebox\u002Fvalue",", which OMP leaves alone, then accepts anything at all. Nobody tells you. You find out when a model sends garbage and your code runs with it.",[222,238,239,240,243,244,247,248,251,252,255,256,259,260,263],{},"Three things keep that away from you. ",[66,241,242],{},"Type"," comes from ",[66,245,246],{},"@agntn\u002Ftools",", where TypeBox is bundled, so there's no bare import to rewrite. ",[66,249,250],{},"defineTool"," refuses a schema that's a function. And the adapter hands OMP the plain JSON Schema through the host's own ",[66,253,254],{},"pi.typebox.Type.Unsafe",", which validates it with OMP's full JSON Schema validator and keeps ",[66,257,258],{},"pattern"," and ",[66,261,262],{},"maxLength"," in what the model sees.",[222,265,266],{},"Bundling fixed the startup cost too. Unbundled, TypeBox is hundreds of small modules, and every one of them goes through OMP's loader on every start. That was about 200 ms per extension on OMP 18.4.4. Bundled it's about 20, which is noise.",[217,268,270],{"id":269},"approval-and-failures","Approval and failures",[222,272,273,276,277,280,281,259,284,287,288,290,291,294],{},[66,274,275],{},"effect: \"read\""," gives the ",[66,278,279],{},"read"," tier. ",[66,282,283],{},"write",[66,285,286],{},"destructive"," both give ",[66,289,283],{},", since OMP has no tier for \"deletes things\" and ",[66,292,293],{},"exec"," means running commands.",[222,296,297,298,301,302,305],{},"A returned ",[66,299,300],{},"isError"," stays a result, OMP reads it off the object. A bad input throws before ",[66,303,304],{},"execute",".",[217,307,309],{"id":308},"status-lines","Status lines",[222,311,312,313,316,317,320,321,324],{},"The adapter draws the call and result lines with the host theme, never with an import from ",[66,314,315],{},"@oh-my-pi\u002Fpi-coding-agent\u002Ftui",". Compiled OMP gives an extension only the package root, and one import from ",[66,318,319],{},"\u002Ftui"," stops the whole extension from loading. That's why ",[66,322,323],{},"Text"," comes in as an option: you import it in the extension file, where OMP can see it.",[58,326,328],{"className":60,"code":327,"language":63,"meta":64,"style":64},"registerOmpTools(pi, tools, {\n  Text,\n  renderers: {\n    text_slug: {\n      describeCall: (args) => args.text,\n      describeResult: ({ details }) => [`${(details as SlugDetails).words} words`],\n    },\n  },\n});\n",[66,329,330,338,343,348,353,367,401,406,411],{"__ignoreMap":64},[69,331,332,335],{"class":71,"line":72},[69,333,334],{"class":153},"registerOmpTools",[69,336,337],{"class":82},"(pi, tools, {\n",[69,339,340],{"class":71,"line":96},[69,341,342],{"class":82},"  Text,\n",[69,344,345],{"class":71,"line":110},[69,346,347],{"class":82},"  renderers: {\n",[69,349,350],{"class":71,"line":125},[69,351,352],{"class":82},"    text_slug: {\n",[69,354,355,358,361,364],{"class":71,"line":132},[69,356,357],{"class":153},"      describeCall",[69,359,360],{"class":82},": (args) ",[69,362,363],{"class":75},"=>",[69,365,366],{"class":82}," args.text,\n",[69,368,369,372,375,377,380,383,386,389,392,395,398],{"class":71,"line":160},[69,370,371],{"class":153},"      describeResult",[69,373,374],{"class":82},": ({ details }) ",[69,376,363],{"class":75},[69,378,379],{"class":82}," [",[69,381,382],{"class":89},"`${",[69,384,385],{"class":89},"(details ",[69,387,388],{"class":75},"as",[69,390,391],{"class":153}," SlugDetails",[69,393,394],{"class":89},").words",[69,396,397],{"class":89},"} words`",[69,399,400],{"class":82},"],\n",[69,402,403],{"class":71,"line":178},[69,404,405],{"class":82},"    },\n",[69,407,408],{"class":71,"line":203},[69,409,410],{"class":82},"  },\n",[69,412,413],{"class":71,"line":212},[69,414,415],{"class":82},"});\n",[222,417,418,419,422,423,305],{},"Everything those return goes through ",[66,420,421],{},"sanitizeLine"," before the terminal sees it. A result that's an error drops the facts, so a failed call doesn't show a stale summary. For a full preview of long output, pass your own ",[66,424,425],{},"renderResult",[427,428,429],"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 .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":64,"searchDepth":96,"depth":96,"links":431},[432,433,434],{"id":219,"depth":96,"text":220},{"id":269,"depth":96,"text":270},{"id":308,"depth":96,"text":309},"registerOmpTools puts every tool on OMP with an approval tier and a status line. Built around the TypeBox rewrite OMP does behind your back","md",null,{},{"title":40,"description":435},"1qegeC1WYGRscxBvq6OVjf2XUTHtgXvVlgK76q9Hnq0",[442,444],{"title":36,"path":37,"stem":38,"description":443,"children":-1},"registerPiTools puts every tool on Pi with its prompt snippet and guidelines. And throws on failure because older Pi only listens to throws",{"title":44,"path":45,"stem":46,"description":445,"children":-1},"toAiTool turns a definition into an AI SDK tool. The TypeBox schema goes in as it is and nobody writes it again in Zod",[447,466,481,492],{"key":448,"rows":449,"registration":462,"fields":463},"mcp",[450,453,456,459],{"label":451,"value":452},"title","Text Slug",{"label":454,"value":455,"accent":128},"hints","readOnly, idempotent",{"label":457,"value":458},"inputSchema","text, separator",{"label":460,"value":461},"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    \"readOnlyHint\": true,\n    \"destructiveHint\": false,\n    \"idempotentHint\": true,\n    \"openWorldHint\": false\n  }\n}",{"name":464,"label":451,"schema":457,"effect":465,"prompt":437,"run":437},"name","annotations",{"key":467,"rows":468,"registration":478,"fields":479},"pi",[469,471,474,476],{"label":470,"value":452},"label",{"label":472,"value":473,"accent":128},"prompt","snippet, 1 rule",{"label":475,"value":458},"parameters",{"label":460,"value":477},"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":464,"label":470,"schema":475,"effect":437,"prompt":480,"run":304},"promptSnippet",{"key":56,"rows":482,"registration":490,"fields":491},[483,484,486,488],{"label":470,"value":452},{"label":485,"value":279,"accent":128},"approval",{"label":475,"value":487},"Type.Unsafe(json)",{"label":460,"value":489},"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":464,"label":470,"schema":475,"effect":485,"prompt":437,"run":304},{"key":493,"rows":494,"registration":502,"fields":503},"ai",[495,496,498,501],{"label":451,"value":452},{"label":457,"value":497,"accent":128},"jsonSchema()",{"label":499,"value":500},"output","details + text",{"label":460,"value":477},"{\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":437,"label":451,"schema":457,"effect":437,"prompt":437,"run":304},1790784241443]