@ellipsis-dev/sdk 0.34.1 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -7
- package/dist/index.d.ts +97 -171
- package/dist/index.js +19 -183
- package/dist/store/index.d.ts +5 -2
- package/dist/store/index.js +326 -130
- package/dist/stream/index.d.ts +4 -7
- package/dist/stream/index.js +187 -21
- package/dist/{types-DV2H5ZsR.d.ts → types-CbePyY-S.d.ts} +919 -1142
- package/package.json +1 -1
- package/schema/collection_frames.schema.json +162 -17
- package/schema/frames.schema.json +883 -87
- package/schema/openapi.v1.json +5830 -6248
- package/dist/chunk-6V7QTLLF.js +0 -214
package/dist/store/index.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SESSION_STREAM_PROTOCOL_VERSION
|
|
3
|
-
} from "../chunk-6V7QTLLF.js";
|
|
4
|
-
|
|
5
1
|
// src/store/claude.ts
|
|
6
2
|
function claudePayload(record) {
|
|
7
3
|
if (record.kind === "claude_sdk") return record.payload;
|
|
@@ -51,6 +47,42 @@ function claudePayload(record) {
|
|
|
51
47
|
}
|
|
52
48
|
|
|
53
49
|
// src/store/codexAppServer.ts
|
|
50
|
+
function codexSubagentThreads(records) {
|
|
51
|
+
const threads = /* @__PURE__ */ new Set();
|
|
52
|
+
for (const record of records) addCodexSubagentThreads(threads, record);
|
|
53
|
+
return threads;
|
|
54
|
+
}
|
|
55
|
+
function addCodexSubagentThreads(threads, record) {
|
|
56
|
+
if (record.kind !== "codex_app_server") return false;
|
|
57
|
+
const event = record.payload;
|
|
58
|
+
if (event.method !== "item/started" && event.method !== "item/completed") {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const item = event.params.item;
|
|
62
|
+
if (item.type === "subAgentActivity") {
|
|
63
|
+
threads.add(item.agentThreadId);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
if (item.type === "collabAgentToolCall") {
|
|
67
|
+
for (const thread of item.receiverThreadIds) threads.add(thread);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
function isCodexSubagentSpawn(record) {
|
|
73
|
+
if (record.kind !== "codex_app_server") return false;
|
|
74
|
+
const event = record.payload;
|
|
75
|
+
if (event.method !== "item/started" && event.method !== "item/completed") {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
const item = event.params.item;
|
|
79
|
+
return item.type === "subAgentActivity" && item.kind === "started";
|
|
80
|
+
}
|
|
81
|
+
function isCodexSubagentRecord(threads, record) {
|
|
82
|
+
if (record.kind !== "codex_app_server") return false;
|
|
83
|
+
const params = record.payload.params;
|
|
84
|
+
return "threadId" in params && typeof params.threadId === "string" && threads.has(params.threadId);
|
|
85
|
+
}
|
|
54
86
|
function codexAppServerContent(event) {
|
|
55
87
|
if (event.method === "turn/completed") {
|
|
56
88
|
return { kind: "end", isError: event.params.turn.status !== "completed" };
|
|
@@ -90,6 +122,15 @@ function codexAppServerContent(event) {
|
|
|
90
122
|
result: item.changes.map((change) => change.diff).join("\n"),
|
|
91
123
|
isError: item.status === "failed" || item.status === "declined"
|
|
92
124
|
};
|
|
125
|
+
case "subAgentActivity":
|
|
126
|
+
return {
|
|
127
|
+
kind: "tool",
|
|
128
|
+
name: "Agent",
|
|
129
|
+
input: { agentPath: item.agentPath ?? null, kind: item.kind },
|
|
130
|
+
summary: item.agentPath ?? item.agentThreadId,
|
|
131
|
+
result: item.kind,
|
|
132
|
+
isError: false
|
|
133
|
+
};
|
|
93
134
|
case "webSearch":
|
|
94
135
|
return {
|
|
95
136
|
kind: "tool",
|
|
@@ -104,124 +145,6 @@ function codexAppServerContent(event) {
|
|
|
104
145
|
}
|
|
105
146
|
}
|
|
106
147
|
|
|
107
|
-
// src/store/progress.ts
|
|
108
|
-
function messageProgress(records) {
|
|
109
|
-
const messages = /* @__PURE__ */ new Map();
|
|
110
|
-
const pending = /* @__PURE__ */ new Map();
|
|
111
|
-
const turns = /* @__PURE__ */ new Map();
|
|
112
|
-
let ready = false;
|
|
113
|
-
const getTurn = (id) => {
|
|
114
|
-
let turn = turns.get(id);
|
|
115
|
-
if (!turn) {
|
|
116
|
-
turn = {
|
|
117
|
-
timing: { id, startedAt: null, completedAt: null },
|
|
118
|
-
phase: ready ? "working" : "starting",
|
|
119
|
-
messages: /* @__PURE__ */ new Set()
|
|
120
|
-
};
|
|
121
|
-
turns.set(id, turn);
|
|
122
|
-
}
|
|
123
|
-
return turn;
|
|
124
|
-
};
|
|
125
|
-
const attach = (messageId, turnId) => {
|
|
126
|
-
const message = messages.get(messageId);
|
|
127
|
-
if (!message) return;
|
|
128
|
-
const turn = getTurn(turnId);
|
|
129
|
-
if (!turn.messages.has(messageId)) {
|
|
130
|
-
turn.messages.add(messageId);
|
|
131
|
-
message.turns.push(turn.timing);
|
|
132
|
-
}
|
|
133
|
-
pending.delete(messageId);
|
|
134
|
-
message.phase = turn.phase;
|
|
135
|
-
};
|
|
136
|
-
const setPending = (turnId, phase) => {
|
|
137
|
-
for (const [id, turn] of pending) {
|
|
138
|
-
if (turnId == null || turn == null || turn === turnId)
|
|
139
|
-
messages.get(id).phase = phase;
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
for (const record of records) {
|
|
143
|
-
if (record.kind === "platform") {
|
|
144
|
-
const p = record.payload;
|
|
145
|
-
const messageId = typeof p.message_id === "string" ? p.message_id : null;
|
|
146
|
-
const turnId = typeof p.turn_id === "string" ? p.turn_id : record.turn_id;
|
|
147
|
-
switch (record.record_type) {
|
|
148
|
-
case "message_received":
|
|
149
|
-
if (messageId && !messages.has(messageId)) {
|
|
150
|
-
messages.set(messageId, { phase: "queued", turns: [] });
|
|
151
|
-
if (turnId && turns.has(turnId)) attach(messageId, turnId);
|
|
152
|
-
else pending.set(messageId, turnId ?? null);
|
|
153
|
-
}
|
|
154
|
-
break;
|
|
155
|
-
case "message_delivered":
|
|
156
|
-
if (messageId && turnId) attach(messageId, turnId);
|
|
157
|
-
break;
|
|
158
|
-
case "message_requeued":
|
|
159
|
-
if (messageId && messages.has(messageId)) {
|
|
160
|
-
const requeued = typeof p.requeued_turn_id === "string" ? p.requeued_turn_id : null;
|
|
161
|
-
pending.set(messageId, requeued);
|
|
162
|
-
messages.get(messageId).phase = "queued";
|
|
163
|
-
}
|
|
164
|
-
break;
|
|
165
|
-
case "environment_phase":
|
|
166
|
-
case "environment_output":
|
|
167
|
-
ready = false;
|
|
168
|
-
setPending(turnId ?? null, "preparing");
|
|
169
|
-
break;
|
|
170
|
-
case "environment_ready":
|
|
171
|
-
ready = false;
|
|
172
|
-
setPending(turnId ?? null, "starting");
|
|
173
|
-
break;
|
|
174
|
-
case "turn_started":
|
|
175
|
-
if (turnId) {
|
|
176
|
-
getTurn(turnId).timing.startedAt = record.created_at;
|
|
177
|
-
for (const [id, turn] of pending) {
|
|
178
|
-
if (turn === turnId) attach(id, turnId);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
break;
|
|
182
|
-
case "turn_ended":
|
|
183
|
-
if (turnId) {
|
|
184
|
-
const turn = getTurn(turnId);
|
|
185
|
-
turn.timing.completedAt = record.created_at;
|
|
186
|
-
turn.phase = null;
|
|
187
|
-
for (const id of turn.messages) {
|
|
188
|
-
if (!pending.has(id)) messages.get(id).phase = null;
|
|
189
|
-
}
|
|
190
|
-
for (const [id, pendingTurn] of pending) {
|
|
191
|
-
if (pendingTurn === turnId) {
|
|
192
|
-
pending.delete(id);
|
|
193
|
-
messages.get(id).phase = null;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
break;
|
|
198
|
-
case "session_closed":
|
|
199
|
-
ready = false;
|
|
200
|
-
for (const id of pending.keys()) messages.get(id).phase = null;
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
const claude = claudePayload(record);
|
|
206
|
-
const agentStarted = record.kind === "codex_app_server" && record.payload.method === "turn/started" || record.kind === "codex" && record.payload.type === "turn.started" || claude != null && (claude.kind === "assistant" || claude.kind === "user" || claude.kind === "system" && claude.subtype === "init");
|
|
207
|
-
if (agentStarted) {
|
|
208
|
-
ready = true;
|
|
209
|
-
if (record.turn_id) {
|
|
210
|
-
const turn = getTurn(record.turn_id);
|
|
211
|
-
if (turn.timing.completedAt == null) {
|
|
212
|
-
turn.timing.startedAt ??= record.created_at;
|
|
213
|
-
turn.phase = "working";
|
|
214
|
-
for (const id of turn.messages) messages.get(id).phase = "working";
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
if (record.session_message_id && record.turn_id) {
|
|
219
|
-
attach(record.session_message_id, record.turn_id);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return messages;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
148
|
// src/store/lifecycle.ts
|
|
226
149
|
function environmentOutputStep(payload) {
|
|
227
150
|
if (typeof payload.step === "string" && payload.step) return payload.step;
|
|
@@ -623,6 +546,55 @@ function recordToItems(record, keyBase, options = {}) {
|
|
|
623
546
|
}
|
|
624
547
|
] : [];
|
|
625
548
|
}
|
|
549
|
+
case "gemini": {
|
|
550
|
+
const content = geminiStreamContent(record.payload);
|
|
551
|
+
if (!content) return [];
|
|
552
|
+
if (content.kind === "end") {
|
|
553
|
+
return content.isError ? [
|
|
554
|
+
{
|
|
555
|
+
key: keyBase,
|
|
556
|
+
kind: "summary",
|
|
557
|
+
text: "turn ended with an error",
|
|
558
|
+
isError: true,
|
|
559
|
+
spaceBefore: true
|
|
560
|
+
}
|
|
561
|
+
] : [];
|
|
562
|
+
}
|
|
563
|
+
if (content.kind === "tool") {
|
|
564
|
+
return [
|
|
565
|
+
{
|
|
566
|
+
key: keyBase,
|
|
567
|
+
kind: "tool",
|
|
568
|
+
gutter: "\u25CF",
|
|
569
|
+
text: content.name,
|
|
570
|
+
detail: content.summary ? `(${content.summary})` : void 0,
|
|
571
|
+
spaceBefore: true,
|
|
572
|
+
tool: { name: content.name, input: content.input ?? void 0 }
|
|
573
|
+
}
|
|
574
|
+
];
|
|
575
|
+
}
|
|
576
|
+
if (content.kind === "tool_result") {
|
|
577
|
+
return [
|
|
578
|
+
{
|
|
579
|
+
key: keyBase,
|
|
580
|
+
kind: "tool_result",
|
|
581
|
+
gutter: "\u23BF",
|
|
582
|
+
text: content.text || "(completed)",
|
|
583
|
+
isError: content.isError,
|
|
584
|
+
spaceBefore: false
|
|
585
|
+
}
|
|
586
|
+
];
|
|
587
|
+
}
|
|
588
|
+
return [
|
|
589
|
+
{
|
|
590
|
+
key: keyBase,
|
|
591
|
+
kind: content.kind,
|
|
592
|
+
text: content.text.trim(),
|
|
593
|
+
isError: content.kind === "error",
|
|
594
|
+
spaceBefore: true
|
|
595
|
+
}
|
|
596
|
+
];
|
|
597
|
+
}
|
|
626
598
|
case "platform": {
|
|
627
599
|
const text2 = lifecycleText(record.record_type, record.payload);
|
|
628
600
|
return text2 ? [{ key: keyBase, kind: "notice", text: text2, spaceBefore: true }] : [];
|
|
@@ -728,6 +700,155 @@ function statusActivityText(status) {
|
|
|
728
700
|
}
|
|
729
701
|
}
|
|
730
702
|
|
|
703
|
+
// src/store/geminiStream.ts
|
|
704
|
+
function geminiStreamContent(event) {
|
|
705
|
+
switch (event.type) {
|
|
706
|
+
case "message":
|
|
707
|
+
return event.role === "assistant" && !event.delta && event.content.trim() ? { kind: "assistant", text: event.content } : null;
|
|
708
|
+
case "tool_use": {
|
|
709
|
+
const input = event.parameters ?? null;
|
|
710
|
+
return {
|
|
711
|
+
kind: "tool",
|
|
712
|
+
toolId: event.tool_id,
|
|
713
|
+
name: event.tool_name,
|
|
714
|
+
input,
|
|
715
|
+
summary: oneLine(summarizeToolInput(event.tool_name, input ?? {}), 100)
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
case "tool_result":
|
|
719
|
+
return {
|
|
720
|
+
kind: "tool_result",
|
|
721
|
+
toolId: event.tool_id,
|
|
722
|
+
text: (event.output ?? event.error?.message ?? "").trim(),
|
|
723
|
+
isError: event.status === "error"
|
|
724
|
+
};
|
|
725
|
+
case "error":
|
|
726
|
+
return { kind: "error", text: event.message };
|
|
727
|
+
case "result":
|
|
728
|
+
return { kind: "end", isError: event.status === "error" };
|
|
729
|
+
default:
|
|
730
|
+
return null;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// src/store/progress.ts
|
|
735
|
+
function messageProgress(records) {
|
|
736
|
+
const messages = /* @__PURE__ */ new Map();
|
|
737
|
+
const pending = /* @__PURE__ */ new Map();
|
|
738
|
+
const turns = /* @__PURE__ */ new Map();
|
|
739
|
+
let ready = false;
|
|
740
|
+
const getTurn = (id) => {
|
|
741
|
+
let turn = turns.get(id);
|
|
742
|
+
if (!turn) {
|
|
743
|
+
turn = {
|
|
744
|
+
timing: { id, startedAt: null, completedAt: null },
|
|
745
|
+
phase: ready ? "working" : "starting",
|
|
746
|
+
messages: /* @__PURE__ */ new Set()
|
|
747
|
+
};
|
|
748
|
+
turns.set(id, turn);
|
|
749
|
+
}
|
|
750
|
+
return turn;
|
|
751
|
+
};
|
|
752
|
+
const attach = (messageId, turnId) => {
|
|
753
|
+
const message = messages.get(messageId);
|
|
754
|
+
if (!message) return;
|
|
755
|
+
const turn = getTurn(turnId);
|
|
756
|
+
if (!turn.messages.has(messageId)) {
|
|
757
|
+
turn.messages.add(messageId);
|
|
758
|
+
message.turns.push(turn.timing);
|
|
759
|
+
}
|
|
760
|
+
pending.delete(messageId);
|
|
761
|
+
message.phase = turn.phase;
|
|
762
|
+
};
|
|
763
|
+
const setPending = (turnId, phase) => {
|
|
764
|
+
for (const [id, turn] of pending) {
|
|
765
|
+
if (turnId == null || turn == null || turn === turnId)
|
|
766
|
+
messages.get(id).phase = phase;
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
for (const record of records) {
|
|
770
|
+
if (record.kind === "platform") {
|
|
771
|
+
const p = record.payload;
|
|
772
|
+
const messageId = typeof p.message_id === "string" ? p.message_id : null;
|
|
773
|
+
const turnId = typeof p.turn_id === "string" ? p.turn_id : record.turn_id;
|
|
774
|
+
switch (record.record_type) {
|
|
775
|
+
case "message_received":
|
|
776
|
+
if (messageId && !messages.has(messageId)) {
|
|
777
|
+
messages.set(messageId, { phase: "queued", turns: [] });
|
|
778
|
+
if (turnId && turns.has(turnId)) attach(messageId, turnId);
|
|
779
|
+
else pending.set(messageId, turnId ?? null);
|
|
780
|
+
}
|
|
781
|
+
break;
|
|
782
|
+
case "message_delivered":
|
|
783
|
+
if (messageId && turnId) attach(messageId, turnId);
|
|
784
|
+
break;
|
|
785
|
+
case "message_requeued":
|
|
786
|
+
if (messageId && messages.has(messageId)) {
|
|
787
|
+
const requeued = typeof p.requeued_turn_id === "string" ? p.requeued_turn_id : null;
|
|
788
|
+
pending.set(messageId, requeued);
|
|
789
|
+
messages.get(messageId).phase = "queued";
|
|
790
|
+
}
|
|
791
|
+
break;
|
|
792
|
+
case "environment_phase":
|
|
793
|
+
case "environment_output":
|
|
794
|
+
ready = false;
|
|
795
|
+
setPending(turnId ?? null, "preparing");
|
|
796
|
+
break;
|
|
797
|
+
case "environment_ready":
|
|
798
|
+
ready = false;
|
|
799
|
+
setPending(turnId ?? null, "starting");
|
|
800
|
+
break;
|
|
801
|
+
case "turn_started":
|
|
802
|
+
if (turnId) {
|
|
803
|
+
getTurn(turnId).timing.startedAt = record.created_at;
|
|
804
|
+
for (const [id, turn] of pending) {
|
|
805
|
+
if (turn === turnId) attach(id, turnId);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
break;
|
|
809
|
+
case "turn_ended":
|
|
810
|
+
if (turnId) {
|
|
811
|
+
const turn = getTurn(turnId);
|
|
812
|
+
turn.timing.completedAt = record.created_at;
|
|
813
|
+
turn.phase = null;
|
|
814
|
+
for (const id of turn.messages) {
|
|
815
|
+
if (!pending.has(id)) messages.get(id).phase = null;
|
|
816
|
+
}
|
|
817
|
+
for (const [id, pendingTurn] of pending) {
|
|
818
|
+
if (pendingTurn === turnId) {
|
|
819
|
+
pending.delete(id);
|
|
820
|
+
messages.get(id).phase = null;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
break;
|
|
825
|
+
case "session_closed":
|
|
826
|
+
ready = false;
|
|
827
|
+
for (const id of pending.keys()) messages.get(id).phase = null;
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
const claude = claudePayload(record);
|
|
833
|
+
const agentStarted = record.kind === "codex_app_server" && record.payload.method === "turn/started" || record.kind === "codex" && record.payload.type === "turn.started" || record.kind === "gemini" && record.payload.type === "init" || claude != null && (claude.kind === "assistant" || claude.kind === "user" || claude.kind === "system" && claude.subtype === "init");
|
|
834
|
+
if (agentStarted) {
|
|
835
|
+
ready = true;
|
|
836
|
+
if (record.turn_id) {
|
|
837
|
+
const turn = getTurn(record.turn_id);
|
|
838
|
+
if (turn.timing.completedAt == null) {
|
|
839
|
+
turn.timing.startedAt ??= record.created_at;
|
|
840
|
+
turn.phase = "working";
|
|
841
|
+
for (const id of turn.messages) messages.get(id).phase = "working";
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
if (record.session_message_id && record.turn_id) {
|
|
846
|
+
attach(record.session_message_id, record.turn_id);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return messages;
|
|
850
|
+
}
|
|
851
|
+
|
|
731
852
|
// src/store/chatTurns.ts
|
|
732
853
|
var isInitEvent = (data) => data.kind === "system" && data.subtype === "init";
|
|
733
854
|
var ENVIRONMENT_RECORD_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -738,6 +859,8 @@ var ENVIRONMENT_RECORD_TYPES = /* @__PURE__ */ new Set([
|
|
|
738
859
|
function groupRecordsToChatTurns(records, session) {
|
|
739
860
|
const turns = [];
|
|
740
861
|
const toolNodeByUseId = /* @__PURE__ */ new Map();
|
|
862
|
+
const openGeminiTools = /* @__PURE__ */ new Map();
|
|
863
|
+
const codexSubagentThreads2 = /* @__PURE__ */ new Set();
|
|
741
864
|
const userTurnByMessageId = /* @__PURE__ */ new Map();
|
|
742
865
|
const turnByMessageId = /* @__PURE__ */ new Map();
|
|
743
866
|
const unansweredTurnIds = /* @__PURE__ */ new Set();
|
|
@@ -773,6 +896,20 @@ function groupRecordsToChatTurns(records, session) {
|
|
|
773
896
|
}
|
|
774
897
|
return turns[openIdx];
|
|
775
898
|
};
|
|
899
|
+
const subagentTurn = (record) => {
|
|
900
|
+
for (let i = turns.length - 1; i >= 0; i--) {
|
|
901
|
+
const turn = turns[i];
|
|
902
|
+
if (turn.role === "assistant" && turn.turnId === (record.turn_id ?? void 0))
|
|
903
|
+
return turn;
|
|
904
|
+
}
|
|
905
|
+
return null;
|
|
906
|
+
};
|
|
907
|
+
const newestAssistantTurn = () => {
|
|
908
|
+
for (let i = turns.length - 1; i >= 0; i--) {
|
|
909
|
+
if (turns[i].role === "assistant") return turns[i];
|
|
910
|
+
}
|
|
911
|
+
return null;
|
|
912
|
+
};
|
|
776
913
|
for (const record of records) {
|
|
777
914
|
if (record.kind === "platform") {
|
|
778
915
|
const messageId = typeof record.payload.message_id === "string" ? record.payload.message_id : null;
|
|
@@ -897,17 +1034,75 @@ function groupRecordsToChatTurns(records, session) {
|
|
|
897
1034
|
});
|
|
898
1035
|
continue;
|
|
899
1036
|
}
|
|
1037
|
+
if (record.kind === "gemini") {
|
|
1038
|
+
const content = geminiStreamContent(record.payload);
|
|
1039
|
+
if (!content) continue;
|
|
1040
|
+
if (content.kind === "end") {
|
|
1041
|
+
if (openIdx >= 0) {
|
|
1042
|
+
turns[openIdx].completedAt = record.created_at;
|
|
1043
|
+
if (content.isError) turns[openIdx].isError = true;
|
|
1044
|
+
openIdx = -1;
|
|
1045
|
+
}
|
|
1046
|
+
} else if (content.kind === "tool") {
|
|
1047
|
+
const node = {
|
|
1048
|
+
key: nextKey(record.id),
|
|
1049
|
+
kind: "tool",
|
|
1050
|
+
name: content.name,
|
|
1051
|
+
input: content.input,
|
|
1052
|
+
summary: content.summary,
|
|
1053
|
+
result: null,
|
|
1054
|
+
isError: false,
|
|
1055
|
+
startedAt: record.created_at,
|
|
1056
|
+
completedAt: null
|
|
1057
|
+
};
|
|
1058
|
+
openSessionTurn(record).nodes.push(node);
|
|
1059
|
+
openGeminiTools.set(content.toolId, node);
|
|
1060
|
+
} else if (content.kind === "tool_result") {
|
|
1061
|
+
const node = openGeminiTools.get(content.toolId);
|
|
1062
|
+
if (node) {
|
|
1063
|
+
node.result = content.text;
|
|
1064
|
+
node.isError = content.isError;
|
|
1065
|
+
node.completedAt = record.created_at;
|
|
1066
|
+
openGeminiTools.delete(content.toolId);
|
|
1067
|
+
}
|
|
1068
|
+
} else {
|
|
1069
|
+
const turn2 = openSessionTurn(record);
|
|
1070
|
+
if (content.kind === "error") turn2.isError = true;
|
|
1071
|
+
turn2.nodes.push({
|
|
1072
|
+
key: nextKey(record.id),
|
|
1073
|
+
kind: "assistant",
|
|
1074
|
+
text: content.text.trim(),
|
|
1075
|
+
createdAt: record.created_at
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
continue;
|
|
1079
|
+
}
|
|
900
1080
|
if (record.kind === "codex_app_server") {
|
|
1081
|
+
const fromSubagent = isCodexSubagentRecord(codexSubagentThreads2, record);
|
|
1082
|
+
const announces = addCodexSubagentThreads(codexSubagentThreads2, record);
|
|
901
1083
|
const content = codexAppServerContent(record.payload);
|
|
902
1084
|
if (!content) continue;
|
|
1085
|
+
const late = fromSubagent || announces && !isCodexSubagentSpawn(record);
|
|
1086
|
+
const turnFor = () => {
|
|
1087
|
+
if (!late) return openSessionTurn(record);
|
|
1088
|
+
const open = openIdx >= 0 ? turns[openIdx] : null;
|
|
1089
|
+
if (open !== null && open.turnId === (record.turn_id ?? void 0)) {
|
|
1090
|
+
return open;
|
|
1091
|
+
}
|
|
1092
|
+
if (record.turn_id == null) {
|
|
1093
|
+
return open ?? newestAssistantTurn() ?? openSessionTurn(record);
|
|
1094
|
+
}
|
|
1095
|
+
return subagentTurn(record) ?? openSessionTurn(record);
|
|
1096
|
+
};
|
|
903
1097
|
if (content.kind === "end") {
|
|
1098
|
+
if (fromSubagent) continue;
|
|
904
1099
|
if (openIdx >= 0) {
|
|
905
1100
|
turns[openIdx].completedAt = record.created_at;
|
|
906
1101
|
if (content.isError) turns[openIdx].isError = true;
|
|
907
1102
|
openIdx = -1;
|
|
908
1103
|
}
|
|
909
1104
|
} else if (content.kind === "tool") {
|
|
910
|
-
|
|
1105
|
+
turnFor().nodes.push({
|
|
911
1106
|
key: nextKey(record.id),
|
|
912
1107
|
kind: "tool",
|
|
913
1108
|
name: content.name,
|
|
@@ -919,8 +1114,8 @@ function groupRecordsToChatTurns(records, session) {
|
|
|
919
1114
|
completedAt: record.created_at
|
|
920
1115
|
});
|
|
921
1116
|
} else if (content.text.trim()) {
|
|
922
|
-
const turn2 =
|
|
923
|
-
if (content.kind === "error") turn2.isError = true;
|
|
1117
|
+
const turn2 = turnFor();
|
|
1118
|
+
if (content.kind === "error" && !fromSubagent) turn2.isError = true;
|
|
924
1119
|
turn2.nodes.push({
|
|
925
1120
|
key: nextKey(record.id),
|
|
926
1121
|
kind: content.kind === "error" ? "assistant" : content.kind,
|
|
@@ -1866,7 +2061,6 @@ function isConversationOver(session) {
|
|
|
1866
2061
|
function seedTranscriptStore(store, seed) {
|
|
1867
2062
|
store.ingest({
|
|
1868
2063
|
type: "snapshot",
|
|
1869
|
-
protocol: SESSION_STREAM_PROTOCOL_VERSION,
|
|
1870
2064
|
earliest_feed_seq: seed.earliestFeedSeq ?? null,
|
|
1871
2065
|
session: seed.session,
|
|
1872
2066
|
messages: [...seed.messages ?? []]
|
|
@@ -1894,13 +2088,13 @@ var SessionTranscriptStore = class {
|
|
|
1894
2088
|
snapshot = EMPTY_SNAPSHOT;
|
|
1895
2089
|
listeners = /* @__PURE__ */ new Set();
|
|
1896
2090
|
acknowledged = /* @__PURE__ */ new Set();
|
|
1897
|
-
// The inbox projection
|
|
2091
|
+
// The inbox projection: message_received/delivered/requeued
|
|
1898
2092
|
// RECORDS drive it; the snapshot seeds the pending set at connect. Keyed by
|
|
1899
2093
|
// message id so a requeue can restore a message the delivered record
|
|
1900
2094
|
// removed from the pending view.
|
|
1901
2095
|
inbox = /* @__PURE__ */ new Map();
|
|
1902
2096
|
// The resume cursor: the highest feed_seq received via records_append. Only
|
|
1903
|
-
// records advance it
|
|
2097
|
+
// records advance it — never messages/session frames. streamSession
|
|
1904
2098
|
// tracks its own copy; this one seeds a NEW streamSession call (e.g. a
|
|
1905
2099
|
// page-level reconnect after unmount) from already-held state.
|
|
1906
2100
|
cursorSeq = 0;
|
|
@@ -1933,7 +2127,7 @@ var SessionTranscriptStore = class {
|
|
|
1933
2127
|
// The current pending set, in feed order — what queued chips render.
|
|
1934
2128
|
pendingMessages = () => [...this.inbox.values()].filter((m) => m.status === "pending").sort((a, b) => (a.feed_seq ?? 0) - (b.feed_seq ?? 0));
|
|
1935
2129
|
// Fold one lifecycle record into the inbox projection; returns whether the
|
|
1936
|
-
// pending view changed. Unknown fields/types are ignored
|
|
2130
|
+
// pending view changed. Unknown fields/types are ignored.
|
|
1937
2131
|
applyMessageRecord = (record) => {
|
|
1938
2132
|
if (record.kind !== "platform") return false;
|
|
1939
2133
|
const payload = record.payload;
|
|
@@ -1984,7 +2178,7 @@ var SessionTranscriptStore = class {
|
|
|
1984
2178
|
}
|
|
1985
2179
|
};
|
|
1986
2180
|
// Ingest one frame from the stream client. Unknown frame types stamp
|
|
1987
|
-
// liveness and change nothing else
|
|
2181
|
+
// liveness and change nothing else.
|
|
1988
2182
|
ingest = (rawFrame) => {
|
|
1989
2183
|
const prev = this.snapshot;
|
|
1990
2184
|
const next = {
|
|
@@ -2093,6 +2287,7 @@ export {
|
|
|
2093
2287
|
codexChangedPaths,
|
|
2094
2288
|
codexEventToItems,
|
|
2095
2289
|
codexMcpToolName,
|
|
2290
|
+
codexSubagentThreads,
|
|
2096
2291
|
collapseToolRuns,
|
|
2097
2292
|
deliveredUnechoedSends,
|
|
2098
2293
|
deriveEnvironmentState,
|
|
@@ -2113,6 +2308,7 @@ export {
|
|
|
2113
2308
|
gutterFor,
|
|
2114
2309
|
hookPhrase,
|
|
2115
2310
|
humanDuration,
|
|
2311
|
+
isCodexSubagentRecord,
|
|
2116
2312
|
isConnectVisibleRecord,
|
|
2117
2313
|
isConversationOver,
|
|
2118
2314
|
isFoldable,
|
package/dist/stream/index.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d4 as StreamFrame, co as Session } from '../types-CbePyY-S.js';
|
|
2
2
|
|
|
3
|
-
declare const SESSION_STREAM_PROTOCOL_VERSION = 7;
|
|
4
3
|
declare const WS_CLOSE_NORMAL = 1000;
|
|
5
4
|
declare const WS_CLOSE_GOING_AWAY = 1001;
|
|
6
|
-
declare const WS_CLOSE_UNSUPPORTED_PROTOCOL_VERSION = 1002;
|
|
7
|
-
declare const WS_CLOSE_NO_PROTOCOL = 1003;
|
|
8
5
|
declare const WS_CLOSE_AUTH_FAILED = 1008;
|
|
9
6
|
declare const WS_CLOSE_SERVER_ERROR = 1011;
|
|
10
7
|
declare const WS_CLOSE_OVER_CAPACITY = 1013;
|
|
@@ -38,11 +35,11 @@ type OpenSocket = (args: {
|
|
|
38
35
|
query: string;
|
|
39
36
|
}) => StreamSocket | Promise<StreamSocket>;
|
|
40
37
|
declare function streamQuery(afterSeq: number): string;
|
|
41
|
-
type CloseKind = 'normal' | 'auth' | '
|
|
38
|
+
type CloseKind = 'normal' | 'auth' | 'retry';
|
|
42
39
|
declare function classifyCloseCode(code: number): CloseKind;
|
|
43
40
|
declare function nextReconnectDelayMs(attempt: number): number;
|
|
44
41
|
interface ReconnectDecision {
|
|
45
|
-
action: 'reconnect' | '
|
|
42
|
+
action: 'reconnect' | 'give-up' | 'fail-auth';
|
|
46
43
|
delayMs?: number;
|
|
47
44
|
}
|
|
48
45
|
declare function decideReconnect(params: {
|
|
@@ -61,4 +58,4 @@ interface StreamSessionOptions {
|
|
|
61
58
|
}
|
|
62
59
|
declare function streamSession(opts: StreamSessionOptions): Promise<StreamOutcome>;
|
|
63
60
|
|
|
64
|
-
export { type CloseKind, type OpenSocket, type ReconnectDecision,
|
|
61
|
+
export { type CloseKind, type OpenSocket, type ReconnectDecision, StreamAuthError, StreamFrame, type StreamOutcome, type StreamSessionOptions, type StreamSocket, StreamUnavailableError, WS_CLOSE_AUTH_FAILED, WS_CLOSE_GOING_AWAY, WS_CLOSE_NORMAL, WS_CLOSE_OVER_CAPACITY, WS_CLOSE_SERVER_ERROR, classifyCloseCode, decideReconnect, nextReconnectDelayMs, sessionStatusWord, streamQuery, streamSession };
|