@noodleseed/agent-kit 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/manifest.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
- "packageVersion": "0.16.0",
2
+ "packageVersion": "0.17.0",
3
3
  "files": [
4
4
  {
5
5
  "path": "skills/codex/SKILL.md",
6
- "sha256": "5a709e078dbc9e5ab9194e35e1cef93936c62f2c4e826877028ec269162d9b7c",
6
+ "sha256": "5f24dd83ca00ad0b078de17f0a978b28ee17b17678ab103a0151f550444e1c47",
7
7
  "agentTarget": "codex"
8
8
  },
9
9
  {
10
10
  "path": "skills/codex/references/sdk-surface.md",
11
- "sha256": "410fe309a6091b469892edc55c8083b0643cae7706b3769e9b836546a6ad1235",
11
+ "sha256": "7275aedfb2338040f1b9f989765179ce970d1b25c77066b3d3f4f4e2fe39f7cc",
12
12
  "agentTarget": "codex"
13
13
  },
14
14
  {
@@ -28,12 +28,12 @@
28
28
  },
29
29
  {
30
30
  "path": "skills/codex/references/authoring-workflow.md",
31
- "sha256": "eca8d1f2b98ee64f6beda4d983f0f0df9023ceed8bd00ffb9dd6b5025dcaa4e4",
31
+ "sha256": "bf59d1550ce72fa188e50e74b7d586be49a0e5473501ee3b83a5f41687ac5163",
32
32
  "agentTarget": "codex"
33
33
  },
34
34
  {
35
35
  "path": "skills/codex/references/connect-an-api.md",
36
- "sha256": "890dd3a73a73e29f0cad88d1fb1b4ebc24791b791cfffb130143b26f714e9da0",
36
+ "sha256": "497221256ebb78300b5e4055daff3f222052a7b78fb829fd24171668dd7fc0fa",
37
37
  "agentTarget": "codex"
38
38
  },
39
39
  {
@@ -268,7 +268,7 @@
268
268
  },
269
269
  {
270
270
  "path": "skills/codex/examples/food-ordering/src/server.ts",
271
- "sha256": "760817a7c1731cf0f5d721fc2fb9adcaa7c2cfe0cbaae5d97e7673a535de26b8",
271
+ "sha256": "491e7e7e8289d4295d09ca2a5f7035f00a06e1d9f3349c406397f90a966269df",
272
272
  "agentTarget": "codex"
273
273
  },
274
274
  {
@@ -338,7 +338,7 @@
338
338
  },
339
339
  {
340
340
  "path": "skills/codex/examples/weather/src/server.ts",
341
- "sha256": "4af1ea8c9ed5d41456bfa52b4b0245a3d482f4a95ef4e994b2758dd32c1c52ce",
341
+ "sha256": "95cd3a2ef47be898469d40d109f3fb89ac6e59a34fd8ad600c80dfe2908d4598",
342
342
  "agentTarget": "codex"
343
343
  },
344
344
  {
@@ -348,12 +348,12 @@
348
348
  },
349
349
  {
350
350
  "path": "skills/claude-code/SKILL.md",
351
- "sha256": "0a3e1998439a89d14887c9e533a225e7f83dbfdedffd278eb773213d3758e469",
351
+ "sha256": "24cdedbf4db8484b6e06823037b5b8fd0ef7ee39a57eb0fd135d167196fea3ff",
352
352
  "agentTarget": "claude-code"
353
353
  },
354
354
  {
355
355
  "path": "skills/claude-code/references/sdk-surface.md",
356
- "sha256": "410fe309a6091b469892edc55c8083b0643cae7706b3769e9b836546a6ad1235",
356
+ "sha256": "7275aedfb2338040f1b9f989765179ce970d1b25c77066b3d3f4f4e2fe39f7cc",
357
357
  "agentTarget": "claude-code"
358
358
  },
359
359
  {
@@ -373,12 +373,12 @@
373
373
  },
374
374
  {
375
375
  "path": "skills/claude-code/references/authoring-workflow.md",
376
- "sha256": "eca8d1f2b98ee64f6beda4d983f0f0df9023ceed8bd00ffb9dd6b5025dcaa4e4",
376
+ "sha256": "bf59d1550ce72fa188e50e74b7d586be49a0e5473501ee3b83a5f41687ac5163",
377
377
  "agentTarget": "claude-code"
378
378
  },
379
379
  {
380
380
  "path": "skills/claude-code/references/connect-an-api.md",
381
- "sha256": "890dd3a73a73e29f0cad88d1fb1b4ebc24791b791cfffb130143b26f714e9da0",
381
+ "sha256": "497221256ebb78300b5e4055daff3f222052a7b78fb829fd24171668dd7fc0fa",
382
382
  "agentTarget": "claude-code"
383
383
  },
384
384
  {
@@ -613,7 +613,7 @@
613
613
  },
614
614
  {
615
615
  "path": "skills/claude-code/examples/food-ordering/src/server.ts",
616
- "sha256": "760817a7c1731cf0f5d721fc2fb9adcaa7c2cfe0cbaae5d97e7673a535de26b8",
616
+ "sha256": "491e7e7e8289d4295d09ca2a5f7035f00a06e1d9f3349c406397f90a966269df",
617
617
  "agentTarget": "claude-code"
618
618
  },
619
619
  {
@@ -683,7 +683,7 @@
683
683
  },
684
684
  {
685
685
  "path": "skills/claude-code/examples/weather/src/server.ts",
686
- "sha256": "4af1ea8c9ed5d41456bfa52b4b0245a3d482f4a95ef4e994b2758dd32c1c52ce",
686
+ "sha256": "95cd3a2ef47be898469d40d109f3fb89ac6e59a34fd8ad600c80dfe2908d4598",
687
687
  "agentTarget": "claude-code"
688
688
  },
689
689
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodleseed/agent-kit",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "private": false,
5
5
  "description": "Self-checking, self-updating agent skills for the Noodle Seed CLI. Authored in this repo by @noodle-borg/agent-kit; this is the published, independently-versioned canonical skills artifact the CLI fetches and verifies.",
6
6
  "license": "Apache-2.0",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: noodle-seed
3
3
  description: Use when building, validating, testing, deploying, or operating a local or hosted Noodle Seed MCP server or app authored in TypeScript with the noodle CLI.
4
- version: 0.16.0
4
+ version: 0.17.0
5
5
  hash: b4952708b1c38f55
6
6
  ---
7
7
 
@@ -17,28 +17,28 @@ const state = connector('noodle_state')
17
17
  .version('1.0.0')
18
18
  .operation('read_state', {
19
19
  type: 'read',
20
- input: {
21
- handle: { type: 'string', required: true },
22
- key: { type: 'string' },
23
- },
24
- output: {
25
- value: { type: 'object', required: true },
26
- revision: { type: 'integer', required: true },
27
- status: { type: 'string', required: true },
28
- },
20
+ input: z.object({
21
+ handle: z.string(),
22
+ key: z.string().optional(),
23
+ }),
24
+ output: z.object({
25
+ value: z.record(z.string(), z.unknown()),
26
+ revision: z.number().int(),
27
+ status: z.string(),
28
+ }),
29
29
  })
30
30
  .operation('patch_state', {
31
31
  type: 'action',
32
- input: {
33
- handle: { type: 'string', required: true },
34
- expectedRevision: { type: 'integer', required: true },
35
- value: { type: 'object', required: true },
36
- },
37
- output: {
38
- value: { type: 'object', required: true },
39
- revision: { type: 'integer', required: true },
40
- status: { type: 'string', required: true },
41
- },
32
+ input: z.object({
33
+ handle: z.string(),
34
+ expectedRevision: z.number().int(),
35
+ value: z.record(z.string(), z.unknown()),
36
+ }),
37
+ output: z.object({
38
+ value: z.record(z.string(), z.unknown()),
39
+ revision: z.number().int(),
40
+ status: z.string(),
41
+ }),
42
42
  });
43
43
 
44
44
  const stores = [
@@ -19,13 +19,13 @@ const geocoding = connector('open_meteo_geocoding')
19
19
  method: 'GET',
20
20
  path: '/v1/search',
21
21
  query: ['name'],
22
- input: { name: { type: 'string', required: true } },
23
- output: {
24
- latitude: { type: 'number', required: true },
25
- longitude: { type: 'number', required: true },
26
- place: { type: 'string' },
27
- country: { type: 'string' },
28
- },
22
+ input: z.object({ name: z.string() }),
23
+ output: z.object({
24
+ latitude: z.number(),
25
+ longitude: z.number(),
26
+ place: z.string().optional(),
27
+ country: z.string().optional(),
28
+ }),
29
29
  response: {
30
30
  latitude: '${response.results[0].latitude}',
31
31
  longitude: '${response.results[0].longitude}',
@@ -44,13 +44,8 @@ const geocoding = connector('open_meteo_geocoding')
44
44
  method: 'GET',
45
45
  path: '/v1/search',
46
46
  query: ['name', 'count'],
47
- input: {
48
- name: { type: 'string', required: true },
49
- count: { type: 'number' },
50
- },
51
- output: {
52
- results: { type: 'array' },
53
- },
47
+ input: z.object({ name: z.string(), count: z.number().optional() }),
48
+ output: z.object({ results: z.array(z.unknown()).optional() }),
54
49
  response: {
55
50
  results: '${response.results}',
56
51
  },
@@ -69,15 +64,12 @@ const forecast = connector('open_meteo_forecast')
69
64
  method: 'GET',
70
65
  path: '/v1/forecast?current_weather=true',
71
66
  query: ['latitude', 'longitude'],
72
- input: {
73
- latitude: { type: 'number', required: true },
74
- longitude: { type: 'number', required: true },
75
- },
76
- output: {
77
- temperature: { type: 'number' },
78
- windspeed: { type: 'number' },
79
- weathercode: { type: 'number' },
80
- },
67
+ input: z.object({ latitude: z.number(), longitude: z.number() }),
68
+ output: z.object({
69
+ temperature: z.number().optional(),
70
+ windspeed: z.number().optional(),
71
+ weathercode: z.number().optional(),
72
+ }),
81
73
  response: {
82
74
  temperature: '${response.current_weather.temperature}',
83
75
  windspeed: '${response.current_weather.windspeed}',
@@ -91,18 +83,18 @@ const brief = connector('weather_brief')
91
83
  .version('1.0.0')
92
84
  .compute('summarize', {
93
85
  type: 'read',
94
- input: {
95
- place: { type: 'string', required: true },
96
- country: { type: 'string' },
97
- temperature: { type: 'number', required: true },
98
- windspeed: { type: 'number', required: true },
99
- weathercode: { type: 'number', required: true },
100
- },
101
- output: {
102
- conditions: { type: 'string', required: true },
103
- headline: { type: 'string', required: true },
104
- advice: { type: 'string', required: true },
105
- },
86
+ input: z.object({
87
+ place: z.string(),
88
+ country: z.string().optional(),
89
+ temperature: z.number(),
90
+ windspeed: z.number(),
91
+ weathercode: z.number(),
92
+ }),
93
+ output: z.object({
94
+ conditions: z.string(),
95
+ headline: z.string(),
96
+ advice: z.string(),
97
+ }),
106
98
  // A real function — type-checked here, serialized to source and run in the sandbox. It must be
107
99
  // self-contained: no imports, no closure over outer variables, synchronous.
108
100
  run: (input) => {
@@ -162,12 +154,8 @@ const placeNarrow = connector('geo_places')
162
154
  .version('1.0.0')
163
155
  .compute('narrow', {
164
156
  type: 'read',
165
- input: {
166
- results: { type: 'unknown' },
167
- },
168
- output: {
169
- places: { type: 'array', required: true },
170
- },
157
+ input: z.object({ results: z.unknown().optional() }),
158
+ output: z.object({ places: z.array(z.unknown()) }),
171
159
  // Self-contained: no imports, no closure over outer variables, synchronous.
172
160
  run: (input) => {
173
161
  const raw = input.results;
@@ -55,16 +55,16 @@ const crm = connector('crm').version('1.0.0').http({
55
55
  method: 'GET',
56
56
  path: '/customers',
57
57
  query: ['email'],
58
- input: { email: { type: 'string', required: true } },
59
- output: { id: { type: 'string', required: true }, name: { type: 'string' } },
58
+ input: z.object({ email: z.string() }),
59
+ output: z.object({ id: z.string(), name: z.string().optional() }),
60
60
  response: { id: '${response.data[0].id}', name: '${response.data[0].name}' },
61
61
  },
62
62
  create_ticket: {
63
63
  type: 'action',
64
64
  method: 'POST',
65
65
  path: '/tickets',
66
- input: { customer_id: { type: 'string', required: true }, body: { type: 'string', required: true } },
67
- output: { ticket_id: { type: 'string', required: true } },
66
+ input: z.object({ customer_id: z.string(), body: z.string() }),
67
+ output: z.object({ ticket_id: z.string() }),
68
68
  request: { customer_id: '${args.customer_id}', body: '${args.body}' },
69
69
  response: { ticket_id: '${response.id}' },
70
70
  },
@@ -120,16 +120,16 @@ const tasks = connector('tasks').version('1.0.0').http({
120
120
  method: 'GET',
121
121
  path: '/tasks',
122
122
  query: ['query'],
123
- input: { query: { type: 'string', required: true } },
124
- output: { matches: { type: 'array', required: true } },
123
+ input: z.object({ query: z.string() }),
124
+ output: z.object({ matches: z.array(z.unknown()) }),
125
125
  response: { matches: '${response.results}' },
126
126
  },
127
127
  close_task: {
128
128
  type: 'action',
129
129
  method: 'POST',
130
130
  path: '/tasks/{id}/close',
131
- input: { id: { type: 'string', required: true } },
132
- output: { ok: { type: 'boolean', required: true } },
131
+ input: z.object({ id: z.string() }),
132
+ output: z.object({ ok: z.boolean() }),
133
133
  response: { ok: '${response.ok}' },
134
134
  },
135
135
  },
@@ -163,8 +163,8 @@ The model never sees a task id from the user; `find_tasks` returns `{ id, title
163
163
 
164
164
  ```ts
165
165
  const scoring = connector('scoring').version('1.0.0').compute('normalize', {
166
- input: { email: { type: "string", required: true }, priority: { type: "string" } },
167
- output: { score: { type: "number", required: true } },
166
+ input: z.object({ email: z.string(), priority: z.string().optional() }),
167
+ output: z.object({ score: z.number() }),
168
168
  calls: { find_customer: 'crm.find_customer' },
169
169
  limits: { timeoutMs: 1000, maxHostCalls: 2 },
170
170
  run(input, { callOperation }) {
@@ -62,7 +62,7 @@ Most real tools return a variable-length list (search results, a user’s tasks)
62
62
 
63
63
  ```ts
64
64
  // The API returns { results: [ { id, name, country, … }, … ] }
65
- output: { places: { type: 'array' } },
65
+ output: z.object({ places: z.array(z.unknown()) }),
66
66
  response: { places: '${response.results}' },
67
67
  ```
68
68
 
@@ -96,7 +96,7 @@ Pair the read/list with the mutations your intent tools need:
96
96
  ```ts
97
97
  close_task: {
98
98
  type: 'action', method: 'POST', path: '/tasks/{id}/close',
99
- input: { id: { type: 'string', required: true } },
99
+ input: z.object({ id: z.string() }),
100
100
  responseType: 'empty',
101
101
  },
102
102
  ```
@@ -144,8 +144,8 @@ const crm = connector('crm')
144
144
  method: 'GET',
145
145
  path: '/tickets',
146
146
  query: ['id'],
147
- input: { id: { type: 'string', required: true } },
148
- output: { subject: { type: 'string' }, status: { type: 'string' } },
147
+ input: z.object({ id: z.string() }),
148
+ output: z.object({ subject: z.string().optional(), status: z.string().optional() }),
149
149
  response: { subject: '${response.subject}', status: '${response.status}' },
150
150
  },
151
151
  },
@@ -195,8 +195,8 @@ const orders = connector('orders')
195
195
  method: 'GET',
196
196
  path: '/orders',
197
197
  query: ['id'],
198
- input: { id: { type: 'string', required: true } },
199
- output: { id: { type: 'string' }, status: { type: 'string' } },
198
+ input: z.object({ id: z.string() }),
199
+ output: z.object({ id: z.string().optional(), status: z.string().optional() }),
200
200
  response: { id: '${response.id}', status: '${response.status}' },
201
201
  },
202
202
  get_tracking: {
@@ -204,8 +204,8 @@ const orders = connector('orders')
204
204
  method: 'GET',
205
205
  path: '/tracking',
206
206
  query: ['order_id'],
207
- input: { order_id: { type: 'string', required: true } },
208
- output: { url: { type: 'string' } },
207
+ input: z.object({ order_id: z.string() }),
208
+ output: z.object({ url: z.string().optional() }),
209
209
  response: { url: '${response.url}' },
210
210
  },
211
211
  },
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: noodle-seed
3
3
  description: Use when building, validating, testing, deploying, or operating a local or hosted Noodle Seed MCP server or app authored in TypeScript with the noodle CLI.
4
- version: 0.16.0
4
+ version: 0.17.0
5
5
  hash: 39c6a606c728d164
6
6
  ---
7
7
 
@@ -17,28 +17,28 @@ const state = connector('noodle_state')
17
17
  .version('1.0.0')
18
18
  .operation('read_state', {
19
19
  type: 'read',
20
- input: {
21
- handle: { type: 'string', required: true },
22
- key: { type: 'string' },
23
- },
24
- output: {
25
- value: { type: 'object', required: true },
26
- revision: { type: 'integer', required: true },
27
- status: { type: 'string', required: true },
28
- },
20
+ input: z.object({
21
+ handle: z.string(),
22
+ key: z.string().optional(),
23
+ }),
24
+ output: z.object({
25
+ value: z.record(z.string(), z.unknown()),
26
+ revision: z.number().int(),
27
+ status: z.string(),
28
+ }),
29
29
  })
30
30
  .operation('patch_state', {
31
31
  type: 'action',
32
- input: {
33
- handle: { type: 'string', required: true },
34
- expectedRevision: { type: 'integer', required: true },
35
- value: { type: 'object', required: true },
36
- },
37
- output: {
38
- value: { type: 'object', required: true },
39
- revision: { type: 'integer', required: true },
40
- status: { type: 'string', required: true },
41
- },
32
+ input: z.object({
33
+ handle: z.string(),
34
+ expectedRevision: z.number().int(),
35
+ value: z.record(z.string(), z.unknown()),
36
+ }),
37
+ output: z.object({
38
+ value: z.record(z.string(), z.unknown()),
39
+ revision: z.number().int(),
40
+ status: z.string(),
41
+ }),
42
42
  });
43
43
 
44
44
  const stores = [
@@ -19,13 +19,13 @@ const geocoding = connector('open_meteo_geocoding')
19
19
  method: 'GET',
20
20
  path: '/v1/search',
21
21
  query: ['name'],
22
- input: { name: { type: 'string', required: true } },
23
- output: {
24
- latitude: { type: 'number', required: true },
25
- longitude: { type: 'number', required: true },
26
- place: { type: 'string' },
27
- country: { type: 'string' },
28
- },
22
+ input: z.object({ name: z.string() }),
23
+ output: z.object({
24
+ latitude: z.number(),
25
+ longitude: z.number(),
26
+ place: z.string().optional(),
27
+ country: z.string().optional(),
28
+ }),
29
29
  response: {
30
30
  latitude: '${response.results[0].latitude}',
31
31
  longitude: '${response.results[0].longitude}',
@@ -44,13 +44,8 @@ const geocoding = connector('open_meteo_geocoding')
44
44
  method: 'GET',
45
45
  path: '/v1/search',
46
46
  query: ['name', 'count'],
47
- input: {
48
- name: { type: 'string', required: true },
49
- count: { type: 'number' },
50
- },
51
- output: {
52
- results: { type: 'array' },
53
- },
47
+ input: z.object({ name: z.string(), count: z.number().optional() }),
48
+ output: z.object({ results: z.array(z.unknown()).optional() }),
54
49
  response: {
55
50
  results: '${response.results}',
56
51
  },
@@ -69,15 +64,12 @@ const forecast = connector('open_meteo_forecast')
69
64
  method: 'GET',
70
65
  path: '/v1/forecast?current_weather=true',
71
66
  query: ['latitude', 'longitude'],
72
- input: {
73
- latitude: { type: 'number', required: true },
74
- longitude: { type: 'number', required: true },
75
- },
76
- output: {
77
- temperature: { type: 'number' },
78
- windspeed: { type: 'number' },
79
- weathercode: { type: 'number' },
80
- },
67
+ input: z.object({ latitude: z.number(), longitude: z.number() }),
68
+ output: z.object({
69
+ temperature: z.number().optional(),
70
+ windspeed: z.number().optional(),
71
+ weathercode: z.number().optional(),
72
+ }),
81
73
  response: {
82
74
  temperature: '${response.current_weather.temperature}',
83
75
  windspeed: '${response.current_weather.windspeed}',
@@ -91,18 +83,18 @@ const brief = connector('weather_brief')
91
83
  .version('1.0.0')
92
84
  .compute('summarize', {
93
85
  type: 'read',
94
- input: {
95
- place: { type: 'string', required: true },
96
- country: { type: 'string' },
97
- temperature: { type: 'number', required: true },
98
- windspeed: { type: 'number', required: true },
99
- weathercode: { type: 'number', required: true },
100
- },
101
- output: {
102
- conditions: { type: 'string', required: true },
103
- headline: { type: 'string', required: true },
104
- advice: { type: 'string', required: true },
105
- },
86
+ input: z.object({
87
+ place: z.string(),
88
+ country: z.string().optional(),
89
+ temperature: z.number(),
90
+ windspeed: z.number(),
91
+ weathercode: z.number(),
92
+ }),
93
+ output: z.object({
94
+ conditions: z.string(),
95
+ headline: z.string(),
96
+ advice: z.string(),
97
+ }),
106
98
  // A real function — type-checked here, serialized to source and run in the sandbox. It must be
107
99
  // self-contained: no imports, no closure over outer variables, synchronous.
108
100
  run: (input) => {
@@ -162,12 +154,8 @@ const placeNarrow = connector('geo_places')
162
154
  .version('1.0.0')
163
155
  .compute('narrow', {
164
156
  type: 'read',
165
- input: {
166
- results: { type: 'unknown' },
167
- },
168
- output: {
169
- places: { type: 'array', required: true },
170
- },
157
+ input: z.object({ results: z.unknown().optional() }),
158
+ output: z.object({ places: z.array(z.unknown()) }),
171
159
  // Self-contained: no imports, no closure over outer variables, synchronous.
172
160
  run: (input) => {
173
161
  const raw = input.results;
@@ -55,16 +55,16 @@ const crm = connector('crm').version('1.0.0').http({
55
55
  method: 'GET',
56
56
  path: '/customers',
57
57
  query: ['email'],
58
- input: { email: { type: 'string', required: true } },
59
- output: { id: { type: 'string', required: true }, name: { type: 'string' } },
58
+ input: z.object({ email: z.string() }),
59
+ output: z.object({ id: z.string(), name: z.string().optional() }),
60
60
  response: { id: '${response.data[0].id}', name: '${response.data[0].name}' },
61
61
  },
62
62
  create_ticket: {
63
63
  type: 'action',
64
64
  method: 'POST',
65
65
  path: '/tickets',
66
- input: { customer_id: { type: 'string', required: true }, body: { type: 'string', required: true } },
67
- output: { ticket_id: { type: 'string', required: true } },
66
+ input: z.object({ customer_id: z.string(), body: z.string() }),
67
+ output: z.object({ ticket_id: z.string() }),
68
68
  request: { customer_id: '${args.customer_id}', body: '${args.body}' },
69
69
  response: { ticket_id: '${response.id}' },
70
70
  },
@@ -120,16 +120,16 @@ const tasks = connector('tasks').version('1.0.0').http({
120
120
  method: 'GET',
121
121
  path: '/tasks',
122
122
  query: ['query'],
123
- input: { query: { type: 'string', required: true } },
124
- output: { matches: { type: 'array', required: true } },
123
+ input: z.object({ query: z.string() }),
124
+ output: z.object({ matches: z.array(z.unknown()) }),
125
125
  response: { matches: '${response.results}' },
126
126
  },
127
127
  close_task: {
128
128
  type: 'action',
129
129
  method: 'POST',
130
130
  path: '/tasks/{id}/close',
131
- input: { id: { type: 'string', required: true } },
132
- output: { ok: { type: 'boolean', required: true } },
131
+ input: z.object({ id: z.string() }),
132
+ output: z.object({ ok: z.boolean() }),
133
133
  response: { ok: '${response.ok}' },
134
134
  },
135
135
  },
@@ -163,8 +163,8 @@ The model never sees a task id from the user; `find_tasks` returns `{ id, title
163
163
 
164
164
  ```ts
165
165
  const scoring = connector('scoring').version('1.0.0').compute('normalize', {
166
- input: { email: { type: "string", required: true }, priority: { type: "string" } },
167
- output: { score: { type: "number", required: true } },
166
+ input: z.object({ email: z.string(), priority: z.string().optional() }),
167
+ output: z.object({ score: z.number() }),
168
168
  calls: { find_customer: 'crm.find_customer' },
169
169
  limits: { timeoutMs: 1000, maxHostCalls: 2 },
170
170
  run(input, { callOperation }) {
@@ -62,7 +62,7 @@ Most real tools return a variable-length list (search results, a user’s tasks)
62
62
 
63
63
  ```ts
64
64
  // The API returns { results: [ { id, name, country, … }, … ] }
65
- output: { places: { type: 'array' } },
65
+ output: z.object({ places: z.array(z.unknown()) }),
66
66
  response: { places: '${response.results}' },
67
67
  ```
68
68
 
@@ -96,7 +96,7 @@ Pair the read/list with the mutations your intent tools need:
96
96
  ```ts
97
97
  close_task: {
98
98
  type: 'action', method: 'POST', path: '/tasks/{id}/close',
99
- input: { id: { type: 'string', required: true } },
99
+ input: z.object({ id: z.string() }),
100
100
  responseType: 'empty',
101
101
  },
102
102
  ```
@@ -144,8 +144,8 @@ const crm = connector('crm')
144
144
  method: 'GET',
145
145
  path: '/tickets',
146
146
  query: ['id'],
147
- input: { id: { type: 'string', required: true } },
148
- output: { subject: { type: 'string' }, status: { type: 'string' } },
147
+ input: z.object({ id: z.string() }),
148
+ output: z.object({ subject: z.string().optional(), status: z.string().optional() }),
149
149
  response: { subject: '${response.subject}', status: '${response.status}' },
150
150
  },
151
151
  },
@@ -195,8 +195,8 @@ const orders = connector('orders')
195
195
  method: 'GET',
196
196
  path: '/orders',
197
197
  query: ['id'],
198
- input: { id: { type: 'string', required: true } },
199
- output: { id: { type: 'string' }, status: { type: 'string' } },
198
+ input: z.object({ id: z.string() }),
199
+ output: z.object({ id: z.string().optional(), status: z.string().optional() }),
200
200
  response: { id: '${response.id}', status: '${response.status}' },
201
201
  },
202
202
  get_tracking: {
@@ -204,8 +204,8 @@ const orders = connector('orders')
204
204
  method: 'GET',
205
205
  path: '/tracking',
206
206
  query: ['order_id'],
207
- input: { order_id: { type: 'string', required: true } },
208
- output: { url: { type: 'string' } },
207
+ input: z.object({ order_id: z.string() }),
208
+ output: z.object({ url: z.string().optional() }),
209
209
  response: { url: '${response.url}' },
210
210
  },
211
211
  },