stitchkit 0.118.1 → 0.120.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/CHANGELOG.md +92 -0
- package/README.md +10 -7
- package/dist/browser/http.d.ts.map +1 -1
- package/dist/contract/client-types.d.ts +6 -3
- package/dist/contract/client-types.d.ts.map +1 -1
- package/dist/contract/define-validation.d.ts.map +1 -1
- package/dist/contract/define.d.ts +18 -12
- package/dist/contract/define.d.ts.map +1 -1
- package/dist/contract/endpoint-capabilities.d.ts +28 -0
- package/dist/contract/endpoint-capabilities.d.ts.map +1 -0
- package/dist/contract/factory.d.ts +49 -19
- package/dist/contract/factory.d.ts.map +1 -1
- package/dist/contract/tool-view.d.ts +1 -1
- package/dist/contract/tool-view.d.ts.map +1 -1
- package/dist/contract/transports.d.ts +5 -0
- package/dist/contract/transports.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/coding-tools.js +9 -8
- package/dist/entrypoints/agent-runtime/harness.js +9 -8
- package/dist/entrypoints/agent-runtime/realtime.js +3 -3
- package/dist/entrypoints/agent-runtime/sandbox.js +10 -9
- package/dist/entrypoints/agent-runtime/sqlite/bun.js +12 -11
- package/dist/entrypoints/agent-runtime/sqlite/node.js +12 -11
- package/dist/entrypoints/agent-runtime/testing.js +12 -11
- package/dist/entrypoints/agent-runtime.js +22 -19
- package/dist/entrypoints/application/diagnostic-journal.js +3 -3
- package/dist/entrypoints/application/directory-inbox.js +4 -4
- package/dist/entrypoints/application/opentelemetry.js +1 -1
- package/dist/entrypoints/application.js +10 -10
- package/dist/entrypoints/cli/publish.js +4 -4
- package/dist/entrypoints/cli.js +13 -12
- package/dist/entrypoints/contract.d.ts +1 -1
- package/dist/entrypoints/contract.d.ts.map +1 -1
- package/dist/entrypoints/contract.js +6 -4
- package/dist/entrypoints/files.js +3 -3
- package/dist/entrypoints/geo/contract.d.ts +7 -0
- package/dist/entrypoints/geo/contract.d.ts.map +1 -0
- package/dist/entrypoints/geo/contract.js +6 -0
- package/dist/entrypoints/geo.js +60 -23
- package/dist/entrypoints/http.js +3 -3
- package/dist/entrypoints/index.js +9 -7
- package/dist/entrypoints/live.js +1 -1
- package/dist/entrypoints/node.js +7 -6
- package/dist/entrypoints/primitives.js +1 -1
- package/dist/entrypoints/process/owner-loss.js +1 -1
- package/dist/entrypoints/process.js +3 -3
- package/dist/entrypoints/react.js +1 -1
- package/dist/entrypoints/remote.js +4 -3
- package/dist/entrypoints/server.js +16 -15
- package/dist/entrypoints/telegram/screens.js +5 -5
- package/dist/entrypoints/telegram.js +7 -7
- package/dist/entrypoints/testing.js +7 -6
- package/dist/entrypoints/tools/agent.d.ts +9 -0
- package/dist/entrypoints/tools/agent.d.ts.map +1 -0
- package/dist/entrypoints/tools/agent.js +16 -0
- package/dist/entrypoints/tools/connections.js +7 -6
- package/dist/entrypoints/tools/contract.js +1 -1
- package/dist/entrypoints/tools/invoker.js +5 -4
- package/dist/entrypoints/tools/mcp.js +110 -9
- package/dist/entrypoints/tools/toolkit.d.ts +9 -0
- package/dist/entrypoints/tools/toolkit.d.ts.map +1 -0
- package/dist/entrypoints/tools/toolkit.js +40 -0
- package/dist/entrypoints/tools.d.ts +0 -10
- package/dist/entrypoints/tools.d.ts.map +1 -1
- package/dist/entrypoints/tools.js +38 -80
- package/dist/entrypoints/tracking/contract.js +5 -3
- package/dist/entrypoints/tracking/performance.js +3 -3
- package/dist/entrypoints/tracking.d.ts +1 -1
- package/dist/entrypoints/tracking.d.ts.map +1 -1
- package/dist/entrypoints/tracking.js +63 -83
- package/dist/entrypoints/xlsx.js +1 -1
- package/dist/geo/index.d.ts +2 -1
- package/dist/geo/index.d.ts.map +1 -1
- package/dist/geo/record.d.ts +8 -0
- package/dist/geo/record.d.ts.map +1 -0
- package/dist/geo/resolver.d.ts +1 -3
- package/dist/geo/resolver.d.ts.map +1 -1
- package/dist/geo/schema.d.ts +44 -0
- package/dist/geo/schema.d.ts.map +1 -0
- package/dist/geo/types.d.ts +2 -13
- package/dist/geo/types.d.ts.map +1 -1
- package/dist/{index-n5sv4z0w.js → index-0qyrcjfs.js} +16 -18
- package/dist/index-1psbyyhj.js +21 -0
- package/dist/{index-tsngj2b5.js → index-2fc1k9k2.js} +206 -206
- package/dist/index-3prvb42w.js +30 -0
- package/dist/{index-073nw9qr.js → index-3yb5kft5.js} +524 -522
- package/dist/{index-d9hq291n.js → index-4jpykzvw.js} +70 -81
- package/dist/index-568w258r.js +76 -0
- package/dist/index-69t14s4a.js +39 -0
- package/dist/{index-dky0dcmf.js → index-72r9k0av.js} +6 -2
- package/dist/{index-6p3frkv5.js → index-7zwtbak8.js} +9 -50
- package/dist/{index-90p34rts.js → index-8ryydawp.js} +7 -5
- package/dist/{index-vv1sch8a.js → index-8vzh5wpv.js} +13 -8
- package/dist/{index-75ns2ybj.js → index-8xyf8h2k.js} +1 -1
- package/dist/{index-xx1j310k.js → index-8yxgcyt6.js} +171 -169
- package/dist/{index-p6apg0jg.js → index-9frf01t9.js} +16 -9
- package/dist/{index-q0th8q0z.js → index-9mjrnqxs.js} +1 -3
- package/dist/{index-6f49krb5.js → index-aa50qwv4.js} +1 -1
- package/dist/{index-ega3yz4c.js → index-aqwg2dm5.js} +1 -1
- package/dist/{index-p0rf7sq9.js → index-bgcwxhxh.js} +225 -223
- package/dist/index-bph35vpy.js +77 -0
- package/dist/{index-tdpmfks8.js → index-bz479f0x.js} +1 -1
- package/dist/index-d3xdyjt6.js +38 -0
- package/dist/{index-q968hy6y.js → index-e452syyh.js} +1 -1
- package/dist/{index-86nbfysb.js → index-ff39f9dr.js} +3 -3
- package/dist/index-h1j71dr1.js +48 -0
- package/dist/{index-mgb7r8b8.js → index-jswst0h3.js} +1 -1
- package/dist/{index-095ya5hm.js → index-knmnj11j.js} +22 -191
- package/dist/{index-vwhrnp67.js → index-kz9734jc.js} +3 -3
- package/dist/{index-txg1npmg.js → index-mtwh9hyp.js} +1 -1
- package/dist/{index-dr3t5n1v.js → index-nn9qvkww.js} +46 -46
- package/dist/{index-ghtpfz4z.js → index-nyyam9ce.js} +2 -2
- package/dist/{index-qezhmp51.js → index-nz06qw5a.js} +3 -1
- package/dist/{index-1bx1xv1k.js → index-pfvde2fz.js} +5 -2
- package/dist/{index-w7jq3fz9.js → index-pq2m7t46.js} +1142 -1212
- package/dist/{index-yk4g8805.js → index-pq7rkwkk.js} +1 -30
- package/dist/{index-s80awwsw.js → index-qch1vcaa.js} +3 -1
- package/dist/{index-hdjmdwsj.js → index-qctbzmg9.js} +521 -511
- package/dist/{index-n8z3rvzw.js → index-qevqn3d3.js} +3 -5
- package/dist/{index-nqxrm176.js → index-r3db01kh.js} +1 -1
- package/dist/{index-v6vb5qx8.js → index-s3yxw6kt.js} +1 -1
- package/dist/{index-cqmqyjax.js → index-sa99p98w.js} +1 -1
- package/dist/index-sb9dr3tq.js +14 -0
- package/dist/{index-0gxvns6s.js → index-sba3e6m4.js} +1 -0
- package/dist/{index-f24bdt13.js → index-v1swr26p.js} +3 -1
- package/dist/{index-rhzkndr5.js → index-x4p3kw1p.js} +533 -530
- package/dist/{index-cycp3r3e.js → index-yb9n4pgj.js} +2 -2
- package/dist/{index-htxh46ej.js → index-ycqhyars.js} +2 -2
- package/dist/{index-9bwcthxw.js → index-yj6saztf.js} +31 -13
- package/dist/{index-f6m4c545.js → index-zrdcmg6j.js} +4 -6
- package/dist/{index-tvtacc9a.js → index-zyc64nbh.js} +1 -34
- package/dist/process/bun-child.d.ts +3 -2
- package/dist/process/bun-child.d.ts.map +1 -1
- package/dist/server/contract-method.d.ts.map +1 -1
- package/dist/tools/internal/surface-projector.d.ts.map +1 -1
- package/dist/tools/operations/async-operation-canonical-types.d.ts +1 -1
- package/dist/tracking/attribution.d.ts +21 -25
- package/dist/tracking/attribution.d.ts.map +1 -1
- package/dist/tracking/client-visit.d.ts +5 -7
- package/dist/tracking/client-visit.d.ts.map +1 -1
- package/dist/tracking/client.d.ts +2 -2
- package/dist/tracking/client.d.ts.map +1 -1
- package/dist/tracking/contract.d.ts +1 -1
- package/dist/tracking/host.d.ts +0 -1
- package/dist/tracking/host.d.ts.map +1 -1
- package/dist/tracking/privacy.d.ts +6 -0
- package/dist/tracking/privacy.d.ts.map +1 -1
- package/dist/tracking/schemas.d.ts +2 -2
- package/dist/tracking/schemas.d.ts.map +1 -1
- package/llms/agent-runtime-harness.txt +4 -3
- package/llms/agent-runtime-sandbox.txt +1 -1
- package/llms/agent-runtime.2.txt +3 -2
- package/llms/agent-runtime.3.txt +4 -46
- package/llms/agent-runtime.4.txt +113 -0
- package/llms/agent-runtime.txt +11 -13
- package/llms/cli.txt +1 -1
- package/llms/contract.txt +46 -24
- package/llms/geo-contract.txt +23 -0
- package/llms/geo.txt +40 -4
- package/llms/stitchkit.txt +16 -9
- package/llms/testing.txt +4 -6
- package/llms/tools-agent.txt +24 -0
- package/llms/tools-mcp.txt +71 -6
- package/llms/tools-toolkit.txt +23 -0
- package/llms/tools.2.txt +8 -5
- package/llms/tools.3.txt +9 -78
- package/llms/tools.txt +8 -8
- package/llms/tracking-contract.txt +1 -1
- package/llms/tracking.txt +27 -5
- package/llms/{upgrading-0.105.0-0.118.0.txt → upgrading-0.106.0-0.120.0.txt} +152 -410
- package/llms/upgrading-0.37.0-0.53.0.txt +969 -0
- package/llms/{upgrading-0.44.0-0.62.0.txt → upgrading-0.55.0-0.68.0.txt} +509 -528
- package/llms/{upgrading-0.63.0-0.83.0.txt → upgrading-0.69.0-0.95.0.txt} +506 -509
- package/llms/{upgrading-0.84.0-0.104.0.txt → upgrading-0.96.0-0.105.0.txt} +410 -506
- package/llms/upgrading.txt +5 -5
- package/llms-full.txt +475 -154
- package/llms.txt +17 -14
- package/package.json +32 -20
- package/llms/upgrading-0.37.0-0.44.0.txt +0 -444
- package/dist/{index-arjmb6de.js → index-1jwsfkfz.js} +0 -0
- package/dist/{index-qndsr7f0.js → index-5efrpfmj.js} +3 -3
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
toJsonSchema
|
|
6
6
|
} from "./index-ct75c3at.js";
|
|
7
|
+
import {
|
|
8
|
+
isHttpOnlyEndpoint
|
|
9
|
+
} from "./index-69t14s4a.js";
|
|
7
10
|
import {
|
|
8
11
|
AppError2
|
|
9
12
|
} from "./index-qcn84byh.js";
|
|
@@ -14,6 +17,214 @@ import {
|
|
|
14
17
|
isRecord
|
|
15
18
|
} from "./index-9jfdm5tg.js";
|
|
16
19
|
|
|
20
|
+
// src/tools/internal/tool-view.ts
|
|
21
|
+
function toolSurfaceOutputSchema(operation) {
|
|
22
|
+
if (!operation.outputSchema)
|
|
23
|
+
return;
|
|
24
|
+
return operation.toolView?.output ?? operation.outputSchema;
|
|
25
|
+
}
|
|
26
|
+
function applyToolViewDefaults(inputArgs, defaults) {
|
|
27
|
+
if (!defaults)
|
|
28
|
+
return inputArgs;
|
|
29
|
+
const filled = { ...inputArgs };
|
|
30
|
+
for (const [key, value] of Object.entries(defaults)) {
|
|
31
|
+
if (filled[key] === undefined)
|
|
32
|
+
filled[key] = structuredClone(value);
|
|
33
|
+
}
|
|
34
|
+
return filled;
|
|
35
|
+
}
|
|
36
|
+
function projectToolView(options) {
|
|
37
|
+
const { view } = options;
|
|
38
|
+
let projected = options.full;
|
|
39
|
+
if (view.project) {
|
|
40
|
+
try {
|
|
41
|
+
projected = Reflect.apply(view.project, undefined, [options.full, options.call]);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
const failure = new AppError2("INTERNAL_SERVER_ERROR", {
|
|
44
|
+
message: `${options.operation} toolView.project threw`,
|
|
45
|
+
status: 500
|
|
46
|
+
});
|
|
47
|
+
failure.cause = error;
|
|
48
|
+
throw failure;
|
|
49
|
+
}
|
|
50
|
+
if (isRecord(projected) && typeof projected.then === "function") {
|
|
51
|
+
Promise.resolve(projected).catch(() => {
|
|
52
|
+
return;
|
|
53
|
+
});
|
|
54
|
+
throw new AppError2("INTERNAL_SERVER_ERROR", {
|
|
55
|
+
message: `${options.operation} toolView.project returned a Promise — it must be synchronous`,
|
|
56
|
+
status: 500
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (projected === undefined) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
message: `${options.operation} toolView.project returned undefined`
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const checked = validateDeclaredOutput(view.output ?? options.fullSchema, projected, view.project ? options.onStripped : undefined);
|
|
67
|
+
if (!checked.ok) {
|
|
68
|
+
return { ok: false, message: `${options.operation} toolView: ${checked.message}` };
|
|
69
|
+
}
|
|
70
|
+
return checked;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/tools/schema/schema.ts
|
|
74
|
+
import { z } from "zod";
|
|
75
|
+
function objectShapeKeys(schema) {
|
|
76
|
+
return schema instanceof z.ZodObject ? Object.keys(schema.shape) : [];
|
|
77
|
+
}
|
|
78
|
+
function keyPolicyOf(schema) {
|
|
79
|
+
return schema.def.catchall;
|
|
80
|
+
}
|
|
81
|
+
function rebuildObject(source, shape) {
|
|
82
|
+
return withKeyPolicy(z.object(shape), keyPolicyOf(source));
|
|
83
|
+
}
|
|
84
|
+
function withKeyPolicy(object, policy) {
|
|
85
|
+
if (policy === undefined)
|
|
86
|
+
return object;
|
|
87
|
+
return object.catchall(representable(policy));
|
|
88
|
+
}
|
|
89
|
+
function representable(policy) {
|
|
90
|
+
if (policy instanceof z.ZodNever || policy instanceof z.ZodUnknown)
|
|
91
|
+
return policy;
|
|
92
|
+
if (!(policy instanceof z.ZodType))
|
|
93
|
+
return z.unknown();
|
|
94
|
+
try {
|
|
95
|
+
toJsonSchema(policy, "input");
|
|
96
|
+
return policy;
|
|
97
|
+
} catch {
|
|
98
|
+
return z.unknown();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function mergeSchemas(paramsSchema, inputSchema) {
|
|
102
|
+
if (paramsSchema && !(paramsSchema instanceof z.ZodObject)) {
|
|
103
|
+
throw new Error("Tool params schema must be a z.object()");
|
|
104
|
+
}
|
|
105
|
+
const paramsObject = paramsSchema instanceof z.ZodObject ? paramsSchema : undefined;
|
|
106
|
+
if (!inputSchema) {
|
|
107
|
+
return paramsObject ?? z.object({});
|
|
108
|
+
}
|
|
109
|
+
if (inputSchema instanceof z.ZodObject) {
|
|
110
|
+
if (paramsObject) {
|
|
111
|
+
const conflicts = Object.keys(paramsObject.shape).filter((key) => (key in inputSchema.shape));
|
|
112
|
+
if (conflicts.length > 0) {
|
|
113
|
+
throw new Error(`Schema merge conflict: ${conflicts.join(", ")} appear in both params and input`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return rebuildObject(inputSchema, {
|
|
117
|
+
...paramsObject?.shape ?? {},
|
|
118
|
+
...inputSchema.shape
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return paramsObject ? z.intersection(paramsObject, inputSchema) : inputSchema;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/tools/internal/surface-projector.ts
|
|
125
|
+
import { z as z3 } from "zod";
|
|
126
|
+
|
|
127
|
+
// src/tools/mcp/round-policy.ts
|
|
128
|
+
function staticInputRounds(policy) {
|
|
129
|
+
return Array.isArray(policy.inputRequired) ? policy.inputRequired : undefined;
|
|
130
|
+
}
|
|
131
|
+
function validateMcpRoundPolicy(tool, policy, runtime) {
|
|
132
|
+
if (!runtime?.stateConfigured) {
|
|
133
|
+
throw new Error(`[stitchkit] MCP tool "${tool.name}" declares inputRequired but no multiRound.state key is configured`);
|
|
134
|
+
}
|
|
135
|
+
const { maxRounds } = runtime;
|
|
136
|
+
if (!Number.isInteger(maxRounds) || maxRounds < 1) {
|
|
137
|
+
throw new Error("[stitchkit] multiRound.serving.maxRounds must be a positive integer");
|
|
138
|
+
}
|
|
139
|
+
const declared = staticInputRounds(policy);
|
|
140
|
+
if (!declared)
|
|
141
|
+
return;
|
|
142
|
+
if (declared.length === 0) {
|
|
143
|
+
throw new Error(`[stitchkit] MCP tool "${tool.name}" must declare at least one input round`);
|
|
144
|
+
}
|
|
145
|
+
assertRoundShape(tool, declared, maxRounds);
|
|
146
|
+
}
|
|
147
|
+
function validateResolvedInputRounds(tool, resolved, maxRounds) {
|
|
148
|
+
assertRoundShape(tool, resolved, maxRounds);
|
|
149
|
+
}
|
|
150
|
+
function assertRoundShape(tool, rounds, maxRounds) {
|
|
151
|
+
if (rounds.length > maxRounds) {
|
|
152
|
+
throw new Error(`[stitchkit] MCP tool "${tool.name}" declares ${rounds.length} input rounds, exceeding maxRounds ${maxRounds}`);
|
|
153
|
+
}
|
|
154
|
+
const keys = new Set;
|
|
155
|
+
for (const request of rounds) {
|
|
156
|
+
if (keys.has(request.key)) {
|
|
157
|
+
throw new Error(`[stitchkit] MCP tool "${tool.name}" declares duplicate input key "${request.key}"`);
|
|
158
|
+
}
|
|
159
|
+
keys.add(request.key);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/tools/names.ts
|
|
164
|
+
var SINGULAR_EXCEPTIONS = new Set([
|
|
165
|
+
"analytics",
|
|
166
|
+
"status",
|
|
167
|
+
"stats",
|
|
168
|
+
"settings",
|
|
169
|
+
"media",
|
|
170
|
+
"progress",
|
|
171
|
+
"news"
|
|
172
|
+
]);
|
|
173
|
+
var TOOL_NAME_RE = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
174
|
+
function normalizeService(value) {
|
|
175
|
+
return value.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
176
|
+
}
|
|
177
|
+
function normalizeMethod(value) {
|
|
178
|
+
return value.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
179
|
+
}
|
|
180
|
+
function singularize(name) {
|
|
181
|
+
if (SINGULAR_EXCEPTIONS.has(name))
|
|
182
|
+
return name;
|
|
183
|
+
if (name.endsWith("ies"))
|
|
184
|
+
return `${name.slice(0, -3)}y`;
|
|
185
|
+
if (name.endsWith("s") && !name.endsWith("ss"))
|
|
186
|
+
return name.slice(0, -1);
|
|
187
|
+
return name;
|
|
188
|
+
}
|
|
189
|
+
function singularizeTail(name) {
|
|
190
|
+
const cut = name.lastIndexOf("_");
|
|
191
|
+
if (cut === -1)
|
|
192
|
+
return singularize(name);
|
|
193
|
+
return `${name.slice(0, cut + 1)}${singularize(name.slice(cut + 1))}`;
|
|
194
|
+
}
|
|
195
|
+
function hasUsableChars(value) {
|
|
196
|
+
return /[a-zA-Z0-9]/.test(value);
|
|
197
|
+
}
|
|
198
|
+
function assertToolName(name, serviceName, key) {
|
|
199
|
+
const where = `service "${serviceName}", method "${key}"`;
|
|
200
|
+
if (!TOOL_NAME_RE.test(name)) {
|
|
201
|
+
const why = name.length > 64 ? `is ${name.length} characters (max 64) — set an explicit \`tool.name\`` : "must match [a-zA-Z0-9_-]";
|
|
202
|
+
throw new Error(`Tool name "${name}" (${where}) ${why}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function toToolName(serviceName, methodName) {
|
|
206
|
+
const normalized = normalizeService(serviceName);
|
|
207
|
+
const singular = singularizeTail(normalized);
|
|
208
|
+
const method = normalizeMethod(methodName);
|
|
209
|
+
if (method === "list")
|
|
210
|
+
return `list_${normalized}`;
|
|
211
|
+
if (method === "get")
|
|
212
|
+
return `get_${singular}`;
|
|
213
|
+
if (method === "create")
|
|
214
|
+
return `create_${singular}`;
|
|
215
|
+
if (method === "update")
|
|
216
|
+
return `update_${singular}`;
|
|
217
|
+
if (method === "delete")
|
|
218
|
+
return `delete_${singular}`;
|
|
219
|
+
const snake = method.replace(/([A-Z])/g, "_$1").toLowerCase();
|
|
220
|
+
return `${snake}_${singular}`.replace(/^_/, "");
|
|
221
|
+
}
|
|
222
|
+
function assertUniqueToolName(name, taken, surface) {
|
|
223
|
+
if (taken) {
|
|
224
|
+
throw new Error(`Duplicate ${surface} "${name}" across mounted operations`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
17
228
|
// src/tools/schema/portable-formats.ts
|
|
18
229
|
var PORTABLE_JSON_SCHEMA_FORMATS2 = new Set([
|
|
19
230
|
"date",
|
|
@@ -100,53 +311,148 @@ function findNonPortableFormats2(schema, allowFormats = []) {
|
|
|
100
311
|
return found.sort((left, right) => left.path.localeCompare(right.path) || left.format.localeCompare(right.format));
|
|
101
312
|
}
|
|
102
313
|
|
|
103
|
-
// src/tools/schema/
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (!
|
|
147
|
-
return
|
|
148
|
-
}
|
|
149
|
-
const
|
|
314
|
+
// src/tools/schema/presentation.ts
|
|
315
|
+
import { z as z2 } from "zod";
|
|
316
|
+
|
|
317
|
+
// src/json-schema/dialect.ts
|
|
318
|
+
var DRAFT_07_MARKER = "draft-07";
|
|
319
|
+
var DRAFT_07_KEYWORD = "definitions";
|
|
320
|
+
var DEFS_KEYWORD = "$defs";
|
|
321
|
+
var SCHEMA_KEYWORDS = [
|
|
322
|
+
"items",
|
|
323
|
+
"additionalItems",
|
|
324
|
+
"additionalProperties",
|
|
325
|
+
"contains",
|
|
326
|
+
"propertyNames",
|
|
327
|
+
"not",
|
|
328
|
+
"if",
|
|
329
|
+
"then",
|
|
330
|
+
"else",
|
|
331
|
+
"unevaluatedItems",
|
|
332
|
+
"unevaluatedProperties"
|
|
333
|
+
];
|
|
334
|
+
var SCHEMA_LIST_KEYWORDS = ["allOf", "anyOf", "oneOf", "prefixItems"];
|
|
335
|
+
var SCHEMA_MAP_KEYWORDS = [
|
|
336
|
+
"properties",
|
|
337
|
+
"patternProperties",
|
|
338
|
+
"dependentSchemas",
|
|
339
|
+
DRAFT_07_KEYWORD,
|
|
340
|
+
DEFS_KEYWORD
|
|
341
|
+
];
|
|
342
|
+
function declaresDraft07(dialect) {
|
|
343
|
+
return typeof dialect === "string" && dialect.includes(DRAFT_07_MARKER);
|
|
344
|
+
}
|
|
345
|
+
function rewriteDefinitionPointers(value) {
|
|
346
|
+
if (Array.isArray(value))
|
|
347
|
+
return value.map(rewriteDefinitionPointers);
|
|
348
|
+
if (!isRecord(value))
|
|
349
|
+
return value;
|
|
350
|
+
const rewritten = {};
|
|
351
|
+
for (const [key, child] of Object.entries(value)) {
|
|
352
|
+
rewritten[key] = key === "$ref" && typeof child === "string" && child.startsWith(`#/${DRAFT_07_KEYWORD}/`) ? `#/${DEFS_KEYWORD}/${child.slice(`#/${DRAFT_07_KEYWORD}/`.length)}` : rewriteDefinitionPointers(child);
|
|
353
|
+
}
|
|
354
|
+
return rewritten;
|
|
355
|
+
}
|
|
356
|
+
function mapValues(value, rewrite) {
|
|
357
|
+
if (!isRecord(value))
|
|
358
|
+
return value;
|
|
359
|
+
const rewritten = {};
|
|
360
|
+
for (const [name, child] of Object.entries(value))
|
|
361
|
+
rewritten[name] = rewrite(child);
|
|
362
|
+
return rewritten;
|
|
363
|
+
}
|
|
364
|
+
function withPositionalItems(schema) {
|
|
365
|
+
if (!isRecord(schema))
|
|
366
|
+
return schema;
|
|
367
|
+
const rewritten = {};
|
|
368
|
+
for (const [key, child] of Object.entries(schema)) {
|
|
369
|
+
if (SCHEMA_KEYWORDS.includes(key))
|
|
370
|
+
rewritten[key] = withPositionalItems(child);
|
|
371
|
+
else if (SCHEMA_LIST_KEYWORDS.includes(key) && Array.isArray(child)) {
|
|
372
|
+
rewritten[key] = child.map(withPositionalItems);
|
|
373
|
+
} else if (SCHEMA_MAP_KEYWORDS.includes(key)) {
|
|
374
|
+
rewritten[key] = mapValues(child, withPositionalItems);
|
|
375
|
+
} else
|
|
376
|
+
rewritten[key] = child;
|
|
377
|
+
}
|
|
378
|
+
const { items, additionalItems } = rewritten;
|
|
379
|
+
if (!Array.isArray(items))
|
|
380
|
+
return rewritten;
|
|
381
|
+
const positional = {};
|
|
382
|
+
for (const [key, child] of Object.entries(rewritten)) {
|
|
383
|
+
if (key === "items")
|
|
384
|
+
positional.prefixItems = items;
|
|
385
|
+
else if (key !== "additionalItems")
|
|
386
|
+
positional[key] = child;
|
|
387
|
+
}
|
|
388
|
+
if (additionalItems !== undefined)
|
|
389
|
+
positional.items = additionalItems;
|
|
390
|
+
return positional;
|
|
391
|
+
}
|
|
392
|
+
function withDraft2020Keywords(schema) {
|
|
393
|
+
const positional = withPositionalItems(schema);
|
|
394
|
+
if (!isRecord(positional))
|
|
395
|
+
return schema;
|
|
396
|
+
const definitions = positional[DRAFT_07_KEYWORD];
|
|
397
|
+
if (!isRecord(definitions) || DEFS_KEYWORD in positional)
|
|
398
|
+
return positional;
|
|
399
|
+
const rewritten = {};
|
|
400
|
+
for (const [key, value] of Object.entries(positional)) {
|
|
401
|
+
if (key === DRAFT_07_KEYWORD)
|
|
402
|
+
continue;
|
|
403
|
+
rewritten[key] = rewriteDefinitionPointers(value);
|
|
404
|
+
}
|
|
405
|
+
rewritten[DEFS_KEYWORD] = rewriteDefinitionPointers(definitions);
|
|
406
|
+
return rewritten;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// src/tools/schema/flatten-join.ts
|
|
410
|
+
var ANNOTATION_KEYS = new Set(["$schema", "default", "description", "examples", "title"]);
|
|
411
|
+
var TYPE_KEYWORDS = {
|
|
412
|
+
array: [
|
|
413
|
+
"contains",
|
|
414
|
+
"items",
|
|
415
|
+
"maxContains",
|
|
416
|
+
"maxItems",
|
|
417
|
+
"minContains",
|
|
418
|
+
"minItems",
|
|
419
|
+
"prefixItems",
|
|
420
|
+
"uniqueItems"
|
|
421
|
+
],
|
|
422
|
+
integer: ["exclusiveMaximum", "exclusiveMinimum", "maximum", "minimum", "multipleOf"],
|
|
423
|
+
number: ["exclusiveMaximum", "exclusiveMinimum", "maximum", "minimum", "multipleOf"],
|
|
424
|
+
object: [
|
|
425
|
+
"additionalProperties",
|
|
426
|
+
"dependentRequired",
|
|
427
|
+
"dependentSchemas",
|
|
428
|
+
"maxProperties",
|
|
429
|
+
"minProperties",
|
|
430
|
+
"patternProperties",
|
|
431
|
+
"properties",
|
|
432
|
+
"propertyNames",
|
|
433
|
+
"required"
|
|
434
|
+
],
|
|
435
|
+
string: [
|
|
436
|
+
"contentEncoding",
|
|
437
|
+
"contentMediaType",
|
|
438
|
+
"format",
|
|
439
|
+
"maxLength",
|
|
440
|
+
"minLength",
|
|
441
|
+
"pattern"
|
|
442
|
+
]
|
|
443
|
+
};
|
|
444
|
+
function nullableProjection(schema) {
|
|
445
|
+
if (!Array.isArray(schema.anyOf) || schema.anyOf.length !== 2)
|
|
446
|
+
return schema;
|
|
447
|
+
const branches = schema.anyOf.filter(isRecord);
|
|
448
|
+
if (branches.length !== 2)
|
|
449
|
+
return schema;
|
|
450
|
+
const nullBranch = branches.find((branch) => branch.type === "null");
|
|
451
|
+
const value = branches.find((branch) => typeof branch.type === "string" && branch.type !== "null");
|
|
452
|
+
if (!nullBranch || !value || Object.keys(nullBranch).some((key) => key !== "type")) {
|
|
453
|
+
return schema;
|
|
454
|
+
}
|
|
455
|
+
const type = value.type;
|
|
150
456
|
if (typeof type !== "string")
|
|
151
457
|
return schema;
|
|
152
458
|
const projected = { type: [type, "null"] };
|
|
@@ -390,465 +696,130 @@ function findDiscriminator(variants) {
|
|
|
390
696
|
for (const key of Object.keys(first.properties).sort()) {
|
|
391
697
|
const values = [];
|
|
392
698
|
const seen = new Set;
|
|
393
|
-
let valid = true;
|
|
394
|
-
for (const variant of variants) {
|
|
395
|
-
if (!requiredKeys(variant).has(key)) {
|
|
396
|
-
valid = false;
|
|
397
|
-
break;
|
|
398
|
-
}
|
|
399
|
-
const properties = variant.properties;
|
|
400
|
-
const field = isRecord(properties) ? properties[key] : undefined;
|
|
401
|
-
const branchValues = isRecord(field) ? stringValues(field) : null;
|
|
402
|
-
if (!branchValues || branchValues.length === 0) {
|
|
403
|
-
valid = false;
|
|
404
|
-
break;
|
|
405
|
-
}
|
|
406
|
-
for (const value of branchValues) {
|
|
407
|
-
if (seen.has(value)) {
|
|
408
|
-
valid = false;
|
|
409
|
-
break;
|
|
410
|
-
}
|
|
411
|
-
seen.add(value);
|
|
412
|
-
}
|
|
413
|
-
if (!valid)
|
|
414
|
-
break;
|
|
415
|
-
values.push(branchValues);
|
|
416
|
-
}
|
|
417
|
-
if (valid)
|
|
418
|
-
return { key, values };
|
|
419
|
-
}
|
|
420
|
-
return null;
|
|
421
|
-
}
|
|
422
|
-
function requiredKeys(variant) {
|
|
423
|
-
if (!Array.isArray(variant.required))
|
|
424
|
-
return new Set;
|
|
425
|
-
return new Set(variant.required.filter((key) => typeof key === "string"));
|
|
426
|
-
}
|
|
427
|
-
function appendHint(schema, hint) {
|
|
428
|
-
const description = typeof schema.description === "string" ? schema.description : undefined;
|
|
429
|
-
return { ...schema, description: description ? `${description} ${hint}` : hint };
|
|
430
|
-
}
|
|
431
|
-
function flattenNode(node) {
|
|
432
|
-
const variants = objectVariants(node);
|
|
433
|
-
if (!variants)
|
|
434
|
-
return node;
|
|
435
|
-
const discriminator = findDiscriminator(variants);
|
|
436
|
-
if (!discriminator)
|
|
437
|
-
return node;
|
|
438
|
-
const perKey = new Map;
|
|
439
|
-
for (let index = 0;index < variants.length; index++) {
|
|
440
|
-
const variant = variants[index];
|
|
441
|
-
if (!variant)
|
|
442
|
-
continue;
|
|
443
|
-
const labels = discriminator.values[index] ?? [];
|
|
444
|
-
const required = requiredKeys(variant);
|
|
445
|
-
if (!isRecord(variant.properties))
|
|
446
|
-
continue;
|
|
447
|
-
for (const [key, rawSchema] of Object.entries(variant.properties)) {
|
|
448
|
-
if (key === discriminator.key || !isRecord(rawSchema))
|
|
449
|
-
continue;
|
|
450
|
-
const entries = perKey.get(key) ?? [];
|
|
451
|
-
entries.push({ schema: rawSchema, labels, required: required.has(key) });
|
|
452
|
-
perKey.set(key, entries);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
const discriminatorProperties = [];
|
|
456
|
-
for (let index = 0;index < variants.length; index++) {
|
|
457
|
-
const variant = variants[index];
|
|
458
|
-
if (!variant || !isRecord(variant.properties))
|
|
459
|
-
continue;
|
|
460
|
-
const schema = variant.properties[discriminator.key];
|
|
461
|
-
if (!isRecord(schema))
|
|
462
|
-
continue;
|
|
463
|
-
discriminatorProperties.push({
|
|
464
|
-
schema,
|
|
465
|
-
labels: discriminator.values[index] ?? [],
|
|
466
|
-
required: true
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
const properties = {
|
|
470
|
-
[discriminator.key]: mergePropertySchemas(discriminatorProperties, discriminator.key)
|
|
471
|
-
};
|
|
472
|
-
const required = [discriminator.key];
|
|
473
|
-
for (const [key, entries] of perKey) {
|
|
474
|
-
let merged = mergePropertySchemas(entries, discriminator.key);
|
|
475
|
-
const requiredEverywhere = entries.length === variants.length && entries.every((entry) => entry.required);
|
|
476
|
-
if (requiredEverywhere) {
|
|
477
|
-
required.push(key);
|
|
478
|
-
} else {
|
|
479
|
-
const requiredLabels = entries.filter((entry) => entry.required).flatMap((entry) => entry.labels);
|
|
480
|
-
const presentLabels = entries.flatMap((entry) => entry.labels);
|
|
481
|
-
merged = appendHint(merged, `Available if ${discriminator.key} = ${[...new Set(presentLabels)].join(" | ")}.`);
|
|
482
|
-
if (requiredLabels.length > 0) {
|
|
483
|
-
merged = appendHint(merged, `Required if ${discriminator.key} = ${[...new Set(requiredLabels)].join(" | ")}`);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
properties[key] = merged;
|
|
487
|
-
}
|
|
488
|
-
const result = {};
|
|
489
|
-
for (const [key, value] of Object.entries(node)) {
|
|
490
|
-
if (key !== "oneOf" && key !== "anyOf" && key !== "properties" && key !== "required") {
|
|
491
|
-
result[key] = value;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
result.type = "object";
|
|
495
|
-
result.properties = properties;
|
|
496
|
-
result.required = required;
|
|
497
|
-
result.additionalProperties = variants.every((variant) => variant.additionalProperties === false) ? false : {};
|
|
498
|
-
return result;
|
|
499
|
-
}
|
|
500
|
-
function flattenToolJsonSchema2(schema) {
|
|
501
|
-
const result = rebuild(schema);
|
|
502
|
-
return isRecord(result) ? result : {};
|
|
503
|
-
}
|
|
504
|
-
function freezeToolJsonSchema(schema) {
|
|
505
|
-
for (const value of Object.values(schema))
|
|
506
|
-
freezeJsonValue(value);
|
|
507
|
-
return Object.freeze(schema);
|
|
508
|
-
}
|
|
509
|
-
function freezeJsonValue(value) {
|
|
510
|
-
if (Array.isArray(value)) {
|
|
511
|
-
for (const item of value)
|
|
512
|
-
freezeJsonValue(item);
|
|
513
|
-
Object.freeze(value);
|
|
514
|
-
} else if (isRecord(value)) {
|
|
515
|
-
freezeToolJsonSchema(value);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// src/tools/schema/untyped-properties.ts
|
|
520
|
-
var TYPE_KEYWORDS2 = ["type", "enum", "const", "anyOf", "oneOf", "allOf", "$ref", "not"];
|
|
521
|
-
function saysWhatItIs(schema) {
|
|
522
|
-
return TYPE_KEYWORDS2.some((keyword) => schema[keyword] !== undefined);
|
|
523
|
-
}
|
|
524
|
-
function findUntypedProperties2(schema, prefix = "") {
|
|
525
|
-
if (!isRecord(schema))
|
|
526
|
-
return [];
|
|
527
|
-
const found = [];
|
|
528
|
-
const properties = schema.properties;
|
|
529
|
-
if (isRecord(properties)) {
|
|
530
|
-
for (const [key, value] of Object.entries(properties)) {
|
|
531
|
-
const path = prefix ? `${prefix}.${key}` : key;
|
|
532
|
-
if (isRecord(value)) {
|
|
533
|
-
if (!saysWhatItIs(value)) {
|
|
534
|
-
const description = value.description;
|
|
535
|
-
found.push({
|
|
536
|
-
path,
|
|
537
|
-
...typeof description === "string" && { description }
|
|
538
|
-
});
|
|
539
|
-
}
|
|
540
|
-
found.push(...findUntypedProperties2(value, path));
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
for (const key of ["items", "additionalProperties"]) {
|
|
545
|
-
const child = schema[key];
|
|
546
|
-
if (isRecord(child))
|
|
547
|
-
found.push(...findUntypedProperties2(child, prefix));
|
|
548
|
-
if (Array.isArray(child)) {
|
|
549
|
-
for (const entry of child) {
|
|
550
|
-
if (isRecord(entry))
|
|
551
|
-
found.push(...findUntypedProperties2(entry, prefix));
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
for (const key of ["prefixItems"]) {
|
|
556
|
-
const child = schema[key];
|
|
557
|
-
if (Array.isArray(child)) {
|
|
558
|
-
for (const entry of child) {
|
|
559
|
-
if (isRecord(entry))
|
|
560
|
-
found.push(...findUntypedProperties2(entry, prefix));
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
const patterned = schema.patternProperties;
|
|
565
|
-
if (isRecord(patterned)) {
|
|
566
|
-
for (const value of Object.values(patterned)) {
|
|
567
|
-
if (isRecord(value))
|
|
568
|
-
found.push(...findUntypedProperties2(value, prefix));
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
for (const key of ["$defs", "definitions"]) {
|
|
572
|
-
const container = schema[key];
|
|
573
|
-
if (!isRecord(container))
|
|
574
|
-
continue;
|
|
575
|
-
for (const definition of Object.values(container)) {
|
|
576
|
-
if (isRecord(definition))
|
|
577
|
-
found.push(...findUntypedProperties2(definition, prefix));
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
for (const key of ["allOf", "anyOf", "oneOf"]) {
|
|
581
|
-
const branches = schema[key];
|
|
582
|
-
if (Array.isArray(branches)) {
|
|
583
|
-
for (const branch of branches)
|
|
584
|
-
found.push(...findUntypedProperties2(branch, prefix));
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
return found;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// src/tools/internal/tool-view.ts
|
|
591
|
-
function toolSurfaceOutputSchema(operation) {
|
|
592
|
-
if (!operation.outputSchema)
|
|
593
|
-
return;
|
|
594
|
-
return operation.toolView?.output ?? operation.outputSchema;
|
|
595
|
-
}
|
|
596
|
-
function applyToolViewDefaults(inputArgs, defaults) {
|
|
597
|
-
if (!defaults)
|
|
598
|
-
return inputArgs;
|
|
599
|
-
const filled = { ...inputArgs };
|
|
600
|
-
for (const [key, value] of Object.entries(defaults)) {
|
|
601
|
-
if (filled[key] === undefined)
|
|
602
|
-
filled[key] = structuredClone(value);
|
|
603
|
-
}
|
|
604
|
-
return filled;
|
|
605
|
-
}
|
|
606
|
-
function projectToolView(options) {
|
|
607
|
-
const { view } = options;
|
|
608
|
-
let projected = options.full;
|
|
609
|
-
if (view.project) {
|
|
610
|
-
try {
|
|
611
|
-
projected = Reflect.apply(view.project, undefined, [options.full, options.call]);
|
|
612
|
-
} catch (error) {
|
|
613
|
-
const failure = new AppError2("INTERNAL_SERVER_ERROR", {
|
|
614
|
-
message: `${options.operation} toolView.project threw`,
|
|
615
|
-
status: 500
|
|
616
|
-
});
|
|
617
|
-
failure.cause = error;
|
|
618
|
-
throw failure;
|
|
619
|
-
}
|
|
620
|
-
if (isRecord(projected) && typeof projected.then === "function") {
|
|
621
|
-
Promise.resolve(projected).catch(() => {
|
|
622
|
-
return;
|
|
623
|
-
});
|
|
624
|
-
throw new AppError2("INTERNAL_SERVER_ERROR", {
|
|
625
|
-
message: `${options.operation} toolView.project returned a Promise — it must be synchronous`,
|
|
626
|
-
status: 500
|
|
627
|
-
});
|
|
628
|
-
}
|
|
629
|
-
if (projected === undefined) {
|
|
630
|
-
return {
|
|
631
|
-
ok: false,
|
|
632
|
-
message: `${options.operation} toolView.project returned undefined`
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
const checked = validateDeclaredOutput(view.output ?? options.fullSchema, projected, view.project ? options.onStripped : undefined);
|
|
637
|
-
if (!checked.ok) {
|
|
638
|
-
return { ok: false, message: `${options.operation} toolView: ${checked.message}` };
|
|
639
|
-
}
|
|
640
|
-
return checked;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// src/tools/schema/schema.ts
|
|
644
|
-
import { z } from "zod";
|
|
645
|
-
function objectShapeKeys(schema) {
|
|
646
|
-
return schema instanceof z.ZodObject ? Object.keys(schema.shape) : [];
|
|
647
|
-
}
|
|
648
|
-
function keyPolicyOf(schema) {
|
|
649
|
-
return schema.def.catchall;
|
|
650
|
-
}
|
|
651
|
-
function rebuildObject(source, shape) {
|
|
652
|
-
return withKeyPolicy(z.object(shape), keyPolicyOf(source));
|
|
653
|
-
}
|
|
654
|
-
function withKeyPolicy(object, policy) {
|
|
655
|
-
if (policy === undefined)
|
|
656
|
-
return object;
|
|
657
|
-
return object.catchall(representable(policy));
|
|
658
|
-
}
|
|
659
|
-
function representable(policy) {
|
|
660
|
-
if (policy instanceof z.ZodNever || policy instanceof z.ZodUnknown)
|
|
661
|
-
return policy;
|
|
662
|
-
if (!(policy instanceof z.ZodType))
|
|
663
|
-
return z.unknown();
|
|
664
|
-
try {
|
|
665
|
-
toJsonSchema(policy, "input");
|
|
666
|
-
return policy;
|
|
667
|
-
} catch {
|
|
668
|
-
return z.unknown();
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
function mergeSchemas(paramsSchema, inputSchema) {
|
|
672
|
-
if (paramsSchema && !(paramsSchema instanceof z.ZodObject)) {
|
|
673
|
-
throw new Error("Tool params schema must be a z.object()");
|
|
674
|
-
}
|
|
675
|
-
const paramsObject = paramsSchema instanceof z.ZodObject ? paramsSchema : undefined;
|
|
676
|
-
if (!inputSchema) {
|
|
677
|
-
return paramsObject ?? z.object({});
|
|
678
|
-
}
|
|
679
|
-
if (inputSchema instanceof z.ZodObject) {
|
|
680
|
-
if (paramsObject) {
|
|
681
|
-
const conflicts = Object.keys(paramsObject.shape).filter((key) => (key in inputSchema.shape));
|
|
682
|
-
if (conflicts.length > 0) {
|
|
683
|
-
throw new Error(`Schema merge conflict: ${conflicts.join(", ")} appear in both params and input`);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
return rebuildObject(inputSchema, {
|
|
687
|
-
...paramsObject?.shape ?? {},
|
|
688
|
-
...inputSchema.shape
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
return paramsObject ? z.intersection(paramsObject, inputSchema) : inputSchema;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
// src/tools/names.ts
|
|
695
|
-
var SINGULAR_EXCEPTIONS = new Set([
|
|
696
|
-
"analytics",
|
|
697
|
-
"status",
|
|
698
|
-
"stats",
|
|
699
|
-
"settings",
|
|
700
|
-
"media",
|
|
701
|
-
"progress",
|
|
702
|
-
"news"
|
|
703
|
-
]);
|
|
704
|
-
var TOOL_NAME_RE = /^[a-zA-Z0-9_-]{1,64}$/;
|
|
705
|
-
function normalizeService(value) {
|
|
706
|
-
return value.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
707
|
-
}
|
|
708
|
-
function normalizeMethod(value) {
|
|
709
|
-
return value.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
710
|
-
}
|
|
711
|
-
function singularize(name) {
|
|
712
|
-
if (SINGULAR_EXCEPTIONS.has(name))
|
|
713
|
-
return name;
|
|
714
|
-
if (name.endsWith("ies"))
|
|
715
|
-
return `${name.slice(0, -3)}y`;
|
|
716
|
-
if (name.endsWith("s") && !name.endsWith("ss"))
|
|
717
|
-
return name.slice(0, -1);
|
|
718
|
-
return name;
|
|
719
|
-
}
|
|
720
|
-
function singularizeTail(name) {
|
|
721
|
-
const cut = name.lastIndexOf("_");
|
|
722
|
-
if (cut === -1)
|
|
723
|
-
return singularize(name);
|
|
724
|
-
return `${name.slice(0, cut + 1)}${singularize(name.slice(cut + 1))}`;
|
|
725
|
-
}
|
|
726
|
-
function hasUsableChars(value) {
|
|
727
|
-
return /[a-zA-Z0-9]/.test(value);
|
|
728
|
-
}
|
|
729
|
-
function assertToolName(name, serviceName, key) {
|
|
730
|
-
const where = `service "${serviceName}", method "${key}"`;
|
|
731
|
-
if (!TOOL_NAME_RE.test(name)) {
|
|
732
|
-
const why = name.length > 64 ? `is ${name.length} characters (max 64) — set an explicit \`tool.name\`` : "must match [a-zA-Z0-9_-]";
|
|
733
|
-
throw new Error(`Tool name "${name}" (${where}) ${why}`);
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
function toToolName(serviceName, methodName) {
|
|
737
|
-
const normalized = normalizeService(serviceName);
|
|
738
|
-
const singular = singularizeTail(normalized);
|
|
739
|
-
const method = normalizeMethod(methodName);
|
|
740
|
-
if (method === "list")
|
|
741
|
-
return `list_${normalized}`;
|
|
742
|
-
if (method === "get")
|
|
743
|
-
return `get_${singular}`;
|
|
744
|
-
if (method === "create")
|
|
745
|
-
return `create_${singular}`;
|
|
746
|
-
if (method === "update")
|
|
747
|
-
return `update_${singular}`;
|
|
748
|
-
if (method === "delete")
|
|
749
|
-
return `delete_${singular}`;
|
|
750
|
-
const snake = method.replace(/([A-Z])/g, "_$1").toLowerCase();
|
|
751
|
-
return `${snake}_${singular}`.replace(/^_/, "");
|
|
752
|
-
}
|
|
753
|
-
function assertUniqueToolName(name, taken, surface) {
|
|
754
|
-
if (taken) {
|
|
755
|
-
throw new Error(`Duplicate ${surface} "${name}" across mounted operations`);
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
// src/tools/schema/presentation.ts
|
|
760
|
-
import { z as z2 } from "zod";
|
|
761
|
-
|
|
762
|
-
// src/json-schema/dialect.ts
|
|
763
|
-
var DRAFT_07_MARKER = "draft-07";
|
|
764
|
-
var DRAFT_07_KEYWORD = "definitions";
|
|
765
|
-
var DEFS_KEYWORD = "$defs";
|
|
766
|
-
var SCHEMA_KEYWORDS = [
|
|
767
|
-
"items",
|
|
768
|
-
"additionalItems",
|
|
769
|
-
"additionalProperties",
|
|
770
|
-
"contains",
|
|
771
|
-
"propertyNames",
|
|
772
|
-
"not",
|
|
773
|
-
"if",
|
|
774
|
-
"then",
|
|
775
|
-
"else",
|
|
776
|
-
"unevaluatedItems",
|
|
777
|
-
"unevaluatedProperties"
|
|
778
|
-
];
|
|
779
|
-
var SCHEMA_LIST_KEYWORDS = ["allOf", "anyOf", "oneOf", "prefixItems"];
|
|
780
|
-
var SCHEMA_MAP_KEYWORDS = [
|
|
781
|
-
"properties",
|
|
782
|
-
"patternProperties",
|
|
783
|
-
"dependentSchemas",
|
|
784
|
-
DRAFT_07_KEYWORD,
|
|
785
|
-
DEFS_KEYWORD
|
|
786
|
-
];
|
|
787
|
-
function declaresDraft07(dialect) {
|
|
788
|
-
return typeof dialect === "string" && dialect.includes(DRAFT_07_MARKER);
|
|
789
|
-
}
|
|
790
|
-
function rewriteDefinitionPointers(value) {
|
|
791
|
-
if (Array.isArray(value))
|
|
792
|
-
return value.map(rewriteDefinitionPointers);
|
|
793
|
-
if (!isRecord(value))
|
|
794
|
-
return value;
|
|
795
|
-
const rewritten = {};
|
|
796
|
-
for (const [key, child] of Object.entries(value)) {
|
|
797
|
-
rewritten[key] = key === "$ref" && typeof child === "string" && child.startsWith(`#/${DRAFT_07_KEYWORD}/`) ? `#/${DEFS_KEYWORD}/${child.slice(`#/${DRAFT_07_KEYWORD}/`.length)}` : rewriteDefinitionPointers(child);
|
|
699
|
+
let valid = true;
|
|
700
|
+
for (const variant of variants) {
|
|
701
|
+
if (!requiredKeys(variant).has(key)) {
|
|
702
|
+
valid = false;
|
|
703
|
+
break;
|
|
704
|
+
}
|
|
705
|
+
const properties = variant.properties;
|
|
706
|
+
const field = isRecord(properties) ? properties[key] : undefined;
|
|
707
|
+
const branchValues = isRecord(field) ? stringValues(field) : null;
|
|
708
|
+
if (!branchValues || branchValues.length === 0) {
|
|
709
|
+
valid = false;
|
|
710
|
+
break;
|
|
711
|
+
}
|
|
712
|
+
for (const value of branchValues) {
|
|
713
|
+
if (seen.has(value)) {
|
|
714
|
+
valid = false;
|
|
715
|
+
break;
|
|
716
|
+
}
|
|
717
|
+
seen.add(value);
|
|
718
|
+
}
|
|
719
|
+
if (!valid)
|
|
720
|
+
break;
|
|
721
|
+
values.push(branchValues);
|
|
722
|
+
}
|
|
723
|
+
if (valid)
|
|
724
|
+
return { key, values };
|
|
798
725
|
}
|
|
799
|
-
return
|
|
726
|
+
return null;
|
|
800
727
|
}
|
|
801
|
-
function
|
|
802
|
-
if (!
|
|
803
|
-
return
|
|
804
|
-
|
|
805
|
-
for (const [name, child] of Object.entries(value))
|
|
806
|
-
rewritten[name] = rewrite(child);
|
|
807
|
-
return rewritten;
|
|
728
|
+
function requiredKeys(variant) {
|
|
729
|
+
if (!Array.isArray(variant.required))
|
|
730
|
+
return new Set;
|
|
731
|
+
return new Set(variant.required.filter((key) => typeof key === "string"));
|
|
808
732
|
}
|
|
809
|
-
function
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
733
|
+
function appendHint(schema, hint) {
|
|
734
|
+
const description = typeof schema.description === "string" ? schema.description : undefined;
|
|
735
|
+
return { ...schema, description: description ? `${description} ${hint}` : hint };
|
|
736
|
+
}
|
|
737
|
+
function flattenNode(node) {
|
|
738
|
+
const variants = objectVariants(node);
|
|
739
|
+
if (!variants)
|
|
740
|
+
return node;
|
|
741
|
+
const discriminator = findDiscriminator(variants);
|
|
742
|
+
if (!discriminator)
|
|
743
|
+
return node;
|
|
744
|
+
const perKey = new Map;
|
|
745
|
+
for (let index = 0;index < variants.length; index++) {
|
|
746
|
+
const variant = variants[index];
|
|
747
|
+
if (!variant)
|
|
748
|
+
continue;
|
|
749
|
+
const labels = discriminator.values[index] ?? [];
|
|
750
|
+
const required = requiredKeys(variant);
|
|
751
|
+
if (!isRecord(variant.properties))
|
|
752
|
+
continue;
|
|
753
|
+
for (const [key, rawSchema] of Object.entries(variant.properties)) {
|
|
754
|
+
if (key === discriminator.key || !isRecord(rawSchema))
|
|
755
|
+
continue;
|
|
756
|
+
const entries = perKey.get(key) ?? [];
|
|
757
|
+
entries.push({ schema: rawSchema, labels, required: required.has(key) });
|
|
758
|
+
perKey.set(key, entries);
|
|
759
|
+
}
|
|
822
760
|
}
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
761
|
+
const discriminatorProperties = [];
|
|
762
|
+
for (let index = 0;index < variants.length; index++) {
|
|
763
|
+
const variant = variants[index];
|
|
764
|
+
if (!variant || !isRecord(variant.properties))
|
|
765
|
+
continue;
|
|
766
|
+
const schema = variant.properties[discriminator.key];
|
|
767
|
+
if (!isRecord(schema))
|
|
768
|
+
continue;
|
|
769
|
+
discriminatorProperties.push({
|
|
770
|
+
schema,
|
|
771
|
+
labels: discriminator.values[index] ?? [],
|
|
772
|
+
required: true
|
|
773
|
+
});
|
|
832
774
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
775
|
+
const properties = {
|
|
776
|
+
[discriminator.key]: mergePropertySchemas(discriminatorProperties, discriminator.key)
|
|
777
|
+
};
|
|
778
|
+
const required = [discriminator.key];
|
|
779
|
+
for (const [key, entries] of perKey) {
|
|
780
|
+
let merged = mergePropertySchemas(entries, discriminator.key);
|
|
781
|
+
const requiredEverywhere = entries.length === variants.length && entries.every((entry) => entry.required);
|
|
782
|
+
if (requiredEverywhere) {
|
|
783
|
+
required.push(key);
|
|
784
|
+
} else {
|
|
785
|
+
const requiredLabels = entries.filter((entry) => entry.required).flatMap((entry) => entry.labels);
|
|
786
|
+
const presentLabels = entries.flatMap((entry) => entry.labels);
|
|
787
|
+
merged = appendHint(merged, `Available if ${discriminator.key} = ${[...new Set(presentLabels)].join(" | ")}.`);
|
|
788
|
+
if (requiredLabels.length > 0) {
|
|
789
|
+
merged = appendHint(merged, `Required if ${discriminator.key} = ${[...new Set(requiredLabels)].join(" | ")}`);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
properties[key] = merged;
|
|
793
|
+
}
|
|
794
|
+
const result = {};
|
|
795
|
+
for (const [key, value] of Object.entries(node)) {
|
|
796
|
+
if (key !== "oneOf" && key !== "anyOf" && key !== "properties" && key !== "required") {
|
|
797
|
+
result[key] = value;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
result.type = "object";
|
|
801
|
+
result.properties = properties;
|
|
802
|
+
result.required = required;
|
|
803
|
+
result.additionalProperties = variants.every((variant) => variant.additionalProperties === false) ? false : {};
|
|
804
|
+
return result;
|
|
836
805
|
}
|
|
837
|
-
function
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
806
|
+
function flattenToolJsonSchema2(schema) {
|
|
807
|
+
const result = rebuild(schema);
|
|
808
|
+
return isRecord(result) ? result : {};
|
|
809
|
+
}
|
|
810
|
+
function freezeToolJsonSchema(schema) {
|
|
811
|
+
for (const value of Object.values(schema))
|
|
812
|
+
freezeJsonValue(value);
|
|
813
|
+
return Object.freeze(schema);
|
|
814
|
+
}
|
|
815
|
+
function freezeJsonValue(value) {
|
|
816
|
+
if (Array.isArray(value)) {
|
|
817
|
+
for (const item of value)
|
|
818
|
+
freezeJsonValue(item);
|
|
819
|
+
Object.freeze(value);
|
|
820
|
+
} else if (isRecord(value)) {
|
|
821
|
+
freezeToolJsonSchema(value);
|
|
849
822
|
}
|
|
850
|
-
rewritten[DEFS_KEYWORD] = rewriteDefinitionPointers(definitions);
|
|
851
|
-
return rewritten;
|
|
852
823
|
}
|
|
853
824
|
|
|
854
825
|
// src/tools/schema/presentation.ts
|
|
@@ -1040,43 +1011,75 @@ function presentationMetadata(schema) {
|
|
|
1040
1011
|
return withDraft2020Keywords(withoutDialect(schema));
|
|
1041
1012
|
}
|
|
1042
1013
|
|
|
1043
|
-
// src/tools/
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
function staticInputRounds(policy) {
|
|
1048
|
-
return Array.isArray(policy.inputRequired) ? policy.inputRequired : undefined;
|
|
1014
|
+
// src/tools/schema/untyped-properties.ts
|
|
1015
|
+
var TYPE_KEYWORDS2 = ["type", "enum", "const", "anyOf", "oneOf", "allOf", "$ref", "not"];
|
|
1016
|
+
function saysWhatItIs(schema) {
|
|
1017
|
+
return TYPE_KEYWORDS2.some((keyword) => schema[keyword] !== undefined);
|
|
1049
1018
|
}
|
|
1050
|
-
function
|
|
1051
|
-
if (!
|
|
1052
|
-
|
|
1019
|
+
function findUntypedProperties2(schema, prefix = "") {
|
|
1020
|
+
if (!isRecord(schema))
|
|
1021
|
+
return [];
|
|
1022
|
+
const found = [];
|
|
1023
|
+
const properties = schema.properties;
|
|
1024
|
+
if (isRecord(properties)) {
|
|
1025
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
1026
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
1027
|
+
if (isRecord(value)) {
|
|
1028
|
+
if (!saysWhatItIs(value)) {
|
|
1029
|
+
const description = value.description;
|
|
1030
|
+
found.push({
|
|
1031
|
+
path,
|
|
1032
|
+
...typeof description === "string" && { description }
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
found.push(...findUntypedProperties2(value, path));
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1053
1038
|
}
|
|
1054
|
-
const
|
|
1055
|
-
|
|
1056
|
-
|
|
1039
|
+
for (const key of ["items", "additionalProperties"]) {
|
|
1040
|
+
const child = schema[key];
|
|
1041
|
+
if (isRecord(child))
|
|
1042
|
+
found.push(...findUntypedProperties2(child, prefix));
|
|
1043
|
+
if (Array.isArray(child)) {
|
|
1044
|
+
for (const entry of child) {
|
|
1045
|
+
if (isRecord(entry))
|
|
1046
|
+
found.push(...findUntypedProperties2(entry, prefix));
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1057
1049
|
}
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1050
|
+
for (const key of ["prefixItems"]) {
|
|
1051
|
+
const child = schema[key];
|
|
1052
|
+
if (Array.isArray(child)) {
|
|
1053
|
+
for (const entry of child) {
|
|
1054
|
+
if (isRecord(entry))
|
|
1055
|
+
found.push(...findUntypedProperties2(entry, prefix));
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1063
1058
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
if (rounds.length > maxRounds) {
|
|
1071
|
-
throw new Error(`[stitchkit] MCP tool "${tool.name}" declares ${rounds.length} input rounds, exceeding maxRounds ${maxRounds}`);
|
|
1059
|
+
const patterned = schema.patternProperties;
|
|
1060
|
+
if (isRecord(patterned)) {
|
|
1061
|
+
for (const value of Object.values(patterned)) {
|
|
1062
|
+
if (isRecord(value))
|
|
1063
|
+
found.push(...findUntypedProperties2(value, prefix));
|
|
1064
|
+
}
|
|
1072
1065
|
}
|
|
1073
|
-
const
|
|
1074
|
-
|
|
1075
|
-
if (
|
|
1076
|
-
|
|
1066
|
+
for (const key of ["$defs", "definitions"]) {
|
|
1067
|
+
const container = schema[key];
|
|
1068
|
+
if (!isRecord(container))
|
|
1069
|
+
continue;
|
|
1070
|
+
for (const definition of Object.values(container)) {
|
|
1071
|
+
if (isRecord(definition))
|
|
1072
|
+
found.push(...findUntypedProperties2(definition, prefix));
|
|
1077
1073
|
}
|
|
1078
|
-
keys.add(request.key);
|
|
1079
1074
|
}
|
|
1075
|
+
for (const key of ["allOf", "anyOf", "oneOf"]) {
|
|
1076
|
+
const branches = schema[key];
|
|
1077
|
+
if (Array.isArray(branches)) {
|
|
1078
|
+
for (const branch of branches)
|
|
1079
|
+
found.push(...findUntypedProperties2(branch, prefix));
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
return found;
|
|
1080
1083
|
}
|
|
1081
1084
|
|
|
1082
1085
|
// src/tools/internal/surface-projector.ts
|
|
@@ -1152,7 +1155,7 @@ function projectToolSurface(surface, transport, config = {}) {
|
|
|
1152
1155
|
} else if (method.expose && !method.expose.includes(transport)) {
|
|
1153
1156
|
continue;
|
|
1154
1157
|
}
|
|
1155
|
-
if (method
|
|
1158
|
+
if (isHttpOnlyEndpoint(method)) {
|
|
1156
1159
|
continue;
|
|
1157
1160
|
}
|
|
1158
1161
|
const name = method.toolName ?? toToolName(service.name, methodName);
|