@kortyx/hooks 0.34.3 → 0.35.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/CHANGELOG.md CHANGED
@@ -5,6 +5,35 @@
5
5
  - Return recoverable, bounded model feedback for invalid named interrupt requests. Preserve strict human responses, request quotas, approval gates, and tool-loop limits.
6
6
  - Replace child execution snapshots natively while reading legacy object and single-element array snapshots.
7
7
 
8
+ ## [0.35.1](https://github.com/kortyx-io/kortyx/compare/hooks-v0.35.0...hooks-v0.35.1) (2026-10-18)
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @kortyx/telemetry-contracts bumped to 0.19.0
16
+ * @kortyx/prompts bumped to 0.2.3
17
+ * @kortyx/usage-telemetry bumped to 0.5.0
18
+
19
+ ## [0.35.0](https://github.com/kortyx-io/kortyx/compare/hooks-v0.34.3...hooks-v0.35.0) (2026-10-16)
20
+
21
+
22
+ ### Features
23
+
24
+ * **evals:** configurable deadlines and original error visibility ([#354](https://github.com/kortyx-io/kortyx/issues/354)) ([7dde173](https://github.com/kortyx-io/kortyx/commit/7dde173b54eb37a2d28ff28ac342a3333e5ed902))
25
+
26
+
27
+ ### Dependencies
28
+
29
+ * The following workspace dependencies were updated
30
+ * dependencies
31
+ * @kortyx/core bumped to 0.15.0
32
+ * @kortyx/providers bumped to 0.9.4
33
+ * @kortyx/telemetry-contracts bumped to 0.18.0
34
+ * @kortyx/prompts bumped to 0.2.2
35
+ * @kortyx/usage-telemetry bumped to 0.4.0
36
+
8
37
  ## [0.34.3](https://github.com/kortyx-io/kortyx/compare/hooks-v0.34.2...hooks-v0.34.3) (2026-10-14)
9
38
 
10
39
 
package/dist/index.js CHANGED
@@ -245,7 +245,7 @@ var import_node = require("@kortyx/usage-telemetry/node");
245
245
  // package.json
246
246
  var package_default = {
247
247
  name: "@kortyx/hooks",
248
- version: "0.34.3",
248
+ version: "0.35.1",
249
249
  private: false,
250
250
  description: "Lifecycle hooks and extension points for Kortyx.",
251
251
  keywords: [
@@ -822,252 +822,17 @@ var emitStructuredData = (args) => {
822
822
  var import_node_async_hooks2 = require("async_hooks");
823
823
  var import_node_crypto3 = require("crypto");
824
824
  var import_core2 = require("@kortyx/core");
825
- var import_errors3 = require("@kortyx/core/errors");
825
+ var import_errors2 = require("@kortyx/core/errors");
826
826
 
827
827
  // src/error-diagnostics.ts
828
828
  var import_telemetry_contracts2 = require("@kortyx/telemetry-contracts");
829
829
 
830
830
  // src/diagnostic-capture.ts
831
- var import_errors2 = require("@kortyx/core/errors");
832
831
  var import_telemetry_contracts = require("@kortyx/telemetry-contracts");
833
- var encoder = new TextEncoder();
834
- var nativeStackGetter = Object.getOwnPropertyDescriptor(
835
- new Error(),
836
- "stack"
837
- )?.get;
838
- function nativeStack(object, getter) {
839
- if (!getter || getter !== nativeStackGetter)
840
- throw new Error("Custom stack accessor");
841
- for (const key of ["name", "message"]) {
842
- let cursor = object;
843
- while (cursor) {
844
- const descriptor = Object.getOwnPropertyDescriptor(cursor, key);
845
- if (descriptor) {
846
- if (!("value" in descriptor) || typeof descriptor.value !== "string")
847
- throw new Error("Custom error formatting");
848
- break;
849
- }
850
- cursor = Object.getPrototypeOf(cursor);
851
- }
852
- }
853
- const formatter = Object.getOwnPropertyDescriptor(Error, "prepareStackTrace");
854
- if (formatter && (!("value" in formatter) || !formatter.writable))
855
- throw new Error("Custom stack formatter");
856
- Object.defineProperty(Error, "prepareStackTrace", {
857
- ...formatter ?? { configurable: true, writable: true },
858
- value: void 0
859
- });
860
- try {
861
- return getter.call(object);
862
- } finally {
863
- if (formatter) Object.defineProperty(Error, "prepareStackTrace", formatter);
864
- else Reflect.deleteProperty(Error, "prepareStackTrace");
865
- }
866
- }
867
- var pointer = (key) => key.replace(/~/g, "~0").replace(/\//g, "~1");
868
- function captureDiagnosticContent(error, project) {
869
- const omissions = [];
870
- const redactions = [];
871
- const seen = /* @__PURE__ */ new WeakMap();
872
- let nodes = 0;
873
- let remaining = import_telemetry_contracts.DIAGNOSTIC_LIMITS.bytes - 64 * 1024;
874
- const omit = (path, reason, extra = {}) => {
875
- if (omissions.length < 1e3)
876
- omissions.push({ path: path.slice(0, 4096), reason, ...extra });
877
- return { $omitted: reason };
878
- };
879
- const visit = (value, path, depth) => {
880
- if (++nodes > import_telemetry_contracts.DIAGNOSTIC_LIMITS.nodes) return omit(path, "node_limit");
881
- if (depth > import_telemetry_contracts.DIAGNOSTIC_LIMITS.depth) return omit(path, "depth_limit");
882
- if (typeof value === "string") {
883
- const clean = (0, import_telemetry_contracts.redactDiagnosticText)(value);
884
- if (clean !== value && redactions.length < 1e3)
885
- redactions.push({
886
- path: path.slice(0, 4096),
887
- reason: "credential_text"
888
- });
889
- const bytes = encoder.encode(JSON.stringify(clean)).length;
890
- if (bytes > remaining)
891
- return omit(path, "byte_limit", {
892
- originalBytes: encoder.encode(value).length
893
- });
894
- remaining -= bytes;
895
- return clean;
896
- }
897
- if (value === null || typeof value === "boolean") return value;
898
- if (typeof value === "number")
899
- return Number.isFinite(value) ? value : { $type: "number", value: String(value) };
900
- if (typeof value === "bigint")
901
- return { $type: "bigint", value: value.toString() };
902
- if (typeof value === "undefined") return { $type: "undefined" };
903
- if (typeof value === "function" || typeof value === "symbol")
904
- return omit(path, `unsupported_${typeof value}`);
905
- const object = value;
906
- const reference = seen.get(object);
907
- if (reference) return { $ref: reference };
908
- seen.set(object, path);
909
- remaining -= 32;
910
- if (remaining < 0) return omit(path, "byte_limit");
911
- try {
912
- if (value instanceof Date)
913
- return { $type: "Date", value: Date.prototype.toISOString.call(value) };
914
- if (value instanceof Map || value instanceof Set) {
915
- const isMap = value instanceof Map;
916
- const iterator = isMap ? Map.prototype.entries.call(value) : Set.prototype.values.call(value);
917
- const count = Object.getOwnPropertyDescriptor(
918
- isMap ? Map.prototype : Set.prototype,
919
- "size"
920
- )?.get?.call(value);
921
- const entries = [];
922
- for (let index = 0; index < Math.min(count, import_telemetry_contracts.DIAGNOSTIC_LIMITS.properties); index++)
923
- entries.push(iterator.next().value);
924
- if (count > entries.length)
925
- omissions.push({
926
- path,
927
- reason: "collection_limit",
928
- originalCount: count
929
- });
930
- return isMap ? {
931
- $type: "Map",
932
- entries: visit(entries, `${path}/entries`, depth + 1)
933
- } : {
934
- $type: "Set",
935
- values: visit(entries, `${path}/values`, depth + 1)
936
- };
937
- }
938
- if (Array.isArray(value)) {
939
- const count = Math.min(value.length, import_telemetry_contracts.DIAGNOSTIC_LIMITS.properties);
940
- const items = Array.from(
941
- { length: count },
942
- (_, index) => read(value, String(index), `${path}/${index}`, depth)
943
- );
944
- if (count < value.length)
945
- items.push(
946
- omit(path, "collection_limit", { originalCount: value.length })
947
- );
948
- return items;
949
- }
950
- const keys = Object.getOwnPropertyNames(object);
951
- const result = /* @__PURE__ */ Object.create(null);
952
- if (value instanceof Error) {
953
- const ownName = Object.getOwnPropertyDescriptor(object, "name");
954
- let type = ownName && "value" in ownName ? ownName.value : void 0;
955
- if (typeof type !== "string") {
956
- const name = Object.getOwnPropertyDescriptor(
957
- Object.getPrototypeOf(value),
958
- "name"
959
- );
960
- type = name && "value" in name ? name.value : "Error";
961
- }
962
- result.type = visit(
963
- typeof type === "string" ? type : "Error",
964
- `${path}/type`,
965
- depth + 1
966
- );
967
- }
968
- for (const key of keys.slice(0, import_telemetry_contracts.DIAGNOSTIC_LIMITS.properties)) {
969
- if (["__proto__", "constructor", "prototype"].includes(key)) {
970
- result[key] = omit(`${path}/${pointer(key)}`, "unsafe_key");
971
- continue;
972
- }
973
- remaining -= encoder.encode(key).length + 4;
974
- result[key] = read(object, key, `${path}/${pointer(key)}`, depth);
975
- }
976
- if (keys.length > import_telemetry_contracts.DIAGNOSTIC_LIMITS.properties)
977
- result.$omittedProperties = omit(path, "property_limit", {
978
- originalCount: keys.length
979
- });
980
- return result;
981
- } catch {
982
- return omit(path, "unreadable_object");
983
- }
984
- };
985
- const read = (object, key, path, depth) => {
986
- if ((0, import_telemetry_contracts.isPrivateDiagnosticField)(key)) {
987
- if (redactions.length < 1e3)
988
- redactions.push({
989
- path: path.slice(0, 4096),
990
- reason: "credential_field"
991
- });
992
- return "[REDACTED]";
993
- }
994
- try {
995
- const property = Object.getOwnPropertyDescriptor(object, key);
996
- if (property && "value" in property)
997
- return visit(property.value, path, depth + 1);
998
- if (key === "stack" && object instanceof Error && property?.get && property.get === nativeStackGetter)
999
- return visit(nativeStack(object, property.get), path, depth + 1);
1000
- return omit(
1001
- path,
1002
- property ? "accessor_not_evaluated" : "unavailable_property"
1003
- );
1004
- } catch {
1005
- return omit(path, "unreadable_property");
1006
- }
1007
- };
1008
- try {
1009
- const original = project ? project(error) : error;
1010
- if (project && original === null) return null;
1011
- const captured = visit(original, "#/data", 0);
1012
- const upstreamOmissions = (0, import_errors2.errorProperty)(original, "diagnosticOmissions");
1013
- if (Array.isArray(upstreamOmissions))
1014
- for (const note of upstreamOmissions.slice(0, 1e3)) {
1015
- const path = (0, import_errors2.errorProperty)(note, "path");
1016
- const reason = (0, import_errors2.errorProperty)(note, "reason");
1017
- if (typeof path === "string" && typeof reason === "string")
1018
- omissions.push({
1019
- path: (0, import_telemetry_contracts.redactDiagnosticText)(path).slice(0, 4096),
1020
- reason: (0, import_telemetry_contracts.redactDiagnosticText)(reason).slice(0, 128)
1021
- });
1022
- }
1023
- const data = captured && typeof captured === "object" && !Array.isArray(captured) ? captured : {
1024
- type: "Error",
1025
- message: typeof captured === "string" ? captured : "Execution reported a fault.",
1026
- value: captured
1027
- };
1028
- if (typeof data.message !== "string" && !("message" in data))
1029
- data.message = "Execution reported a fault.";
1030
- if (!("type" in data))
1031
- data.type = typeof data.name === "string" ? data.name : "Error";
1032
- const content = {
1033
- schemaVersion: 1,
1034
- data,
1035
- capture: {
1036
- status: omissions.length ? "partial" : "complete",
1037
- omissions,
1038
- redactions
1039
- }
1040
- };
1041
- if (encoder.encode(JSON.stringify(content)).length > import_telemetry_contracts.DIAGNOSTIC_LIMITS.bytes)
1042
- return {
1043
- schemaVersion: 1,
1044
- data: {
1045
- type: "Error",
1046
- message: "Diagnostic exceeded the capture budget."
1047
- },
1048
- capture: {
1049
- status: "partial",
1050
- redactions: [],
1051
- omissions: [{ path: "#/data", reason: "serialized_byte_limit" }]
1052
- }
1053
- };
1054
- return content;
1055
- } catch {
1056
- return {
1057
- schemaVersion: 1,
1058
- data: { type: "Error", message: "Diagnostic capture failed." },
1059
- capture: {
1060
- status: "failed",
1061
- redactions: [],
1062
- omissions: [{ path: "#/data", reason: "projection_or_capture_failed" }]
1063
- }
1064
- };
1065
- }
1066
- }
1067
832
 
1068
833
  // src/error-diagnostics.ts
1069
834
  function exceptionDiagnostics(error, project) {
1070
- const content = captureDiagnosticContent(error, project);
835
+ const content = (0, import_telemetry_contracts.captureDiagnosticContent)(error, project);
1071
836
  return !content || content.capture.status === "failed" ? null : content.data;
1072
837
  }
1073
838
  function errorDiagnostics(error, project) {
@@ -1332,7 +1097,7 @@ async function executeObservedTool(args) {
1332
1097
  return result;
1333
1098
  } catch (error) {
1334
1099
  if (args.abortSignal?.aborted) observation.outcome = "cancelled";
1335
- else if (!(0, import_errors3.isControlFlowError)(error)) {
1100
+ else if (!(0, import_errors2.isControlFlowError)(error)) {
1336
1101
  const outcome = classification(
1337
1102
  args.tool,
1338
1103
  error,
@@ -1471,11 +1236,11 @@ var import_prompts = require("@kortyx/prompts");
1471
1236
  // src/reason-engine.ts
1472
1237
  var import_node_crypto4 = require("crypto");
1473
1238
  var import_core3 = require("@kortyx/core");
1474
- var import_errors4 = require("@kortyx/core/errors");
1239
+ var import_errors3 = require("@kortyx/core/errors");
1475
1240
  function assertModelFinish(result) {
1476
1241
  if (result.finishReason?.unified !== "content-filter") return;
1477
1242
  throw Object.assign(
1478
- new import_errors4.KortyxError("PROVIDER_REFUSAL", "The provider refused the request.", {
1243
+ new import_errors3.KortyxError("PROVIDER_REFUSAL", "The provider refused the request.", {
1479
1244
  category: "provider",
1480
1245
  retryable: false,
1481
1246
  safeMessage: "The provider refused the request."
@@ -2549,7 +2314,7 @@ function createStructuredOutputStreamer(args, id, opId) {
2549
2314
  }
2550
2315
 
2551
2316
  // src/reason/parsing.ts
2552
- var import_errors5 = require("@kortyx/core/errors");
2317
+ var import_errors4 = require("@kortyx/core/errors");
2553
2318
  var tryJsonParse = (value) => {
2554
2319
  try {
2555
2320
  return { ok: true, value: JSON.parse(value) };
@@ -2587,12 +2352,12 @@ var resolveOutputCandidate = (text) => {
2587
2352
  }
2588
2353
  return text;
2589
2354
  };
2590
- var createTruncatedStructuredOutputError = (label, cause) => new import_errors5.ValidationError(
2355
+ var createTruncatedStructuredOutputError = (label, cause) => new import_errors4.ValidationError(
2591
2356
  "OUTPUT_TRUNCATED",
2592
2357
  `${label} was truncated before producing valid structured output. The model stopped due to output length. Increase maxOutputTokens or simplify the requested output.`,
2593
2358
  cause
2594
2359
  );
2595
- var createInvalidStructuredOutputError = (label, cause) => new import_errors5.ValidationError(
2360
+ var createInvalidStructuredOutputError = (label, cause) => new import_errors4.ValidationError(
2596
2361
  "INVALID_MODEL_JSON",
2597
2362
  `${label} did not produce valid structured output. The model returned text instead of the expected JSON payload. Check the output contract or outputSchema and provider structured-output settings.`,
2598
2363
  cause
@@ -2604,7 +2369,7 @@ var parseReasonOutputWithSchema = (args) => {
2604
2369
  try {
2605
2370
  return parseWithSchema(args.schema, candidate, args.label);
2606
2371
  } catch (error) {
2607
- if (!(error instanceof import_errors5.ValidationError)) throw error;
2372
+ if (!(error instanceof import_errors4.ValidationError)) throw error;
2608
2373
  const failure = args.finishReason?.unified === "length" ? createTruncatedStructuredOutputError(args.label, error) : typeof candidate === "string" && !validJson ? createInvalidStructuredOutputError(args.label, error) : error;
2609
2374
  if (failure && typeof failure === "object")
2610
2375
  Object.assign(failure, {
@@ -2624,7 +2389,7 @@ var parseInterruptFirstPassResult = (args) => {
2624
2389
  if (typeof candidate === "string" && candidate.trim().length > 0) {
2625
2390
  throw createInvalidStructuredOutputError("useReason output");
2626
2391
  }
2627
- throw new import_errors5.ValidationError(
2392
+ throw new import_errors4.ValidationError(
2628
2393
  "MODEL_OUTPUT_SCHEMA",
2629
2394
  "useReason first pass with interrupt must return a JSON object."
2630
2395
  );
@@ -2633,7 +2398,7 @@ var parseInterruptFirstPassResult = (args) => {
2633
2398
  let interruptRequired = true;
2634
2399
  if (mode === "optional") {
2635
2400
  if (candidate.decision !== "continue" && candidate.decision !== "interrupt") {
2636
- throw new import_errors5.ValidationError(
2401
+ throw new import_errors4.ValidationError(
2637
2402
  "MODEL_OUTPUT_SCHEMA",
2638
2403
  'useReason optional interrupt first pass must include decision "continue" or "interrupt".'
2639
2404
  );
@@ -2646,7 +2411,7 @@ var parseInterruptFirstPassResult = (args) => {
2646
2411
  candidate.interrupt
2647
2412
  ].some((value) => value !== null && value !== void 0);
2648
2413
  if (hasUnexpectedRequest) {
2649
- throw new import_errors5.ValidationError(
2414
+ throw new import_errors4.ValidationError(
2650
2415
  "MODEL_OUTPUT_SCHEMA",
2651
2416
  'useReason optional interrupt first pass with decision "continue" must not include an interrupt request.'
2652
2417
  );
@@ -2680,7 +2445,7 @@ var parseInterruptFirstPassResult = (args) => {
2680
2445
  "useReason output"
2681
2446
  );
2682
2447
  } catch (error) {
2683
- if (!(error instanceof import_errors5.ValidationError)) throw error;
2448
+ if (!(error instanceof import_errors4.ValidationError)) throw error;
2684
2449
  if (args.finishReason?.unified === "length") {
2685
2450
  throw createTruncatedStructuredOutputError("useReason output", error);
2686
2451
  }
@@ -2689,7 +2454,7 @@ var parseInterruptFirstPassResult = (args) => {
2689
2454
  }
2690
2455
  const explicitDraft = typeof candidate.draftText === "string" && candidate.draftText.length > 0 ? candidate.draftText : typeof candidate.text === "string" && candidate.text.length > 0 ? candidate.text : void 0;
2691
2456
  if (!args.outputSchema && !explicitDraft) {
2692
- throw new import_errors5.ValidationError(
2457
+ throw new import_errors4.ValidationError(
2693
2458
  "MODEL_OUTPUT_SCHEMA",
2694
2459
  "useReason first pass with interrupt requires `draftText` when outputSchema is not provided."
2695
2460
  );
@@ -2963,7 +2728,7 @@ var emitReasonStructuredOutput = (args) => {
2963
2728
 
2964
2729
  // src/reason/tools.ts
2965
2730
  var import_core5 = require("@kortyx/core");
2966
- var import_errors6 = require("@kortyx/core/errors");
2731
+ var import_errors5 = require("@kortyx/core/errors");
2967
2732
  var import_zod5 = require("zod");
2968
2733
 
2969
2734
  // src/reason/input-feedback.ts
@@ -3203,7 +2968,7 @@ var runReasonToolLoop = async (args) => {
3203
2968
  const maxSteps = Math.max(1, useReasonArgs.toolExecution?.maxSteps ?? 3);
3204
2969
  const missingReturnCorrections = useReasonArgs.toolExecution?.missingReturnCorrections ?? 0;
3205
2970
  if (!Number.isSafeInteger(missingReturnCorrections) || missingReturnCorrections < 0)
3206
- throw new import_errors6.KortyxError(
2971
+ throw new import_errors5.KortyxError(
3207
2972
  "INVALID_REASON_CORRECTION_POLICY",
3208
2973
  "Invalid missing return correction budget.",
3209
2974
  {
@@ -3264,7 +3029,7 @@ var runReasonToolLoop = async (args) => {
3264
3029
  let outputContractCorrections = checkpoint?.outputContractCorrections ?? 0;
3265
3030
  const correctionExhausted = () => {
3266
3031
  const message = `useReason could not complete output-contract correction within toolExecution.maxSteps (${maxSteps}). Select exactly one terminal return contract; multiple emit contracts are allowed. Increase maxSteps to allow correction and output generation.`;
3267
- return new import_errors6.KortyxError(
3032
+ return new import_errors5.KortyxError(
3268
3033
  "REASON_OUTPUT_CONTRACT_CORRECTION_EXHAUSTED",
3269
3034
  message,
3270
3035
  {
@@ -3361,7 +3126,7 @@ var runReasonToolLoop = async (args) => {
3361
3126
  aggregatedWarnings = mergeWarnings(aggregatedWarnings, step.warnings);
3362
3127
  const toolCalls = step.toolCalls ?? [];
3363
3128
  if (missingReturnAttempts > 0 && toolCalls.some((call) => !outputByToolName.has(call.name)))
3364
- throw new import_errors6.KortyxError(
3129
+ throw new import_errors5.KortyxError(
3365
3130
  "REASON_OUTPUT_CORRECTION_TOOL_DISALLOWED",
3366
3131
  "A return correction requested a non-output tool.",
3367
3132
  {
@@ -3404,7 +3169,7 @@ var runReasonToolLoop = async (args) => {
3404
3169
  save();
3405
3170
  continue;
3406
3171
  }
3407
- throw new import_errors6.KortyxError(
3172
+ throw new import_errors5.KortyxError(
3408
3173
  "REASON_TERMINAL_OUTPUT_MISSING",
3409
3174
  "useReason outputs.return requires one terminal output contract call.",
3410
3175
  {
@@ -3538,7 +3303,7 @@ var runReasonToolLoop = async (args) => {
3538
3303
  );
3539
3304
  if (steps.length >= maxSteps) {
3540
3305
  const message = `useReason output generation requires another model pass within toolExecution.maxSteps (${maxSteps}). Increase maxSteps to allow outputs to use completed tool and interrupt results.`;
3541
- throw new import_errors6.ProviderRequestError(message, {
3306
+ throw new import_errors5.ProviderRequestError(message, {
3542
3307
  code: "REASON_OUTPUT_BUDGET_EXHAUSTED",
3543
3308
  operation: "useReason",
3544
3309
  safeMessage: message,
@@ -3733,7 +3498,7 @@ var runReasonToolLoop = async (args) => {
3733
3498
  `useReason interrupt contract "${resolved.name}" request`
3734
3499
  );
3735
3500
  } catch (error) {
3736
- if (!(error instanceof import_errors6.ValidationError)) throw error;
3501
+ if (!(error instanceof import_errors5.ValidationError)) throw error;
3737
3502
  const result3 = {
3738
3503
  toolCallId: toolCall.id,
3739
3504
  name: toolCall.name,
@@ -3943,12 +3708,12 @@ var runReasonToolLoop = async (args) => {
3943
3708
  }
3944
3709
  } catch (error) {
3945
3710
  (0, import_core5.throwIfExecutionAborted)(abortSignal);
3946
- if ((0, import_errors6.isControlFlowError)(error)) throw error;
3711
+ if ((0, import_errors5.isControlFlowError)(error)) throw error;
3947
3712
  const result2 = {
3948
3713
  toolCallId: toolCall.id,
3949
3714
  name: tool.name,
3950
- content: (0, import_errors6.serializeFailure)(error).message,
3951
- failure: (0, import_errors6.serializeFailure)(error),
3715
+ content: (0, import_errors5.serializeFailure)(error).message,
3716
+ failure: (0, import_errors5.serializeFailure)(error),
3952
3717
  isError: true
3953
3718
  };
3954
3719
  toolResults.push(result2);
@@ -4551,7 +4316,7 @@ function useWorkflowState(key, ...rest) {
4551
4316
 
4552
4317
  // src/parallel.ts
4553
4318
  var import_core7 = require("@kortyx/core");
4554
- var import_errors7 = require("@kortyx/core/errors");
4319
+ var import_errors6 = require("@kortyx/core/errors");
4555
4320
  var ParallelChildWaiting = class extends Error {
4556
4321
  name = "ParallelChildWaiting";
4557
4322
  };
@@ -4565,14 +4330,14 @@ var ParallelError = class extends AggregateError {
4565
4330
  );
4566
4331
  this.results = results;
4567
4332
  this.name = "ParallelError";
4568
- this.failure = (0, import_errors7.serializeFailure)({
4333
+ this.failure = (0, import_errors6.serializeFailure)({
4569
4334
  version: 1,
4570
4335
  code: this.code,
4571
4336
  category: "workflow",
4572
4337
  message: this.message,
4573
4338
  retryable: null,
4574
4339
  results: results.map(
4575
- (result) => result.status === "fulfilled" ? { status: "fulfilled" } : { status: "rejected", failure: (0, import_errors7.serializeFailure)(result.reason) }
4340
+ (result) => result.status === "fulfilled" ? { status: "fulfilled" } : { status: "rejected", failure: (0, import_errors6.serializeFailure)(result.reason) }
4576
4341
  )
4577
4342
  });
4578
4343
  }
@@ -4580,7 +4345,7 @@ var ParallelError = class extends AggregateError {
4580
4345
  code = "PARALLEL_FAILED";
4581
4346
  failure;
4582
4347
  toJSON() {
4583
- return (0, import_errors7.serializeFailure)(this);
4348
+ return (0, import_errors6.serializeFailure)(this);
4584
4349
  }
4585
4350
  };
4586
4351
  function registerWorkflowTask(id) {
@@ -4761,11 +4526,11 @@ async function usePrompt(reference, options) {
4761
4526
  // src/workflow.ts
4762
4527
  var import_node_crypto6 = require("crypto");
4763
4528
  var import_core8 = require("@kortyx/core");
4764
- var import_errors8 = require("@kortyx/core/errors");
4765
- var WorkflowCallError = class extends import_errors8.KortyxError {
4529
+ var import_errors7 = require("@kortyx/core/errors");
4530
+ var WorkflowCallError = class extends import_errors7.KortyxError {
4766
4531
  constructor(workflow, message, cause, failure) {
4767
- const detail = (0, import_errors8.serializeFailure)(
4768
- failure ?? cause ?? new import_errors8.WorkflowContractError(message)
4532
+ const detail = (0, import_errors7.serializeFailure)(
4533
+ failure ?? cause ?? new import_errors7.WorkflowContractError(message)
4769
4534
  );
4770
4535
  super(detail.code, `Workflow '${workflow}': ${message}`, {
4771
4536
  ...detail,
@@ -4786,12 +4551,12 @@ function workflowCallFingerprint(value) {
4786
4551
  if (v === null || typeof v === "string" || typeof v === "boolean") return v;
4787
4552
  if (typeof v === "number" && Number.isFinite(v)) return v;
4788
4553
  if (typeof v !== "object" || !v || seen.has(v)) {
4789
- throw new import_errors8.WorkflowContractError(
4554
+ throw new import_errors7.WorkflowContractError(
4790
4555
  "Workflow input and output must be JSON serializable."
4791
4556
  );
4792
4557
  }
4793
4558
  if (!Array.isArray(v) && Object.getPrototypeOf(v) !== Object.prototype) {
4794
- throw new import_errors8.WorkflowContractError(
4559
+ throw new import_errors7.WorkflowContractError(
4795
4560
  "Workflow input and output must contain plain JSON objects."
4796
4561
  );
4797
4562
  }
@@ -4812,7 +4577,7 @@ function createWorkflowHooks(workflows) {
4812
4577
  useWorkflow: (args) => {
4813
4578
  const workflow = workflows[args.workflow];
4814
4579
  if (!workflow || workflow.id !== args.workflow)
4815
- throw new import_errors8.WorkflowContractError(
4580
+ throw new import_errors7.WorkflowContractError(
4816
4581
  "Workflow registry keys must match definition ids."
4817
4582
  );
4818
4583
  return useWorkflow({ ...args, workflow });
@@ -4838,23 +4603,23 @@ async function runWorkflowCall(args, task) {
4838
4603
  (0, import_core8.throwIfExecutionAborted)(ctx.node.abortSignal);
4839
4604
  const service = ctx.node.callWorkflow;
4840
4605
  if (!service)
4841
- throw new import_errors8.WorkflowContractError(
4606
+ throw new import_errors7.WorkflowContractError(
4842
4607
  "useWorkflow requires an agent workflow registry."
4843
4608
  );
4844
4609
  if (!args.id.trim())
4845
- throw new import_errors8.WorkflowContractError(
4610
+ throw new import_errors7.WorkflowContractError(
4846
4611
  "useWorkflow requires a stable, nonempty id."
4847
4612
  );
4848
4613
  if (ctx.workflowCallActive && !task.group)
4849
- throw new import_errors8.WorkflowContractError(
4614
+ throw new import_errors7.WorkflowContractError(
4850
4615
  "Concurrent workflow calls require parallel([...]); otherwise await each call."
4851
4616
  );
4852
4617
  if (ctx.workflowCallIds.has(args.id))
4853
- throw new import_errors8.WorkflowContractError(
4618
+ throw new import_errors7.WorkflowContractError(
4854
4619
  `Duplicate workflow call id '${args.id}' in one node activation.`
4855
4620
  );
4856
4621
  if (ctx.workflowCallIds.size >= 64)
4857
- throw new import_errors8.WorkflowContractError(
4622
+ throw new import_errors7.WorkflowContractError(
4858
4623
  "A node may call at most 64 child workflows per activation."
4859
4624
  );
4860
4625
  ctx.workflowCallIds.add(args.id);
@@ -4935,7 +4700,7 @@ async function runWorkflowCall(args, task) {
4935
4700
  workflow,
4936
4701
  record2.error ?? "child failed",
4937
4702
  void 0,
4938
- record2.failure ?? (0, import_errors8.serializeFailure)(void 0)
4703
+ record2.failure ?? (0, import_errors7.serializeFailure)(void 0)
4939
4704
  );
4940
4705
  if (task.group && record2.status === "interrupted" && record2.interrupts.at(-1)?.response === void 0)
4941
4706
  throw new ParallelChildWaiting();
@@ -4943,7 +4708,7 @@ async function runWorkflowCall(args, task) {
4943
4708
  let outcome;
4944
4709
  try {
4945
4710
  if (Array.isArray(record2.snapshot) && record2.snapshot.length !== 1)
4946
- throw new import_errors8.WorkflowContractError("Invalid child workflow snapshot.");
4711
+ throw new import_errors7.WorkflowContractError("Invalid child workflow snapshot.");
4947
4712
  const snapshot = Array.isArray(record2.snapshot) ? record2.snapshot[0] : record2.snapshot;
4948
4713
  report(
4949
4714
  snapshot ? "resumed" : "started",
@@ -4974,7 +4739,7 @@ async function runWorkflowCall(args, task) {
4974
4739
  throw error;
4975
4740
  }
4976
4741
  record2.status = "failed";
4977
- record2.failure = (0, import_errors8.serializeFailure)(error);
4742
+ record2.failure = (0, import_errors7.serializeFailure)(error);
4978
4743
  record2.error = record2.failure.message;
4979
4744
  report("failed", { error: "Child workflow failed" });
4980
4745
  throw new WorkflowCallError(