@opencode-ai/ai 0.0.0-dev-18548 → 0.0.0-dev-18549
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.
|
@@ -569,12 +569,15 @@ export interface ParserState {
|
|
|
569
569
|
readonly hasFunctionCall: boolean;
|
|
570
570
|
readonly lifecycle: Lifecycle.State;
|
|
571
571
|
readonly outputItems: Readonly<Record<number, string>>;
|
|
572
|
-
readonly
|
|
573
|
-
|
|
572
|
+
readonly message: {
|
|
573
|
+
readonly id: string;
|
|
574
|
+
readonly phase: MessagePhase | null | undefined;
|
|
575
|
+
} | undefined;
|
|
574
576
|
readonly reasoningItems: Readonly<Record<string, ReasoningStreamItem>>;
|
|
575
577
|
}
|
|
576
578
|
type ReasoningSummaryStatus = "active" | "can-conclude" | "concluded";
|
|
577
579
|
interface ReasoningStreamItem {
|
|
580
|
+
readonly open: boolean;
|
|
578
581
|
readonly encryptedContent: string | null | undefined;
|
|
579
582
|
readonly summaryParts: Readonly<Record<number, ReasoningSummaryStatus>>;
|
|
580
583
|
readonly deltaIndexes: ReadonlySet<number>;
|
|
@@ -607,16 +607,16 @@ const NO_EVENTS = [];
|
|
|
607
607
|
const TERMINAL_TYPES = new Set(["error", "response.completed", "response.incomplete", "response.failed"]);
|
|
608
608
|
export const terminal = (event) => TERMINAL_TYPES.has(event.type);
|
|
609
609
|
const onOutputTextDelta = (state, event, id) => {
|
|
610
|
-
if (!event.delta ||
|
|
610
|
+
if (!event.delta || state.message?.id !== id)
|
|
611
611
|
return [state, NO_EVENTS];
|
|
612
612
|
const events = [];
|
|
613
|
-
const phase = state.
|
|
613
|
+
const phase = state.message.phase;
|
|
614
614
|
const metadata = providerMetadata(state, { itemId: id, ...(phase === undefined ? {} : { phase }) });
|
|
615
615
|
const lifecycle = Lifecycle.textStart(state.lifecycle, events, id, metadata);
|
|
616
616
|
return [{ ...state, lifecycle: Lifecycle.textDelta(lifecycle, events, id, event.delta) }, events];
|
|
617
617
|
};
|
|
618
618
|
const onOutputTextDone = (state, event, id) => {
|
|
619
|
-
if (state.
|
|
619
|
+
if (state.message?.id === id) {
|
|
620
620
|
if (state.lifecycle.text.has(id) || event.text === undefined)
|
|
621
621
|
return [state, NO_EVENTS];
|
|
622
622
|
return onOutputTextDelta(state, { ...event, delta: event.text }, id);
|
|
@@ -627,9 +627,7 @@ const onOutputTextDone = (state, event, id) => {
|
|
|
627
627
|
export const outputItemID = (state, event) => event.output_index === undefined ? event.item_id : (state.outputItems[event.output_index] ?? event.item_id);
|
|
628
628
|
const startReasoningSummaryPart = (state, itemID, index) => {
|
|
629
629
|
const item = state.reasoningItems[itemID];
|
|
630
|
-
if (!item || index === 0 || item.summaryParts[index] !== undefined)
|
|
631
|
-
return [state, NO_EVENTS];
|
|
632
|
-
if (Object.values(item.summaryParts).every((status) => status === "concluded"))
|
|
630
|
+
if (!item?.open || index === 0 || item.summaryParts[index] !== undefined)
|
|
633
631
|
return [state, NO_EVENTS];
|
|
634
632
|
const events = [];
|
|
635
633
|
const lifecycle = Object.entries(item.summaryParts)
|
|
@@ -655,26 +653,22 @@ const startReasoningSummaryPart = (state, itemID, index) => {
|
|
|
655
653
|
};
|
|
656
654
|
export const onReasoningDelta = (state, event, itemID) => {
|
|
657
655
|
const item = state.reasoningItems[itemID];
|
|
658
|
-
if (!event.delta || !item)
|
|
656
|
+
if (!event.delta || !item?.open)
|
|
659
657
|
return [state, NO_EVENTS];
|
|
660
658
|
const index = event.summary_index ?? 0;
|
|
661
659
|
if (item.summaryParts[index] === "concluded")
|
|
662
660
|
return [state, NO_EVENTS];
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
Object.values(item.summaryParts).every((status) => status === "concluded"))
|
|
666
|
-
return [state, NO_EVENTS];
|
|
667
|
-
const started = item.summaryParts[index] === undefined ? startReasoningSummaryPart(state, itemID, index) : [state, NO_EVENTS];
|
|
668
|
-
const current = started[0].reasoningItems[itemID];
|
|
661
|
+
const [started, emitted] = startReasoningSummaryPart(state, itemID, index);
|
|
662
|
+
const current = started.reasoningItems[itemID];
|
|
669
663
|
if (!current)
|
|
670
|
-
return started;
|
|
671
|
-
const events = [...
|
|
664
|
+
return [started, emitted];
|
|
665
|
+
const events = [...emitted];
|
|
672
666
|
return [
|
|
673
667
|
{
|
|
674
|
-
...started
|
|
675
|
-
lifecycle: Lifecycle.reasoningDelta(started
|
|
668
|
+
...started,
|
|
669
|
+
lifecycle: Lifecycle.reasoningDelta(started.lifecycle, events, `${itemID}:${index}`, event.delta),
|
|
676
670
|
reasoningItems: {
|
|
677
|
-
...started
|
|
671
|
+
...started.reasoningItems,
|
|
678
672
|
[itemID]: { ...current, deltaIndexes: new Set([...current.deltaIndexes, index]) },
|
|
679
673
|
},
|
|
680
674
|
},
|
|
@@ -686,7 +680,7 @@ export const onReasoningDelta = (state, event, itemID) => {
|
|
|
686
680
|
// as a single delta unless that summary index already streamed one.
|
|
687
681
|
export const onReasoningDone = (state, event, itemID) => {
|
|
688
682
|
const item = state.reasoningItems[itemID];
|
|
689
|
-
if (!item || typeof event.text !== "string")
|
|
683
|
+
if (!item?.open || typeof event.text !== "string")
|
|
690
684
|
return [state, NO_EVENTS];
|
|
691
685
|
const index = event.summary_index ?? 0;
|
|
692
686
|
if (item.deltaIndexes.has(index))
|
|
@@ -709,23 +703,22 @@ const onOutputItemAdded = (state, event) => {
|
|
|
709
703
|
if (item?.type === "message" && item.id !== undefined) {
|
|
710
704
|
const itemID = item.id;
|
|
711
705
|
const phase = messagePhase(item.phase);
|
|
712
|
-
// A new message
|
|
713
|
-
// item: text still streaming is ended, and all older items leave the
|
|
714
|
-
// tracked set so their late deltas stay no-ops instead of overlapping.
|
|
706
|
+
// A new message closes earlier messages, including ones that never streamed.
|
|
715
707
|
const events = [];
|
|
716
708
|
const lifecycle = [...state.lifecycle.text]
|
|
717
709
|
.filter((id) => id !== itemID)
|
|
718
710
|
.reduce((lifecycle, id) => {
|
|
719
|
-
const openPhase = state.
|
|
711
|
+
const openPhase = state.message?.id === id ? state.message.phase : undefined;
|
|
720
712
|
return Lifecycle.textEnd(lifecycle, events, id, providerMetadata(state, { itemId: id, ...(openPhase === undefined ? {} : { phase: openPhase }) }));
|
|
721
713
|
}, state.lifecycle);
|
|
722
|
-
const nextPhase = phase === undefined ? state.messagePhases[itemID] : phase;
|
|
723
714
|
return [
|
|
724
715
|
{
|
|
725
716
|
...state,
|
|
726
717
|
lifecycle,
|
|
727
|
-
|
|
728
|
-
|
|
718
|
+
message: {
|
|
719
|
+
id: itemID,
|
|
720
|
+
phase: phase === undefined && state.message?.id === itemID ? state.message.phase : phase,
|
|
721
|
+
},
|
|
729
722
|
},
|
|
730
723
|
events,
|
|
731
724
|
];
|
|
@@ -741,6 +734,7 @@ const onOutputItemAdded = (state, event) => {
|
|
|
741
734
|
reasoningItems: {
|
|
742
735
|
...state.reasoningItems,
|
|
743
736
|
[item.id]: {
|
|
737
|
+
open: true,
|
|
744
738
|
encryptedContent: item.encrypted_content,
|
|
745
739
|
summaryParts: { 0: "active" },
|
|
746
740
|
deltaIndexes: new Set(),
|
|
@@ -753,8 +747,6 @@ const onOutputItemAdded = (state, event) => {
|
|
|
753
747
|
if (item?.type !== "function_call" || !item.call_id)
|
|
754
748
|
return [state, NO_EVENTS];
|
|
755
749
|
const id = item.id ?? item.call_id;
|
|
756
|
-
// Pending tools always store the call id, so this also catches duplicates
|
|
757
|
-
// that disagree on whether `item.id` is present.
|
|
758
750
|
if (Object.values(state.tools).some((tool) => tool?.id === item.call_id) || state.completedTools.has(item.call_id))
|
|
759
751
|
return [state, NO_EVENTS];
|
|
760
752
|
const metadata = item.id !== undefined ? providerMetadata(state, { itemId: item.id }) : undefined;
|
|
@@ -783,7 +775,7 @@ const onReasoningSummaryPartDone = (state, event) => {
|
|
|
783
775
|
if (event.item_id === undefined || event.summary_index === undefined)
|
|
784
776
|
return [state, NO_EVENTS];
|
|
785
777
|
const item = state.reasoningItems[event.item_id];
|
|
786
|
-
if (!item)
|
|
778
|
+
if (!item?.open)
|
|
787
779
|
return [state, NO_EVENTS];
|
|
788
780
|
if (item.summaryParts[event.summary_index] !== "active")
|
|
789
781
|
return [state, NO_EVENTS];
|
|
@@ -835,17 +827,13 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
|
|
|
835
827
|
return [state, NO_EVENTS];
|
|
836
828
|
if (item.type === "message" && item.id !== undefined) {
|
|
837
829
|
const itemPhase = messagePhase(item.phase);
|
|
838
|
-
const phase = itemPhase === undefined
|
|
830
|
+
const phase = itemPhase === undefined && state.message?.id === item.id ? state.message.phase : itemPhase;
|
|
839
831
|
const events = [];
|
|
840
|
-
const messageItems = new Set(state.messageItems);
|
|
841
|
-
messageItems.delete(item.id);
|
|
842
|
-
const { [item.id]: _phase, ...messagePhases } = state.messagePhases;
|
|
843
832
|
return [
|
|
844
833
|
{
|
|
845
834
|
...state,
|
|
846
835
|
lifecycle: Lifecycle.textEnd(state.lifecycle, events, item.id, providerMetadata(state, { itemId: item.id, ...(phase === undefined ? {} : { phase }) })),
|
|
847
|
-
|
|
848
|
-
messagePhases,
|
|
836
|
+
message: state.message?.id === item.id ? undefined : state.message,
|
|
849
837
|
},
|
|
850
838
|
events,
|
|
851
839
|
];
|
|
@@ -899,11 +887,11 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
|
|
|
899
887
|
const metadata = reasoningMetadata(state, item);
|
|
900
888
|
const reasoningItem = state.reasoningItems[item.id];
|
|
901
889
|
if (reasoningItem) {
|
|
890
|
+
if (!reasoningItem.open)
|
|
891
|
+
return [state, NO_EVENTS];
|
|
902
892
|
const lifecycle = Object.entries(reasoningItem.summaryParts)
|
|
903
893
|
.filter((entry) => entry[1] === "active" || entry[1] === "can-conclude")
|
|
904
894
|
.reduce((lifecycle, entry) => Lifecycle.reasoningEnd(lifecycle, events, `${item.id}:${entry[0]}`, metadata), state.lifecycle);
|
|
905
|
-
// Keep the fully-concluded entry so duplicate or late events for this
|
|
906
|
-
// item remain no-ops instead of reopening lifecycle state.
|
|
907
895
|
return [
|
|
908
896
|
{
|
|
909
897
|
...state,
|
|
@@ -912,8 +900,8 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
|
|
|
912
900
|
...state.reasoningItems,
|
|
913
901
|
[item.id]: {
|
|
914
902
|
...reasoningItem,
|
|
903
|
+
open: false,
|
|
915
904
|
encryptedContent: item.encrypted_content ?? reasoningItem.encryptedContent,
|
|
916
|
-
summaryParts: Object.fromEntries(Object.keys(reasoningItem.summaryParts).map((index) => [index, "concluded"])),
|
|
917
905
|
},
|
|
918
906
|
},
|
|
919
907
|
},
|
|
@@ -931,6 +919,7 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
|
|
|
931
919
|
reasoningItems: {
|
|
932
920
|
...state.reasoningItems,
|
|
933
921
|
[item.id]: {
|
|
922
|
+
open: false,
|
|
934
923
|
encryptedContent: item.encrypted_content,
|
|
935
924
|
summaryParts: { 0: "concluded" },
|
|
936
925
|
deltaIndexes: new Set(),
|
|
@@ -953,7 +942,7 @@ const onResponseFinish = Effect.fn("OpenResponses.onResponseFinish")(function* (
|
|
|
953
942
|
const id = item.id ?? (item.type === "function_call" ? item.call_id : undefined);
|
|
954
943
|
if (id === undefined ||
|
|
955
944
|
((item.type !== "function_call" || !current.tools[id]) &&
|
|
956
|
-
(item.type !== "reasoning" || !current.reasoningItems[id])))
|
|
945
|
+
(item.type !== "reasoning" || !current.reasoningItems[id]?.open)))
|
|
957
946
|
return Effect.succeed([current, events]);
|
|
958
947
|
return onOutputItemDone(current, { type: "response.output_item.done", item }).pipe(Effect.map(([next, emitted]) => [next, [...events, ...emitted]]));
|
|
959
948
|
})
|
|
@@ -1098,8 +1087,7 @@ export const initial = (request, extension = BASE) => ({
|
|
|
1098
1087
|
completedTools: new Set(),
|
|
1099
1088
|
lifecycle: Lifecycle.initial(),
|
|
1100
1089
|
outputItems: {},
|
|
1101
|
-
|
|
1102
|
-
messagePhases: {},
|
|
1090
|
+
message: undefined,
|
|
1103
1091
|
reasoningItems: {},
|
|
1104
1092
|
});
|
|
1105
1093
|
export const protocol = Protocol.make({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
-
"version": "0.0.0-dev-
|
|
3
|
+
"version": "0.0.0-dev-18549",
|
|
4
4
|
"name": "@opencode-ai/ai",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@clack/prompts": "1.0.0-alpha.1",
|
|
32
32
|
"@effect/platform-node": "4.0.0-rc.112",
|
|
33
|
-
"@opencode-ai/http-recorder": "0.0.0-dev-
|
|
33
|
+
"@opencode-ai/http-recorder": "0.0.0-dev-18549",
|
|
34
34
|
"@tsconfig/bun": "1.0.9",
|
|
35
35
|
"@types/bun": "1.3.13",
|
|
36
36
|
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@smithy/eventstream-codec": "4.2.14",
|
|
41
41
|
"@smithy/util-utf8": "4.2.2",
|
|
42
|
-
"@opencode-ai/schema": "0.0.0-dev-
|
|
42
|
+
"@opencode-ai/schema": "0.0.0-dev-18549",
|
|
43
43
|
"aws4fetch": "1.0.20",
|
|
44
44
|
"effect": "4.0.0-rc.112",
|
|
45
45
|
"google-auth-library": "10.5.0"
|