11# Extending MetaObjects with a custom provider
22
33This recipe walks through adding a new metamodel subtype to a downstream
4- project — using the same ` wizards -template-toolcall` example the conformance
4+ project — using the same ` example -template-toolcall` example the conformance
55fixtures use, so the example here matches a real test that runs in TS, C#,
66and Python.
77
@@ -24,7 +24,7 @@ envelope your app needs to drive Anthropic's `tool_use` mode. You want:
2424 functions.
2525
2626The recipe shows steps 1 + 2. Step 3 (the custom generator) follows the
27- existing ` wizardRegistry ` pattern in this repo — see
27+ existing ` exampleRegistry ` pattern in this repo — see
2828[ ` features/templates-and-payloads.md ` ] ( ../features/templates-and-payloads.md )
2929for how custom generators walk MO-typed metadata.
3030
@@ -33,7 +33,7 @@ for how custom generators walk MO-typed metadata.
3333A provider is ~ 25 lines. Drop it next to your codegen config:
3434
3535``` ts
36- // src/codegen/wizards -provider.ts
36+ // src/codegen/example -provider.ts
3737import {
3838 type MetaDataTypeProvider ,
3939 TYPE_TEMPLATE ,
@@ -44,8 +44,8 @@ import {
4444 ATTR_SUBTYPE_STRING ,
4545} from " @metaobjectsdev/metadata" ;
4646
47- export const wizardsProvider : MetaDataTypeProvider = {
48- id: " wizards -template-toolcall" ,
47+ export const exampleProvider : MetaDataTypeProvider = {
48+ id: " example -template-toolcall" ,
4949 dependencies: [" metaobjects-core-types" ],
5050 description: " Adds template.toolcall for LLM tool-use templates." ,
5151 registerTypes(registry ) {
@@ -89,12 +89,12 @@ Notable bits:
8989// metaobjects.config.ts
9090import { defineConfig } from " @metaobjectsdev/cli" ;
9191import { entityFile , queriesFile , barrel , promptRender } from " @metaobjectsdev/codegen-ts/generators" ;
92- import { wizardsProvider } from " ./src/codegen/wizards -provider" ;
92+ import { exampleProvider } from " ./src/codegen/example -provider" ;
9393
9494export default defineConfig ({
9595 outDir: " src/db/generated" ,
9696 dialect: " sqlite" ,
97- providers: [wizardsProvider ], // ← the new field
97+ providers: [exampleProvider ], // ← the new field
9898 generators: [entityFile (), queriesFile (), barrel (), promptRender ()],
9999});
100100```
@@ -108,20 +108,20 @@ tooling sees the same metamodel.
108108``` jsonc
109109// metaobjects/meta.toolcalls.json
110110{ " metadata.root" : {
111- " package" : " wizards " ,
111+ " package" : " examples " ,
112112 " children" : [
113113 { " object.value" : {
114- " name" : " WizardCall " ,
114+ " name" : " ToolCall " ,
115115 " children" : [
116116 { " field.string" : { " name" : " spell" } },
117117 { " field.string" : { " name" : " target" } }
118118 ]
119119 }},
120120 { " template.toolcall" : {
121- " name" : " InvokeWizard " ,
122- " @payloadRef" : " WizardCall " ,
123- " @textRef" : " wizards /invoke" ,
124- " @toolName" : " invoke_wizard "
121+ " name" : " InvokeTool " ,
122+ " @payloadRef" : " ToolCall " ,
123+ " @textRef" : " tools /invoke" ,
124+ " @toolName" : " invoke_tool "
125125 }}
126126 ]
127127}}
@@ -132,23 +132,23 @@ YAML works just as well:
132132``` yaml
133133# metaobjects/meta.toolcalls.yaml
134134metadata :
135- package : wizards
135+ package : examples
136136 children :
137137 - object.value :
138- name : WizardCall
138+ name : ToolCall
139139 children :
140140 - field.string : { name: spell }
141141 - field.string : { name: target }
142142 - template.toolcall :
143- name : InvokeWizard
144- " @payloadRef " : WizardCall
145- " @textRef " : wizards /invoke
146- " @toolName " : invoke_wizard
143+ name : InvokeTool
144+ " @payloadRef " : ToolCall
145+ " @textRef " : tools /invoke
146+ " @toolName " : invoke_tool
147147` ` `
148148
149149Run ` meta gen` and the loader recognizes `template.toolcall`, validates the
150150three required attrs, and resolves `@payloadRef` against the package's
151- ` WizardCall ` value-object.
151+ ` ToolCall ` value-object.
152152
153153# # 4. What you get from this
154154
@@ -160,8 +160,8 @@ Once the provider is wired, three things happen automatically:
160160- **A traversable AST.** Custom code generators can walk
161161 ` root.ownChildren().filter((c) => c.type === "template" && c.subType === "toolcall")`
162162 to find every toolcall declaration. The
163- [`wizards -template-toolcall` example in
164- the canonical pattern is the existing `wizardRegistry ` generator : it walks
163+ [`example -template-toolcall` example in
164+ the canonical pattern is the existing `exampleRegistry ` generator : it walks
165165 ` root.ownChildren()` filtered by `(type, subType)` and emits one TS file per
166166 matched node. Custom toolcall generators do the same — emit
167167 ` callEmit<Name>(params)` wrapper functions, one per toolcall declaration.
@@ -178,12 +178,12 @@ $ meta gen
178178
179179$ meta verify
180180✓ No metadata drift. 4 providers composed:
181- metaobjects-core-types, metaobjects-forge, metaobjects-documentation, wizards -template-toolcall
181+ metaobjects-core-types, metaobjects-forge, metaobjects-documentation, example -template-toolcall
182182` ` `
183183
184184# # What happens when the provider is missing
185185
186- Forget to add `providers : [wizardsProvider ]` to `defineConfig` (or to delete
186+ Forget to add `providers : [exampleProvider ]` to `defineConfig` (or to delete
187187the provider entirely), and the same metadata fails to load :
188188
189189` ` `
@@ -208,7 +208,7 @@ is the API surface for loader composition. See the per-port quickstarts:
208208
209209The provider object itself is structurally identical across languages
210210(id + dependencies + description + a body that calls `registry.register` or
211- ` registry.extend` ). A C# port of `wizardsProvider ` reads exactly like the TS
211+ ` registry.extend` ). A C# port of `exampleProvider ` reads exactly like the TS
212212version with C# spelling.
213213
214214# # When NOT to write a provider
0 commit comments