@axlsdk/axl 0.21.0 → 0.21.1

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/dist/index.js CHANGED
@@ -171,6 +171,221 @@ var ValidationError = class extends AxlError {
171
171
 
172
172
  // src/tool.ts
173
173
  var DEFAULT_MAX_STRING_LENGTH = 1e4;
174
+ var MAX_MODEL_ARGUMENT_ISSUES = 8;
175
+ var MAX_MODEL_ARGUMENT_MESSAGE_LENGTH = 2e3;
176
+ var MAX_MODEL_ARGUMENT_LINE_LENGTH = 220;
177
+ var MAX_MODEL_ARGUMENT_PATH_LENGTH = 160;
178
+ var MAX_UNION_DEPTH = 3;
179
+ var MAX_UNION_BRANCHES = 4;
180
+ var MAX_LITERAL_ALTERNATIVES = 10;
181
+ var SAFE_SCHEMA_TYPES = /* @__PURE__ */ new Set([
182
+ "string",
183
+ "number",
184
+ "boolean",
185
+ "null",
186
+ "array",
187
+ "object",
188
+ "integer"
189
+ ]);
190
+ var SAFE_STRING_FORMATS = /* @__PURE__ */ new Set([
191
+ "email",
192
+ "url",
193
+ "emoji",
194
+ "uuid",
195
+ "guid",
196
+ "nanoid",
197
+ "cuid",
198
+ "cuid2",
199
+ "ulid",
200
+ "xid",
201
+ "ksuid",
202
+ "datetime",
203
+ "date",
204
+ "time",
205
+ "duration",
206
+ "ipv4",
207
+ "ipv6",
208
+ "cidrv4",
209
+ "cidrv6",
210
+ "base64",
211
+ "base64url",
212
+ "json_string",
213
+ "e164",
214
+ "lowercase",
215
+ "uppercase",
216
+ "jwt"
217
+ ]);
218
+ function truncateModelFeedback(value, maximum) {
219
+ return value.length <= maximum ? value : `${value.slice(0, Math.max(0, maximum - 1))}\u2026`;
220
+ }
221
+ var DISPLAY_CONTROL_CHARACTERS = /[\u061C\u200B-\u200F\u202A-\u202E\u2066-\u2069\u2028\u2029]/g;
222
+ function isJsonSchema(value) {
223
+ return value !== null && typeof value === "object" && !Array.isArray(value);
224
+ }
225
+ function escapeDisplayControls(value) {
226
+ return value.replace(
227
+ DISPLAY_CONTROL_CHARACTERS,
228
+ (character) => `\\u${character.codePointAt(0).toString(16).padStart(4, "0")}`
229
+ );
230
+ }
231
+ function quoteModelText(value) {
232
+ return escapeDisplayControls(JSON.stringify(value));
233
+ }
234
+ function schemaNumber(value) {
235
+ return typeof value === "number" && Number.isFinite(value) ? String(value) : void 0;
236
+ }
237
+ function schemaLiteral(value) {
238
+ if (typeof value === "string") {
239
+ const rendered = quoteModelText(value);
240
+ return rendered.length <= 120 ? rendered : '"<literal omitted>"';
241
+ }
242
+ if (typeof value === "number") return Number.isFinite(value) ? String(value) : void 0;
243
+ if (typeof value === "boolean") return String(value);
244
+ if (value === null) return "null";
245
+ return void 0;
246
+ }
247
+ function schemaType(schema) {
248
+ const type = schema.type;
249
+ return typeof type === "string" && SAFE_SCHEMA_TYPES.has(type) ? type : void 0;
250
+ }
251
+ function compositionBranches(schema) {
252
+ const branches = [];
253
+ for (const key of ["anyOf", "oneOf", "allOf"]) {
254
+ const value = schema[key];
255
+ if (!Array.isArray(value)) continue;
256
+ for (const branch of value.slice(0, MAX_UNION_BRANCHES)) {
257
+ if (isJsonSchema(branch)) branches.push(branch);
258
+ }
259
+ }
260
+ return branches;
261
+ }
262
+ function unionBranches(schema) {
263
+ const branches = [];
264
+ for (const key of ["anyOf", "oneOf"]) {
265
+ const value = schema[key];
266
+ if (!Array.isArray(value)) continue;
267
+ for (const branch of value.slice(0, MAX_UNION_BRANCHES)) {
268
+ if (isJsonSchema(branch)) branches.push(branch);
269
+ }
270
+ }
271
+ return branches;
272
+ }
273
+ function resolvePathSegment(schema, segment, depth = 0) {
274
+ if (depth >= MAX_UNION_DEPTH) return void 0;
275
+ if (typeof segment === "string") {
276
+ const properties = schema.properties;
277
+ if (isJsonSchema(properties) && Object.hasOwn(properties, segment)) {
278
+ const child = properties[segment];
279
+ if (isJsonSchema(child)) return { node: child, renderedSegment: segment };
280
+ }
281
+ if (isJsonSchema(schema.additionalProperties)) {
282
+ return { node: schema.additionalProperties, renderedSegment: "<key>" };
283
+ }
284
+ } else if (typeof segment === "number" && Number.isSafeInteger(segment) && segment >= 0) {
285
+ const prefixItems = schema.prefixItems;
286
+ if (Array.isArray(prefixItems) && isJsonSchema(prefixItems[segment])) {
287
+ return { node: prefixItems[segment], renderedSegment: String(segment) };
288
+ }
289
+ if (isJsonSchema(schema.items)) {
290
+ return { node: schema.items, renderedSegment: "<index>" };
291
+ }
292
+ }
293
+ for (const branch of compositionBranches(schema)) {
294
+ const resolved = resolvePathSegment(branch, segment, depth + 1);
295
+ if (resolved !== void 0) return resolved;
296
+ }
297
+ return void 0;
298
+ }
299
+ function resolveSchemaPath(providerVisibleSchema, issuePath) {
300
+ if (!isJsonSchema(providerVisibleSchema)) return void 0;
301
+ let node = providerVisibleSchema;
302
+ const segments = [];
303
+ for (const segment of issuePath) {
304
+ const resolved = resolvePathSegment(node, segment);
305
+ if (resolved === void 0) {
306
+ segments.push("<path omitted>");
307
+ return { node, segments };
308
+ }
309
+ node = resolved.node;
310
+ segments.push(resolved.renderedSegment);
311
+ }
312
+ return { node, segments };
313
+ }
314
+ function jsonPointerPath(segments) {
315
+ if (segments.length === 0) return "<root>";
316
+ const pointer = `/${segments.map((segment) => segment.replaceAll("~", "~0").replaceAll("/", "~1")).join("/")}`;
317
+ const rendered = quoteModelText(pointer);
318
+ return rendered.length <= MAX_MODEL_ARGUMENT_PATH_LENGTH ? rendered : '"<path omitted>"';
319
+ }
320
+ function schemaAlternatives(schema, depth = 0) {
321
+ if (depth >= MAX_UNION_DEPTH) return [];
322
+ const constant = "const" in schema ? schemaLiteral(schema.const) : void 0;
323
+ if (constant !== void 0) return [constant];
324
+ if (Array.isArray(schema.enum)) {
325
+ const values = schema.enum.slice(0, MAX_LITERAL_ALTERNATIVES).map(schemaLiteral);
326
+ if (values.every((value) => value !== void 0)) return values;
327
+ }
328
+ const type = schemaType(schema);
329
+ if (type !== void 0) return [type];
330
+ const alternatives = unionBranches(schema).flatMap(
331
+ (branch) => schemaAlternatives(branch, depth + 1)
332
+ );
333
+ return alternatives.slice(0, MAX_LITERAL_ALTERNATIVES);
334
+ }
335
+ function schemaEnumExpectation(schema) {
336
+ if ("const" in schema) {
337
+ const constant = schemaLiteral(schema.const);
338
+ return constant === void 0 ? void 0 : `expected ${constant}`;
339
+ }
340
+ if (!Array.isArray(schema.enum)) return void 0;
341
+ const values = schema.enum.slice(0, MAX_LITERAL_ALTERNATIVES).map(schemaLiteral);
342
+ if (values.some((value) => value === void 0)) return void 0;
343
+ const rendered = values;
344
+ if (rendered.length === 0) return void 0;
345
+ const omission = schema.enum.length > rendered.length ? ", \u2026" : "";
346
+ return `expected ${rendered.length === 1 ? rendered[0] : `one of ${rendered.join(", ")}`}${omission}`;
347
+ }
348
+ function schemaTypeExpectation(schema) {
349
+ const type = schemaType(schema);
350
+ if (type !== void 0) return `expected ${type}`;
351
+ const alternatives = schemaAlternatives(schema);
352
+ return alternatives.length === 0 ? void 0 : `expected one of: ${alternatives.join(", ")}`;
353
+ }
354
+ function schemaSizeExpectation(schema, direction) {
355
+ const type = schemaType(schema);
356
+ const keyword = direction === "small" ? type === "string" ? "minLength" : type === "array" ? "minItems" : "minimum" : type === "string" ? "maxLength" : type === "array" ? "maxItems" : "maximum";
357
+ const value = schemaNumber(schema[keyword]);
358
+ if (value === void 0) return void 0;
359
+ const label = type === "string" ? "string length" : type === "array" ? "array length" : type;
360
+ if (label === void 0) return void 0;
361
+ return `expected ${label} ${direction === "small" ? "at least" : "at most"} ${value}`;
362
+ }
363
+ function schemaExpectation(schema, issueCode) {
364
+ switch (issueCode) {
365
+ case "invalid_type":
366
+ return schemaTypeExpectation(schema) ?? "failed structural validation";
367
+ case "invalid_value":
368
+ return schemaEnumExpectation(schema) ?? schemaTypeExpectation(schema) ?? "failed structural validation";
369
+ case "too_small":
370
+ return schemaSizeExpectation(schema, "small") ?? schemaTypeExpectation(schema) ?? "failed structural validation";
371
+ case "too_big":
372
+ return schemaSizeExpectation(schema, "big") ?? schemaTypeExpectation(schema) ?? "failed structural validation";
373
+ case "not_multiple_of": {
374
+ const multipleOf = schemaNumber(schema.multipleOf);
375
+ return multipleOf === void 0 ? schemaTypeExpectation(schema) ?? "failed structural validation" : `expected a multiple of ${multipleOf}`;
376
+ }
377
+ case "invalid_format": {
378
+ const format = schema.format;
379
+ return typeof format === "string" && SAFE_STRING_FORMATS.has(format) ? `expected valid ${format} format` : schemaTypeExpectation(schema) ?? "failed structural validation";
380
+ }
381
+ case "invalid_union":
382
+ return schemaTypeExpectation(schema) ?? "failed structural validation";
383
+ default: {
384
+ const typeExpectation = schemaTypeExpectation(schema);
385
+ return typeExpectation === void 0 ? "failed structural validation" : `failed structural validation; ${typeExpectation}`;
386
+ }
387
+ }
388
+ }
174
389
  var ToolStringLengthError = class extends Error {
175
390
  constructor(path, actual, maximum) {
176
391
  const renderedPath = path.reduce(
@@ -186,6 +401,42 @@ var ToolStringLengthError = class extends Error {
186
401
  this.name = "ToolStringLengthError";
187
402
  }
188
403
  };
404
+ function toolArgumentModelMessage(error, providerVisibleSchema) {
405
+ try {
406
+ let lines;
407
+ let omitted = false;
408
+ if (error instanceof ZodError) {
409
+ if (error.issues.length === 0) return void 0;
410
+ lines = [];
411
+ for (const issue of error.issues.slice(0, MAX_MODEL_ARGUMENT_ISSUES)) {
412
+ const resolved = resolveSchemaPath(providerVisibleSchema, issue.path);
413
+ if (resolved === void 0) return void 0;
414
+ const path = jsonPointerPath(resolved.segments);
415
+ const expectation = schemaExpectation(resolved.node, issue.code);
416
+ lines.push(
417
+ truncateModelFeedback(`- ${path}: ${expectation}`, MAX_MODEL_ARGUMENT_LINE_LENGTH)
418
+ );
419
+ }
420
+ omitted = error.issues.length > lines.length;
421
+ } else if (error instanceof ToolStringLengthError) {
422
+ const resolved = resolveSchemaPath(providerVisibleSchema, error.path);
423
+ const maximum = schemaNumber(error.maximum);
424
+ if (resolved === void 0 || maximum === void 0) return void 0;
425
+ const path = jsonPointerPath(resolved.segments);
426
+ lines = [`- ${path}: maximum string length is ${maximum}`];
427
+ } else {
428
+ return void 0;
429
+ }
430
+ const header = "Error: Invalid tool arguments:";
431
+ const footer = "Correct the arguments and try again.";
432
+ const omission = omitted ? "Additional validation issues were omitted." : void 0;
433
+ const parts = [header, ...lines, ...omission ? [omission] : [], footer];
434
+ const message = parts.join("\n");
435
+ return message.length <= MAX_MODEL_ARGUMENT_MESSAGE_LENGTH ? message : void 0;
436
+ } catch {
437
+ return void 0;
438
+ }
439
+ }
189
440
  function validateStringLengths(value, maxLen, path = []) {
190
441
  if (typeof value === "string") {
191
442
  if (value.length > maxLen) {
@@ -6330,7 +6581,15 @@ function cloneToolArguments(value) {
6330
6581
  }
6331
6582
  }
6332
6583
  function parseToolInvocation(options) {
6333
- const { toolCall, configuredTool, override, mcpCall, mcpTraceName, availableTools } = options;
6584
+ const {
6585
+ toolCall,
6586
+ configuredTool,
6587
+ override,
6588
+ mcpCall,
6589
+ mcpTraceName,
6590
+ availableTools,
6591
+ providerVisibleSchema
6592
+ } = options;
6334
6593
  const requestedTool = toolCall.function.name;
6335
6594
  if (!override && !configuredTool && !mcpCall) {
6336
6595
  return {
@@ -6390,7 +6649,7 @@ function parseToolInvocation(options) {
6390
6649
  args: parsedArguments,
6391
6650
  issues: toolArgumentIssues(error)
6392
6651
  },
6393
- modelMessage: INVALID_ARGUMENTS_MODEL_MESSAGE
6652
+ modelMessage: toolArgumentModelMessage(error, providerVisibleSchema) ?? INVALID_ARGUMENTS_MODEL_MESSAGE
6394
6653
  };
6395
6654
  }
6396
6655
  }
@@ -7293,7 +7552,7 @@ var WorkflowContext = class _WorkflowContext {
7293
7552
  /** Resolve, execute, and observe one non-handoff tool request. Rejections
7294
7553
  * never start. Every accepted request emits one terminal event before a
7295
7554
  * continuation message or abort escapes this coordinator. */
7296
- async observeToolInvocation(agent2, toolCall, currentMessages, availableTools) {
7555
+ async observeToolInvocation(agent2, toolCall, currentMessages, toolDefs) {
7297
7556
  const signal = this.currentSignal;
7298
7557
  signal?.throwIfAborted();
7299
7558
  const requestedTool = toolCall.function.name;
@@ -7303,6 +7562,7 @@ var WorkflowContext = class _WorkflowContext {
7303
7562
  const override = this.toolOverrides?.get(requestedTool);
7304
7563
  const mcpManager = this.mcpManager;
7305
7564
  const mcpMatch = !configuredTool ? mcpManager?.getToolsForAgent(agent2._config.mcp, agent2._config.mcpTools).find(({ tool: tool2 }) => tool2.name === requestedTool) : void 0;
7565
+ const providerVisibleSchema = toolDefs.find((tool2) => tool2.function.name === requestedTool)?.function.parameters;
7306
7566
  const parsed = parseToolInvocation({
7307
7567
  toolCall,
7308
7568
  configuredTool,
@@ -7311,7 +7571,8 @@ var WorkflowContext = class _WorkflowContext {
7311
7571
  mcpCall: (args) => mcpManager.callTool(requestedTool, args, mcpMatch.server),
7312
7572
  mcpTraceName: `${mcpMatch.server}:${requestedTool}`
7313
7573
  } : {},
7314
- availableTools
7574
+ availableTools: toolDefs.map((tool2) => tool2.function.name),
7575
+ ...configuredTool ? { providerVisibleSchema } : {}
7315
7576
  });
7316
7577
  signal?.throwIfAborted();
7317
7578
  if ("kind" in parsed) {
@@ -8122,12 +8383,7 @@ ${appendedSchemaText}`;
8122
8383
  return await handoffFn();
8123
8384
  }
8124
8385
  }
8125
- await this.observeToolInvocation(
8126
- agent2,
8127
- toolCall,
8128
- currentMessages,
8129
- toolDefs.map((tool2) => tool2.function.name)
8130
- );
8386
+ await this.observeToolInvocation(agent2, toolCall, currentMessages, toolDefs);
8131
8387
  }
8132
8388
  continue;
8133
8389
  }