@kortyx/agent 0.24.0 → 0.25.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
@@ -29,6 +29,448 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
29
29
  ));
30
30
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
31
 
32
+ // ../hooks/dist/internal.js
33
+ var require_internal = __commonJS({
34
+ "../hooks/dist/internal.js"(exports2, module2) {
35
+ var __defProp2 = Object.defineProperty;
36
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
37
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
38
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
39
+ var __export2 = (target, all) => {
40
+ for (var name in all)
41
+ __defProp2(target, name, { get: all[name], enumerable: true });
42
+ };
43
+ var __copyProps2 = (to, from, except, desc) => {
44
+ if (from && typeof from === "object" || typeof from === "function") {
45
+ for (let key of __getOwnPropNames2(from))
46
+ if (!__hasOwnProp2.call(to, key) && key !== except)
47
+ __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
48
+ }
49
+ return to;
50
+ };
51
+ var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
52
+ var internal_exports = {};
53
+ __export2(internal_exports, {
54
+ errorDiagnostics: () => errorDiagnostics,
55
+ isModelTraceSpan: () => isModelTraceSpan,
56
+ runReasonEngine: () => runReasonEngine,
57
+ safeSpan: () => safeSpan,
58
+ safeStartSpan: () => safeStartSpan2,
59
+ safeTelemetryMetadata: () => safeTelemetryMetadata2,
60
+ withSafeTraceSpan: () => withSafeTraceSpan2
61
+ });
62
+ module2.exports = __toCommonJS2(internal_exports);
63
+ var import_errors6 = require("@kortyx/core/errors");
64
+ function errorDiagnostics(error, project) {
65
+ try {
66
+ const name = (0, import_errors6.errorProperty)(error, "name") ?? (error instanceof Error ? error.name : void 0);
67
+ const message = (0, import_errors6.errorProperty)(error, "message");
68
+ const details = project ? project(error) : {
69
+ type: typeof name === "string" ? name : "Error",
70
+ message: typeof error === "string" ? error : typeof message === "string" ? message : "Execution reported a fault."
71
+ };
72
+ if (!details) return {};
73
+ const projectedMessage = details.message;
74
+ const projectedType = details.type;
75
+ if (typeof projectedMessage !== "string") return {};
76
+ return {
77
+ errorMessage: projectedMessage.slice(0, 8192),
78
+ ...typeof projectedType === "string" ? { errorType: projectedType.slice(0, 256) } : {}
79
+ };
80
+ } catch {
81
+ return {};
82
+ }
83
+ }
84
+ function isModelTraceSpan(name) {
85
+ return name === "runReasonEngine" || name === "useReason";
86
+ }
87
+ var import_node_crypto4 = require("crypto");
88
+ var import_core6 = require("@kortyx/core");
89
+ var import_errors22 = require("@kortyx/core/errors");
90
+ function safeSpan(span) {
91
+ const guard = (fn) => (...args) => {
92
+ try {
93
+ fn?.(...args);
94
+ } catch {
95
+ }
96
+ };
97
+ let ended = false;
98
+ const finish = (fn) => (...args) => {
99
+ if (ended) return;
100
+ ended = true;
101
+ guard(fn)(...args);
102
+ };
103
+ return {
104
+ addEvent: guard(
105
+ (name, attributes) => span?.addEvent?.(name, attributes)
106
+ ),
107
+ setAttributes: guard(
108
+ (attributes) => span?.setAttributes?.(attributes)
109
+ ),
110
+ end: finish((args) => span?.end?.(args)),
111
+ fail: finish((error, args) => {
112
+ if (span?.fail) span.fail(error, args);
113
+ else span?.end?.(args);
114
+ })
115
+ };
116
+ }
117
+ function safeStartSpan2(adapter, args) {
118
+ try {
119
+ return safeSpan(adapter?.startSpan?.(args));
120
+ } catch {
121
+ return safeSpan(void 0);
122
+ }
123
+ }
124
+ async function withSafeTraceSpan2(adapter, args, fn) {
125
+ let execution;
126
+ const invoke = (span) => {
127
+ execution ??= Promise.resolve().then(async () => {
128
+ const observed = safeSpan(span);
129
+ try {
130
+ const result = await fn(observed);
131
+ observed.end?.();
132
+ return result;
133
+ } catch (error) {
134
+ observed.fail?.(error);
135
+ throw error;
136
+ }
137
+ });
138
+ return execution;
139
+ };
140
+ let activeScope;
141
+ try {
142
+ activeScope = adapter?.withSpan?.bind(adapter);
143
+ } catch {
144
+ }
145
+ if (activeScope) {
146
+ let started;
147
+ const invoked = new Promise((resolve2) => {
148
+ started = resolve2;
149
+ });
150
+ const observe = async () => {
151
+ try {
152
+ await activeScope(args, (span) => {
153
+ const result = invoke(span);
154
+ started?.();
155
+ return result;
156
+ });
157
+ } catch {
158
+ }
159
+ };
160
+ const observation = observe();
161
+ if (!execution) await Promise.race([invoked, observation]);
162
+ } else {
163
+ await invoke(safeStartSpan2(adapter, args)).catch(() => {
164
+ });
165
+ }
166
+ return execution ?? invoke(safeSpan(void 0));
167
+ }
168
+ function assertModelFinish(result) {
169
+ if (result.finishReason?.unified !== "content-filter") return;
170
+ throw Object.assign(
171
+ new import_errors22.KortyxError("PROVIDER_REFUSAL", "The provider refused the request.", {
172
+ category: "provider",
173
+ retryable: false,
174
+ safeMessage: "The provider refused the request."
175
+ }),
176
+ {
177
+ ...result.usage ? { usage: result.usage } : {},
178
+ finishReason: result.finishReason
179
+ }
180
+ );
181
+ }
182
+ var toError = (value) => value instanceof Error ? value : new Error(String(value));
183
+ var createRuntimeId = () => {
184
+ try {
185
+ return (0, import_node_crypto4.randomUUID)();
186
+ } catch {
187
+ return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
188
+ }
189
+ };
190
+ var emitNodeEvent = (emitEvent, nodeId, event, payload) => {
191
+ if (!emitEvent) return;
192
+ emitEvent(event, {
193
+ ...payload,
194
+ ...typeof nodeId === "string" && nodeId.length > 0 ? { node: nodeId } : {}
195
+ });
196
+ };
197
+ var resolveProviderOptions = (defaults, overrides) => {
198
+ const providerOptions = defaults || overrides ? { ...defaults, ...overrides } : void 0;
199
+ for (const [key, value] of Object.entries(overrides ?? {})) {
200
+ const previous = defaults?.[key];
201
+ if (previous && value && typeof previous === "object" && typeof value === "object" && !Array.isArray(previous) && !Array.isArray(value)) {
202
+ if (providerOptions) providerOptions[key] = { ...previous, ...value };
203
+ }
204
+ }
205
+ return providerOptions;
206
+ };
207
+ async function runReasonEngine(args) {
208
+ let stream = args.stream ?? args.model.options?.streaming ?? true;
209
+ const emit = args.emit ?? true;
210
+ const temperature = args.temperature ?? args.model.options?.temperature ?? args.defaultTemperature;
211
+ const maxOutputTokens = args.maxOutputTokens ?? args.model.options?.maxOutputTokens;
212
+ const stopSequences = args.stopSequences ?? args.model.options?.stopSequences;
213
+ const abortSignal = args.abortSignal ?? args.model.options?.abortSignal;
214
+ const reasoning = args.reasoning ?? args.model.options?.reasoning;
215
+ const responseFormat = args.responseFormat ?? args.model.options?.responseFormat;
216
+ const providerOptions = resolveProviderOptions(
217
+ args.model.options?.providerOptions,
218
+ args.providerOptions
219
+ );
220
+ const tools = args.tools ?? args.model.options?.tools;
221
+ (0, import_core6.throwIfExecutionAborted)(abortSignal);
222
+ const model = args.model.provider.getModel(args.model.modelId, {
223
+ ...temperature !== void 0 ? { temperature } : {},
224
+ streaming: stream,
225
+ ...maxOutputTokens !== void 0 ? { maxOutputTokens } : {},
226
+ ...stopSequences !== void 0 ? { stopSequences } : {},
227
+ ...abortSignal !== void 0 ? { abortSignal } : {},
228
+ ...reasoning !== void 0 ? { reasoning } : {},
229
+ ...responseFormat !== void 0 ? { responseFormat } : {},
230
+ ...tools !== void 0 ? { tools } : {},
231
+ ...providerOptions !== void 0 ? { providerOptions } : {}
232
+ });
233
+ if (tools?.length && !model.supportsToolStreaming) stream = false;
234
+ const messages = args.messages !== void 0 ? args.messages : [
235
+ ...typeof args.system === "string" && args.system.length > 0 ? [{ role: "system", content: args.system }] : [],
236
+ { role: "user", content: String(args.input ?? "") }
237
+ ];
238
+ const opId = typeof args.opId === "string" && args.opId.length > 0 ? args.opId : createRuntimeId();
239
+ const segmentId = typeof args.segmentId === "string" && args.segmentId.length > 0 ? args.segmentId : createRuntimeId();
240
+ const commonMeta = {
241
+ ...typeof args.id === "string" && args.id.length > 0 ? { id: args.id } : {},
242
+ opId,
243
+ segmentId
244
+ };
245
+ const traceSpan = safeStartSpan2(args.reasonTrace, {
246
+ name: "runReasonEngine",
247
+ attributes: {
248
+ ...commonMeta,
249
+ providerId: args.model.provider.id,
250
+ modelId: args.model.modelId,
251
+ stream,
252
+ emit,
253
+ ...args.telemetry?.operation ? { operation: args.telemetry.operation } : {},
254
+ ...args.telemetry?.prompt?.name ? { promptName: args.telemetry.prompt.name } : {},
255
+ ...args.telemetry?.prompt?.version !== void 0 ? { promptVersion: args.telemetry.prompt.version } : {},
256
+ ...args.telemetry?.prompt?.type ? { promptType: args.telemetry.prompt.type } : {},
257
+ ...typeof args.nodeId === "string" && args.nodeId.length > 0 ? { nodeId: args.nodeId } : {}
258
+ },
259
+ telemetry: {
260
+ ...args.telemetry ?? {},
261
+ input: args.telemetry?.input ?? messages.map(
262
+ ({ continuation: _continuation, raw: _raw, ...message }) => message
263
+ )
264
+ }
265
+ });
266
+ const modelRequestStartedAt = Date.now();
267
+ let firstTextTokenAt;
268
+ let lastTextTokenAt;
269
+ const generationTimingAttributes = () => firstTextTokenAt === void 0 || lastTextTokenAt === void 0 ? {} : {
270
+ ttftMs: Math.max(0, firstTextTokenAt - modelRequestStartedAt),
271
+ streamDurationMs: Math.max(0, lastTextTokenAt - firstTextTokenAt),
272
+ timeToLastTokenMs: Math.max(
273
+ 0,
274
+ lastTextTokenAt - modelRequestStartedAt
275
+ )
276
+ };
277
+ const endTrace = (span, result) => {
278
+ span?.end?.({
279
+ ...result.usage !== void 0 ? { usage: result.usage } : {},
280
+ ...result.finishReason !== void 0 ? { finishReason: result.finishReason } : {},
281
+ ...result.providerMetadata !== void 0 ? { providerMetadata: result.providerMetadata } : {},
282
+ ...result.warnings !== void 0 ? { warnings: result.warnings } : {},
283
+ attributes: {
284
+ textLength: result.text.length,
285
+ ...generationTimingAttributes()
286
+ },
287
+ telemetry: {
288
+ ...args.telemetry ?? {},
289
+ output: args.telemetry?.output ?? result.text
290
+ }
291
+ });
292
+ };
293
+ const failTrace = (span, error) => {
294
+ const detail = error;
295
+ try {
296
+ span?.fail?.(error, {
297
+ ...detail?.usage ? { usage: detail.usage } : {},
298
+ ...detail?.finishReason ? { finishReason: detail.finishReason } : {},
299
+ ...detail?.providerMetadata ? { providerMetadata: detail.providerMetadata } : {},
300
+ attributes: {
301
+ providerId: args.model.provider.id,
302
+ modelId: args.model.modelId
303
+ }
304
+ });
305
+ } catch {
306
+ }
307
+ };
308
+ try {
309
+ if (stream) {
310
+ let continuation;
311
+ let final = "";
312
+ let raw;
313
+ let usage;
314
+ let finishReason;
315
+ let toolCalls;
316
+ let providerMetadata;
317
+ let warnings;
318
+ if (emit) {
319
+ emitNodeEvent(args.emitEvent, args.nodeId, "text-start", {
320
+ ...commonMeta
321
+ });
322
+ }
323
+ const response2 = await model.stream(messages);
324
+ for await (const chunk of response2) {
325
+ (0, import_core6.throwIfExecutionAborted)(abortSignal);
326
+ switch (chunk.type) {
327
+ case "text-delta": {
328
+ if (chunk.delta.length === 0) break;
329
+ const tokenAt = Date.now();
330
+ firstTextTokenAt ??= tokenAt;
331
+ lastTextTokenAt = tokenAt;
332
+ final += chunk.delta;
333
+ args.onTextChunk?.(chunk.delta);
334
+ if (chunk.raw !== void 0) {
335
+ raw = chunk.raw;
336
+ }
337
+ if (chunk.providerMetadata !== void 0) {
338
+ providerMetadata = chunk.providerMetadata;
339
+ }
340
+ if (emit) {
341
+ emitNodeEvent(args.emitEvent, args.nodeId, "text-delta", {
342
+ ...commonMeta,
343
+ delta: chunk.delta
344
+ });
345
+ }
346
+ break;
347
+ }
348
+ case "finish": {
349
+ continuation = chunk.continuation;
350
+ if (chunk.raw !== void 0) {
351
+ raw = chunk.raw;
352
+ }
353
+ if (chunk.usage !== void 0) {
354
+ usage = chunk.usage;
355
+ }
356
+ if (chunk.finishReason !== void 0) {
357
+ finishReason = chunk.finishReason;
358
+ }
359
+ if (chunk.toolCalls !== void 0) {
360
+ toolCalls = chunk.toolCalls;
361
+ }
362
+ if (chunk.providerMetadata !== void 0) {
363
+ providerMetadata = chunk.providerMetadata;
364
+ }
365
+ if (chunk.warnings !== void 0) {
366
+ warnings = chunk.warnings;
367
+ }
368
+ break;
369
+ }
370
+ case "raw": {
371
+ raw = chunk.raw;
372
+ if (chunk.providerMetadata !== void 0) {
373
+ providerMetadata = chunk.providerMetadata;
374
+ }
375
+ break;
376
+ }
377
+ case "error": {
378
+ if (chunk.raw !== void 0) {
379
+ raw = chunk.raw;
380
+ }
381
+ if (chunk.providerMetadata !== void 0) {
382
+ providerMetadata = chunk.providerMetadata;
383
+ }
384
+ if (chunk.warnings !== void 0) {
385
+ warnings = chunk.warnings;
386
+ }
387
+ throw toError(chunk.error);
388
+ }
389
+ }
390
+ }
391
+ (0, import_core6.throwIfExecutionAborted)(abortSignal);
392
+ assertModelFinish({ finishReason, usage });
393
+ if (emit) {
394
+ emitNodeEvent(args.emitEvent, args.nodeId, "text-end", {
395
+ ...commonMeta
396
+ });
397
+ }
398
+ const result2 = {
399
+ text: final,
400
+ ...continuation ? { continuation } : {},
401
+ ...raw !== void 0 ? { raw } : {},
402
+ ...usage !== void 0 ? { usage } : {},
403
+ ...finishReason !== void 0 ? { finishReason } : {},
404
+ ...toolCalls !== void 0 ? { toolCalls } : {},
405
+ ...providerMetadata !== void 0 ? { providerMetadata } : {},
406
+ ...warnings !== void 0 ? { warnings } : {}
407
+ };
408
+ (0, import_core6.throwIfExecutionAborted)(abortSignal);
409
+ endTrace(traceSpan, result2);
410
+ return result2;
411
+ }
412
+ const response = await model.invoke(messages);
413
+ (0, import_core6.throwIfExecutionAborted)(abortSignal);
414
+ assertModelFinish(response);
415
+ if (response.content) args.onTextChunk?.(response.content);
416
+ if (emit) {
417
+ emitNodeEvent(args.emitEvent, args.nodeId, "text-start", {
418
+ ...commonMeta
419
+ });
420
+ if (response.content) {
421
+ emitNodeEvent(args.emitEvent, args.nodeId, "text-delta", {
422
+ ...commonMeta,
423
+ delta: response.content
424
+ });
425
+ }
426
+ emitNodeEvent(args.emitEvent, args.nodeId, "text-end", {
427
+ ...commonMeta
428
+ });
429
+ }
430
+ const result = {
431
+ text: response.content,
432
+ ...response.continuation ? { continuation: response.continuation } : {},
433
+ ...response.raw !== void 0 ? { raw: response.raw } : {},
434
+ ...response.usage !== void 0 ? { usage: response.usage } : {},
435
+ ...response.finishReason !== void 0 ? { finishReason: response.finishReason } : {},
436
+ ...response.toolCalls !== void 0 ? { toolCalls: response.toolCalls } : {},
437
+ ...response.providerMetadata !== void 0 ? { providerMetadata: response.providerMetadata } : {},
438
+ ...response.warnings !== void 0 ? { warnings: response.warnings } : {}
439
+ };
440
+ endTrace(traceSpan, result);
441
+ return result;
442
+ } catch (error) {
443
+ const failure = abortSignal?.aborted ? (0, import_core6.createExecutionCancelledError)() : error;
444
+ failTrace(traceSpan, failure);
445
+ throw failure;
446
+ }
447
+ }
448
+ var privateField = /^(?:password|passwd|secret|clientsecret|privatekey|credential|credentials|authorization|bearer|bearertoken|jwt|token|accesstoken|refreshtoken|authtoken|apikey|apisecret|cookie|setcookie|resumehandle|resumetoken)$/;
449
+ function safeTelemetryMetadata2(value) {
450
+ const seen = /* @__PURE__ */ new WeakSet();
451
+ const visit = (input, depth) => {
452
+ if (depth > 8 || typeof input === "function" || typeof input === "symbol")
453
+ return void 0;
454
+ if (!input || typeof input !== "object") return input;
455
+ if (seen.has(input)) return void 0;
456
+ seen.add(input);
457
+ if (Array.isArray(input))
458
+ return input.map((item) => visit(item, depth + 1));
459
+ return Object.fromEntries(
460
+ Object.entries(input).flatMap(
461
+ ([key, nested]) => privateField.test(key.toLowerCase().replace(/[^a-z0-9]/g, "")) ? [] : [[key, visit(nested, depth + 1)]]
462
+ )
463
+ );
464
+ };
465
+ try {
466
+ return visit(value, 0);
467
+ } catch {
468
+ return {};
469
+ }
470
+ }
471
+ }
472
+ });
473
+
32
474
  // ../hooks/dist/index.js
33
475
  var require_dist = __commonJS({
34
476
  "../hooks/dist/index.js"(exports2, module2) {
@@ -64,6 +506,7 @@ var require_dist = __commonJS({
64
506
  useReason: () => useReason2,
65
507
  useRuntimeContext: () => useRuntimeContext,
66
508
  useStructuredData: () => useStructuredData,
509
+ useTool: () => useTool,
67
510
  useWorkflow: () => useWorkflow,
68
511
  useWorkflowState: () => useWorkflowState,
69
512
  workflowCallFingerprint: () => workflowCallFingerprint
@@ -127,6 +570,7 @@ var require_dist = __commonJS({
127
570
  workflowContextClosed: false,
128
571
  nodeStateIndex: 0,
129
572
  reasonCallIndex: 0,
573
+ toolCallIndex: 0,
130
574
  currentNodeState,
131
575
  workflowState: cloneWorkflowState(hookRuntimeState.workflowState),
132
576
  tokenUsage: cloneTokenUsage(ctx.state.runtime?.tokenUsage),
@@ -217,6 +661,12 @@ var require_dist = __commonJS({
217
661
  }
218
662
  });
219
663
  cleanupCompletedReasonCheckpoints(internal);
664
+ for (const key of Object.keys(internal.currentNodeState.byKey)) {
665
+ if (key.startsWith("__useTool:")) {
666
+ delete internal.currentNodeState.byKey[key];
667
+ internal.stateDirty = true;
668
+ }
669
+ }
220
670
  for (const key of Object.keys(internal.currentNodeState.byKey)) {
221
671
  if (key.startsWith("__useWorkflow:") || key.startsWith("__parallel:") || key === "__useWorkflowActivation") {
222
672
  internal.currentNodeState.byKey[key] = null;
@@ -357,7 +807,85 @@ var require_dist = __commonJS({
357
807
  );
358
808
  return Promise.resolve(response);
359
809
  };
360
- var import_core52 = require("@kortyx/core");
810
+ var import_core62 = require("@kortyx/core");
811
+ function safeSpan(span) {
812
+ const guard = (fn) => (...args) => {
813
+ try {
814
+ fn?.(...args);
815
+ } catch {
816
+ }
817
+ };
818
+ let ended = false;
819
+ const finish = (fn) => (...args) => {
820
+ if (ended) return;
821
+ ended = true;
822
+ guard(fn)(...args);
823
+ };
824
+ return {
825
+ addEvent: guard(
826
+ (name, attributes) => span?.addEvent?.(name, attributes)
827
+ ),
828
+ setAttributes: guard(
829
+ (attributes) => span?.setAttributes?.(attributes)
830
+ ),
831
+ end: finish((args) => span?.end?.(args)),
832
+ fail: finish((error, args) => {
833
+ if (span?.fail) span.fail(error, args);
834
+ else span?.end?.(args);
835
+ })
836
+ };
837
+ }
838
+ function safeStartSpan2(adapter, args) {
839
+ try {
840
+ return safeSpan(adapter?.startSpan?.(args));
841
+ } catch {
842
+ return safeSpan(void 0);
843
+ }
844
+ }
845
+ async function withSafeTraceSpan2(adapter, args, fn) {
846
+ let execution;
847
+ const invoke = (span) => {
848
+ execution ??= Promise.resolve().then(async () => {
849
+ const observed = safeSpan(span);
850
+ try {
851
+ const result = await fn(observed);
852
+ observed.end?.();
853
+ return result;
854
+ } catch (error) {
855
+ observed.fail?.(error);
856
+ throw error;
857
+ }
858
+ });
859
+ return execution;
860
+ };
861
+ let activeScope;
862
+ try {
863
+ activeScope = adapter?.withSpan?.bind(adapter);
864
+ } catch {
865
+ }
866
+ if (activeScope) {
867
+ let started;
868
+ const invoked = new Promise((resolve2) => {
869
+ started = resolve2;
870
+ });
871
+ const observe = async () => {
872
+ try {
873
+ await activeScope(args, (span) => {
874
+ const result = invoke(span);
875
+ started?.();
876
+ return result;
877
+ });
878
+ } catch {
879
+ }
880
+ };
881
+ const observation = observe();
882
+ if (!execution) await Promise.race([invoked, observation]);
883
+ } else {
884
+ await invoke(safeStartSpan2(adapter, args)).catch(() => {
885
+ });
886
+ }
887
+ return execution ?? invoke(safeSpan(void 0));
888
+ }
361
889
  var import_node_crypto4 = require("crypto");
362
890
  var parseStructuredPath = (path, source) => {
363
891
  if (path.length === 0) {
@@ -444,15 +972,381 @@ var require_dist = __commonJS({
444
972
  };
445
973
  var shouldEmitStructured = (cfg) => Boolean(cfg);
446
974
  var shouldStreamStructured = (cfg) => Boolean(cfg) && (cfg?.stream ?? true);
975
+ var import_node_async_hooks2 = require("async_hooks");
447
976
  var import_node_crypto32 = require("crypto");
448
- var import_core32 = require("@kortyx/core");
449
- var import_node_crypto22 = require("crypto");
450
977
  var import_core22 = require("@kortyx/core");
978
+ var import_errors32 = require("@kortyx/core/errors");
451
979
  var import_errors22 = require("@kortyx/core/errors");
980
+ function errorDiagnostics(error, project) {
981
+ try {
982
+ const name = (0, import_errors22.errorProperty)(error, "name") ?? (error instanceof Error ? error.name : void 0);
983
+ const message = (0, import_errors22.errorProperty)(error, "message");
984
+ const details = project ? project(error) : {
985
+ type: typeof name === "string" ? name : "Error",
986
+ message: typeof error === "string" ? error : typeof message === "string" ? message : "Execution reported a fault."
987
+ };
988
+ if (!details) return {};
989
+ const projectedMessage = details.message;
990
+ const projectedType = details.type;
991
+ if (typeof projectedMessage !== "string") return {};
992
+ return {
993
+ errorMessage: projectedMessage.slice(0, 8192),
994
+ ...typeof projectedType === "string" ? { errorType: projectedType.slice(0, 256) } : {}
995
+ };
996
+ } catch {
997
+ return {};
998
+ }
999
+ }
1000
+ var import_node_crypto22 = require("crypto");
1001
+ function emitWorkflowCall2(telemetry, type, payload) {
1002
+ const base = telemetry?.correlation;
1003
+ if (!telemetry?.reporter || !telemetry.environment || !telemetry.service || !base?.runId || !base.workflowId)
1004
+ return;
1005
+ try {
1006
+ const active = telemetry.trace?.getActiveContext?.();
1007
+ void Promise.resolve(
1008
+ telemetry.reporter.emit([
1009
+ {
1010
+ schemaVersion: 1,
1011
+ eventId: (0, import_node_crypto22.randomUUID)(),
1012
+ occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
1013
+ environment: telemetry.environment,
1014
+ service: telemetry.service,
1015
+ correlation: {
1016
+ ...base,
1017
+ runId: base.runId,
1018
+ workflowId: base.workflowId,
1019
+ ...active
1020
+ },
1021
+ type,
1022
+ payload
1023
+ }
1024
+ ])
1025
+ ).catch(() => {
1026
+ });
1027
+ } catch {
1028
+ }
1029
+ }
1030
+ function workflowCallContent(telemetry, side, value) {
1031
+ const policy = telemetry?.captureContent;
1032
+ if (!(policy === true || policy && typeof policy === "object" && policy[side]))
1033
+ return {};
1034
+ const serialized = JSON.stringify(value);
1035
+ return serialized && Buffer.byteLength(serialized, "utf8") <= 16384 ? { [side]: JSON.parse(serialized) } : { [`${side}Omitted`]: "Content exceeds 16 KiB" };
1036
+ }
1037
+ var tools = new import_node_async_hooks2.AsyncLocalStorage();
1038
+ function classification(tool, value, thrown, policy = tool.outcomes) {
1039
+ const fallback = {
1040
+ outcome: thrown ? "fault" : "success"
1041
+ };
1042
+ try {
1043
+ if (value && typeof value === "object" && "isError" in value && value.isError === true)
1044
+ fallback.outcome = "fault";
1045
+ const result = thrown ? policy?.classifyError?.(value) : policy?.classifyResult?.(value);
1046
+ if (!result || !["success", "denied", "fault"].includes(result.outcome))
1047
+ return fallback;
1048
+ if (result.outcome !== "denied")
1049
+ return thrown || fallback.outcome === "fault" ? fallback : { outcome: result.outcome };
1050
+ const code = result.code;
1051
+ return {
1052
+ outcome: "denied",
1053
+ code: typeof code === "string" && /^[A-Z][A-Z0-9_]{0,63}$/.test(code) && policy?.denialCodes?.includes(code) ? code : "DENIED"
1054
+ };
1055
+ } catch {
1056
+ return fallback;
1057
+ }
1058
+ }
1059
+ async function closeOwnedTools(owned) {
1060
+ const closers = /* @__PURE__ */ new Map();
1061
+ for (const tool of owned) {
1062
+ if (tool.closeAfterUse !== false && tool.close && !closers.has(tool.close))
1063
+ closers.set(tool.close, tool);
1064
+ }
1065
+ await Promise.all(
1066
+ [...closers].map(async ([close, tool]) => {
1067
+ try {
1068
+ await close.call(tool);
1069
+ } catch {
1070
+ const ctx = getHookContext();
1071
+ try {
1072
+ ctx.reasonTrace?.startSpan({
1073
+ name: "kortyx.tool.cleanup",
1074
+ attributes: { cleanupFailed: true }
1075
+ })?.end?.();
1076
+ } catch {
1077
+ }
1078
+ }
1079
+ })
1080
+ );
1081
+ }
1082
+ function captureToolError(observation, error, policy, returned = false) {
1083
+ try {
1084
+ const reported = returned && error && typeof error === "object" && "isError" in error && error.isError === true && "content" in error && typeof error.content === "string" ? { name: "ToolError", message: error.content } : error;
1085
+ Object.assign(
1086
+ observation,
1087
+ errorDiagnostics(policy?.error ? error : reported, policy?.error)
1088
+ );
1089
+ } catch {
1090
+ }
1091
+ }
1092
+ function ownership() {
1093
+ const ctx = getHookContext();
1094
+ const correlation = ctx.node.workflowCallTelemetry?.correlation;
1095
+ return {
1096
+ workflowId: ctx.node.graph.name,
1097
+ nodeId: ctx.node.graph.node,
1098
+ ...correlation?.workflowRevisionId ? { workflowRevisionId: correlation.workflowRevisionId } : {},
1099
+ ...correlation?.parentInvocationId ? { parentInvocationId: correlation.parentInvocationId } : {},
1100
+ ...correlation?.runId ? { runId: correlation.runId } : {},
1101
+ ...correlation?.invocationId ? { invocationId: correlation.invocationId } : {},
1102
+ ...correlation?.branchId ? { branchId: correlation.branchId } : {}
1103
+ };
1104
+ }
1105
+ function rememberToolObservation(observation) {
1106
+ const ctx = getHookContext();
1107
+ const existing = ctx.workflowState.__kortyxToolObservations;
1108
+ const observations = Array.isArray(existing) ? existing : [];
1109
+ if (!observations.some((item) => item.attemptId === observation.attemptId))
1110
+ observations.push({ ...observation });
1111
+ ctx.workflowState.__kortyxToolObservations = observations;
1112
+ ctx.stateDirty = true;
1113
+ }
1114
+ function toolTrace(observation) {
1115
+ const ctx = getHookContext();
1116
+ const adapter = ctx.reasonTrace ?? ctx.node.workflowCallTelemetry?.trace;
1117
+ if (adapter) return adapter;
1118
+ const telemetry = ctx.node.workflowCallTelemetry;
1119
+ if (!telemetry?.reporter) return void 0;
1120
+ const correlation = { ...telemetry.correlation, ...observation };
1121
+ const spanId = (0, import_node_crypto32.randomUUID)();
1122
+ const emit = (type, payload) => emitWorkflowCall2(
1123
+ {
1124
+ ...telemetry,
1125
+ correlation,
1126
+ trace: {
1127
+ startSpan: () => void 0,
1128
+ getActiveContext: () => ({
1129
+ traceId: correlation.runId ?? spanId,
1130
+ spanId
1131
+ })
1132
+ }
1133
+ },
1134
+ type,
1135
+ payload
1136
+ );
1137
+ return {
1138
+ startSpan: ({ attributes = {} }) => {
1139
+ if (attributes.executed === true) emit("tool.started", attributes);
1140
+ let ended = false;
1141
+ return {
1142
+ end: (args) => {
1143
+ if (ended) return;
1144
+ ended = true;
1145
+ const payload = { ...attributes, ...args?.attributes };
1146
+ const type = payload.observationKind === "reused" ? "tool.reused" : payload.observationKind === "waiting" ? "tool.waiting" : payload.suspended ? "tool.suspended" : payload.outcome === "denied" ? "tool.denied" : payload.outcome === "fault" ? "tool.failed" : payload.outcome === "cancelled" ? "tool.cancelled" : "tool.completed";
1147
+ emit(type, payload);
1148
+ }
1149
+ };
1150
+ }
1151
+ };
1152
+ }
1153
+ async function executeObservedTool(args) {
1154
+ const ctx = getHookContext();
1155
+ const observation = {
1156
+ version: 1,
1157
+ name: args.tool.name,
1158
+ toolCallId: args.toolCallId,
1159
+ attemptId: (0, import_node_crypto32.randomUUID)(),
1160
+ callingMode: args.callingMode,
1161
+ executed: false,
1162
+ ...ownership()
1163
+ };
1164
+ const scope = {
1165
+ tool: args.tool,
1166
+ input: args.input,
1167
+ signal: args.abortSignal,
1168
+ mode: args.callingMode,
1169
+ providerToolCallId: args.providerToolCallId ?? args.toolCallId,
1170
+ adopted: false
1171
+ };
1172
+ try {
1173
+ (0, import_core22.throwIfExecutionAborted)(args.abortSignal);
1174
+ } catch (error) {
1175
+ observation.outcome = "cancelled";
1176
+ await observeToolFact(observation);
1177
+ args.onObservation?.(observation);
1178
+ throw error;
1179
+ }
1180
+ ctx.node.consumeExecution?.("maxToolCalls");
1181
+ observation.executed = true;
1182
+ const started = performance.now();
1183
+ return withSafeTraceSpan2(
1184
+ toolTrace(observation),
1185
+ {
1186
+ name: "kortyx.tool",
1187
+ attributes: { ...observation, nodeId: ctx.node.graph.node }
1188
+ },
1189
+ async (span) => tools.run(scope, async () => {
1190
+ try {
1191
+ const result = await args.tool.execute(args.input, {
1192
+ toolCallId: args.providerToolCallId ?? args.toolCallId,
1193
+ ...args.abortSignal ? { abortSignal: args.abortSignal } : {}
1194
+ });
1195
+ (0, import_core22.throwIfExecutionAborted)(args.abortSignal);
1196
+ const outcome = classification(
1197
+ args.tool,
1198
+ result,
1199
+ false,
1200
+ scope.classify ?? args.tool.outcomes
1201
+ );
1202
+ observation.outcome = outcome.outcome;
1203
+ if (outcome.code) observation.denialCode = outcome.code;
1204
+ if (observation.outcome === "fault") {
1205
+ captureToolError(
1206
+ observation,
1207
+ result,
1208
+ scope.telemetry ?? args.tool.telemetry,
1209
+ true
1210
+ );
1211
+ }
1212
+ return result;
1213
+ } catch (error) {
1214
+ if (args.abortSignal?.aborted) observation.outcome = "cancelled";
1215
+ else if (!(0, import_errors32.isControlFlowError)(error)) {
1216
+ const outcome = classification(
1217
+ args.tool,
1218
+ error,
1219
+ true,
1220
+ scope.classify ?? args.tool.outcomes
1221
+ );
1222
+ observation.outcome = outcome.outcome;
1223
+ if (outcome.code) observation.denialCode = outcome.code;
1224
+ if (observation.outcome === "fault")
1225
+ captureToolError(
1226
+ observation,
1227
+ error,
1228
+ scope.telemetry ?? args.tool.telemetry
1229
+ );
1230
+ }
1231
+ throw error;
1232
+ } finally {
1233
+ observation.durationMs = Math.max(0, performance.now() - started);
1234
+ span.end?.({
1235
+ attributes: {
1236
+ ...observation,
1237
+ ...observation.outcome ? {} : { suspended: true }
1238
+ }
1239
+ });
1240
+ rememberToolObservation(observation);
1241
+ args.onObservation?.({ ...observation });
1242
+ }
1243
+ })
1244
+ );
1245
+ }
1246
+ async function observeToolFact(observation, kind, preserveOwner = false) {
1247
+ const ctx = getHookContext();
1248
+ if (!preserveOwner) Object.assign(observation, ownership());
1249
+ if (observation.outcome && kind !== "reused")
1250
+ rememberToolObservation(observation);
1251
+ await withSafeTraceSpan2(
1252
+ toolTrace(observation),
1253
+ {
1254
+ name: "kortyx.tool",
1255
+ attributes: {
1256
+ ...observation,
1257
+ executed: false,
1258
+ ...kind ? { observationKind: kind } : {},
1259
+ nodeId: observation.nodeId ?? ctx.node.graph.node
1260
+ }
1261
+ },
1262
+ async (span) => {
1263
+ span.end?.({
1264
+ attributes: {
1265
+ ...observation,
1266
+ executed: false,
1267
+ ...kind ? { observationKind: kind } : {}
1268
+ }
1269
+ });
1270
+ }
1271
+ );
1272
+ }
1273
+ async function useTool(args) {
1274
+ const ctx = getHookContext();
1275
+ const scope = tools.getStore();
1276
+ if (scope?.mode === "model" && !scope.adopted && scope.tool.name === args.tool.name && scope.input === args.input) {
1277
+ scope.adopted = true;
1278
+ scope.classify = args.tool.outcomes ?? scope.classify;
1279
+ scope.telemetry = args.tool.telemetry ?? scope.telemetry;
1280
+ return tools.run(
1281
+ { ...scope, mode: "direct" },
1282
+ () => args.tool.execute(args.input, {
1283
+ toolCallId: scope.providerToolCallId,
1284
+ ...scope.signal ? { abortSignal: scope.signal } : {}
1285
+ })
1286
+ );
1287
+ }
1288
+ const index = ctx.toolCallIndex++;
1289
+ const key = `__useTool:${args.id ?? `auto:${index}`}`;
1290
+ let id = ctx.currentNodeState.byKey[key];
1291
+ if (typeof id !== "string") {
1292
+ id = (0, import_node_crypto32.randomUUID)();
1293
+ ctx.currentNodeState.byKey[key] = id;
1294
+ ctx.stateDirty = true;
1295
+ }
1296
+ try {
1297
+ return await executeObservedTool({
1298
+ tool: args.tool,
1299
+ input: args.input,
1300
+ toolCallId: String(id),
1301
+ callingMode: "direct",
1302
+ abortSignal: (0, import_core22.combineAbortSignals)(ctx.node.abortSignal, args.abortSignal)
1303
+ });
1304
+ } finally {
1305
+ await closeOwnedTools([args.tool]);
1306
+ }
1307
+ }
1308
+ async function replayToolObservations(observations, child = false) {
1309
+ for (const original of observations) {
1310
+ const source = original.source ?? {
1311
+ ...ownershipFrom(original),
1312
+ toolCallId: original.toolCallId,
1313
+ attemptId: original.attemptId
1314
+ };
1315
+ await observeToolFact(
1316
+ {
1317
+ ...original,
1318
+ ...ownership(),
1319
+ ...child ? {
1320
+ workflowId: original.workflowId,
1321
+ nodeId: original.nodeId,
1322
+ workflowRevisionId: original.workflowRevisionId,
1323
+ invocationId: original.invocationId,
1324
+ parentInvocationId: original.parentInvocationId
1325
+ } : {},
1326
+ attemptId: (0, import_node_crypto32.randomUUID)(),
1327
+ executed: false,
1328
+ source,
1329
+ durationMs: void 0
1330
+ },
1331
+ "reused",
1332
+ child
1333
+ );
1334
+ }
1335
+ }
1336
+ var ownershipFrom = (observation) => ({
1337
+ runId: observation.runId,
1338
+ invocationId: observation.invocationId,
1339
+ branchId: observation.branchId
1340
+ });
1341
+ var import_node_crypto5 = require("crypto");
1342
+ var import_core42 = require("@kortyx/core");
1343
+ var import_node_crypto42 = require("crypto");
1344
+ var import_core32 = require("@kortyx/core");
1345
+ var import_errors42 = require("@kortyx/core/errors");
452
1346
  function assertModelFinish(result) {
453
1347
  if (result.finishReason?.unified !== "content-filter") return;
454
1348
  throw Object.assign(
455
- new import_errors22.KortyxError("PROVIDER_REFUSAL", "The provider refused the request.", {
1349
+ new import_errors42.KortyxError("PROVIDER_REFUSAL", "The provider refused the request.", {
456
1350
  category: "provider",
457
1351
  retryable: false,
458
1352
  safeMessage: "The provider refused the request."
@@ -466,7 +1360,7 @@ var require_dist = __commonJS({
466
1360
  var toError = (value) => value instanceof Error ? value : new Error(String(value));
467
1361
  var createRuntimeId = () => {
468
1362
  try {
469
- return (0, import_node_crypto22.randomUUID)();
1363
+ return (0, import_node_crypto42.randomUUID)();
470
1364
  } catch {
471
1365
  return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
472
1366
  }
@@ -501,8 +1395,8 @@ var require_dist = __commonJS({
501
1395
  args.model.options?.providerOptions,
502
1396
  args.providerOptions
503
1397
  );
504
- const tools = args.tools ?? args.model.options?.tools;
505
- (0, import_core22.throwIfExecutionAborted)(abortSignal);
1398
+ const tools2 = args.tools ?? args.model.options?.tools;
1399
+ (0, import_core32.throwIfExecutionAborted)(abortSignal);
506
1400
  const model = args.model.provider.getModel(args.model.modelId, {
507
1401
  ...temperature !== void 0 ? { temperature } : {},
508
1402
  streaming: stream,
@@ -511,10 +1405,10 @@ var require_dist = __commonJS({
511
1405
  ...abortSignal !== void 0 ? { abortSignal } : {},
512
1406
  ...reasoning !== void 0 ? { reasoning } : {},
513
1407
  ...responseFormat !== void 0 ? { responseFormat } : {},
514
- ...tools !== void 0 ? { tools } : {},
1408
+ ...tools2 !== void 0 ? { tools: tools2 } : {},
515
1409
  ...providerOptions !== void 0 ? { providerOptions } : {}
516
1410
  });
517
- if (tools?.length && !model.supportsToolStreaming) stream = false;
1411
+ if (tools2?.length && !model.supportsToolStreaming) stream = false;
518
1412
  const messages = args.messages !== void 0 ? args.messages : [
519
1413
  ...typeof args.system === "string" && args.system.length > 0 ? [{ role: "system", content: args.system }] : [],
520
1414
  { role: "user", content: String(args.input ?? "") }
@@ -526,7 +1420,7 @@ var require_dist = __commonJS({
526
1420
  opId,
527
1421
  segmentId
528
1422
  };
529
- const traceSpan = args.reasonTrace?.startSpan({
1423
+ const traceSpan = safeStartSpan2(args.reasonTrace, {
530
1424
  name: "runReasonEngine",
531
1425
  attributes: {
532
1426
  ...commonMeta,
@@ -606,7 +1500,7 @@ var require_dist = __commonJS({
606
1500
  }
607
1501
  const response2 = await model.stream(messages);
608
1502
  for await (const chunk of response2) {
609
- (0, import_core22.throwIfExecutionAborted)(abortSignal);
1503
+ (0, import_core32.throwIfExecutionAborted)(abortSignal);
610
1504
  switch (chunk.type) {
611
1505
  case "text-delta": {
612
1506
  if (chunk.delta.length === 0) break;
@@ -672,7 +1566,7 @@ var require_dist = __commonJS({
672
1566
  }
673
1567
  }
674
1568
  }
675
- (0, import_core22.throwIfExecutionAborted)(abortSignal);
1569
+ (0, import_core32.throwIfExecutionAborted)(abortSignal);
676
1570
  assertModelFinish({ finishReason, usage });
677
1571
  if (emit) {
678
1572
  emitNodeEvent(args.emitEvent, args.nodeId, "text-end", {
@@ -689,12 +1583,12 @@ var require_dist = __commonJS({
689
1583
  ...providerMetadata !== void 0 ? { providerMetadata } : {},
690
1584
  ...warnings !== void 0 ? { warnings } : {}
691
1585
  };
692
- (0, import_core22.throwIfExecutionAborted)(abortSignal);
1586
+ (0, import_core32.throwIfExecutionAborted)(abortSignal);
693
1587
  endTrace(traceSpan, result2);
694
1588
  return result2;
695
1589
  }
696
1590
  const response = await model.invoke(messages);
697
- (0, import_core22.throwIfExecutionAborted)(abortSignal);
1591
+ (0, import_core32.throwIfExecutionAborted)(abortSignal);
698
1592
  assertModelFinish(response);
699
1593
  if (response.content) args.onTextChunk?.(response.content);
700
1594
  if (emit) {
@@ -724,26 +1618,26 @@ var require_dist = __commonJS({
724
1618
  endTrace(traceSpan, result);
725
1619
  return result;
726
1620
  } catch (error) {
727
- const failure = abortSignal?.aborted ? (0, import_core22.createExecutionCancelledError)() : error;
1621
+ const failure = abortSignal?.aborted ? (0, import_core32.createExecutionCancelledError)() : error;
728
1622
  failTrace(traceSpan, failure);
729
1623
  throw failure;
730
1624
  }
731
1625
  }
732
1626
  var createRuntimeId2 = () => {
733
1627
  try {
734
- return (0, import_node_crypto32.randomUUID)();
1628
+ return (0, import_node_crypto5.randomUUID)();
735
1629
  } catch {
736
1630
  return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
737
1631
  }
738
1632
  };
739
1633
  async function reasonEngine(args, meta, inputOverride) {
740
1634
  const ctx = getHookContext();
741
- const abortSignal = (0, import_core32.combineAbortSignals)(
1635
+ const abortSignal = (0, import_core42.combineAbortSignals)(
742
1636
  ctx.node.abortSignal,
743
1637
  args.abortSignal,
744
1638
  args.model.options?.abortSignal
745
1639
  );
746
- (0, import_core32.throwIfExecutionAborted)(abortSignal);
1640
+ (0, import_core42.throwIfExecutionAborted)(abortSignal);
747
1641
  ctx.node.consumeExecution?.("maxModelPasses");
748
1642
  try {
749
1643
  return await runReasonEngine({
@@ -1485,7 +2379,7 @@ var require_dist = __commonJS({
1485
2379
  }
1486
2380
  };
1487
2381
  }
1488
- var import_errors32 = require("@kortyx/core/errors");
2382
+ var import_errors52 = require("@kortyx/core/errors");
1489
2383
  var tryJsonParse = (value) => {
1490
2384
  try {
1491
2385
  return { ok: true, value: JSON.parse(value) };
@@ -1523,12 +2417,12 @@ var require_dist = __commonJS({
1523
2417
  }
1524
2418
  return text;
1525
2419
  };
1526
- var createTruncatedStructuredOutputError = (label, cause) => new import_errors32.ValidationError(
2420
+ var createTruncatedStructuredOutputError = (label, cause) => new import_errors52.ValidationError(
1527
2421
  "OUTPUT_TRUNCATED",
1528
2422
  `${label} was truncated before producing valid structured output. The model stopped due to output length. Increase maxOutputTokens or simplify the requested output.`,
1529
2423
  cause
1530
2424
  );
1531
- var createInvalidStructuredOutputError = (label, cause) => new import_errors32.ValidationError(
2425
+ var createInvalidStructuredOutputError = (label, cause) => new import_errors52.ValidationError(
1532
2426
  "INVALID_MODEL_JSON",
1533
2427
  `${label} did not produce valid structured output. The model returned text instead of the expected JSON payload. Check outputSchema and provider structured-output settings.`,
1534
2428
  cause
@@ -1540,7 +2434,7 @@ var require_dist = __commonJS({
1540
2434
  try {
1541
2435
  return parseWithSchema(args.schema, candidate, args.label);
1542
2436
  } catch (error) {
1543
- if (!(error instanceof import_errors32.ValidationError)) throw error;
2437
+ if (!(error instanceof import_errors52.ValidationError)) throw error;
1544
2438
  const failure = args.finishReason?.unified === "length" ? createTruncatedStructuredOutputError(args.label, error) : typeof candidate === "string" && !validJson ? createInvalidStructuredOutputError(args.label, error) : error;
1545
2439
  if (failure && typeof failure === "object")
1546
2440
  Object.assign(failure, {
@@ -1560,7 +2454,7 @@ var require_dist = __commonJS({
1560
2454
  if (typeof candidate === "string" && candidate.trim().length > 0) {
1561
2455
  throw createInvalidStructuredOutputError("useReason output");
1562
2456
  }
1563
- throw new import_errors32.ValidationError(
2457
+ throw new import_errors52.ValidationError(
1564
2458
  "MODEL_OUTPUT_SCHEMA",
1565
2459
  "useReason first pass with interrupt must return a JSON object."
1566
2460
  );
@@ -1569,7 +2463,7 @@ var require_dist = __commonJS({
1569
2463
  let interruptRequired = true;
1570
2464
  if (mode === "optional") {
1571
2465
  if (candidate.decision !== "continue" && candidate.decision !== "interrupt") {
1572
- throw new import_errors32.ValidationError(
2466
+ throw new import_errors52.ValidationError(
1573
2467
  "MODEL_OUTPUT_SCHEMA",
1574
2468
  'useReason optional interrupt first pass must include decision "continue" or "interrupt".'
1575
2469
  );
@@ -1582,7 +2476,7 @@ var require_dist = __commonJS({
1582
2476
  candidate.interrupt
1583
2477
  ].some((value) => value !== null && value !== void 0);
1584
2478
  if (hasUnexpectedRequest) {
1585
- throw new import_errors32.ValidationError(
2479
+ throw new import_errors52.ValidationError(
1586
2480
  "MODEL_OUTPUT_SCHEMA",
1587
2481
  'useReason optional interrupt first pass with decision "continue" must not include an interrupt request.'
1588
2482
  );
@@ -1616,7 +2510,7 @@ var require_dist = __commonJS({
1616
2510
  "useReason output"
1617
2511
  );
1618
2512
  } catch (error) {
1619
- if (!(error instanceof import_errors32.ValidationError)) throw error;
2513
+ if (!(error instanceof import_errors52.ValidationError)) throw error;
1620
2514
  if (args.finishReason?.unified === "length") {
1621
2515
  throw createTruncatedStructuredOutputError("useReason output", error);
1622
2516
  }
@@ -1625,7 +2519,7 @@ var require_dist = __commonJS({
1625
2519
  }
1626
2520
  const explicitDraft = typeof candidate.draftText === "string" && candidate.draftText.length > 0 ? candidate.draftText : typeof candidate.text === "string" && candidate.text.length > 0 ? candidate.text : void 0;
1627
2521
  if (!args.outputSchema && !explicitDraft) {
1628
- throw new import_errors32.ValidationError(
2522
+ throw new import_errors52.ValidationError(
1629
2523
  "MODEL_OUTPUT_SCHEMA",
1630
2524
  "useReason first pass with interrupt requires `draftText` when outputSchema is not provided."
1631
2525
  );
@@ -1811,6 +2705,7 @@ ${tryStringify2(args.response)}`
1811
2705
  const reasoning = sum(left.reasoning, right.reasoning);
1812
2706
  const cacheRead = sum(left.cacheRead, right.cacheRead);
1813
2707
  const cacheWrite = sum(left.cacheWrite, right.cacheWrite);
2708
+ const cacheWrite1h = sum(left.cacheWrite1h, right.cacheWrite1h);
1814
2709
  const merged = {
1815
2710
  ...right.outputIncludesReasoning !== void 0 ? { outputIncludesReasoning: right.outputIncludesReasoning } : {},
1816
2711
  ...right.inputIncludesCacheWrite !== void 0 ? { inputIncludesCacheWrite: right.inputIncludesCacheWrite } : {},
@@ -1822,6 +2717,7 @@ ${tryStringify2(args.response)}`
1822
2717
  if (reasoning !== void 0) merged.reasoning = reasoning;
1823
2718
  if (cacheRead !== void 0) merged.cacheRead = cacheRead;
1824
2719
  if (cacheWrite !== void 0) merged.cacheWrite = cacheWrite;
2720
+ if (cacheWrite1h !== void 0) merged.cacheWrite1h = cacheWrite1h;
1825
2721
  if (raw) merged.raw = raw;
1826
2722
  return merged;
1827
2723
  };
@@ -1858,9 +2754,9 @@ ${tryStringify2(args.response)}`
1858
2754
  streamId: args.opId
1859
2755
  });
1860
2756
  };
1861
- var import_core42 = require("@kortyx/core");
1862
- var import_errors42 = require("@kortyx/core/errors");
1863
- var toToolDefinitions = (tools) => tools.map((tool) => ({
2757
+ var import_core52 = require("@kortyx/core");
2758
+ var import_errors62 = require("@kortyx/core/errors");
2759
+ var toToolDefinitions = (tools2) => tools2.map((tool) => ({
1864
2760
  name: tool.name,
1865
2761
  ...tool.title ? { title: tool.title } : {},
1866
2762
  ...tool.description ? { description: tool.description } : {},
@@ -1877,12 +2773,13 @@ ${tryStringify2(args.response)}`
1877
2773
  return fallback;
1878
2774
  };
1879
2775
  var normalizeToolResult = (toolCall, value) => {
1880
- if (value && typeof value === "object" && !Array.isArray(value) && "toolCallId" in value && "name" in value && "content" in value) {
1881
- return value;
2776
+ if (value && typeof value === "object" && !Array.isArray(value) && "toolCallId" in value && "name" in value && "content" in value && typeof value.content === "string") {
2777
+ const result = value;
2778
+ return { ...result, toolCallId: toolCall.id, name: toolCall.name };
1882
2779
  }
1883
2780
  let content;
1884
2781
  try {
1885
- content = typeof value === "string" ? value : JSON.stringify(value);
2782
+ content = typeof value === "string" ? value : JSON.stringify(value) ?? String(value);
1886
2783
  } catch {
1887
2784
  content = String(value);
1888
2785
  }
@@ -1893,28 +2790,6 @@ ${tryStringify2(args.response)}`
1893
2790
  ...value !== void 0 && value !== null && typeof value === "object" && !Array.isArray(value) ? { structuredContent: value } : {}
1894
2791
  };
1895
2792
  };
1896
- var closeOwnedTools = async (tools, preserveFailure = false, traceSpan) => {
1897
- const closeFns = /* @__PURE__ */ new Set();
1898
- for (const tool of tools) {
1899
- if (tool.closeAfterUse === false || !tool.close) continue;
1900
- closeFns.add(tool.close);
1901
- }
1902
- try {
1903
- await Promise.all(
1904
- [...closeFns].map(async (close) => {
1905
- await close();
1906
- })
1907
- );
1908
- } catch (error) {
1909
- if (!preserveFailure) throw error;
1910
- try {
1911
- traceSpan?.addEvent?.("useReason.cleanup.failed", {
1912
- failure: (0, import_errors42.serializeFailure)(error)
1913
- });
1914
- } catch {
1915
- }
1916
- }
1917
- };
1918
2793
  var createInitialMessages = (args) => [
1919
2794
  ...typeof args.system === "string" && args.system.length > 0 ? [{ role: "system", content: args.system }] : [],
1920
2795
  { role: "user", content: String(args.input ?? "") }
@@ -1922,7 +2797,7 @@ ${tryStringify2(args.response)}`
1922
2797
  var runReasonToolLoop = async (args) => {
1923
2798
  const { useReasonArgs, id, traceSpan, checkpointKey } = args;
1924
2799
  const ctx = getHookContext();
1925
- const abortSignal = (0, import_core42.combineAbortSignals)(
2800
+ const abortSignal = (0, import_core52.combineAbortSignals)(
1926
2801
  ctx.node.abortSignal,
1927
2802
  useReasonArgs.abortSignal,
1928
2803
  useReasonArgs.model.options?.abortSignal
@@ -1930,43 +2805,32 @@ ${tryStringify2(args.response)}`
1930
2805
  const saved = ctx.currentNodeState.byKey[checkpointKey];
1931
2806
  const checkpoint = saved?.status === "tool_loop" ? saved : void 0;
1932
2807
  const opId = checkpoint?.opId ?? args.opId;
1933
- let primaryFailure = false;
1934
- const tools = useReasonArgs.tools ?? [];
2808
+ const tools2 = useReasonArgs.tools ?? [];
1935
2809
  const toolByName = /* @__PURE__ */ new Map();
1936
- let validationCompleted = false;
1937
2810
  let separateOutput = false;
1938
- try {
1939
- for (const tool of tools) {
1940
- if (toolByName.has(tool.name)) {
1941
- throw new Error(
1942
- `useReason received duplicate tool name "${tool.name}".`
1943
- );
1944
- }
1945
- toolByName.set(tool.name, tool);
2811
+ for (const tool of tools2) {
2812
+ if (toolByName.has(tool.name)) {
2813
+ throw new Error(`useReason received duplicate tool name "${tool.name}".`);
1946
2814
  }
1947
- if (useReasonArgs.interrupt) {
1948
- throw new Error(
1949
- "useReason tools cannot be combined with useReason interrupt mode yet. Use toolExecution.approval for tool approval."
1950
- );
1951
- }
1952
- separateOutput = Boolean(
1953
- useReasonArgs.model.provider.getModel(useReasonArgs.model.modelId, {
1954
- ...useReasonArgs.model.options,
1955
- ...useReasonArgs.reasoning !== void 0 ? { reasoning: useReasonArgs.reasoning } : {},
1956
- ...useReasonArgs.responseFormat ? { responseFormat: useReasonArgs.responseFormat } : {},
1957
- providerOptions: resolveProviderOptions(
1958
- useReasonArgs.model.options?.providerOptions,
1959
- useReasonArgs.providerOptions
1960
- ) ?? {}
1961
- }).requiresSeparateStructuredOutput
2815
+ toolByName.set(tool.name, tool);
2816
+ }
2817
+ if (useReasonArgs.interrupt) {
2818
+ throw new Error(
2819
+ "useReason tools cannot be combined with useReason interrupt mode yet. Use toolExecution.approval for tool approval."
1962
2820
  );
1963
- validationCompleted = true;
1964
- } finally {
1965
- if (!validationCompleted) {
1966
- await closeOwnedTools(tools, true, traceSpan);
1967
- }
1968
2821
  }
1969
- const toolDefinitions = toToolDefinitions(tools);
2822
+ separateOutput = Boolean(
2823
+ useReasonArgs.model.provider.getModel(useReasonArgs.model.modelId, {
2824
+ ...useReasonArgs.model.options,
2825
+ ...useReasonArgs.reasoning !== void 0 ? { reasoning: useReasonArgs.reasoning } : {},
2826
+ ...useReasonArgs.responseFormat ? { responseFormat: useReasonArgs.responseFormat } : {},
2827
+ providerOptions: resolveProviderOptions(
2828
+ useReasonArgs.model.options?.providerOptions,
2829
+ useReasonArgs.providerOptions
2830
+ ) ?? {}
2831
+ }).requiresSeparateStructuredOutput
2832
+ );
2833
+ const toolDefinitions = toToolDefinitions(tools2);
1970
2834
  let finalizing = checkpoint?.finalizing ?? false;
1971
2835
  let completed = false;
1972
2836
  const maxSteps = Math.max(1, useReasonArgs.toolExecution?.maxSteps ?? 3);
@@ -2018,7 +2882,7 @@ ${tryStringify2(args.response)}`
2018
2882
  };
2019
2883
  try {
2020
2884
  for (let stepIndex = pending ? steps.length - 1 : steps.length; stepIndex < maxSteps; stepIndex += 1) {
2021
- (0, import_core42.throwIfExecutionAborted)(abortSignal);
2885
+ (0, import_core52.throwIfExecutionAborted)(abortSignal);
2022
2886
  traceSpan?.addEvent?.("useReason.tool-step.start", {
2023
2887
  stepIndex,
2024
2888
  toolCount: toolDefinitions.length
@@ -2062,6 +2926,12 @@ ${tryStringify2(args.response)}`
2062
2926
  );
2063
2927
  aggregatedWarnings = mergeWarnings(aggregatedWarnings, step.warnings);
2064
2928
  const toolCalls = step.toolCalls ?? [];
2929
+ const ids = /* @__PURE__ */ new Set();
2930
+ for (const call of toolCalls) {
2931
+ if (!call.id || ids.has(call.id) || !reused && allToolCalls.some((prior) => prior.id === call.id))
2932
+ throw new Error("Model returned duplicate or empty tool call IDs.");
2933
+ ids.add(call.id);
2934
+ }
2065
2935
  const toolResults = reused ? steps[stepIndex]?.toolResults ?? [] : [];
2066
2936
  if (!reused)
2067
2937
  steps.push({
@@ -2130,9 +3000,15 @@ ${tryStringify2(args.response)}`
2130
3000
  pending = step;
2131
3001
  save();
2132
3002
  for (const toolCall of toolCalls) {
2133
- if (toolResults.some((result2) => result2.toolCallId === toolCall.id))
3003
+ if (toolResults.some((result2) => result2.toolCallId === toolCall.id)) {
3004
+ await replayToolObservations(
3005
+ steps[stepIndex]?.toolObservations?.filter(
3006
+ (observation) => observation.toolCallId === `${opId}:${toolCall.id}`
3007
+ ) ?? []
3008
+ );
2134
3009
  continue;
2135
- (0, import_core42.throwIfExecutionAborted)(abortSignal);
3010
+ }
3011
+ (0, import_core52.throwIfExecutionAborted)(abortSignal);
2136
3012
  const tool = toolByName.get(toolCall.name);
2137
3013
  if (!tool) {
2138
3014
  throw new Error(
@@ -2149,11 +3025,6 @@ ${tryStringify2(args.response)}`
2149
3025
  tool.name,
2150
3026
  false
2151
3027
  );
2152
- traceSpan?.addEvent?.("useReason.tool-call.start", {
2153
- stepIndex,
2154
- tool: tool.name,
2155
- toolCallId: toolCall.id
2156
- });
2157
3028
  if (shouldEmitTool) {
2158
3029
  emitToolEvent("tool-call-start", {
2159
3030
  tool: tool.name,
@@ -2162,6 +3033,17 @@ ${tryStringify2(args.response)}`
2162
3033
  });
2163
3034
  }
2164
3035
  if (shouldApproveTool && !approvedCalls.includes(toolCall.id)) {
3036
+ await observeToolFact(
3037
+ {
3038
+ version: 1,
3039
+ name: tool.name,
3040
+ toolCallId: `${opId}:${toolCall.id}`,
3041
+ attemptId: `${opId}:${toolCall.id}:approval`,
3042
+ callingMode: "model",
3043
+ executed: false
3044
+ },
3045
+ "waiting"
3046
+ );
2165
3047
  const approval = await awaitInterruptInternal({
2166
3048
  id: `tool:${toolCall.id}`,
2167
3049
  request: {
@@ -2180,6 +3062,22 @@ ${tryStringify2(args.response)}`
2180
3062
  });
2181
3063
  const approved = Array.isArray(approval) ? approval.includes("approve") : approval === "approve";
2182
3064
  if (!approved) {
3065
+ const deniedObservation = {
3066
+ version: 1,
3067
+ name: tool.name,
3068
+ toolCallId: `${opId}:${toolCall.id}`,
3069
+ attemptId: `${opId}:${toolCall.id}:approval`,
3070
+ callingMode: "model",
3071
+ executed: false,
3072
+ outcome: "denied",
3073
+ denialCode: "APPROVAL_DENIED"
3074
+ };
3075
+ await observeToolFact(deniedObservation);
3076
+ const entry = steps[stepIndex];
3077
+ if (entry) {
3078
+ entry.toolObservations ??= [];
3079
+ entry.toolObservations.push(deniedObservation);
3080
+ }
2183
3081
  const denied = {
2184
3082
  toolCallId: toolCall.id,
2185
3083
  name: tool.name,
@@ -2210,13 +3108,24 @@ ${tryStringify2(args.response)}`
2210
3108
  save();
2211
3109
  }
2212
3110
  try {
2213
- (0, import_core42.throwIfExecutionAborted)(abortSignal);
2214
- ctx.node.consumeExecution?.("maxToolCalls");
2215
- const rawResult = await tool.execute(toolCall.input, {
2216
- toolCallId: toolCall.id,
2217
- ...abortSignal ? { abortSignal } : {}
3111
+ (0, import_core52.throwIfExecutionAborted)(abortSignal);
3112
+ const rawResult = await executeObservedTool({
3113
+ tool,
3114
+ input: toolCall.input,
3115
+ toolCallId: `${opId}:${toolCall.id}`,
3116
+ providerToolCallId: toolCall.id,
3117
+ callingMode: "model",
3118
+ abortSignal,
3119
+ onObservation: (observation) => {
3120
+ const entry = steps[stepIndex];
3121
+ if (entry) {
3122
+ entry.toolObservations ??= [];
3123
+ entry.toolObservations.push(observation);
3124
+ save();
3125
+ }
3126
+ }
2218
3127
  });
2219
- (0, import_core42.throwIfExecutionAborted)(abortSignal);
3128
+ (0, import_core52.throwIfExecutionAborted)(abortSignal);
2220
3129
  const result2 = normalizeToolResult(toolCall, rawResult);
2221
3130
  toolResults.push(result2);
2222
3131
  allToolResults.push(result2);
@@ -2229,20 +3138,14 @@ ${tryStringify2(args.response)}`
2229
3138
  ...result2.isError !== void 0 ? { isError: result2.isError } : {}
2230
3139
  });
2231
3140
  }
2232
- traceSpan?.addEvent?.("useReason.tool-call.complete", {
2233
- stepIndex,
2234
- tool: result2.name,
2235
- toolCallId: result2.toolCallId,
2236
- isError: Boolean(result2.isError)
2237
- });
2238
3141
  } catch (error) {
2239
- (0, import_core42.throwIfExecutionAborted)(abortSignal);
2240
- if ((0, import_errors42.isControlFlowError)(error)) throw error;
3142
+ (0, import_core52.throwIfExecutionAborted)(abortSignal);
3143
+ if ((0, import_errors62.isControlFlowError)(error)) throw error;
2241
3144
  const result2 = {
2242
3145
  toolCallId: toolCall.id,
2243
3146
  name: tool.name,
2244
- content: (0, import_errors42.serializeFailure)(error).message,
2245
- failure: (0, import_errors42.serializeFailure)(error),
3147
+ content: (0, import_errors62.serializeFailure)(error).message,
3148
+ failure: (0, import_errors62.serializeFailure)(error),
2246
3149
  isError: true
2247
3150
  };
2248
3151
  toolResults.push(result2);
@@ -2255,13 +3158,6 @@ ${tryStringify2(args.response)}`
2255
3158
  failure: result2.failure
2256
3159
  });
2257
3160
  }
2258
- traceSpan?.addEvent?.("useReason.tool-call.error", {
2259
- stepIndex,
2260
- tool: tool.name,
2261
- toolCallId: toolCall.id,
2262
- message: result2.content,
2263
- failure: result2.failure
2264
- });
2265
3161
  }
2266
3162
  const completed2 = toolResults.at(-1);
2267
3163
  if (completed2)
@@ -2334,7 +3230,6 @@ ${tryStringify2(args.response)}`
2334
3230
  ctx.stateDirty = true;
2335
3231
  return result;
2336
3232
  } catch (error) {
2337
- primaryFailure = true;
2338
3233
  try {
2339
3234
  traceSpan?.fail?.(error, {
2340
3235
  attributes: {
@@ -2345,8 +3240,6 @@ ${tryStringify2(args.response)}`
2345
3240
  } catch {
2346
3241
  }
2347
3242
  throw error;
2348
- } finally {
2349
- await closeOwnedTools(tools, primaryFailure, traceSpan);
2350
3243
  }
2351
3244
  };
2352
3245
  var shouldStreamReasonStructured = (args) => (args.emit ?? true) && shouldStreamStructured(args.structured);
@@ -2360,15 +3253,15 @@ ${tryStringify2(args.response)}`
2360
3253
  "useReason does not support reasoning.includeThoughts with structured output, interrupt mode, or JSON responseFormat. Disable includeThoughts for this call."
2361
3254
  );
2362
3255
  };
2363
- async function useReason(args) {
3256
+ async function runReason(args) {
2364
3257
  assertReasoningThoughtsCompatibility(args);
2365
3258
  const ctx = getHookContext();
2366
- const abortSignal = (0, import_core52.combineAbortSignals)(
3259
+ const abortSignal = (0, import_core62.combineAbortSignals)(
2367
3260
  ctx.node.abortSignal,
2368
3261
  args.abortSignal,
2369
3262
  args.model.options?.abortSignal
2370
3263
  );
2371
- (0, import_core52.throwIfExecutionAborted)(abortSignal);
3264
+ (0, import_core62.throwIfExecutionAborted)(abortSignal);
2372
3265
  const allowValidatedToolOutput = Boolean(
2373
3266
  args.outputSchema && !(args.responseFormat ?? args.model.options?.responseFormat)
2374
3267
  );
@@ -2391,286 +3284,303 @@ ${tryStringify2(args.response)}`
2391
3284
  ctx.currentNodeState.byKey[checkpointKey]
2392
3285
  );
2393
3286
  if (existingCompleted) {
3287
+ await replayToolObservations(
3288
+ existingCompleted.result.steps?.flatMap(
3289
+ (step) => step.toolObservations ?? []
3290
+ ) ?? []
3291
+ );
2394
3292
  return existingCompleted.result;
2395
3293
  }
2396
3294
  const existingCheckpoint = readReasonCheckpoint(
2397
3295
  ctx.currentNodeState.byKey[checkpointKey]
2398
3296
  );
2399
3297
  const reasonMeta = typeof id === "string" ? { id, opId } : { opId };
2400
- const traceSpan = getReasonTraceAdapter()?.startSpan({
2401
- name: "useReason",
2402
- attributes: {
2403
- ...id ? { id } : {},
2404
- opId,
2405
- nodeId: ctx.node.graph.node,
2406
- providerId: args.model.provider.id,
2407
- modelId: args.model.modelId,
2408
- stream: args.stream ?? args.model.options?.streaming ?? true,
2409
- emit: args.emit ?? true,
2410
- ...args.telemetry?.operation ? { operation: args.telemetry.operation } : {},
2411
- ...args.telemetry?.prompt?.name ? { promptName: args.telemetry.prompt.name } : {},
2412
- ...args.telemetry?.prompt?.version !== void 0 ? { promptVersion: args.telemetry.prompt.version } : {},
2413
- ...args.telemetry?.prompt?.type ? { promptType: args.telemetry.prompt.type } : {},
2414
- hasOutputSchema: Boolean(args.outputSchema),
2415
- hasInterrupt: Boolean(args.interrupt),
2416
- hasStructured: Boolean(args.structured),
2417
- hasTools: Boolean(args.tools?.length)
2418
- },
2419
- telemetry: {
2420
- ...args.telemetry ?? {},
2421
- input: args.telemetry?.input ?? args.input
2422
- }
2423
- });
2424
- if (args.tools?.length) {
2425
- return runReasonToolLoop({
2426
- useReasonArgs: args,
2427
- allowValidatedToolOutput,
2428
- checkpointKey,
2429
- initialWarnings: inferred.warnings,
2430
- ...id ? { id } : {},
2431
- opId,
2432
- ...traceSpan ? { traceSpan } : {}
2433
- });
2434
- }
2435
- const suppressTextStream = Boolean(args.outputSchema || args.interrupt);
2436
- const setFieldPaths = resolveSetFieldPaths(args.structured);
2437
- const appendFieldPaths = resolveAppendFieldPaths(args.structured);
2438
- const textDeltaFieldPaths = resolveTextDeltaFieldPaths(args.structured);
2439
- const useStructuredIncrementalStreaming = Boolean(
2440
- args.outputSchema && !args.interrupt && (setFieldPaths.length > 0 || appendFieldPaths.length > 0 || textDeltaFieldPaths.length > 0) && args.stream !== false && shouldStreamReasonStructured(args)
2441
- );
2442
- let firstText = "";
2443
- let firstRaw;
2444
- let firstOutput;
2445
- let firstInterruptRequest;
2446
- let firstInterruptRequired = false;
2447
- let finalText = "";
2448
- let finalRaw;
2449
- let finalOutput;
2450
- let aggregatedUsage;
2451
- let finalFinishReason;
2452
- let aggregatedProviderMetadata;
2453
- let aggregatedWarnings = inferred.warnings;
2454
- if (existingCheckpoint) {
2455
- firstText = existingCheckpoint.firstText;
2456
- firstRaw = existingCheckpoint.firstRaw;
2457
- firstOutput = existingCheckpoint.firstOutput;
2458
- finalText = firstText;
2459
- finalRaw = firstRaw;
2460
- finalOutput = firstOutput;
2461
- aggregatedUsage = existingCheckpoint.firstUsage;
2462
- finalFinishReason = existingCheckpoint.firstFinishReason;
2463
- aggregatedProviderMetadata = existingCheckpoint.firstProviderMetadata;
2464
- aggregatedWarnings = existingCheckpoint.firstWarnings;
2465
- traceSpan?.addEvent?.("useReason.resume", {
2466
- checkpointKey
2467
- });
2468
- } else {
2469
- const first = await reasonEngine(
2470
- {
2471
- ...args,
2472
- emit: suppressTextStream ? false : args.emit,
2473
- stream: useStructuredIncrementalStreaming ? true : suppressTextStream ? false : args.stream,
2474
- ...useStructuredIncrementalStreaming ? {
2475
- onTextChunk: createStructuredOutputStreamer(args, id, opId)
2476
- } : {}
3298
+ return withSafeTraceSpan2(
3299
+ getReasonTraceAdapter(),
3300
+ {
3301
+ name: "useReason",
3302
+ attributes: {
3303
+ ...id ? { id } : {},
3304
+ opId,
3305
+ nodeId: ctx.node.graph.node,
3306
+ providerId: args.model.provider.id,
3307
+ modelId: args.model.modelId,
3308
+ stream: args.stream ?? args.model.options?.streaming ?? true,
3309
+ emit: args.emit ?? true,
3310
+ ...args.telemetry?.operation ? { operation: args.telemetry.operation } : {},
3311
+ ...args.telemetry?.prompt?.name ? { promptName: args.telemetry.prompt.name } : {},
3312
+ ...args.telemetry?.prompt?.version !== void 0 ? { promptVersion: args.telemetry.prompt.version } : {},
3313
+ ...args.telemetry?.prompt?.type ? { promptType: args.telemetry.prompt.type } : {},
3314
+ hasOutputSchema: Boolean(args.outputSchema),
3315
+ hasInterrupt: Boolean(args.interrupt),
3316
+ hasStructured: Boolean(args.structured),
3317
+ hasTools: Boolean(args.tools?.length)
2477
3318
  },
2478
- reasonMeta,
2479
- args.interrupt ? defaultInterruptFirstPassInput({
2480
- input: args.input,
2481
- requestSchema: args.interrupt.requestSchema,
2482
- mode: args.interrupt.mode ?? "required",
2483
- ...args.outputSchema ? { outputSchema: args.outputSchema } : {}
2484
- }) : args.outputSchema ? withOutputGuardrails(
2485
- withStructuredStreamHints(args.input, {
2486
- ...setFieldPaths.length > 0 ? { setFieldPaths } : {},
2487
- ...appendFieldPaths.length > 0 ? { appendFieldPaths } : {},
2488
- ...textDeltaFieldPaths.length > 0 ? { textDeltaFieldPaths } : {}
2489
- }),
2490
- args.outputSchema
2491
- ) : void 0
2492
- );
2493
- firstRaw = first.raw;
2494
- finalRaw = first.raw;
2495
- accumulateTokenUsage(first.usage);
2496
- aggregatedUsage = mergeUsage(aggregatedUsage, first.usage);
2497
- finalFinishReason = first.finishReason;
2498
- aggregatedProviderMetadata = mergeProviderMetadata(
2499
- aggregatedProviderMetadata,
2500
- first.providerMetadata
2501
- );
2502
- aggregatedWarnings = mergeWarnings(aggregatedWarnings, first.warnings);
2503
- traceSpan?.addEvent?.("useReason.first-pass.complete", {
2504
- textLength: first.text.length,
2505
- hasInterrupt: Boolean(args.interrupt)
2506
- });
2507
- if (args.interrupt) {
2508
- const firstPass = parseInterruptFirstPassResult({
2509
- text: first.text,
2510
- requestSchema: args.interrupt.requestSchema,
2511
- ...first.finishReason ? { finishReason: first.finishReason } : {},
2512
- ...first.usage ? { usage: first.usage } : {},
2513
- ...args.outputSchema ? { outputSchema: args.outputSchema } : {},
2514
- mode: args.interrupt.mode ?? "required"
2515
- });
2516
- firstText = firstPass.draftText;
2517
- finalText = firstPass.draftText;
2518
- firstInterruptRequired = firstPass.interruptRequired;
2519
- firstInterruptRequest = firstPass.request;
2520
- firstOutput = firstPass.output;
2521
- finalOutput = firstPass.output;
2522
- } else {
2523
- firstText = first.text;
2524
- finalText = first.text;
2525
- if (args.outputSchema) {
2526
- firstOutput = parseReasonOutputWithSchema({
2527
- text: first.text,
2528
- schema: args.outputSchema,
2529
- ...first.finishReason ? { finishReason: first.finishReason } : {},
2530
- ...first.usage ? { usage: first.usage } : {},
2531
- label: "useReason output"
3319
+ telemetry: {
3320
+ ...args.telemetry ?? {},
3321
+ input: args.telemetry?.input ?? args.input
3322
+ }
3323
+ },
3324
+ async (traceSpan) => {
3325
+ if (args.tools?.length) {
3326
+ return runReasonToolLoop({
3327
+ useReasonArgs: args,
3328
+ allowValidatedToolOutput,
3329
+ checkpointKey,
3330
+ initialWarnings: inferred.warnings,
3331
+ ...id ? { id } : {},
3332
+ opId,
3333
+ ...traceSpan ? { traceSpan } : {}
2532
3334
  });
2533
3335
  }
2534
- finalOutput = firstOutput;
2535
- }
2536
- }
2537
- let interruptResponse;
2538
- if (args.interrupt && (existingCheckpoint || firstInterruptRequired)) {
2539
- const requestSchema = args.interrupt.requestSchema;
2540
- const interruptRequest = existingCheckpoint ? parseWithSchema(
2541
- requestSchema,
2542
- existingCheckpoint.request,
2543
- "useReason interrupt.request"
2544
- ) : firstInterruptRequest;
2545
- if (!interruptRequest) {
2546
- throw new Error(
2547
- "useReason interrupt request is missing; first pass did not produce a valid interrupt payload."
3336
+ const suppressTextStream = Boolean(args.outputSchema || args.interrupt);
3337
+ const setFieldPaths = resolveSetFieldPaths(args.structured);
3338
+ const appendFieldPaths = resolveAppendFieldPaths(args.structured);
3339
+ const textDeltaFieldPaths = resolveTextDeltaFieldPaths(args.structured);
3340
+ const useStructuredIncrementalStreaming = Boolean(
3341
+ args.outputSchema && !args.interrupt && (setFieldPaths.length > 0 || appendFieldPaths.length > 0 || textDeltaFieldPaths.length > 0) && args.stream !== false && shouldStreamReasonStructured(args)
2548
3342
  );
2549
- }
2550
- if (!existingCheckpoint) {
2551
- ctx.currentNodeState.byKey[checkpointKey] = {
2552
- status: "awaiting_interrupt",
2553
- request: interruptRequest,
2554
- firstText,
2555
- ...firstRaw !== void 0 ? { firstRaw } : {},
2556
- ...aggregatedUsage !== void 0 ? { firstUsage: aggregatedUsage } : {},
2557
- ...finalFinishReason !== void 0 ? { firstFinishReason: finalFinishReason } : {},
2558
- ...aggregatedProviderMetadata !== void 0 ? { firstProviderMetadata: aggregatedProviderMetadata } : {},
2559
- ...aggregatedWarnings !== void 0 ? { firstWarnings: aggregatedWarnings } : {},
2560
- ...firstOutput !== void 0 ? { firstOutput } : {}
2561
- };
2562
- ctx.stateDirty = true;
2563
- }
2564
- const resumeStatePatch = resolveHookStatePatch({
2565
- nodeId: ctx.node.graph.node,
2566
- currentNodeState: ctx.currentNodeState,
2567
- workflowState: ctx.workflowState
2568
- });
2569
- interruptResponse = await awaitInterruptInternal({
2570
- request: interruptRequest,
2571
- requestSchema,
2572
- responseSchema: args.interrupt.responseSchema,
2573
- ...args.interrupt.schemaId ? { schemaId: args.interrupt.schemaId } : {},
2574
- ...args.interrupt.schemaVersion ? { schemaVersion: args.interrupt.schemaVersion } : {},
2575
- ...id ? { id } : {},
2576
- meta: {
2577
- __kortyxResumeStatePatch: resumeStatePatch
3343
+ let firstText = "";
3344
+ let firstRaw;
3345
+ let firstOutput;
3346
+ let firstInterruptRequest;
3347
+ let firstInterruptRequired = false;
3348
+ let finalText = "";
3349
+ let finalRaw;
3350
+ let finalOutput;
3351
+ let aggregatedUsage;
3352
+ let finalFinishReason;
3353
+ let aggregatedProviderMetadata;
3354
+ let aggregatedWarnings = inferred.warnings;
3355
+ if (existingCheckpoint) {
3356
+ firstText = existingCheckpoint.firstText;
3357
+ firstRaw = existingCheckpoint.firstRaw;
3358
+ firstOutput = existingCheckpoint.firstOutput;
3359
+ finalText = firstText;
3360
+ finalRaw = firstRaw;
3361
+ finalOutput = firstOutput;
3362
+ aggregatedUsage = existingCheckpoint.firstUsage;
3363
+ finalFinishReason = existingCheckpoint.firstFinishReason;
3364
+ aggregatedProviderMetadata = existingCheckpoint.firstProviderMetadata;
3365
+ aggregatedWarnings = existingCheckpoint.firstWarnings;
3366
+ traceSpan?.addEvent?.("useReason.resume", {
3367
+ checkpointKey
3368
+ });
3369
+ } else {
3370
+ const first = await reasonEngine(
3371
+ {
3372
+ ...args,
3373
+ emit: suppressTextStream ? false : args.emit,
3374
+ stream: useStructuredIncrementalStreaming ? true : suppressTextStream ? false : args.stream,
3375
+ ...useStructuredIncrementalStreaming ? {
3376
+ onTextChunk: createStructuredOutputStreamer(args, id, opId)
3377
+ } : {}
3378
+ },
3379
+ reasonMeta,
3380
+ args.interrupt ? defaultInterruptFirstPassInput({
3381
+ input: args.input,
3382
+ requestSchema: args.interrupt.requestSchema,
3383
+ mode: args.interrupt.mode ?? "required",
3384
+ ...args.outputSchema ? { outputSchema: args.outputSchema } : {}
3385
+ }) : args.outputSchema ? withOutputGuardrails(
3386
+ withStructuredStreamHints(args.input, {
3387
+ ...setFieldPaths.length > 0 ? { setFieldPaths } : {},
3388
+ ...appendFieldPaths.length > 0 ? { appendFieldPaths } : {},
3389
+ ...textDeltaFieldPaths.length > 0 ? { textDeltaFieldPaths } : {}
3390
+ }),
3391
+ args.outputSchema
3392
+ ) : void 0
3393
+ );
3394
+ firstRaw = first.raw;
3395
+ finalRaw = first.raw;
3396
+ accumulateTokenUsage(first.usage);
3397
+ aggregatedUsage = mergeUsage(aggregatedUsage, first.usage);
3398
+ finalFinishReason = first.finishReason;
3399
+ aggregatedProviderMetadata = mergeProviderMetadata(
3400
+ aggregatedProviderMetadata,
3401
+ first.providerMetadata
3402
+ );
3403
+ aggregatedWarnings = mergeWarnings(aggregatedWarnings, first.warnings);
3404
+ traceSpan?.addEvent?.("useReason.first-pass.complete", {
3405
+ textLength: first.text.length,
3406
+ hasInterrupt: Boolean(args.interrupt)
3407
+ });
3408
+ if (args.interrupt) {
3409
+ const firstPass = parseInterruptFirstPassResult({
3410
+ text: first.text,
3411
+ requestSchema: args.interrupt.requestSchema,
3412
+ ...first.finishReason ? { finishReason: first.finishReason } : {},
3413
+ ...first.usage ? { usage: first.usage } : {},
3414
+ ...args.outputSchema ? { outputSchema: args.outputSchema } : {},
3415
+ mode: args.interrupt.mode ?? "required"
3416
+ });
3417
+ firstText = firstPass.draftText;
3418
+ finalText = firstPass.draftText;
3419
+ firstInterruptRequired = firstPass.interruptRequired;
3420
+ firstInterruptRequest = firstPass.request;
3421
+ firstOutput = firstPass.output;
3422
+ finalOutput = firstPass.output;
3423
+ } else {
3424
+ firstText = first.text;
3425
+ finalText = first.text;
3426
+ if (args.outputSchema) {
3427
+ firstOutput = parseReasonOutputWithSchema({
3428
+ text: first.text,
3429
+ schema: args.outputSchema,
3430
+ ...first.finishReason ? { finishReason: first.finishReason } : {},
3431
+ ...first.usage ? { usage: first.usage } : {},
3432
+ label: "useReason output"
3433
+ });
3434
+ }
3435
+ finalOutput = firstOutput;
3436
+ }
2578
3437
  }
2579
- });
2580
- traceSpan?.addEvent?.("useReason.interrupt.resolved", {
2581
- checkpointKey
2582
- });
2583
- if (Object.hasOwn(ctx.currentNodeState.byKey, checkpointKey)) {
2584
- delete ctx.currentNodeState.byKey[checkpointKey];
2585
- ctx.stateDirty = true;
2586
- }
2587
- const continuationInput = defaultContinuationInput({
2588
- input: args.input,
2589
- draftText: firstText,
2590
- ...firstOutput !== void 0 ? { draftOutput: firstOutput } : {},
2591
- request: interruptRequest,
2592
- response: interruptResponse
2593
- });
2594
- const second = await reasonEngine(
2595
- {
2596
- ...args,
2597
- ...inferred.responseFormat ? { responseFormat: inferred.responseFormat } : {},
2598
- emit: suppressTextStream ? false : args.emit,
2599
- stream: suppressTextStream ? false : args.stream
2600
- },
2601
- reasonMeta,
2602
- args.outputSchema ? withOutputGuardrails(
2603
- continuationInput,
2604
- args.outputSchema
2605
- ) : continuationInput
2606
- );
2607
- finalText = second.text;
2608
- finalRaw = second.raw;
2609
- accumulateTokenUsage(second.usage);
2610
- aggregatedUsage = mergeUsage(aggregatedUsage, second.usage);
2611
- finalFinishReason = second.finishReason;
2612
- aggregatedProviderMetadata = mergeProviderMetadata(
2613
- aggregatedProviderMetadata,
2614
- second.providerMetadata
2615
- );
2616
- aggregatedWarnings = mergeWarnings(aggregatedWarnings, second.warnings);
2617
- traceSpan?.addEvent?.("useReason.continuation.complete", {
2618
- textLength: second.text.length
2619
- });
2620
- if (args.outputSchema) {
2621
- finalOutput = parseReasonOutputWithSchema({
3438
+ let interruptResponse;
3439
+ if (args.interrupt && (existingCheckpoint || firstInterruptRequired)) {
3440
+ const requestSchema = args.interrupt.requestSchema;
3441
+ const interruptRequest = existingCheckpoint ? parseWithSchema(
3442
+ requestSchema,
3443
+ existingCheckpoint.request,
3444
+ "useReason interrupt.request"
3445
+ ) : firstInterruptRequest;
3446
+ if (!interruptRequest) {
3447
+ throw new Error(
3448
+ "useReason interrupt request is missing; first pass did not produce a valid interrupt payload."
3449
+ );
3450
+ }
3451
+ if (!existingCheckpoint) {
3452
+ ctx.currentNodeState.byKey[checkpointKey] = {
3453
+ status: "awaiting_interrupt",
3454
+ request: interruptRequest,
3455
+ firstText,
3456
+ ...firstRaw !== void 0 ? { firstRaw } : {},
3457
+ ...aggregatedUsage !== void 0 ? { firstUsage: aggregatedUsage } : {},
3458
+ ...finalFinishReason !== void 0 ? { firstFinishReason: finalFinishReason } : {},
3459
+ ...aggregatedProviderMetadata !== void 0 ? { firstProviderMetadata: aggregatedProviderMetadata } : {},
3460
+ ...aggregatedWarnings !== void 0 ? { firstWarnings: aggregatedWarnings } : {},
3461
+ ...firstOutput !== void 0 ? { firstOutput } : {}
3462
+ };
3463
+ ctx.stateDirty = true;
3464
+ }
3465
+ const resumeStatePatch = resolveHookStatePatch({
3466
+ nodeId: ctx.node.graph.node,
3467
+ currentNodeState: ctx.currentNodeState,
3468
+ workflowState: ctx.workflowState
3469
+ });
3470
+ interruptResponse = await awaitInterruptInternal({
3471
+ request: interruptRequest,
3472
+ requestSchema,
3473
+ responseSchema: args.interrupt.responseSchema,
3474
+ ...args.interrupt.schemaId ? { schemaId: args.interrupt.schemaId } : {},
3475
+ ...args.interrupt.schemaVersion ? { schemaVersion: args.interrupt.schemaVersion } : {},
3476
+ ...id ? { id } : {},
3477
+ meta: {
3478
+ __kortyxResumeStatePatch: resumeStatePatch
3479
+ }
3480
+ });
3481
+ traceSpan?.addEvent?.("useReason.interrupt.resolved", {
3482
+ checkpointKey
3483
+ });
3484
+ if (Object.hasOwn(ctx.currentNodeState.byKey, checkpointKey)) {
3485
+ delete ctx.currentNodeState.byKey[checkpointKey];
3486
+ ctx.stateDirty = true;
3487
+ }
3488
+ const continuationInput = defaultContinuationInput({
3489
+ input: args.input,
3490
+ draftText: firstText,
3491
+ ...firstOutput !== void 0 ? { draftOutput: firstOutput } : {},
3492
+ request: interruptRequest,
3493
+ response: interruptResponse
3494
+ });
3495
+ const second = await reasonEngine(
3496
+ {
3497
+ ...args,
3498
+ ...inferred.responseFormat ? { responseFormat: inferred.responseFormat } : {},
3499
+ emit: suppressTextStream ? false : args.emit,
3500
+ stream: suppressTextStream ? false : args.stream
3501
+ },
3502
+ reasonMeta,
3503
+ args.outputSchema ? withOutputGuardrails(
3504
+ continuationInput,
3505
+ args.outputSchema
3506
+ ) : continuationInput
3507
+ );
3508
+ finalText = second.text;
3509
+ finalRaw = second.raw;
3510
+ accumulateTokenUsage(second.usage);
3511
+ aggregatedUsage = mergeUsage(aggregatedUsage, second.usage);
3512
+ finalFinishReason = second.finishReason;
3513
+ aggregatedProviderMetadata = mergeProviderMetadata(
3514
+ aggregatedProviderMetadata,
3515
+ second.providerMetadata
3516
+ );
3517
+ aggregatedWarnings = mergeWarnings(aggregatedWarnings, second.warnings);
3518
+ traceSpan?.addEvent?.("useReason.continuation.complete", {
3519
+ textLength: second.text.length
3520
+ });
3521
+ if (args.outputSchema) {
3522
+ finalOutput = parseReasonOutputWithSchema({
3523
+ text: finalText,
3524
+ schema: args.outputSchema,
3525
+ ...second.finishReason ? { finishReason: second.finishReason } : {},
3526
+ ...aggregatedUsage ? { usage: aggregatedUsage } : {},
3527
+ label: "useReason output"
3528
+ });
3529
+ }
3530
+ }
3531
+ if (finalOutput !== void 0) {
3532
+ emitReasonStructuredOutput({
3533
+ ...id ? { id } : {},
3534
+ opId,
3535
+ output: finalOutput,
3536
+ structured: args.structured,
3537
+ emit: args.emit ?? true
3538
+ });
3539
+ }
3540
+ const result = {
3541
+ ...id ? { id } : {},
3542
+ opId,
2622
3543
  text: finalText,
2623
- schema: args.outputSchema,
2624
- ...second.finishReason ? { finishReason: second.finishReason } : {},
2625
- ...aggregatedUsage ? { usage: aggregatedUsage } : {},
2626
- label: "useReason output"
3544
+ ...finalRaw !== void 0 ? { raw: finalRaw } : {},
3545
+ ...aggregatedUsage !== void 0 ? { usage: aggregatedUsage } : {},
3546
+ ...finalFinishReason !== void 0 ? { finishReason: finalFinishReason } : {},
3547
+ ...aggregatedProviderMetadata !== void 0 ? { providerMetadata: aggregatedProviderMetadata } : {},
3548
+ ...aggregatedWarnings !== void 0 ? { warnings: aggregatedWarnings } : {},
3549
+ ...finalOutput !== void 0 ? { output: finalOutput } : {},
3550
+ ...interruptResponse !== void 0 ? { interruptResponse } : {}
3551
+ };
3552
+ if (args.interrupt) {
3553
+ ctx.currentNodeState.byKey[checkpointKey] = {
3554
+ status: "completed",
3555
+ result
3556
+ };
3557
+ ctx.stateDirty = true;
3558
+ }
3559
+ traceSpan?.end?.({
3560
+ ...aggregatedUsage !== void 0 ? { usage: aggregatedUsage } : {},
3561
+ ...finalFinishReason !== void 0 ? { finishReason: finalFinishReason } : {},
3562
+ ...aggregatedProviderMetadata !== void 0 ? { providerMetadata: aggregatedProviderMetadata } : {},
3563
+ ...aggregatedWarnings !== void 0 ? { warnings: aggregatedWarnings } : {},
3564
+ attributes: {
3565
+ textLength: finalText.length,
3566
+ resumedFromCheckpoint: Boolean(existingCheckpoint),
3567
+ interrupted: Boolean(interruptResponse !== void 0)
3568
+ },
3569
+ telemetry: {
3570
+ ...args.telemetry ?? {},
3571
+ output: args.telemetry?.output ?? finalOutput ?? finalText
3572
+ }
2627
3573
  });
3574
+ return result;
2628
3575
  }
3576
+ );
3577
+ }
3578
+ async function useReason(args) {
3579
+ try {
3580
+ return await runReason(args);
3581
+ } finally {
3582
+ await closeOwnedTools(args.tools ?? []);
2629
3583
  }
2630
- if (finalOutput !== void 0) {
2631
- emitReasonStructuredOutput({
2632
- ...id ? { id } : {},
2633
- opId,
2634
- output: finalOutput,
2635
- structured: args.structured,
2636
- emit: args.emit ?? true
2637
- });
2638
- }
2639
- const result = {
2640
- ...id ? { id } : {},
2641
- opId,
2642
- text: finalText,
2643
- ...finalRaw !== void 0 ? { raw: finalRaw } : {},
2644
- ...aggregatedUsage !== void 0 ? { usage: aggregatedUsage } : {},
2645
- ...finalFinishReason !== void 0 ? { finishReason: finalFinishReason } : {},
2646
- ...aggregatedProviderMetadata !== void 0 ? { providerMetadata: aggregatedProviderMetadata } : {},
2647
- ...aggregatedWarnings !== void 0 ? { warnings: aggregatedWarnings } : {},
2648
- ...finalOutput !== void 0 ? { output: finalOutput } : {},
2649
- ...interruptResponse !== void 0 ? { interruptResponse } : {}
2650
- };
2651
- if (args.interrupt) {
2652
- ctx.currentNodeState.byKey[checkpointKey] = {
2653
- status: "completed",
2654
- result
2655
- };
2656
- ctx.stateDirty = true;
2657
- }
2658
- traceSpan?.end?.({
2659
- ...aggregatedUsage !== void 0 ? { usage: aggregatedUsage } : {},
2660
- ...finalFinishReason !== void 0 ? { finishReason: finalFinishReason } : {},
2661
- ...aggregatedProviderMetadata !== void 0 ? { providerMetadata: aggregatedProviderMetadata } : {},
2662
- ...aggregatedWarnings !== void 0 ? { warnings: aggregatedWarnings } : {},
2663
- attributes: {
2664
- textLength: finalText.length,
2665
- resumedFromCheckpoint: Boolean(existingCheckpoint),
2666
- interrupted: Boolean(interruptResponse !== void 0)
2667
- },
2668
- telemetry: {
2669
- ...args.telemetry ?? {},
2670
- output: args.telemetry?.output ?? finalOutput ?? finalText
2671
- }
2672
- });
2673
- return result;
2674
3584
  }
2675
3585
  function useStructuredData(args) {
2676
3586
  emitStructuredData(args);
@@ -2725,8 +3635,8 @@ ${tryStringify2(args.response)}`
2725
3635
  };
2726
3636
  return [getValue(), setValue];
2727
3637
  }
2728
- var import_core62 = require("@kortyx/core");
2729
- var import_errors52 = require("@kortyx/core/errors");
3638
+ var import_core7 = require("@kortyx/core");
3639
+ var import_errors7 = require("@kortyx/core/errors");
2730
3640
  var ParallelChildWaiting = class extends Error {
2731
3641
  name = "ParallelChildWaiting";
2732
3642
  };
@@ -2740,14 +3650,14 @@ ${tryStringify2(args.response)}`
2740
3650
  );
2741
3651
  this.results = results;
2742
3652
  this.name = "ParallelError";
2743
- this.failure = (0, import_errors52.serializeFailure)({
3653
+ this.failure = (0, import_errors7.serializeFailure)({
2744
3654
  version: 1,
2745
3655
  code: this.code,
2746
3656
  category: "workflow",
2747
3657
  message: this.message,
2748
3658
  retryable: null,
2749
3659
  results: results.map(
2750
- (result) => result.status === "fulfilled" ? { status: "fulfilled" } : { status: "rejected", failure: (0, import_errors52.serializeFailure)(result.reason) }
3660
+ (result) => result.status === "fulfilled" ? { status: "fulfilled" } : { status: "rejected", failure: (0, import_errors7.serializeFailure)(result.reason) }
2751
3661
  )
2752
3662
  });
2753
3663
  }
@@ -2755,7 +3665,7 @@ ${tryStringify2(args.response)}`
2755
3665
  code = "PARALLEL_FAILED";
2756
3666
  failure;
2757
3667
  toJSON() {
2758
- return (0, import_errors52.serializeFailure)(this);
3668
+ return (0, import_errors7.serializeFailure)(this);
2759
3669
  }
2760
3670
  };
2761
3671
  function registerWorkflowTask(id) {
@@ -2851,13 +3761,13 @@ ${tryStringify2(args.response)}`
2851
3761
  );
2852
3762
  }
2853
3763
  if (ready[0]?.status === "rejected") throw ready[0].reason;
2854
- (0, import_core62.throwIfExecutionAborted)(ctx.node.abortSignal);
3764
+ (0, import_core7.throwIfExecutionAborted)(ctx.node.abortSignal);
2855
3765
  if (ctx.workflowControlError) throw ctx.workflowControlError;
2856
3766
  const rejected = outcomes.filter(
2857
3767
  (outcome) => outcome.status === "rejected"
2858
3768
  );
2859
3769
  const control = rejected.find(
2860
- (outcome) => (0, import_core62.isExecutionCancelled)(outcome.reason) || (0, import_core62.isExecutionLimitReached)(outcome.reason)
3770
+ (outcome) => (0, import_core7.isExecutionCancelled)(outcome.reason) || (0, import_core7.isExecutionLimitReached)(outcome.reason)
2861
3771
  );
2862
3772
  if (control) {
2863
3773
  ctx.workflowControlError = control.reason;
@@ -2892,50 +3802,13 @@ ${tryStringify2(args.response)}`
2892
3802
  });
2893
3803
  return promise;
2894
3804
  }
2895
- var import_node_crypto5 = require("crypto");
2896
- var import_core7 = require("@kortyx/core");
2897
- var import_errors62 = require("@kortyx/core/errors");
2898
- var import_node_crypto42 = require("crypto");
2899
- function emitWorkflowCall2(telemetry, type, payload) {
2900
- const base = telemetry?.correlation;
2901
- if (!telemetry?.reporter || !telemetry.environment || !telemetry.service || !base?.runId || !base.workflowId)
2902
- return;
2903
- try {
2904
- const active = telemetry.trace?.getActiveContext?.();
2905
- void Promise.resolve(
2906
- telemetry.reporter.emit([
2907
- {
2908
- schemaVersion: 1,
2909
- eventId: (0, import_node_crypto42.randomUUID)(),
2910
- occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
2911
- environment: telemetry.environment,
2912
- service: telemetry.service,
2913
- correlation: {
2914
- ...base,
2915
- runId: base.runId,
2916
- workflowId: base.workflowId,
2917
- ...active
2918
- },
2919
- type,
2920
- payload
2921
- }
2922
- ])
2923
- ).catch(() => {
2924
- });
2925
- } catch {
2926
- }
2927
- }
2928
- function workflowCallContent(telemetry, side, value) {
2929
- const policy = telemetry?.captureContent;
2930
- if (!(policy === true || policy && typeof policy === "object" && policy[side]))
2931
- return {};
2932
- const serialized = JSON.stringify(value);
2933
- return serialized && Buffer.byteLength(serialized, "utf8") <= 16384 ? { [side]: JSON.parse(serialized) } : { [`${side}Omitted`]: "Content exceeds 16 KiB" };
2934
- }
2935
- var WorkflowCallError = class extends import_errors62.KortyxError {
3805
+ var import_node_crypto6 = require("crypto");
3806
+ var import_core8 = require("@kortyx/core");
3807
+ var import_errors8 = require("@kortyx/core/errors");
3808
+ var WorkflowCallError = class extends import_errors8.KortyxError {
2936
3809
  constructor(workflow, message, cause, failure) {
2937
- const detail = (0, import_errors62.serializeFailure)(
2938
- failure ?? cause ?? new import_errors62.WorkflowContractError(message)
3810
+ const detail = (0, import_errors8.serializeFailure)(
3811
+ failure ?? cause ?? new import_errors8.WorkflowContractError(message)
2939
3812
  );
2940
3813
  super(detail.code, `Workflow '${workflow}': ${message}`, {
2941
3814
  ...detail,
@@ -2956,12 +3829,12 @@ ${tryStringify2(args.response)}`
2956
3829
  if (v === null || typeof v === "string" || typeof v === "boolean") return v;
2957
3830
  if (typeof v === "number" && Number.isFinite(v)) return v;
2958
3831
  if (typeof v !== "object" || !v || seen.has(v)) {
2959
- throw new import_errors62.WorkflowContractError(
3832
+ throw new import_errors8.WorkflowContractError(
2960
3833
  "Workflow input and output must be JSON serializable."
2961
3834
  );
2962
3835
  }
2963
3836
  if (!Array.isArray(v) && Object.getPrototypeOf(v) !== Object.prototype) {
2964
- throw new import_errors62.WorkflowContractError(
3837
+ throw new import_errors8.WorkflowContractError(
2965
3838
  "Workflow input and output must contain plain JSON objects."
2966
3839
  );
2967
3840
  }
@@ -2982,7 +3855,7 @@ ${tryStringify2(args.response)}`
2982
3855
  useWorkflow: (args) => {
2983
3856
  const workflow = workflows[args.workflow];
2984
3857
  if (!workflow || workflow.id !== args.workflow)
2985
- throw new import_errors62.WorkflowContractError(
3858
+ throw new import_errors8.WorkflowContractError(
2986
3859
  "Workflow registry keys must match definition ids."
2987
3860
  );
2988
3861
  return useWorkflow({ ...args, workflow });
@@ -2996,7 +3869,7 @@ ${tryStringify2(args.response)}`
2996
3869
  if (task.group) await task.group.ready;
2997
3870
  return await runWorkflowCall(args, task);
2998
3871
  } catch (error) {
2999
- if ((0, import_core7.isExecutionCancelled)(error) || (0, import_core7.isExecutionLimitReached)(error))
3872
+ if ((0, import_core8.isExecutionCancelled)(error) || (0, import_core8.isExecutionLimitReached)(error))
3000
3873
  getHookContext().workflowControlError = error;
3001
3874
  throw error;
3002
3875
  } finally {
@@ -3005,26 +3878,26 @@ ${tryStringify2(args.response)}`
3005
3878
  }
3006
3879
  async function runWorkflowCall(args, task) {
3007
3880
  const ctx = getHookContext();
3008
- (0, import_core7.throwIfExecutionAborted)(ctx.node.abortSignal);
3881
+ (0, import_core8.throwIfExecutionAborted)(ctx.node.abortSignal);
3009
3882
  const service = ctx.node.callWorkflow;
3010
3883
  if (!service)
3011
- throw new import_errors62.WorkflowContractError(
3884
+ throw new import_errors8.WorkflowContractError(
3012
3885
  "useWorkflow requires an agent workflow registry."
3013
3886
  );
3014
3887
  if (!args.id.trim())
3015
- throw new import_errors62.WorkflowContractError(
3888
+ throw new import_errors8.WorkflowContractError(
3016
3889
  "useWorkflow requires a stable, nonempty id."
3017
3890
  );
3018
3891
  if (ctx.workflowCallActive && !task.group)
3019
- throw new import_errors62.WorkflowContractError(
3892
+ throw new import_errors8.WorkflowContractError(
3020
3893
  "Concurrent workflow calls require parallel([...]); otherwise await each call."
3021
3894
  );
3022
3895
  if (ctx.workflowCallIds.has(args.id))
3023
- throw new import_errors62.WorkflowContractError(
3896
+ throw new import_errors8.WorkflowContractError(
3024
3897
  `Duplicate workflow call id '${args.id}' in one node activation.`
3025
3898
  );
3026
3899
  if (ctx.workflowCallIds.size >= 64)
3027
- throw new import_errors62.WorkflowContractError(
3900
+ throw new import_errors8.WorkflowContractError(
3028
3901
  "A node may call at most 64 child workflows per activation."
3029
3902
  );
3030
3903
  ctx.workflowCallIds.add(args.id);
@@ -3051,7 +3924,7 @@ ${tryStringify2(args.response)}`
3051
3924
  if (!record) ctx.node.consumeExecution?.("maxChildInvocations");
3052
3925
  record ??= {
3053
3926
  fingerprint,
3054
- invocationId: (0, import_node_crypto5.randomUUID)(),
3927
+ invocationId: (0, import_node_crypto6.randomUUID)(),
3055
3928
  status: "running",
3056
3929
  interrupts: [],
3057
3930
  ...task.group ? { parallelKey: task.group.key } : {}
@@ -3061,7 +3934,7 @@ ${tryStringify2(args.response)}`
3061
3934
  if (!task.group) ctx.workflowCallActive = true;
3062
3935
  const telemetry = ctx.node.workflowCallTelemetry;
3063
3936
  const activationKey = "__useWorkflowActivation";
3064
- ctx.currentNodeState.byKey[activationKey] ??= (0, import_node_crypto5.randomUUID)();
3937
+ ctx.currentNodeState.byKey[activationKey] ??= (0, import_node_crypto6.randomUUID)();
3065
3938
  const callerNodeExecutionId = ctx.currentNodeState.byKey[activationKey];
3066
3939
  const metadata2 = {
3067
3940
  invocationId: record.invocationId,
@@ -3105,7 +3978,7 @@ ${tryStringify2(args.response)}`
3105
3978
  workflow,
3106
3979
  record.error ?? "child failed",
3107
3980
  void 0,
3108
- record.failure ?? (0, import_errors62.serializeFailure)(void 0)
3981
+ record.failure ?? (0, import_errors8.serializeFailure)(void 0)
3109
3982
  );
3110
3983
  if (task.group && record.status === "interrupted" && record.interrupts.at(-1)?.response === void 0)
3111
3984
  throw new ParallelChildWaiting();
@@ -3129,9 +4002,9 @@ ${tryStringify2(args.response)}`
3129
4002
  } catch (error) {
3130
4003
  const child = error;
3131
4004
  recordUsage(child?.__kortyxChildUsage);
3132
- (0, import_core7.throwIfExecutionAborted)(ctx.node.abortSignal);
3133
- if ((0, import_core7.isExecutionCancelled)(error)) throw error;
3134
- if ((0, import_core7.isExecutionLimitReached)(error)) {
4005
+ (0, import_core8.throwIfExecutionAborted)(ctx.node.abortSignal);
4006
+ if ((0, import_core8.isExecutionCancelled)(error)) throw error;
4007
+ if ((0, import_core8.isExecutionLimitReached)(error)) {
3135
4008
  if (child?.__kortyxChildSnapshot)
3136
4009
  record.snapshot = child.__kortyxChildSnapshot;
3137
4010
  report("suspended", {
@@ -3141,7 +4014,7 @@ ${tryStringify2(args.response)}`
3141
4014
  throw error;
3142
4015
  }
3143
4016
  record.status = "failed";
3144
- record.failure = (0, import_errors62.serializeFailure)(error);
4017
+ record.failure = (0, import_errors8.serializeFailure)(error);
3145
4018
  record.error = record.failure.message;
3146
4019
  report("failed", { error: "Child workflow failed" });
3147
4020
  throw new WorkflowCallError(
@@ -3151,12 +4024,15 @@ ${tryStringify2(args.response)}`
3151
4024
  record.failure
3152
4025
  );
3153
4026
  }
3154
- (0, import_core7.throwIfExecutionAborted)(ctx.node.abortSignal);
4027
+ (0, import_core8.throwIfExecutionAborted)(ctx.node.abortSignal);
3155
4028
  recordUsage(outcome.usage);
3156
4029
  if (outcome.status === "completed") {
3157
4030
  record.data = outcome.data;
3158
4031
  workflowCallFingerprint(record.data);
3159
4032
  record.status = "completed";
4033
+ record.toolObservations = outcome.toolObservations ?? [];
4034
+ for (const observation of record.toolObservations)
4035
+ rememberToolObservation(observation);
3160
4036
  delete record.snapshot;
3161
4037
  report(
3162
4038
  "completed",
@@ -3179,8 +4055,12 @@ ${tryStringify2(args.response)}`
3179
4055
  });
3180
4056
  }
3181
4057
  }
3182
- if (cached)
4058
+ if (cached) {
3183
4059
  report("reused", workflowCallContent(telemetry, "output", record.data));
4060
+ if (record.restoredToolBranch !== telemetry?.correlation?.branchId)
4061
+ await replayToolObservations(record.toolObservations ?? [], true);
4062
+ delete record.restoredToolBranch;
4063
+ }
3184
4064
  const data = record.data ?? {};
3185
4065
  return {
3186
4066
  data: JSON.parse(JSON.stringify(data))
@@ -3417,6 +4297,7 @@ var ExecutionRequestError = class extends import_errors2.KortyxError {
3417
4297
  var import_node_stream = require("stream");
3418
4298
  var import_core2 = require("@kortyx/core");
3419
4299
  var import_errors4 = require("@kortyx/core/errors");
4300
+ var import_internal = __toESM(require_internal());
3420
4301
  var import_runtime = require("@kortyx/runtime");
3421
4302
  var import_langgraph = require("@langchain/langgraph");
3422
4303
 
@@ -3991,7 +4872,9 @@ async function orchestrateGraphStream({
3991
4872
  let structuredSeq = 0;
3992
4873
  const debugEnabled = Boolean(config?.features?.tracing);
3993
4874
  const traceAdapter = getTraceAdapter(config);
3994
- const contextMeta = isRecord3(config.context) ? config.context : {};
4875
+ const contextMeta = (0, import_internal.safeTelemetryMetadata)(
4876
+ isRecord3(config.context) ? { userId: config.context.userId, tenantId: config.context.tenantId } : {}
4877
+ );
3995
4878
  const telemetryConfig = isRecord3(config.telemetry) ? config.telemetry : {};
3996
4879
  const emitResumeFailure = (resumeError) => {
3997
4880
  const interruptId = typeof config.telemetryInterruptId === "string" ? config.telemetryInterruptId : void 0;
@@ -4027,8 +4910,13 @@ async function orchestrateGraphStream({
4027
4910
  ...isRecord3(telemetryConfig.metadata) ? telemetryConfig.metadata : {},
4028
4911
  ...contextMeta
4029
4912
  },
4030
- tags: Array.isArray(telemetryConfig.tags) ? telemetryConfig.tags : void 0,
4031
- captureContent: telemetryConfig.captureContent,
4913
+ tags: Array.isArray(telemetryConfig.tags) ? telemetryConfig.tags.filter(
4914
+ (tag) => typeof tag === "string"
4915
+ ) : void 0,
4916
+ captureContent: typeof telemetryConfig.captureContent === "boolean" ? telemetryConfig.captureContent : isRecord3(telemetryConfig.captureContent) ? {
4917
+ ...typeof telemetryConfig.captureContent.input === "boolean" ? { input: telemetryConfig.captureContent.input } : {},
4918
+ ...typeof telemetryConfig.captureContent.output === "boolean" ? { output: telemetryConfig.captureContent.output } : {}
4919
+ } : void 0,
4032
4920
  input: typeof state.input === "string" ? state.input : JSON.stringify(state.input)
4033
4921
  }
4034
4922
  };
@@ -4784,24 +5672,28 @@ async function orchestrateGraphStream({
4784
5672
  }
4785
5673
  };
4786
5674
  const emitTraceChunk = () => {
4787
- const traceContext = traceAdapter?.getActiveContext?.();
4788
- if (!traceContext) return;
4789
- write({
4790
- type: "trace",
4791
- traceId: traceContext.traceId,
4792
- spanId: traceContext.spanId,
4793
- runId,
4794
- rootSpanName: "kortyx.run"
4795
- });
5675
+ try {
5676
+ const traceContext = traceAdapter?.getActiveContext?.();
5677
+ if (!traceContext) return;
5678
+ write({
5679
+ type: "trace",
5680
+ traceId: traceContext.traceId,
5681
+ spanId: traceContext.spanId,
5682
+ runId,
5683
+ rootSpanName: "kortyx.run"
5684
+ });
5685
+ } catch {
5686
+ }
4796
5687
  };
4797
- const fallbackRunSpan = traceAdapter?.withSpan ? void 0 : traceAdapter?.startSpan?.(runSpanArgs);
5688
+ let fallbackRunSpan;
4798
5689
  if (!traceAdapter?.withSpan) {
5690
+ fallbackRunSpan = (0, import_internal.safeStartSpan)(traceAdapter, runSpanArgs);
4799
5691
  emitTraceChunk();
4800
5692
  }
4801
- const startRun = () => traceAdapter?.withSpan ? traceAdapter.withSpan(runSpanArgs, (runTraceSpan) => {
5693
+ const startRun = () => traceAdapter?.withSpan ? (0, import_internal.withSafeTraceSpan)(traceAdapter, runSpanArgs, async (runTraceSpan) => {
4802
5694
  emitTraceChunk();
4803
5695
  return runLoop(runTraceSpan);
4804
- }) : runLoop(fallbackRunSpan ?? {});
5696
+ }) : runLoop(fallbackRunSpan);
4805
5697
  const runPromise = frameworkAdapter?.acquireRunLease && !releaseLease ? frameworkAdapter.acquireRunLease({
4806
5698
  runId,
4807
5699
  ...sessionId ? { sessionId } : {},
@@ -5564,6 +6456,7 @@ var import_hooks = __toESM(require_dist());
5564
6456
  function restoreWorkflowCallBranch(requests, telemetry, sourceRunId) {
5565
6457
  const branchId = (0, import_node_crypto3.randomUUID)();
5566
6458
  const emitted = /* @__PURE__ */ new Set();
6459
+ const toolEvidence = /* @__PURE__ */ new Set();
5567
6460
  for (const request of requests) {
5568
6461
  if (request.state)
5569
6462
  request.state.config = {
@@ -5601,6 +6494,52 @@ function restoreWorkflowCallBranch(requests, telemetry, sourceRunId) {
5601
6494
  status: record.status
5602
6495
  }
5603
6496
  );
6497
+ if (record.status === "completed" && Array.isArray(record.toolObservations)) {
6498
+ if (telemetry?.reporter && telemetry.environment && telemetry.service)
6499
+ record.restoredToolBranch = branchId;
6500
+ for (const original of record.toolObservations) {
6501
+ const key = JSON.stringify([
6502
+ original.invocationId,
6503
+ original.toolCallId,
6504
+ original.attemptId
6505
+ ]);
6506
+ if (toolEvidence.has(key)) continue;
6507
+ toolEvidence.add(key);
6508
+ const payload = {
6509
+ ...original,
6510
+ runId: request.runId,
6511
+ branchId,
6512
+ attemptId: (0, import_node_crypto3.randomUUID)(),
6513
+ executed: false,
6514
+ durationMs: void 0,
6515
+ observationKind: "reused",
6516
+ source: original.source ?? {
6517
+ runId: original.runId ?? sourceRunId,
6518
+ invocationId: original.invocationId,
6519
+ branchId: original.branchId,
6520
+ toolCallId: original.toolCallId,
6521
+ attemptId: original.attemptId
6522
+ }
6523
+ };
6524
+ (0, import_hooks.emitWorkflowCall)(
6525
+ telemetry ? {
6526
+ ...telemetry,
6527
+ correlation: {
6528
+ runId: request.runId,
6529
+ sessionId: request.sessionId,
6530
+ workflowId: original.workflowId ?? request.workflow,
6531
+ nodeId: original.nodeId,
6532
+ workflowRevisionId: original.workflowRevisionId,
6533
+ invocationId: original.invocationId,
6534
+ parentInvocationId: original.parentInvocationId,
6535
+ branchId
6536
+ }
6537
+ } : void 0,
6538
+ "tool.reused",
6539
+ payload
6540
+ );
6541
+ }
6542
+ }
5604
6543
  }
5605
6544
  }
5606
6545
  }