@ellipsis-dev/sdk 0.22.0 → 0.27.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/dist/index.d.ts +64 -31
- package/dist/index.js +55 -19
- package/dist/store/index.d.ts +33 -4
- package/dist/store/index.js +238 -65
- package/dist/stream/index.d.ts +1 -1
- package/dist/{types-BKAbWcLN.d.ts → types-ClEF_IA9.d.ts} +1349 -938
- package/package.json +1 -1
- package/schema/frames.schema.json +1334 -1298
- package/schema/openapi.v1.json +1820 -1358
package/dist/store/index.js
CHANGED
|
@@ -62,11 +62,11 @@ function sandboxPhaseText(payload) {
|
|
|
62
62
|
if (tier) parts.push(tier);
|
|
63
63
|
const duration = durationLabel(payload.duration_ms);
|
|
64
64
|
if (duration) parts.push(duration);
|
|
65
|
-
return parts.join("
|
|
65
|
+
return parts.join(", ");
|
|
66
66
|
}
|
|
67
67
|
case "failed": {
|
|
68
68
|
const duration = durationLabel(payload.duration_ms);
|
|
69
|
-
return duration ? `${label} failed
|
|
69
|
+
return duration ? `${label} failed, ${duration}` : `${label} failed`;
|
|
70
70
|
}
|
|
71
71
|
default:
|
|
72
72
|
return label;
|
|
@@ -76,7 +76,7 @@ function lifecycleText(recordType, payload) {
|
|
|
76
76
|
switch (recordType) {
|
|
77
77
|
case "session_scheduled": {
|
|
78
78
|
const config = typeof payload.config_name === "string" ? payload.config_name : null;
|
|
79
|
-
return config ? `Session scheduled
|
|
79
|
+
return config ? `Session scheduled, ${config}` : "Session scheduled";
|
|
80
80
|
}
|
|
81
81
|
case "session_starting": {
|
|
82
82
|
const attempt = typeof payload.attempt === "number" ? payload.attempt : 0;
|
|
@@ -85,14 +85,14 @@ function lifecycleText(recordType, payload) {
|
|
|
85
85
|
return wakeIndex > 0 ? "Waking the session\u2026" : "Session starting\u2026";
|
|
86
86
|
}
|
|
87
87
|
case "session_retrying":
|
|
88
|
-
return typeof payload.reason === "string" && payload.reason ? `Retrying
|
|
88
|
+
return typeof payload.reason === "string" && payload.reason ? `Retrying, ${payload.reason}` : "Retrying after a transient error\u2026";
|
|
89
89
|
case "sandbox_starting":
|
|
90
90
|
return "Starting sandbox\u2026";
|
|
91
91
|
case "sandbox_phase":
|
|
92
92
|
return sandboxPhaseText(payload);
|
|
93
93
|
case "sandbox_output": {
|
|
94
94
|
const last = sandboxOutputLine(payload);
|
|
95
|
-
return last ? `${sandboxOutputStep(payload)}
|
|
95
|
+
return last ? `${sandboxOutputStep(payload)}, ${last}` : null;
|
|
96
96
|
}
|
|
97
97
|
case "sandbox_ready": {
|
|
98
98
|
const repos = Array.isArray(payload.repositories) ? payload.repositories.filter(
|
|
@@ -102,7 +102,7 @@ function lifecycleText(recordType, payload) {
|
|
|
102
102
|
if (repos.length) parts.push(repos.join(", "));
|
|
103
103
|
const tier = cacheTierLabel(payload.cache_tier);
|
|
104
104
|
if (tier) parts.push(tier);
|
|
105
|
-
return parts.join("
|
|
105
|
+
return parts.join(", ");
|
|
106
106
|
}
|
|
107
107
|
case "session_resumed":
|
|
108
108
|
return "Resumed the conversation";
|
|
@@ -112,7 +112,7 @@ function lifecycleText(recordType, payload) {
|
|
|
112
112
|
return "Conversation closed";
|
|
113
113
|
case "session_cancelled": {
|
|
114
114
|
const reason = typeof payload.reason === "string" ? payload.reason : null;
|
|
115
|
-
return reason ? `Session cancelled
|
|
115
|
+
return reason ? `Session cancelled, ${reason}` : "Session cancelled";
|
|
116
116
|
}
|
|
117
117
|
default:
|
|
118
118
|
return null;
|
|
@@ -182,7 +182,7 @@ function eventToItems(event, keyBase, options = {}) {
|
|
|
182
182
|
const label = event.is_error ? "turn ended with an error" : "turn complete";
|
|
183
183
|
push({
|
|
184
184
|
kind: "summary",
|
|
185
|
-
text: bits.length ? `${label}
|
|
185
|
+
text: bits.length ? `${label}, ${bits.join(", ")}` : label,
|
|
186
186
|
spaceBefore: true,
|
|
187
187
|
isError: event.is_error
|
|
188
188
|
});
|
|
@@ -196,7 +196,7 @@ function eventToItems(event, keyBase, options = {}) {
|
|
|
196
196
|
if (typeof data.cwd === "string") bits.push(data.cwd);
|
|
197
197
|
push({
|
|
198
198
|
kind: "system",
|
|
199
|
-
text: bits.length ? `session started
|
|
199
|
+
text: bits.length ? `session started, ${bits.join(", ")}` : "session started",
|
|
200
200
|
spaceBefore: true
|
|
201
201
|
});
|
|
202
202
|
return items;
|
|
@@ -386,42 +386,55 @@ function pendingToolCalls(items) {
|
|
|
386
386
|
}
|
|
387
387
|
return pending;
|
|
388
388
|
}
|
|
389
|
-
function
|
|
389
|
+
function isFoldable(item) {
|
|
390
|
+
return item.kind === "tool" || item.kind === "tool_result" || item.kind === "thinking";
|
|
391
|
+
}
|
|
392
|
+
function foldLabel(group, settled) {
|
|
393
|
+
const work = group.filter((i) => i.kind !== "thinking");
|
|
394
|
+
if (work.length === 0) return settled ? "Thinking\u2026" : "Thinking";
|
|
395
|
+
const names = [
|
|
396
|
+
...new Set(work.filter((i) => i.kind === "tool").map((i) => i.text))
|
|
397
|
+
];
|
|
398
|
+
const n = work.filter((i) => i.kind === "tool").length || work.length;
|
|
399
|
+
const plural = n === 1 ? "" : "s";
|
|
400
|
+
if (names.length === 1 && names[0] === "Bash")
|
|
401
|
+
return `Ran ${n} shell command${plural}`;
|
|
402
|
+
if (names.length === 1 && names[0] === "Read")
|
|
403
|
+
return `Read ${n} file${plural}`;
|
|
404
|
+
if (names.length === 1)
|
|
405
|
+
return n === 1 ? `Ran ${names[0]}` : `Ran ${names[0]} ${n} times`;
|
|
406
|
+
if (names.length === 0) return `Ran ${n} tool call${plural}`;
|
|
407
|
+
const shown = names.slice(0, 3).join(", ") + (names.length > 3 ? ", \u2026" : "");
|
|
408
|
+
return `Ran ${n} tool call${plural} (${shown})`;
|
|
409
|
+
}
|
|
410
|
+
function foldRun(group, loading) {
|
|
411
|
+
return {
|
|
412
|
+
key: `grp:${group[0].key}`,
|
|
413
|
+
kind: "notice",
|
|
414
|
+
text: foldLabel(group, !loading),
|
|
415
|
+
spaceBefore: true,
|
|
416
|
+
...loading ? { loading } : {}
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function collapseToolRuns(items, { working = false } = {}) {
|
|
390
420
|
const out = [];
|
|
391
421
|
let group = [];
|
|
392
|
-
const flush = () => {
|
|
422
|
+
const flush = (trailing) => {
|
|
393
423
|
if (group.length === 0) return;
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const plural = n === 1 ? "" : "s";
|
|
399
|
-
let label;
|
|
400
|
-
if (names.length === 1 && names[0] === "Bash")
|
|
401
|
-
label = `Ran ${n} shell command${plural}`;
|
|
402
|
-
else if (names.length === 1 && names[0] === "Read")
|
|
403
|
-
label = `Read ${n} file${plural}`;
|
|
404
|
-
else if (names.length === 0) label = `Ran ${n} tool call${plural}`;
|
|
405
|
-
else {
|
|
406
|
-
const shown = names.slice(0, 3).join(", ") + (names.length > 3 ? ", \u2026" : "");
|
|
407
|
-
label = `Ran ${n} tool call${plural} (${shown})`;
|
|
408
|
-
}
|
|
409
|
-
out.push({
|
|
410
|
-
key: `grp:${group[0].key}`,
|
|
411
|
-
kind: "notice",
|
|
412
|
-
text: label,
|
|
413
|
-
spaceBefore: true
|
|
414
|
-
});
|
|
424
|
+
const pending = pendingToolCalls(group).length > 0;
|
|
425
|
+
const thinkingOnly = group.every((i) => i.kind === "thinking");
|
|
426
|
+
const loading = pending || trailing && working && thinkingOnly;
|
|
427
|
+
out.push(foldRun(group, loading));
|
|
415
428
|
group = [];
|
|
416
429
|
};
|
|
417
430
|
for (const item of items) {
|
|
418
|
-
if (item
|
|
431
|
+
if (isFoldable(item)) group.push(item);
|
|
419
432
|
else {
|
|
420
|
-
flush();
|
|
433
|
+
flush(false);
|
|
421
434
|
out.push(item);
|
|
422
435
|
}
|
|
423
436
|
}
|
|
424
|
-
flush();
|
|
437
|
+
flush(true);
|
|
425
438
|
return out;
|
|
426
439
|
}
|
|
427
440
|
function clampLines(text, maxLines) {
|
|
@@ -471,6 +484,8 @@ var SANDBOX_RECORD_TYPES = /* @__PURE__ */ new Set([
|
|
|
471
484
|
function groupRecordsToChatTurns(records) {
|
|
472
485
|
const turns = [];
|
|
473
486
|
const toolNodeByUseId = /* @__PURE__ */ new Map();
|
|
487
|
+
const userTurnByMessageId = /* @__PURE__ */ new Map();
|
|
488
|
+
const messageIdByTurnId = /* @__PURE__ */ new Map();
|
|
474
489
|
let seq = 0;
|
|
475
490
|
const nextKey = (base) => `${base}:${seq++}`;
|
|
476
491
|
let openIdx = -1;
|
|
@@ -497,6 +512,38 @@ function groupRecordsToChatTurns(records) {
|
|
|
497
512
|
};
|
|
498
513
|
for (const record of records) {
|
|
499
514
|
if (record.record_format === "ellipsis_lifecycle@1") {
|
|
515
|
+
const messageId = typeof record.payload.message_id === "string" ? record.payload.message_id : null;
|
|
516
|
+
if (record.record_type === "message_received" && messageId) {
|
|
517
|
+
const body = typeof record.payload.body === "string" ? record.payload.body : "";
|
|
518
|
+
if (!body.trim() || userTurnByMessageId.has(messageId)) continue;
|
|
519
|
+
const turn2 = {
|
|
520
|
+
resumed: false,
|
|
521
|
+
isError: false,
|
|
522
|
+
key: `msg:${messageId}`,
|
|
523
|
+
role: "user",
|
|
524
|
+
nodes: [{ key: `msg:${messageId}`, kind: "user", text: body.trim() }],
|
|
525
|
+
startedAt: record.created_at,
|
|
526
|
+
completedAt: record.created_at,
|
|
527
|
+
durationMs: null,
|
|
528
|
+
costUsd: null,
|
|
529
|
+
tokens: null
|
|
530
|
+
};
|
|
531
|
+
userTurnByMessageId.set(messageId, turn2);
|
|
532
|
+
turns.push(turn2);
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
if (record.record_type === "message_delivered" && messageId) {
|
|
536
|
+
if (typeof record.payload.turn_id === "string")
|
|
537
|
+
messageIdByTurnId.set(record.payload.turn_id, messageId);
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
if (record.record_type === "turn_failed") {
|
|
541
|
+
const turnId = typeof record.payload.turn_id === "string" ? record.payload.turn_id : null;
|
|
542
|
+
const owner = turnId ? messageIdByTurnId.get(turnId) : void 0;
|
|
543
|
+
const userTurn = owner ? userTurnByMessageId.get(owner) : void 0;
|
|
544
|
+
if (userTurn) userTurn.isError = true;
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
500
547
|
const text = lifecycleText(record.record_type, record.payload);
|
|
501
548
|
if (!text) continue;
|
|
502
549
|
const isSandbox = SANDBOX_RECORD_TYPES.has(record.record_type);
|
|
@@ -598,6 +645,8 @@ function groupRecordsToChatTurns(records) {
|
|
|
598
645
|
if (typeof content === "string") {
|
|
599
646
|
if (content.trim()) {
|
|
600
647
|
openIdx = -1;
|
|
648
|
+
if (record.session_message_id != null && userTurnByMessageId.has(record.session_message_id))
|
|
649
|
+
continue;
|
|
601
650
|
turns.push({
|
|
602
651
|
resumed: false,
|
|
603
652
|
isError: false,
|
|
@@ -801,6 +850,7 @@ function humanDuration(seconds) {
|
|
|
801
850
|
if (s > 0 || bits.length === 0) bits.push(`${s}s`);
|
|
802
851
|
return bits.join(" ");
|
|
803
852
|
}
|
|
853
|
+
var SESSION_WAKING = "Session waking";
|
|
804
854
|
function sessionLogText(recordType, payload) {
|
|
805
855
|
const p = payload;
|
|
806
856
|
switch (recordType) {
|
|
@@ -810,14 +860,14 @@ function sessionLogText(recordType, payload) {
|
|
|
810
860
|
const wake = typeof p.wake_index === "number" ? p.wake_index : 0;
|
|
811
861
|
const attempt = typeof p.attempt === "number" ? p.attempt : 0;
|
|
812
862
|
if (attempt > 0) return "Restarting the sandbox after a transient error\u2026";
|
|
813
|
-
return wake > 0 ?
|
|
863
|
+
return wake > 0 ? SESSION_WAKING : null;
|
|
814
864
|
}
|
|
815
865
|
case "session_retrying":
|
|
816
|
-
return typeof p.reason === "string" && p.reason ? `Retrying
|
|
866
|
+
return typeof p.reason === "string" && p.reason ? `Retrying, ${p.reason}` : "Retrying after a transient error\u2026";
|
|
817
867
|
case "session_resumed":
|
|
818
868
|
return "Session awake";
|
|
819
869
|
case "session_cancelled": {
|
|
820
|
-
const reason = typeof p.reason === "string" && p.reason ?
|
|
870
|
+
const reason = typeof p.reason === "string" && p.reason ? `, ${p.reason}` : "";
|
|
821
871
|
return `Session cancelled${reason}`;
|
|
822
872
|
}
|
|
823
873
|
default:
|
|
@@ -879,6 +929,7 @@ function deliveredUnechoedSends(records) {
|
|
|
879
929
|
}
|
|
880
930
|
return out;
|
|
881
931
|
}
|
|
932
|
+
var STARTING_SANDBOX = "Starting sandbox\u2026";
|
|
882
933
|
function msLabel(ms) {
|
|
883
934
|
if (typeof ms !== "number" || !isFinite(ms) || ms < 0) return null;
|
|
884
935
|
return humanDuration(ms / 1e3);
|
|
@@ -920,7 +971,7 @@ function stepLabel(phase, step) {
|
|
|
920
971
|
}
|
|
921
972
|
function deriveSandboxState(records, minFeedSeq) {
|
|
922
973
|
let seen = false;
|
|
923
|
-
let headline =
|
|
974
|
+
let headline = STARTING_SANDBOX;
|
|
924
975
|
let done = false;
|
|
925
976
|
let sandboxDone = false;
|
|
926
977
|
let readySeconds = null;
|
|
@@ -955,7 +1006,7 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
955
1006
|
case "session_retrying": {
|
|
956
1007
|
seen = true;
|
|
957
1008
|
const text = lifecycleText(record.record_type, p);
|
|
958
|
-
headline = !text || text === "Session starting\u2026" ?
|
|
1009
|
+
headline = !text || text === "Session starting\u2026" ? STARTING_SANDBOX : text;
|
|
959
1010
|
done = false;
|
|
960
1011
|
readySeconds = null;
|
|
961
1012
|
reset();
|
|
@@ -970,7 +1021,6 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
970
1021
|
case "sandbox_starting": {
|
|
971
1022
|
seen = true;
|
|
972
1023
|
reset();
|
|
973
|
-
push(record, "step", "Starting sandbox\u2026");
|
|
974
1024
|
break;
|
|
975
1025
|
}
|
|
976
1026
|
case "sandbox_phase": {
|
|
@@ -989,7 +1039,7 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
989
1039
|
base,
|
|
990
1040
|
...tier ? [tier] : [],
|
|
991
1041
|
...dur ? [dur] : []
|
|
992
|
-
].join("
|
|
1042
|
+
].join(", ");
|
|
993
1043
|
const line = open.get(key);
|
|
994
1044
|
if (line) {
|
|
995
1045
|
line.kind = failed ? "failed" : "done";
|
|
@@ -1025,7 +1075,7 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
1025
1075
|
"Sandbox ready",
|
|
1026
1076
|
...tier ? [tier] : [],
|
|
1027
1077
|
...totalSeconds > 0 ? [humanDuration(totalSeconds)] : []
|
|
1028
|
-
].join("
|
|
1078
|
+
].join(", ")
|
|
1029
1079
|
);
|
|
1030
1080
|
sandboxDone = true;
|
|
1031
1081
|
readySeconds = totalSeconds > 0 ? totalSeconds : null;
|
|
@@ -1036,6 +1086,8 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
1036
1086
|
break;
|
|
1037
1087
|
}
|
|
1038
1088
|
}
|
|
1089
|
+
const openLines = [...open.values()];
|
|
1090
|
+
if (openLines.length) openLines[openLines.length - 1].loading = true;
|
|
1039
1091
|
const full = configName ? [
|
|
1040
1092
|
{
|
|
1041
1093
|
key: "config",
|
|
@@ -1054,6 +1106,14 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
1054
1106
|
log: full
|
|
1055
1107
|
} : null;
|
|
1056
1108
|
}
|
|
1109
|
+
function startupSettled(sandbox, status) {
|
|
1110
|
+
return (sandbox?.done ?? false) && statusActivityText(status) == null;
|
|
1111
|
+
}
|
|
1112
|
+
function startupHeadline(sandbox, status) {
|
|
1113
|
+
const activity = statusActivityText(status);
|
|
1114
|
+
const text = !sandbox || sandbox.done ? activity ?? STARTING_SANDBOX : sandbox.headline;
|
|
1115
|
+
return `${text.replace(/…$/, "")}\u2026`;
|
|
1116
|
+
}
|
|
1057
1117
|
function sandboxSummary(sandbox) {
|
|
1058
1118
|
const seconds = sandbox?.readySeconds ?? null;
|
|
1059
1119
|
return seconds ? `Sandbox ready in ${humanDuration(seconds)}` : "Sandbox started";
|
|
@@ -1081,20 +1141,33 @@ var SANDBOX_RECORD_TYPES2 = /* @__PURE__ */ new Set([
|
|
|
1081
1141
|
function chatTurnsToItems(turns) {
|
|
1082
1142
|
const items = [];
|
|
1083
1143
|
let wakeAt = -1;
|
|
1144
|
+
const settleWake = () => {
|
|
1145
|
+
if (wakeAt < 0) return;
|
|
1146
|
+
const { loading: _, ...settled } = items[wakeAt];
|
|
1147
|
+
items[wakeAt] = { ...settled, text: "Session awake" };
|
|
1148
|
+
wakeAt = -1;
|
|
1149
|
+
};
|
|
1084
1150
|
for (const turn of turns) {
|
|
1151
|
+
if (turn.role === "assistant") settleWake();
|
|
1085
1152
|
if (turn.role === "lifecycle") {
|
|
1086
1153
|
for (const node of turn.nodes) {
|
|
1087
1154
|
if (node.kind !== "lifecycle") continue;
|
|
1088
1155
|
if (SANDBOX_RECORD_TYPES2.has(node.recordType)) continue;
|
|
1089
|
-
if (node.recordType === "session_resumed"
|
|
1090
|
-
|
|
1091
|
-
wakeAt = -1;
|
|
1156
|
+
if (node.recordType === "session_resumed") {
|
|
1157
|
+
settleWake();
|
|
1092
1158
|
continue;
|
|
1093
1159
|
}
|
|
1094
1160
|
const text = sessionLogText(node.recordType, node.payload ?? {});
|
|
1095
1161
|
if (!text) continue;
|
|
1096
|
-
|
|
1097
|
-
|
|
1162
|
+
const waking = text === SESSION_WAKING;
|
|
1163
|
+
items.push({
|
|
1164
|
+
key: node.key,
|
|
1165
|
+
kind: "notice",
|
|
1166
|
+
text,
|
|
1167
|
+
spaceBefore: true,
|
|
1168
|
+
...waking ? { loading: true } : {}
|
|
1169
|
+
});
|
|
1170
|
+
wakeAt = waking ? items.length - 1 : -1;
|
|
1098
1171
|
}
|
|
1099
1172
|
continue;
|
|
1100
1173
|
}
|
|
@@ -1105,7 +1178,8 @@ function chatTurnsToItems(turns) {
|
|
|
1105
1178
|
key: node.key,
|
|
1106
1179
|
kind: "user",
|
|
1107
1180
|
text: node.text,
|
|
1108
|
-
spaceBefore: true
|
|
1181
|
+
spaceBefore: true,
|
|
1182
|
+
...turn.isError ? { isError: true } : {}
|
|
1109
1183
|
});
|
|
1110
1184
|
}
|
|
1111
1185
|
}
|
|
@@ -1170,21 +1244,8 @@ function isToolFold(item) {
|
|
|
1170
1244
|
function isToolActivity(item) {
|
|
1171
1245
|
return item.kind === "tool" || item.kind === "tool_result" || isToolFold(item);
|
|
1172
1246
|
}
|
|
1173
|
-
function isAgentSpeech(item) {
|
|
1174
|
-
return item.kind === "assistant" || item.kind === "thinking";
|
|
1175
|
-
}
|
|
1176
1247
|
function layOutItems(items) {
|
|
1177
|
-
|
|
1178
|
-
let nestUnder = false;
|
|
1179
|
-
for (const item of items) {
|
|
1180
|
-
if (!isToolActivity(item)) {
|
|
1181
|
-
out.push({ item, nested: false, attach: false });
|
|
1182
|
-
nestUnder = isAgentSpeech(item);
|
|
1183
|
-
continue;
|
|
1184
|
-
}
|
|
1185
|
-
out.push({ item, nested: nestUnder, attach: nestUnder });
|
|
1186
|
-
}
|
|
1187
|
-
return out;
|
|
1248
|
+
return items.map((item) => ({ item, nested: false, attach: false }));
|
|
1188
1249
|
}
|
|
1189
1250
|
function foldGutter(nested) {
|
|
1190
1251
|
return nested ? BRANCH_GLYPH : "\u25CF";
|
|
@@ -1205,13 +1266,118 @@ function toolRunMembers(items) {
|
|
|
1205
1266
|
group = [];
|
|
1206
1267
|
};
|
|
1207
1268
|
for (const item of items) {
|
|
1208
|
-
if (item
|
|
1269
|
+
if (isFoldable(item)) group.push(item);
|
|
1209
1270
|
else flush();
|
|
1210
1271
|
}
|
|
1211
1272
|
flush();
|
|
1212
1273
|
return out;
|
|
1213
1274
|
}
|
|
1214
1275
|
|
|
1276
|
+
// src/store/ledger.ts
|
|
1277
|
+
function splitLedger(turns) {
|
|
1278
|
+
const preamble = [];
|
|
1279
|
+
const entries = [];
|
|
1280
|
+
for (const turn of turns) {
|
|
1281
|
+
if (turn.role === "user") {
|
|
1282
|
+
const node = turn.nodes.find((n) => n.kind === "user");
|
|
1283
|
+
entries.push({
|
|
1284
|
+
key: turn.key,
|
|
1285
|
+
prompt: node?.text ?? "",
|
|
1286
|
+
cancelled: turn.isError,
|
|
1287
|
+
turns: []
|
|
1288
|
+
});
|
|
1289
|
+
continue;
|
|
1290
|
+
}
|
|
1291
|
+
const last = entries[entries.length - 1];
|
|
1292
|
+
if (last) last.turns.push(turn);
|
|
1293
|
+
else preamble.push(turn);
|
|
1294
|
+
}
|
|
1295
|
+
return { preamble, entries };
|
|
1296
|
+
}
|
|
1297
|
+
function entrySeconds(entry, now) {
|
|
1298
|
+
let ms = 0;
|
|
1299
|
+
for (const turn of entry.turns) {
|
|
1300
|
+
if (turn.role !== "assistant" || turn.startedAt == null) continue;
|
|
1301
|
+
if (turn.durationMs != null) ms += turn.durationMs;
|
|
1302
|
+
else {
|
|
1303
|
+
const end = turn.completedAt != null ? Date.parse(turn.completedAt) : now;
|
|
1304
|
+
ms += Math.max(0, end - Date.parse(turn.startedAt));
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
return ms / 1e3;
|
|
1308
|
+
}
|
|
1309
|
+
function foldToolTurn(raw, live, members) {
|
|
1310
|
+
const items = [];
|
|
1311
|
+
let run = [];
|
|
1312
|
+
const flush = () => {
|
|
1313
|
+
if (run.length === 0) return;
|
|
1314
|
+
const fold = foldRun(run, live && pendingToolCalls(run).length > 0);
|
|
1315
|
+
members.set(fold.key, run);
|
|
1316
|
+
items.push(fold);
|
|
1317
|
+
run = [];
|
|
1318
|
+
};
|
|
1319
|
+
for (const item of raw) {
|
|
1320
|
+
if (item.kind === "tool" || item.kind === "tool_result") run.push(item);
|
|
1321
|
+
else {
|
|
1322
|
+
flush();
|
|
1323
|
+
items.push(item);
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
flush();
|
|
1327
|
+
return items;
|
|
1328
|
+
}
|
|
1329
|
+
function entryBody(entry, {
|
|
1330
|
+
live,
|
|
1331
|
+
now,
|
|
1332
|
+
liveText = ""
|
|
1333
|
+
}) {
|
|
1334
|
+
const raw = chatTurnsToItems(entry.turns);
|
|
1335
|
+
const members = /* @__PURE__ */ new Map();
|
|
1336
|
+
const toolRan = raw.some((i) => i.kind === "tool");
|
|
1337
|
+
let items;
|
|
1338
|
+
if (toolRan) {
|
|
1339
|
+
items = foldToolTurn(raw, live, members);
|
|
1340
|
+
} else {
|
|
1341
|
+
const thoughts = raw.filter((i) => i.kind === "thinking");
|
|
1342
|
+
items = raw.filter((i) => i.kind !== "thinking");
|
|
1343
|
+
const key = `grp:thought:${entry.key}`;
|
|
1344
|
+
if (thoughts.length) members.set(key, thoughts);
|
|
1345
|
+
if (live && liveText === "") {
|
|
1346
|
+
items.push({ key, kind: "notice", text: "Thinking", spaceBefore: true });
|
|
1347
|
+
} else if (!live && thoughts.length) {
|
|
1348
|
+
items.push({
|
|
1349
|
+
key,
|
|
1350
|
+
kind: "notice",
|
|
1351
|
+
text: `Thought for ${humanDuration(entrySeconds(entry, now))}`,
|
|
1352
|
+
spaceBefore: true
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
if (live && liveText !== "") {
|
|
1357
|
+
items.push({
|
|
1358
|
+
key: `live:${entry.key}`,
|
|
1359
|
+
kind: "assistant",
|
|
1360
|
+
text: liveText,
|
|
1361
|
+
spaceBefore: true
|
|
1362
|
+
});
|
|
1363
|
+
}
|
|
1364
|
+
const chosen = live ? liveRow(items, members) : -1;
|
|
1365
|
+
items = items.map((item, i) => {
|
|
1366
|
+
const { loading: _, ...rest } = item;
|
|
1367
|
+
return i === chosen ? { ...rest, loading: true } : rest;
|
|
1368
|
+
});
|
|
1369
|
+
return { items, members };
|
|
1370
|
+
}
|
|
1371
|
+
function liveRow(items, members) {
|
|
1372
|
+
if (items.length === 0) return -1;
|
|
1373
|
+
const running = items.findIndex((item) => {
|
|
1374
|
+
const run = members.get(item.key);
|
|
1375
|
+
return run != null && pendingToolCalls(run).length > 0;
|
|
1376
|
+
});
|
|
1377
|
+
if (running >= 0) return running;
|
|
1378
|
+
return items.length - 1;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1215
1381
|
// src/store/index.ts
|
|
1216
1382
|
var TERMINAL_SESSION_STATUSES = /* @__PURE__ */ new Set([
|
|
1217
1383
|
"completed",
|
|
@@ -1418,6 +1584,7 @@ var SessionTranscriptStore = class {
|
|
|
1418
1584
|
export {
|
|
1419
1585
|
BRANCH_GLYPH,
|
|
1420
1586
|
LIVE_GLYPH,
|
|
1587
|
+
SESSION_WAKING,
|
|
1421
1588
|
SessionTranscriptStore,
|
|
1422
1589
|
USER_BAR,
|
|
1423
1590
|
awaitingAgentPhase,
|
|
@@ -1431,17 +1598,20 @@ export {
|
|
|
1431
1598
|
deliveredUnechoedSends,
|
|
1432
1599
|
deriveSandboxState,
|
|
1433
1600
|
emptySessionTranscriptSnapshot,
|
|
1601
|
+
entryBody,
|
|
1602
|
+
entrySeconds,
|
|
1434
1603
|
eventToItems,
|
|
1435
1604
|
foldCosts,
|
|
1436
1605
|
foldGutter,
|
|
1606
|
+
foldRun,
|
|
1437
1607
|
formatDuration,
|
|
1438
1608
|
groupRecordsToChatTurns,
|
|
1439
1609
|
gutterFor,
|
|
1440
1610
|
hookPhrase,
|
|
1441
1611
|
humanDuration,
|
|
1442
|
-
isAgentSpeech,
|
|
1443
1612
|
isConnectVisibleRecord,
|
|
1444
1613
|
isConversationOver,
|
|
1614
|
+
isFoldable,
|
|
1445
1615
|
isToolActivity,
|
|
1446
1616
|
isToolFold,
|
|
1447
1617
|
lastLines,
|
|
@@ -1459,6 +1629,9 @@ export {
|
|
|
1459
1629
|
sandboxSummary,
|
|
1460
1630
|
seedTranscriptStore,
|
|
1461
1631
|
sessionLogText,
|
|
1632
|
+
splitLedger,
|
|
1633
|
+
startupHeadline,
|
|
1634
|
+
startupSettled,
|
|
1462
1635
|
statusActivityText,
|
|
1463
1636
|
summarizeToolInput,
|
|
1464
1637
|
tailLines,
|
package/dist/stream/index.d.ts
CHANGED