@kortyx/hooks 0.18.0 → 0.21.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 +45 -0
- package/README.md +28 -0
- package/dist/index.d.ts +71 -4
- package/dist/index.js +326 -7
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +8 -2
- package/dist/internal.js.map +1 -1
- package/dist/{tracing-DeYHBpY1.d.ts → tracing-BI6YKHSf.d.ts} +4 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -19,13 +19,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
// src/index.ts
|
|
20
20
|
var index_exports = {};
|
|
21
21
|
__export(index_exports, {
|
|
22
|
+
WorkflowCallError: () => WorkflowCallError,
|
|
23
|
+
createWorkflowHooks: () => createWorkflowHooks,
|
|
24
|
+
emitWorkflowCall: () => emitWorkflowCall,
|
|
22
25
|
runWithHookContext: () => runWithHookContext,
|
|
26
|
+
useAbortSignal: () => useAbortSignal,
|
|
23
27
|
useInterrupt: () => useInterrupt,
|
|
24
28
|
useNodeState: () => useNodeState,
|
|
25
29
|
useReason: () => useReason2,
|
|
26
30
|
useRuntimeContext: () => useRuntimeContext,
|
|
27
31
|
useStructuredData: () => useStructuredData,
|
|
28
|
-
|
|
32
|
+
useWorkflow: () => useWorkflow,
|
|
33
|
+
useWorkflowState: () => useWorkflowState,
|
|
34
|
+
workflowCallFingerprint: () => workflowCallFingerprint
|
|
29
35
|
});
|
|
30
36
|
module.exports = __toCommonJS(index_exports);
|
|
31
37
|
|
|
@@ -78,6 +84,8 @@ var createInternalContext = (ctx) => {
|
|
|
78
84
|
const currentNodeState = storedNodeId && storedNodeId === nodeId ? normalizeNodeState(storedState) : { byIndex: [], byKey: {} };
|
|
79
85
|
return {
|
|
80
86
|
...ctx,
|
|
87
|
+
workflowCallActive: false,
|
|
88
|
+
workflowCallIds: /* @__PURE__ */ new Set(),
|
|
81
89
|
nodeStateIndex: 0,
|
|
82
90
|
reasonCallIndex: 0,
|
|
83
91
|
currentNodeState,
|
|
@@ -151,6 +159,12 @@ async function runWithHookContext(ctx, fn) {
|
|
|
151
159
|
try {
|
|
152
160
|
const result = await storage.run(internal, fn);
|
|
153
161
|
cleanupCompletedReasonCheckpoints(internal);
|
|
162
|
+
for (const key of Object.keys(internal.currentNodeState.byKey)) {
|
|
163
|
+
if (key.startsWith("__useWorkflow:") || key === "__useWorkflowActivation") {
|
|
164
|
+
internal.currentNodeState.byKey[key] = null;
|
|
165
|
+
internal.stateDirty = true;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
154
168
|
return { result, runtimeUpdates: buildRuntimeStateUpdates(internal) };
|
|
155
169
|
} catch (err) {
|
|
156
170
|
const runtimeUpdates = buildRuntimeStateUpdates(internal);
|
|
@@ -175,6 +189,9 @@ function getHookContext() {
|
|
|
175
189
|
return ctx;
|
|
176
190
|
}
|
|
177
191
|
|
|
192
|
+
// src/interrupt.ts
|
|
193
|
+
var import_core = require("@kortyx/core");
|
|
194
|
+
|
|
178
195
|
// src/reason/checkpoint.ts
|
|
179
196
|
var resolveReasonCheckpointKey = (args) => typeof args.id === "string" && args.id.length > 0 ? `__useReason:${args.id}` : `__useReason:auto:${args.autoIndex}`;
|
|
180
197
|
var readReasonCheckpoint = (raw) => {
|
|
@@ -230,6 +247,7 @@ var parseWithSchema = (schema, value, label) => {
|
|
|
230
247
|
// src/interrupt.ts
|
|
231
248
|
var awaitInterruptInternal = (args) => {
|
|
232
249
|
const ctx = getHookContext();
|
|
250
|
+
(0, import_core.throwIfExecutionAborted)(ctx.node.abortSignal);
|
|
233
251
|
const request = parseWithSchema(
|
|
234
252
|
args.requestSchema,
|
|
235
253
|
args.request,
|
|
@@ -248,7 +266,10 @@ var awaitInterruptInternal = (args) => {
|
|
|
248
266
|
...typeof args.id === "string" && args.id.length > 0 ? { id: args.id } : {},
|
|
249
267
|
meta: {
|
|
250
268
|
...userMeta,
|
|
251
|
-
__kortyxResumeStatePatch:
|
|
269
|
+
__kortyxResumeStatePatch: {
|
|
270
|
+
...resumeStatePatch,
|
|
271
|
+
...ctx.tokenUsage ? { tokenUsage: ctx.tokenUsage } : {}
|
|
272
|
+
}
|
|
252
273
|
}
|
|
253
274
|
};
|
|
254
275
|
const raw = ctx.node.awaitInterrupt(enrichedRequest);
|
|
@@ -260,6 +281,9 @@ var awaitInterruptInternal = (args) => {
|
|
|
260
281
|
return Promise.resolve(response);
|
|
261
282
|
};
|
|
262
283
|
|
|
284
|
+
// src/reason/use-reason.ts
|
|
285
|
+
var import_core5 = require("@kortyx/core");
|
|
286
|
+
|
|
263
287
|
// src/structured.ts
|
|
264
288
|
var import_node_crypto = require("crypto");
|
|
265
289
|
|
|
@@ -354,9 +378,11 @@ var shouldStreamStructured = (cfg) => Boolean(cfg) && (cfg?.stream ?? true);
|
|
|
354
378
|
|
|
355
379
|
// src/reason/engine.ts
|
|
356
380
|
var import_node_crypto3 = require("crypto");
|
|
381
|
+
var import_core3 = require("@kortyx/core");
|
|
357
382
|
|
|
358
383
|
// src/reason-engine.ts
|
|
359
384
|
var import_node_crypto2 = require("crypto");
|
|
385
|
+
var import_core2 = require("@kortyx/core");
|
|
360
386
|
var toError = (value) => value instanceof Error ? value : new Error(String(value));
|
|
361
387
|
var createRuntimeId = () => {
|
|
362
388
|
try {
|
|
@@ -383,6 +409,7 @@ async function runReasonEngine(args) {
|
|
|
383
409
|
const responseFormat = args.responseFormat ?? args.model.options?.responseFormat;
|
|
384
410
|
const providerOptions = args.providerOptions ?? args.model.options?.providerOptions;
|
|
385
411
|
const tools = args.tools ?? args.model.options?.tools;
|
|
412
|
+
(0, import_core2.throwIfExecutionAborted)(abortSignal);
|
|
386
413
|
const model = args.model.provider.getModel(args.model.modelId, {
|
|
387
414
|
...temperature !== void 0 ? { temperature } : {},
|
|
388
415
|
streaming: stream,
|
|
@@ -475,6 +502,7 @@ async function runReasonEngine(args) {
|
|
|
475
502
|
}
|
|
476
503
|
const response2 = await model.stream(messages);
|
|
477
504
|
for await (const chunk of response2) {
|
|
505
|
+
(0, import_core2.throwIfExecutionAborted)(abortSignal);
|
|
478
506
|
switch (chunk.type) {
|
|
479
507
|
case "text-delta": {
|
|
480
508
|
if (chunk.delta.length === 0) break;
|
|
@@ -553,10 +581,12 @@ async function runReasonEngine(args) {
|
|
|
553
581
|
...providerMetadata !== void 0 ? { providerMetadata } : {},
|
|
554
582
|
...warnings !== void 0 ? { warnings } : {}
|
|
555
583
|
};
|
|
584
|
+
(0, import_core2.throwIfExecutionAborted)(abortSignal);
|
|
556
585
|
endTrace(traceSpan, result2);
|
|
557
586
|
return result2;
|
|
558
587
|
}
|
|
559
588
|
const response = await model.invoke(messages);
|
|
589
|
+
(0, import_core2.throwIfExecutionAborted)(abortSignal);
|
|
560
590
|
if (emit) {
|
|
561
591
|
emitNodeEvent(args.emitEvent, args.nodeId, "text-start", {
|
|
562
592
|
...commonMeta
|
|
@@ -583,8 +613,9 @@ async function runReasonEngine(args) {
|
|
|
583
613
|
endTrace(traceSpan, result);
|
|
584
614
|
return result;
|
|
585
615
|
} catch (error) {
|
|
586
|
-
|
|
587
|
-
|
|
616
|
+
const failure = abortSignal?.aborted ? (0, import_core2.createExecutionCancelledError)() : error;
|
|
617
|
+
failTrace(traceSpan, failure);
|
|
618
|
+
throw failure;
|
|
588
619
|
}
|
|
589
620
|
}
|
|
590
621
|
|
|
@@ -598,6 +629,13 @@ var createRuntimeId2 = () => {
|
|
|
598
629
|
};
|
|
599
630
|
async function reasonEngine(args, meta, inputOverride) {
|
|
600
631
|
const ctx = getHookContext();
|
|
632
|
+
const abortSignal = (0, import_core3.combineAbortSignals)(
|
|
633
|
+
ctx.node.abortSignal,
|
|
634
|
+
args.abortSignal,
|
|
635
|
+
args.model.options?.abortSignal
|
|
636
|
+
);
|
|
637
|
+
(0, import_core3.throwIfExecutionAborted)(abortSignal);
|
|
638
|
+
ctx.node.consumeExecution?.("maxModelPasses");
|
|
601
639
|
return runReasonEngine({
|
|
602
640
|
model: args.model,
|
|
603
641
|
input: inputOverride ?? args.input,
|
|
@@ -605,7 +643,7 @@ async function reasonEngine(args, meta, inputOverride) {
|
|
|
605
643
|
temperature: args.temperature,
|
|
606
644
|
maxOutputTokens: args.maxOutputTokens,
|
|
607
645
|
stopSequences: args.stopSequences,
|
|
608
|
-
abortSignal
|
|
646
|
+
abortSignal,
|
|
609
647
|
reasoning: args.reasoning,
|
|
610
648
|
responseFormat: args.responseFormat,
|
|
611
649
|
providerOptions: args.providerOptions,
|
|
@@ -1556,6 +1594,7 @@ var extractStreamingStringValues = (args) => {
|
|
|
1556
1594
|
};
|
|
1557
1595
|
|
|
1558
1596
|
// src/reason/tools.ts
|
|
1597
|
+
var import_core4 = require("@kortyx/core");
|
|
1559
1598
|
var toErrorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
1560
1599
|
var toToolDefinitions = (tools) => tools.map((tool) => ({
|
|
1561
1600
|
name: tool.name,
|
|
@@ -1609,6 +1648,11 @@ var createInitialMessages = (args) => [
|
|
|
1609
1648
|
var runReasonToolLoop = async (args) => {
|
|
1610
1649
|
const { useReasonArgs, id, opId, traceSpan } = args;
|
|
1611
1650
|
const ctx = getHookContext();
|
|
1651
|
+
const abortSignal = (0, import_core4.combineAbortSignals)(
|
|
1652
|
+
ctx.node.abortSignal,
|
|
1653
|
+
useReasonArgs.abortSignal,
|
|
1654
|
+
useReasonArgs.model.options?.abortSignal
|
|
1655
|
+
);
|
|
1612
1656
|
const tools = useReasonArgs.tools ?? [];
|
|
1613
1657
|
const toolByName = /* @__PURE__ */ new Map();
|
|
1614
1658
|
let validationCompleted = false;
|
|
@@ -1658,6 +1702,7 @@ var runReasonToolLoop = async (args) => {
|
|
|
1658
1702
|
};
|
|
1659
1703
|
try {
|
|
1660
1704
|
for (let stepIndex = 0; stepIndex < maxSteps; stepIndex += 1) {
|
|
1705
|
+
(0, import_core4.throwIfExecutionAborted)(abortSignal);
|
|
1661
1706
|
traceSpan?.addEvent?.("useReason.tool-step.start", {
|
|
1662
1707
|
stepIndex,
|
|
1663
1708
|
toolCount: toolDefinitions.length
|
|
@@ -1675,6 +1720,7 @@ var runReasonToolLoop = async (args) => {
|
|
|
1675
1720
|
finalText = step.text;
|
|
1676
1721
|
finalRaw = step.raw;
|
|
1677
1722
|
aggregatedUsage = mergeUsage(aggregatedUsage, step.usage);
|
|
1723
|
+
accumulateTokenUsage(step.usage);
|
|
1678
1724
|
finalFinishReason = step.finishReason;
|
|
1679
1725
|
aggregatedProviderMetadata = mergeProviderMetadata(
|
|
1680
1726
|
aggregatedProviderMetadata,
|
|
@@ -1708,6 +1754,7 @@ var runReasonToolLoop = async (args) => {
|
|
|
1708
1754
|
toolCalls
|
|
1709
1755
|
});
|
|
1710
1756
|
for (const toolCall of toolCalls) {
|
|
1757
|
+
(0, import_core4.throwIfExecutionAborted)(abortSignal);
|
|
1711
1758
|
const tool = toolByName.get(toolCall.name);
|
|
1712
1759
|
if (!tool) {
|
|
1713
1760
|
throw new Error(
|
|
@@ -1775,10 +1822,13 @@ var runReasonToolLoop = async (args) => {
|
|
|
1775
1822
|
}
|
|
1776
1823
|
}
|
|
1777
1824
|
try {
|
|
1825
|
+
(0, import_core4.throwIfExecutionAborted)(abortSignal);
|
|
1826
|
+
ctx.node.consumeExecution?.("maxToolCalls");
|
|
1778
1827
|
const rawResult = await tool.execute(toolCall.input, {
|
|
1779
1828
|
toolCallId: toolCall.id,
|
|
1780
|
-
...
|
|
1829
|
+
...abortSignal ? { abortSignal } : {}
|
|
1781
1830
|
});
|
|
1831
|
+
(0, import_core4.throwIfExecutionAborted)(abortSignal);
|
|
1782
1832
|
const result2 = normalizeToolResult(toolCall, rawResult);
|
|
1783
1833
|
toolResults.push(result2);
|
|
1784
1834
|
allToolResults.push(result2);
|
|
@@ -1798,6 +1848,9 @@ var runReasonToolLoop = async (args) => {
|
|
|
1798
1848
|
isError: Boolean(result2.isError)
|
|
1799
1849
|
});
|
|
1800
1850
|
} catch (error) {
|
|
1851
|
+
(0, import_core4.throwIfExecutionAborted)(abortSignal);
|
|
1852
|
+
if ((0, import_core4.isExecutionLimitReached)(error) || (0, import_core4.isExecutionCancelled)(error))
|
|
1853
|
+
throw error;
|
|
1801
1854
|
const result2 = {
|
|
1802
1855
|
toolCallId: toolCall.id,
|
|
1803
1856
|
name: tool.name,
|
|
@@ -1921,6 +1974,13 @@ var assertReasoningThoughtsCompatibility = (args) => {
|
|
|
1921
1974
|
async function useReason(args) {
|
|
1922
1975
|
assertReasoningThoughtsCompatibility(args);
|
|
1923
1976
|
const ctx = getHookContext();
|
|
1977
|
+
const abortSignal = (0, import_core5.combineAbortSignals)(
|
|
1978
|
+
ctx.node.abortSignal,
|
|
1979
|
+
args.abortSignal,
|
|
1980
|
+
args.model.options?.abortSignal
|
|
1981
|
+
);
|
|
1982
|
+
(0, import_core5.throwIfExecutionAborted)(abortSignal);
|
|
1983
|
+
args = { ...args, abortSignal };
|
|
1924
1984
|
const id = typeof args.id === "string" && args.id.length > 0 ? args.id : void 0;
|
|
1925
1985
|
const opId = createRuntimeId2();
|
|
1926
1986
|
const checkpointKey = resolveReasonCheckpointKey({
|
|
@@ -2290,6 +2350,9 @@ function useReason2(args) {
|
|
|
2290
2350
|
function useInterrupt(args) {
|
|
2291
2351
|
return awaitInterruptInternal(args);
|
|
2292
2352
|
}
|
|
2353
|
+
function useAbortSignal() {
|
|
2354
|
+
return getHookContext().node.abortSignal;
|
|
2355
|
+
}
|
|
2293
2356
|
function useRuntimeContext() {
|
|
2294
2357
|
const ctx = getHookContext();
|
|
2295
2358
|
const config = ctx.state.config;
|
|
@@ -2331,14 +2394,270 @@ function useWorkflowState(key, ...rest) {
|
|
|
2331
2394
|
};
|
|
2332
2395
|
return [getValue(), setValue];
|
|
2333
2396
|
}
|
|
2397
|
+
|
|
2398
|
+
// src/workflow.ts
|
|
2399
|
+
var import_node_crypto5 = require("crypto");
|
|
2400
|
+
var import_core6 = require("@kortyx/core");
|
|
2401
|
+
|
|
2402
|
+
// src/workflow-telemetry.ts
|
|
2403
|
+
var import_node_crypto4 = require("crypto");
|
|
2404
|
+
function emitWorkflowCall(telemetry, type, payload) {
|
|
2405
|
+
const base = telemetry?.correlation;
|
|
2406
|
+
if (!telemetry?.reporter || !telemetry.environment || !telemetry.service || !base?.runId || !base.workflowId)
|
|
2407
|
+
return;
|
|
2408
|
+
try {
|
|
2409
|
+
const active = telemetry.trace?.getActiveContext?.();
|
|
2410
|
+
void Promise.resolve(
|
|
2411
|
+
telemetry.reporter.emit([
|
|
2412
|
+
{
|
|
2413
|
+
schemaVersion: 1,
|
|
2414
|
+
eventId: (0, import_node_crypto4.randomUUID)(),
|
|
2415
|
+
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2416
|
+
environment: telemetry.environment,
|
|
2417
|
+
service: telemetry.service,
|
|
2418
|
+
correlation: {
|
|
2419
|
+
...base,
|
|
2420
|
+
runId: base.runId,
|
|
2421
|
+
workflowId: base.workflowId,
|
|
2422
|
+
...active
|
|
2423
|
+
},
|
|
2424
|
+
type,
|
|
2425
|
+
payload
|
|
2426
|
+
}
|
|
2427
|
+
])
|
|
2428
|
+
).catch(() => {
|
|
2429
|
+
});
|
|
2430
|
+
} catch {
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
function workflowCallContent(telemetry, side, value) {
|
|
2434
|
+
const policy = telemetry?.captureContent;
|
|
2435
|
+
if (!(policy === true || policy && typeof policy === "object" && policy[side]))
|
|
2436
|
+
return {};
|
|
2437
|
+
const serialized = JSON.stringify(value);
|
|
2438
|
+
return serialized && Buffer.byteLength(serialized, "utf8") <= 16384 ? { [side]: JSON.parse(serialized) } : { [`${side}Omitted`]: "Content exceeds 16 KiB" };
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
// src/workflow.ts
|
|
2442
|
+
var WorkflowCallError = class extends Error {
|
|
2443
|
+
constructor(workflow, message) {
|
|
2444
|
+
super(`Workflow '${workflow}': ${message}`);
|
|
2445
|
+
this.workflow = workflow;
|
|
2446
|
+
this.name = "WorkflowCallError";
|
|
2447
|
+
}
|
|
2448
|
+
workflow;
|
|
2449
|
+
};
|
|
2450
|
+
function workflowCallFingerprint(value) {
|
|
2451
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2452
|
+
const canonical = (v) => {
|
|
2453
|
+
if (v === null || typeof v === "string" || typeof v === "boolean") return v;
|
|
2454
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
2455
|
+
if (typeof v !== "object" || !v || seen.has(v)) {
|
|
2456
|
+
throw new Error("Workflow input and output must be JSON serializable.");
|
|
2457
|
+
}
|
|
2458
|
+
if (!Array.isArray(v) && Object.getPrototypeOf(v) !== Object.prototype) {
|
|
2459
|
+
throw new Error(
|
|
2460
|
+
"Workflow input and output must contain plain JSON objects."
|
|
2461
|
+
);
|
|
2462
|
+
}
|
|
2463
|
+
seen.add(v);
|
|
2464
|
+
const result = Array.isArray(v) ? v.map(canonical) : Object.fromEntries(
|
|
2465
|
+
Object.keys(v).sort().map((key) => [
|
|
2466
|
+
key,
|
|
2467
|
+
canonical(v[key])
|
|
2468
|
+
])
|
|
2469
|
+
);
|
|
2470
|
+
seen.delete(v);
|
|
2471
|
+
return result;
|
|
2472
|
+
};
|
|
2473
|
+
return JSON.stringify(canonical(value));
|
|
2474
|
+
}
|
|
2475
|
+
function createWorkflowHooks(workflows) {
|
|
2476
|
+
return {
|
|
2477
|
+
useWorkflow: (args) => {
|
|
2478
|
+
const workflow = workflows[args.workflow];
|
|
2479
|
+
if (!workflow || workflow.id !== args.workflow)
|
|
2480
|
+
throw new Error("Workflow registry keys must match definition ids.");
|
|
2481
|
+
return useWorkflow({ ...args, workflow });
|
|
2482
|
+
}
|
|
2483
|
+
};
|
|
2484
|
+
}
|
|
2485
|
+
async function useWorkflow(args) {
|
|
2486
|
+
const ctx = getHookContext();
|
|
2487
|
+
(0, import_core6.throwIfExecutionAborted)(ctx.node.abortSignal);
|
|
2488
|
+
const service = ctx.node.callWorkflow;
|
|
2489
|
+
if (!service)
|
|
2490
|
+
throw new Error("useWorkflow requires an agent workflow registry.");
|
|
2491
|
+
if (!args.id.trim())
|
|
2492
|
+
throw new Error("useWorkflow requires a stable, nonempty id.");
|
|
2493
|
+
if (ctx.workflowCallActive)
|
|
2494
|
+
throw new Error(
|
|
2495
|
+
"Concurrent workflow calls are not supported; await each call."
|
|
2496
|
+
);
|
|
2497
|
+
if (ctx.workflowCallIds.has(args.id))
|
|
2498
|
+
throw new Error(
|
|
2499
|
+
`Duplicate workflow call id '${args.id}' in one node activation.`
|
|
2500
|
+
);
|
|
2501
|
+
if (ctx.workflowCallIds.size >= 64)
|
|
2502
|
+
throw new Error(
|
|
2503
|
+
"A node may call at most 64 child workflows per activation."
|
|
2504
|
+
);
|
|
2505
|
+
ctx.workflowCallIds.add(args.id);
|
|
2506
|
+
const definition = typeof args.workflow === "string" ? void 0 : args.workflow;
|
|
2507
|
+
const workflow = definition?.id ?? args.workflow;
|
|
2508
|
+
const input = args.input;
|
|
2509
|
+
const fingerprint = workflowCallFingerprint({
|
|
2510
|
+
workflow,
|
|
2511
|
+
input,
|
|
2512
|
+
version: definition?.version ?? null
|
|
2513
|
+
});
|
|
2514
|
+
const key = `__useWorkflow:${args.id}`;
|
|
2515
|
+
let record = ctx.currentNodeState.byKey[key];
|
|
2516
|
+
if (record && record.fingerprint !== fingerprint)
|
|
2517
|
+
throw new WorkflowCallError(
|
|
2518
|
+
workflow,
|
|
2519
|
+
"call input or target changed during replay"
|
|
2520
|
+
);
|
|
2521
|
+
if (!record) ctx.node.consumeExecution?.("maxChildInvocations");
|
|
2522
|
+
record ??= {
|
|
2523
|
+
fingerprint,
|
|
2524
|
+
invocationId: (0, import_node_crypto5.randomUUID)(),
|
|
2525
|
+
status: "running",
|
|
2526
|
+
interrupts: []
|
|
2527
|
+
};
|
|
2528
|
+
ctx.currentNodeState.byKey[key] = record;
|
|
2529
|
+
ctx.stateDirty = true;
|
|
2530
|
+
ctx.workflowCallActive = true;
|
|
2531
|
+
const telemetry = ctx.node.workflowCallTelemetry;
|
|
2532
|
+
const activationKey = "__useWorkflowActivation";
|
|
2533
|
+
ctx.currentNodeState.byKey[activationKey] ??= (0, import_node_crypto5.randomUUID)();
|
|
2534
|
+
const callerNodeExecutionId = ctx.currentNodeState.byKey[activationKey];
|
|
2535
|
+
const metadata = {
|
|
2536
|
+
invocationId: record.invocationId,
|
|
2537
|
+
parentInvocationId: telemetry?.correlation?.invocationId ?? null,
|
|
2538
|
+
branchId: telemetry?.correlation?.branchId ?? telemetry?.correlation?.runId ?? "unknown",
|
|
2539
|
+
callId: args.id,
|
|
2540
|
+
callerNodeId: ctx.node.graph.node,
|
|
2541
|
+
callerNodeExecutionId,
|
|
2542
|
+
sourceWorkflowId: ctx.node.graph.name,
|
|
2543
|
+
targetWorkflowId: workflow,
|
|
2544
|
+
targetVersion: definition?.version ?? null
|
|
2545
|
+
};
|
|
2546
|
+
record.telemetry = metadata;
|
|
2547
|
+
const report = (status, content = {}) => {
|
|
2548
|
+
record.sequence = (record.sequence ?? 0) + 1;
|
|
2549
|
+
emitWorkflowCall(telemetry, `workflow.call.${status}`, {
|
|
2550
|
+
...metadata,
|
|
2551
|
+
sequence: record.sequence,
|
|
2552
|
+
...content
|
|
2553
|
+
});
|
|
2554
|
+
};
|
|
2555
|
+
const recordUsage = (usage) => {
|
|
2556
|
+
if (!usage) return;
|
|
2557
|
+
accumulateTokenUsage({
|
|
2558
|
+
input: usage.input - (record.usage?.input ?? 0),
|
|
2559
|
+
output: usage.output - (record.usage?.output ?? 0),
|
|
2560
|
+
total: usage.total - (record.usage?.total ?? 0)
|
|
2561
|
+
});
|
|
2562
|
+
record.usage = usage;
|
|
2563
|
+
};
|
|
2564
|
+
const cached = record.status === "completed";
|
|
2565
|
+
try {
|
|
2566
|
+
for (const interruption of record.interrupts) {
|
|
2567
|
+
interruption.response = await awaitInterruptInternal({
|
|
2568
|
+
request: interruption.request,
|
|
2569
|
+
...interruption.request.meta ? { meta: interruption.request.meta } : {}
|
|
2570
|
+
});
|
|
2571
|
+
}
|
|
2572
|
+
if (record.status === "failed")
|
|
2573
|
+
throw new WorkflowCallError(workflow, record.error ?? "child failed");
|
|
2574
|
+
while (record.status !== "completed") {
|
|
2575
|
+
let outcome;
|
|
2576
|
+
try {
|
|
2577
|
+
report(
|
|
2578
|
+
record.snapshot ? "resumed" : "started",
|
|
2579
|
+
workflowCallContent(telemetry, "input", input)
|
|
2580
|
+
);
|
|
2581
|
+
outcome = await service({
|
|
2582
|
+
callerNodeExecutionId,
|
|
2583
|
+
id: args.id,
|
|
2584
|
+
workflow,
|
|
2585
|
+
input,
|
|
2586
|
+
definition,
|
|
2587
|
+
invocationId: record.invocationId,
|
|
2588
|
+
...record.snapshot ? { snapshot: record.snapshot } : {},
|
|
2589
|
+
...record.interrupts.length ? { response: record.interrupts.at(-1)?.response } : {}
|
|
2590
|
+
});
|
|
2591
|
+
} catch (error) {
|
|
2592
|
+
(0, import_core6.throwIfExecutionAborted)(ctx.node.abortSignal);
|
|
2593
|
+
if ((0, import_core6.isExecutionCancelled)(error)) throw error;
|
|
2594
|
+
if ((0, import_core6.isExecutionLimitReached)(error)) {
|
|
2595
|
+
const child = error;
|
|
2596
|
+
if (child.__kortyxChildSnapshot)
|
|
2597
|
+
record.snapshot = child.__kortyxChildSnapshot;
|
|
2598
|
+
recordUsage(child.__kortyxChildUsage);
|
|
2599
|
+
report("suspended", {
|
|
2600
|
+
reason: "limit_reached",
|
|
2601
|
+
limit: error.limitReached
|
|
2602
|
+
});
|
|
2603
|
+
throw error;
|
|
2604
|
+
}
|
|
2605
|
+
record.status = "failed";
|
|
2606
|
+
record.error = error instanceof Error ? error.message : String(error);
|
|
2607
|
+
report("failed", { error: "Child workflow failed" });
|
|
2608
|
+
throw new WorkflowCallError(workflow, record.error);
|
|
2609
|
+
}
|
|
2610
|
+
(0, import_core6.throwIfExecutionAborted)(ctx.node.abortSignal);
|
|
2611
|
+
recordUsage(outcome.usage);
|
|
2612
|
+
if (outcome.status === "completed") {
|
|
2613
|
+
record.data = outcome.data;
|
|
2614
|
+
workflowCallFingerprint(record.data);
|
|
2615
|
+
record.status = "completed";
|
|
2616
|
+
delete record.snapshot;
|
|
2617
|
+
report(
|
|
2618
|
+
"completed",
|
|
2619
|
+
workflowCallContent(telemetry, "output", record.data)
|
|
2620
|
+
);
|
|
2621
|
+
} else {
|
|
2622
|
+
record.status = "interrupted";
|
|
2623
|
+
record.snapshot = outcome.snapshot;
|
|
2624
|
+
report("suspended", {
|
|
2625
|
+
leaf: outcome.request.meta?.workflowCall ?? null
|
|
2626
|
+
});
|
|
2627
|
+
const interruption = {
|
|
2628
|
+
request: outcome.request
|
|
2629
|
+
};
|
|
2630
|
+
record.interrupts.push(interruption);
|
|
2631
|
+
interruption.response = await awaitInterruptInternal({
|
|
2632
|
+
request: interruption.request,
|
|
2633
|
+
...interruption.request.meta ? { meta: interruption.request.meta } : {}
|
|
2634
|
+
});
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
if (cached)
|
|
2638
|
+
report("reused", workflowCallContent(telemetry, "output", record.data));
|
|
2639
|
+
const data = record.data ?? {};
|
|
2640
|
+
return {
|
|
2641
|
+
data: JSON.parse(JSON.stringify(data))
|
|
2642
|
+
};
|
|
2643
|
+
} finally {
|
|
2644
|
+
ctx.workflowCallActive = false;
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2334
2647
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2335
2648
|
0 && (module.exports = {
|
|
2649
|
+
WorkflowCallError,
|
|
2650
|
+
createWorkflowHooks,
|
|
2651
|
+
emitWorkflowCall,
|
|
2336
2652
|
runWithHookContext,
|
|
2653
|
+
useAbortSignal,
|
|
2337
2654
|
useInterrupt,
|
|
2338
2655
|
useNodeState,
|
|
2339
2656
|
useReason,
|
|
2340
2657
|
useRuntimeContext,
|
|
2341
2658
|
useStructuredData,
|
|
2342
|
-
|
|
2659
|
+
useWorkflow,
|
|
2660
|
+
useWorkflowState,
|
|
2661
|
+
workflowCallFingerprint
|
|
2343
2662
|
});
|
|
2344
2663
|
//# sourceMappingURL=index.js.map
|