@axlsdk/axl 0.7.6 → 0.9.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/dist/index.js CHANGED
@@ -1922,7 +1922,7 @@ var defaultRegistry = new ProviderRegistry();
1922
1922
 
1923
1923
  // src/context.ts
1924
1924
  import { AsyncLocalStorage } from "async_hooks";
1925
- import { ZodError } from "zod";
1925
+ import { z, ZodError } from "zod";
1926
1926
 
1927
1927
  // src/errors.ts
1928
1928
  var AxlError = class extends Error {
@@ -1998,6 +1998,18 @@ var GuardrailError = class extends AxlError {
1998
1998
  this.reason = reason;
1999
1999
  }
2000
2000
  };
2001
+ var ValidationError = class extends AxlError {
2002
+ lastOutput;
2003
+ reason;
2004
+ retries;
2005
+ constructor(lastOutput, reason, retries) {
2006
+ super("VALIDATION_ERROR", `Validation failed after ${retries} retries: ${reason}`);
2007
+ this.name = "ValidationError";
2008
+ this.lastOutput = lastOutput;
2009
+ this.reason = reason;
2010
+ this.retries = retries;
2011
+ }
2012
+ };
2001
2013
  var ToolDenied = class extends AxlError {
2002
2014
  toolName;
2003
2015
  agentName;
@@ -2090,48 +2102,9 @@ function resolveConfig(config) {
2090
2102
  // src/context.ts
2091
2103
  var signalStorage = new AsyncLocalStorage();
2092
2104
  function zodToJsonSchema(schema) {
2093
- const def = schema._def;
2094
- if (!def || !def.typeName) return {};
2095
- switch (def.typeName) {
2096
- case "ZodString":
2097
- return { type: "string" };
2098
- case "ZodNumber":
2099
- return { type: "number" };
2100
- case "ZodBoolean":
2101
- return { type: "boolean" };
2102
- case "ZodArray":
2103
- return { type: "array", items: zodToJsonSchema(def.type) };
2104
- case "ZodObject": {
2105
- const shape = def.shape?.() ?? {};
2106
- const properties = {};
2107
- const required = [];
2108
- for (const [key, value] of Object.entries(shape)) {
2109
- properties[key] = zodToJsonSchema(value);
2110
- const innerDef = value._def;
2111
- if (innerDef?.typeName !== "ZodOptional" && innerDef?.typeName !== "ZodDefault") {
2112
- required.push(key);
2113
- }
2114
- }
2115
- return { type: "object", properties, required: required.length > 0 ? required : void 0 };
2116
- }
2117
- case "ZodOptional":
2118
- return zodToJsonSchema(def.innerType);
2119
- case "ZodDefault":
2120
- return zodToJsonSchema(def.innerType);
2121
- case "ZodEnum":
2122
- return { type: "string", enum: def.values };
2123
- case "ZodLiteral": {
2124
- const v = def.value;
2125
- const t = v === null ? "null" : typeof v;
2126
- return { type: t, const: v };
2127
- }
2128
- case "ZodUnion":
2129
- return { oneOf: def.options.map((o) => zodToJsonSchema(o)) };
2130
- case "ZodNullable":
2131
- return { ...zodToJsonSchema(def.innerType), nullable: true };
2132
- default:
2133
- return {};
2134
- }
2105
+ const result = z.toJSONSchema(schema, { unrepresentable: "any" });
2106
+ delete result.$schema;
2107
+ return result;
2135
2108
  }
2136
2109
  function estimateTokens(text) {
2137
2110
  return Math.ceil(text.length / 4);
@@ -2262,9 +2235,6 @@ var WorkflowContext = class _WorkflowContext {
2262
2235
  agent2,
2263
2236
  prompt,
2264
2237
  options,
2265
- 0,
2266
- void 0,
2267
- void 0,
2268
2238
  void 0,
2269
2239
  usageCapture
2270
2240
  );
@@ -2314,7 +2284,7 @@ var WorkflowContext = class _WorkflowContext {
2314
2284
  return result;
2315
2285
  });
2316
2286
  }
2317
- async executeAgentCall(agent2, prompt, options, retryCount = 0, previousOutput, previousError, handoffMessages, usageCapture) {
2287
+ async executeAgentCall(agent2, prompt, options, handoffMessages, usageCapture) {
2318
2288
  if (this.budgetContext?.exceeded) {
2319
2289
  const { limit, totalCost: spent, policy } = this.budgetContext;
2320
2290
  if (policy === "warn") {
@@ -2386,16 +2356,6 @@ var WorkflowContext = class _WorkflowContext {
2386
2356
 
2387
2357
  Respond with valid JSON matching this schema:
2388
2358
  ${JSON.stringify(jsonSchema, null, 2)}`;
2389
- }
2390
- if (previousOutput && previousError) {
2391
- userContent += `
2392
-
2393
- Your previous response was invalid:
2394
- ${previousOutput}
2395
-
2396
- Error: ${previousError}
2397
-
2398
- Please fix and try again.`;
2399
2359
  }
2400
2360
  messages.push({ role: "user", content: userContent });
2401
2361
  if (handoffMessages && handoffMessages.length > 0) {
@@ -2440,9 +2400,17 @@ Please fix and try again.`;
2440
2400
  const maxTurns = agent2._config.maxTurns ?? 25;
2441
2401
  const timeoutMs = parseDuration(agent2._config.timeout ?? "60s");
2442
2402
  const startTime = Date.now();
2403
+ if (this.onToken && options?.validate) {
2404
+ throw new AxlError(
2405
+ "INVALID_CONFIG",
2406
+ "Cannot use validate with streaming. Validate requires schema (JSON output) which does not benefit from token streaming. Use a non-streaming call instead."
2407
+ );
2408
+ }
2443
2409
  const currentMessages = [...messages];
2444
2410
  let turns = 0;
2445
2411
  let guardrailOutputRetries = 0;
2412
+ let schemaRetries = 0;
2413
+ let validateRetries = 0;
2446
2414
  while (turns < maxTurns) {
2447
2415
  if (Date.now() - startTime > timeoutMs) {
2448
2416
  throw new TimeoutError("ctx.ask()", timeoutMs);
@@ -2570,14 +2538,17 @@ Please fix and try again.`;
2570
2538
  }
2571
2539
  }
2572
2540
  const handoffStart = Date.now();
2573
- const handoffOptions = options ? { schema: options.schema, retries: options.retries, metadata: options.metadata } : void 0;
2541
+ const handoffOptions = options ? {
2542
+ schema: options.schema,
2543
+ retries: options.retries,
2544
+ metadata: options.metadata,
2545
+ validate: options.validate,
2546
+ validateRetries: options.validateRetries
2547
+ } : void 0;
2574
2548
  const handoffFn = () => this.executeAgentCall(
2575
2549
  descriptor.agent,
2576
2550
  handoffPrompt,
2577
2551
  handoffOptions,
2578
- 0,
2579
- void 0,
2580
- void 0,
2581
2552
  currentMessages,
2582
2553
  usageCapture
2583
2554
  );
@@ -2911,26 +2882,26 @@ Please fix and try again.`;
2911
2882
  throw new GuardrailError("output", outputResult.reason ?? "Output blocked by guardrail");
2912
2883
  }
2913
2884
  }
2885
+ let validated = void 0;
2914
2886
  if (options?.schema) {
2915
2887
  try {
2916
2888
  const parsed = JSON.parse(stripMarkdownFences(content));
2917
- const validated = options.schema.parse(parsed);
2918
- this.pushAssistantToSessionHistory(content, response.providerMetadata);
2919
- return validated;
2889
+ validated = options.schema.parse(parsed);
2920
2890
  } catch (err) {
2921
- const maxRetries = options.retries ?? 3;
2922
- if (retryCount < maxRetries) {
2891
+ const maxSchemaRetries = options.retries ?? 3;
2892
+ if (schemaRetries < maxSchemaRetries) {
2893
+ schemaRetries++;
2923
2894
  const errorMsg = err instanceof Error ? err.message : String(err);
2924
- return this.executeAgentCall(
2925
- agent2,
2926
- prompt,
2927
- options,
2928
- retryCount + 1,
2895
+ currentMessages.push({
2896
+ role: "assistant",
2929
2897
  content,
2930
- errorMsg,
2931
- void 0,
2932
- usageCapture
2933
- );
2898
+ ...response.providerMetadata ? { providerMetadata: response.providerMetadata } : {}
2899
+ });
2900
+ currentMessages.push({
2901
+ role: "system",
2902
+ content: `Your response was not valid JSON or did not match the required schema: ${errorMsg}. Please fix and try again.`
2903
+ });
2904
+ continue;
2934
2905
  }
2935
2906
  const zodErr = err instanceof ZodError ? err : new ZodError([
2936
2907
  {
@@ -2939,11 +2910,55 @@ Please fix and try again.`;
2939
2910
  message: err instanceof Error ? err.message : String(err)
2940
2911
  }
2941
2912
  ]);
2942
- throw new VerifyError(content, zodErr, maxRetries);
2913
+ throw new VerifyError(content, zodErr, maxSchemaRetries);
2914
+ }
2915
+ }
2916
+ if (options?.schema && options.validate) {
2917
+ let validateResult;
2918
+ try {
2919
+ validateResult = await options.validate(validated, {
2920
+ metadata: this.metadata
2921
+ });
2922
+ } catch (err) {
2923
+ const reason = err instanceof Error ? err.message : String(err);
2924
+ validateResult = { valid: false, reason: `Validator error: ${reason}` };
2925
+ }
2926
+ this.emitTrace({
2927
+ type: "validate",
2928
+ agent: agent2._name,
2929
+ data: {
2930
+ valid: validateResult.valid,
2931
+ ...validateResult.reason ? { reason: validateResult.reason } : {}
2932
+ }
2933
+ });
2934
+ this.spanManager?.addEventToActiveSpan("axl.validate.check", {
2935
+ "axl.validate.valid": validateResult.valid,
2936
+ ...validateResult.reason ? { "axl.validate.reason": validateResult.reason } : {}
2937
+ });
2938
+ if (!validateResult.valid) {
2939
+ const maxValidateRetries = options.validateRetries ?? 2;
2940
+ if (validateRetries < maxValidateRetries) {
2941
+ validateRetries++;
2942
+ currentMessages.push({
2943
+ role: "assistant",
2944
+ content,
2945
+ ...response.providerMetadata ? { providerMetadata: response.providerMetadata } : {}
2946
+ });
2947
+ currentMessages.push({
2948
+ role: "system",
2949
+ content: `Your response parsed correctly but failed validation: ${validateResult.reason ?? "Validation failed"}. Previous attempts are visible above. Please fix and try again.`
2950
+ });
2951
+ continue;
2952
+ }
2953
+ throw new ValidationError(
2954
+ validated,
2955
+ validateResult.reason ?? "Validation failed",
2956
+ maxValidateRetries
2957
+ );
2943
2958
  }
2944
2959
  }
2945
2960
  this.pushAssistantToSessionHistory(content, response.providerMetadata);
2946
- return content;
2961
+ return validated ?? content;
2947
2962
  }
2948
2963
  throw new MaxTurnsError("ctx.ask()", maxTurns);
2949
2964
  }
@@ -3300,32 +3315,57 @@ ${summaryResponse.content}`
3300
3315
  // ── ctx.verify() ──────────────────────────────────────────────────────
3301
3316
  async verify(fn, schema, options) {
3302
3317
  const maxRetries = options?.retries ?? 3;
3303
- let lastOutput = void 0;
3304
- let lastErrorMessage = void 0;
3318
+ let lastRetry = void 0;
3305
3319
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
3306
- let result;
3320
+ let rawOutput;
3307
3321
  try {
3308
- result = await fn(lastOutput, lastErrorMessage);
3309
- lastOutput = result;
3310
- return schema.parse(result);
3322
+ const result = await fn(lastRetry);
3323
+ rawOutput = result;
3324
+ const parsed = schema.parse(result);
3325
+ if (options?.validate) {
3326
+ let validateResult;
3327
+ try {
3328
+ validateResult = await options.validate(parsed, { metadata: this.metadata });
3329
+ } catch (err) {
3330
+ const reason = err instanceof Error ? err.message : String(err);
3331
+ validateResult = { valid: false, reason: `Validator error: ${reason}` };
3332
+ }
3333
+ if (!validateResult.valid) {
3334
+ const errorMsg = validateResult.reason ?? "Validation failed";
3335
+ lastRetry = { error: errorMsg, output: rawOutput, parsed };
3336
+ if (attempt === maxRetries) {
3337
+ if (options?.fallback !== void 0) return options.fallback;
3338
+ throw new ValidationError(parsed, errorMsg, maxRetries);
3339
+ }
3340
+ continue;
3341
+ }
3342
+ }
3343
+ return parsed;
3311
3344
  } catch (err) {
3312
- if (err instanceof ZodError) {
3313
- lastErrorMessage = err.message;
3314
- } else if (err instanceof Error) {
3315
- lastErrorMessage = err.message;
3316
- } else {
3317
- lastErrorMessage = String(err);
3345
+ if (err instanceof ValidationError) {
3346
+ lastRetry = {
3347
+ error: err.reason,
3348
+ output: rawOutput,
3349
+ parsed: err.lastOutput
3350
+ };
3351
+ if (attempt === maxRetries) {
3352
+ if (options?.fallback !== void 0) return options.fallback;
3353
+ throw err;
3354
+ }
3355
+ continue;
3318
3356
  }
3357
+ const errorMsg = err instanceof ZodError ? err.message : err instanceof Error ? err.message : String(err);
3358
+ lastRetry = { error: errorMsg, output: rawOutput };
3319
3359
  if (attempt === maxRetries) {
3320
3360
  if (options?.fallback !== void 0) return options.fallback;
3321
- const zodErr = err instanceof ZodError ? err : new ZodError([{ code: "custom", path: [], message: lastErrorMessage }]);
3322
- throw new VerifyError(lastOutput, zodErr, maxRetries);
3361
+ const zodErr = err instanceof ZodError ? err : new ZodError([{ code: "custom", path: [], message: errorMsg }]);
3362
+ throw new VerifyError(rawOutput, zodErr, maxRetries);
3323
3363
  }
3324
3364
  }
3325
3365
  }
3326
3366
  if (options?.fallback !== void 0) return options.fallback;
3327
3367
  throw new VerifyError(
3328
- lastOutput,
3368
+ lastRetry?.output,
3329
3369
  new ZodError([{ code: "custom", path: [], message: "Verify failed" }]),
3330
3370
  maxRetries
3331
3371
  );
@@ -3427,7 +3467,7 @@ ${summaryResponse.content}`
3427
3467
  let remaining = fns.length;
3428
3468
  for (const fn of fns) {
3429
3469
  const p = signalStorage.run(composedSignal, fn);
3430
- p.then((value) => {
3470
+ p.then(async (value) => {
3431
3471
  if (settled) return;
3432
3472
  if (schema) {
3433
3473
  const parsed = schema.safeParse(value);
@@ -3440,6 +3480,33 @@ ${summaryResponse.content}`
3440
3480
  }
3441
3481
  return;
3442
3482
  }
3483
+ if (options?.validate) {
3484
+ try {
3485
+ const validateResult = await options.validate(parsed.data, {
3486
+ metadata: this.metadata
3487
+ });
3488
+ if (!validateResult.valid) {
3489
+ remaining--;
3490
+ lastError = new Error(
3491
+ `Validation failed: ${validateResult.reason ?? "Validation failed"}`
3492
+ );
3493
+ if (remaining === 0 && !settled) {
3494
+ settled = true;
3495
+ reject(lastError);
3496
+ }
3497
+ return;
3498
+ }
3499
+ } catch (err) {
3500
+ remaining--;
3501
+ lastError = err instanceof Error ? err : new Error(`Validator error: ${String(err)}`);
3502
+ if (remaining === 0 && !settled) {
3503
+ settled = true;
3504
+ reject(lastError);
3505
+ }
3506
+ return;
3507
+ }
3508
+ }
3509
+ if (settled) return;
3443
3510
  settled = true;
3444
3511
  controller.abort();
3445
3512
  resolve(parsed.data);
@@ -3691,7 +3758,9 @@ ${summaryResponse.content}`
3691
3758
  return this.ask(agents[0], prompt, {
3692
3759
  schema: options?.schema,
3693
3760
  retries: options?.retries,
3694
- metadata: options?.metadata
3761
+ metadata: options?.metadata,
3762
+ validate: options?.validate,
3763
+ validateRetries: options?.validateRetries
3695
3764
  });
3696
3765
  }
3697
3766
  const resolveCtx = options?.metadata ? { metadata: { ...this.metadata, ...options.metadata } } : { metadata: this.metadata };
@@ -3732,7 +3801,9 @@ ${summaryResponse.content}`
3732
3801
  return this.ask(routerAgent, prompt, {
3733
3802
  schema: options?.schema,
3734
3803
  retries: options?.retries,
3735
- metadata: options?.metadata
3804
+ metadata: options?.metadata,
3805
+ validate: options?.validate,
3806
+ validateRetries: options?.validateRetries
3736
3807
  });
3737
3808
  }
3738
3809
  // ── Private ───────────────────────────────────────────────────────────
@@ -6012,6 +6083,7 @@ export {
6012
6083
  SqliteVectorStore,
6013
6084
  TimeoutError,
6014
6085
  ToolDenied,
6086
+ ValidationError,
6015
6087
  VerifyError,
6016
6088
  WorkflowContext,
6017
6089
  agent,