stitchkit 0.36.0 → 0.37.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.
Files changed (81) hide show
  1. package/README.md +4 -2
  2. package/dist/browser/http.d.ts +2 -2
  3. package/dist/browser/http.d.ts.map +1 -1
  4. package/dist/cli.js +3 -3
  5. package/dist/contract/define.d.ts +28 -2
  6. package/dist/contract/define.d.ts.map +1 -1
  7. package/dist/contract/errors.d.ts.map +1 -1
  8. package/dist/contract/index.js +1 -1
  9. package/dist/{index-dvrn81q4.js → index-4pvtq6h2.js} +83 -34
  10. package/dist/{index-0ed3bx43.js → index-frfyw9fa.js} +2 -2
  11. package/dist/{index-pmftwk2a.js → index-g3jrbd0z.js} +26 -0
  12. package/dist/{index-kgga1n8d.js → index-s6yhmg1k.js} +563 -342
  13. package/dist/{index-bx49hskg.js → index-xq45akyd.js} +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/node.d.ts +1 -1
  16. package/dist/node.d.ts.map +1 -1
  17. package/dist/node.js +7 -3
  18. package/dist/observability/index.js +3 -3
  19. package/dist/server/bun.d.ts +32 -0
  20. package/dist/server/bun.d.ts.map +1 -0
  21. package/dist/server/context.d.ts +1 -1
  22. package/dist/server/context.d.ts.map +1 -1
  23. package/dist/server/create.d.ts +2 -3
  24. package/dist/server/create.d.ts.map +1 -1
  25. package/dist/server/implement.d.ts.map +1 -1
  26. package/dist/server/index.d.ts +3 -2
  27. package/dist/server/index.d.ts.map +1 -1
  28. package/dist/server/index.js +25 -5
  29. package/dist/server/logger.d.ts +5 -5
  30. package/dist/server/logger.d.ts.map +1 -1
  31. package/dist/server/logging.d.ts +4 -1
  32. package/dist/server/logging.d.ts.map +1 -1
  33. package/dist/server/middleware/auth.d.ts +2 -2
  34. package/dist/server/middleware/auth.d.ts.map +1 -1
  35. package/dist/server/request-body.d.ts +4 -0
  36. package/dist/server/request-body.d.ts.map +1 -0
  37. package/dist/server/router.d.ts +3 -3
  38. package/dist/server/router.d.ts.map +1 -1
  39. package/dist/server/socket-io-config.d.ts +20 -0
  40. package/dist/server/socket-io-config.d.ts.map +1 -0
  41. package/dist/server/socket-io-node.d.ts +14 -0
  42. package/dist/server/socket-io-node.d.ts.map +1 -0
  43. package/dist/server/socket-io.d.ts +5 -32
  44. package/dist/server/socket-io.d.ts.map +1 -1
  45. package/dist/server/types.d.ts +54 -49
  46. package/dist/server/types.d.ts.map +1 -1
  47. package/dist/tools/agent.d.ts.map +1 -1
  48. package/dist/tools/execute.d.ts +60 -15
  49. package/dist/tools/execute.d.ts.map +1 -1
  50. package/dist/tools/flatten-join.d.ts +8 -0
  51. package/dist/tools/flatten-join.d.ts.map +1 -0
  52. package/dist/tools/flatten.d.ts +7 -44
  53. package/dist/tools/flatten.d.ts.map +1 -1
  54. package/dist/tools/json-schema.d.ts +1 -1
  55. package/dist/tools/json-schema.d.ts.map +1 -1
  56. package/dist/tools/manifest.d.ts.map +1 -1
  57. package/dist/tools/mcp-handler.d.ts +7 -13
  58. package/dist/tools/mcp-handler.d.ts.map +1 -1
  59. package/dist/tools/mcp.d.ts +61 -24
  60. package/dist/tools/mcp.d.ts.map +1 -1
  61. package/dist/tools/mount.d.ts +9 -6
  62. package/dist/tools/mount.d.ts.map +1 -1
  63. package/dist/tools/names.d.ts +1 -1
  64. package/dist/tools/native-mcp.d.ts +57 -0
  65. package/dist/tools/native-mcp.d.ts.map +1 -0
  66. package/dist/tools/portable-formats.d.ts +15 -0
  67. package/dist/tools/portable-formats.d.ts.map +1 -0
  68. package/dist/tools/presentation.d.ts +15 -0
  69. package/dist/tools/presentation.d.ts.map +1 -0
  70. package/dist/tools/remote.d.ts.map +1 -1
  71. package/dist/tools/schema.d.ts +3 -8
  72. package/dist/tools/schema.d.ts.map +1 -1
  73. package/dist/tools/tool-logger.d.ts.map +1 -1
  74. package/dist/tools/view-file.d.ts +5 -3
  75. package/dist/tools/view-file.d.ts.map +1 -1
  76. package/dist/tools.d.ts +7 -4
  77. package/dist/tools.d.ts.map +1 -1
  78. package/dist/tools.js +357 -95
  79. package/llms-full.txt +374 -77
  80. package/package.json +14 -11
  81. /package/dist/{index-17rdjw68.js → index-e497hxcy.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  jsonSchemaFields,
3
3
  toJsonSchema
4
- } from "./index-0ed3bx43.js";
4
+ } from "./index-frfyw9fa.js";
5
5
  import {
6
6
  isWithinDir
7
7
  } from "./index-x3fcszf8.js";
@@ -14,7 +14,7 @@ import {
14
14
  runWithRequestContext,
15
15
  safeJsonParse,
16
16
  validateHandlerOutput
17
- } from "./index-17rdjw68.js";
17
+ } from "./index-e497hxcy.js";
18
18
 
19
19
  // src/tools/coerce.ts
20
20
  import { z } from "zod";
@@ -77,8 +77,325 @@ function coerceJsonArgs(args, schema) {
77
77
  return isRecord(coerced) ? coerced : args;
78
78
  }
79
79
 
80
+ // src/tools/flatten-join.ts
81
+ var ANNOTATION_KEYS = new Set(["$schema", "default", "description", "examples", "title"]);
82
+ var TYPE_KEYWORDS = {
83
+ array: [
84
+ "contains",
85
+ "items",
86
+ "maxContains",
87
+ "maxItems",
88
+ "minContains",
89
+ "minItems",
90
+ "prefixItems",
91
+ "uniqueItems"
92
+ ],
93
+ integer: ["exclusiveMaximum", "exclusiveMinimum", "maximum", "minimum", "multipleOf"],
94
+ number: ["exclusiveMaximum", "exclusiveMinimum", "maximum", "minimum", "multipleOf"],
95
+ object: [
96
+ "additionalProperties",
97
+ "dependentRequired",
98
+ "dependentSchemas",
99
+ "maxProperties",
100
+ "minProperties",
101
+ "patternProperties",
102
+ "properties",
103
+ "propertyNames",
104
+ "required"
105
+ ],
106
+ string: [
107
+ "contentEncoding",
108
+ "contentMediaType",
109
+ "format",
110
+ "maxLength",
111
+ "minLength",
112
+ "pattern"
113
+ ]
114
+ };
115
+ function nullableProjection(schema) {
116
+ if (!Array.isArray(schema.anyOf) || schema.anyOf.length !== 2)
117
+ return schema;
118
+ const branches = schema.anyOf.filter(isRecord);
119
+ if (branches.length !== 2)
120
+ return schema;
121
+ const nullBranch = branches.find((branch) => branch.type === "null");
122
+ const value = branches.find((branch) => typeof branch.type === "string" && branch.type !== "null");
123
+ if (!nullBranch || !value || Object.keys(nullBranch).some((key) => key !== "type")) {
124
+ return schema;
125
+ }
126
+ const type = value.type;
127
+ if (typeof type !== "string")
128
+ return schema;
129
+ const projected = { type: [type, "null"] };
130
+ for (const key of [...ANNOTATION_KEYS, ...TYPE_KEYWORDS[type] ?? []]) {
131
+ if (value[key] !== undefined)
132
+ projected[key] = value[key];
133
+ else if (schema[key] !== undefined)
134
+ projected[key] = schema[key];
135
+ }
136
+ if (value.const !== undefined)
137
+ projected.enum = [value.const, null];
138
+ else if (Array.isArray(value.enum))
139
+ projected.enum = [...value.enum, null];
140
+ return projected;
141
+ }
142
+ function withoutAnnotations(schema) {
143
+ const result = {};
144
+ for (const [key, value] of Object.entries(schema)) {
145
+ if (!ANNOTATION_KEYS.has(key))
146
+ result[key] = value;
147
+ }
148
+ return result;
149
+ }
150
+ function stableJson(value) {
151
+ if (Array.isArray(value))
152
+ return `[${value.map(stableJson).join(",")}]`;
153
+ if (!isRecord(value))
154
+ return JSON.stringify(value) ?? "undefined";
155
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
156
+ }
157
+ function stringValues(schema) {
158
+ if (typeof schema.const === "string")
159
+ return [schema.const];
160
+ if (!Array.isArray(schema.enum))
161
+ return null;
162
+ const values = schema.enum.filter((value) => typeof value === "string");
163
+ return values.length === schema.enum.length ? values : null;
164
+ }
165
+ function typeNames(schema) {
166
+ if (typeof schema.type === "string")
167
+ return [schema.type];
168
+ if (Array.isArray(schema.type)) {
169
+ const values2 = schema.type.filter((value) => typeof value === "string");
170
+ if (values2.length === schema.type.length)
171
+ return values2;
172
+ }
173
+ const values = stringValues(schema);
174
+ if (values)
175
+ return ["string"];
176
+ if (typeof schema.const === "number")
177
+ return ["number"];
178
+ if (typeof schema.const === "boolean")
179
+ return ["boolean"];
180
+ return null;
181
+ }
182
+ function typeSchema(type, nullable) {
183
+ const schema = { type: nullable ? [type, "null"] : type };
184
+ if (type === "array")
185
+ schema.items = {};
186
+ if (type === "object")
187
+ schema.additionalProperties = {};
188
+ return schema;
189
+ }
190
+ function commonBaseType(schemas) {
191
+ const names = schemas.map(typeNames);
192
+ if (names.some((value) => value === null))
193
+ return {};
194
+ let nullable = false;
195
+ const bases = new Set;
196
+ for (const branch of names) {
197
+ if (!branch)
198
+ return {};
199
+ for (const name of branch) {
200
+ if (name === "null")
201
+ nullable = true;
202
+ else
203
+ bases.add(name);
204
+ }
205
+ }
206
+ if (bases.size === 1) {
207
+ const [only] = bases;
208
+ return only ? typeSchema(only, nullable) : {};
209
+ }
210
+ if ([...bases].every((name) => name === "integer" || name === "number")) {
211
+ return typeSchema("number", nullable);
212
+ }
213
+ return {};
214
+ }
215
+ function mergePropertySchemas(properties) {
216
+ const schemas = properties.map((property) => nullableProjection(property.schema));
217
+ const structural = schemas.map(withoutAnnotations);
218
+ const [first] = structural;
219
+ let merged;
220
+ if (first && structural.every((schema) => stableJson(schema) === stableJson(first))) {
221
+ merged = structuredClone(first);
222
+ } else {
223
+ const values = schemas.map(stringValues);
224
+ const allStrings = values.every((value) => value !== null);
225
+ merged = allStrings ? { type: "string", enum: [...new Set(values.flatMap((value) => value ?? []))] } : commonBaseType(schemas);
226
+ }
227
+ const descriptions = [
228
+ ...new Set(schemas.map((schema) => schema.description).filter((value) => typeof value === "string"))
229
+ ];
230
+ if (descriptions.length === 1)
231
+ merged.description = descriptions[0];
232
+ return merged;
233
+ }
234
+
80
235
  // src/tools/flatten.ts
81
- import { z as z3 } from "zod";
236
+ function rebuild(value) {
237
+ if (Array.isArray(value))
238
+ return value.map(rebuild);
239
+ if (!isRecord(value))
240
+ return value;
241
+ const node = {};
242
+ for (const [key, child] of Object.entries(value))
243
+ node[key] = rebuild(child);
244
+ return flattenNode(node);
245
+ }
246
+ function stringValues2(schema) {
247
+ if (typeof schema.const === "string")
248
+ return [schema.const];
249
+ if (!Array.isArray(schema.enum))
250
+ return null;
251
+ const values = schema.enum.filter((value) => typeof value === "string");
252
+ return values.length === schema.enum.length ? values : null;
253
+ }
254
+ function objectVariants(node) {
255
+ if (!Array.isArray(node.oneOf) || node.oneOf.length < 2)
256
+ return null;
257
+ const variants = node.oneOf.filter(isRecord);
258
+ if (variants.length !== node.oneOf.length)
259
+ return null;
260
+ if (variants.some((variant) => variant.type !== "object" || !isRecord(variant.properties))) {
261
+ return null;
262
+ }
263
+ return variants;
264
+ }
265
+ function findDiscriminator(variants) {
266
+ const [first] = variants;
267
+ if (!first || !isRecord(first.properties))
268
+ return null;
269
+ for (const key of Object.keys(first.properties).sort()) {
270
+ const values = [];
271
+ const seen = new Set;
272
+ let valid = true;
273
+ for (const variant of variants) {
274
+ if (!requiredKeys(variant).has(key)) {
275
+ valid = false;
276
+ break;
277
+ }
278
+ const properties = variant.properties;
279
+ const field = isRecord(properties) ? properties[key] : undefined;
280
+ const branchValues = isRecord(field) ? stringValues2(field) : null;
281
+ if (!branchValues || branchValues.length === 0) {
282
+ valid = false;
283
+ break;
284
+ }
285
+ for (const value of branchValues) {
286
+ if (seen.has(value)) {
287
+ valid = false;
288
+ break;
289
+ }
290
+ seen.add(value);
291
+ }
292
+ if (!valid)
293
+ break;
294
+ values.push(branchValues);
295
+ }
296
+ if (valid)
297
+ return { key, values };
298
+ }
299
+ return null;
300
+ }
301
+ function requiredKeys(variant) {
302
+ if (!Array.isArray(variant.required))
303
+ return new Set;
304
+ return new Set(variant.required.filter((key) => typeof key === "string"));
305
+ }
306
+ function appendHint(schema, hint) {
307
+ const description = typeof schema.description === "string" ? schema.description : undefined;
308
+ return { ...schema, description: description ? `${description} ${hint}` : hint };
309
+ }
310
+ function flattenNode(node) {
311
+ const variants = objectVariants(node);
312
+ if (!variants)
313
+ return node;
314
+ const discriminator = findDiscriminator(variants);
315
+ if (!discriminator)
316
+ return node;
317
+ const perKey = new Map;
318
+ for (let index = 0;index < variants.length; index++) {
319
+ const variant = variants[index];
320
+ if (!variant)
321
+ continue;
322
+ const labels = discriminator.values[index] ?? [];
323
+ const required2 = requiredKeys(variant);
324
+ if (!isRecord(variant.properties))
325
+ continue;
326
+ for (const [key, rawSchema] of Object.entries(variant.properties)) {
327
+ if (key === discriminator.key || !isRecord(rawSchema))
328
+ continue;
329
+ const entries = perKey.get(key) ?? [];
330
+ entries.push({ schema: rawSchema, labels, required: required2.has(key) });
331
+ perKey.set(key, entries);
332
+ }
333
+ }
334
+ const discriminatorProperties = [];
335
+ for (let index = 0;index < variants.length; index++) {
336
+ const variant = variants[index];
337
+ if (!variant || !isRecord(variant.properties))
338
+ continue;
339
+ const schema = variant.properties[discriminator.key];
340
+ if (!isRecord(schema))
341
+ continue;
342
+ discriminatorProperties.push({
343
+ schema,
344
+ labels: discriminator.values[index] ?? [],
345
+ required: true
346
+ });
347
+ }
348
+ const properties = {
349
+ [discriminator.key]: mergePropertySchemas(discriminatorProperties)
350
+ };
351
+ const required = [discriminator.key];
352
+ for (const [key, entries] of perKey) {
353
+ let merged = mergePropertySchemas(entries);
354
+ const requiredEverywhere = entries.length === variants.length && entries.every((entry) => entry.required);
355
+ if (requiredEverywhere) {
356
+ required.push(key);
357
+ } else {
358
+ const requiredLabels = entries.filter((entry) => entry.required).flatMap((entry) => entry.labels);
359
+ const presentLabels = entries.flatMap((entry) => entry.labels);
360
+ const labels = requiredLabels.length > 0 ? requiredLabels : presentLabels;
361
+ const verb = requiredLabels.length > 0 ? "Required" : "Available";
362
+ merged = appendHint(merged, `${verb} if ${discriminator.key} = ${[...new Set(labels)].join(" | ")}`);
363
+ }
364
+ properties[key] = merged;
365
+ }
366
+ const result = {};
367
+ for (const [key, value] of Object.entries(node)) {
368
+ if (key !== "oneOf" && key !== "anyOf" && key !== "properties" && key !== "required") {
369
+ result[key] = value;
370
+ }
371
+ }
372
+ result.type = "object";
373
+ result.properties = properties;
374
+ result.required = required;
375
+ result.additionalProperties = variants.every((variant) => variant.additionalProperties === false) ? false : {};
376
+ return result;
377
+ }
378
+ function flattenToolJsonSchema(schema) {
379
+ const result = rebuild(schema);
380
+ return isRecord(result) ? result : {};
381
+ }
382
+ function freezeToolJsonSchema(schema) {
383
+ for (const value of Object.values(schema))
384
+ freezeJsonValue(value);
385
+ return Object.freeze(schema);
386
+ }
387
+ function freezeJsonValue(value) {
388
+ if (Array.isArray(value)) {
389
+ for (const item of value)
390
+ freezeJsonValue(item);
391
+ Object.freeze(value);
392
+ } else if (isRecord(value)) {
393
+ freezeToolJsonSchema(value);
394
+ }
395
+ }
396
+
397
+ // src/tools/mount.ts
398
+ import { z as z4 } from "zod";
82
399
 
83
400
  // src/tools/schema.ts
84
401
  import { z as z2 } from "zod";
@@ -131,300 +448,6 @@ function mergeSchemas(paramsSchema, inputSchema) {
131
448
  return paramsObject ? z2.intersection(paramsObject, inputSchema) : inputSchema;
132
449
  }
133
450
 
134
- // src/tools/flatten.ts
135
- function flattenDiscriminatedUnion(union) {
136
- const discriminator = union.def.discriminator;
137
- const allDiscValues = [];
138
- const perKey = new Map;
139
- for (const opt of union.def.options) {
140
- if (!(opt instanceof z3.ZodObject)) {
141
- throw new Error(`flattenDiscriminatedUnion: variant for discriminator '${discriminator}' is not a ZodObject`);
142
- }
143
- const discValues = stringLiteralOrEnumValues(opt.shape[discriminator]);
144
- if (discValues === null) {
145
- throw new Error(`flattenDiscriminatedUnion: discriminator '${discriminator}' must be a string z.literal() or z.enum()`);
146
- }
147
- allDiscValues.push(...discValues);
148
- const label = discValues.join(" | ");
149
- for (const [key, field] of Object.entries(opt.shape)) {
150
- if (key === discriminator)
151
- continue;
152
- const entry = perKey.get(key) ?? { schemas: [], variants: [] };
153
- entry.schemas.push(unwrapField(field));
154
- entry.variants.push(label);
155
- perKey.set(key, entry);
156
- }
157
- }
158
- const uniqDisc = [...new Set(allDiscValues)];
159
- const [firstLiteral, ...restLiterals] = uniqDisc;
160
- if (firstLiteral === undefined) {
161
- throw new Error("flattenDiscriminatedUnion: union has no options");
162
- }
163
- const shape = {
164
- [discriminator]: z3.enum([firstLiteral, ...restLiterals])
165
- };
166
- for (const [key, entry] of perKey) {
167
- const advertised = mergeCollidingFields(entry.schemas);
168
- const hint = `Required if ${discriminator} = ${[...new Set(entry.variants)].join(" | ")}`;
169
- shape[key] = z3.optional(advertised).describe(hint);
170
- }
171
- return withKeyPolicy(z3.object(shape), mergeVariantKeyPolicies(union.def.options));
172
- }
173
- function mergeVariantKeyPolicies(options) {
174
- let strict = 0;
175
- let counted = 0;
176
- for (const option of options) {
177
- const policy = option instanceof z3.ZodObject ? keyPolicyOf(option) : undefined;
178
- if (policy !== undefined && !(policy instanceof z3.ZodNever))
179
- return z3.unknown();
180
- counted++;
181
- if (policy instanceof z3.ZodNever)
182
- strict++;
183
- }
184
- if (counted === 0 || strict === 0)
185
- return;
186
- return strict === counted ? z3.never() : z3.unknown();
187
- }
188
- function unwrapField(field) {
189
- if (field instanceof z3.ZodOptional || field instanceof z3.ZodDefault) {
190
- return unwrapField(field.unwrap());
191
- }
192
- return field;
193
- }
194
- function preserveDescription(from, to) {
195
- return from.description === undefined ? to : to.describe(from.description);
196
- }
197
- function stringLiteralOrEnumValues(field) {
198
- let raw = null;
199
- if (field instanceof z3.ZodLiteral)
200
- raw = field.def.values;
201
- else if (field instanceof z3.ZodEnum)
202
- raw = field.options;
203
- if (raw === null)
204
- return null;
205
- const strings = raw.filter((v) => typeof v === "string");
206
- return strings.length === raw.length ? strings : null;
207
- }
208
- function isFlattenableDU(union) {
209
- const disc = union.def.discriminator;
210
- if (union.def.options.length === 0)
211
- return false;
212
- for (const opt of union.def.options) {
213
- if (!(opt instanceof z3.ZodObject))
214
- return false;
215
- if (stringLiteralOrEnumValues(opt.shape[disc]) === null)
216
- return false;
217
- }
218
- return true;
219
- }
220
- function stripAnnotations(node) {
221
- if (Array.isArray(node)) {
222
- for (const item of node)
223
- stripAnnotations(item);
224
- return;
225
- }
226
- if (typeof node === "object" && node !== null) {
227
- Reflect.deleteProperty(node, "description");
228
- Reflect.deleteProperty(node, "default");
229
- Reflect.deleteProperty(node, "$schema");
230
- for (const value of Object.values(node))
231
- stripAnnotations(value);
232
- }
233
- }
234
- function hasInvisibleConstraint(schema) {
235
- if (!(schema instanceof z3.ZodType))
236
- return false;
237
- const def = schema.def;
238
- if (isRecord(def) && def.type !== "unknown" && def.type !== "any") {
239
- if (normalizedJson(schema) === "{}")
240
- return true;
241
- }
242
- if (schema instanceof z3.ZodCatch)
243
- return true;
244
- if (isRecord(def) && def.coerce === true)
245
- return true;
246
- if (isRecord(def) && Array.isArray(def.checks)) {
247
- for (const check of def.checks) {
248
- if (isInvisibleCheck(check))
249
- return true;
250
- }
251
- }
252
- if (schema instanceof z3.ZodOptional || schema instanceof z3.ZodNullable || schema instanceof z3.ZodDefault) {
253
- return hasInvisibleConstraint(schema.unwrap());
254
- }
255
- if (schema instanceof z3.ZodPipe)
256
- return true;
257
- if (schema instanceof z3.ZodObject) {
258
- return Object.values(schema.shape).some(hasInvisibleConstraint);
259
- }
260
- if (schema instanceof z3.ZodArray)
261
- return hasInvisibleConstraint(schema.element);
262
- if (schema instanceof z3.ZodUnion)
263
- return schema.def.options.some(hasInvisibleConstraint);
264
- if (schema instanceof z3.ZodRecord)
265
- return hasInvisibleConstraint(schema.valueType);
266
- if (schema instanceof z3.ZodIntersection) {
267
- return hasInvisibleConstraint(schema.def.left) || hasInvisibleConstraint(schema.def.right);
268
- }
269
- return false;
270
- }
271
- var INVISIBLE_CHECK_KINDS = new Set(["custom", "overwrite"]);
272
- function acceptsMoreThanItsType(schema) {
273
- if (!(schema instanceof z3.ZodType))
274
- return false;
275
- if (schema instanceof z3.ZodCatch)
276
- return true;
277
- if (isRecord(schema.def) && schema.def.coerce === true)
278
- return true;
279
- if (schema instanceof z3.ZodOptional || schema instanceof z3.ZodNullable || schema instanceof z3.ZodDefault) {
280
- return acceptsMoreThanItsType(schema.unwrap());
281
- }
282
- if (schema instanceof z3.ZodPipe)
283
- return acceptsMoreThanItsType(schema.def.in);
284
- return false;
285
- }
286
- function isInvisibleCheck(check) {
287
- if (!isRecord(check))
288
- return false;
289
- const inner = check._zod;
290
- const def = isRecord(inner) ? inner.def : undefined;
291
- const kind = isRecord(def) ? def.check : undefined;
292
- return typeof kind === "string" && INVISIBLE_CHECK_KINDS.has(kind);
293
- }
294
- function projectToBaseType(schema) {
295
- if (!(schema instanceof z3.ZodType))
296
- return z3.unknown();
297
- if (schema instanceof z3.ZodNullable) {
298
- return z3.nullable(projectToBaseType(schema.unwrap()));
299
- }
300
- if (schema instanceof z3.ZodOptional || schema instanceof z3.ZodDefault) {
301
- return projectToBaseType(schema.unwrap());
302
- }
303
- if (schema instanceof z3.ZodPipe)
304
- return projectToBaseType(schema.def.in);
305
- if (schema instanceof z3.ZodCatch)
306
- return z3.unknown();
307
- const coerces = isRecord(schema.def) && schema.def.coerce === true;
308
- if (schema instanceof z3.ZodNumber)
309
- return coerces ? z3.coerce.number() : z3.number();
310
- if (schema instanceof z3.ZodString)
311
- return coerces ? z3.coerce.string() : z3.string();
312
- if (schema instanceof z3.ZodBoolean && coerces)
313
- return z3.coerce.boolean();
314
- if (schema instanceof z3.ZodEnum || schema instanceof z3.ZodLiteral) {
315
- return stringLiteralOrEnumValues(schema) === null ? z3.unknown() : z3.string();
316
- }
317
- if (schema instanceof z3.ZodBoolean)
318
- return z3.boolean();
319
- if (schema instanceof z3.ZodArray)
320
- return z3.array(z3.unknown());
321
- if (schema instanceof z3.ZodObject)
322
- return z3.looseObject({});
323
- return z3.unknown();
324
- }
325
- function normalizedJson(schema) {
326
- if (!(schema instanceof z3.ZodType))
327
- return "{}";
328
- const json = toJsonSchema(schema, "input", "any");
329
- stripAnnotations(json);
330
- return JSON.stringify(json);
331
- }
332
- function mergeCollidingFields(schemas) {
333
- const distinct = new Map;
334
- for (const schema of schemas) {
335
- const key = normalizedJson(schema);
336
- if (!distinct.has(key))
337
- distinct.set(key, schema);
338
- }
339
- const values = [...distinct.values()];
340
- const only = values[0];
341
- if (values.length <= 1) {
342
- if (only === undefined)
343
- return z3.unknown();
344
- if (schemas.length <= 1)
345
- return only;
346
- const hazards2 = schemas.map(acceptsMoreThanItsType);
347
- if (hazards2.some(Boolean) && !hazards2.every(Boolean))
348
- return z3.unknown();
349
- if (schemas.some(hasInvisibleConstraint)) {
350
- if (normalizedJson(only) === "{}")
351
- return only;
352
- return projectToBaseType(only);
353
- }
354
- return only;
355
- }
356
- const merged = [];
357
- let allEnum = true;
358
- for (const schema of values) {
359
- const vals = stringLiteralOrEnumValues(schema);
360
- if (vals === null) {
361
- allEnum = false;
362
- break;
363
- }
364
- merged.push(...vals);
365
- }
366
- if (allEnum) {
367
- const uniq = [...new Set(merged)];
368
- const [first2, ...rest] = uniq;
369
- if (first2 !== undefined)
370
- return z3.enum([first2, ...rest]);
371
- }
372
- const hazards = schemas.map(acceptsMoreThanItsType);
373
- if (hazards.some(Boolean) && !hazards.every(Boolean))
374
- return z3.unknown();
375
- const projected = values.map(projectToBaseType);
376
- const first = projected[0];
377
- if (first !== undefined) {
378
- const shape = normalizedJson(first);
379
- if (shape !== "{}" && projected.every((p) => normalizedJson(p) === shape))
380
- return first;
381
- }
382
- return z3.unknown();
383
- }
384
- function flattenUnionsDeep(schema) {
385
- if (!(schema instanceof z3.ZodType))
386
- return z3.unknown();
387
- if (schema instanceof z3.ZodDiscriminatedUnion) {
388
- if (!isFlattenableDU(schema))
389
- return schema;
390
- return preserveDescription(schema, flattenUnionsDeep(flattenDiscriminatedUnion(schema)));
391
- }
392
- if (schema instanceof z3.ZodObject) {
393
- const shape = {};
394
- for (const [key, field] of Object.entries(schema.shape)) {
395
- shape[key] = flattenUnionsDeep(field);
396
- }
397
- return preserveDescription(schema, rebuildObject(schema, shape));
398
- }
399
- if (schema instanceof z3.ZodArray) {
400
- return preserveDescription(schema, z3.array(flattenUnionsDeep(schema.element)));
401
- }
402
- if (schema instanceof z3.ZodUnion) {
403
- const opts = schema.def.options.map((option) => flattenUnionsDeep(option));
404
- const [a, b, ...rest] = opts;
405
- return a && b ? preserveDescription(schema, z3.union([a, b, ...rest])) : schema;
406
- }
407
- if (schema instanceof z3.ZodRecord) {
408
- return preserveDescription(schema, z3.record(schema.keyType, flattenUnionsDeep(schema.valueType)));
409
- }
410
- if (schema instanceof z3.ZodOptional) {
411
- return preserveDescription(schema, z3.optional(flattenUnionsDeep(schema.unwrap())));
412
- }
413
- if (schema instanceof z3.ZodNullable) {
414
- return preserveDescription(schema, z3.nullable(flattenUnionsDeep(schema.unwrap())));
415
- }
416
- if (schema instanceof z3.ZodDefault) {
417
- return preserveDescription(schema, flattenUnionsDeep(schema.unwrap()).default(schema.def.defaultValue));
418
- }
419
- if (schema instanceof z3.ZodIntersection) {
420
- return preserveDescription(schema, z3.intersection(flattenUnionsDeep(schema.def.left), flattenUnionsDeep(schema.def.right)));
421
- }
422
- return schema;
423
- }
424
-
425
- // src/tools/mount.ts
426
- import { z as z4 } from "zod";
427
-
428
451
  // src/tools/execute.ts
429
452
  function toolResultFromError(err) {
430
453
  const appErr = normalizeError(err);
@@ -435,40 +458,112 @@ function toolResultFromError(err) {
435
458
  ...appErr.hint && { hint: appErr.hint }
436
459
  };
437
460
  }
438
- async function executeToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson = false, onOutputStrip) {
461
+ async function executeToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson = false, onOutputStrip, extension) {
462
+ return inToolCallContext({ source: context.source, toolName, method }, () => runToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson, onOutputStrip, extension));
463
+ }
464
+ function inToolCallContext(call, body) {
439
465
  const parent = getRequestContext();
440
- if (!parent) {
441
- return runToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson, onOutputStrip);
442
- }
466
+ if (!parent)
467
+ return body();
443
468
  return runWithRequestContext({
444
469
  ...parent,
445
470
  trace: parent.trace,
446
471
  dimensions: parent.dimensions ? { ...parent.dimensions } : undefined,
447
472
  error: undefined,
448
- source: context.source,
473
+ source: call.source,
449
474
  method: "TOOL",
450
- path: `/${context.source}/${toolName}`,
451
- serviceName: method.serviceName,
452
- action: method.key
453
- }, () => runToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson, onOutputStrip));
475
+ path: `/${call.source}/${call.toolName}`,
476
+ serviceName: call.method.serviceName,
477
+ action: call.method.key
478
+ }, body);
454
479
  }
455
- async function runToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson, onOutputStrip) {
480
+ async function runToolMethod(method, toolName, rawArgs, context, hooks, lifecycle, coerceJson, onOutputStrip, extension) {
456
481
  const startedAt = Date.now();
482
+ let hookContext = context;
457
483
  const finish = async (result, thrown) => {
458
- await hooks?.afterToolCall?.(toolName, rawArgs, result, Date.now() - startedAt, context, method, thrown);
484
+ await hooks?.afterToolCall?.({
485
+ toolName,
486
+ args: rawArgs,
487
+ result,
488
+ durationMs: Date.now() - startedAt,
489
+ context: hookContext,
490
+ endpoint: method,
491
+ ...thrown !== undefined && { error: thrown }
492
+ });
459
493
  return result;
460
494
  };
461
- if (hooks?.beforeToolCall) {
495
+ let beforeRan = false;
496
+ const runBefore = async () => {
497
+ if (beforeRan || !hooks?.beforeToolCall)
498
+ return null;
499
+ beforeRan = true;
462
500
  try {
463
- await hooks.beforeToolCall(toolName, rawArgs, context, method);
501
+ await hooks.beforeToolCall({
502
+ toolName,
503
+ args: rawArgs,
504
+ context: hookContext,
505
+ endpoint: method
506
+ });
507
+ return null;
464
508
  } catch (err) {
465
509
  return finish(toolResultFromError(err));
466
510
  }
511
+ };
512
+ const finishThrown = async (err) => {
513
+ const beforeFailure2 = await runBefore();
514
+ if (beforeFailure2)
515
+ return beforeFailure2;
516
+ if (hooks?.onToolError) {
517
+ try {
518
+ await hooks.onToolError({
519
+ toolName,
520
+ error: err,
521
+ context: hookContext,
522
+ endpoint: method
523
+ });
524
+ } catch (hookErr) {
525
+ console.error("[stitchkit] onToolError hook failed:", hookErr);
526
+ }
527
+ }
528
+ return finish(toolResultFromError(err), err);
529
+ };
530
+ let callArgs = rawArgs;
531
+ let callContext = context;
532
+ if (extension) {
533
+ const extensionKeys = new Set(Object.keys(extension.schema.shape));
534
+ const extensionArgs = Object.fromEntries(Object.entries(rawArgs).filter(([key]) => extensionKeys.has(key)));
535
+ let parsed;
536
+ try {
537
+ parsed = extension.schema.safeParse(extensionArgs);
538
+ } catch (err) {
539
+ return finishThrown(err);
540
+ }
541
+ if (!parsed.success) {
542
+ const beforeFailure2 = await runBefore();
543
+ if (beforeFailure2)
544
+ return beforeFailure2;
545
+ return finish({
546
+ ok: false,
547
+ code: "VALIDATION_ERROR",
548
+ details: { message: `Invalid tool extension: ${formatZodError(parsed.error)}` }
549
+ });
550
+ }
551
+ try {
552
+ const resolved = await extension.resolve({ ...rawArgs, ...parsed.data });
553
+ callContext = { ...context, ...resolved, source: context.source };
554
+ hookContext = callContext;
555
+ callArgs = Object.fromEntries(Object.entries(rawArgs).filter(([key]) => !extensionKeys.has(key)));
556
+ } catch (err) {
557
+ return finishThrown(err);
558
+ }
467
559
  }
560
+ const beforeFailure = await runBefore();
561
+ if (beforeFailure)
562
+ return beforeFailure;
468
563
  const paramKeys = new Set(objectShapeKeys(method.paramsSchema));
469
564
  let paramArgs = {};
470
565
  let inputArgs = {};
471
- for (const [key, value] of Object.entries(rawArgs)) {
566
+ for (const [key, value] of Object.entries(callArgs)) {
472
567
  if (isUnsafeKey(key))
473
568
  continue;
474
569
  if (paramKeys.has(key))
@@ -482,7 +577,12 @@ async function runToolMethod(method, toolName, rawArgs, context, hooks, lifecycl
482
577
  }
483
578
  let params;
484
579
  if (method.paramsSchema) {
485
- const result = method.paramsSchema.safeParse(paramArgs);
580
+ let result;
581
+ try {
582
+ result = method.paramsSchema.safeParse(paramArgs);
583
+ } catch (err) {
584
+ return finishThrown(err);
585
+ }
486
586
  if (!result.success) {
487
587
  return finish({
488
588
  ok: false,
@@ -494,7 +594,12 @@ async function runToolMethod(method, toolName, rawArgs, context, hooks, lifecycl
494
594
  }
495
595
  let input;
496
596
  if (method.inputSchema) {
497
- const result = method.inputSchema.safeParse(inputArgs);
597
+ let result;
598
+ try {
599
+ result = method.inputSchema.safeParse(inputArgs);
600
+ } catch (err) {
601
+ return finishThrown(err);
602
+ }
498
603
  if (!result.success) {
499
604
  return finish({
500
605
  ok: false,
@@ -505,7 +610,12 @@ async function runToolMethod(method, toolName, rawArgs, context, hooks, lifecycl
505
610
  input = result.data;
506
611
  }
507
612
  try {
508
- const ctx = { ...context, params, input, source: context.source };
613
+ const ctx = {
614
+ ...callContext,
615
+ params,
616
+ input,
617
+ source: context.source
618
+ };
509
619
  if (lifecycle?.beforeHandle) {
510
620
  await lifecycle.beforeHandle(ctx, method);
511
621
  }
@@ -529,14 +639,7 @@ async function runToolMethod(method, toolName, rawArgs, context, hooks, lifecycl
529
639
  const output = (data === undefined || data === null) && !method.outputSchema ? { status: "ok" } : data;
530
640
  return finish({ ok: true, data: output });
531
641
  } catch (err) {
532
- if (hooks?.onToolError) {
533
- try {
534
- await hooks.onToolError(toolName, err, context, method);
535
- } catch (hookErr) {
536
- console.error("[stitchkit] onToolError hook failed:", hookErr);
537
- }
538
- }
539
- return finish(toolResultFromError(err), err);
642
+ return finishThrown(err);
540
643
  }
541
644
  }
542
645
 
@@ -605,6 +708,121 @@ function assertUniqueToolName(name, taken, surface) {
605
708
  }
606
709
  }
607
710
 
711
+ // src/tools/presentation.ts
712
+ import { z as z3 } from "zod";
713
+ function withoutDialect(schema) {
714
+ const result = {};
715
+ for (const [key, value] of Object.entries(schema)) {
716
+ if (key !== "$schema")
717
+ result[key] = value;
718
+ }
719
+ return result;
720
+ }
721
+ function hasLocalReference(value) {
722
+ if (Array.isArray(value))
723
+ return value.some(hasLocalReference);
724
+ if (!isRecord(value))
725
+ return false;
726
+ if (typeof value.$ref === "string" && value.$ref.startsWith("#"))
727
+ return true;
728
+ return Object.values(value).some(hasLocalReference);
729
+ }
730
+ function rewriteLocalReferences(value, namespace) {
731
+ if (Array.isArray(value)) {
732
+ return value.map((child) => rewriteLocalReferences(child, namespace));
733
+ }
734
+ if (!isRecord(value))
735
+ return value;
736
+ const rewritten = {};
737
+ for (const [key, child] of Object.entries(value)) {
738
+ rewritten[key] = key === "$ref" && typeof child === "string" && child.startsWith("#") ? `#/definitions/${namespace}${child.slice(1)}` : rewriteLocalReferences(child, namespace);
739
+ }
740
+ return rewritten;
741
+ }
742
+ function namespaceLocalReferences(schema, namespace) {
743
+ if (!schema || !hasLocalReference(schema))
744
+ return schema;
745
+ const rewritten = rewriteLocalReferences(schema, namespace);
746
+ if (!isRecord(rewritten))
747
+ return schema;
748
+ return { ...rewritten, definitions: { [namespace]: rewritten } };
749
+ }
750
+ function objectProperties(schema) {
751
+ return schema.type === "object" && isRecord(schema.properties) ? schema.properties : null;
752
+ }
753
+ function requiredKeys2(schema) {
754
+ return Array.isArray(schema.required) ? schema.required.filter((key) => typeof key === "string") : [];
755
+ }
756
+ function mergeObjectSchemas(left, right, rightOwnsUnknownKeys) {
757
+ const leftProperties = objectProperties(left);
758
+ const rightProperties = objectProperties(right);
759
+ if (!leftProperties || !rightProperties)
760
+ return { allOf: [left, right] };
761
+ const conflicts = Object.keys(leftProperties).filter((key) => (key in rightProperties));
762
+ if (conflicts.length > 0) {
763
+ throw new Error(`Schema merge conflict: ${conflicts.join(", ")} appear in both params and input`);
764
+ }
765
+ const merged = {
766
+ type: "object",
767
+ properties: { ...leftProperties, ...rightProperties },
768
+ required: [...new Set([...requiredKeys2(left), ...requiredKeys2(right)])]
769
+ };
770
+ const leftDefinitions = isRecord(left.definitions) ? left.definitions : {};
771
+ const rightDefinitions = isRecord(right.definitions) ? right.definitions : {};
772
+ const definitions = { ...leftDefinitions, ...rightDefinitions };
773
+ if (Object.keys(definitions).length > 0)
774
+ merged.definitions = definitions;
775
+ const unknownKeys = rightOwnsUnknownKeys ? right.additionalProperties : left.additionalProperties;
776
+ if (unknownKeys !== undefined)
777
+ merged.additionalProperties = unknownKeys;
778
+ return merged;
779
+ }
780
+ function schemaFromZod(schema, unrepresentable, flatten) {
781
+ if (!schema)
782
+ return;
783
+ const json = toJsonSchema(schema, "input", unrepresentable, "draft-07");
784
+ return flatten ? flattenToolJsonSchema(json) : json;
785
+ }
786
+ function buildToolPresentationSchema(config) {
787
+ const unrepresentable = config.unrepresentable ?? "any";
788
+ const flatten = config.flattenUnionInput ?? false;
789
+ const params = namespaceLocalReferences(schemaFromZod(config.paramsSchema, unrepresentable, flatten), "params");
790
+ const input = namespaceLocalReferences(schemaFromZod(config.inputSchema, unrepresentable, flatten), "input");
791
+ let presentation;
792
+ if (params && input) {
793
+ presentation = mergeObjectSchemas(withoutDialect(params), withoutDialect(input), true);
794
+ } else if (input) {
795
+ presentation = input;
796
+ } else if (params) {
797
+ presentation = params;
798
+ } else {
799
+ presentation = {
800
+ $schema: "http://json-schema.org/draft-07/schema#",
801
+ type: "object",
802
+ properties: {}
803
+ };
804
+ }
805
+ if (config.extendSchema) {
806
+ const extra = namespaceLocalReferences(schemaFromZod(z3.object(config.extendSchema), unrepresentable, flatten), "extend");
807
+ if (extra) {
808
+ presentation = mergeObjectSchemas(withoutDialect(extra), withoutDialect(presentation), true);
809
+ }
810
+ }
811
+ if (presentation.$schema === undefined) {
812
+ presentation = {
813
+ $schema: "http://json-schema.org/draft-07/schema#",
814
+ ...presentation
815
+ };
816
+ }
817
+ return freezeToolJsonSchema(presentation);
818
+ }
819
+ function isObjectPresentationSchema(schema) {
820
+ return schema.type === "object" && isRecord(schema.properties);
821
+ }
822
+ function presentationMetadata(schema) {
823
+ return withoutDialect(schema);
824
+ }
825
+
608
826
  // src/tools/mount.ts
609
827
  function applyExtend(base, extra) {
610
828
  if (base instanceof z4.ZodObject) {
@@ -628,6 +846,8 @@ function collectTools(service, transport, config = {}) {
628
846
  }
629
847
  if (method.multipart)
630
848
  continue;
849
+ if (method.rawBody)
850
+ continue;
631
851
  if (method.rawResponse)
632
852
  continue;
633
853
  const name = method.toolName ?? toToolName(service.name, methodName);
@@ -637,22 +857,27 @@ function collectTools(service, transport, config = {}) {
637
857
  }
638
858
  assertToolName(name, service.name, methodName);
639
859
  }
640
- const baseSchema = flattenUnionInput ? mergeSchemas(method.paramsSchema ? flattenUnionsDeep(method.paramsSchema) : undefined, method.inputSchema ? flattenUnionsDeep(method.inputSchema) : undefined) : mergeSchemas(method.paramsSchema, method.inputSchema);
641
860
  const shouldExtend = !!extend && (!extend.filter || extend.filter(service, method));
642
- const schema = shouldExtend && extend ? applyExtend(baseSchema, extend.schema) : baseSchema;
643
- tools.push({ method, name, schema, shouldExtend });
861
+ const baseArgumentSchema = mergeSchemas(method.paramsSchema, method.inputSchema);
862
+ const argumentSchema = shouldExtend && extend ? applyExtend(baseArgumentSchema, extend.schema) : baseArgumentSchema;
863
+ const presentationSchema = buildToolPresentationSchema({
864
+ paramsSchema: method.paramsSchema,
865
+ inputSchema: method.inputSchema,
866
+ extendSchema: shouldExtend ? extend?.schema : undefined,
867
+ flattenUnionInput,
868
+ unrepresentable: "any"
869
+ });
870
+ tools.push({ method, name, argumentSchema, presentationSchema, shouldExtend });
644
871
  }
645
872
  return tools;
646
873
  }
647
874
  function createToolRunner(config) {
648
- const extendKeys = config.extend ? new Set(Object.keys(config.extend.schema)) : null;
649
- return async (tool, rawArgs) => {
650
- let extraContext = {};
651
- if (tool.shouldExtend && config.extend) {
652
- extraContext = await config.extend.resolve(rawArgs);
653
- }
654
- const cleanArgs = tool.shouldExtend && extendKeys ? Object.fromEntries(Object.entries(rawArgs).filter(([key]) => !extendKeys.has(key))) : rawArgs;
655
- return executeToolMethod(tool.method, tool.name, cleanArgs, { ...config.context, ...extraContext, source: config.source }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true, config.onOutputStrip ? (paths) => config.onOutputStrip?.(tool.name, paths) : undefined);
875
+ const extension = config.extend ? {
876
+ schema: z4.object(config.extend.schema),
877
+ resolve: config.extend.resolve
878
+ } : undefined;
879
+ return async function runOneToolCall(tool, rawArgs) {
880
+ return executeToolMethod(tool.method, tool.name, rawArgs, { ...config.context, source: config.source }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true, config.onOutputStrip ? (paths) => config.onOutputStrip?.(tool.name, paths) : undefined, tool.shouldExtend ? extension : undefined);
656
881
  };
657
882
  }
658
883
  function formatToolError(result, toolName, errorHint) {
@@ -1224,7 +1449,7 @@ function renderCommandHelp(name, command, tool) {
1224
1449
  const lines = [tool.method.desc, "", `Usage: ${name} ${command} [args] [--flags]`, ""];
1225
1450
  let fields = [];
1226
1451
  try {
1227
- fields = jsonSchemaFields(toJsonSchema(tool.schema, "input"));
1452
+ fields = jsonSchemaFields(tool.presentationSchema);
1228
1453
  } catch {
1229
1454
  lines.push("(arguments: pass a JSON object — this command has a complex schema)", "");
1230
1455
  }
@@ -1304,7 +1529,7 @@ async function createCli(config) {
1304
1529
  `);
1305
1530
  return exit(1);
1306
1531
  }
1307
- const { toolArgs, options } = parseCliArgs(commandArgv, tool.schema);
1532
+ const { toolArgs, options } = parseCliArgs(commandArgv, tool.argumentSchema);
1308
1533
  if (options.help) {
1309
1534
  stdout(renderCommandHelp(config.name, command, tool));
1310
1535
  return exit(0);
@@ -1318,7 +1543,7 @@ async function createCli(config) {
1318
1543
  }
1319
1544
  const passthroughField = config.passthrough?.[command];
1320
1545
  if (passthroughField) {
1321
- collectPassthrough(toolArgs, passthroughField, objectShapeKeys(tool.schema));
1546
+ collectPassthrough(toolArgs, passthroughField, objectShapeKeys(tool.argumentSchema));
1322
1547
  }
1323
1548
  if (options.dryRun) {
1324
1549
  stdout(`${JSON.stringify({ command, args: toolArgs }, null, 2)}
@@ -1364,11 +1589,7 @@ async function createCli(config) {
1364
1589
  return exit(exitCode);
1365
1590
  }
1366
1591
  function safeInputSchema(tool) {
1367
- try {
1368
- return toJsonSchema(tool.schema, "input");
1369
- } catch {
1370
- return {};
1371
- }
1592
+ return tool.presentationSchema;
1372
1593
  }
1373
1594
 
1374
- export { coerceJsonArgs, toolResultFromError, flattenDiscriminatedUnion, flattenUnionsDeep, assertToolName, assertUniqueToolName, collectTools, createToolRunner, formatToolError, fetchGuarded, readCapped, writeDownload, parseCliArgs, DEFAULT_EXIT_CODES, emitResult, pollUntil, pollUntilDone, createCli };
1595
+ export { coerceJsonArgs, toolResultFromError, executeToolMethod, assertToolName, assertUniqueToolName, flattenToolJsonSchema, buildToolPresentationSchema, isObjectPresentationSchema, presentationMetadata, collectTools, createToolRunner, formatToolError, fetchGuarded, readCapped, writeDownload, parseCliArgs, DEFAULT_EXIT_CODES, emitResult, pollUntil, pollUntilDone, createCli };