@kortyx/agent 0.19.0 → 0.20.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 +33 -0
- package/dist/index.js +906 -671
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -157,7 +157,7 @@ var require_dist = __commonJS({
|
|
|
157
157
|
if (!usage) return void 0;
|
|
158
158
|
const input = usage.input ?? 0;
|
|
159
159
|
const output = usage.output ?? 0;
|
|
160
|
-
const total = usage.total ?? input + output + (usage.reasoning ?? 0);
|
|
160
|
+
const total = usage.total ?? input + output + (usage.outputIncludesReasoning ? 0 : usage.reasoning ?? 0);
|
|
161
161
|
if (input === 0 && output === 0 && total === 0) {
|
|
162
162
|
return void 0;
|
|
163
163
|
}
|
|
@@ -432,8 +432,18 @@ var require_dist = __commonJS({
|
|
|
432
432
|
...typeof nodeId === "string" && nodeId.length > 0 ? { node: nodeId } : {}
|
|
433
433
|
});
|
|
434
434
|
};
|
|
435
|
+
var resolveProviderOptions = (defaults, overrides) => {
|
|
436
|
+
const providerOptions = defaults || overrides ? { ...defaults, ...overrides } : void 0;
|
|
437
|
+
for (const [key, value] of Object.entries(overrides ?? {})) {
|
|
438
|
+
const previous = defaults?.[key];
|
|
439
|
+
if (previous && value && typeof previous === "object" && typeof value === "object" && !Array.isArray(previous) && !Array.isArray(value)) {
|
|
440
|
+
if (providerOptions) providerOptions[key] = { ...previous, ...value };
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return providerOptions;
|
|
444
|
+
};
|
|
435
445
|
async function runReasonEngine(args) {
|
|
436
|
-
|
|
446
|
+
let stream = args.stream ?? args.model.options?.streaming ?? true;
|
|
437
447
|
const emit = args.emit ?? true;
|
|
438
448
|
const temperature = args.temperature ?? args.model.options?.temperature ?? args.defaultTemperature;
|
|
439
449
|
const maxOutputTokens = args.maxOutputTokens ?? args.model.options?.maxOutputTokens;
|
|
@@ -441,7 +451,10 @@ var require_dist = __commonJS({
|
|
|
441
451
|
const abortSignal = args.abortSignal ?? args.model.options?.abortSignal;
|
|
442
452
|
const reasoning = args.reasoning ?? args.model.options?.reasoning;
|
|
443
453
|
const responseFormat = args.responseFormat ?? args.model.options?.responseFormat;
|
|
444
|
-
const providerOptions =
|
|
454
|
+
const providerOptions = resolveProviderOptions(
|
|
455
|
+
args.model.options?.providerOptions,
|
|
456
|
+
args.providerOptions
|
|
457
|
+
);
|
|
445
458
|
const tools = args.tools ?? args.model.options?.tools;
|
|
446
459
|
(0, import_core22.throwIfExecutionAborted)(abortSignal);
|
|
447
460
|
const model = args.model.provider.getModel(args.model.modelId, {
|
|
@@ -455,6 +468,7 @@ var require_dist = __commonJS({
|
|
|
455
468
|
...tools !== void 0 ? { tools } : {},
|
|
456
469
|
...providerOptions !== void 0 ? { providerOptions } : {}
|
|
457
470
|
});
|
|
471
|
+
if (tools?.length && !model.supportsToolStreaming) stream = false;
|
|
458
472
|
const messages = args.messages !== void 0 ? args.messages : [
|
|
459
473
|
...typeof args.system === "string" && args.system.length > 0 ? [{ role: "system", content: args.system }] : [],
|
|
460
474
|
{ role: "user", content: String(args.input ?? "") }
|
|
@@ -482,7 +496,9 @@ var require_dist = __commonJS({
|
|
|
482
496
|
},
|
|
483
497
|
telemetry: {
|
|
484
498
|
...args.telemetry ?? {},
|
|
485
|
-
input: args.telemetry?.input ?? messages
|
|
499
|
+
input: args.telemetry?.input ?? messages.map(
|
|
500
|
+
({ continuation: _continuation, raw: _raw, ...message }) => message
|
|
501
|
+
)
|
|
486
502
|
}
|
|
487
503
|
});
|
|
488
504
|
const modelRequestStartedAt = Date.now();
|
|
@@ -513,7 +529,11 @@ var require_dist = __commonJS({
|
|
|
513
529
|
});
|
|
514
530
|
};
|
|
515
531
|
const failTrace = (span, error) => {
|
|
532
|
+
const detail = error;
|
|
516
533
|
span?.fail?.(error, {
|
|
534
|
+
...detail?.usage ? { usage: detail.usage } : {},
|
|
535
|
+
...detail?.finishReason ? { finishReason: detail.finishReason } : {},
|
|
536
|
+
...detail?.providerMetadata ? { providerMetadata: detail.providerMetadata } : {},
|
|
517
537
|
attributes: {
|
|
518
538
|
providerId: args.model.provider.id,
|
|
519
539
|
modelId: args.model.modelId
|
|
@@ -522,6 +542,7 @@ var require_dist = __commonJS({
|
|
|
522
542
|
};
|
|
523
543
|
try {
|
|
524
544
|
if (stream) {
|
|
545
|
+
let continuation;
|
|
525
546
|
let final = "";
|
|
526
547
|
let raw;
|
|
527
548
|
let usage;
|
|
@@ -560,6 +581,7 @@ var require_dist = __commonJS({
|
|
|
560
581
|
break;
|
|
561
582
|
}
|
|
562
583
|
case "finish": {
|
|
584
|
+
continuation = chunk.continuation;
|
|
563
585
|
if (chunk.raw !== void 0) {
|
|
564
586
|
raw = chunk.raw;
|
|
565
587
|
}
|
|
@@ -608,6 +630,7 @@ var require_dist = __commonJS({
|
|
|
608
630
|
}
|
|
609
631
|
const result2 = {
|
|
610
632
|
text: final,
|
|
633
|
+
...continuation ? { continuation } : {},
|
|
611
634
|
...raw !== void 0 ? { raw } : {},
|
|
612
635
|
...usage !== void 0 ? { usage } : {},
|
|
613
636
|
...finishReason !== void 0 ? { finishReason } : {},
|
|
@@ -621,6 +644,7 @@ var require_dist = __commonJS({
|
|
|
621
644
|
}
|
|
622
645
|
const response = await model.invoke(messages);
|
|
623
646
|
(0, import_core22.throwIfExecutionAborted)(abortSignal);
|
|
647
|
+
if (response.content) args.onTextChunk?.(response.content);
|
|
624
648
|
if (emit) {
|
|
625
649
|
emitNodeEvent(args.emitEvent, args.nodeId, "text-start", {
|
|
626
650
|
...commonMeta
|
|
@@ -637,6 +661,7 @@ var require_dist = __commonJS({
|
|
|
637
661
|
}
|
|
638
662
|
const result = {
|
|
639
663
|
text: response.content,
|
|
664
|
+
...response.continuation ? { continuation: response.continuation } : {},
|
|
640
665
|
...response.raw !== void 0 ? { raw: response.raw } : {},
|
|
641
666
|
...response.usage !== void 0 ? { usage: response.usage } : {},
|
|
642
667
|
...response.finishReason !== void 0 ? { finishReason: response.finishReason } : {},
|
|
@@ -668,472 +693,184 @@ var require_dist = __commonJS({
|
|
|
668
693
|
);
|
|
669
694
|
(0, import_core32.throwIfExecutionAborted)(abortSignal);
|
|
670
695
|
ctx.node.consumeExecution?.("maxModelPasses");
|
|
671
|
-
return runReasonEngine({
|
|
672
|
-
model: args.model,
|
|
673
|
-
input: inputOverride ?? args.input,
|
|
674
|
-
system: args.system,
|
|
675
|
-
temperature: args.temperature,
|
|
676
|
-
maxOutputTokens: args.maxOutputTokens,
|
|
677
|
-
stopSequences: args.stopSequences,
|
|
678
|
-
abortSignal,
|
|
679
|
-
reasoning: args.reasoning,
|
|
680
|
-
responseFormat: args.responseFormat,
|
|
681
|
-
providerOptions: args.providerOptions,
|
|
682
|
-
tools: args.tools,
|
|
683
|
-
messages: args.messages,
|
|
684
|
-
defaultTemperature: ctx.node.config?.model?.temperature,
|
|
685
|
-
stream: args.stream,
|
|
686
|
-
emit: args.emit,
|
|
687
|
-
onTextChunk: args.onTextChunk,
|
|
688
|
-
telemetry: args.telemetry,
|
|
689
|
-
nodeId: ctx.node.graph.node,
|
|
690
|
-
emitEvent: ctx.node.emit,
|
|
691
|
-
reasonTrace: ctx.reasonTrace,
|
|
692
|
-
id: meta.id,
|
|
693
|
-
opId: meta.opId
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
var tryJsonParse = (value) => {
|
|
697
696
|
try {
|
|
698
|
-
return
|
|
697
|
+
return await runReasonEngine({
|
|
698
|
+
model: args.model,
|
|
699
|
+
input: inputOverride ?? args.input,
|
|
700
|
+
system: args.system,
|
|
701
|
+
temperature: args.temperature,
|
|
702
|
+
maxOutputTokens: args.maxOutputTokens,
|
|
703
|
+
stopSequences: args.stopSequences,
|
|
704
|
+
abortSignal,
|
|
705
|
+
reasoning: args.reasoning,
|
|
706
|
+
responseFormat: args.responseFormat,
|
|
707
|
+
providerOptions: args.providerOptions,
|
|
708
|
+
tools: args.tools,
|
|
709
|
+
messages: args.messages,
|
|
710
|
+
defaultTemperature: ctx.node.config?.model?.temperature,
|
|
711
|
+
stream: args.stream,
|
|
712
|
+
emit: args.emit,
|
|
713
|
+
onTextChunk: args.onTextChunk,
|
|
714
|
+
telemetry: args.telemetry,
|
|
715
|
+
nodeId: ctx.node.graph.node,
|
|
716
|
+
emitEvent: ctx.node.emit,
|
|
717
|
+
reasonTrace: ctx.reasonTrace,
|
|
718
|
+
id: meta.id,
|
|
719
|
+
opId: meta.opId
|
|
720
|
+
});
|
|
699
721
|
} catch (error) {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
};
|
|
722
|
+
const usage = error?.usage;
|
|
723
|
+
if (usage) accumulateTokenUsage(usage);
|
|
724
|
+
throw error;
|
|
704
725
|
}
|
|
705
|
-
}
|
|
706
|
-
var
|
|
707
|
-
|
|
708
|
-
if (
|
|
709
|
-
|
|
710
|
-
return inner.length > 0 ? inner : null;
|
|
711
|
-
};
|
|
712
|
-
var tryStringify = (value) => {
|
|
713
|
-
if (typeof value === "string") return value;
|
|
726
|
+
}
|
|
727
|
+
var import_zod22 = require("zod");
|
|
728
|
+
function inferOutputFormat(schema, explicit) {
|
|
729
|
+
if (explicit) return { responseFormat: explicit };
|
|
730
|
+
if (!schema) return {};
|
|
714
731
|
try {
|
|
715
|
-
|
|
732
|
+
const json = (0, import_zod22.toJSONSchema)(schema);
|
|
733
|
+
const clean = (value) => {
|
|
734
|
+
if (Array.isArray(value)) return value.map(clean);
|
|
735
|
+
if (!value || typeof value !== "object") return value;
|
|
736
|
+
const object = value;
|
|
737
|
+
if ([
|
|
738
|
+
"allOf",
|
|
739
|
+
"not",
|
|
740
|
+
"dependentRequired",
|
|
741
|
+
"dependentSchemas",
|
|
742
|
+
"if",
|
|
743
|
+
"then",
|
|
744
|
+
"else",
|
|
745
|
+
"prefixItems"
|
|
746
|
+
].some((key) => key in object))
|
|
747
|
+
throw new Error(
|
|
748
|
+
"Schema composition requires an explicit provider schema"
|
|
749
|
+
);
|
|
750
|
+
if (object.type === "object") {
|
|
751
|
+
if (object.additionalProperties !== false)
|
|
752
|
+
throw new Error(
|
|
753
|
+
"Dynamic properties require an explicit provider schema"
|
|
754
|
+
);
|
|
755
|
+
const properties = object.properties;
|
|
756
|
+
const required = object.required;
|
|
757
|
+
if (properties && Object.keys(properties).some((key) => !required?.includes(key))) {
|
|
758
|
+
throw new Error(
|
|
759
|
+
"Optional properties require an explicit provider schema"
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
return Object.fromEntries(
|
|
764
|
+
Object.entries(object).filter(([key]) => key !== "$schema" && key !== "default").map(([key, child]) => {
|
|
765
|
+
if ((key === "properties" || key === "$defs" || key === "definitions") && child && typeof child === "object")
|
|
766
|
+
return [
|
|
767
|
+
key,
|
|
768
|
+
Object.fromEntries(
|
|
769
|
+
Object.entries(child).map(([name, definition]) => [
|
|
770
|
+
name,
|
|
771
|
+
clean(definition)
|
|
772
|
+
])
|
|
773
|
+
)
|
|
774
|
+
];
|
|
775
|
+
return [
|
|
776
|
+
key,
|
|
777
|
+
key === "enum" || key === "const" ? child : clean(child)
|
|
778
|
+
];
|
|
779
|
+
})
|
|
780
|
+
);
|
|
781
|
+
};
|
|
782
|
+
if (json.type !== "object")
|
|
783
|
+
throw new Error("The provider schema must have an object root");
|
|
784
|
+
return { responseFormat: { type: "json", schema: clean(json) } };
|
|
716
785
|
} catch {
|
|
717
|
-
return
|
|
786
|
+
return {
|
|
787
|
+
responseFormat: { type: "json" },
|
|
788
|
+
warnings: [
|
|
789
|
+
{
|
|
790
|
+
type: "compatibility",
|
|
791
|
+
feature: "outputSchema",
|
|
792
|
+
details: "This validator cannot be inferred as a strict provider JSON schema. Kortyx still validates the final output locally. Supply responseFormat.schema to enforce a wire schema."
|
|
793
|
+
}
|
|
794
|
+
]
|
|
795
|
+
};
|
|
718
796
|
}
|
|
719
|
-
}
|
|
720
|
-
var
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
const
|
|
725
|
-
|
|
726
|
-
const block = extractJsonCodeBlock(trimmed);
|
|
727
|
-
if (block) {
|
|
728
|
-
const parsedBlock = tryJsonParse(block);
|
|
729
|
-
if (parsedBlock.ok) return parsedBlock.value;
|
|
797
|
+
}
|
|
798
|
+
var resolveAppendFieldPaths = (cfg) => {
|
|
799
|
+
const fields = cfg?.fields;
|
|
800
|
+
if (!fields) return [];
|
|
801
|
+
const appendPaths = Object.entries(fields).filter(([, mode]) => mode === "append").map(([path]) => path);
|
|
802
|
+
for (const path of appendPaths) {
|
|
803
|
+
assertStructuredPath(path, "useReason structured append");
|
|
730
804
|
}
|
|
731
|
-
return
|
|
732
|
-
};
|
|
733
|
-
var looksLikeStructuredJsonAttempt = (value) => {
|
|
734
|
-
const trimmed = value.trim();
|
|
735
|
-
if (!trimmed) return false;
|
|
736
|
-
return trimmed.startsWith("{") || trimmed.startsWith("[") || /^```(?:json)?/i.test(trimmed);
|
|
805
|
+
return appendPaths;
|
|
737
806
|
};
|
|
738
|
-
var
|
|
739
|
-
const
|
|
740
|
-
if (!
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
return !parsedBlock.ok && Boolean(parsedBlock.error);
|
|
807
|
+
var resolveSetFieldPaths = (cfg) => {
|
|
808
|
+
const fields = cfg?.fields;
|
|
809
|
+
if (!fields) return [];
|
|
810
|
+
const setPaths = Object.entries(fields).filter(([, mode]) => mode === "set").map(([path]) => path);
|
|
811
|
+
for (const path of setPaths) {
|
|
812
|
+
assertStructuredPath(path, "useReason structured set");
|
|
813
|
+
}
|
|
814
|
+
return setPaths;
|
|
747
815
|
};
|
|
748
|
-
var
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
var parseReasonOutputWithSchema = (args) => {
|
|
755
|
-
const candidate = resolveOutputCandidate(args.text);
|
|
756
|
-
try {
|
|
757
|
-
return parseWithSchema(args.schema, candidate, args.label);
|
|
758
|
-
} catch (error) {
|
|
759
|
-
if (args.finishReason?.unified === "length" || isLikelyTruncatedStructuredOutput(args.text)) {
|
|
760
|
-
throw createTruncatedStructuredOutputError(args.label);
|
|
761
|
-
}
|
|
762
|
-
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
763
|
-
throw createInvalidStructuredOutputError(args.label);
|
|
764
|
-
}
|
|
765
|
-
throw error;
|
|
816
|
+
var resolveTextDeltaFieldPaths = (cfg) => {
|
|
817
|
+
const fields = cfg?.fields;
|
|
818
|
+
if (!fields) return [];
|
|
819
|
+
const textPaths = Object.entries(fields).filter(([, mode]) => mode === "text-delta").map(([path]) => path);
|
|
820
|
+
for (const path of textPaths) {
|
|
821
|
+
assertStructuredPath(path, "useReason structured text-delta");
|
|
766
822
|
}
|
|
823
|
+
return textPaths;
|
|
767
824
|
};
|
|
768
|
-
var
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
825
|
+
var extractCompletedStringValueAt = (args) => {
|
|
826
|
+
let value = "";
|
|
827
|
+
for (let i = args.start; i < args.text.length; i += 1) {
|
|
828
|
+
const ch = args.text[i];
|
|
829
|
+
if (ch === void 0) break;
|
|
830
|
+
if (ch === '"') {
|
|
831
|
+
return {
|
|
832
|
+
complete: true,
|
|
833
|
+
value
|
|
834
|
+
};
|
|
773
835
|
}
|
|
774
|
-
if (
|
|
775
|
-
|
|
836
|
+
if (ch !== "\\") {
|
|
837
|
+
value += ch;
|
|
838
|
+
continue;
|
|
776
839
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
let interruptRequired = true;
|
|
783
|
-
if (mode === "optional") {
|
|
784
|
-
if (candidate.decision !== "continue" && candidate.decision !== "interrupt") {
|
|
785
|
-
throw new Error(
|
|
786
|
-
'useReason optional interrupt first pass must include decision "continue" or "interrupt".'
|
|
787
|
-
);
|
|
840
|
+
const next = args.text[i + 1];
|
|
841
|
+
if (!next) {
|
|
842
|
+
return {
|
|
843
|
+
complete: false
|
|
844
|
+
};
|
|
788
845
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
candidate.request,
|
|
794
|
-
candidate.interrupt
|
|
795
|
-
].some((value) => value !== null && value !== void 0);
|
|
796
|
-
if (hasUnexpectedRequest) {
|
|
797
|
-
throw new Error(
|
|
798
|
-
'useReason optional interrupt first pass with decision "continue" must not include an interrupt request.'
|
|
799
|
-
);
|
|
800
|
-
}
|
|
846
|
+
if (next === '"' || next === "\\" || next === "/" || next === "b" || next === "f" || next === "n" || next === "r" || next === "t") {
|
|
847
|
+
value += next === "b" ? "\b" : next === "f" ? "\f" : next === "n" ? "\n" : next === "r" ? "\r" : next === "t" ? " " : next;
|
|
848
|
+
i += 1;
|
|
849
|
+
continue;
|
|
801
850
|
}
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
candidate.interrupt,
|
|
809
|
-
mode === "required" ? candidate : void 0
|
|
810
|
-
];
|
|
811
|
-
const requestPayload = requestCandidates.find(
|
|
812
|
-
(value) => value !== null && value !== void 0
|
|
813
|
-
);
|
|
814
|
-
request = parseWithSchema(
|
|
815
|
-
args.requestSchema,
|
|
816
|
-
requestPayload,
|
|
817
|
-
"useReason interrupt.request"
|
|
818
|
-
);
|
|
819
|
-
}
|
|
820
|
-
let output;
|
|
821
|
-
if (args.outputSchema) {
|
|
822
|
-
const outputPayload = Object.hasOwn(candidate, "output") ? candidate.output : candidate;
|
|
823
|
-
try {
|
|
824
|
-
output = parseWithSchema(
|
|
825
|
-
args.outputSchema,
|
|
826
|
-
outputPayload,
|
|
827
|
-
"useReason output"
|
|
828
|
-
);
|
|
829
|
-
} catch (error) {
|
|
830
|
-
if (args.finishReason?.unified === "length" || isLikelyTruncatedStructuredOutput(args.text)) {
|
|
831
|
-
throw createTruncatedStructuredOutputError("useReason output");
|
|
832
|
-
}
|
|
833
|
-
if (typeof outputPayload === "string" && outputPayload.trim().length > 0) {
|
|
834
|
-
throw createInvalidStructuredOutputError("useReason output");
|
|
851
|
+
if (next === "u") {
|
|
852
|
+
const hex = args.text.slice(i + 2, i + 6);
|
|
853
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
854
|
+
return {
|
|
855
|
+
complete: false
|
|
856
|
+
};
|
|
835
857
|
}
|
|
836
|
-
|
|
858
|
+
value += String.fromCharCode(Number.parseInt(hex, 16));
|
|
859
|
+
i += 5;
|
|
860
|
+
continue;
|
|
837
861
|
}
|
|
838
|
-
}
|
|
839
|
-
const explicitDraft = typeof candidate.draftText === "string" && candidate.draftText.length > 0 ? candidate.draftText : typeof candidate.text === "string" && candidate.text.length > 0 ? candidate.text : void 0;
|
|
840
|
-
if (!args.outputSchema && !explicitDraft) {
|
|
841
|
-
throw new Error(
|
|
842
|
-
"useReason first pass with interrupt requires `draftText` when outputSchema is not provided."
|
|
843
|
-
);
|
|
844
|
-
}
|
|
845
|
-
const draftText = explicitDraft ?? (output !== void 0 ? tryStringify(output) : String(args.text ?? ""));
|
|
846
|
-
if (!interruptRequired) {
|
|
847
862
|
return {
|
|
848
|
-
|
|
849
|
-
interruptRequired: false,
|
|
850
|
-
...output !== void 0 ? { output } : {}
|
|
863
|
+
complete: false
|
|
851
864
|
};
|
|
852
865
|
}
|
|
853
866
|
return {
|
|
854
|
-
|
|
855
|
-
interruptRequired: true,
|
|
856
|
-
request,
|
|
857
|
-
...output !== void 0 ? { output } : {}
|
|
867
|
+
complete: false
|
|
858
868
|
};
|
|
859
869
|
};
|
|
860
|
-
var
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
return JSON.stringify(value, null, 2);
|
|
865
|
-
} catch {
|
|
866
|
-
return String(value);
|
|
867
|
-
}
|
|
868
|
-
};
|
|
869
|
-
var tryGetSchemaHint = (schema) => {
|
|
870
|
-
try {
|
|
871
|
-
const hint = (0, import_zod22.toJSONSchema)(schema);
|
|
872
|
-
return JSON.stringify(hint, null, 2);
|
|
873
|
-
} catch {
|
|
874
|
-
return void 0;
|
|
875
|
-
}
|
|
876
|
-
};
|
|
877
|
-
var withSchemaHint = (input, label, schema) => {
|
|
878
|
-
const hint = tryGetSchemaHint(schema);
|
|
879
|
-
if (!hint) return input;
|
|
880
|
-
return `${input}
|
|
881
|
-
|
|
882
|
-
${label}:
|
|
883
|
-
${hint}`;
|
|
884
|
-
};
|
|
885
|
-
var defaultInterruptFirstPassInput = (args) => {
|
|
886
|
-
const mode = args.mode ?? "required";
|
|
887
|
-
const base = mode === "optional" ? args.outputSchema ? [
|
|
888
|
-
args.input,
|
|
889
|
-
"Output rules:",
|
|
890
|
-
"- Return JSON only. No markdown fences.",
|
|
891
|
-
"- Return an object with keys: decision, output, interruptRequest, draftText.",
|
|
892
|
-
'- decision must be either "continue" or "interrupt".',
|
|
893
|
-
'- Use decision "continue" when you can produce the final output without asking the user.',
|
|
894
|
-
'- Use decision "interrupt" only when user input is needed before finalizing.',
|
|
895
|
-
"- output must match the expected output JSON schema.",
|
|
896
|
-
'- When decision is "interrupt", interruptRequest must match the expected interrupt request JSON schema and must be a non-null object.',
|
|
897
|
-
'- When decision is "continue", interruptRequest must be null.',
|
|
898
|
-
"- draftText should be a concise plain-language summary of output."
|
|
899
|
-
].join("\n\n") : [
|
|
900
|
-
args.input,
|
|
901
|
-
"Output rules:",
|
|
902
|
-
"- Return JSON only. No markdown fences.",
|
|
903
|
-
"- Return an object with keys: decision, draftText, interruptRequest.",
|
|
904
|
-
'- decision must be either "continue" or "interrupt".',
|
|
905
|
-
'- Use decision "continue" when you can produce the final answer without asking the user.',
|
|
906
|
-
'- Use decision "interrupt" only when user input is needed before finalizing.',
|
|
907
|
-
"- draftText should be the current answer text.",
|
|
908
|
-
'- When decision is "interrupt", interruptRequest must match the expected interrupt request JSON schema and must be a non-null object.',
|
|
909
|
-
'- When decision is "continue", interruptRequest must be null.'
|
|
910
|
-
].join("\n\n") : args.outputSchema ? [
|
|
911
|
-
args.input,
|
|
912
|
-
"Output rules:",
|
|
913
|
-
"- Return JSON only. No markdown fences.",
|
|
914
|
-
"- Return an object with keys: output, interruptRequest, draftText.",
|
|
915
|
-
"- output must match the expected output JSON schema.",
|
|
916
|
-
"- interruptRequest must match the expected interrupt request JSON schema.",
|
|
917
|
-
"- interruptRequest must be a non-null object.",
|
|
918
|
-
"- draftText should be a concise plain-language summary of output.",
|
|
919
|
-
"- If uncertain, still return a valid interruptRequest with safe default options."
|
|
920
|
-
].join("\n\n") : [
|
|
921
|
-
args.input,
|
|
922
|
-
"Output rules:",
|
|
923
|
-
"- Return JSON only. No markdown fences.",
|
|
924
|
-
"- Return an object with keys: draftText, interruptRequest.",
|
|
925
|
-
"- draftText should be the current draft answer text.",
|
|
926
|
-
"- interruptRequest must match the expected interrupt request JSON schema.",
|
|
927
|
-
"- interruptRequest must be a non-null object.",
|
|
928
|
-
"- If uncertain, still return a valid interruptRequest with safe default options."
|
|
929
|
-
].join("\n\n");
|
|
930
|
-
const withInterruptSchema = withSchemaHint(
|
|
931
|
-
base,
|
|
932
|
-
"Expected interrupt request JSON schema (for `interruptRequest`)",
|
|
933
|
-
args.requestSchema
|
|
934
|
-
);
|
|
935
|
-
if (!args.outputSchema) return withInterruptSchema;
|
|
936
|
-
const withOutputSchema = withSchemaHint(
|
|
937
|
-
withInterruptSchema,
|
|
938
|
-
"Expected output JSON schema (for `output`)",
|
|
939
|
-
args.outputSchema
|
|
940
|
-
);
|
|
941
|
-
return [
|
|
942
|
-
withOutputSchema,
|
|
943
|
-
"JSON template:",
|
|
944
|
-
mode === "optional" ? '{ "decision": "continue", "output": { ... }, "interruptRequest": null, "draftText": "..." }' : '{ "output": { ... }, "interruptRequest": { ... }, "draftText": "..." }'
|
|
945
|
-
].join("\n\n");
|
|
946
|
-
};
|
|
947
|
-
var defaultContinuationInput = (args) => [
|
|
948
|
-
"You are continuing a paused reasoning task after user input.",
|
|
949
|
-
"Update the previous result using the user response and return the final answer only.",
|
|
950
|
-
"If the previous output was JSON, return JSON in the same schema.",
|
|
951
|
-
"",
|
|
952
|
-
`Original request:
|
|
953
|
-
${args.input}`,
|
|
954
|
-
`Draft answer text:
|
|
955
|
-
${args.draftText}`,
|
|
956
|
-
`Draft output object:
|
|
957
|
-
${tryStringify2(args.draftOutput ?? args.draftText)}`,
|
|
958
|
-
`Interrupt request shown to user:
|
|
959
|
-
${tryStringify2(args.request)}`,
|
|
960
|
-
`User response:
|
|
961
|
-
${tryStringify2(args.response)}`
|
|
962
|
-
].join("\n\n");
|
|
963
|
-
var withOutputGuardrails = (input, schema) => {
|
|
964
|
-
const base = [
|
|
965
|
-
input,
|
|
966
|
-
"Output rules:",
|
|
967
|
-
"- Return only JSON, no markdown fences.",
|
|
968
|
-
"- Ensure the response conforms to the expected output schema.",
|
|
969
|
-
"- Do not include explanatory text outside the JSON object."
|
|
970
|
-
].join("\n\n");
|
|
971
|
-
return withSchemaHint(base, "Expected output JSON schema", schema);
|
|
972
|
-
};
|
|
973
|
-
var withStructuredStreamHints = (input, args) => {
|
|
974
|
-
const rules = [];
|
|
975
|
-
for (const path of args.setFieldPaths ?? []) {
|
|
976
|
-
rules.push(
|
|
977
|
-
`- For the field path pattern \`${path}\`, write one stable final value and do not rewrite it after it is complete.`
|
|
978
|
-
);
|
|
979
|
-
}
|
|
980
|
-
for (const path of args.appendFieldPaths ?? []) {
|
|
981
|
-
rules.push(
|
|
982
|
-
`- For the array field path pattern \`${path}\`, write items in final order and finish each item before starting the next.`
|
|
983
|
-
);
|
|
984
|
-
rules.push(
|
|
985
|
-
`- Once an item in \`${path}\` is complete, do not rewrite or reorder earlier items.`
|
|
986
|
-
);
|
|
987
|
-
}
|
|
988
|
-
for (const path of args.textDeltaFieldPaths ?? []) {
|
|
989
|
-
rules.push(
|
|
990
|
-
`- For the string field path pattern \`${path}\`, write the value progressively by appending text to the end.`
|
|
991
|
-
);
|
|
992
|
-
rules.push(
|
|
993
|
-
`- Do not rewrite or replace the earlier prefix of \`${path}\` once emitted.`
|
|
994
|
-
);
|
|
995
|
-
}
|
|
996
|
-
if (rules.length === 0) return input;
|
|
997
|
-
return [
|
|
998
|
-
input,
|
|
999
|
-
"Streaming rules:",
|
|
1000
|
-
...rules,
|
|
1001
|
-
"- Keep the overall response as valid JSON."
|
|
1002
|
-
].join("\n\n");
|
|
1003
|
-
};
|
|
1004
|
-
var mergeUsage = (left, right) => {
|
|
1005
|
-
if (!left) return right;
|
|
1006
|
-
if (!right) return left;
|
|
1007
|
-
const sum = (a, b) => a === void 0 && b === void 0 ? void 0 : (a ?? 0) + (b ?? 0);
|
|
1008
|
-
const raw = left.raw || right.raw ? {
|
|
1009
|
-
...left.raw ?? {},
|
|
1010
|
-
...right.raw ?? {}
|
|
1011
|
-
} : void 0;
|
|
1012
|
-
const input = sum(left.input, right.input);
|
|
1013
|
-
const output = sum(left.output, right.output);
|
|
1014
|
-
const total = sum(left.total, right.total);
|
|
1015
|
-
const reasoning = sum(left.reasoning, right.reasoning);
|
|
1016
|
-
const cacheRead = sum(left.cacheRead, right.cacheRead);
|
|
1017
|
-
const cacheWrite = sum(left.cacheWrite, right.cacheWrite);
|
|
1018
|
-
const merged = {};
|
|
1019
|
-
if (input !== void 0) merged.input = input;
|
|
1020
|
-
if (output !== void 0) merged.output = output;
|
|
1021
|
-
if (total !== void 0) merged.total = total;
|
|
1022
|
-
if (reasoning !== void 0) merged.reasoning = reasoning;
|
|
1023
|
-
if (cacheRead !== void 0) merged.cacheRead = cacheRead;
|
|
1024
|
-
if (cacheWrite !== void 0) merged.cacheWrite = cacheWrite;
|
|
1025
|
-
if (raw) merged.raw = raw;
|
|
1026
|
-
return merged;
|
|
1027
|
-
};
|
|
1028
|
-
var mergeWarnings = (left, right) => {
|
|
1029
|
-
if (!left?.length) return right;
|
|
1030
|
-
if (!right?.length) return left;
|
|
1031
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1032
|
-
const merged = [];
|
|
1033
|
-
for (const warning of [...left, ...right]) {
|
|
1034
|
-
const key = JSON.stringify(warning);
|
|
1035
|
-
if (seen.has(key)) continue;
|
|
1036
|
-
seen.add(key);
|
|
1037
|
-
merged.push(warning);
|
|
1038
|
-
}
|
|
1039
|
-
return merged;
|
|
1040
|
-
};
|
|
1041
|
-
var mergeProviderMetadata = (left, right) => {
|
|
1042
|
-
if (!left) return right;
|
|
1043
|
-
if (!right) return left;
|
|
1044
|
-
return {
|
|
1045
|
-
...left,
|
|
1046
|
-
...right
|
|
1047
|
-
};
|
|
1048
|
-
};
|
|
1049
|
-
var emitReasonStructuredOutput = (args) => {
|
|
1050
|
-
if (!args.emit || !shouldEmitStructured(args.structured)) return;
|
|
1051
|
-
emitStructuredData({
|
|
1052
|
-
dataType: args.structured?.dataType ?? "reason-output",
|
|
1053
|
-
data: args.output,
|
|
1054
|
-
kind: "final",
|
|
1055
|
-
...args.structured?.schemaId ? { schemaId: args.structured.schemaId } : {},
|
|
1056
|
-
...args.structured?.schemaVersion ? { schemaVersion: args.structured.schemaVersion } : {},
|
|
1057
|
-
...args.id ? { id: args.id } : {},
|
|
1058
|
-
streamId: args.opId
|
|
1059
|
-
});
|
|
1060
|
-
};
|
|
1061
|
-
var resolveAppendFieldPaths = (cfg) => {
|
|
1062
|
-
const fields = cfg?.fields;
|
|
1063
|
-
if (!fields) return [];
|
|
1064
|
-
const appendPaths = Object.entries(fields).filter(([, mode]) => mode === "append").map(([path]) => path);
|
|
1065
|
-
for (const path of appendPaths) {
|
|
1066
|
-
assertStructuredPath(path, "useReason structured append");
|
|
1067
|
-
}
|
|
1068
|
-
return appendPaths;
|
|
1069
|
-
};
|
|
1070
|
-
var resolveSetFieldPaths = (cfg) => {
|
|
1071
|
-
const fields = cfg?.fields;
|
|
1072
|
-
if (!fields) return [];
|
|
1073
|
-
const setPaths = Object.entries(fields).filter(([, mode]) => mode === "set").map(([path]) => path);
|
|
1074
|
-
for (const path of setPaths) {
|
|
1075
|
-
assertStructuredPath(path, "useReason structured set");
|
|
1076
|
-
}
|
|
1077
|
-
return setPaths;
|
|
1078
|
-
};
|
|
1079
|
-
var resolveTextDeltaFieldPaths = (cfg) => {
|
|
1080
|
-
const fields = cfg?.fields;
|
|
1081
|
-
if (!fields) return [];
|
|
1082
|
-
const textPaths = Object.entries(fields).filter(([, mode]) => mode === "text-delta").map(([path]) => path);
|
|
1083
|
-
for (const path of textPaths) {
|
|
1084
|
-
assertStructuredPath(path, "useReason structured text-delta");
|
|
1085
|
-
}
|
|
1086
|
-
return textPaths;
|
|
1087
|
-
};
|
|
1088
|
-
var extractCompletedStringValueAt = (args) => {
|
|
1089
|
-
let value = "";
|
|
1090
|
-
for (let i = args.start; i < args.text.length; i += 1) {
|
|
1091
|
-
const ch = args.text[i];
|
|
1092
|
-
if (ch === void 0) break;
|
|
1093
|
-
if (ch === '"') {
|
|
1094
|
-
return {
|
|
1095
|
-
complete: true,
|
|
1096
|
-
value
|
|
1097
|
-
};
|
|
1098
|
-
}
|
|
1099
|
-
if (ch !== "\\") {
|
|
1100
|
-
value += ch;
|
|
1101
|
-
continue;
|
|
1102
|
-
}
|
|
1103
|
-
const next = args.text[i + 1];
|
|
1104
|
-
if (!next) {
|
|
1105
|
-
return {
|
|
1106
|
-
complete: false
|
|
1107
|
-
};
|
|
1108
|
-
}
|
|
1109
|
-
if (next === '"' || next === "\\" || next === "/" || next === "b" || next === "f" || next === "n" || next === "r" || next === "t") {
|
|
1110
|
-
value += next === "b" ? "\b" : next === "f" ? "\f" : next === "n" ? "\n" : next === "r" ? "\r" : next === "t" ? " " : next;
|
|
1111
|
-
i += 1;
|
|
1112
|
-
continue;
|
|
1113
|
-
}
|
|
1114
|
-
if (next === "u") {
|
|
1115
|
-
const hex = args.text.slice(i + 2, i + 6);
|
|
1116
|
-
if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
1117
|
-
return {
|
|
1118
|
-
complete: false
|
|
1119
|
-
};
|
|
1120
|
-
}
|
|
1121
|
-
value += String.fromCharCode(Number.parseInt(hex, 16));
|
|
1122
|
-
i += 5;
|
|
1123
|
-
continue;
|
|
1124
|
-
}
|
|
1125
|
-
return {
|
|
1126
|
-
complete: false
|
|
1127
|
-
};
|
|
1128
|
-
}
|
|
1129
|
-
return {
|
|
1130
|
-
complete: false
|
|
1131
|
-
};
|
|
1132
|
-
};
|
|
1133
|
-
var skipWhitespace = (text, start) => {
|
|
1134
|
-
let i = start;
|
|
1135
|
-
while (i < text.length && /\s/.test(text[i] ?? "")) i += 1;
|
|
1136
|
-
return i;
|
|
870
|
+
var skipWhitespace = (text, start) => {
|
|
871
|
+
let i = start;
|
|
872
|
+
while (i < text.length && /\s/.test(text[i] ?? "")) i += 1;
|
|
873
|
+
return i;
|
|
1137
874
|
};
|
|
1138
875
|
var pathSegmentMatches = (patternPart, actualPart) => patternPart === "*" || patternPart === actualPart;
|
|
1139
876
|
var pathMatchesPattern = (actualParts, patternParts) => actualParts.length === patternParts.length && actualParts.every(
|
|
@@ -1517,103 +1254,552 @@ ${tryStringify2(args.response)}`
|
|
|
1517
1254
|
}
|
|
1518
1255
|
return items;
|
|
1519
1256
|
};
|
|
1520
|
-
var extractCompletedArrayItemGroups = (args) => {
|
|
1521
|
-
return locateValueStarts(args).flatMap((match) => {
|
|
1522
|
-
const items = extractCompletedArrayItems({
|
|
1523
|
-
text: args.text,
|
|
1524
|
-
path: match.path
|
|
1525
|
-
});
|
|
1526
|
-
return items.length > 0 ? [
|
|
1527
|
-
{
|
|
1528
|
-
path: match.path,
|
|
1529
|
-
items
|
|
1530
|
-
}
|
|
1531
|
-
] : [];
|
|
1532
|
-
});
|
|
1257
|
+
var extractCompletedArrayItemGroups = (args) => {
|
|
1258
|
+
return locateValueStarts(args).flatMap((match) => {
|
|
1259
|
+
const items = extractCompletedArrayItems({
|
|
1260
|
+
text: args.text,
|
|
1261
|
+
path: match.path
|
|
1262
|
+
});
|
|
1263
|
+
return items.length > 0 ? [
|
|
1264
|
+
{
|
|
1265
|
+
path: match.path,
|
|
1266
|
+
items
|
|
1267
|
+
}
|
|
1268
|
+
] : [];
|
|
1269
|
+
});
|
|
1270
|
+
};
|
|
1271
|
+
var extractStreamingStringValue = (args) => {
|
|
1272
|
+
const located = locateValueStart(args);
|
|
1273
|
+
if (!located.found || located.start === void 0) {
|
|
1274
|
+
return {
|
|
1275
|
+
found: located.found,
|
|
1276
|
+
complete: false,
|
|
1277
|
+
value: ""
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
const stringStart = skipWhitespace(args.text, located.start);
|
|
1281
|
+
if (args.text[stringStart] !== '"') {
|
|
1282
|
+
return {
|
|
1283
|
+
found: true,
|
|
1284
|
+
complete: false,
|
|
1285
|
+
value: ""
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
let value = "";
|
|
1289
|
+
for (let i = stringStart + 1; i < args.text.length; i += 1) {
|
|
1290
|
+
const ch = args.text[i];
|
|
1291
|
+
if (ch === void 0) break;
|
|
1292
|
+
if (ch === '"') {
|
|
1293
|
+
return {
|
|
1294
|
+
found: true,
|
|
1295
|
+
complete: true,
|
|
1296
|
+
value
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
if (ch !== "\\") {
|
|
1300
|
+
value += ch;
|
|
1301
|
+
continue;
|
|
1302
|
+
}
|
|
1303
|
+
const next = args.text[i + 1];
|
|
1304
|
+
if (!next) {
|
|
1305
|
+
return {
|
|
1306
|
+
found: true,
|
|
1307
|
+
complete: false,
|
|
1308
|
+
value
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
if (next === '"' || next === "\\" || next === "/" || next === "b" || next === "f" || next === "n" || next === "r" || next === "t") {
|
|
1312
|
+
value += next === "b" ? "\b" : next === "f" ? "\f" : next === "n" ? "\n" : next === "r" ? "\r" : next === "t" ? " " : next;
|
|
1313
|
+
i += 1;
|
|
1314
|
+
continue;
|
|
1315
|
+
}
|
|
1316
|
+
if (next === "u") {
|
|
1317
|
+
const hex = args.text.slice(i + 2, i + 6);
|
|
1318
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
1319
|
+
return {
|
|
1320
|
+
found: true,
|
|
1321
|
+
complete: false,
|
|
1322
|
+
value
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
value += String.fromCharCode(Number.parseInt(hex, 16));
|
|
1326
|
+
i += 5;
|
|
1327
|
+
continue;
|
|
1328
|
+
}
|
|
1329
|
+
return {
|
|
1330
|
+
found: true,
|
|
1331
|
+
complete: false,
|
|
1332
|
+
value
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
return {
|
|
1336
|
+
found: true,
|
|
1337
|
+
complete: false,
|
|
1338
|
+
value
|
|
1339
|
+
};
|
|
1340
|
+
};
|
|
1341
|
+
var extractStreamingStringValues = (args) => {
|
|
1342
|
+
return locateValueStarts(args).flatMap((match) => {
|
|
1343
|
+
const current = extractStreamingStringValue({
|
|
1344
|
+
text: args.text,
|
|
1345
|
+
path: match.path
|
|
1346
|
+
});
|
|
1347
|
+
return current.found ? [
|
|
1348
|
+
{
|
|
1349
|
+
path: match.path,
|
|
1350
|
+
complete: current.complete,
|
|
1351
|
+
value: current.value
|
|
1352
|
+
}
|
|
1353
|
+
] : [];
|
|
1354
|
+
});
|
|
1355
|
+
};
|
|
1356
|
+
function createStructuredOutputStreamer(args, id, opId) {
|
|
1357
|
+
let firstText = "";
|
|
1358
|
+
const setFieldPaths = resolveSetFieldPaths(args.structured);
|
|
1359
|
+
const appendFieldPaths = resolveAppendFieldPaths(args.structured);
|
|
1360
|
+
const textDeltaFieldPaths = resolveTextDeltaFieldPaths(args.structured);
|
|
1361
|
+
const emittedSetValues = /* @__PURE__ */ new Map();
|
|
1362
|
+
const emittedAppendCounts = /* @__PURE__ */ new Map();
|
|
1363
|
+
const emittedTextValues = /* @__PURE__ */ new Map();
|
|
1364
|
+
return (delta) => {
|
|
1365
|
+
firstText += delta;
|
|
1366
|
+
for (const fieldPath of setFieldPaths) {
|
|
1367
|
+
const values = extractCompletedFieldValues({
|
|
1368
|
+
text: firstText,
|
|
1369
|
+
path: fieldPath
|
|
1370
|
+
});
|
|
1371
|
+
for (const { path, value } of values) {
|
|
1372
|
+
const nextSerialized = JSON.stringify(value);
|
|
1373
|
+
if (emittedSetValues.get(path) === nextSerialized) continue;
|
|
1374
|
+
emittedSetValues.set(path, nextSerialized);
|
|
1375
|
+
emitStructuredData({
|
|
1376
|
+
kind: "set",
|
|
1377
|
+
path,
|
|
1378
|
+
value,
|
|
1379
|
+
dataType: args.structured?.dataType ?? "reason-output",
|
|
1380
|
+
...args.structured?.schemaId ? { schemaId: args.structured.schemaId } : {},
|
|
1381
|
+
...args.structured?.schemaVersion ? { schemaVersion: args.structured.schemaVersion } : {},
|
|
1382
|
+
...id ? { id } : {},
|
|
1383
|
+
streamId: opId
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
for (const fieldPath of appendFieldPaths) {
|
|
1388
|
+
const groups = extractCompletedArrayItemGroups({
|
|
1389
|
+
text: firstText,
|
|
1390
|
+
path: fieldPath
|
|
1391
|
+
});
|
|
1392
|
+
for (const { path, items } of groups) {
|
|
1393
|
+
const emittedAppendCount = emittedAppendCounts.get(path) ?? 0;
|
|
1394
|
+
if (items.length <= emittedAppendCount) continue;
|
|
1395
|
+
const nextItems = items.slice(emittedAppendCount);
|
|
1396
|
+
emittedAppendCounts.set(path, items.length);
|
|
1397
|
+
emitStructuredData({
|
|
1398
|
+
kind: "append",
|
|
1399
|
+
path,
|
|
1400
|
+
items: nextItems,
|
|
1401
|
+
dataType: args.structured?.dataType ?? "reason-output",
|
|
1402
|
+
...args.structured?.schemaId ? { schemaId: args.structured.schemaId } : {},
|
|
1403
|
+
...args.structured?.schemaVersion ? { schemaVersion: args.structured.schemaVersion } : {},
|
|
1404
|
+
...id ? { id } : {},
|
|
1405
|
+
streamId: opId
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
for (const fieldPath of textDeltaFieldPaths) {
|
|
1410
|
+
const values = extractStreamingStringValues({
|
|
1411
|
+
text: firstText,
|
|
1412
|
+
path: fieldPath
|
|
1413
|
+
});
|
|
1414
|
+
for (const { path, value } of values) {
|
|
1415
|
+
const emittedTextValue = emittedTextValues.get(path) ?? "";
|
|
1416
|
+
if (value.length <= emittedTextValue.length || !value.startsWith(emittedTextValue)) {
|
|
1417
|
+
continue;
|
|
1418
|
+
}
|
|
1419
|
+
const nextDelta = value.slice(emittedTextValue.length);
|
|
1420
|
+
emittedTextValues.set(path, value);
|
|
1421
|
+
if (nextDelta.length === 0) continue;
|
|
1422
|
+
emitStructuredData({
|
|
1423
|
+
kind: "text-delta",
|
|
1424
|
+
path,
|
|
1425
|
+
delta: nextDelta,
|
|
1426
|
+
dataType: args.structured?.dataType ?? "reason-output",
|
|
1427
|
+
...args.structured?.schemaId ? { schemaId: args.structured.schemaId } : {},
|
|
1428
|
+
...args.structured?.schemaVersion ? { schemaVersion: args.structured.schemaVersion } : {},
|
|
1429
|
+
...id ? { id } : {},
|
|
1430
|
+
streamId: opId
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
var tryJsonParse = (value) => {
|
|
1437
|
+
try {
|
|
1438
|
+
return { ok: true, value: JSON.parse(value) };
|
|
1439
|
+
} catch (error) {
|
|
1440
|
+
return {
|
|
1441
|
+
ok: false,
|
|
1442
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
};
|
|
1446
|
+
var extractJsonCodeBlock = (value) => {
|
|
1447
|
+
const match = value.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
1448
|
+
if (!match || typeof match[1] !== "string") return null;
|
|
1449
|
+
const inner = match[1].trim();
|
|
1450
|
+
return inner.length > 0 ? inner : null;
|
|
1451
|
+
};
|
|
1452
|
+
var tryStringify = (value) => {
|
|
1453
|
+
if (typeof value === "string") return value;
|
|
1454
|
+
try {
|
|
1455
|
+
return JSON.stringify(value, null, 2);
|
|
1456
|
+
} catch {
|
|
1457
|
+
return String(value);
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
var isRecord22 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1461
|
+
var resolveOutputCandidate = (text) => {
|
|
1462
|
+
const trimmed = text.trim();
|
|
1463
|
+
if (!trimmed) return text;
|
|
1464
|
+
const direct = tryJsonParse(trimmed);
|
|
1465
|
+
if (direct.ok) return direct.value;
|
|
1466
|
+
const block = extractJsonCodeBlock(trimmed);
|
|
1467
|
+
if (block) {
|
|
1468
|
+
const parsedBlock = tryJsonParse(block);
|
|
1469
|
+
if (parsedBlock.ok) return parsedBlock.value;
|
|
1470
|
+
}
|
|
1471
|
+
return text;
|
|
1472
|
+
};
|
|
1473
|
+
var looksLikeStructuredJsonAttempt = (value) => {
|
|
1474
|
+
const trimmed = value.trim();
|
|
1475
|
+
if (!trimmed) return false;
|
|
1476
|
+
return trimmed.startsWith("{") || trimmed.startsWith("[") || /^```(?:json)?/i.test(trimmed);
|
|
1477
|
+
};
|
|
1478
|
+
var isLikelyTruncatedStructuredOutput = (text) => {
|
|
1479
|
+
const trimmed = text.trim();
|
|
1480
|
+
if (!looksLikeStructuredJsonAttempt(trimmed)) return false;
|
|
1481
|
+
const direct = tryJsonParse(trimmed);
|
|
1482
|
+
if (!direct.ok && direct.error) return true;
|
|
1483
|
+
const block = extractJsonCodeBlock(trimmed);
|
|
1484
|
+
if (!block) return false;
|
|
1485
|
+
const parsedBlock = tryJsonParse(block);
|
|
1486
|
+
return !parsedBlock.ok && Boolean(parsedBlock.error);
|
|
1487
|
+
};
|
|
1488
|
+
var createTruncatedStructuredOutputError = (label) => new Error(
|
|
1489
|
+
`${label} was truncated before producing valid structured output. The model stopped due to output length. Increase maxOutputTokens or simplify the requested output.`
|
|
1490
|
+
);
|
|
1491
|
+
var createInvalidStructuredOutputError = (label) => new Error(
|
|
1492
|
+
`${label} did not produce valid structured output. The model returned text instead of the expected JSON payload. This often happens when output is truncated or the provider does not follow JSON mode. Increase maxOutputTokens or simplify the requested output.`
|
|
1493
|
+
);
|
|
1494
|
+
var parseReasonOutputWithSchema = (args) => {
|
|
1495
|
+
const candidate = resolveOutputCandidate(args.text);
|
|
1496
|
+
try {
|
|
1497
|
+
return parseWithSchema(args.schema, candidate, args.label);
|
|
1498
|
+
} catch (error) {
|
|
1499
|
+
if (args.finishReason?.unified === "length" || isLikelyTruncatedStructuredOutput(args.text)) {
|
|
1500
|
+
throw createTruncatedStructuredOutputError(args.label);
|
|
1501
|
+
}
|
|
1502
|
+
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
1503
|
+
throw createInvalidStructuredOutputError(args.label);
|
|
1504
|
+
}
|
|
1505
|
+
throw error;
|
|
1506
|
+
}
|
|
1507
|
+
};
|
|
1508
|
+
var parseInterruptFirstPassResult = (args) => {
|
|
1509
|
+
const candidate = resolveOutputCandidate(args.text);
|
|
1510
|
+
if (!isRecord22(candidate)) {
|
|
1511
|
+
if (args.finishReason?.unified === "length" || isLikelyTruncatedStructuredOutput(args.text)) {
|
|
1512
|
+
throw createTruncatedStructuredOutputError("useReason output");
|
|
1513
|
+
}
|
|
1514
|
+
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
1515
|
+
throw createInvalidStructuredOutputError("useReason output");
|
|
1516
|
+
}
|
|
1517
|
+
throw new Error(
|
|
1518
|
+
"useReason first pass with interrupt must return a JSON object."
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
const mode = args.mode ?? "required";
|
|
1522
|
+
let interruptRequired = true;
|
|
1523
|
+
if (mode === "optional") {
|
|
1524
|
+
if (candidate.decision !== "continue" && candidate.decision !== "interrupt") {
|
|
1525
|
+
throw new Error(
|
|
1526
|
+
'useReason optional interrupt first pass must include decision "continue" or "interrupt".'
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1529
|
+
interruptRequired = candidate.decision === "interrupt";
|
|
1530
|
+
if (!interruptRequired) {
|
|
1531
|
+
const hasUnexpectedRequest = [
|
|
1532
|
+
candidate.interruptRequest,
|
|
1533
|
+
candidate.request,
|
|
1534
|
+
candidate.interrupt
|
|
1535
|
+
].some((value) => value !== null && value !== void 0);
|
|
1536
|
+
if (hasUnexpectedRequest) {
|
|
1537
|
+
throw new Error(
|
|
1538
|
+
'useReason optional interrupt first pass with decision "continue" must not include an interrupt request.'
|
|
1539
|
+
);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
let request;
|
|
1544
|
+
if (interruptRequired) {
|
|
1545
|
+
const requestCandidates = [
|
|
1546
|
+
candidate.interruptRequest,
|
|
1547
|
+
candidate.request,
|
|
1548
|
+
candidate.interrupt,
|
|
1549
|
+
mode === "required" ? candidate : void 0
|
|
1550
|
+
];
|
|
1551
|
+
const requestPayload = requestCandidates.find(
|
|
1552
|
+
(value) => value !== null && value !== void 0
|
|
1553
|
+
);
|
|
1554
|
+
request = parseWithSchema(
|
|
1555
|
+
args.requestSchema,
|
|
1556
|
+
requestPayload,
|
|
1557
|
+
"useReason interrupt.request"
|
|
1558
|
+
);
|
|
1559
|
+
}
|
|
1560
|
+
let output;
|
|
1561
|
+
if (args.outputSchema) {
|
|
1562
|
+
const outputPayload = Object.hasOwn(candidate, "output") ? candidate.output : candidate;
|
|
1563
|
+
try {
|
|
1564
|
+
output = parseWithSchema(
|
|
1565
|
+
args.outputSchema,
|
|
1566
|
+
outputPayload,
|
|
1567
|
+
"useReason output"
|
|
1568
|
+
);
|
|
1569
|
+
} catch (error) {
|
|
1570
|
+
if (args.finishReason?.unified === "length" || isLikelyTruncatedStructuredOutput(args.text)) {
|
|
1571
|
+
throw createTruncatedStructuredOutputError("useReason output");
|
|
1572
|
+
}
|
|
1573
|
+
if (typeof outputPayload === "string" && outputPayload.trim().length > 0) {
|
|
1574
|
+
throw createInvalidStructuredOutputError("useReason output");
|
|
1575
|
+
}
|
|
1576
|
+
throw error;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
const explicitDraft = typeof candidate.draftText === "string" && candidate.draftText.length > 0 ? candidate.draftText : typeof candidate.text === "string" && candidate.text.length > 0 ? candidate.text : void 0;
|
|
1580
|
+
if (!args.outputSchema && !explicitDraft) {
|
|
1581
|
+
throw new Error(
|
|
1582
|
+
"useReason first pass with interrupt requires `draftText` when outputSchema is not provided."
|
|
1583
|
+
);
|
|
1584
|
+
}
|
|
1585
|
+
const draftText = explicitDraft ?? (output !== void 0 ? tryStringify(output) : String(args.text ?? ""));
|
|
1586
|
+
if (!interruptRequired) {
|
|
1587
|
+
return {
|
|
1588
|
+
draftText,
|
|
1589
|
+
interruptRequired: false,
|
|
1590
|
+
...output !== void 0 ? { output } : {}
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
return {
|
|
1594
|
+
draftText,
|
|
1595
|
+
interruptRequired: true,
|
|
1596
|
+
request,
|
|
1597
|
+
...output !== void 0 ? { output } : {}
|
|
1598
|
+
};
|
|
1599
|
+
};
|
|
1600
|
+
var import_zod32 = require("zod");
|
|
1601
|
+
var tryStringify2 = (value) => {
|
|
1602
|
+
if (typeof value === "string") return value;
|
|
1603
|
+
try {
|
|
1604
|
+
return JSON.stringify(value, null, 2);
|
|
1605
|
+
} catch {
|
|
1606
|
+
return String(value);
|
|
1607
|
+
}
|
|
1608
|
+
};
|
|
1609
|
+
var tryGetSchemaHint = (schema) => {
|
|
1610
|
+
try {
|
|
1611
|
+
const hint = (0, import_zod32.toJSONSchema)(schema);
|
|
1612
|
+
return JSON.stringify(hint, null, 2);
|
|
1613
|
+
} catch {
|
|
1614
|
+
return void 0;
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
var withSchemaHint = (input, label, schema) => {
|
|
1618
|
+
const hint = tryGetSchemaHint(schema);
|
|
1619
|
+
if (!hint) return input;
|
|
1620
|
+
return `${input}
|
|
1621
|
+
|
|
1622
|
+
${label}:
|
|
1623
|
+
${hint}`;
|
|
1624
|
+
};
|
|
1625
|
+
var defaultInterruptFirstPassInput = (args) => {
|
|
1626
|
+
const mode = args.mode ?? "required";
|
|
1627
|
+
const base = mode === "optional" ? args.outputSchema ? [
|
|
1628
|
+
args.input,
|
|
1629
|
+
"Output rules:",
|
|
1630
|
+
"- Return JSON only. No markdown fences.",
|
|
1631
|
+
"- Return an object with keys: decision, output, interruptRequest, draftText.",
|
|
1632
|
+
'- decision must be either "continue" or "interrupt".',
|
|
1633
|
+
'- Use decision "continue" when you can produce the final output without asking the user.',
|
|
1634
|
+
'- Use decision "interrupt" only when user input is needed before finalizing.',
|
|
1635
|
+
"- output must match the expected output JSON schema.",
|
|
1636
|
+
'- When decision is "interrupt", interruptRequest must match the expected interrupt request JSON schema and must be a non-null object.',
|
|
1637
|
+
'- When decision is "continue", interruptRequest must be null.',
|
|
1638
|
+
"- draftText should be a concise plain-language summary of output."
|
|
1639
|
+
].join("\n\n") : [
|
|
1640
|
+
args.input,
|
|
1641
|
+
"Output rules:",
|
|
1642
|
+
"- Return JSON only. No markdown fences.",
|
|
1643
|
+
"- Return an object with keys: decision, draftText, interruptRequest.",
|
|
1644
|
+
'- decision must be either "continue" or "interrupt".',
|
|
1645
|
+
'- Use decision "continue" when you can produce the final answer without asking the user.',
|
|
1646
|
+
'- Use decision "interrupt" only when user input is needed before finalizing.',
|
|
1647
|
+
"- draftText should be the current answer text.",
|
|
1648
|
+
'- When decision is "interrupt", interruptRequest must match the expected interrupt request JSON schema and must be a non-null object.',
|
|
1649
|
+
'- When decision is "continue", interruptRequest must be null.'
|
|
1650
|
+
].join("\n\n") : args.outputSchema ? [
|
|
1651
|
+
args.input,
|
|
1652
|
+
"Output rules:",
|
|
1653
|
+
"- Return JSON only. No markdown fences.",
|
|
1654
|
+
"- Return an object with keys: output, interruptRequest, draftText.",
|
|
1655
|
+
"- output must match the expected output JSON schema.",
|
|
1656
|
+
"- interruptRequest must match the expected interrupt request JSON schema.",
|
|
1657
|
+
"- interruptRequest must be a non-null object.",
|
|
1658
|
+
"- draftText should be a concise plain-language summary of output.",
|
|
1659
|
+
"- If uncertain, still return a valid interruptRequest with safe default options."
|
|
1660
|
+
].join("\n\n") : [
|
|
1661
|
+
args.input,
|
|
1662
|
+
"Output rules:",
|
|
1663
|
+
"- Return JSON only. No markdown fences.",
|
|
1664
|
+
"- Return an object with keys: draftText, interruptRequest.",
|
|
1665
|
+
"- draftText should be the current draft answer text.",
|
|
1666
|
+
"- interruptRequest must match the expected interrupt request JSON schema.",
|
|
1667
|
+
"- interruptRequest must be a non-null object.",
|
|
1668
|
+
"- If uncertain, still return a valid interruptRequest with safe default options."
|
|
1669
|
+
].join("\n\n");
|
|
1670
|
+
const withInterruptSchema = withSchemaHint(
|
|
1671
|
+
base,
|
|
1672
|
+
"Expected interrupt request JSON schema (for `interruptRequest`)",
|
|
1673
|
+
args.requestSchema
|
|
1674
|
+
);
|
|
1675
|
+
if (!args.outputSchema) return withInterruptSchema;
|
|
1676
|
+
const withOutputSchema = withSchemaHint(
|
|
1677
|
+
withInterruptSchema,
|
|
1678
|
+
"Expected output JSON schema (for `output`)",
|
|
1679
|
+
args.outputSchema
|
|
1680
|
+
);
|
|
1681
|
+
return [
|
|
1682
|
+
withOutputSchema,
|
|
1683
|
+
"JSON template:",
|
|
1684
|
+
mode === "optional" ? '{ "decision": "continue", "output": { ... }, "interruptRequest": null, "draftText": "..." }' : '{ "output": { ... }, "interruptRequest": { ... }, "draftText": "..." }'
|
|
1685
|
+
].join("\n\n");
|
|
1686
|
+
};
|
|
1687
|
+
var defaultContinuationInput = (args) => [
|
|
1688
|
+
"You are continuing a paused reasoning task after user input.",
|
|
1689
|
+
"Update the previous result using the user response and return the final answer only.",
|
|
1690
|
+
"If the previous output was JSON, return JSON in the same schema.",
|
|
1691
|
+
"",
|
|
1692
|
+
`Original request:
|
|
1693
|
+
${args.input}`,
|
|
1694
|
+
`Draft answer text:
|
|
1695
|
+
${args.draftText}`,
|
|
1696
|
+
`Draft output object:
|
|
1697
|
+
${tryStringify2(args.draftOutput ?? args.draftText)}`,
|
|
1698
|
+
`Interrupt request shown to user:
|
|
1699
|
+
${tryStringify2(args.request)}`,
|
|
1700
|
+
`User response:
|
|
1701
|
+
${tryStringify2(args.response)}`
|
|
1702
|
+
].join("\n\n");
|
|
1703
|
+
var withOutputGuardrails = (input, schema) => {
|
|
1704
|
+
const base = [
|
|
1705
|
+
input,
|
|
1706
|
+
"Output rules:",
|
|
1707
|
+
"- Return only JSON, no markdown fences.",
|
|
1708
|
+
"- Ensure the response conforms to the expected output schema.",
|
|
1709
|
+
"- Do not include explanatory text outside the JSON object."
|
|
1710
|
+
].join("\n\n");
|
|
1711
|
+
return withSchemaHint(base, "Expected output JSON schema", schema);
|
|
1533
1712
|
};
|
|
1534
|
-
var
|
|
1535
|
-
const
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
value: ""
|
|
1541
|
-
};
|
|
1713
|
+
var withStructuredStreamHints = (input, args) => {
|
|
1714
|
+
const rules = [];
|
|
1715
|
+
for (const path of args.setFieldPaths ?? []) {
|
|
1716
|
+
rules.push(
|
|
1717
|
+
`- For the field path pattern \`${path}\`, write one stable final value and do not rewrite it after it is complete.`
|
|
1718
|
+
);
|
|
1542
1719
|
}
|
|
1543
|
-
const
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1720
|
+
for (const path of args.appendFieldPaths ?? []) {
|
|
1721
|
+
rules.push(
|
|
1722
|
+
`- For the array field path pattern \`${path}\`, write items in final order and finish each item before starting the next.`
|
|
1723
|
+
);
|
|
1724
|
+
rules.push(
|
|
1725
|
+
`- Once an item in \`${path}\` is complete, do not rewrite or reorder earlier items.`
|
|
1726
|
+
);
|
|
1550
1727
|
}
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1728
|
+
for (const path of args.textDeltaFieldPaths ?? []) {
|
|
1729
|
+
rules.push(
|
|
1730
|
+
`- For the string field path pattern \`${path}\`, write the value progressively by appending text to the end.`
|
|
1731
|
+
);
|
|
1732
|
+
rules.push(
|
|
1733
|
+
`- Do not rewrite or replace the earlier prefix of \`${path}\` once emitted.`
|
|
1734
|
+
);
|
|
1735
|
+
}
|
|
1736
|
+
if (rules.length === 0) return input;
|
|
1737
|
+
return [
|
|
1738
|
+
input,
|
|
1739
|
+
"Streaming rules:",
|
|
1740
|
+
...rules,
|
|
1741
|
+
"- Keep the overall response as valid JSON."
|
|
1742
|
+
].join("\n\n");
|
|
1743
|
+
};
|
|
1744
|
+
var mergeUsage = (left, right) => {
|
|
1745
|
+
if (!left) return right;
|
|
1746
|
+
if (!right) return left;
|
|
1747
|
+
const sum = (a, b) => a === void 0 && b === void 0 ? void 0 : (a ?? 0) + (b ?? 0);
|
|
1748
|
+
const raw = left.raw || right.raw ? {
|
|
1749
|
+
...left.raw ?? {},
|
|
1750
|
+
...right.raw ?? {}
|
|
1751
|
+
} : void 0;
|
|
1752
|
+
const input = sum(left.input, right.input);
|
|
1753
|
+
const output = sum(left.output, right.output);
|
|
1754
|
+
const total = sum(left.total, right.total);
|
|
1755
|
+
const reasoning = sum(left.reasoning, right.reasoning);
|
|
1756
|
+
const cacheRead = sum(left.cacheRead, right.cacheRead);
|
|
1757
|
+
const cacheWrite = sum(left.cacheWrite, right.cacheWrite);
|
|
1758
|
+
const merged = {
|
|
1759
|
+
...right.outputIncludesReasoning !== void 0 ? { outputIncludesReasoning: right.outputIncludesReasoning } : {},
|
|
1760
|
+
...right.inputIncludesCacheWrite !== void 0 ? { inputIncludesCacheWrite: right.inputIncludesCacheWrite } : {},
|
|
1761
|
+
...right.inputIncludesCacheRead !== void 0 ? { inputIncludesCacheRead: right.inputIncludesCacheRead } : {}
|
|
1762
|
+
};
|
|
1763
|
+
if (input !== void 0) merged.input = input;
|
|
1764
|
+
if (output !== void 0) merged.output = output;
|
|
1765
|
+
if (total !== void 0) merged.total = total;
|
|
1766
|
+
if (reasoning !== void 0) merged.reasoning = reasoning;
|
|
1767
|
+
if (cacheRead !== void 0) merged.cacheRead = cacheRead;
|
|
1768
|
+
if (cacheWrite !== void 0) merged.cacheWrite = cacheWrite;
|
|
1769
|
+
if (raw) merged.raw = raw;
|
|
1770
|
+
return merged;
|
|
1771
|
+
};
|
|
1772
|
+
var mergeWarnings = (left, right) => {
|
|
1773
|
+
if (!left?.length) return right;
|
|
1774
|
+
if (!right?.length) return left;
|
|
1775
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1776
|
+
const merged = [];
|
|
1777
|
+
for (const warning of [...left, ...right]) {
|
|
1778
|
+
const key = JSON.stringify(warning);
|
|
1779
|
+
if (seen.has(key)) continue;
|
|
1780
|
+
seen.add(key);
|
|
1781
|
+
merged.push(warning);
|
|
1597
1782
|
}
|
|
1783
|
+
return merged;
|
|
1784
|
+
};
|
|
1785
|
+
var mergeProviderMetadata = (left, right) => {
|
|
1786
|
+
if (!left) return right;
|
|
1787
|
+
if (!right) return left;
|
|
1598
1788
|
return {
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
value
|
|
1789
|
+
...left,
|
|
1790
|
+
...right
|
|
1602
1791
|
};
|
|
1603
1792
|
};
|
|
1604
|
-
var
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
value: current.value
|
|
1615
|
-
}
|
|
1616
|
-
] : [];
|
|
1793
|
+
var emitReasonStructuredOutput = (args) => {
|
|
1794
|
+
if (!args.emit || !shouldEmitStructured(args.structured)) return;
|
|
1795
|
+
emitStructuredData({
|
|
1796
|
+
dataType: args.structured?.dataType ?? "reason-output",
|
|
1797
|
+
data: args.output,
|
|
1798
|
+
kind: "final",
|
|
1799
|
+
...args.structured?.schemaId ? { schemaId: args.structured.schemaId } : {},
|
|
1800
|
+
...args.structured?.schemaVersion ? { schemaVersion: args.structured.schemaVersion } : {},
|
|
1801
|
+
...args.id ? { id: args.id } : {},
|
|
1802
|
+
streamId: args.opId
|
|
1617
1803
|
});
|
|
1618
1804
|
};
|
|
1619
1805
|
var import_core42 = require("@kortyx/core");
|
|
@@ -1668,16 +1854,20 @@ ${tryStringify2(args.response)}`
|
|
|
1668
1854
|
{ role: "user", content: String(args.input ?? "") }
|
|
1669
1855
|
];
|
|
1670
1856
|
var runReasonToolLoop = async (args) => {
|
|
1671
|
-
const { useReasonArgs, id,
|
|
1857
|
+
const { useReasonArgs, id, traceSpan, checkpointKey } = args;
|
|
1672
1858
|
const ctx = getHookContext();
|
|
1673
1859
|
const abortSignal = (0, import_core42.combineAbortSignals)(
|
|
1674
1860
|
ctx.node.abortSignal,
|
|
1675
1861
|
useReasonArgs.abortSignal,
|
|
1676
1862
|
useReasonArgs.model.options?.abortSignal
|
|
1677
1863
|
);
|
|
1864
|
+
const saved = ctx.currentNodeState.byKey[checkpointKey];
|
|
1865
|
+
const checkpoint = saved?.status === "tool_loop" ? saved : void 0;
|
|
1866
|
+
const opId = checkpoint?.opId ?? args.opId;
|
|
1678
1867
|
const tools = useReasonArgs.tools ?? [];
|
|
1679
1868
|
const toolByName = /* @__PURE__ */ new Map();
|
|
1680
1869
|
let validationCompleted = false;
|
|
1870
|
+
let separateOutput = false;
|
|
1681
1871
|
try {
|
|
1682
1872
|
for (const tool of tools) {
|
|
1683
1873
|
if (toolByName.has(tool.name)) {
|
|
@@ -1692,6 +1882,17 @@ ${tryStringify2(args.response)}`
|
|
|
1692
1882
|
"useReason tools cannot be combined with useReason interrupt mode yet. Use toolExecution.approval for tool approval."
|
|
1693
1883
|
);
|
|
1694
1884
|
}
|
|
1885
|
+
separateOutput = Boolean(
|
|
1886
|
+
useReasonArgs.model.provider.getModel(useReasonArgs.model.modelId, {
|
|
1887
|
+
...useReasonArgs.model.options,
|
|
1888
|
+
...useReasonArgs.reasoning !== void 0 ? { reasoning: useReasonArgs.reasoning } : {},
|
|
1889
|
+
...useReasonArgs.responseFormat ? { responseFormat: useReasonArgs.responseFormat } : {},
|
|
1890
|
+
providerOptions: resolveProviderOptions(
|
|
1891
|
+
useReasonArgs.model.options?.providerOptions,
|
|
1892
|
+
useReasonArgs.providerOptions
|
|
1893
|
+
) ?? {}
|
|
1894
|
+
}).requiresSeparateStructuredOutput
|
|
1895
|
+
);
|
|
1695
1896
|
validationCompleted = true;
|
|
1696
1897
|
} finally {
|
|
1697
1898
|
if (!validationCompleted) {
|
|
@@ -1699,21 +1900,47 @@ ${tryStringify2(args.response)}`
|
|
|
1699
1900
|
}
|
|
1700
1901
|
}
|
|
1701
1902
|
const toolDefinitions = toToolDefinitions(tools);
|
|
1903
|
+
let finalizing = checkpoint?.finalizing ?? false;
|
|
1904
|
+
let completed = false;
|
|
1702
1905
|
const maxSteps = Math.max(1, useReasonArgs.toolExecution?.maxSteps ?? 3);
|
|
1703
|
-
const messages = createInitialMessages({
|
|
1906
|
+
const messages = checkpoint?.messages ?? createInitialMessages({
|
|
1704
1907
|
system: useReasonArgs.system,
|
|
1705
|
-
input: useReasonArgs.input
|
|
1908
|
+
input: useReasonArgs.outputSchema ? withOutputGuardrails(useReasonArgs.input, useReasonArgs.outputSchema) : useReasonArgs.input
|
|
1706
1909
|
});
|
|
1707
|
-
const steps = [];
|
|
1708
|
-
const allToolCalls =
|
|
1709
|
-
|
|
1910
|
+
const steps = checkpoint?.steps ?? [];
|
|
1911
|
+
const allToolCalls = steps.flatMap(
|
|
1912
|
+
(step) => step.toolCalls
|
|
1913
|
+
);
|
|
1914
|
+
const allToolResults = steps.flatMap(
|
|
1915
|
+
(step) => step.toolResults
|
|
1916
|
+
);
|
|
1710
1917
|
let finalText = "";
|
|
1711
1918
|
let finalRaw;
|
|
1712
1919
|
let finalOutput;
|
|
1713
|
-
let aggregatedUsage
|
|
1920
|
+
let aggregatedUsage = steps.reduce(
|
|
1921
|
+
(usage, step) => mergeUsage(usage, step.usage),
|
|
1922
|
+
void 0
|
|
1923
|
+
);
|
|
1714
1924
|
let finalFinishReason;
|
|
1715
1925
|
let aggregatedProviderMetadata;
|
|
1716
|
-
let aggregatedWarnings
|
|
1926
|
+
let aggregatedWarnings = steps.reduce(
|
|
1927
|
+
(warnings, step) => mergeWarnings(warnings, step.warnings),
|
|
1928
|
+
args.initialWarnings
|
|
1929
|
+
);
|
|
1930
|
+
let pending = checkpoint?.pending;
|
|
1931
|
+
const approvedCalls = checkpoint?.approvedCalls ?? [];
|
|
1932
|
+
const save = () => {
|
|
1933
|
+
ctx.currentNodeState.byKey[checkpointKey] = {
|
|
1934
|
+
status: "tool_loop",
|
|
1935
|
+
opId,
|
|
1936
|
+
messages,
|
|
1937
|
+
steps,
|
|
1938
|
+
approvedCalls,
|
|
1939
|
+
finalizing,
|
|
1940
|
+
...pending ? { pending } : {}
|
|
1941
|
+
};
|
|
1942
|
+
ctx.stateDirty = true;
|
|
1943
|
+
};
|
|
1717
1944
|
const emitToolEvent = (event, payload) => {
|
|
1718
1945
|
ctx.node.emit(event, {
|
|
1719
1946
|
...payload,
|
|
@@ -1723,26 +1950,44 @@ ${tryStringify2(args.response)}`
|
|
|
1723
1950
|
});
|
|
1724
1951
|
};
|
|
1725
1952
|
try {
|
|
1726
|
-
for (let stepIndex =
|
|
1953
|
+
for (let stepIndex = pending ? steps.length - 1 : steps.length; stepIndex < maxSteps; stepIndex += 1) {
|
|
1727
1954
|
(0, import_core42.throwIfExecutionAborted)(abortSignal);
|
|
1728
1955
|
traceSpan?.addEvent?.("useReason.tool-step.start", {
|
|
1729
1956
|
stepIndex,
|
|
1730
1957
|
toolCount: toolDefinitions.length
|
|
1731
1958
|
});
|
|
1732
|
-
const
|
|
1959
|
+
const reused = Boolean(pending);
|
|
1960
|
+
const stream = useReasonArgs.stream ?? useReasonArgs.model.options?.streaming ?? true;
|
|
1961
|
+
const emit = useReasonArgs.emit ?? true;
|
|
1962
|
+
let textStarted = false;
|
|
1963
|
+
const structuredChunk = useReasonArgs.outputSchema && (!separateOutput || finalizing) && stream && emit && shouldStreamStructured(useReasonArgs.structured) ? createStructuredOutputStreamer(useReasonArgs, id, opId) : void 0;
|
|
1964
|
+
const step = pending ?? await reasonEngine(
|
|
1733
1965
|
{
|
|
1734
1966
|
...useReasonArgs,
|
|
1735
|
-
tools: toolDefinitions,
|
|
1967
|
+
tools: finalizing ? [] : toolDefinitions,
|
|
1968
|
+
...separateOutput && !finalizing ? { responseFormat: { type: "text" } } : {},
|
|
1736
1969
|
messages,
|
|
1737
1970
|
emit: false,
|
|
1738
|
-
stream
|
|
1971
|
+
stream,
|
|
1972
|
+
onTextChunk: (delta) => {
|
|
1973
|
+
if (structuredChunk) structuredChunk(delta);
|
|
1974
|
+
if (!emit || useReasonArgs.outputSchema || !delta) return;
|
|
1975
|
+
if (!textStarted) {
|
|
1976
|
+
emitToolEvent("text-start", {});
|
|
1977
|
+
textStarted = true;
|
|
1978
|
+
}
|
|
1979
|
+
emitToolEvent("text-delta", { delta });
|
|
1980
|
+
}
|
|
1739
1981
|
},
|
|
1740
1982
|
{ ...id ? { id } : {}, opId }
|
|
1741
1983
|
);
|
|
1984
|
+
if (textStarted) emitToolEvent("text-end", {});
|
|
1742
1985
|
finalText = step.text;
|
|
1743
1986
|
finalRaw = step.raw;
|
|
1744
|
-
|
|
1745
|
-
|
|
1987
|
+
if (!reused) {
|
|
1988
|
+
aggregatedUsage = mergeUsage(aggregatedUsage, step.usage);
|
|
1989
|
+
accumulateTokenUsage(step.usage);
|
|
1990
|
+
}
|
|
1746
1991
|
finalFinishReason = step.finishReason;
|
|
1747
1992
|
aggregatedProviderMetadata = mergeProviderMetadata(
|
|
1748
1993
|
aggregatedProviderMetadata,
|
|
@@ -1750,32 +1995,75 @@ ${tryStringify2(args.response)}`
|
|
|
1750
1995
|
);
|
|
1751
1996
|
aggregatedWarnings = mergeWarnings(aggregatedWarnings, step.warnings);
|
|
1752
1997
|
const toolCalls = step.toolCalls ?? [];
|
|
1753
|
-
const toolResults = [];
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1998
|
+
const toolResults = reused ? steps[stepIndex]?.toolResults ?? [] : [];
|
|
1999
|
+
if (!reused)
|
|
2000
|
+
steps.push({
|
|
2001
|
+
stepIndex,
|
|
2002
|
+
text: step.text,
|
|
2003
|
+
toolCalls,
|
|
2004
|
+
toolResults,
|
|
2005
|
+
...step.usage ? { usage: step.usage } : {},
|
|
2006
|
+
...step.finishReason ? { finishReason: step.finishReason } : {},
|
|
2007
|
+
...step.providerMetadata ? { providerMetadata: step.providerMetadata } : {},
|
|
2008
|
+
...step.warnings ? { warnings: step.warnings } : {}
|
|
2009
|
+
});
|
|
1764
2010
|
if (toolCalls.length === 0) {
|
|
1765
|
-
if (
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
2011
|
+
if (separateOutput && !finalizing) {
|
|
2012
|
+
if (args.allowValidatedToolOutput && useReasonArgs.outputSchema) {
|
|
2013
|
+
try {
|
|
2014
|
+
finalOutput = parseReasonOutputWithSchema({
|
|
2015
|
+
text: step.text,
|
|
2016
|
+
schema: useReasonArgs.outputSchema,
|
|
2017
|
+
...step.finishReason ? { finishReason: step.finishReason } : {},
|
|
2018
|
+
label: "useReason output"
|
|
2019
|
+
});
|
|
2020
|
+
aggregatedWarnings = mergeWarnings(aggregatedWarnings, [
|
|
2021
|
+
{
|
|
2022
|
+
type: "compatibility",
|
|
2023
|
+
feature: "responseFormat",
|
|
2024
|
+
details: "Reused locally validated tool-phase output without an extra native-schema request. Set responseFormat.schema explicitly to require provider schema enforcement."
|
|
2025
|
+
}
|
|
2026
|
+
]);
|
|
2027
|
+
completed = true;
|
|
2028
|
+
break;
|
|
2029
|
+
} catch {
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
messages.push({
|
|
2033
|
+
role: "assistant",
|
|
2034
|
+
content: step.text,
|
|
2035
|
+
...step.continuation ? { continuation: step.continuation } : {}
|
|
2036
|
+
});
|
|
2037
|
+
messages.push({
|
|
2038
|
+
role: "user",
|
|
2039
|
+
content: "Return the final answer using the requested output schema and the tool results above."
|
|
2040
|
+
});
|
|
2041
|
+
finalizing = true;
|
|
2042
|
+
pending = void 0;
|
|
2043
|
+
save();
|
|
2044
|
+
continue;
|
|
1769
2045
|
}
|
|
2046
|
+
completed = true;
|
|
1770
2047
|
break;
|
|
1771
2048
|
}
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
2049
|
+
if (finalizing)
|
|
2050
|
+
throw new Error(
|
|
2051
|
+
"Provider requested a tool during schema-only finalization."
|
|
2052
|
+
);
|
|
2053
|
+
if (!reused) {
|
|
2054
|
+
allToolCalls.push(...toolCalls);
|
|
2055
|
+
messages.push({
|
|
2056
|
+
role: "assistant",
|
|
2057
|
+
content: step.text,
|
|
2058
|
+
toolCalls,
|
|
2059
|
+
...step.continuation ? { continuation: step.continuation } : {}
|
|
2060
|
+
});
|
|
2061
|
+
}
|
|
2062
|
+
pending = step;
|
|
2063
|
+
save();
|
|
1778
2064
|
for (const toolCall of toolCalls) {
|
|
2065
|
+
if (toolResults.some((result2) => result2.toolCallId === toolCall.id))
|
|
2066
|
+
continue;
|
|
1779
2067
|
(0, import_core42.throwIfExecutionAborted)(abortSignal);
|
|
1780
2068
|
const tool = toolByName.get(toolCall.name);
|
|
1781
2069
|
if (!tool) {
|
|
@@ -1805,7 +2093,7 @@ ${tryStringify2(args.response)}`
|
|
|
1805
2093
|
input: toolCall.input
|
|
1806
2094
|
});
|
|
1807
2095
|
}
|
|
1808
|
-
if (shouldApproveTool) {
|
|
2096
|
+
if (shouldApproveTool && !approvedCalls.includes(toolCall.id)) {
|
|
1809
2097
|
const approval = await awaitInterruptInternal({
|
|
1810
2098
|
id: `tool:${toolCall.id}`,
|
|
1811
2099
|
request: {
|
|
@@ -1840,8 +2128,18 @@ ${tryStringify2(args.response)}`
|
|
|
1840
2128
|
isError: true
|
|
1841
2129
|
});
|
|
1842
2130
|
}
|
|
2131
|
+
messages.push({
|
|
2132
|
+
role: "tool",
|
|
2133
|
+
content: denied.content,
|
|
2134
|
+
toolCallId: denied.toolCallId,
|
|
2135
|
+
name: denied.name,
|
|
2136
|
+
isError: true
|
|
2137
|
+
});
|
|
2138
|
+
save();
|
|
1843
2139
|
continue;
|
|
1844
2140
|
}
|
|
2141
|
+
approvedCalls.push(toolCall.id);
|
|
2142
|
+
save();
|
|
1845
2143
|
}
|
|
1846
2144
|
try {
|
|
1847
2145
|
(0, import_core42.throwIfExecutionAborted)(abortSignal);
|
|
@@ -1895,32 +2193,26 @@ ${tryStringify2(args.response)}`
|
|
|
1895
2193
|
message: result2.content
|
|
1896
2194
|
});
|
|
1897
2195
|
}
|
|
2196
|
+
const completed2 = toolResults.at(-1);
|
|
2197
|
+
if (completed2)
|
|
2198
|
+
messages.push({
|
|
2199
|
+
role: "tool",
|
|
2200
|
+
content: completed2.content,
|
|
2201
|
+
toolCallId: completed2.toolCallId,
|
|
2202
|
+
name: completed2.name,
|
|
2203
|
+
...completed2.isError !== void 0 ? { isError: completed2.isError } : {}
|
|
2204
|
+
});
|
|
2205
|
+
save();
|
|
1898
2206
|
}
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
steps[steps.length - 1] = {
|
|
1902
|
-
...currentStep,
|
|
1903
|
-
toolResults
|
|
1904
|
-
};
|
|
1905
|
-
}
|
|
1906
|
-
for (const result2 of toolResults) {
|
|
1907
|
-
messages.push({
|
|
1908
|
-
role: "tool",
|
|
1909
|
-
content: result2.content,
|
|
1910
|
-
toolCallId: result2.toolCallId,
|
|
1911
|
-
name: result2.name,
|
|
1912
|
-
...result2.structuredContent !== void 0 ? { structuredContent: result2.structuredContent } : {},
|
|
1913
|
-
...result2.isError !== void 0 ? { isError: result2.isError } : {},
|
|
1914
|
-
...result2.raw !== void 0 ? { raw: result2.raw } : {}
|
|
1915
|
-
});
|
|
1916
|
-
}
|
|
2207
|
+
pending = void 0;
|
|
2208
|
+
save();
|
|
1917
2209
|
}
|
|
1918
|
-
if (
|
|
2210
|
+
if (!completed) {
|
|
1919
2211
|
throw new Error(
|
|
1920
2212
|
`useReason tool loop reached maxSteps (${maxSteps}) before producing a final response.`
|
|
1921
2213
|
);
|
|
1922
2214
|
}
|
|
1923
|
-
if (useReasonArgs.outputSchema) {
|
|
2215
|
+
if (useReasonArgs.outputSchema && finalOutput === void 0) {
|
|
1924
2216
|
finalOutput = parseReasonOutputWithSchema({
|
|
1925
2217
|
text: finalText,
|
|
1926
2218
|
schema: useReasonArgs.outputSchema,
|
|
@@ -1967,6 +2259,8 @@ ${tryStringify2(args.response)}`
|
|
|
1967
2259
|
output: useReasonArgs.telemetry?.output ?? finalOutput ?? finalText
|
|
1968
2260
|
}
|
|
1969
2261
|
});
|
|
2262
|
+
ctx.currentNodeState.byKey[checkpointKey] = { status: "completed", result };
|
|
2263
|
+
ctx.stateDirty = true;
|
|
1970
2264
|
return result;
|
|
1971
2265
|
} catch (error) {
|
|
1972
2266
|
traceSpan?.fail?.(error, {
|
|
@@ -2000,7 +2294,18 @@ ${tryStringify2(args.response)}`
|
|
|
2000
2294
|
args.model.options?.abortSignal
|
|
2001
2295
|
);
|
|
2002
2296
|
(0, import_core52.throwIfExecutionAborted)(abortSignal);
|
|
2003
|
-
|
|
2297
|
+
const allowValidatedToolOutput = Boolean(
|
|
2298
|
+
args.outputSchema && !(args.responseFormat ?? args.model.options?.responseFormat)
|
|
2299
|
+
);
|
|
2300
|
+
const inferred = inferOutputFormat(
|
|
2301
|
+
args.outputSchema,
|
|
2302
|
+
args.responseFormat ?? args.model.options?.responseFormat
|
|
2303
|
+
);
|
|
2304
|
+
args = {
|
|
2305
|
+
...args,
|
|
2306
|
+
abortSignal,
|
|
2307
|
+
...!args.interrupt && inferred.responseFormat ? { responseFormat: inferred.responseFormat } : {}
|
|
2308
|
+
};
|
|
2004
2309
|
const id = typeof args.id === "string" && args.id.length > 0 ? args.id : void 0;
|
|
2005
2310
|
const opId = createRuntimeId2();
|
|
2006
2311
|
const checkpointKey = resolveReasonCheckpointKey({
|
|
@@ -2044,6 +2349,9 @@ ${tryStringify2(args.response)}`
|
|
|
2044
2349
|
if (args.tools?.length) {
|
|
2045
2350
|
return runReasonToolLoop({
|
|
2046
2351
|
useReasonArgs: args,
|
|
2352
|
+
allowValidatedToolOutput,
|
|
2353
|
+
checkpointKey,
|
|
2354
|
+
initialWarnings: inferred.warnings,
|
|
2047
2355
|
...id ? { id } : {},
|
|
2048
2356
|
opId,
|
|
2049
2357
|
...traceSpan ? { traceSpan } : {}
|
|
@@ -2067,10 +2375,7 @@ ${tryStringify2(args.response)}`
|
|
|
2067
2375
|
let aggregatedUsage;
|
|
2068
2376
|
let finalFinishReason;
|
|
2069
2377
|
let aggregatedProviderMetadata;
|
|
2070
|
-
let aggregatedWarnings;
|
|
2071
|
-
const emittedSetValues = /* @__PURE__ */ new Map();
|
|
2072
|
-
const emittedAppendCounts = /* @__PURE__ */ new Map();
|
|
2073
|
-
const emittedTextValues = /* @__PURE__ */ new Map();
|
|
2378
|
+
let aggregatedWarnings = inferred.warnings;
|
|
2074
2379
|
if (existingCheckpoint) {
|
|
2075
2380
|
firstText = existingCheckpoint.firstText;
|
|
2076
2381
|
firstRaw = existingCheckpoint.firstRaw;
|
|
@@ -2092,78 +2397,7 @@ ${tryStringify2(args.response)}`
|
|
|
2092
2397
|
emit: suppressTextStream ? false : args.emit,
|
|
2093
2398
|
stream: useStructuredIncrementalStreaming ? true : suppressTextStream ? false : args.stream,
|
|
2094
2399
|
...useStructuredIncrementalStreaming ? {
|
|
2095
|
-
onTextChunk: (
|
|
2096
|
-
firstText += delta;
|
|
2097
|
-
finalText = firstText;
|
|
2098
|
-
for (const fieldPath of setFieldPaths) {
|
|
2099
|
-
const values = extractCompletedFieldValues({
|
|
2100
|
-
text: firstText,
|
|
2101
|
-
path: fieldPath
|
|
2102
|
-
});
|
|
2103
|
-
for (const { path, value } of values) {
|
|
2104
|
-
const nextSerialized = JSON.stringify(value);
|
|
2105
|
-
if (emittedSetValues.get(path) === nextSerialized) continue;
|
|
2106
|
-
emittedSetValues.set(path, nextSerialized);
|
|
2107
|
-
emitStructuredData({
|
|
2108
|
-
kind: "set",
|
|
2109
|
-
path,
|
|
2110
|
-
value,
|
|
2111
|
-
dataType: args.structured?.dataType ?? "reason-output",
|
|
2112
|
-
...args.structured?.schemaId ? { schemaId: args.structured.schemaId } : {},
|
|
2113
|
-
...args.structured?.schemaVersion ? { schemaVersion: args.structured.schemaVersion } : {},
|
|
2114
|
-
...id ? { id } : {},
|
|
2115
|
-
streamId: opId
|
|
2116
|
-
});
|
|
2117
|
-
}
|
|
2118
|
-
}
|
|
2119
|
-
for (const fieldPath of appendFieldPaths) {
|
|
2120
|
-
const groups = extractCompletedArrayItemGroups({
|
|
2121
|
-
text: firstText,
|
|
2122
|
-
path: fieldPath
|
|
2123
|
-
});
|
|
2124
|
-
for (const { path, items } of groups) {
|
|
2125
|
-
const emittedAppendCount = emittedAppendCounts.get(path) ?? 0;
|
|
2126
|
-
if (items.length <= emittedAppendCount) continue;
|
|
2127
|
-
const nextItems = items.slice(emittedAppendCount);
|
|
2128
|
-
emittedAppendCounts.set(path, items.length);
|
|
2129
|
-
emitStructuredData({
|
|
2130
|
-
kind: "append",
|
|
2131
|
-
path,
|
|
2132
|
-
items: nextItems,
|
|
2133
|
-
dataType: args.structured?.dataType ?? "reason-output",
|
|
2134
|
-
...args.structured?.schemaId ? { schemaId: args.structured.schemaId } : {},
|
|
2135
|
-
...args.structured?.schemaVersion ? { schemaVersion: args.structured.schemaVersion } : {},
|
|
2136
|
-
...id ? { id } : {},
|
|
2137
|
-
streamId: opId
|
|
2138
|
-
});
|
|
2139
|
-
}
|
|
2140
|
-
}
|
|
2141
|
-
for (const fieldPath of textDeltaFieldPaths) {
|
|
2142
|
-
const values = extractStreamingStringValues({
|
|
2143
|
-
text: firstText,
|
|
2144
|
-
path: fieldPath
|
|
2145
|
-
});
|
|
2146
|
-
for (const { path, value } of values) {
|
|
2147
|
-
const emittedTextValue = emittedTextValues.get(path) ?? "";
|
|
2148
|
-
if (value.length <= emittedTextValue.length || !value.startsWith(emittedTextValue)) {
|
|
2149
|
-
continue;
|
|
2150
|
-
}
|
|
2151
|
-
const nextDelta = value.slice(emittedTextValue.length);
|
|
2152
|
-
emittedTextValues.set(path, value);
|
|
2153
|
-
if (nextDelta.length === 0) continue;
|
|
2154
|
-
emitStructuredData({
|
|
2155
|
-
kind: "text-delta",
|
|
2156
|
-
path,
|
|
2157
|
-
delta: nextDelta,
|
|
2158
|
-
dataType: args.structured?.dataType ?? "reason-output",
|
|
2159
|
-
...args.structured?.schemaId ? { schemaId: args.structured.schemaId } : {},
|
|
2160
|
-
...args.structured?.schemaVersion ? { schemaVersion: args.structured.schemaVersion } : {},
|
|
2161
|
-
...id ? { id } : {},
|
|
2162
|
-
streamId: opId
|
|
2163
|
-
});
|
|
2164
|
-
}
|
|
2165
|
-
}
|
|
2166
|
-
}
|
|
2400
|
+
onTextChunk: createStructuredOutputStreamer(args, id, opId)
|
|
2167
2401
|
} : {}
|
|
2168
2402
|
},
|
|
2169
2403
|
reasonMeta,
|
|
@@ -2283,6 +2517,7 @@ ${tryStringify2(args.response)}`
|
|
|
2283
2517
|
const second = await reasonEngine(
|
|
2284
2518
|
{
|
|
2285
2519
|
...args,
|
|
2520
|
+
...inferred.responseFormat ? { responseFormat: inferred.responseFormat } : {},
|
|
2286
2521
|
emit: suppressTextStream ? false : args.emit,
|
|
2287
2522
|
stream: suppressTextStream ? false : args.stream
|
|
2288
2523
|
},
|
|
@@ -4629,7 +4864,7 @@ var responseSchema = import_zod3.z.discriminatedUnion("type", [
|
|
|
4629
4864
|
import_zod3.z.object({ type: import_zod3.z.literal("cancel") }).strict()
|
|
4630
4865
|
]);
|
|
4631
4866
|
function resultFromOutcome(outcome, runId, sessionId) {
|
|
4632
|
-
const usage = outcome.pending?.schema.meta?.__kortyxResumeStatePatch?.tokenUsage ?? outcome.state.runtime?.tokenUsage;
|
|
4867
|
+
const usage = outcome.pending?.schema.meta?.__kortyxResumeStatePatch?.tokenUsage ?? outcome.error?.__kortyxHookStatePatch?.tokenUsage ?? outcome.state.runtime?.tokenUsage;
|
|
4633
4868
|
const info = {
|
|
4634
4869
|
runId,
|
|
4635
4870
|
sessionId,
|