@kortyx/agent 0.23.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/CHANGELOG.md +34 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1555 -565
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
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;
|
|
@@ -347,17 +797,95 @@ var require_dist = __commonJS({
|
|
|
347
797
|
...resumeStatePatch,
|
|
348
798
|
...ctx.tokenUsage ? { tokenUsage: ctx.tokenUsage } : {}
|
|
349
799
|
}
|
|
350
|
-
}
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
const raw = ctx.node.awaitInterrupt(enrichedRequest);
|
|
803
|
+
const response = parseWithSchema(
|
|
804
|
+
args.responseSchema,
|
|
805
|
+
raw,
|
|
806
|
+
"useInterrupt response"
|
|
807
|
+
);
|
|
808
|
+
return Promise.resolve(response);
|
|
809
|
+
};
|
|
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;
|
|
351
860
|
};
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
)
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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
|
|
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,
|
|
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
|
|
505
|
-
(0,
|
|
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
|
-
...
|
|
1408
|
+
...tools2 !== void 0 ? { tools: tools2 } : {},
|
|
515
1409
|
...providerOptions !== void 0 ? { providerOptions } : {}
|
|
516
1410
|
});
|
|
517
|
-
if (
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1862
|
-
var
|
|
1863
|
-
var toToolDefinitions = (
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
throw new Error(
|
|
1942
|
-
`useReason received duplicate tool name "${tool.name}".`
|
|
1943
|
-
);
|
|
1944
|
-
}
|
|
1945
|
-
toolByName.set(tool.name, tool);
|
|
1946
|
-
}
|
|
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
|
-
);
|
|
2811
|
+
for (const tool of tools2) {
|
|
2812
|
+
if (toolByName.has(tool.name)) {
|
|
2813
|
+
throw new Error(`useReason received duplicate tool name "${tool.name}".`);
|
|
1951
2814
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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,
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
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,
|
|
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,
|
|
2240
|
-
if ((0,
|
|
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,
|
|
2245
|
-
failure: (0,
|
|
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
|
|
3256
|
+
async function runReason(args) {
|
|
2364
3257
|
assertReasoningThoughtsCompatibility(args);
|
|
2365
3258
|
const ctx = getHookContext();
|
|
2366
|
-
const abortSignal = (0,
|
|
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,
|
|
3264
|
+
(0, import_core62.throwIfExecutionAborted)(abortSignal);
|
|
2372
3265
|
const allowValidatedToolOutput = Boolean(
|
|
2373
3266
|
args.outputSchema && !(args.responseFormat ?? args.model.options?.responseFormat)
|
|
2374
3267
|
);
|
|
@@ -2390,287 +3283,304 @@ ${tryStringify2(args.response)}`
|
|
|
2390
3283
|
const existingCompleted = readReasonCompletedCheckpoint(
|
|
2391
3284
|
ctx.currentNodeState.byKey[checkpointKey]
|
|
2392
3285
|
);
|
|
2393
|
-
if (existingCompleted) {
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
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
|
-
});
|
|
3286
|
+
if (existingCompleted) {
|
|
3287
|
+
await replayToolObservations(
|
|
3288
|
+
existingCompleted.result.steps?.flatMap(
|
|
3289
|
+
(step) => step.toolObservations ?? []
|
|
3290
|
+
) ?? []
|
|
3291
|
+
);
|
|
3292
|
+
return existingCompleted.result;
|
|
2434
3293
|
}
|
|
2435
|
-
const
|
|
2436
|
-
|
|
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)
|
|
3294
|
+
const existingCheckpoint = readReasonCheckpoint(
|
|
3295
|
+
ctx.currentNodeState.byKey[checkpointKey]
|
|
2441
3296
|
);
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
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
|
-
} : {}
|
|
3297
|
+
const reasonMeta = typeof id === "string" ? { id, opId } : { opId };
|
|
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
|
-
|
|
2479
|
-
|
|
2480
|
-
input: args.input
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
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
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
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
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
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
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
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
|
-
|
|
2624
|
-
...
|
|
2625
|
-
...
|
|
2626
|
-
|
|
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
|
|
2729
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
2896
|
-
var
|
|
2897
|
-
var
|
|
2898
|
-
var
|
|
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,
|
|
2938
|
-
failure ?? cause ?? new
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
3881
|
+
(0, import_core8.throwIfExecutionAborted)(ctx.node.abortSignal);
|
|
3009
3882
|
const service = ctx.node.callWorkflow;
|
|
3010
3883
|
if (!service)
|
|
3011
|
-
throw new
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
3133
|
-
if ((0,
|
|
3134
|
-
if ((0,
|
|
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,
|
|
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,
|
|
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
|
|
|
@@ -3894,7 +4775,8 @@ async function orchestrateGraphStream({
|
|
|
3894
4775
|
onOutcome,
|
|
3895
4776
|
selectWorkflow,
|
|
3896
4777
|
knownWorkflowIds,
|
|
3897
|
-
frameworkAdapter
|
|
4778
|
+
frameworkAdapter,
|
|
4779
|
+
executionLeaseRelease
|
|
3898
4780
|
}) {
|
|
3899
4781
|
const out = new import_node_stream.PassThrough({ objectMode: true });
|
|
3900
4782
|
const write = (chunk) => {
|
|
@@ -3912,11 +4794,13 @@ async function orchestrateGraphStream({
|
|
|
3912
4794
|
let currentGraph = graph;
|
|
3913
4795
|
let currentState = state;
|
|
3914
4796
|
let finished = false;
|
|
4797
|
+
const leaseAbort = new AbortController();
|
|
4798
|
+
let releaseLease = executionLeaseRelease;
|
|
3915
4799
|
const response = createResponseLifecycle({
|
|
3916
4800
|
enabled: emitOutput,
|
|
3917
4801
|
restored: initialConfig.responseCompleted === true,
|
|
3918
4802
|
requestSignal,
|
|
3919
|
-
executionSignal,
|
|
4803
|
+
executionSignal: executionSignal ? AbortSignal.any([executionSignal, leaseAbort.signal]) : leaseAbort.signal,
|
|
3920
4804
|
onClosed: () => {
|
|
3921
4805
|
out.write({ type: "done" });
|
|
3922
4806
|
out.end();
|
|
@@ -3988,7 +4872,9 @@ async function orchestrateGraphStream({
|
|
|
3988
4872
|
let structuredSeq = 0;
|
|
3989
4873
|
const debugEnabled = Boolean(config?.features?.tracing);
|
|
3990
4874
|
const traceAdapter = getTraceAdapter(config);
|
|
3991
|
-
const contextMeta =
|
|
4875
|
+
const contextMeta = (0, import_internal.safeTelemetryMetadata)(
|
|
4876
|
+
isRecord3(config.context) ? { userId: config.context.userId, tenantId: config.context.tenantId } : {}
|
|
4877
|
+
);
|
|
3992
4878
|
const telemetryConfig = isRecord3(config.telemetry) ? config.telemetry : {};
|
|
3993
4879
|
const emitResumeFailure = (resumeError) => {
|
|
3994
4880
|
const interruptId = typeof config.telemetryInterruptId === "string" ? config.telemetryInterruptId : void 0;
|
|
@@ -4024,8 +4910,13 @@ async function orchestrateGraphStream({
|
|
|
4024
4910
|
...isRecord3(telemetryConfig.metadata) ? telemetryConfig.metadata : {},
|
|
4025
4911
|
...contextMeta
|
|
4026
4912
|
},
|
|
4027
|
-
tags: Array.isArray(telemetryConfig.tags) ? telemetryConfig.tags
|
|
4028
|
-
|
|
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,
|
|
4029
4920
|
input: typeof state.input === "string" ? state.input : JSON.stringify(state.input)
|
|
4030
4921
|
}
|
|
4031
4922
|
};
|
|
@@ -4781,24 +5672,36 @@ async function orchestrateGraphStream({
|
|
|
4781
5672
|
}
|
|
4782
5673
|
};
|
|
4783
5674
|
const emitTraceChunk = () => {
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
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
|
+
}
|
|
4793
5687
|
};
|
|
4794
|
-
|
|
5688
|
+
let fallbackRunSpan;
|
|
4795
5689
|
if (!traceAdapter?.withSpan) {
|
|
5690
|
+
fallbackRunSpan = (0, import_internal.safeStartSpan)(traceAdapter, runSpanArgs);
|
|
4796
5691
|
emitTraceChunk();
|
|
4797
5692
|
}
|
|
4798
|
-
const
|
|
5693
|
+
const startRun = () => traceAdapter?.withSpan ? (0, import_internal.withSafeTraceSpan)(traceAdapter, runSpanArgs, async (runTraceSpan) => {
|
|
4799
5694
|
emitTraceChunk();
|
|
4800
5695
|
return runLoop(runTraceSpan);
|
|
4801
|
-
}) : runLoop(fallbackRunSpan
|
|
5696
|
+
}) : runLoop(fallbackRunSpan);
|
|
5697
|
+
const runPromise = frameworkAdapter?.acquireRunLease && !releaseLease ? frameworkAdapter.acquireRunLease({
|
|
5698
|
+
runId,
|
|
5699
|
+
...sessionId ? { sessionId } : {},
|
|
5700
|
+
onLost: (cause) => leaseAbort.abort(cause)
|
|
5701
|
+
}).then((release) => {
|
|
5702
|
+
releaseLease = release;
|
|
5703
|
+
return startRun();
|
|
5704
|
+
}) : startRun();
|
|
4802
5705
|
const finishCancelled = async () => {
|
|
4803
5706
|
emitTelemetryEvent({
|
|
4804
5707
|
config,
|
|
@@ -4962,7 +5865,12 @@ async function orchestrateGraphStream({
|
|
|
4962
5865
|
write({ type: "done" });
|
|
4963
5866
|
finished = true;
|
|
4964
5867
|
out.end();
|
|
4965
|
-
}).finally(() => {
|
|
5868
|
+
}).finally(async () => {
|
|
5869
|
+
try {
|
|
5870
|
+
await releaseLease?.();
|
|
5871
|
+
} catch (error) {
|
|
5872
|
+
console.error("[execution:releaseLease]", (0, import_errors4.serializeFailure)(error));
|
|
5873
|
+
}
|
|
4966
5874
|
response.dispose();
|
|
4967
5875
|
onOutcome?.({
|
|
4968
5876
|
state: outcomeState,
|
|
@@ -5023,7 +5931,7 @@ async function tryPrepareResumeStream({
|
|
|
5023
5931
|
if (!meta) return null;
|
|
5024
5932
|
const store = frameworkAdapter?.pendingRequests;
|
|
5025
5933
|
if (!store) return null;
|
|
5026
|
-
|
|
5934
|
+
let pending = await store.get(meta.token);
|
|
5027
5935
|
if (!pending || pending.requestId !== meta.requestId) {
|
|
5028
5936
|
throw new ExecutionRequestError(
|
|
5029
5937
|
"INVALID_RESUME",
|
|
@@ -5053,34 +5961,48 @@ async function tryPrepareResumeStream({
|
|
|
5053
5961
|
yield { type: "done" };
|
|
5054
5962
|
})();
|
|
5055
5963
|
}
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
"Interrupt has already been resumed or cancelled."
|
|
5060
|
-
);
|
|
5061
|
-
if (meta.cancel) {
|
|
5062
|
-
await store.delete(pending.token);
|
|
5063
|
-
emitTelemetryEvent({
|
|
5064
|
-
config,
|
|
5065
|
-
type: "interrupt.cancelled",
|
|
5066
|
-
correlation: {
|
|
5067
|
-
runId: pending.runId,
|
|
5068
|
-
sessionId,
|
|
5069
|
-
workflowId: pending.workflow,
|
|
5070
|
-
nodeId: pending.node
|
|
5071
|
-
},
|
|
5072
|
-
payload: {
|
|
5073
|
-
interruptId: pending.requestId,
|
|
5074
|
-
reason: "cancelled_by_client"
|
|
5075
|
-
},
|
|
5076
|
-
flush: true
|
|
5077
|
-
});
|
|
5078
|
-
onOutcome?.({ state: pending.state, cancelled: true });
|
|
5079
|
-
return (async function* () {
|
|
5080
|
-
yield { type: "done" };
|
|
5081
|
-
})();
|
|
5082
|
-
}
|
|
5964
|
+
const leaseAbort = new AbortController();
|
|
5965
|
+
let releaseLease;
|
|
5966
|
+
let consumed = false;
|
|
5083
5967
|
try {
|
|
5968
|
+
releaseLease = await frameworkAdapter?.acquireRunLease?.({
|
|
5969
|
+
runId: pending.runId,
|
|
5970
|
+
sessionId,
|
|
5971
|
+
onLost: (cause) => leaseAbort.abort(cause)
|
|
5972
|
+
});
|
|
5973
|
+
leaseAbort.signal.throwIfAborted();
|
|
5974
|
+
if (store.take) {
|
|
5975
|
+
const taken = await store.take(meta.token);
|
|
5976
|
+
if (!taken)
|
|
5977
|
+
throw new ExecutionRequestError(
|
|
5978
|
+
"INVALID_RESUME",
|
|
5979
|
+
"Interrupt has already been resumed or cancelled."
|
|
5980
|
+
);
|
|
5981
|
+
pending = taken;
|
|
5982
|
+
}
|
|
5983
|
+
consumed = true;
|
|
5984
|
+
if (meta.cancel) {
|
|
5985
|
+
await store.delete(pending.token);
|
|
5986
|
+
emitTelemetryEvent({
|
|
5987
|
+
config,
|
|
5988
|
+
type: "interrupt.cancelled",
|
|
5989
|
+
correlation: {
|
|
5990
|
+
runId: pending.runId,
|
|
5991
|
+
sessionId,
|
|
5992
|
+
workflowId: pending.workflow,
|
|
5993
|
+
nodeId: pending.node
|
|
5994
|
+
},
|
|
5995
|
+
payload: {
|
|
5996
|
+
interruptId: pending.requestId,
|
|
5997
|
+
reason: "cancelled_by_client"
|
|
5998
|
+
},
|
|
5999
|
+
flush: true
|
|
6000
|
+
});
|
|
6001
|
+
onOutcome?.({ state: pending.state, cancelled: true });
|
|
6002
|
+
return (async function* () {
|
|
6003
|
+
yield { type: "done" };
|
|
6004
|
+
})();
|
|
6005
|
+
}
|
|
5084
6006
|
const resumeData = isLimitPause ? {} : applyResumeSelection ? applyResumeSelection({ pending, selected: meta.selected }) : meta.selected?.length ? { coordinates: String(meta.selected[0]) } : {};
|
|
5085
6007
|
const resumeDataPatch = isRecord4(resumeData) ? resumeData : {};
|
|
5086
6008
|
const pendingMeta = isRecord4(pending.schema?.meta) ? pending.schema.meta : {};
|
|
@@ -5135,6 +6057,7 @@ async function tryPrepareResumeStream({
|
|
|
5135
6057
|
...resumeStatePatch
|
|
5136
6058
|
};
|
|
5137
6059
|
}
|
|
6060
|
+
leaseAbort.signal.throwIfAborted();
|
|
5138
6061
|
if (pending.graphSnapshot && frameworkAdapter)
|
|
5139
6062
|
await (0, import_runtime2.restoreGraphSnapshot)(
|
|
5140
6063
|
frameworkAdapter.checkpointer,
|
|
@@ -5184,9 +6107,11 @@ async function tryPrepareResumeStream({
|
|
|
5184
6107
|
},
|
|
5185
6108
|
flush: true
|
|
5186
6109
|
});
|
|
6110
|
+
const continuedSignal = pending.responseCompleted && emitOutput === false ? abortSignal : executionSignal;
|
|
5187
6111
|
const args = {
|
|
5188
6112
|
abortSignal,
|
|
5189
|
-
executionSignal:
|
|
6113
|
+
executionSignal: continuedSignal ? AbortSignal.any([continuedSignal, leaseAbort.signal]) : leaseAbort.signal,
|
|
6114
|
+
executionLeaseRelease: releaseLease,
|
|
5190
6115
|
onExecution,
|
|
5191
6116
|
emitOutput,
|
|
5192
6117
|
onOutcome,
|
|
@@ -5207,11 +6132,15 @@ async function tryPrepareResumeStream({
|
|
|
5207
6132
|
knownWorkflowIds,
|
|
5208
6133
|
frameworkAdapter
|
|
5209
6134
|
};
|
|
6135
|
+
leaseAbort.signal.throwIfAborted();
|
|
5210
6136
|
const stream = await orchestrateGraphStream(args);
|
|
6137
|
+
releaseLease = void 0;
|
|
5211
6138
|
return stream;
|
|
5212
6139
|
} catch (error) {
|
|
5213
|
-
await store.save(pending);
|
|
6140
|
+
if (consumed && !leaseAbort.signal.aborted) await store.save(pending);
|
|
5214
6141
|
throw error;
|
|
6142
|
+
} finally {
|
|
6143
|
+
await releaseLease?.();
|
|
5215
6144
|
}
|
|
5216
6145
|
}
|
|
5217
6146
|
|
|
@@ -5527,6 +6456,7 @@ var import_hooks = __toESM(require_dist());
|
|
|
5527
6456
|
function restoreWorkflowCallBranch(requests, telemetry, sourceRunId) {
|
|
5528
6457
|
const branchId = (0, import_node_crypto3.randomUUID)();
|
|
5529
6458
|
const emitted = /* @__PURE__ */ new Set();
|
|
6459
|
+
const toolEvidence = /* @__PURE__ */ new Set();
|
|
5530
6460
|
for (const request of requests) {
|
|
5531
6461
|
if (request.state)
|
|
5532
6462
|
request.state.config = {
|
|
@@ -5564,6 +6494,52 @@ function restoreWorkflowCallBranch(requests, telemetry, sourceRunId) {
|
|
|
5564
6494
|
status: record.status
|
|
5565
6495
|
}
|
|
5566
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
|
+
}
|
|
5567
6543
|
}
|
|
5568
6544
|
}
|
|
5569
6545
|
}
|
|
@@ -5907,30 +6883,38 @@ function createAgent(args) {
|
|
|
5907
6883
|
const getCheckpoint = (id) => resolvedFrameworkAdapter.sessionCheckpoints.get(id);
|
|
5908
6884
|
const rollbackTo = async (id) => {
|
|
5909
6885
|
const target = await resolvedFrameworkAdapter.sessionCheckpoints.get(id);
|
|
5910
|
-
const
|
|
5911
|
-
const
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
activePendingRequests,
|
|
5918
|
-
telemetry,
|
|
5919
|
-
target?.runId ?? "unknown"
|
|
5920
|
-
);
|
|
5921
|
-
await Promise.all(
|
|
5922
|
-
activePendingRequests.map(
|
|
5923
|
-
(request) => clearPendingGraphWrites(resolvedFrameworkAdapter, request)
|
|
5924
|
-
)
|
|
6886
|
+
const sourceRunId = target?.runId ?? "unknown";
|
|
6887
|
+
const managed = resolvedFrameworkAdapter.sessionCheckpoints.managesPendingRequests;
|
|
6888
|
+
const result = await resolvedFrameworkAdapter.sessionCheckpoints.rollbackTo(
|
|
6889
|
+
id,
|
|
6890
|
+
managed ? {
|
|
6891
|
+
preparePendingRequests: (requests) => restoreWorkflowCallBranch(requests, telemetry, sourceRunId)
|
|
6892
|
+
} : void 0
|
|
5925
6893
|
);
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
6894
|
+
let activePendingRequests;
|
|
6895
|
+
if (managed) {
|
|
6896
|
+
activePendingRequests = result.activePendingRequests;
|
|
6897
|
+
} else {
|
|
6898
|
+
activePendingRequests = await Promise.all(
|
|
6899
|
+
result.activePendingRequests.map(
|
|
6900
|
+
(request) => hydratePendingGraphCheckpoint(resolvedFrameworkAdapter, request)
|
|
6901
|
+
)
|
|
6902
|
+
);
|
|
6903
|
+
restoreWorkflowCallBranch(activePendingRequests, telemetry, sourceRunId);
|
|
6904
|
+
await Promise.all(
|
|
6905
|
+
activePendingRequests.map(
|
|
6906
|
+
(request) => clearPendingGraphWrites(resolvedFrameworkAdapter, request)
|
|
6907
|
+
)
|
|
6908
|
+
);
|
|
6909
|
+
await Promise.all([
|
|
6910
|
+
...result.invalidatedInterruptTokens.map(
|
|
6911
|
+
(token) => resolvedFrameworkAdapter.pendingRequests.delete(token)
|
|
6912
|
+
),
|
|
6913
|
+
...activePendingRequests.map(
|
|
6914
|
+
(request) => resolvedFrameworkAdapter.pendingRequests.save(request)
|
|
6915
|
+
)
|
|
6916
|
+
]);
|
|
6917
|
+
}
|
|
5934
6918
|
if (target) {
|
|
5935
6919
|
emitTelemetryEvent({
|
|
5936
6920
|
config: { ...telemetry ? { telemetry } : {} },
|
|
@@ -5950,30 +6934,36 @@ function createAgent(args) {
|
|
|
5950
6934
|
};
|
|
5951
6935
|
const fork = async (id, options) => {
|
|
5952
6936
|
const source = await resolvedFrameworkAdapter.sessionCheckpoints.get(id);
|
|
6937
|
+
const sourceRunId = source?.runId ?? "unknown";
|
|
6938
|
+
const managed = resolvedFrameworkAdapter.sessionCheckpoints.managesPendingRequests;
|
|
5953
6939
|
const result = await resolvedFrameworkAdapter.sessionCheckpoints.fork(
|
|
5954
6940
|
id,
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
(request) => hydratePendingGraphCheckpoint(resolvedFrameworkAdapter, request)
|
|
5960
|
-
)
|
|
5961
|
-
);
|
|
5962
|
-
restoreWorkflowCallBranch(
|
|
5963
|
-
activePendingRequests,
|
|
5964
|
-
telemetry,
|
|
5965
|
-
source?.runId ?? "unknown"
|
|
5966
|
-
);
|
|
5967
|
-
await Promise.all(
|
|
5968
|
-
activePendingRequests.map(
|
|
5969
|
-
(request) => clearPendingGraphWrites(resolvedFrameworkAdapter, request)
|
|
5970
|
-
)
|
|
5971
|
-
);
|
|
5972
|
-
await Promise.all(
|
|
5973
|
-
activePendingRequests.map(
|
|
5974
|
-
(request) => resolvedFrameworkAdapter.pendingRequests.save(request)
|
|
5975
|
-
)
|
|
6941
|
+
managed ? {
|
|
6942
|
+
...options,
|
|
6943
|
+
preparePendingRequests: (requests) => restoreWorkflowCallBranch(requests, telemetry, sourceRunId)
|
|
6944
|
+
} : options
|
|
5976
6945
|
);
|
|
6946
|
+
let activePendingRequests;
|
|
6947
|
+
if (managed) {
|
|
6948
|
+
activePendingRequests = result.checkpoint.activePendingRequests;
|
|
6949
|
+
} else {
|
|
6950
|
+
activePendingRequests = await Promise.all(
|
|
6951
|
+
result.checkpoint.activePendingRequests.map(
|
|
6952
|
+
(request) => hydratePendingGraphCheckpoint(resolvedFrameworkAdapter, request)
|
|
6953
|
+
)
|
|
6954
|
+
);
|
|
6955
|
+
restoreWorkflowCallBranch(activePendingRequests, telemetry, sourceRunId);
|
|
6956
|
+
await Promise.all(
|
|
6957
|
+
activePendingRequests.map(
|
|
6958
|
+
(request) => clearPendingGraphWrites(resolvedFrameworkAdapter, request)
|
|
6959
|
+
)
|
|
6960
|
+
);
|
|
6961
|
+
await Promise.all(
|
|
6962
|
+
activePendingRequests.map(
|
|
6963
|
+
(request) => resolvedFrameworkAdapter.pendingRequests.save(request)
|
|
6964
|
+
)
|
|
6965
|
+
);
|
|
6966
|
+
}
|
|
5977
6967
|
emitTelemetryEvent({
|
|
5978
6968
|
config: { ...telemetry ? { telemetry } : {} },
|
|
5979
6969
|
type: "session.forked",
|