@astralform/js 0.2.1 → 0.2.3
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.cjs +558 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +260 -70
- package/dist/index.d.ts +260 -70
- package/dist/index.js +556 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -332,6 +332,8 @@ var BlockBuilder = class {
|
|
|
332
332
|
this.activeTextId = null;
|
|
333
333
|
this.activeThinkingId = null;
|
|
334
334
|
this.thinkingStartMs = null;
|
|
335
|
+
this.activeEditorId = null;
|
|
336
|
+
this.activeTodoId = null;
|
|
335
337
|
}
|
|
336
338
|
// ── Registration ──────────────────────────────────────────────
|
|
337
339
|
on(eventType, handler) {
|
|
@@ -358,6 +360,8 @@ var BlockBuilder = class {
|
|
|
358
360
|
this.activeTextId = null;
|
|
359
361
|
this.activeThinkingId = null;
|
|
360
362
|
this.thinkingStartMs = null;
|
|
363
|
+
this.activeEditorId = null;
|
|
364
|
+
this.activeTodoId = null;
|
|
361
365
|
}
|
|
362
366
|
setOnChange(fn) {
|
|
363
367
|
this._onChange = fn;
|
|
@@ -583,7 +587,6 @@ var ChatSession = class {
|
|
|
583
587
|
this.thinkingContent = "";
|
|
584
588
|
this.isThinking = false;
|
|
585
589
|
this.activeSubagents = /* @__PURE__ */ new Map();
|
|
586
|
-
this.sources = [];
|
|
587
590
|
this.capsuleOutputs = [];
|
|
588
591
|
this.todos = [];
|
|
589
592
|
this.activeTools = /* @__PURE__ */ new Map();
|
|
@@ -687,7 +690,6 @@ var ChatSession = class {
|
|
|
687
690
|
this.thinkingContent = "";
|
|
688
691
|
this.isThinking = false;
|
|
689
692
|
this.activeSubagents.clear();
|
|
690
|
-
this.sources = [];
|
|
691
693
|
this.capsuleOutputs = [];
|
|
692
694
|
this.todos = [];
|
|
693
695
|
this.activeTools.clear();
|
|
@@ -699,10 +701,12 @@ var ChatSession = class {
|
|
|
699
701
|
try {
|
|
700
702
|
await this.consumeJobStream(request);
|
|
701
703
|
} catch (err) {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
704
|
+
if (!(err instanceof DOMException && err.name === "AbortError")) {
|
|
705
|
+
this.emit({
|
|
706
|
+
type: "error",
|
|
707
|
+
error: err instanceof Error ? err : new ConnectionError(String(err))
|
|
708
|
+
});
|
|
709
|
+
}
|
|
706
710
|
} finally {
|
|
707
711
|
this.isStreaming = false;
|
|
708
712
|
this.executingTool = null;
|
|
@@ -855,11 +859,24 @@ var ChatSession = class {
|
|
|
855
859
|
applyEvent(event) {
|
|
856
860
|
switch (event.type) {
|
|
857
861
|
case "user_message":
|
|
858
|
-
this.emit({
|
|
862
|
+
this.emit({
|
|
863
|
+
type: "user_message",
|
|
864
|
+
content: event.content,
|
|
865
|
+
createdAt: event.created_at
|
|
866
|
+
});
|
|
859
867
|
break;
|
|
860
|
-
case "title_generated":
|
|
868
|
+
case "title_generated": {
|
|
869
|
+
if (this.conversationId && event.title) {
|
|
870
|
+
const conv = this.conversations.find(
|
|
871
|
+
(c) => c.id === this.conversationId
|
|
872
|
+
);
|
|
873
|
+
if (conv) {
|
|
874
|
+
conv.title = event.title;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
861
877
|
this.emit({ type: "title_generated", title: event.title });
|
|
862
878
|
break;
|
|
879
|
+
}
|
|
863
880
|
case "message_start":
|
|
864
881
|
if (event.conversation_id && !this.conversationId) {
|
|
865
882
|
this.conversationId = event.conversation_id;
|
|
@@ -882,6 +899,23 @@ var ChatSession = class {
|
|
|
882
899
|
this.isThinking = false;
|
|
883
900
|
this.emit({ type: "thinking_complete" });
|
|
884
901
|
break;
|
|
902
|
+
case "tool_executing":
|
|
903
|
+
this.emit({
|
|
904
|
+
type: "tool_executing",
|
|
905
|
+
name: event.tool,
|
|
906
|
+
call_id: event.call_id
|
|
907
|
+
});
|
|
908
|
+
break;
|
|
909
|
+
case "tool_progress":
|
|
910
|
+
this.emit({
|
|
911
|
+
type: "tool_progress",
|
|
912
|
+
callId: event.call_id,
|
|
913
|
+
tool: event.tool,
|
|
914
|
+
index: event.index,
|
|
915
|
+
total: event.total,
|
|
916
|
+
item: event.item
|
|
917
|
+
});
|
|
918
|
+
break;
|
|
885
919
|
case "message_stop":
|
|
886
920
|
this.emit({
|
|
887
921
|
type: "complete",
|
|
@@ -991,10 +1025,6 @@ var ChatSession = class {
|
|
|
991
1025
|
result: event.result
|
|
992
1026
|
});
|
|
993
1027
|
break;
|
|
994
|
-
case "sources":
|
|
995
|
-
this.sources.push(...event.sources);
|
|
996
|
-
this.emit({ type: "sources", sources: event.sources });
|
|
997
|
-
break;
|
|
998
1028
|
case "capsule_output": {
|
|
999
1029
|
const capsule = {
|
|
1000
1030
|
toolName: event.tool_name,
|
|
@@ -1020,6 +1050,40 @@ var ChatSession = class {
|
|
|
1020
1050
|
this.todos = event.todos;
|
|
1021
1051
|
this.emit({ type: "todo_update", todos: event.todos });
|
|
1022
1052
|
break;
|
|
1053
|
+
case "context_update":
|
|
1054
|
+
this.emit({
|
|
1055
|
+
type: "context_update",
|
|
1056
|
+
context: event.context,
|
|
1057
|
+
phase: event.phase,
|
|
1058
|
+
updatedAt: event.updated_at
|
|
1059
|
+
});
|
|
1060
|
+
break;
|
|
1061
|
+
case "desktop_stream":
|
|
1062
|
+
this.emit({
|
|
1063
|
+
type: "desktop_stream",
|
|
1064
|
+
url: event.url,
|
|
1065
|
+
authKey: event.auth_key,
|
|
1066
|
+
sandboxId: event.sandbox_id
|
|
1067
|
+
});
|
|
1068
|
+
break;
|
|
1069
|
+
case "attachment_staged":
|
|
1070
|
+
this.emit({
|
|
1071
|
+
type: "attachment_staged",
|
|
1072
|
+
files: (event.files || []).map((f) => ({
|
|
1073
|
+
name: f.name,
|
|
1074
|
+
path: f.path,
|
|
1075
|
+
mediaType: f.media_type,
|
|
1076
|
+
sizeBytes: f.size_bytes
|
|
1077
|
+
}))
|
|
1078
|
+
});
|
|
1079
|
+
break;
|
|
1080
|
+
case "workspace_ready":
|
|
1081
|
+
this.emit({
|
|
1082
|
+
type: "workspace_ready",
|
|
1083
|
+
conversationId: event.conversation_id,
|
|
1084
|
+
sandboxId: event.sandbox_id
|
|
1085
|
+
});
|
|
1086
|
+
break;
|
|
1023
1087
|
case "asset_created":
|
|
1024
1088
|
this.emit({
|
|
1025
1089
|
type: "asset_created",
|
|
@@ -1030,27 +1094,6 @@ var ChatSession = class {
|
|
|
1030
1094
|
sizeBytes: event.size_bytes
|
|
1031
1095
|
});
|
|
1032
1096
|
break;
|
|
1033
|
-
case "timeline_entry":
|
|
1034
|
-
this.emit({
|
|
1035
|
-
type: "timeline_entry",
|
|
1036
|
-
id: event.id,
|
|
1037
|
-
status: event.status,
|
|
1038
|
-
kind: event.kind,
|
|
1039
|
-
agent_name: event.agent_name,
|
|
1040
|
-
tool_name: event.tool_name,
|
|
1041
|
-
display_name: event.display_name,
|
|
1042
|
-
tool_category: event.tool_category,
|
|
1043
|
-
viewer: event.viewer,
|
|
1044
|
-
call_id: event.call_id,
|
|
1045
|
-
detail: event.detail,
|
|
1046
|
-
started_at: event.started_at,
|
|
1047
|
-
duration_ms: event.duration_ms,
|
|
1048
|
-
output_summary: event.output_summary,
|
|
1049
|
-
sources: event.sources,
|
|
1050
|
-
parent_id: event.parent_id,
|
|
1051
|
-
structured_output: event.structured_output
|
|
1052
|
-
});
|
|
1053
|
-
break;
|
|
1054
1097
|
case "editor_content_start":
|
|
1055
1098
|
this.emit({
|
|
1056
1099
|
type: "editor_content_start",
|
|
@@ -1172,19 +1215,26 @@ var ChatSession = class {
|
|
|
1172
1215
|
this.abortController = null;
|
|
1173
1216
|
}
|
|
1174
1217
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
});
|
|
1179
|
-
this.currentJobId = null;
|
|
1180
|
-
}
|
|
1218
|
+
/** Detach from the SSE stream without cancelling the job.
|
|
1219
|
+
* The backend job keeps running — caller can reconnect later. */
|
|
1220
|
+
detach() {
|
|
1181
1221
|
this.abortController?.abort();
|
|
1182
1222
|
this.abortController = null;
|
|
1183
1223
|
this.isStreaming = false;
|
|
1184
1224
|
this.streamingContent = "";
|
|
1185
1225
|
this.executingTool = null;
|
|
1226
|
+
this.blockBuilder.reset();
|
|
1186
1227
|
this.emit({ type: "disconnected" });
|
|
1187
1228
|
}
|
|
1229
|
+
/** Stop the job and disconnect (explicit user action). */
|
|
1230
|
+
disconnect() {
|
|
1231
|
+
if (this.currentJobId) {
|
|
1232
|
+
this.client.cancelJob(this.currentJobId).catch(() => {
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
this.detach();
|
|
1236
|
+
this.currentJobId = null;
|
|
1237
|
+
}
|
|
1188
1238
|
async createNewConversation() {
|
|
1189
1239
|
const id = generateId();
|
|
1190
1240
|
const conversation = await this.storage.createConversation(
|
|
@@ -1252,10 +1302,31 @@ function finalizeThinking(builder) {
|
|
|
1252
1302
|
builder.thinkingStartMs = null;
|
|
1253
1303
|
}
|
|
1254
1304
|
}
|
|
1305
|
+
function finalizeEditor(builder) {
|
|
1306
|
+
if (builder.activeEditorId) {
|
|
1307
|
+
builder.patchBlock(builder.activeEditorId, {
|
|
1308
|
+
isStreaming: false
|
|
1309
|
+
});
|
|
1310
|
+
builder.activeEditorId = null;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1255
1313
|
var handleUserMessage = (event, builder) => {
|
|
1256
|
-
if (builder.findBlock((b) => b.type === "user")) return;
|
|
1257
1314
|
const e = event;
|
|
1258
|
-
|
|
1315
|
+
const existing = builder.findBlock((b) => b.type === "user");
|
|
1316
|
+
if (existing) {
|
|
1317
|
+
if (e.createdAt) {
|
|
1318
|
+
builder.patchBlock(existing.id, {
|
|
1319
|
+
createdAt: e.createdAt
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
builder.addBlock({
|
|
1325
|
+
type: "user",
|
|
1326
|
+
id: builder.nextId(),
|
|
1327
|
+
content: e.content,
|
|
1328
|
+
createdAt: e.createdAt
|
|
1329
|
+
});
|
|
1259
1330
|
};
|
|
1260
1331
|
var handleChunk = (event, builder) => {
|
|
1261
1332
|
const e = event;
|
|
@@ -1297,12 +1368,26 @@ var handleToolCall = (event, builder) => {
|
|
|
1297
1368
|
var handleToolExecuting = (event, builder) => {
|
|
1298
1369
|
const e = event;
|
|
1299
1370
|
const block = builder.findBlock(
|
|
1300
|
-
(b) => b.type === "tool" && b.toolName === e.name && b.status === "calling"
|
|
1371
|
+
(b) => b.type === "tool" && (e.call_id ? b.callId === e.call_id : b.toolName === e.name) && b.status === "calling"
|
|
1301
1372
|
);
|
|
1302
1373
|
if (block) {
|
|
1303
1374
|
builder.patchBlock(block.id, { status: "executing" });
|
|
1304
1375
|
}
|
|
1305
1376
|
};
|
|
1377
|
+
var handleToolProgress = (event, builder) => {
|
|
1378
|
+
const e = event;
|
|
1379
|
+
const block = builder.findBlock(
|
|
1380
|
+
(b) => b.type === "tool" && b.callId === e.callId
|
|
1381
|
+
);
|
|
1382
|
+
if (block && block.type === "tool") {
|
|
1383
|
+
const sources = block.sources ? [...block.sources] : [];
|
|
1384
|
+
sources.push(e.item);
|
|
1385
|
+
builder.patchBlock(block.id, {
|
|
1386
|
+
sources,
|
|
1387
|
+
status: "executing"
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
};
|
|
1306
1391
|
var handleToolEnd = (event, builder) => {
|
|
1307
1392
|
const e = event;
|
|
1308
1393
|
const callId = e.type === "tool_end" ? e.callId : void 0;
|
|
@@ -1415,6 +1500,7 @@ var handleSubagentEnd = (event, builder) => {
|
|
|
1415
1500
|
var handleComplete = (_event, builder) => {
|
|
1416
1501
|
finalizeText(builder);
|
|
1417
1502
|
finalizeThinking(builder);
|
|
1503
|
+
finalizeEditor(builder);
|
|
1418
1504
|
for (const b of builder.getBlocks()) {
|
|
1419
1505
|
if (b.type === "tool" && b.status !== "completed") {
|
|
1420
1506
|
builder.patchBlock(b.id, { status: "completed" });
|
|
@@ -1434,30 +1520,457 @@ var handleError = (event, builder) => {
|
|
|
1434
1520
|
var handleDisconnected = (_event, builder) => {
|
|
1435
1521
|
finalizeText(builder);
|
|
1436
1522
|
finalizeThinking(builder);
|
|
1523
|
+
finalizeEditor(builder);
|
|
1524
|
+
};
|
|
1525
|
+
var handleCapsuleOutputChunk = (event, builder) => {
|
|
1526
|
+
const e = event;
|
|
1527
|
+
const block = builder.findBlock(
|
|
1528
|
+
(b) => b.type === "capsule" && b.callId === e.callId
|
|
1529
|
+
);
|
|
1530
|
+
if (block && block.type === "capsule") {
|
|
1531
|
+
builder.patchBlock(block.id, {
|
|
1532
|
+
output: block.output + e.chunk
|
|
1533
|
+
});
|
|
1534
|
+
} else {
|
|
1535
|
+
builder.addBlock({
|
|
1536
|
+
type: "capsule",
|
|
1537
|
+
id: builder.nextId(),
|
|
1538
|
+
callId: e.callId,
|
|
1539
|
+
toolName: "",
|
|
1540
|
+
output: e.chunk,
|
|
1541
|
+
isActive: true
|
|
1542
|
+
});
|
|
1543
|
+
}
|
|
1544
|
+
};
|
|
1545
|
+
var handleCapsuleOutput = (event, builder) => {
|
|
1546
|
+
const e = event;
|
|
1547
|
+
const block = builder.findBlock(
|
|
1548
|
+
(b) => b.type === "capsule" && b.callId === (e.callId ?? "")
|
|
1549
|
+
);
|
|
1550
|
+
if (block) {
|
|
1551
|
+
builder.patchBlock(block.id, {
|
|
1552
|
+
output: e.output,
|
|
1553
|
+
command: e.command,
|
|
1554
|
+
toolName: e.toolName,
|
|
1555
|
+
durationMs: e.durationMs,
|
|
1556
|
+
isActive: false
|
|
1557
|
+
});
|
|
1558
|
+
} else {
|
|
1559
|
+
builder.addBlock({
|
|
1560
|
+
type: "capsule",
|
|
1561
|
+
id: builder.nextId(),
|
|
1562
|
+
callId: e.callId ?? "",
|
|
1563
|
+
toolName: e.toolName,
|
|
1564
|
+
command: e.command,
|
|
1565
|
+
output: e.output,
|
|
1566
|
+
durationMs: e.durationMs,
|
|
1567
|
+
isActive: false
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
};
|
|
1571
|
+
var handleAssetCreated = (event, builder) => {
|
|
1572
|
+
const e = event;
|
|
1573
|
+
builder.addBlock({
|
|
1574
|
+
type: "asset",
|
|
1575
|
+
id: builder.nextId(),
|
|
1576
|
+
assetId: e.assetId,
|
|
1577
|
+
name: e.name,
|
|
1578
|
+
url: e.url,
|
|
1579
|
+
mediaType: e.mediaType,
|
|
1580
|
+
sizeBytes: e.sizeBytes
|
|
1581
|
+
});
|
|
1582
|
+
};
|
|
1583
|
+
var handleTodoUpdate = (event, builder) => {
|
|
1584
|
+
const e = event;
|
|
1585
|
+
if (builder.activeTodoId) {
|
|
1586
|
+
builder.patchBlock(builder.activeTodoId, {
|
|
1587
|
+
todos: e.todos
|
|
1588
|
+
});
|
|
1589
|
+
} else {
|
|
1590
|
+
const id = builder.nextId();
|
|
1591
|
+
builder.activeTodoId = id;
|
|
1592
|
+
builder.addBlock({
|
|
1593
|
+
type: "todo",
|
|
1594
|
+
id,
|
|
1595
|
+
todos: e.todos
|
|
1596
|
+
});
|
|
1597
|
+
}
|
|
1598
|
+
};
|
|
1599
|
+
var handleEditorContentStart = (event, builder) => {
|
|
1600
|
+
const e = event;
|
|
1601
|
+
const id = builder.nextId();
|
|
1602
|
+
builder.activeEditorId = id;
|
|
1603
|
+
builder.addBlock({
|
|
1604
|
+
type: "editor",
|
|
1605
|
+
id,
|
|
1606
|
+
callId: e.callId,
|
|
1607
|
+
path: e.path,
|
|
1608
|
+
language: e.language,
|
|
1609
|
+
content: "",
|
|
1610
|
+
isStreaming: true
|
|
1611
|
+
});
|
|
1612
|
+
};
|
|
1613
|
+
var handleEditorContentDelta = (event, builder) => {
|
|
1614
|
+
const e = event;
|
|
1615
|
+
const block = builder.findBlock(
|
|
1616
|
+
(b) => b.type === "editor" && b.callId === e.callId
|
|
1617
|
+
);
|
|
1618
|
+
if (block && block.type === "editor") {
|
|
1619
|
+
builder.patchBlock(block.id, {
|
|
1620
|
+
content: block.content + e.delta
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
var handleEditorContentEnd = (event, builder) => {
|
|
1625
|
+
const e = event;
|
|
1626
|
+
const block = builder.findBlock(
|
|
1627
|
+
(b) => b.type === "editor" && b.callId === e.callId
|
|
1628
|
+
);
|
|
1629
|
+
if (block) {
|
|
1630
|
+
builder.patchBlock(block.id, {
|
|
1631
|
+
isStreaming: false
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
builder.activeEditorId = null;
|
|
1635
|
+
};
|
|
1636
|
+
var handleDesktopStream = (event, builder) => {
|
|
1637
|
+
const e = event;
|
|
1638
|
+
if (!e.url) return;
|
|
1639
|
+
const existing = builder.findBlock((b) => b.type === "desktop_stream");
|
|
1640
|
+
if (existing) {
|
|
1641
|
+
builder.patchBlock(existing.id, {
|
|
1642
|
+
url: e.url,
|
|
1643
|
+
authKey: e.authKey,
|
|
1644
|
+
sandboxId: e.sandboxId
|
|
1645
|
+
});
|
|
1646
|
+
} else {
|
|
1647
|
+
builder.addBlock({
|
|
1648
|
+
type: "desktop_stream",
|
|
1649
|
+
id: builder.nextId(),
|
|
1650
|
+
url: e.url,
|
|
1651
|
+
authKey: e.authKey,
|
|
1652
|
+
sandboxId: e.sandboxId
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
};
|
|
1656
|
+
var handleAttachmentStaged = (event, builder) => {
|
|
1657
|
+
const e = event;
|
|
1658
|
+
if (!e.files || e.files.length === 0) return;
|
|
1659
|
+
builder.addBlock({
|
|
1660
|
+
type: "attachment",
|
|
1661
|
+
id: builder.nextId(),
|
|
1662
|
+
files: e.files
|
|
1663
|
+
});
|
|
1664
|
+
};
|
|
1665
|
+
var noop = () => {
|
|
1437
1666
|
};
|
|
1438
1667
|
var standardHandlers = {
|
|
1439
1668
|
user_message: handleUserMessage,
|
|
1440
1669
|
chunk: handleChunk,
|
|
1441
1670
|
tool_call: handleToolCall,
|
|
1442
1671
|
tool_executing: handleToolExecuting,
|
|
1672
|
+
tool_progress: handleToolProgress,
|
|
1443
1673
|
tool_completed: handleToolEnd,
|
|
1444
1674
|
tool_end: handleToolEnd,
|
|
1445
1675
|
agent_start: handleAgentStart,
|
|
1676
|
+
agent_end: noop,
|
|
1446
1677
|
thinking_delta: handleThinkingDelta,
|
|
1447
1678
|
thinking_complete: handleThinkingComplete,
|
|
1448
1679
|
subagent_start: handleSubagentStart,
|
|
1449
1680
|
subagent_chunk: handleSubagentChunk,
|
|
1450
1681
|
subagent_update: handleSubagentUpdate,
|
|
1451
1682
|
subagent_end: handleSubagentEnd,
|
|
1683
|
+
subagent_tool_use: noop,
|
|
1684
|
+
capsule_output: handleCapsuleOutput,
|
|
1685
|
+
capsule_output_chunk: handleCapsuleOutputChunk,
|
|
1686
|
+
asset_created: handleAssetCreated,
|
|
1687
|
+
todo_update: handleTodoUpdate,
|
|
1688
|
+
editor_content_start: handleEditorContentStart,
|
|
1689
|
+
editor_content_delta: handleEditorContentDelta,
|
|
1690
|
+
editor_content_end: handleEditorContentEnd,
|
|
1691
|
+
desktop_stream: handleDesktopStream,
|
|
1692
|
+
attachment_staged: handleAttachmentStaged,
|
|
1693
|
+
workspace_ready: noop,
|
|
1694
|
+
retry: noop,
|
|
1452
1695
|
complete: handleComplete,
|
|
1453
1696
|
error: handleError,
|
|
1454
1697
|
disconnected: handleDisconnected
|
|
1455
1698
|
};
|
|
1699
|
+
|
|
1700
|
+
// src/types.ts
|
|
1701
|
+
var ChatEventType = {
|
|
1702
|
+
Connected: "connected",
|
|
1703
|
+
BlocksChanged: "blocks_changed",
|
|
1704
|
+
UserMessage: "user_message",
|
|
1705
|
+
TitleGenerated: "title_generated",
|
|
1706
|
+
ModelInfo: "model_info",
|
|
1707
|
+
Chunk: "chunk",
|
|
1708
|
+
ToolCall: "tool_call",
|
|
1709
|
+
ToolExecuting: "tool_executing",
|
|
1710
|
+
ToolProgress: "tool_progress",
|
|
1711
|
+
ToolCompleted: "tool_completed",
|
|
1712
|
+
ToolEnd: "tool_end",
|
|
1713
|
+
AgentStart: "agent_start",
|
|
1714
|
+
AgentEnd: "agent_end",
|
|
1715
|
+
ThinkingDelta: "thinking_delta",
|
|
1716
|
+
ThinkingComplete: "thinking_complete",
|
|
1717
|
+
SubagentStart: "subagent_start",
|
|
1718
|
+
SubagentChunk: "subagent_chunk",
|
|
1719
|
+
SubagentUpdate: "subagent_update",
|
|
1720
|
+
SubagentEnd: "subagent_end",
|
|
1721
|
+
SubagentToolUse: "subagent_tool_use",
|
|
1722
|
+
CapsuleOutput: "capsule_output",
|
|
1723
|
+
CapsuleOutputChunk: "capsule_output_chunk",
|
|
1724
|
+
AssetCreated: "asset_created",
|
|
1725
|
+
TodoUpdate: "todo_update",
|
|
1726
|
+
EditorContentStart: "editor_content_start",
|
|
1727
|
+
EditorContentDelta: "editor_content_delta",
|
|
1728
|
+
EditorContentEnd: "editor_content_end",
|
|
1729
|
+
Complete: "complete",
|
|
1730
|
+
Error: "error",
|
|
1731
|
+
Disconnected: "disconnected",
|
|
1732
|
+
Retry: "retry",
|
|
1733
|
+
ContextUpdate: "context_update",
|
|
1734
|
+
DesktopStream: "desktop_stream",
|
|
1735
|
+
AttachmentStaged: "attachment_staged",
|
|
1736
|
+
WorkspaceReady: "workspace_ready"
|
|
1737
|
+
};
|
|
1738
|
+
|
|
1739
|
+
// src/stream-manager.ts
|
|
1740
|
+
var StreamManager = class {
|
|
1741
|
+
constructor(session) {
|
|
1742
|
+
this._state = "idle";
|
|
1743
|
+
this._activeConversationId = null;
|
|
1744
|
+
this._backgroundJobs = /* @__PURE__ */ new Map();
|
|
1745
|
+
this.handlers = [];
|
|
1746
|
+
this.unsub = null;
|
|
1747
|
+
this.session = session;
|
|
1748
|
+
this.attach();
|
|
1749
|
+
}
|
|
1750
|
+
// ── Public state ──────────────────────────────────────────────
|
|
1751
|
+
get state() {
|
|
1752
|
+
return this._state;
|
|
1753
|
+
}
|
|
1754
|
+
get activeConversationId() {
|
|
1755
|
+
return this._activeConversationId;
|
|
1756
|
+
}
|
|
1757
|
+
get backgroundJobs() {
|
|
1758
|
+
return this._backgroundJobs;
|
|
1759
|
+
}
|
|
1760
|
+
// ── Event subscription ────────────────────────────────────────
|
|
1761
|
+
on(handler) {
|
|
1762
|
+
this.handlers.push(handler);
|
|
1763
|
+
return () => {
|
|
1764
|
+
this.handlers = this.handlers.filter((h) => h !== handler);
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1767
|
+
emit(event) {
|
|
1768
|
+
for (const handler of this.handlers) {
|
|
1769
|
+
try {
|
|
1770
|
+
handler(event);
|
|
1771
|
+
} catch {
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
setState(state) {
|
|
1776
|
+
this._state = state;
|
|
1777
|
+
this.emit({
|
|
1778
|
+
type: "stateChange",
|
|
1779
|
+
state,
|
|
1780
|
+
conversationId: this._activeConversationId
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
// ── Session event wiring ──────────────────────────────────────
|
|
1784
|
+
attach() {
|
|
1785
|
+
this.unsub = this.session.on((event) => {
|
|
1786
|
+
this.onSessionEvent(event);
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
onSessionEvent(event) {
|
|
1790
|
+
const convId = this.session.conversationId;
|
|
1791
|
+
if (event.type === ChatEventType.BlocksChanged) {
|
|
1792
|
+
if (this._state === "streaming" && convId) {
|
|
1793
|
+
this.emit({
|
|
1794
|
+
type: "blocksChanged",
|
|
1795
|
+
conversationId: convId,
|
|
1796
|
+
blocks: event.blocks
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
this.emit({
|
|
1802
|
+
type: "event",
|
|
1803
|
+
conversationId: convId,
|
|
1804
|
+
event
|
|
1805
|
+
});
|
|
1806
|
+
if (event.type === ChatEventType.Complete) {
|
|
1807
|
+
if (this._state === "streaming") {
|
|
1808
|
+
this.setState("idle");
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
// ── Send ──────────────────────────────────────────────────────
|
|
1813
|
+
async send(content, options) {
|
|
1814
|
+
if (this._state === "streaming") return;
|
|
1815
|
+
if (!this._activeConversationId) {
|
|
1816
|
+
const id = await this.session.createNewConversation();
|
|
1817
|
+
this.setActiveConversation(id);
|
|
1818
|
+
}
|
|
1819
|
+
this.prepareUserBlock(content);
|
|
1820
|
+
this.setState("streaming");
|
|
1821
|
+
try {
|
|
1822
|
+
await this.session.send(content, {
|
|
1823
|
+
enableSearch: options?.enableSearch,
|
|
1824
|
+
agentName: options?.agentName,
|
|
1825
|
+
uploadIds: options?.uploadIds
|
|
1826
|
+
});
|
|
1827
|
+
} catch {
|
|
1828
|
+
}
|
|
1829
|
+
this.finalizeStream();
|
|
1830
|
+
}
|
|
1831
|
+
// ── Regenerate ────────────────────────────────────────────────
|
|
1832
|
+
async regenerate() {
|
|
1833
|
+
if (this._state === "streaming") return;
|
|
1834
|
+
const userMsgs = this.session.messages.filter(
|
|
1835
|
+
(m) => m.role === "user"
|
|
1836
|
+
);
|
|
1837
|
+
const lastUserMsg = userMsgs[userMsgs.length - 1];
|
|
1838
|
+
if (!lastUserMsg) return;
|
|
1839
|
+
this.prepareUserBlock(lastUserMsg.content);
|
|
1840
|
+
this.setState("streaming");
|
|
1841
|
+
try {
|
|
1842
|
+
await this.session.resendFromCheckpoint(
|
|
1843
|
+
lastUserMsg.id,
|
|
1844
|
+
lastUserMsg.content
|
|
1845
|
+
);
|
|
1846
|
+
} catch {
|
|
1847
|
+
}
|
|
1848
|
+
this.finalizeStream();
|
|
1849
|
+
}
|
|
1850
|
+
// ── Switch conversation ───────────────────────────────────────
|
|
1851
|
+
async switchTo(conversationId) {
|
|
1852
|
+
if (conversationId === this._activeConversationId) return;
|
|
1853
|
+
if (this._state === "streaming") {
|
|
1854
|
+
const oldConvId = this._activeConversationId;
|
|
1855
|
+
const jobId = this.session.currentJobId;
|
|
1856
|
+
if (oldConvId && jobId) {
|
|
1857
|
+
this._backgroundJobs.set(oldConvId, jobId);
|
|
1858
|
+
this.emit({
|
|
1859
|
+
type: "backgroundJobsChanged",
|
|
1860
|
+
jobs: this._backgroundJobs
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
this.session.detach();
|
|
1864
|
+
}
|
|
1865
|
+
if (this._backgroundJobs.has(conversationId)) {
|
|
1866
|
+
this._backgroundJobs.delete(conversationId);
|
|
1867
|
+
this.emit({
|
|
1868
|
+
type: "backgroundJobsChanged",
|
|
1869
|
+
jobs: this._backgroundJobs
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
this.setActiveConversation(conversationId);
|
|
1873
|
+
await this.restore(conversationId);
|
|
1874
|
+
}
|
|
1875
|
+
// ── Create / delete conversation ──────────────────────────────
|
|
1876
|
+
async createConversation() {
|
|
1877
|
+
const id = await this.session.createNewConversation();
|
|
1878
|
+
this.setActiveConversation(id);
|
|
1879
|
+
return id;
|
|
1880
|
+
}
|
|
1881
|
+
async deleteConversation(id) {
|
|
1882
|
+
await this.session.deleteConversation(id);
|
|
1883
|
+
this._backgroundJobs.delete(id);
|
|
1884
|
+
if (this._activeConversationId === id) {
|
|
1885
|
+
this._activeConversationId = null;
|
|
1886
|
+
this.emit({ type: "conversationChanged", conversationId: null });
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
// ── Stop (explicit cancel) ────────────────────────────────────
|
|
1890
|
+
stop() {
|
|
1891
|
+
this.session.disconnect();
|
|
1892
|
+
this.setState("idle");
|
|
1893
|
+
}
|
|
1894
|
+
// ── Cleanup ───────────────────────────────────────────────────
|
|
1895
|
+
destroy() {
|
|
1896
|
+
if (this.unsub) {
|
|
1897
|
+
this.unsub();
|
|
1898
|
+
this.unsub = null;
|
|
1899
|
+
}
|
|
1900
|
+
this.handlers = [];
|
|
1901
|
+
}
|
|
1902
|
+
// ── Internal: helpers ──────────────────────────────────────────
|
|
1903
|
+
prepareUserBlock(content) {
|
|
1904
|
+
this.session.blockBuilder.reset();
|
|
1905
|
+
this.session.blockBuilder.addBlock({
|
|
1906
|
+
type: "user",
|
|
1907
|
+
id: this.session.blockBuilder.nextId(),
|
|
1908
|
+
content
|
|
1909
|
+
});
|
|
1910
|
+
}
|
|
1911
|
+
finalizeStream() {
|
|
1912
|
+
if (this._state === "streaming") {
|
|
1913
|
+
this.setState("idle");
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
// ── Internal: restore ─────────────────────────────────────────
|
|
1917
|
+
async restore(conversationId) {
|
|
1918
|
+
this.setState("restoring");
|
|
1919
|
+
let activeJobId = null;
|
|
1920
|
+
try {
|
|
1921
|
+
const res = await this.session.client.get(`/v1/conversations/${encodeURIComponent(conversationId)}/active-job`);
|
|
1922
|
+
activeJobId = res.job_id ?? null;
|
|
1923
|
+
} catch {
|
|
1924
|
+
}
|
|
1925
|
+
if (activeJobId) {
|
|
1926
|
+
await this.session.loadConversation(conversationId);
|
|
1927
|
+
this.setState("streaming");
|
|
1928
|
+
try {
|
|
1929
|
+
await this.session.reconnectToJob(activeJobId);
|
|
1930
|
+
} catch {
|
|
1931
|
+
}
|
|
1932
|
+
if (this._state === "streaming") {
|
|
1933
|
+
this.setState("idle");
|
|
1934
|
+
}
|
|
1935
|
+
} else {
|
|
1936
|
+
await this.session.loadConversation(conversationId);
|
|
1937
|
+
try {
|
|
1938
|
+
const jobs = await this.session.client.get(`/v1/conversations/${encodeURIComponent(conversationId)}/jobs`);
|
|
1939
|
+
const completedJobs = jobs.filter(
|
|
1940
|
+
(j) => j.status === "completed"
|
|
1941
|
+
);
|
|
1942
|
+
for (const job of completedJobs) {
|
|
1943
|
+
await this.session.switchConversation(conversationId, job.job_id);
|
|
1944
|
+
}
|
|
1945
|
+
if (completedJobs.length > 0) {
|
|
1946
|
+
this.emit({
|
|
1947
|
+
type: "blocksChanged",
|
|
1948
|
+
conversationId,
|
|
1949
|
+
blocks: this.session.blockBuilder.getBlocks()
|
|
1950
|
+
});
|
|
1951
|
+
this.emit({
|
|
1952
|
+
type: "versionsReady",
|
|
1953
|
+
conversationId,
|
|
1954
|
+
count: completedJobs.length
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
} catch {
|
|
1958
|
+
}
|
|
1959
|
+
this.setState("idle");
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
// ── Internal: set active conversation ─────────────────────────
|
|
1963
|
+
setActiveConversation(id) {
|
|
1964
|
+
this._activeConversationId = id;
|
|
1965
|
+
this.emit({ type: "conversationChanged", conversationId: id });
|
|
1966
|
+
}
|
|
1967
|
+
};
|
|
1456
1968
|
export {
|
|
1457
1969
|
AstralformClient,
|
|
1458
1970
|
AstralformError,
|
|
1459
1971
|
AuthenticationError,
|
|
1460
1972
|
BlockBuilder,
|
|
1973
|
+
ChatEventType,
|
|
1461
1974
|
ChatSession,
|
|
1462
1975
|
ConnectionError,
|
|
1463
1976
|
InMemoryStorage,
|
|
@@ -1465,6 +1978,7 @@ export {
|
|
|
1465
1978
|
RateLimitError,
|
|
1466
1979
|
ServerError,
|
|
1467
1980
|
StreamAbortedError,
|
|
1981
|
+
StreamManager,
|
|
1468
1982
|
ToolRegistry,
|
|
1469
1983
|
generateId,
|
|
1470
1984
|
standardHandlers,
|