@kortyx/agent 0.21.0 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/dist/index.d.ts +9 -8
- package/dist/index.js +382 -227
- package/dist/index.js.map +1 -1
- package/package.json +8 -7
package/dist/index.js
CHANGED
|
@@ -309,13 +309,18 @@ var require_dist = __commonJS({
|
|
|
309
309
|
workflowState: args.workflowState
|
|
310
310
|
}
|
|
311
311
|
});
|
|
312
|
+
var import_errors6 = require("@kortyx/core/errors");
|
|
312
313
|
var parseWithSchema = (schema, value, label) => {
|
|
313
314
|
if (!schema) return value;
|
|
314
315
|
const parsed = schema.safeParse(value);
|
|
315
316
|
if (parsed.success) return parsed.data;
|
|
316
317
|
const parsedError = "error" in parsed && parsed.error ? parsed.error : void 0;
|
|
317
318
|
const reason = typeof parsedError?.message === "string" && parsedError.message.length > 0 ? parsedError.message : "invalid payload";
|
|
318
|
-
throw new
|
|
319
|
+
throw new import_errors6.ValidationError(
|
|
320
|
+
label === "useReason output" ? "MODEL_OUTPUT_SCHEMA" : "SCHEMA_VALIDATION",
|
|
321
|
+
`${label} validation failed: ${reason}`,
|
|
322
|
+
parsedError
|
|
323
|
+
);
|
|
319
324
|
};
|
|
320
325
|
var awaitInterruptInternal = (args) => {
|
|
321
326
|
const ctx = getHookContext();
|
|
@@ -443,6 +448,21 @@ var require_dist = __commonJS({
|
|
|
443
448
|
var import_core32 = require("@kortyx/core");
|
|
444
449
|
var import_node_crypto22 = require("crypto");
|
|
445
450
|
var import_core22 = require("@kortyx/core");
|
|
451
|
+
var import_errors22 = require("@kortyx/core/errors");
|
|
452
|
+
function assertModelFinish(result) {
|
|
453
|
+
if (result.finishReason?.unified !== "content-filter") return;
|
|
454
|
+
throw Object.assign(
|
|
455
|
+
new import_errors22.KortyxError("PROVIDER_REFUSAL", "The provider refused the request.", {
|
|
456
|
+
category: "provider",
|
|
457
|
+
retryable: false,
|
|
458
|
+
safeMessage: "The provider refused the request."
|
|
459
|
+
}),
|
|
460
|
+
{
|
|
461
|
+
...result.usage ? { usage: result.usage } : {},
|
|
462
|
+
finishReason: result.finishReason
|
|
463
|
+
}
|
|
464
|
+
);
|
|
465
|
+
}
|
|
446
466
|
var toError = (value) => value instanceof Error ? value : new Error(String(value));
|
|
447
467
|
var createRuntimeId = () => {
|
|
448
468
|
try {
|
|
@@ -556,15 +576,18 @@ var require_dist = __commonJS({
|
|
|
556
576
|
};
|
|
557
577
|
const failTrace = (span, error) => {
|
|
558
578
|
const detail = error;
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
579
|
+
try {
|
|
580
|
+
span?.fail?.(error, {
|
|
581
|
+
...detail?.usage ? { usage: detail.usage } : {},
|
|
582
|
+
...detail?.finishReason ? { finishReason: detail.finishReason } : {},
|
|
583
|
+
...detail?.providerMetadata ? { providerMetadata: detail.providerMetadata } : {},
|
|
584
|
+
attributes: {
|
|
585
|
+
providerId: args.model.provider.id,
|
|
586
|
+
modelId: args.model.modelId
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
} catch {
|
|
590
|
+
}
|
|
568
591
|
};
|
|
569
592
|
try {
|
|
570
593
|
if (stream) {
|
|
@@ -649,6 +672,8 @@ var require_dist = __commonJS({
|
|
|
649
672
|
}
|
|
650
673
|
}
|
|
651
674
|
}
|
|
675
|
+
(0, import_core22.throwIfExecutionAborted)(abortSignal);
|
|
676
|
+
assertModelFinish({ finishReason, usage });
|
|
652
677
|
if (emit) {
|
|
653
678
|
emitNodeEvent(args.emitEvent, args.nodeId, "text-end", {
|
|
654
679
|
...commonMeta
|
|
@@ -670,6 +695,7 @@ var require_dist = __commonJS({
|
|
|
670
695
|
}
|
|
671
696
|
const response = await model.invoke(messages);
|
|
672
697
|
(0, import_core22.throwIfExecutionAborted)(abortSignal);
|
|
698
|
+
assertModelFinish(response);
|
|
673
699
|
if (response.content) args.onTextChunk?.(response.content);
|
|
674
700
|
if (emit) {
|
|
675
701
|
emitNodeEvent(args.emitEvent, args.nodeId, "text-start", {
|
|
@@ -1459,6 +1485,7 @@ var require_dist = __commonJS({
|
|
|
1459
1485
|
}
|
|
1460
1486
|
};
|
|
1461
1487
|
}
|
|
1488
|
+
var import_errors32 = require("@kortyx/core/errors");
|
|
1462
1489
|
var tryJsonParse = (value) => {
|
|
1463
1490
|
try {
|
|
1464
1491
|
return { ok: true, value: JSON.parse(value) };
|
|
@@ -1496,132 +1523,135 @@ var require_dist = __commonJS({
|
|
|
1496
1523
|
}
|
|
1497
1524
|
return text;
|
|
1498
1525
|
};
|
|
1499
|
-
var
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
};
|
|
1504
|
-
var isLikelyTruncatedStructuredOutput = (text) => {
|
|
1505
|
-
const trimmed = text.trim();
|
|
1506
|
-
if (!looksLikeStructuredJsonAttempt(trimmed)) return false;
|
|
1507
|
-
const direct = tryJsonParse(trimmed);
|
|
1508
|
-
if (!direct.ok && direct.error) return true;
|
|
1509
|
-
const block = extractJsonCodeBlock(trimmed);
|
|
1510
|
-
if (!block) return false;
|
|
1511
|
-
const parsedBlock = tryJsonParse(block);
|
|
1512
|
-
return !parsedBlock.ok && Boolean(parsedBlock.error);
|
|
1513
|
-
};
|
|
1514
|
-
var createTruncatedStructuredOutputError = (label) => new Error(
|
|
1515
|
-
`${label} was truncated before producing valid structured output. The model stopped due to output length. Increase maxOutputTokens or simplify the requested output.`
|
|
1526
|
+
var createTruncatedStructuredOutputError = (label, cause) => new import_errors32.ValidationError(
|
|
1527
|
+
"OUTPUT_TRUNCATED",
|
|
1528
|
+
`${label} was truncated before producing valid structured output. The model stopped due to output length. Increase maxOutputTokens or simplify the requested output.`,
|
|
1529
|
+
cause
|
|
1516
1530
|
);
|
|
1517
|
-
var createInvalidStructuredOutputError = (label) => new
|
|
1518
|
-
|
|
1531
|
+
var createInvalidStructuredOutputError = (label, cause) => new import_errors32.ValidationError(
|
|
1532
|
+
"INVALID_MODEL_JSON",
|
|
1533
|
+
`${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
|
+
cause
|
|
1519
1535
|
);
|
|
1520
1536
|
var parseReasonOutputWithSchema = (args) => {
|
|
1521
1537
|
const candidate = resolveOutputCandidate(args.text);
|
|
1538
|
+
const block = extractJsonCodeBlock(args.text.trim());
|
|
1539
|
+
const validJson = tryJsonParse(args.text.trim()).ok || block !== null && tryJsonParse(block).ok;
|
|
1522
1540
|
try {
|
|
1523
1541
|
return parseWithSchema(args.schema, candidate, args.label);
|
|
1524
1542
|
} catch (error) {
|
|
1525
|
-
if (
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1543
|
+
if (!(error instanceof import_errors32.ValidationError)) throw error;
|
|
1544
|
+
const failure = args.finishReason?.unified === "length" ? createTruncatedStructuredOutputError(args.label, error) : typeof candidate === "string" && !validJson ? createInvalidStructuredOutputError(args.label, error) : error;
|
|
1545
|
+
if (failure && typeof failure === "object")
|
|
1546
|
+
Object.assign(failure, {
|
|
1547
|
+
...args.usage ? { usage: args.usage } : {},
|
|
1548
|
+
...args.finishReason ? { finishReason: args.finishReason } : {}
|
|
1549
|
+
});
|
|
1550
|
+
throw failure;
|
|
1532
1551
|
}
|
|
1533
1552
|
};
|
|
1534
1553
|
var parseInterruptFirstPassResult = (args) => {
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
if (
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
const mode = args.mode ?? "required";
|
|
1548
|
-
let interruptRequired = true;
|
|
1549
|
-
if (mode === "optional") {
|
|
1550
|
-
if (candidate.decision !== "continue" && candidate.decision !== "interrupt") {
|
|
1551
|
-
throw new Error(
|
|
1552
|
-
'useReason optional interrupt first pass must include decision "continue" or "interrupt".'
|
|
1554
|
+
try {
|
|
1555
|
+
const candidate = resolveOutputCandidate(args.text);
|
|
1556
|
+
if (!isRecord22(candidate)) {
|
|
1557
|
+
if (args.finishReason?.unified === "length") {
|
|
1558
|
+
throw createTruncatedStructuredOutputError("useReason output");
|
|
1559
|
+
}
|
|
1560
|
+
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
1561
|
+
throw createInvalidStructuredOutputError("useReason output");
|
|
1562
|
+
}
|
|
1563
|
+
throw new import_errors32.ValidationError(
|
|
1564
|
+
"MODEL_OUTPUT_SCHEMA",
|
|
1565
|
+
"useReason first pass with interrupt must return a JSON object."
|
|
1553
1566
|
);
|
|
1554
1567
|
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1568
|
+
const mode = args.mode ?? "required";
|
|
1569
|
+
let interruptRequired = true;
|
|
1570
|
+
if (mode === "optional") {
|
|
1571
|
+
if (candidate.decision !== "continue" && candidate.decision !== "interrupt") {
|
|
1572
|
+
throw new import_errors32.ValidationError(
|
|
1573
|
+
"MODEL_OUTPUT_SCHEMA",
|
|
1574
|
+
'useReason optional interrupt first pass must include decision "continue" or "interrupt".'
|
|
1575
|
+
);
|
|
1576
|
+
}
|
|
1577
|
+
interruptRequired = candidate.decision === "interrupt";
|
|
1578
|
+
if (!interruptRequired) {
|
|
1579
|
+
const hasUnexpectedRequest = [
|
|
1580
|
+
candidate.interruptRequest,
|
|
1581
|
+
candidate.request,
|
|
1582
|
+
candidate.interrupt
|
|
1583
|
+
].some((value) => value !== null && value !== void 0);
|
|
1584
|
+
if (hasUnexpectedRequest) {
|
|
1585
|
+
throw new import_errors32.ValidationError(
|
|
1586
|
+
"MODEL_OUTPUT_SCHEMA",
|
|
1587
|
+
'useReason optional interrupt first pass with decision "continue" must not include an interrupt request.'
|
|
1588
|
+
);
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
let request;
|
|
1593
|
+
if (interruptRequired) {
|
|
1594
|
+
const requestCandidates = [
|
|
1558
1595
|
candidate.interruptRequest,
|
|
1559
1596
|
candidate.request,
|
|
1560
|
-
candidate.interrupt
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1597
|
+
candidate.interrupt,
|
|
1598
|
+
mode === "required" ? candidate : void 0
|
|
1599
|
+
];
|
|
1600
|
+
const requestPayload = requestCandidates.find(
|
|
1601
|
+
(value) => value !== null && value !== void 0
|
|
1602
|
+
);
|
|
1603
|
+
request = parseWithSchema(
|
|
1604
|
+
args.requestSchema,
|
|
1605
|
+
requestPayload,
|
|
1606
|
+
"useReason interrupt.request"
|
|
1607
|
+
);
|
|
1608
|
+
}
|
|
1609
|
+
let output;
|
|
1610
|
+
if (args.outputSchema) {
|
|
1611
|
+
const outputPayload = Object.hasOwn(candidate, "output") ? candidate.output : candidate;
|
|
1612
|
+
try {
|
|
1613
|
+
output = parseWithSchema(
|
|
1614
|
+
args.outputSchema,
|
|
1615
|
+
outputPayload,
|
|
1616
|
+
"useReason output"
|
|
1565
1617
|
);
|
|
1618
|
+
} catch (error) {
|
|
1619
|
+
if (!(error instanceof import_errors32.ValidationError)) throw error;
|
|
1620
|
+
if (args.finishReason?.unified === "length") {
|
|
1621
|
+
throw createTruncatedStructuredOutputError("useReason output", error);
|
|
1622
|
+
}
|
|
1623
|
+
throw error;
|
|
1566
1624
|
}
|
|
1567
1625
|
}
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
candidate.request,
|
|
1574
|
-
candidate.interrupt,
|
|
1575
|
-
mode === "required" ? candidate : void 0
|
|
1576
|
-
];
|
|
1577
|
-
const requestPayload = requestCandidates.find(
|
|
1578
|
-
(value) => value !== null && value !== void 0
|
|
1579
|
-
);
|
|
1580
|
-
request = parseWithSchema(
|
|
1581
|
-
args.requestSchema,
|
|
1582
|
-
requestPayload,
|
|
1583
|
-
"useReason interrupt.request"
|
|
1584
|
-
);
|
|
1585
|
-
}
|
|
1586
|
-
let output;
|
|
1587
|
-
if (args.outputSchema) {
|
|
1588
|
-
const outputPayload = Object.hasOwn(candidate, "output") ? candidate.output : candidate;
|
|
1589
|
-
try {
|
|
1590
|
-
output = parseWithSchema(
|
|
1591
|
-
args.outputSchema,
|
|
1592
|
-
outputPayload,
|
|
1593
|
-
"useReason output"
|
|
1626
|
+
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
|
+
if (!args.outputSchema && !explicitDraft) {
|
|
1628
|
+
throw new import_errors32.ValidationError(
|
|
1629
|
+
"MODEL_OUTPUT_SCHEMA",
|
|
1630
|
+
"useReason first pass with interrupt requires `draftText` when outputSchema is not provided."
|
|
1594
1631
|
);
|
|
1595
|
-
} catch (error) {
|
|
1596
|
-
if (args.finishReason?.unified === "length" || isLikelyTruncatedStructuredOutput(args.text)) {
|
|
1597
|
-
throw createTruncatedStructuredOutputError("useReason output");
|
|
1598
|
-
}
|
|
1599
|
-
if (typeof outputPayload === "string" && outputPayload.trim().length > 0) {
|
|
1600
|
-
throw createInvalidStructuredOutputError("useReason output");
|
|
1601
|
-
}
|
|
1602
|
-
throw error;
|
|
1603
1632
|
}
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
if (!interruptRequired) {
|
|
1633
|
+
const draftText = explicitDraft ?? (output !== void 0 ? tryStringify(output) : String(args.text ?? ""));
|
|
1634
|
+
if (!interruptRequired) {
|
|
1635
|
+
return {
|
|
1636
|
+
draftText,
|
|
1637
|
+
interruptRequired: false,
|
|
1638
|
+
...output !== void 0 ? { output } : {}
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1613
1641
|
return {
|
|
1614
1642
|
draftText,
|
|
1615
|
-
interruptRequired:
|
|
1643
|
+
interruptRequired: true,
|
|
1644
|
+
request,
|
|
1616
1645
|
...output !== void 0 ? { output } : {}
|
|
1617
1646
|
};
|
|
1647
|
+
} catch (error) {
|
|
1648
|
+
if (error && typeof error === "object")
|
|
1649
|
+
Object.assign(error, {
|
|
1650
|
+
...args.usage ? { usage: args.usage } : {},
|
|
1651
|
+
...args.finishReason ? { finishReason: args.finishReason } : {}
|
|
1652
|
+
});
|
|
1653
|
+
throw error;
|
|
1618
1654
|
}
|
|
1619
|
-
return {
|
|
1620
|
-
draftText,
|
|
1621
|
-
interruptRequired: true,
|
|
1622
|
-
request,
|
|
1623
|
-
...output !== void 0 ? { output } : {}
|
|
1624
|
-
};
|
|
1625
1655
|
};
|
|
1626
1656
|
var import_zod32 = require("zod");
|
|
1627
1657
|
var tryStringify2 = (value) => {
|
|
@@ -1829,7 +1859,7 @@ ${tryStringify2(args.response)}`
|
|
|
1829
1859
|
});
|
|
1830
1860
|
};
|
|
1831
1861
|
var import_core42 = require("@kortyx/core");
|
|
1832
|
-
var
|
|
1862
|
+
var import_errors42 = require("@kortyx/core/errors");
|
|
1833
1863
|
var toToolDefinitions = (tools) => tools.map((tool) => ({
|
|
1834
1864
|
name: tool.name,
|
|
1835
1865
|
...tool.title ? { title: tool.title } : {},
|
|
@@ -1863,17 +1893,27 @@ ${tryStringify2(args.response)}`
|
|
|
1863
1893
|
...value !== void 0 && value !== null && typeof value === "object" && !Array.isArray(value) ? { structuredContent: value } : {}
|
|
1864
1894
|
};
|
|
1865
1895
|
};
|
|
1866
|
-
var closeOwnedTools = async (tools) => {
|
|
1896
|
+
var closeOwnedTools = async (tools, preserveFailure = false, traceSpan) => {
|
|
1867
1897
|
const closeFns = /* @__PURE__ */ new Set();
|
|
1868
1898
|
for (const tool of tools) {
|
|
1869
1899
|
if (tool.closeAfterUse === false || !tool.close) continue;
|
|
1870
1900
|
closeFns.add(tool.close);
|
|
1871
1901
|
}
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
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
|
+
}
|
|
1877
1917
|
};
|
|
1878
1918
|
var createInitialMessages = (args) => [
|
|
1879
1919
|
...typeof args.system === "string" && args.system.length > 0 ? [{ role: "system", content: args.system }] : [],
|
|
@@ -1890,6 +1930,7 @@ ${tryStringify2(args.response)}`
|
|
|
1890
1930
|
const saved = ctx.currentNodeState.byKey[checkpointKey];
|
|
1891
1931
|
const checkpoint = saved?.status === "tool_loop" ? saved : void 0;
|
|
1892
1932
|
const opId = checkpoint?.opId ?? args.opId;
|
|
1933
|
+
let primaryFailure = false;
|
|
1893
1934
|
const tools = useReasonArgs.tools ?? [];
|
|
1894
1935
|
const toolByName = /* @__PURE__ */ new Map();
|
|
1895
1936
|
let validationCompleted = false;
|
|
@@ -1922,7 +1963,7 @@ ${tryStringify2(args.response)}`
|
|
|
1922
1963
|
validationCompleted = true;
|
|
1923
1964
|
} finally {
|
|
1924
1965
|
if (!validationCompleted) {
|
|
1925
|
-
await closeOwnedTools(tools);
|
|
1966
|
+
await closeOwnedTools(tools, true, traceSpan);
|
|
1926
1967
|
}
|
|
1927
1968
|
}
|
|
1928
1969
|
const toolDefinitions = toToolDefinitions(tools);
|
|
@@ -2041,6 +2082,7 @@ ${tryStringify2(args.response)}`
|
|
|
2041
2082
|
text: step.text,
|
|
2042
2083
|
schema: useReasonArgs.outputSchema,
|
|
2043
2084
|
...step.finishReason ? { finishReason: step.finishReason } : {},
|
|
2085
|
+
...aggregatedUsage ? { usage: aggregatedUsage } : {},
|
|
2044
2086
|
label: "useReason output"
|
|
2045
2087
|
});
|
|
2046
2088
|
aggregatedWarnings = mergeWarnings(aggregatedWarnings, [
|
|
@@ -2128,12 +2170,12 @@ ${tryStringify2(args.response)}`
|
|
|
2128
2170
|
options: [
|
|
2129
2171
|
{ id: "approve", label: "Approve" },
|
|
2130
2172
|
{ id: "deny", label: "Deny" }
|
|
2131
|
-
]
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2173
|
+
]
|
|
2174
|
+
},
|
|
2175
|
+
meta: {
|
|
2176
|
+
tool: tool.name,
|
|
2177
|
+
toolCallId: toolCall.id,
|
|
2178
|
+
input: toolCall.input
|
|
2137
2179
|
}
|
|
2138
2180
|
});
|
|
2139
2181
|
const approved = Array.isArray(approval) ? approval.includes("approve") : approval === "approve";
|
|
@@ -2195,12 +2237,12 @@ ${tryStringify2(args.response)}`
|
|
|
2195
2237
|
});
|
|
2196
2238
|
} catch (error) {
|
|
2197
2239
|
(0, import_core42.throwIfExecutionAborted)(abortSignal);
|
|
2198
|
-
if ((0,
|
|
2199
|
-
throw error;
|
|
2240
|
+
if ((0, import_errors42.isControlFlowError)(error)) throw error;
|
|
2200
2241
|
const result2 = {
|
|
2201
2242
|
toolCallId: toolCall.id,
|
|
2202
2243
|
name: tool.name,
|
|
2203
|
-
content:
|
|
2244
|
+
content: (0, import_errors42.serializeFailure)(error).message,
|
|
2245
|
+
failure: (0, import_errors42.serializeFailure)(error),
|
|
2204
2246
|
isError: true
|
|
2205
2247
|
};
|
|
2206
2248
|
toolResults.push(result2);
|
|
@@ -2209,14 +2251,16 @@ ${tryStringify2(args.response)}`
|
|
|
2209
2251
|
emitToolEvent("tool-call-error", {
|
|
2210
2252
|
tool: tool.name,
|
|
2211
2253
|
toolCallId: toolCall.id,
|
|
2212
|
-
message: result2.content
|
|
2254
|
+
message: result2.content,
|
|
2255
|
+
failure: result2.failure
|
|
2213
2256
|
});
|
|
2214
2257
|
}
|
|
2215
2258
|
traceSpan?.addEvent?.("useReason.tool-call.error", {
|
|
2216
2259
|
stepIndex,
|
|
2217
2260
|
tool: tool.name,
|
|
2218
2261
|
toolCallId: toolCall.id,
|
|
2219
|
-
message: result2.content
|
|
2262
|
+
message: result2.content,
|
|
2263
|
+
failure: result2.failure
|
|
2220
2264
|
});
|
|
2221
2265
|
}
|
|
2222
2266
|
const completed2 = toolResults.at(-1);
|
|
@@ -2243,6 +2287,7 @@ ${tryStringify2(args.response)}`
|
|
|
2243
2287
|
text: finalText,
|
|
2244
2288
|
schema: useReasonArgs.outputSchema,
|
|
2245
2289
|
...finalFinishReason ? { finishReason: finalFinishReason } : {},
|
|
2290
|
+
...aggregatedUsage ? { usage: aggregatedUsage } : {},
|
|
2246
2291
|
label: "useReason output"
|
|
2247
2292
|
});
|
|
2248
2293
|
}
|
|
@@ -2289,15 +2334,19 @@ ${tryStringify2(args.response)}`
|
|
|
2289
2334
|
ctx.stateDirty = true;
|
|
2290
2335
|
return result;
|
|
2291
2336
|
} catch (error) {
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2337
|
+
primaryFailure = true;
|
|
2338
|
+
try {
|
|
2339
|
+
traceSpan?.fail?.(error, {
|
|
2340
|
+
attributes: {
|
|
2341
|
+
toolStepCount: steps.length,
|
|
2342
|
+
toolCallCount: allToolCalls.length
|
|
2343
|
+
}
|
|
2344
|
+
});
|
|
2345
|
+
} catch {
|
|
2346
|
+
}
|
|
2298
2347
|
throw error;
|
|
2299
2348
|
} finally {
|
|
2300
|
-
await closeOwnedTools(tools);
|
|
2349
|
+
await closeOwnedTools(tools, primaryFailure, traceSpan);
|
|
2301
2350
|
}
|
|
2302
2351
|
};
|
|
2303
2352
|
var shouldStreamReasonStructured = (args) => (args.emit ?? true) && shouldStreamStructured(args.structured);
|
|
@@ -2460,6 +2509,7 @@ ${tryStringify2(args.response)}`
|
|
|
2460
2509
|
text: first.text,
|
|
2461
2510
|
requestSchema: args.interrupt.requestSchema,
|
|
2462
2511
|
...first.finishReason ? { finishReason: first.finishReason } : {},
|
|
2512
|
+
...first.usage ? { usage: first.usage } : {},
|
|
2463
2513
|
...args.outputSchema ? { outputSchema: args.outputSchema } : {},
|
|
2464
2514
|
mode: args.interrupt.mode ?? "required"
|
|
2465
2515
|
});
|
|
@@ -2477,6 +2527,7 @@ ${tryStringify2(args.response)}`
|
|
|
2477
2527
|
text: first.text,
|
|
2478
2528
|
schema: args.outputSchema,
|
|
2479
2529
|
...first.finishReason ? { finishReason: first.finishReason } : {},
|
|
2530
|
+
...first.usage ? { usage: first.usage } : {},
|
|
2480
2531
|
label: "useReason output"
|
|
2481
2532
|
});
|
|
2482
2533
|
}
|
|
@@ -2571,6 +2622,7 @@ ${tryStringify2(args.response)}`
|
|
|
2571
2622
|
text: finalText,
|
|
2572
2623
|
schema: args.outputSchema,
|
|
2573
2624
|
...second.finishReason ? { finishReason: second.finishReason } : {},
|
|
2625
|
+
...aggregatedUsage ? { usage: aggregatedUsage } : {},
|
|
2574
2626
|
label: "useReason output"
|
|
2575
2627
|
});
|
|
2576
2628
|
}
|
|
@@ -2674,7 +2726,9 @@ ${tryStringify2(args.response)}`
|
|
|
2674
2726
|
return [getValue(), setValue];
|
|
2675
2727
|
}
|
|
2676
2728
|
var import_core62 = require("@kortyx/core");
|
|
2729
|
+
var import_errors52 = require("@kortyx/core/errors");
|
|
2677
2730
|
var ParallelChildWaiting = class extends Error {
|
|
2731
|
+
name = "ParallelChildWaiting";
|
|
2678
2732
|
};
|
|
2679
2733
|
var ParallelError = class extends AggregateError {
|
|
2680
2734
|
constructor(results) {
|
|
@@ -2686,8 +2740,23 @@ ${tryStringify2(args.response)}`
|
|
|
2686
2740
|
);
|
|
2687
2741
|
this.results = results;
|
|
2688
2742
|
this.name = "ParallelError";
|
|
2743
|
+
this.failure = (0, import_errors52.serializeFailure)({
|
|
2744
|
+
version: 1,
|
|
2745
|
+
code: this.code,
|
|
2746
|
+
category: "workflow",
|
|
2747
|
+
message: this.message,
|
|
2748
|
+
retryable: null,
|
|
2749
|
+
results: results.map(
|
|
2750
|
+
(result) => result.status === "fulfilled" ? { status: "fulfilled" } : { status: "rejected", failure: (0, import_errors52.serializeFailure)(result.reason) }
|
|
2751
|
+
)
|
|
2752
|
+
});
|
|
2689
2753
|
}
|
|
2690
2754
|
results;
|
|
2755
|
+
code = "PARALLEL_FAILED";
|
|
2756
|
+
failure;
|
|
2757
|
+
toJSON() {
|
|
2758
|
+
return (0, import_errors52.serializeFailure)(this);
|
|
2759
|
+
}
|
|
2691
2760
|
};
|
|
2692
2761
|
function registerWorkflowTask(id) {
|
|
2693
2762
|
const ctx = getHookContext();
|
|
@@ -2825,6 +2894,7 @@ ${tryStringify2(args.response)}`
|
|
|
2825
2894
|
}
|
|
2826
2895
|
var import_node_crypto5 = require("crypto");
|
|
2827
2896
|
var import_core7 = require("@kortyx/core");
|
|
2897
|
+
var import_errors62 = require("@kortyx/core/errors");
|
|
2828
2898
|
var import_node_crypto42 = require("crypto");
|
|
2829
2899
|
function emitWorkflowCall2(telemetry, type, payload) {
|
|
2830
2900
|
const base = telemetry?.correlation;
|
|
@@ -2862,10 +2932,20 @@ ${tryStringify2(args.response)}`
|
|
|
2862
2932
|
const serialized = JSON.stringify(value);
|
|
2863
2933
|
return serialized && Buffer.byteLength(serialized, "utf8") <= 16384 ? { [side]: JSON.parse(serialized) } : { [`${side}Omitted`]: "Content exceeds 16 KiB" };
|
|
2864
2934
|
}
|
|
2865
|
-
var WorkflowCallError = class extends
|
|
2866
|
-
constructor(workflow, message) {
|
|
2867
|
-
|
|
2935
|
+
var WorkflowCallError = class extends import_errors62.KortyxError {
|
|
2936
|
+
constructor(workflow, message, cause, failure) {
|
|
2937
|
+
const detail = (0, import_errors62.serializeFailure)(
|
|
2938
|
+
failure ?? cause ?? new import_errors62.WorkflowContractError(message)
|
|
2939
|
+
);
|
|
2940
|
+
super(detail.code, `Workflow '${workflow}': ${message}`, {
|
|
2941
|
+
...detail,
|
|
2942
|
+
safeMessage: detail.message,
|
|
2943
|
+
...cause !== void 0 ? { cause } : {}
|
|
2944
|
+
});
|
|
2868
2945
|
this.workflow = workflow;
|
|
2946
|
+
Object.assign(this.failure, detail, {
|
|
2947
|
+
context: { ...detail.context, workflow }
|
|
2948
|
+
});
|
|
2869
2949
|
this.name = "WorkflowCallError";
|
|
2870
2950
|
}
|
|
2871
2951
|
workflow;
|
|
@@ -2876,10 +2956,12 @@ ${tryStringify2(args.response)}`
|
|
|
2876
2956
|
if (v === null || typeof v === "string" || typeof v === "boolean") return v;
|
|
2877
2957
|
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
2878
2958
|
if (typeof v !== "object" || !v || seen.has(v)) {
|
|
2879
|
-
throw new
|
|
2959
|
+
throw new import_errors62.WorkflowContractError(
|
|
2960
|
+
"Workflow input and output must be JSON serializable."
|
|
2961
|
+
);
|
|
2880
2962
|
}
|
|
2881
2963
|
if (!Array.isArray(v) && Object.getPrototypeOf(v) !== Object.prototype) {
|
|
2882
|
-
throw new
|
|
2964
|
+
throw new import_errors62.WorkflowContractError(
|
|
2883
2965
|
"Workflow input and output must contain plain JSON objects."
|
|
2884
2966
|
);
|
|
2885
2967
|
}
|
|
@@ -2900,7 +2982,9 @@ ${tryStringify2(args.response)}`
|
|
|
2900
2982
|
useWorkflow: (args) => {
|
|
2901
2983
|
const workflow = workflows[args.workflow];
|
|
2902
2984
|
if (!workflow || workflow.id !== args.workflow)
|
|
2903
|
-
throw new
|
|
2985
|
+
throw new import_errors62.WorkflowContractError(
|
|
2986
|
+
"Workflow registry keys must match definition ids."
|
|
2987
|
+
);
|
|
2904
2988
|
return useWorkflow({ ...args, workflow });
|
|
2905
2989
|
}
|
|
2906
2990
|
};
|
|
@@ -2924,19 +3008,23 @@ ${tryStringify2(args.response)}`
|
|
|
2924
3008
|
(0, import_core7.throwIfExecutionAborted)(ctx.node.abortSignal);
|
|
2925
3009
|
const service = ctx.node.callWorkflow;
|
|
2926
3010
|
if (!service)
|
|
2927
|
-
throw new
|
|
3011
|
+
throw new import_errors62.WorkflowContractError(
|
|
3012
|
+
"useWorkflow requires an agent workflow registry."
|
|
3013
|
+
);
|
|
2928
3014
|
if (!args.id.trim())
|
|
2929
|
-
throw new
|
|
3015
|
+
throw new import_errors62.WorkflowContractError(
|
|
3016
|
+
"useWorkflow requires a stable, nonempty id."
|
|
3017
|
+
);
|
|
2930
3018
|
if (ctx.workflowCallActive && !task.group)
|
|
2931
|
-
throw new
|
|
3019
|
+
throw new import_errors62.WorkflowContractError(
|
|
2932
3020
|
"Concurrent workflow calls require parallel([...]); otherwise await each call."
|
|
2933
3021
|
);
|
|
2934
3022
|
if (ctx.workflowCallIds.has(args.id))
|
|
2935
|
-
throw new
|
|
3023
|
+
throw new import_errors62.WorkflowContractError(
|
|
2936
3024
|
`Duplicate workflow call id '${args.id}' in one node activation.`
|
|
2937
3025
|
);
|
|
2938
3026
|
if (ctx.workflowCallIds.size >= 64)
|
|
2939
|
-
throw new
|
|
3027
|
+
throw new import_errors62.WorkflowContractError(
|
|
2940
3028
|
"A node may call at most 64 child workflows per activation."
|
|
2941
3029
|
);
|
|
2942
3030
|
ctx.workflowCallIds.add(args.id);
|
|
@@ -3013,7 +3101,12 @@ ${tryStringify2(args.response)}`
|
|
|
3013
3101
|
});
|
|
3014
3102
|
}
|
|
3015
3103
|
if (record.status === "failed")
|
|
3016
|
-
throw new WorkflowCallError(
|
|
3104
|
+
throw new WorkflowCallError(
|
|
3105
|
+
workflow,
|
|
3106
|
+
record.error ?? "child failed",
|
|
3107
|
+
void 0,
|
|
3108
|
+
record.failure ?? (0, import_errors62.serializeFailure)(void 0)
|
|
3109
|
+
);
|
|
3017
3110
|
if (task.group && record.status === "interrupted" && record.interrupts.at(-1)?.response === void 0)
|
|
3018
3111
|
throw new ParallelChildWaiting();
|
|
3019
3112
|
while (record.status !== "completed") {
|
|
@@ -3048,9 +3141,15 @@ ${tryStringify2(args.response)}`
|
|
|
3048
3141
|
throw error;
|
|
3049
3142
|
}
|
|
3050
3143
|
record.status = "failed";
|
|
3051
|
-
record.
|
|
3144
|
+
record.failure = (0, import_errors62.serializeFailure)(error);
|
|
3145
|
+
record.error = record.failure.message;
|
|
3052
3146
|
report("failed", { error: "Child workflow failed" });
|
|
3053
|
-
throw new WorkflowCallError(
|
|
3147
|
+
throw new WorkflowCallError(
|
|
3148
|
+
workflow,
|
|
3149
|
+
record.error,
|
|
3150
|
+
error,
|
|
3151
|
+
record.failure
|
|
3152
|
+
);
|
|
3054
3153
|
}
|
|
3055
3154
|
(0, import_core7.throwIfExecutionAborted)(ctx.node.abortSignal);
|
|
3056
3155
|
recordUsage(outcome.usage);
|
|
@@ -3100,6 +3199,7 @@ __export(index_exports, {
|
|
|
3100
3199
|
createAgent: () => createAgent,
|
|
3101
3200
|
createChatRouteHandler: () => createChatRouteHandler,
|
|
3102
3201
|
createCheckpointRouteHandler: () => createCheckpointRouteHandler,
|
|
3202
|
+
createFailureResponse: () => createFailureResponse,
|
|
3103
3203
|
extractLatestUserMessage: () => extractLatestUserMessage,
|
|
3104
3204
|
handleChatRequestBody: () => handleChatRequestBody,
|
|
3105
3205
|
handleCheckpointRequestBody: () => handleCheckpointRequestBody,
|
|
@@ -3108,6 +3208,7 @@ __export(index_exports, {
|
|
|
3108
3208
|
parseCheckpointRequestBody: () => parseCheckpointRequestBody,
|
|
3109
3209
|
parseResumeMeta: () => parseResumeMeta,
|
|
3110
3210
|
projectWorkflowTopology: () => projectWorkflowTopology,
|
|
3211
|
+
readRequestJson: () => readRequestJson,
|
|
3111
3212
|
streamChat: () => streamChat,
|
|
3112
3213
|
streamChatFromRoute: () => streamChatFromRoute,
|
|
3113
3214
|
transformGraphStreamForUI: () => transformGraphStreamForUI,
|
|
@@ -3116,6 +3217,7 @@ __export(index_exports, {
|
|
|
3116
3217
|
module.exports = __toCommonJS(index_exports);
|
|
3117
3218
|
|
|
3118
3219
|
// src/adapters/http.ts
|
|
3220
|
+
var import_errors = require("@kortyx/core/errors");
|
|
3119
3221
|
var import_stream = require("@kortyx/stream");
|
|
3120
3222
|
var import_zod = require("zod");
|
|
3121
3223
|
var chatMessageSchema = import_zod.z.object({
|
|
@@ -3151,12 +3253,41 @@ var checkpointRequestBodySchema = import_zod.z.discriminatedUnion("action", [
|
|
|
3151
3253
|
newSessionId: import_zod.z.string().min(1).optional()
|
|
3152
3254
|
}).strict()
|
|
3153
3255
|
]);
|
|
3154
|
-
|
|
3256
|
+
async function readRequestJson(request) {
|
|
3257
|
+
try {
|
|
3258
|
+
const value = await request.json();
|
|
3259
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
3260
|
+
throw new Error("Expected a JSON object.");
|
|
3261
|
+
return value;
|
|
3262
|
+
} catch (cause) {
|
|
3263
|
+
throw new import_errors.KortyxError(
|
|
3264
|
+
"INVALID_REQUEST",
|
|
3265
|
+
"Request body is not valid JSON.",
|
|
3266
|
+
{
|
|
3267
|
+
category: "request",
|
|
3268
|
+
retryable: false,
|
|
3269
|
+
safeMessage: "The request body must contain a valid JSON object.",
|
|
3270
|
+
cause
|
|
3271
|
+
}
|
|
3272
|
+
);
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
function createFailureResponse(error, status) {
|
|
3276
|
+
const failure = (0, import_errors.serializeFailure)(error);
|
|
3277
|
+
return Response.json(
|
|
3278
|
+
{ error: failure.message, failure },
|
|
3279
|
+
{ status: status ?? (0, import_errors.failureHttpStatus)(failure) }
|
|
3280
|
+
);
|
|
3281
|
+
}
|
|
3155
3282
|
function parseChatRequestBody(value) {
|
|
3156
3283
|
const parsed = chatRequestBodySchema.safeParse(value);
|
|
3157
3284
|
if (!parsed.success) {
|
|
3158
3285
|
const [firstIssue] = parsed.error.issues;
|
|
3159
|
-
throw new
|
|
3286
|
+
throw new import_errors.KortyxError("INVALID_REQUEST", firstIssue.message, {
|
|
3287
|
+
category: "request",
|
|
3288
|
+
retryable: false,
|
|
3289
|
+
safeMessage: "The request body is invalid."
|
|
3290
|
+
});
|
|
3160
3291
|
}
|
|
3161
3292
|
const sessionId = parsed.data.sessionId?.trim();
|
|
3162
3293
|
const workflowId = parsed.data.workflowId?.trim();
|
|
@@ -3172,7 +3303,11 @@ function parseCheckpointRequestBody(value) {
|
|
|
3172
3303
|
const parsed = checkpointRequestBodySchema.safeParse(value);
|
|
3173
3304
|
if (parsed.success) return parsed.data;
|
|
3174
3305
|
const [firstIssue] = parsed.error.issues;
|
|
3175
|
-
throw new
|
|
3306
|
+
throw new import_errors.KortyxError("INVALID_REQUEST", firstIssue.message, {
|
|
3307
|
+
category: "request",
|
|
3308
|
+
retryable: false,
|
|
3309
|
+
safeMessage: "The request body is invalid."
|
|
3310
|
+
});
|
|
3176
3311
|
}
|
|
3177
3312
|
async function handleChatRequestBody(args) {
|
|
3178
3313
|
const { agent, body } = args;
|
|
@@ -3194,10 +3329,10 @@ async function handleChatRequestBody(args) {
|
|
|
3194
3329
|
return (0, import_stream.toSSE)(stream);
|
|
3195
3330
|
}
|
|
3196
3331
|
function createChatRouteHandler(args) {
|
|
3197
|
-
const { agent, errorStatus
|
|
3332
|
+
const { agent, errorStatus } = args;
|
|
3198
3333
|
return async function POST(request) {
|
|
3199
3334
|
try {
|
|
3200
|
-
const body = parseChatRequestBody(await request
|
|
3335
|
+
const body = parseChatRequestBody(await readRequestJson(request));
|
|
3201
3336
|
return await handleChatRequestBody({
|
|
3202
3337
|
agent,
|
|
3203
3338
|
body,
|
|
@@ -3205,17 +3340,7 @@ function createChatRouteHandler(args) {
|
|
|
3205
3340
|
onExecution: args.onExecution
|
|
3206
3341
|
});
|
|
3207
3342
|
} catch (error) {
|
|
3208
|
-
return
|
|
3209
|
-
JSON.stringify({
|
|
3210
|
-
error: toErrorMessage(error)
|
|
3211
|
-
}),
|
|
3212
|
-
{
|
|
3213
|
-
status: errorStatus,
|
|
3214
|
-
headers: {
|
|
3215
|
-
"content-type": "application/json"
|
|
3216
|
-
}
|
|
3217
|
-
}
|
|
3218
|
-
);
|
|
3343
|
+
return createFailureResponse(error, errorStatus);
|
|
3219
3344
|
}
|
|
3220
3345
|
};
|
|
3221
3346
|
}
|
|
@@ -3231,23 +3356,13 @@ async function handleCheckpointRequestBody(args) {
|
|
|
3231
3356
|
});
|
|
3232
3357
|
}
|
|
3233
3358
|
function createCheckpointRouteHandler(args) {
|
|
3234
|
-
const { agent, errorStatus
|
|
3359
|
+
const { agent, errorStatus } = args;
|
|
3235
3360
|
return async function POST(request) {
|
|
3236
3361
|
try {
|
|
3237
|
-
const body = parseCheckpointRequestBody(await request
|
|
3362
|
+
const body = parseCheckpointRequestBody(await readRequestJson(request));
|
|
3238
3363
|
return await handleCheckpointRequestBody({ agent, body });
|
|
3239
3364
|
} catch (error) {
|
|
3240
|
-
return
|
|
3241
|
-
JSON.stringify({
|
|
3242
|
-
error: toErrorMessage(error)
|
|
3243
|
-
}),
|
|
3244
|
-
{
|
|
3245
|
-
status: errorStatus,
|
|
3246
|
-
headers: {
|
|
3247
|
-
"content-type": "application/json"
|
|
3248
|
-
}
|
|
3249
|
-
}
|
|
3250
|
-
);
|
|
3365
|
+
return createFailureResponse(error, errorStatus);
|
|
3251
3366
|
}
|
|
3252
3367
|
};
|
|
3253
3368
|
}
|
|
@@ -3276,6 +3391,7 @@ var import_zod5 = require("zod");
|
|
|
3276
3391
|
|
|
3277
3392
|
// src/execution/execute.ts
|
|
3278
3393
|
var import_core4 = require("@kortyx/core");
|
|
3394
|
+
var import_errors5 = require("@kortyx/core/errors");
|
|
3279
3395
|
var import_runtime3 = require("@kortyx/runtime");
|
|
3280
3396
|
var import_zod3 = require("zod");
|
|
3281
3397
|
|
|
@@ -3283,32 +3399,37 @@ var import_zod3 = require("zod");
|
|
|
3283
3399
|
var import_core3 = require("@kortyx/core");
|
|
3284
3400
|
var import_runtime2 = require("@kortyx/runtime");
|
|
3285
3401
|
|
|
3402
|
+
// src/execution/types.ts
|
|
3403
|
+
var import_errors2 = require("@kortyx/core/errors");
|
|
3404
|
+
var ExecutionRequestError = class extends import_errors2.KortyxError {
|
|
3405
|
+
name = "ExecutionRequestError";
|
|
3406
|
+
constructor(code, message, cause) {
|
|
3407
|
+
super(code, message, {
|
|
3408
|
+
category: "request",
|
|
3409
|
+
retryable: false,
|
|
3410
|
+
safeMessage: "The execution request is invalid. Check the workflow contract and request fields.",
|
|
3411
|
+
cause
|
|
3412
|
+
});
|
|
3413
|
+
}
|
|
3414
|
+
};
|
|
3415
|
+
|
|
3286
3416
|
// src/orchestrator.ts
|
|
3287
3417
|
var import_node_stream = require("stream");
|
|
3288
3418
|
var import_core2 = require("@kortyx/core");
|
|
3419
|
+
var import_errors4 = require("@kortyx/core/errors");
|
|
3289
3420
|
var import_runtime = require("@kortyx/runtime");
|
|
3290
3421
|
var import_langgraph = require("@langchain/langgraph");
|
|
3291
3422
|
|
|
3292
3423
|
// src/execution/contracts.ts
|
|
3424
|
+
var import_errors3 = require("@kortyx/core/errors");
|
|
3293
3425
|
var import_zod2 = require("zod");
|
|
3294
|
-
|
|
3295
|
-
// src/execution/types.ts
|
|
3296
|
-
var ExecutionRequestError = class extends Error {
|
|
3297
|
-
constructor(code, message) {
|
|
3298
|
-
super(message);
|
|
3299
|
-
this.code = code;
|
|
3300
|
-
}
|
|
3301
|
-
code;
|
|
3302
|
-
name = "ExecutionRequestError";
|
|
3303
|
-
};
|
|
3304
|
-
|
|
3305
|
-
// src/execution/contracts.ts
|
|
3306
3426
|
async function resolveExecutionWorkflow(select, reference) {
|
|
3307
3427
|
const id = typeof reference === "string" ? reference : reference.id;
|
|
3308
3428
|
let workflow;
|
|
3309
3429
|
try {
|
|
3310
3430
|
workflow = await select(id);
|
|
3311
|
-
} catch {
|
|
3431
|
+
} catch (error) {
|
|
3432
|
+
if ((0, import_errors3.errorProperty)(error, "code") !== "UNKNOWN_WORKFLOW") throw error;
|
|
3312
3433
|
throw new ExecutionRequestError(
|
|
3313
3434
|
"UNKNOWN_WORKFLOW",
|
|
3314
3435
|
`Workflow '${id}' is not registered.`
|
|
@@ -3338,10 +3459,8 @@ function parseExecutionInput(workflow, input) {
|
|
|
3338
3459
|
import_zod2.z.json().parse(parsed);
|
|
3339
3460
|
return parsed;
|
|
3340
3461
|
} catch (error) {
|
|
3341
|
-
throw
|
|
3342
|
-
|
|
3343
|
-
error instanceof Error ? error.message : String(error)
|
|
3344
|
-
);
|
|
3462
|
+
if (!(error instanceof import_zod2.z.ZodError)) throw error;
|
|
3463
|
+
throw new ExecutionRequestError("INVALID_INPUT", error.message, error);
|
|
3345
3464
|
}
|
|
3346
3465
|
}
|
|
3347
3466
|
async function validateExecutionOutput(state, select) {
|
|
@@ -3350,7 +3469,9 @@ async function validateExecutionOutput(state, select) {
|
|
|
3350
3469
|
const contract = state.config.executionContract;
|
|
3351
3470
|
const root = await select(contract.id);
|
|
3352
3471
|
if (root.id !== contract.id || root.version !== contract.version)
|
|
3353
|
-
throw new
|
|
3472
|
+
throw new import_errors3.WorkflowContractError(
|
|
3473
|
+
"The root workflow changed since execution started."
|
|
3474
|
+
);
|
|
3354
3475
|
let data = state.data ?? {};
|
|
3355
3476
|
try {
|
|
3356
3477
|
for (const schema of /* @__PURE__ */ new Set([terminal.outputSchema, root.outputSchema])) {
|
|
@@ -3358,10 +3479,12 @@ async function validateExecutionOutput(state, select) {
|
|
|
3358
3479
|
}
|
|
3359
3480
|
if (terminal.outputSchema || root.outputSchema) import_zod2.z.json().parse(data);
|
|
3360
3481
|
} catch (error) {
|
|
3361
|
-
|
|
3362
|
-
|
|
3482
|
+
if (!(error instanceof import_zod2.z.ZodError)) throw error;
|
|
3483
|
+
const failure = new import_errors3.ValidationError(
|
|
3484
|
+
"INVALID_OUTPUT",
|
|
3485
|
+
`Workflow output validation failed: ${error.message}`,
|
|
3486
|
+
error
|
|
3363
3487
|
);
|
|
3364
|
-
Object.assign(failure, { code: "INVALID_OUTPUT" });
|
|
3365
3488
|
throw failure;
|
|
3366
3489
|
}
|
|
3367
3490
|
return { ...state, data };
|
|
@@ -3873,7 +3996,8 @@ async function orchestrateGraphStream({
|
|
|
3873
3996
|
interruptId,
|
|
3874
3997
|
resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3875
3998
|
resumeOutcome: "failed",
|
|
3876
|
-
resumeError:
|
|
3999
|
+
resumeError: (0, import_errors4.serializeFailure)(resumeError).message,
|
|
4000
|
+
failure: (0, import_errors4.serializeFailure)(resumeError)
|
|
3877
4001
|
},
|
|
3878
4002
|
flush: true
|
|
3879
4003
|
});
|
|
@@ -3944,8 +4068,10 @@ async function orchestrateGraphStream({
|
|
|
3944
4068
|
if (response.closed) outcomeState.config.responseCompleted = true;
|
|
3945
4069
|
if (typeof frameworkAdapter?.checkpointer?.getTuple !== "function") return;
|
|
3946
4070
|
for (const [token, request] of activePendingRequests) {
|
|
3947
|
-
if (budget
|
|
3948
|
-
|
|
4071
|
+
if (budget && request.state)
|
|
4072
|
+
request.state.config.executionBudget = budget;
|
|
4073
|
+
if (response.closed && request.state)
|
|
4074
|
+
request.state.config.responseCompleted = true;
|
|
3949
4075
|
const graphSnapshot = await (0, import_runtime.captureGraphSnapshot)(
|
|
3950
4076
|
frameworkAdapter.checkpointer,
|
|
3951
4077
|
runId,
|
|
@@ -4012,7 +4138,10 @@ async function orchestrateGraphStream({
|
|
|
4012
4138
|
if (pendingStore) {
|
|
4013
4139
|
const savePromise = pendingStore.save(record).catch((error) => {
|
|
4014
4140
|
outcomeError = error;
|
|
4015
|
-
console.error(
|
|
4141
|
+
console.error(
|
|
4142
|
+
"[orchestrator] failed to save pending request",
|
|
4143
|
+
(0, import_errors4.serializeFailure)(error)
|
|
4144
|
+
);
|
|
4016
4145
|
});
|
|
4017
4146
|
pendingRequestWrites.push(savePromise);
|
|
4018
4147
|
}
|
|
@@ -4084,8 +4213,13 @@ async function orchestrateGraphStream({
|
|
|
4084
4213
|
const msg = String(
|
|
4085
4214
|
payload?.message ?? "Unexpected error"
|
|
4086
4215
|
);
|
|
4087
|
-
|
|
4088
|
-
|
|
4216
|
+
const supplied = payload?.failure;
|
|
4217
|
+
outcomeError = (0, import_errors4.isFailureDescriptor)(supplied) ? (0, import_errors4.errorFromFailure)(supplied) : new Error(msg);
|
|
4218
|
+
write({
|
|
4219
|
+
type: "error",
|
|
4220
|
+
message: (0, import_errors4.serializeFailure)(outcomeError).message,
|
|
4221
|
+
failure: (0, import_errors4.serializeFailure)(outcomeError)
|
|
4222
|
+
});
|
|
4089
4223
|
write({ type: "done" });
|
|
4090
4224
|
finished = true;
|
|
4091
4225
|
out.end();
|
|
@@ -4257,7 +4391,10 @@ async function orchestrateGraphStream({
|
|
|
4257
4391
|
input: p?.input
|
|
4258
4392
|
};
|
|
4259
4393
|
void persistAndEmitInterrupt(local).catch((error) => {
|
|
4260
|
-
console.error(
|
|
4394
|
+
console.error(
|
|
4395
|
+
"[orchestrator] failed to emit interrupt",
|
|
4396
|
+
(0, import_errors4.serializeFailure)(error)
|
|
4397
|
+
);
|
|
4261
4398
|
});
|
|
4262
4399
|
return;
|
|
4263
4400
|
}
|
|
@@ -4444,7 +4581,8 @@ async function orchestrateGraphStream({
|
|
|
4444
4581
|
});
|
|
4445
4582
|
write({
|
|
4446
4583
|
type: "error",
|
|
4447
|
-
message:
|
|
4584
|
+
message: (0, import_errors4.serializeFailure)(err).message,
|
|
4585
|
+
failure: (0, import_errors4.serializeFailure)(err)
|
|
4448
4586
|
});
|
|
4449
4587
|
write({ type: "done" });
|
|
4450
4588
|
out.end();
|
|
@@ -4493,7 +4631,10 @@ async function orchestrateGraphStream({
|
|
|
4493
4631
|
}
|
|
4494
4632
|
}
|
|
4495
4633
|
} catch (e) {
|
|
4496
|
-
console.error(
|
|
4634
|
+
console.error(
|
|
4635
|
+
"[orchestrator] framework cleanup failed",
|
|
4636
|
+
(0, import_errors4.serializeFailure)(e)
|
|
4637
|
+
);
|
|
4497
4638
|
}
|
|
4498
4639
|
}
|
|
4499
4640
|
outcomeState = workflowFinalState;
|
|
@@ -4544,7 +4685,10 @@ async function orchestrateGraphStream({
|
|
|
4544
4685
|
});
|
|
4545
4686
|
} catch (error) {
|
|
4546
4687
|
outcomeError = error;
|
|
4547
|
-
console.error(
|
|
4688
|
+
console.error(
|
|
4689
|
+
"[orchestrator] session checkpoint failed",
|
|
4690
|
+
(0, import_errors4.serializeFailure)(error)
|
|
4691
|
+
);
|
|
4548
4692
|
}
|
|
4549
4693
|
}
|
|
4550
4694
|
write({ type: "done", data: workflowFinalState });
|
|
@@ -4613,7 +4757,10 @@ async function orchestrateGraphStream({
|
|
|
4613
4757
|
});
|
|
4614
4758
|
} catch (error) {
|
|
4615
4759
|
outcomeError = error;
|
|
4616
|
-
console.error(
|
|
4760
|
+
console.error(
|
|
4761
|
+
"[orchestrator] session checkpoint failed",
|
|
4762
|
+
(0, import_errors4.serializeFailure)(error)
|
|
4763
|
+
);
|
|
4617
4764
|
}
|
|
4618
4765
|
}
|
|
4619
4766
|
runTraceSpan.setAttributes?.({
|
|
@@ -4663,7 +4810,7 @@ async function orchestrateGraphStream({
|
|
|
4663
4810
|
try {
|
|
4664
4811
|
await frameworkAdapter?.cleanupRun?.(runId, [...namespacesUsed]);
|
|
4665
4812
|
} catch (cleanupError) {
|
|
4666
|
-
console.error("[cancel:cleanupRun]", cleanupError);
|
|
4813
|
+
console.error("[cancel:cleanupRun]", (0, import_errors4.serializeFailure)(cleanupError));
|
|
4667
4814
|
}
|
|
4668
4815
|
outcomeError = (0, import_core2.createExecutionCancelledError)();
|
|
4669
4816
|
fallbackRunSpan?.setAttributes?.({ "kortyx.run.cancelled": true });
|
|
@@ -4793,10 +4940,11 @@ async function orchestrateGraphStream({
|
|
|
4793
4940
|
outcomeError = err;
|
|
4794
4941
|
fallbackRunSpan?.fail?.(err);
|
|
4795
4942
|
emitResumeFailure(err);
|
|
4796
|
-
console.error("[error:orchestrateGraphStream]", err);
|
|
4943
|
+
console.error("[error:orchestrateGraphStream]", (0, import_errors4.serializeFailure)(err));
|
|
4797
4944
|
write({
|
|
4798
4945
|
type: "error",
|
|
4799
|
-
message:
|
|
4946
|
+
message: (0, import_errors4.serializeFailure)(err).message,
|
|
4947
|
+
failure: (0, import_errors4.serializeFailure)(err)
|
|
4800
4948
|
});
|
|
4801
4949
|
write({ type: "done" });
|
|
4802
4950
|
finished = true;
|
|
@@ -4864,12 +5012,16 @@ async function tryPrepareResumeStream({
|
|
|
4864
5012
|
if (!store) return null;
|
|
4865
5013
|
const pending = await store.get(meta.token);
|
|
4866
5014
|
if (!pending || pending.requestId !== meta.requestId) {
|
|
4867
|
-
throw new
|
|
5015
|
+
throw new ExecutionRequestError(
|
|
5016
|
+
"INVALID_RESUME",
|
|
4868
5017
|
"Interrupt is expired, already consumed, or does not match the request."
|
|
4869
5018
|
);
|
|
4870
5019
|
}
|
|
4871
5020
|
if (pending.sessionId && pending.sessionId !== sessionId)
|
|
4872
|
-
throw new
|
|
5021
|
+
throw new ExecutionRequestError(
|
|
5022
|
+
"RESUME_MISMATCH",
|
|
5023
|
+
"Interrupt belongs to another session."
|
|
5024
|
+
);
|
|
4873
5025
|
await validatePending?.(pending);
|
|
4874
5026
|
const isLimitPause = Boolean(pending.schema.meta?.__kortyxExecutionLimit);
|
|
4875
5027
|
const savedBudget = pending.state?.config?.executionBudget;
|
|
@@ -4889,7 +5041,10 @@ async function tryPrepareResumeStream({
|
|
|
4889
5041
|
})();
|
|
4890
5042
|
}
|
|
4891
5043
|
if (store.take && !await store.take(meta.token))
|
|
4892
|
-
throw new
|
|
5044
|
+
throw new ExecutionRequestError(
|
|
5045
|
+
"INVALID_RESUME",
|
|
5046
|
+
"Interrupt has already been resumed or cancelled."
|
|
5047
|
+
);
|
|
4893
5048
|
if (meta.cancel) {
|
|
4894
5049
|
await store.delete(pending.token);
|
|
4895
5050
|
emitTelemetryEvent({
|
|
@@ -5077,10 +5232,7 @@ function resultFromOutcome(outcome, runId, sessionId) {
|
|
|
5077
5232
|
return {
|
|
5078
5233
|
...info,
|
|
5079
5234
|
status: "failed",
|
|
5080
|
-
error:
|
|
5081
|
-
code: typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "EXECUTION_FAILED",
|
|
5082
|
-
message: error instanceof Error ? error.message : String(error)
|
|
5083
|
-
}
|
|
5235
|
+
error: (0, import_errors5.serializeFailure)(error)
|
|
5084
5236
|
};
|
|
5085
5237
|
}
|
|
5086
5238
|
if (outcome.cancelled)
|
|
@@ -5254,10 +5406,11 @@ async function resumeWorkflow(services, args) {
|
|
|
5254
5406
|
);
|
|
5255
5407
|
}).catch(
|
|
5256
5408
|
(error) => reject(
|
|
5257
|
-
error instanceof
|
|
5258
|
-
"
|
|
5259
|
-
|
|
5260
|
-
|
|
5409
|
+
error instanceof Error ? error : new import_errors5.KortyxError("RESUME_FAILED", "Resume failed.", {
|
|
5410
|
+
category: "persistence",
|
|
5411
|
+
cause: error,
|
|
5412
|
+
safeMessage: "The saved execution could not be resumed."
|
|
5413
|
+
})
|
|
5261
5414
|
)
|
|
5262
5415
|
);
|
|
5263
5416
|
});
|
|
@@ -5861,6 +6014,7 @@ function createAgent(args) {
|
|
|
5861
6014
|
createAgent,
|
|
5862
6015
|
createChatRouteHandler,
|
|
5863
6016
|
createCheckpointRouteHandler,
|
|
6017
|
+
createFailureResponse,
|
|
5864
6018
|
extractLatestUserMessage,
|
|
5865
6019
|
handleChatRequestBody,
|
|
5866
6020
|
handleCheckpointRequestBody,
|
|
@@ -5869,6 +6023,7 @@ function createAgent(args) {
|
|
|
5869
6023
|
parseCheckpointRequestBody,
|
|
5870
6024
|
parseResumeMeta,
|
|
5871
6025
|
projectWorkflowTopology,
|
|
6026
|
+
readRequestJson,
|
|
5872
6027
|
streamChat,
|
|
5873
6028
|
streamChatFromRoute,
|
|
5874
6029
|
transformGraphStreamForUI,
|