@runtypelabs/cli 2.59.1 → 2.59.4

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 (84) hide show
  1. package/dist/chunk-0x7UKC1U.js +17 -0
  2. package/dist/chunk-2ySxXtcg.js +418 -0
  3. package/dist/chunk-3An_BRHv.js +501 -0
  4. package/dist/chunk-6uTxgdiY.js +16218 -0
  5. package/dist/chunk-87nRnNRG.js +1363 -0
  6. package/dist/chunk-B3wo8uRx.js +322 -0
  7. package/dist/chunk-BGp3ZdBy.js +560 -0
  8. package/dist/chunk-BJQv9Elp.js +107 -0
  9. package/dist/chunk-BOpO6xE-.js +6053 -0
  10. package/dist/chunk-BQXXCL8B.js +102 -0
  11. package/dist/chunk-BV-8isOd.js +34 -0
  12. package/dist/chunk-BVMhjGVe.js +826 -0
  13. package/dist/chunk-BW2fg46T.js +141 -0
  14. package/dist/chunk-BWJdY5Ag.js +36 -0
  15. package/dist/chunk-BYJOrLhh.js +302 -0
  16. package/dist/chunk-BYab8EVL.js +127 -0
  17. package/dist/chunk-BfEKvp7h.js +82 -0
  18. package/dist/chunk-BhgLSfH6.js +1123 -0
  19. package/dist/chunk-BirUxTtH.js +296 -0
  20. package/dist/chunk-BmB6UVZ9.js +1559 -0
  21. package/dist/chunk-BnWhIqW1.js +109 -0
  22. package/dist/chunk-Bpfnfk0t.js +123 -0
  23. package/dist/chunk-BrhgdnM3.js +108 -0
  24. package/dist/chunk-Bt0XAgX5.js +327 -0
  25. package/dist/chunk-Bu0FJr6S.js +84 -0
  26. package/dist/chunk-BvEoKpN3.js +255 -0
  27. package/dist/chunk-BxNJgYbE.js +28 -0
  28. package/dist/chunk-C1OFhd7F.js +6131 -0
  29. package/dist/chunk-C7e7WwbU.js +331 -0
  30. package/dist/chunk-CDTYP6bN.js +558 -0
  31. package/dist/chunk-CGDQoqDC.js +24 -0
  32. package/dist/chunk-CJraEBVd.js +127 -0
  33. package/dist/chunk-CQrNhOtv.js +40 -0
  34. package/dist/chunk-CW6AzBH6.js +128 -0
  35. package/dist/chunk-CXgL4w-9.js +317 -0
  36. package/dist/chunk-CZrqoPyf.js +233 -0
  37. package/dist/chunk-CcFCyqbB.js +83 -0
  38. package/dist/chunk-CdaIvO-y.js +485 -0
  39. package/dist/chunk-CehSXtgK.js +624 -0
  40. package/dist/chunk-Ciqkop65.js +218 -0
  41. package/dist/chunk-CoAWdSiE.js +43 -0
  42. package/dist/chunk-Crb4y7t4.js +830 -0
  43. package/dist/chunk-CrlqIfmb.js +337 -0
  44. package/dist/chunk-Cs4pwCQ-.js +324 -0
  45. package/dist/chunk-CwM_9y01.js +519 -0
  46. package/dist/chunk-CyRbIJg8.js +440 -0
  47. package/dist/chunk-D0OHsyMy.js +212 -0
  48. package/dist/chunk-D3y2bURs.js +1347 -0
  49. package/dist/chunk-D4_mJk03.js +2338 -0
  50. package/dist/chunk-D6C8rned.js +578 -0
  51. package/dist/chunk-D9ZbUnks.js +11 -0
  52. package/dist/chunk-DEPmLshX.js +834 -0
  53. package/dist/chunk-DFj1UPB2.js +330 -0
  54. package/dist/chunk-DGdFdZVf.js +197 -0
  55. package/dist/chunk-DGv7X9S_.js +63 -0
  56. package/dist/chunk-DJQ47WYZ.js +664 -0
  57. package/dist/chunk-DJw3O61j.js +1974 -0
  58. package/dist/chunk-DK4FbWVK.js +100 -0
  59. package/dist/chunk-DPuofXMp.js +3907 -0
  60. package/dist/chunk-DSRYhUus.js +993 -0
  61. package/dist/chunk-DajZ9Eg4.js +299 -0
  62. package/dist/chunk-Df4dunvU.js +195 -0
  63. package/dist/chunk-DjNTPhfO.js +481 -0
  64. package/dist/chunk-Dn8eaJuu.js +1042 -0
  65. package/dist/chunk-DwDWqSxM.js +637 -0
  66. package/dist/chunk-Dz7cEtxl.js +84 -0
  67. package/dist/chunk-E_0bgjrS.js +359 -0
  68. package/dist/chunk-KPYN2vUp.js +776 -0
  69. package/dist/chunk-KcqPQJBi.js +86 -0
  70. package/dist/chunk-N9H0JnoG.js +349 -0
  71. package/dist/chunk-NONFcXkn.js +728 -0
  72. package/dist/chunk-PrFjcpmH.js +256 -0
  73. package/dist/chunk-QSfNYiw9.js +11 -0
  74. package/dist/chunk-R265bzj9.js +226 -0
  75. package/dist/chunk-X9V_r6jM.js +166 -0
  76. package/dist/chunk-ZBtPUtyA.js +55 -0
  77. package/dist/chunk-ZCTfmOs7.js +4939 -0
  78. package/dist/chunk-h6oavj0t.js +97 -0
  79. package/dist/chunk-i7DwkvvD.js +42 -0
  80. package/dist/chunk-mG-4eZ6S.js +203 -0
  81. package/dist/chunk-o0ygUbCf.js +313 -0
  82. package/dist/chunk-ucu5lrDZ.js +5715 -0
  83. package/dist/index.js +11367 -73789
  84. package/package.json +5 -5
@@ -0,0 +1,826 @@
1
+ #!/usr/bin/env node
2
+ import { C as unknown, S as union, b as string, c as boolean, d as lazy, f as literal, h as object, i as _enum, l as custom, m as number, o as any, p as never, s as array, v as record, y as strictObject } from "./chunk-BOpO6xE-.js";
3
+ import { t as isRecord } from "./chunk-QSfNYiw9.js";
4
+ /**
5
+ * Well-known system variables always available at execution time, populated by the engine (system-vars.ts).
6
+ * Canonical set; flow-validator-core.ts and other consumers import it rather than re-declaring it.
7
+ * MESSAGE_VARIABLES are a subset, spread in below so there is a single source.
8
+ */
9
+ const SYSTEM_VARIABLES = /* @__PURE__ */ new Set([
10
+ "_flow",
11
+ "_user",
12
+ "_execution",
13
+ "_record",
14
+ "_now",
15
+ "_schedule",
16
+ "_conversation",
17
+ "_tools",
18
+ "_endUser",
19
+ "_tenant",
20
+ .../* @__PURE__ */ new Set([
21
+ "messages",
22
+ "userMessage",
23
+ "lastMessage",
24
+ "messageCount"
25
+ ])
26
+ ]);
27
+ /**
28
+ * Canonical {{secret:KEY}} detection regex; KEY is upper-snake, e.g. {{secret:OPENAI_API_KEY}}.
29
+ * Narrower than the general {{var}} form so secret tokens never collide with parameter templates.
30
+ * Single source of truth; historical duplicates import this constant instead of re-declaring the literal.
31
+ * Build a fresh regex per call when iterating matches so the shared instance's lastIndex is never mutated.
32
+ */
33
+ const SECRET_REF_PATTERN = /\{\{secret:([A-Z][A-Z0-9_]*[A-Z0-9])\}\}/g;
34
+ /**
35
+ * The recognized namespace prefixes and their semantics. Keyed by the literal
36
+ * prefix (with trailing colon). Adding a namespace here is the one-line change
37
+ * that teaches every layer about it.
38
+ */
39
+ const RUNTIME_PREFIXES = {
40
+ "secret:": {
41
+ prefix: "secret:",
42
+ namespace: "secret",
43
+ resolvedBy: "the secret pre-pass (substituteSecretReferences) before the template engine runs — never the template engine itself",
44
+ mayReachModelUnresolved: false
45
+ },
46
+ "flow:": {
47
+ prefix: "flow:",
48
+ namespace: "flow",
49
+ resolvedBy: "the template engine, which treats it as an alias for the bare flow variable of the same name",
50
+ mayReachModelUnresolved: false
51
+ }
52
+ };
53
+ /**
54
+ * Matches a leading `prefix:` segment. A prefix is a single identifier-ish
55
+ * segment followed by a colon at the very start of the token. Nested paths
56
+ * (`_record.metadata.field`) and fallback chains are NOT prefixes — they
57
+ * contain no leading `:`-terminated segment.
58
+ */
59
+ const PREFIX_PATTERN = /^([A-Za-z][A-Za-z0-9_-]*):(.*)$/s;
60
+ /**
61
+ * Classify a {{...}} token's variable key; the one function every layer uses to decide what a token is.
62
+ * Pass the KEY with surrounding whitespace and any fallback operand already stripped by the caller.
63
+ * Examples: _now.iso -> system, topic -> plain, flow:topic -> flow, secret:OPENAI -> secret, flwo:topic -> unknown.
64
+ */
65
+ function classifyVariableReference(token) {
66
+ const trimmed = token.trim();
67
+ const prefixMatch = PREFIX_PATTERN.exec(trimmed);
68
+ if (prefixMatch) {
69
+ const prefix = `${prefixMatch[1]}:`;
70
+ const rest = prefixMatch[2] ?? "";
71
+ const spec = RUNTIME_PREFIXES[prefix];
72
+ if (spec) return {
73
+ namespace: spec.namespace,
74
+ baseName: rest.trim()
75
+ };
76
+ return {
77
+ namespace: "unknown",
78
+ raw: trimmed
79
+ };
80
+ }
81
+ if (isSystemVariable(trimmed)) return {
82
+ namespace: "system",
83
+ baseName: trimmed
84
+ };
85
+ return {
86
+ namespace: "plain",
87
+ baseName: trimmed
88
+ };
89
+ }
90
+ /**
91
+ * Whether a variable key is a system variable or a nested access on one
92
+ * (e.g. `_record.metadata.field`, `_flow.name`). The root segment is matched
93
+ * against {@link SYSTEM_VARIABLES}.
94
+ */
95
+ function isSystemVariable(varName) {
96
+ const rootSegment = varName.split(".")[0] || "";
97
+ return SYSTEM_VARIABLES.has(rootSegment);
98
+ }
99
+ /** Error text for a caller-supplied input key in the reserved `_` system namespace. */
100
+ const RESERVED_INPUT_KEY_MESSAGE = "Input keys cannot start with '_' (reserved for system variables)";
101
+ /** Whether caller-supplied `inputs` stay out of the reserved `_` system namespace. */
102
+ function hasNoReservedInputKeys(inputs) {
103
+ if (!inputs) return true;
104
+ return Object.keys(inputs).every((key) => !key.startsWith("_"));
105
+ }
106
+ // ../shared/dist/chunk-9uTZDlBG.mjs
107
+ const nonNegativeInteger = number().int().nonnegative();
108
+ const annotations = {
109
+ title: string().optional(),
110
+ description: string().optional(),
111
+ default: unknown().optional()
112
+ };
113
+ const schemaNode = lazy(() => union([boolean(), schemaObject]));
114
+ const schemaObject = lazy(() => strictObject({
115
+ ...annotations,
116
+ type: _enum([
117
+ "object",
118
+ "array",
119
+ "string",
120
+ "number",
121
+ "integer",
122
+ "boolean",
123
+ "null"
124
+ ]).optional(),
125
+ properties: record(string(), schemaNode).optional(),
126
+ required: array(string()).optional(),
127
+ additionalProperties: schemaNode.optional(),
128
+ items: schemaNode.optional(),
129
+ prefixItems: array(schemaNode).optional(),
130
+ minItems: nonNegativeInteger.optional(),
131
+ maxItems: nonNegativeInteger.optional(),
132
+ uniqueItems: boolean().optional(),
133
+ minProperties: nonNegativeInteger.optional(),
134
+ maxProperties: nonNegativeInteger.optional(),
135
+ minLength: nonNegativeInteger.optional(),
136
+ maxLength: nonNegativeInteger.optional(),
137
+ minimum: number().optional(),
138
+ maximum: number().optional(),
139
+ exclusiveMinimum: number().optional(),
140
+ exclusiveMaximum: number().optional(),
141
+ multipleOf: number().positive().optional(),
142
+ enum: array(unknown()).min(1).optional(),
143
+ const: unknown().optional(),
144
+ format: _enum([
145
+ "date",
146
+ "date-time",
147
+ "time",
148
+ "email",
149
+ "uri",
150
+ "uuid"
151
+ ]).optional(),
152
+ allOf: array(schemaObject).min(1).optional(),
153
+ anyOf: array(schemaObject).min(1).optional(),
154
+ oneOf: array(schemaObject).min(1).optional(),
155
+ not: schemaObject.optional()
156
+ }));
157
+ function boundedJson(value) {
158
+ const pending = [{
159
+ value,
160
+ depth: 0
161
+ }];
162
+ let count = 0;
163
+ while (pending.length) {
164
+ const current = pending.pop();
165
+ if (++count > 4096 || current.depth > 16) return false;
166
+ if (current.value && typeof current.value === "object") for (const child of Object.values(current.value)) pending.push({
167
+ value: child,
168
+ depth: current.depth + 1
169
+ });
170
+ else if (typeof current.value === "string" && current.value.length > 65536) return false;
171
+ }
172
+ return true;
173
+ }
174
+ /** Whether a persisted form schema can be enforced by the elicitation answer validator. */
175
+ function isSupportedElicitationSchema(schema) {
176
+ if (!boundedJson(schema)) return false;
177
+ const parsed = schemaNode.safeParse(schema);
178
+ return parsed.success && typeof parsed.data !== "boolean" && parsed.data.type === "object";
179
+ }
180
+ // ../shared/dist/chunk-CXNdCxH5.mjs
181
+ /** The Tenancy Assurance Levels, in the order `tenancyAssuranceLevelSchema` is built from. */
182
+ const TENANCY_ASSURANCE_LEVELS = [
183
+ "anonymous",
184
+ "asserted",
185
+ "verified"
186
+ ];
187
+ const HOSTNAME_LABEL = /^(?!-)[a-z0-9-]{1,63}(?<!-)$/;
188
+ const IPV4_LITERAL = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
189
+ function isAudienceHostname(host) {
190
+ if (host.length === 0 || host.length > 253) return false;
191
+ const ipv4 = IPV4_LITERAL.exec(host);
192
+ if (ipv4) return ipv4.slice(1).every((octet) => Number(octet) <= 255);
193
+ return host.split(".").every((label) => HOSTNAME_LABEL.test(label));
194
+ }
195
+ /**
196
+ * Normalize one `identityAudiences` entry: a lowercase hostname, or `*.` plus a hostname of at least
197
+ * two labels. Returns `null` for anything else (schemes, ports, paths, a bare `*`, `*.com`).
198
+ */
199
+ function normalizeIdentityAudiencePattern(pattern) {
200
+ if (typeof pattern !== "string") return null;
201
+ const lowered = pattern.trim().toLowerCase();
202
+ if (lowered.startsWith("*.")) {
203
+ const suffix = lowered.slice(2);
204
+ if (IPV4_LITERAL.test(suffix) || suffix.split(".").length < 2) return null;
205
+ return isAudienceHostname(suffix) ? `*.${suffix}` : null;
206
+ }
207
+ return isAudienceHostname(lowered) ? lowered : null;
208
+ }
209
+ /**
210
+ * Whether an assertion audience is one the tool's `identityAudiences` permits. A `*.` pattern
211
+ * matches exactly one extra label, so `*.example.com` admits `pr-1.example.com` only.
212
+ */
213
+ function identityAudienceAllowed(audience, patterns) {
214
+ const host = audience.toLowerCase();
215
+ return patterns.some((pattern) => {
216
+ if (!pattern.startsWith("*.")) return host === pattern;
217
+ const suffix = pattern.slice(1);
218
+ if (!host.endsWith(suffix)) return false;
219
+ const label = host.slice(0, -suffix.length);
220
+ return HOSTNAME_LABEL.test(label);
221
+ });
222
+ }
223
+ // ../shared/dist/chunk-D0Rc89Pf.mjs
224
+ function extractSecretReferences(template) {
225
+ const keys = /* @__PURE__ */ new Set();
226
+ let match;
227
+ const regex = new RegExp(SECRET_REF_PATTERN.source, "g");
228
+ while ((match = regex.exec(template)) !== null) {
229
+ const key = match[1];
230
+ if (key) keys.add(key);
231
+ }
232
+ return Array.from(keys);
233
+ }
234
+ function extractSecretReferencesFromAnyValue(value, maxDepth = 10) {
235
+ const keys = /* @__PURE__ */ new Set();
236
+ walk(value, 0);
237
+ return Array.from(keys);
238
+ function walk(v, depth) {
239
+ if (depth > maxDepth) return;
240
+ if (typeof v === "string") {
241
+ for (const key of extractSecretReferences(v)) keys.add(key);
242
+ return;
243
+ }
244
+ if (Array.isArray(v)) {
245
+ for (const item of v) walk(item, depth + 1);
246
+ return;
247
+ }
248
+ if (v && typeof v === "object") for (const inner of Object.values(v)) walk(inner, depth + 1);
249
+ }
250
+ }
251
+ function isManagedDeploymentTargetPath(path) {
252
+ if (!path.startsWith("/") || path.startsWith("//") || /[\\?#\s{}]/.test(path)) return false;
253
+ let decoded = path;
254
+ for (let pass = 0; pass < 4; pass++) {
255
+ if (/[\\?#]/.test(decoded) || decoded.startsWith("//")) return false;
256
+ if (decoded.split("/").some((part) => part === "." || part === "..")) return false;
257
+ let next;
258
+ try {
259
+ next = decodeURIComponent(decoded);
260
+ } catch {
261
+ return false;
262
+ }
263
+ if (next === decoded) return true;
264
+ if (next.split("/").length !== decoded.split("/").length) return false;
265
+ decoded = next;
266
+ }
267
+ return false;
268
+ }
269
+ const managedDeploymentTargetSchema = object({
270
+ kind: literal("sandbox-deployment"),
271
+ deploymentId: string().regex(/^sbd_[0-9abcdefghjkmnpqrstvwxyz]{20,32}$/),
272
+ path: string().refine(isManagedDeploymentTargetPath, "Expected a fixed relative application path").optional(),
273
+ bearerSecretName: string().refine((name) => extractSecretReferences(`{{secret:${name}}}`)[0] === name, "Expected a canonical managed secret name").optional()
274
+ }).strict();
275
+ const httpDestinationSchema = union([object({
276
+ url: string().min(1),
277
+ target: never().optional()
278
+ }), object({
279
+ target: managedDeploymentTargetSchema,
280
+ url: never().optional()
281
+ })]);
282
+ function validateManagedDeploymentTargetConfig(config) {
283
+ if (httpDestinationSchema.safeParse(config).success) return void 0;
284
+ if (config.target === void 0) return "URL is required";
285
+ const parsed = managedDeploymentTargetSchema.safeParse(config.target);
286
+ if (!parsed.success) return parsed.error.issues.map((issue) => issue.message).join("; ");
287
+ if (config.url !== void 0) return "Use either URL or a managed deployment target, not both";
288
+ }
289
+ /** Validate authored targets while preserving incomplete external-tool drafts and saved MCP references. */
290
+ function validateToolHttpDestination(tool, ctx) {
291
+ if (!tool || typeof tool !== "object" || Array.isArray(tool)) return;
292
+ if (tool.toolType !== "external" && tool.toolType !== "mcp") return;
293
+ if (!tool.config || typeof tool.config !== "object" || Array.isArray(tool.config)) return;
294
+ if (!("target" in tool.config)) return;
295
+ if (tool.config.target === void 0) return;
296
+ const issue = validateManagedDeploymentTargetConfig(tool.config);
297
+ if (issue) ctx.addIssue({
298
+ code: "custom",
299
+ path: ["config", "target"],
300
+ message: issue
301
+ });
302
+ }
303
+ const primitiveSchema = strictObject({
304
+ type: _enum([
305
+ "string",
306
+ "number",
307
+ "integer",
308
+ "boolean"
309
+ ]),
310
+ title: string().optional(),
311
+ description: string().optional(),
312
+ enum: array(union([
313
+ string(),
314
+ number(),
315
+ boolean()
316
+ ])).min(1).optional(),
317
+ minLength: number().int().nonnegative().optional(),
318
+ maxLength: number().int().nonnegative().optional(),
319
+ minimum: number().optional(),
320
+ maximum: number().optional(),
321
+ exclusiveMinimum: number().optional(),
322
+ exclusiveMaximum: number().optional()
323
+ }).superRefine((schema, ctx) => {
324
+ const stringBounds = schema.minLength !== void 0 || schema.maxLength !== void 0;
325
+ const numberBounds = [
326
+ schema.minimum,
327
+ schema.maximum,
328
+ schema.exclusiveMinimum,
329
+ schema.exclusiveMaximum
330
+ ].some((bound) => bound !== void 0);
331
+ if (stringBounds && schema.type !== "string" || numberBounds && schema.type !== "number" && schema.type !== "integer") ctx.addIssue({
332
+ code: "custom",
333
+ message: "Bounds must match the property type"
334
+ });
335
+ if (schema.enum?.some((value) => schema.type === "integer" ? !Number.isInteger(value) : typeof value !== schema.type)) ctx.addIssue({
336
+ code: "custom",
337
+ message: "Enum values must match the property type"
338
+ });
339
+ if ((schema.minLength ?? 0) > (schema.maxLength ?? Infinity) || (schema.minimum ?? -Infinity) > (schema.maximum ?? Infinity)) ctx.addIssue({
340
+ code: "custom",
341
+ message: "Minimum must not exceed maximum"
342
+ });
343
+ });
344
+ const toolElicitationConfigSchema = strictObject({
345
+ message: string().min(1).max(4096),
346
+ requestedSchema: strictObject({
347
+ type: literal("object"),
348
+ title: string().optional(),
349
+ description: string().optional(),
350
+ properties: record(string(), primitiveSchema),
351
+ required: array(string()).optional(),
352
+ additionalProperties: literal(false)
353
+ }),
354
+ merge: literal("parameters")
355
+ });
356
+ function canonicalToolInputDefinition(value) {
357
+ if (Array.isArray(value)) return `[${value.map(canonicalToolInputDefinition).join(",")}]`;
358
+ if (isRecord(value)) return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalToolInputDefinition(value[key])}`).join(",")}}`;
359
+ return JSON.stringify(value) ?? "null";
360
+ }
361
+ /** Validate authored input against the final dispatch schema at every definition boundary. */
362
+ function validateToolElicitationDefinition(tool, ctx) {
363
+ if (!isRecord(tool)) {
364
+ ctx.addIssue({
365
+ code: "custom",
366
+ message: "Runtime tool definition must be an object"
367
+ });
368
+ return;
369
+ }
370
+ const config = isRecord(tool.config) ? tool.config : void 0;
371
+ if (config?.elicit === void 0) return;
372
+ const issue = (message) => {
373
+ ctx.addIssue({
374
+ code: "custom",
375
+ path: ["config", "elicit"],
376
+ message
377
+ });
378
+ };
379
+ if (tool.toolType !== "external" && tool.toolType !== "custom") {
380
+ issue("Authored input is supported only on external and custom tools");
381
+ return;
382
+ }
383
+ const parsed = toolElicitationConfigSchema.safeParse(config.elicit);
384
+ if (!parsed.success) {
385
+ for (const error of parsed.error.issues) ctx.addIssue({
386
+ ...error,
387
+ path: [
388
+ "config",
389
+ "elicit",
390
+ ...error.path
391
+ ]
392
+ });
393
+ return;
394
+ }
395
+ const final = tool.parametersSchema;
396
+ const allowedRootKeys = /* @__PURE__ */ new Set([
397
+ "type",
398
+ "title",
399
+ "description",
400
+ "properties",
401
+ "required",
402
+ "additionalProperties"
403
+ ]);
404
+ if (!isSupportedElicitationSchema(final) || !isRecord(final) || final.type !== "object" || final.additionalProperties !== false || !isRecord(final.properties) || Object.keys(final).some((key) => !allowedRootKeys.has(key))) {
405
+ issue("Final parametersSchema must be a closed, projectable object without cross-field constraints");
406
+ return;
407
+ }
408
+ const requested = parsed.data.requestedSchema;
409
+ const names = Object.keys(requested.properties);
410
+ const required = requested.required ?? [];
411
+ const finalRequired = Array.isArray(final.required) ? final.required : [];
412
+ if (!names.length || required.some((name) => !names.includes(name)) || new Set(required).size !== required.length || finalRequired.some((name) => typeof name !== "string" || !Object.prototype.hasOwnProperty.call(final.properties, name))) issue("Requested properties and required fields must be nonempty and well formed");
413
+ for (const name of names) {
414
+ if (name.startsWith("_") || [
415
+ "constructor",
416
+ "prototype",
417
+ "__proto__"
418
+ ].includes(name) || tool.hiddenParameterNames?.includes(name)) issue(`Human-owned property is reserved or protected: ${name}`);
419
+ if (!Object.prototype.hasOwnProperty.call(final.properties, name) || canonicalToolInputDefinition(final.properties[name]) !== canonicalToolInputDefinition(requested.properties[name]) || finalRequired.includes(name) !== required.includes(name)) issue(`Human-owned property must match the final schema and requiredness: ${name}`);
420
+ }
421
+ }
422
+ const IDENTITY_AUDIENCE_TOOL_TYPES = /* @__PURE__ */ new Set(["external", "mcp"]);
423
+ const URL_AUTHORITY = /^\s*(https?):\/\/([^/?#]*)/i;
424
+ /** The hostname of a URL whose authority is authored literally; `undefined` when it is templated or unparseable. */
425
+ function literalUrlHost(url) {
426
+ if (typeof url !== "string") return void 0;
427
+ const match = URL_AUTHORITY.exec(url);
428
+ if (!match || match[2].includes("{{")) return void 0;
429
+ try {
430
+ return new URL(`${match[1].toLowerCase()}://${match[2]}`).hostname.toLowerCase() || void 0;
431
+ } catch {
432
+ return;
433
+ }
434
+ }
435
+ /**
436
+ * The problem with a tool's `config.identityAudiences`, the hosts its `{{_identity.token}}` may be minted
437
+ * for, or `undefined` when it is absent or valid. A literal URL host must itself be listed.
438
+ */
439
+ function toolIdentityAudiencesIssue(tool) {
440
+ const config = isRecord(tool) && isRecord(tool.config) ? tool.config : void 0;
441
+ if (config?.identityAudiences === void 0) return void 0;
442
+ if (!IDENTITY_AUDIENCE_TOOL_TYPES.has(tool.toolType)) return "identityAudiences is supported only on external and mcp tools";
443
+ const raw = config.identityAudiences;
444
+ if (!Array.isArray(raw) || raw.length === 0 || raw.length > 20) return `identityAudiences must list 1 to 20 hostnames`;
445
+ const patterns = [];
446
+ for (const entry of raw) {
447
+ const normalized = normalizeIdentityAudiencePattern(entry);
448
+ if (!normalized) return `identityAudiences entry ${JSON.stringify(entry)} must be a hostname such as "api.example.com" or a one-label wildcard such as "*.staging.example.com"`;
449
+ patterns.push(normalized);
450
+ }
451
+ const host = literalUrlHost(config.url);
452
+ if (host && !identityAudienceAllowed(host, patterns)) return `The tool URL host "${host}" is not listed in identityAudiences`;
453
+ }
454
+ /** The same check for an inline MCP server, whose discovered tools inherit its `identityAudiences`. */
455
+ function mcpServerIdentityAudiencesIssue(server) {
456
+ if (server.identityAudiences === void 0) return void 0;
457
+ return toolIdentityAudiencesIssue({
458
+ toolType: "mcp",
459
+ config: {
460
+ url: server.url,
461
+ identityAudiences: server.identityAudiences
462
+ }
463
+ });
464
+ }
465
+ /** Zod refinement form of `toolIdentityAudiencesIssue`, wired at every tool definition boundary. */
466
+ function validateToolIdentityAudiences(tool, ctx) {
467
+ const message = toolIdentityAudiencesIssue(tool);
468
+ if (message) ctx.addIssue({
469
+ code: "custom",
470
+ path: ["config", "identityAudiences"],
471
+ message
472
+ });
473
+ }
474
+ const ToolExecutionStatus = {
475
+ PENDING: "pending",
476
+ SUCCESS: "success",
477
+ FAILED: "failed",
478
+ WAITING_FOR_LOCAL: "waiting_for_local",
479
+ /** The call paused at an approval gate and has not been decided. */
480
+ AWAITING_APPROVAL: "awaiting_approval",
481
+ /** The approver declined (or the approval timed out); the tool never ran. */
482
+ DENIED: "denied"
483
+ };
484
+ ToolExecutionStatus.PENDING, ToolExecutionStatus.WAITING_FOR_LOCAL, ToolExecutionStatus.AWAITING_APPROVAL;
485
+ const MCPServerCategory = {
486
+ COMMUNICATION: "communication",
487
+ PRODUCTIVITY: "productivity",
488
+ DEVELOPMENT: "development",
489
+ PROJECT_MANAGEMENT: "project_management"
490
+ };
491
+ const subagentExecutionModeSchema = _enum(["attached", "detached"]);
492
+ const subagentNotificationModeSchema = _enum([
493
+ "none",
494
+ "narrate",
495
+ "react"
496
+ ]);
497
+ object({
498
+ /** Attached is the backwards-compatible default. */
499
+ mode: subagentExecutionModeSchema.optional(),
500
+ /** Detached tools default to `narrate`; attached tools ignore this field. */
501
+ notify: subagentNotificationModeSchema.optional(),
502
+ /** Absolute background-run wall-clock ceiling. */
503
+ maxBudgetMs: number().int().min(1e3).max(864e5).optional(),
504
+ /** Optional resetting silence budget after observable progress. */
505
+ noProgressBudgetMs: number().int().min(1e3).max(864e5).optional()
506
+ });
507
+ object({
508
+ kind: literal("subagent_run"),
509
+ runId: string(),
510
+ /**
511
+ * Which durable lane the child executes on. `'durable'` is the ADR 0020
512
+ * session DO; `'runtype'` is the in-process detached-run DO.
513
+ */
514
+ agentType: _enum([
515
+ "runtype",
516
+ "claude_managed",
517
+ "durable"
518
+ ]),
519
+ status: _enum(["queued", "running"]),
520
+ startedAt: string()
521
+ }).extend({
522
+ agentType: literal("durable"),
523
+ status: _enum(["paused", "detached"]),
524
+ awaitReason: string().optional(),
525
+ approvalId: string().optional(),
526
+ toolName: string().optional(),
527
+ /** How the child is resumed, and whether its result is delivered to the parent conversation. */
528
+ resumeHint: string()
529
+ });
530
+ /**
531
+ * Opt-in configuration for agent-driven dynamic subagent spawning (surface C).
532
+ * Setting subagentConfig synthesizes a spawn_subagent tool into the AI-SDK tool list.
533
+ * The parent's LLM picks the child's task, tool subset, and optionally systemPrompt/model,
534
+ * drawing only from toolPool.
535
+ */
536
+ const agentSubagentConfigSchema = object({
537
+ /**
538
+ * Pool of tool IDs the parent is permitted to grant to ad-hoc subagents.
539
+ * Supports exact IDs, wildcards (`mcp:*`, `builtin:*`, `platform:*`), and
540
+ * runtime-tool names. Must be a SUBSET of the parent's resolved tools —
541
+ * validated at dispatch (no privilege escalation).
542
+ */
543
+ toolPool: array(string()),
544
+ /** Accepted but not applied yet: a spawned child's turn cap comes only from the model's `maxTurns` request. */
545
+ defaultMaxTurns: number().optional(),
546
+ /** Hard cap a spawned subagent can request. Default 10. */
547
+ maxTurnsLimit: number().optional(),
548
+ /** Hard ceiling on total spawns per top-level parent invocation. Default 5. */
549
+ maxSpawnsPerRun: number().optional(),
550
+ /** Default model for spawned subagents. Defaults to parent's model. */
551
+ defaultModel: string().optional(),
552
+ /**
553
+ * Whether a spawned subagent can itself spawn subagents. Default `false`
554
+ * (Anthropic-aligned). Even when `true`, MAX_NESTED_DEPTH still bounds the
555
+ * recursion tree.
556
+ */
557
+ allowNesting: boolean().optional(),
558
+ /** Default per-spawn timeout. Default 300_000 (5 min). */
559
+ defaultTimeoutMs: number().optional(),
560
+ /** Execution modes the model may request. Default `['attached']`. */
561
+ executionModes: array(subagentExecutionModeSchema).min(1).optional(),
562
+ /** Default mode when the model omits `executionMode`. */
563
+ defaultExecutionMode: subagentExecutionModeSchema.optional(),
564
+ /** Default completion policy for detached dynamic children. */
565
+ defaultNotify: subagentNotificationModeSchema.optional(),
566
+ /** Absolute wall-clock ceiling for detached dynamic children. */
567
+ detachedMaxBudgetMs: number().int().min(1e3).max(864e5).optional(),
568
+ /** Optional resetting silence budget for detached dynamic children. */
569
+ detachedNoProgressBudgetMs: number().int().min(1e3).max(864e5).optional()
570
+ });
571
+ /**
572
+ * Configuration for the synthesized `code_mode` agent tool.
573
+ * When set on AgentToolsConfig, the prompt-step layer creates a tool that
574
+ * lets the LLM write and execute JavaScript with access to a subset of tools.
575
+ */
576
+ const codeModeConfigSchema = object({
577
+ /** Tool IDs available in the sandbox (subset of agent's tools, supports wildcards like `mcp:*`) */
578
+ toolPool: array(string()),
579
+ /** Optional custom description prefix for the synthesized tool */
580
+ description: string().optional(),
581
+ /** Sandbox execution timeout in ms (default 60000) */
582
+ timeoutMs: number().optional()
583
+ });
584
+ const toolLimitSchema = object({
585
+ maxCalls: number().optional(),
586
+ required: boolean().optional()
587
+ });
588
+ /**
589
+ * Approval configuration for human-in-the-loop tool approval.
590
+ * Lives under `tools.approval` in agent/flow configs.
591
+ */
592
+ const approvalConfigSchema = object({
593
+ /** Tools that require user approval before execution.
594
+ * string[]: tool names/patterns ("send_email", "mcp:*", "builtin:*")
595
+ * true: all tools require approval
596
+ * false/undefined: no approval required (default) */
597
+ require: union([array(string()), boolean()]).optional(),
598
+ /** Timeout in ms for approval response (default: 300000 = 5 min) */
599
+ timeout: number().optional(),
600
+ /** Messaging channels only: whether a timed-out approval posts the agent's follow-up.
601
+ * Default true. With false the run ends on timeout without resuming the agent, so nothing is sent. */
602
+ notifyUser: boolean().optional(),
603
+ /** Whether to ask the model for a per-call justification on approval-gated
604
+ * tools by injecting a reserved optional `_approvalReason` string into the
605
+ * model-visible parameters schema. The value is stripped before the tool
606
+ * executes and surfaced to the approver. Default: true (opt out with false). */
607
+ requestReason: boolean().optional(),
608
+ /**
609
+ * Who may answer the gate. `owner` (default) is authorization by the builder org;
610
+ * `end-user` lets a client-token chat visitor give consent (confirm their own order);
611
+ * never for policy or budget gates. Stamped into the pause at pause time.
612
+ */
613
+ approver: _enum(["owner", "end-user"]).optional(),
614
+ /**
615
+ * Persistent "always" choices at the human approval prompt; user-facing options, not auto-behavior.
616
+ * Keys mirror the grant decision enum (alwaysAllow -> 'allow', alwaysDeny -> 'deny').
617
+ * Default: both off; this is the sole control for persisted approval grants (no Flagship flag).
618
+ * See docs/features/planning/2026-06-13-cross-session-always-allow-approval-grants.md
619
+ */
620
+ choices: object({
621
+ alwaysAllow: boolean().optional(),
622
+ alwaysDeny: boolean().optional()
623
+ }).optional()
624
+ });
625
+ const toolSearchConfigSchema = object({
626
+ /** On by default for agents; false opts out, true forces it on below the threshold. Multi-turn runs only. */
627
+ enabled: boolean().optional(),
628
+ /** Tool count at which search activates (default: 20) */
629
+ threshold: number().optional(),
630
+ /** Tool names or IDs that should always be in the hot set */
631
+ alwaysLoaded: array(string()).optional()
632
+ });
633
+ /**
634
+ * When a durable host may run a non-idempotent server-side tool. `mandatory`: only once its
635
+ * intent is committed; a refused intent answers `TOOL_INTENT_NOT_COMMITTED` and never runs it.
636
+ * `best-effort` (the default): the intent write never blocks the call.
637
+ */
638
+ const toolIntentPolicySchema = _enum(["mandatory", "best-effort"]);
639
+ /**
640
+ * Unified tool configuration used by both agents and flow steps; the canonical source of truth.
641
+ * AgentToolsConfig is z.infer'd from this; fpo-schema.ts, runtime/schemas.ts, and skill-manifest-types.ts are documented projections.
642
+ * Distinct from the simpler ToolsConfig in client-types.ts (client SDK requests).
643
+ * runtimeTools/mcpServers use z.custom<T>() so structural validation stays deferred to validateRuntimeTools.
644
+ */
645
+ const agentToolsConfigSchema = object({
646
+ /** IDs of tools to enable (builtin:*, mcp:*, platform:*, platform:orthogonal:*, custom tool IDs) */
647
+ toolIds: array(string()).optional(),
648
+ /** Per-tool parameter configurations, keyed by tool ID */
649
+ toolConfigs: record(string(), custom()).optional(),
650
+ /** Inline tool definitions (no DB storage needed) */
651
+ runtimeTools: array(custom().superRefine(validateToolHttpDestination).superRefine(validateToolElicitationDefinition).superRefine(validateToolIdentityAudiences)).optional(),
652
+ /** Runtime MCP server connections */
653
+ mcpServers: array(custom()).optional(),
654
+ /** Maximum tool calls per execution (renamed from maxTurns in agents) */
655
+ maxToolCalls: number().optional(),
656
+ /** Tool calling strategy */
657
+ toolCallStrategy: _enum([
658
+ "auto",
659
+ "required",
660
+ "none"
661
+ ]).optional(),
662
+ /** Per-tool call limits */
663
+ perToolLimits: record(string(), toolLimitSchema).optional(),
664
+ /** Human-in-the-loop approval configuration */
665
+ approval: approvalConfigSchema.optional(),
666
+ /**
667
+ * Opt-in: enables agent-driven dynamic subagent spawning. When set, the
668
+ * prompt-step tool-prep layer synthesizes a `spawn_subagent` tool into the
669
+ * AI-SDK tool list with a dynamically-generated description listing the
670
+ * tools the parent's LLM can grant. See `AgentSubagentConfig` for fields.
671
+ */
672
+ subagentConfig: agentSubagentConfigSchema.optional(),
673
+ /**
674
+ * Opt-in: enables a synthesized `code_mode` tool that lets agents execute
675
+ * JavaScript code in a sandboxed V8 isolate with access to a subset of
676
+ * the agent's tools. The LLM writes code that calls tool functions
677
+ * deterministically instead of making individual tool calls.
678
+ */
679
+ codeModeConfig: codeModeConfigSchema.optional(),
680
+ /**
681
+ * Tool search configuration; when total tool count exceeds the threshold, deferred loading activates.
682
+ * Only a hot set of tools is sent to the model each turn; tool_search lets it discover more on demand.
683
+ * On by default for agents: activates on a multi-turn run once the tool count reaches 20, even when omitted.
684
+ * Set enabled: false to force all tools to be sent regardless of count.
685
+ */
686
+ toolSearch: toolSearchConfigSchema.optional(),
687
+ /** Intent policy for non-idempotent server-side tools on a durable host; default `best-effort`. */
688
+ intent: toolIntentPolicySchema.optional()
689
+ });
690
+ const CreateToolSchema = object({
691
+ name: string().min(1).max(100),
692
+ description: string().min(1).max(500),
693
+ toolType: _enum([
694
+ "flow",
695
+ "custom",
696
+ "external",
697
+ "graphql",
698
+ "mcp",
699
+ "local",
700
+ "subagent"
701
+ ]),
702
+ parametersSchema: record(string(), any()),
703
+ config: record(string(), any())
704
+ }).superRefine(validateToolElicitationDefinition).superRefine(validateToolIdentityAudiences);
705
+ object({
706
+ toolId: string().optional(),
707
+ parameters: record(string(), any()),
708
+ toolConfig: record(string(), unknown()).optional().describe("Built-in tools only: the instance config an agent's toolConfigs entry would carry, validated against the tool's configSchema. Rejected for a saved tool."),
709
+ context: object({
710
+ flowExecutionId: string().optional(),
711
+ stepId: string().optional(),
712
+ userId: string()
713
+ }).optional()
714
+ });
715
+ /**
716
+ * Parse a tool instance ID into its base ID and instance ID
717
+ * @param toolId - Tool ID that may include instance suffix (e.g., "builtin:vector-search#abc123")
718
+ * @returns Object with baseId (e.g., "builtin:vector-search") and instanceId (e.g., "abc123")
719
+ */
720
+ function parseToolInstanceId(toolId) {
721
+ const hashIndex = toolId.indexOf("#");
722
+ if (hashIndex === -1) return {
723
+ baseId: toolId,
724
+ instanceId: ""
725
+ };
726
+ return {
727
+ baseId: toolId.substring(0, hashIndex),
728
+ instanceId: toolId.substring(hashIndex + 1)
729
+ };
730
+ }
731
+ /**
732
+ * Check if a tool ID represents a built-in tool
733
+ */
734
+ function isBuiltInToolId(toolId) {
735
+ return toolId.startsWith("builtin:");
736
+ }
737
+ /**
738
+ * Check if a tool ID represents a platform integration tool
739
+ */
740
+ function isPlatformToolId(toolId) {
741
+ return toolId.startsWith("platform:");
742
+ }
743
+ /**
744
+ * Check if a tool ID represents a built-in integration tool (Slack, GitHub, etc.)
745
+ * Format: builtin:serverId:toolName (e.g., builtin:slack:send_message)
746
+ * This is a 3-part builtin ID, distinct from 2-part builtin IDs like builtin:gpt-image-2
747
+ * Note: Tool instance IDs like builtin:vector-search#abc123 are NOT integration tools
748
+ */
749
+ const INTEGRATION_SERVER_IDS = /* @__PURE__ */ new Set([
750
+ "slack",
751
+ "google",
752
+ "linear",
753
+ "github",
754
+ "telegram",
755
+ "imessage",
756
+ "granola"
757
+ ]);
758
+ function isBuiltInIntegrationToolId(toolId) {
759
+ if (!toolId.startsWith("builtin:")) return false;
760
+ const { baseId } = parseToolInstanceId(toolId);
761
+ const parts = baseId.split(":");
762
+ if (parts.length < 3) return false;
763
+ return INTEGRATION_SERVER_IDS.has(parts[1]);
764
+ }
765
+ /**
766
+ * Check if a tool ID represents an MCP tool (custom MCP servers only)
767
+ * Format: mcp:serverId:toolName (e.g., mcp:custom_myserver:toolname)
768
+ */
769
+ function isMCPToolId(toolId) {
770
+ return toolId.startsWith("mcp:");
771
+ }
772
+ /**
773
+ * Check if a string is a name-based saved-tool reference (`tool:<name>`).
774
+ */
775
+ function isNamedToolRef(toolId) {
776
+ return toolId.startsWith("tool:") && toolId.length > 5;
777
+ }
778
+ /**
779
+ * Parse a tool:<name> reference into its name, splitting on the first colon only.
780
+ * The remainder is the tool name verbatim since names may contain colons, spaces, any varchar content.
781
+ * Exact, case-sensitive; no trimming. Returns null when toolId isn't a valid named tool ref.
782
+ */
783
+ function parseNamedToolRef(toolId) {
784
+ if (!isNamedToolRef(toolId)) return null;
785
+ return { name: toolId.slice(5) };
786
+ }
787
+ /**
788
+ * Separate built-in, platform, integration, MCP, and custom tool IDs from a mixed array
789
+ * - builtInToolIds: 2-part IDs like builtin:gpt-image-2
790
+ * - integrationToolIds: 3-part IDs like builtin:slack:send_message
791
+ * - mcpToolIds: custom MCP server tools like mcp:custom_xxx:tool
792
+ */
793
+ function separateToolIds(toolIds) {
794
+ const builtInToolIds = [];
795
+ const platformToolIds = [];
796
+ const integrationToolIds = [];
797
+ const mcpToolIds = [];
798
+ const dataConnectionToolIds = [];
799
+ const namedToolIds = [];
800
+ const customToolIds = [];
801
+ for (const toolId of toolIds) if (isDataConnectionToolId(toolId)) dataConnectionToolIds.push(toolId);
802
+ else if (isPlatformToolId(toolId)) platformToolIds.push(toolId);
803
+ else if (isBuiltInIntegrationToolId(toolId)) integrationToolIds.push(toolId);
804
+ else if (isBuiltInToolId(toolId)) builtInToolIds.push(toolId);
805
+ else if (isMCPToolId(toolId)) mcpToolIds.push(toolId);
806
+ else if (isNamedToolRef(toolId)) namedToolIds.push(toolId);
807
+ else customToolIds.push(toolId);
808
+ return {
809
+ builtInToolIds,
810
+ platformToolIds,
811
+ integrationToolIds,
812
+ mcpToolIds,
813
+ dataConnectionToolIds,
814
+ namedToolIds,
815
+ customToolIds
816
+ };
817
+ }
818
+ /**
819
+ * Check if a tool ID represents a data connection tool
820
+ * Format: dc:{connectionId}:{action}
821
+ */
822
+ function isDataConnectionToolId(toolId) {
823
+ return toolId.startsWith("dc:");
824
+ }
825
+ export { classifyVariableReference as C, SECRET_REF_PATTERN as S, validateToolHttpDestination as _, isBuiltInIntegrationToolId as a, RESERVED_INPUT_KEY_MESSAGE as b, managedDeploymentTargetSchema as c, parseToolInstanceId as d, separateToolIds as f, validateToolElicitationDefinition as g, validateManagedDeploymentTargetConfig as h, extractSecretReferencesFromAnyValue as i, mcpServerIdentityAudiencesIssue as l, toolSearchConfigSchema as m, MCPServerCategory as n, isBuiltInToolId as o, toolIntentPolicySchema as p, agentToolsConfigSchema as r, isPlatformToolId as s, CreateToolSchema as t, parseNamedToolRef as u, validateToolIdentityAudiences as v, hasNoReservedInputKeys as w, RUNTIME_PREFIXES as x, TENANCY_ASSURANCE_LEVELS as y };
826
+