@astralform/js 0.2.1 → 0.2.2
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 +488 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +192 -71
- package/dist/index.d.ts +192 -71
- package/dist/index.js +486 -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,
|
|
@@ -1030,27 +1060,6 @@ var ChatSession = class {
|
|
|
1030
1060
|
sizeBytes: event.size_bytes
|
|
1031
1061
|
});
|
|
1032
1062
|
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
1063
|
case "editor_content_start":
|
|
1055
1064
|
this.emit({
|
|
1056
1065
|
type: "editor_content_start",
|
|
@@ -1172,19 +1181,26 @@ var ChatSession = class {
|
|
|
1172
1181
|
this.abortController = null;
|
|
1173
1182
|
}
|
|
1174
1183
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
});
|
|
1179
|
-
this.currentJobId = null;
|
|
1180
|
-
}
|
|
1184
|
+
/** Detach from the SSE stream without cancelling the job.
|
|
1185
|
+
* The backend job keeps running — caller can reconnect later. */
|
|
1186
|
+
detach() {
|
|
1181
1187
|
this.abortController?.abort();
|
|
1182
1188
|
this.abortController = null;
|
|
1183
1189
|
this.isStreaming = false;
|
|
1184
1190
|
this.streamingContent = "";
|
|
1185
1191
|
this.executingTool = null;
|
|
1192
|
+
this.blockBuilder.reset();
|
|
1186
1193
|
this.emit({ type: "disconnected" });
|
|
1187
1194
|
}
|
|
1195
|
+
/** Stop the job and disconnect (explicit user action). */
|
|
1196
|
+
disconnect() {
|
|
1197
|
+
if (this.currentJobId) {
|
|
1198
|
+
this.client.cancelJob(this.currentJobId).catch(() => {
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
this.detach();
|
|
1202
|
+
this.currentJobId = null;
|
|
1203
|
+
}
|
|
1188
1204
|
async createNewConversation() {
|
|
1189
1205
|
const id = generateId();
|
|
1190
1206
|
const conversation = await this.storage.createConversation(
|
|
@@ -1252,10 +1268,31 @@ function finalizeThinking(builder) {
|
|
|
1252
1268
|
builder.thinkingStartMs = null;
|
|
1253
1269
|
}
|
|
1254
1270
|
}
|
|
1271
|
+
function finalizeEditor(builder) {
|
|
1272
|
+
if (builder.activeEditorId) {
|
|
1273
|
+
builder.patchBlock(builder.activeEditorId, {
|
|
1274
|
+
isStreaming: false
|
|
1275
|
+
});
|
|
1276
|
+
builder.activeEditorId = null;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1255
1279
|
var handleUserMessage = (event, builder) => {
|
|
1256
|
-
if (builder.findBlock((b) => b.type === "user")) return;
|
|
1257
1280
|
const e = event;
|
|
1258
|
-
|
|
1281
|
+
const existing = builder.findBlock((b) => b.type === "user");
|
|
1282
|
+
if (existing) {
|
|
1283
|
+
if (e.createdAt) {
|
|
1284
|
+
builder.patchBlock(existing.id, {
|
|
1285
|
+
createdAt: e.createdAt
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
builder.addBlock({
|
|
1291
|
+
type: "user",
|
|
1292
|
+
id: builder.nextId(),
|
|
1293
|
+
content: e.content,
|
|
1294
|
+
createdAt: e.createdAt
|
|
1295
|
+
});
|
|
1259
1296
|
};
|
|
1260
1297
|
var handleChunk = (event, builder) => {
|
|
1261
1298
|
const e = event;
|
|
@@ -1297,12 +1334,26 @@ var handleToolCall = (event, builder) => {
|
|
|
1297
1334
|
var handleToolExecuting = (event, builder) => {
|
|
1298
1335
|
const e = event;
|
|
1299
1336
|
const block = builder.findBlock(
|
|
1300
|
-
(b) => b.type === "tool" && b.toolName === e.name && b.status === "calling"
|
|
1337
|
+
(b) => b.type === "tool" && (e.call_id ? b.callId === e.call_id : b.toolName === e.name) && b.status === "calling"
|
|
1301
1338
|
);
|
|
1302
1339
|
if (block) {
|
|
1303
1340
|
builder.patchBlock(block.id, { status: "executing" });
|
|
1304
1341
|
}
|
|
1305
1342
|
};
|
|
1343
|
+
var handleToolProgress = (event, builder) => {
|
|
1344
|
+
const e = event;
|
|
1345
|
+
const block = builder.findBlock(
|
|
1346
|
+
(b) => b.type === "tool" && b.callId === e.callId
|
|
1347
|
+
);
|
|
1348
|
+
if (block && block.type === "tool") {
|
|
1349
|
+
const sources = block.sources ? [...block.sources] : [];
|
|
1350
|
+
sources.push(e.item);
|
|
1351
|
+
builder.patchBlock(block.id, {
|
|
1352
|
+
sources,
|
|
1353
|
+
status: "executing"
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
};
|
|
1306
1357
|
var handleToolEnd = (event, builder) => {
|
|
1307
1358
|
const e = event;
|
|
1308
1359
|
const callId = e.type === "tool_end" ? e.callId : void 0;
|
|
@@ -1415,6 +1466,7 @@ var handleSubagentEnd = (event, builder) => {
|
|
|
1415
1466
|
var handleComplete = (_event, builder) => {
|
|
1416
1467
|
finalizeText(builder);
|
|
1417
1468
|
finalizeThinking(builder);
|
|
1469
|
+
finalizeEditor(builder);
|
|
1418
1470
|
for (const b of builder.getBlocks()) {
|
|
1419
1471
|
if (b.type === "tool" && b.status !== "completed") {
|
|
1420
1472
|
builder.patchBlock(b.id, { status: "completed" });
|
|
@@ -1434,30 +1486,421 @@ var handleError = (event, builder) => {
|
|
|
1434
1486
|
var handleDisconnected = (_event, builder) => {
|
|
1435
1487
|
finalizeText(builder);
|
|
1436
1488
|
finalizeThinking(builder);
|
|
1489
|
+
finalizeEditor(builder);
|
|
1490
|
+
};
|
|
1491
|
+
var handleCapsuleOutputChunk = (event, builder) => {
|
|
1492
|
+
const e = event;
|
|
1493
|
+
const block = builder.findBlock(
|
|
1494
|
+
(b) => b.type === "capsule" && b.callId === e.callId
|
|
1495
|
+
);
|
|
1496
|
+
if (block && block.type === "capsule") {
|
|
1497
|
+
builder.patchBlock(block.id, {
|
|
1498
|
+
output: block.output + e.chunk
|
|
1499
|
+
});
|
|
1500
|
+
} else {
|
|
1501
|
+
builder.addBlock({
|
|
1502
|
+
type: "capsule",
|
|
1503
|
+
id: builder.nextId(),
|
|
1504
|
+
callId: e.callId,
|
|
1505
|
+
toolName: "",
|
|
1506
|
+
output: e.chunk,
|
|
1507
|
+
isActive: true
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1511
|
+
var handleCapsuleOutput = (event, builder) => {
|
|
1512
|
+
const e = event;
|
|
1513
|
+
const block = builder.findBlock(
|
|
1514
|
+
(b) => b.type === "capsule" && b.callId === (e.callId ?? "")
|
|
1515
|
+
);
|
|
1516
|
+
if (block) {
|
|
1517
|
+
builder.patchBlock(block.id, {
|
|
1518
|
+
output: e.output,
|
|
1519
|
+
command: e.command,
|
|
1520
|
+
toolName: e.toolName,
|
|
1521
|
+
durationMs: e.durationMs,
|
|
1522
|
+
isActive: false
|
|
1523
|
+
});
|
|
1524
|
+
} else {
|
|
1525
|
+
builder.addBlock({
|
|
1526
|
+
type: "capsule",
|
|
1527
|
+
id: builder.nextId(),
|
|
1528
|
+
callId: e.callId ?? "",
|
|
1529
|
+
toolName: e.toolName,
|
|
1530
|
+
command: e.command,
|
|
1531
|
+
output: e.output,
|
|
1532
|
+
durationMs: e.durationMs,
|
|
1533
|
+
isActive: false
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
};
|
|
1537
|
+
var handleAssetCreated = (event, builder) => {
|
|
1538
|
+
const e = event;
|
|
1539
|
+
builder.addBlock({
|
|
1540
|
+
type: "asset",
|
|
1541
|
+
id: builder.nextId(),
|
|
1542
|
+
assetId: e.assetId,
|
|
1543
|
+
name: e.name,
|
|
1544
|
+
url: e.url,
|
|
1545
|
+
mediaType: e.mediaType,
|
|
1546
|
+
sizeBytes: e.sizeBytes
|
|
1547
|
+
});
|
|
1548
|
+
};
|
|
1549
|
+
var handleTodoUpdate = (event, builder) => {
|
|
1550
|
+
const e = event;
|
|
1551
|
+
if (builder.activeTodoId) {
|
|
1552
|
+
builder.patchBlock(builder.activeTodoId, {
|
|
1553
|
+
todos: e.todos
|
|
1554
|
+
});
|
|
1555
|
+
} else {
|
|
1556
|
+
const id = builder.nextId();
|
|
1557
|
+
builder.activeTodoId = id;
|
|
1558
|
+
builder.addBlock({
|
|
1559
|
+
type: "todo",
|
|
1560
|
+
id,
|
|
1561
|
+
todos: e.todos
|
|
1562
|
+
});
|
|
1563
|
+
}
|
|
1564
|
+
};
|
|
1565
|
+
var handleEditorContentStart = (event, builder) => {
|
|
1566
|
+
const e = event;
|
|
1567
|
+
const id = builder.nextId();
|
|
1568
|
+
builder.activeEditorId = id;
|
|
1569
|
+
builder.addBlock({
|
|
1570
|
+
type: "editor",
|
|
1571
|
+
id,
|
|
1572
|
+
callId: e.callId,
|
|
1573
|
+
path: e.path,
|
|
1574
|
+
language: e.language,
|
|
1575
|
+
content: "",
|
|
1576
|
+
isStreaming: true
|
|
1577
|
+
});
|
|
1578
|
+
};
|
|
1579
|
+
var handleEditorContentDelta = (event, builder) => {
|
|
1580
|
+
const e = event;
|
|
1581
|
+
const block = builder.findBlock(
|
|
1582
|
+
(b) => b.type === "editor" && b.callId === e.callId
|
|
1583
|
+
);
|
|
1584
|
+
if (block && block.type === "editor") {
|
|
1585
|
+
builder.patchBlock(block.id, {
|
|
1586
|
+
content: block.content + e.delta
|
|
1587
|
+
});
|
|
1588
|
+
}
|
|
1589
|
+
};
|
|
1590
|
+
var handleEditorContentEnd = (event, builder) => {
|
|
1591
|
+
const e = event;
|
|
1592
|
+
const block = builder.findBlock(
|
|
1593
|
+
(b) => b.type === "editor" && b.callId === e.callId
|
|
1594
|
+
);
|
|
1595
|
+
if (block) {
|
|
1596
|
+
builder.patchBlock(block.id, {
|
|
1597
|
+
isStreaming: false
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
builder.activeEditorId = null;
|
|
1601
|
+
};
|
|
1602
|
+
var noop = () => {
|
|
1437
1603
|
};
|
|
1438
1604
|
var standardHandlers = {
|
|
1439
1605
|
user_message: handleUserMessage,
|
|
1440
1606
|
chunk: handleChunk,
|
|
1441
1607
|
tool_call: handleToolCall,
|
|
1442
1608
|
tool_executing: handleToolExecuting,
|
|
1609
|
+
tool_progress: handleToolProgress,
|
|
1443
1610
|
tool_completed: handleToolEnd,
|
|
1444
1611
|
tool_end: handleToolEnd,
|
|
1445
1612
|
agent_start: handleAgentStart,
|
|
1613
|
+
agent_end: noop,
|
|
1446
1614
|
thinking_delta: handleThinkingDelta,
|
|
1447
1615
|
thinking_complete: handleThinkingComplete,
|
|
1448
1616
|
subagent_start: handleSubagentStart,
|
|
1449
1617
|
subagent_chunk: handleSubagentChunk,
|
|
1450
1618
|
subagent_update: handleSubagentUpdate,
|
|
1451
1619
|
subagent_end: handleSubagentEnd,
|
|
1620
|
+
subagent_tool_use: noop,
|
|
1621
|
+
capsule_output: handleCapsuleOutput,
|
|
1622
|
+
capsule_output_chunk: handleCapsuleOutputChunk,
|
|
1623
|
+
asset_created: handleAssetCreated,
|
|
1624
|
+
todo_update: handleTodoUpdate,
|
|
1625
|
+
editor_content_start: handleEditorContentStart,
|
|
1626
|
+
editor_content_delta: handleEditorContentDelta,
|
|
1627
|
+
editor_content_end: handleEditorContentEnd,
|
|
1628
|
+
retry: noop,
|
|
1452
1629
|
complete: handleComplete,
|
|
1453
1630
|
error: handleError,
|
|
1454
1631
|
disconnected: handleDisconnected
|
|
1455
1632
|
};
|
|
1633
|
+
|
|
1634
|
+
// src/types.ts
|
|
1635
|
+
var ChatEventType = {
|
|
1636
|
+
Connected: "connected",
|
|
1637
|
+
BlocksChanged: "blocks_changed",
|
|
1638
|
+
UserMessage: "user_message",
|
|
1639
|
+
TitleGenerated: "title_generated",
|
|
1640
|
+
ModelInfo: "model_info",
|
|
1641
|
+
Chunk: "chunk",
|
|
1642
|
+
ToolCall: "tool_call",
|
|
1643
|
+
ToolExecuting: "tool_executing",
|
|
1644
|
+
ToolProgress: "tool_progress",
|
|
1645
|
+
ToolCompleted: "tool_completed",
|
|
1646
|
+
ToolEnd: "tool_end",
|
|
1647
|
+
AgentStart: "agent_start",
|
|
1648
|
+
AgentEnd: "agent_end",
|
|
1649
|
+
ThinkingDelta: "thinking_delta",
|
|
1650
|
+
ThinkingComplete: "thinking_complete",
|
|
1651
|
+
SubagentStart: "subagent_start",
|
|
1652
|
+
SubagentChunk: "subagent_chunk",
|
|
1653
|
+
SubagentUpdate: "subagent_update",
|
|
1654
|
+
SubagentEnd: "subagent_end",
|
|
1655
|
+
SubagentToolUse: "subagent_tool_use",
|
|
1656
|
+
CapsuleOutput: "capsule_output",
|
|
1657
|
+
CapsuleOutputChunk: "capsule_output_chunk",
|
|
1658
|
+
AssetCreated: "asset_created",
|
|
1659
|
+
TodoUpdate: "todo_update",
|
|
1660
|
+
EditorContentStart: "editor_content_start",
|
|
1661
|
+
EditorContentDelta: "editor_content_delta",
|
|
1662
|
+
EditorContentEnd: "editor_content_end",
|
|
1663
|
+
Complete: "complete",
|
|
1664
|
+
Error: "error",
|
|
1665
|
+
Disconnected: "disconnected",
|
|
1666
|
+
Retry: "retry"
|
|
1667
|
+
};
|
|
1668
|
+
|
|
1669
|
+
// src/stream-manager.ts
|
|
1670
|
+
var StreamManager = class {
|
|
1671
|
+
constructor(session) {
|
|
1672
|
+
this._state = "idle";
|
|
1673
|
+
this._activeConversationId = null;
|
|
1674
|
+
this._backgroundJobs = /* @__PURE__ */ new Map();
|
|
1675
|
+
this.handlers = [];
|
|
1676
|
+
this.unsub = null;
|
|
1677
|
+
this.session = session;
|
|
1678
|
+
this.attach();
|
|
1679
|
+
}
|
|
1680
|
+
// ── Public state ──────────────────────────────────────────────
|
|
1681
|
+
get state() {
|
|
1682
|
+
return this._state;
|
|
1683
|
+
}
|
|
1684
|
+
get activeConversationId() {
|
|
1685
|
+
return this._activeConversationId;
|
|
1686
|
+
}
|
|
1687
|
+
get backgroundJobs() {
|
|
1688
|
+
return this._backgroundJobs;
|
|
1689
|
+
}
|
|
1690
|
+
// ── Event subscription ────────────────────────────────────────
|
|
1691
|
+
on(handler) {
|
|
1692
|
+
this.handlers.push(handler);
|
|
1693
|
+
return () => {
|
|
1694
|
+
this.handlers = this.handlers.filter((h) => h !== handler);
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
emit(event) {
|
|
1698
|
+
for (const handler of this.handlers) {
|
|
1699
|
+
try {
|
|
1700
|
+
handler(event);
|
|
1701
|
+
} catch {
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
setState(state) {
|
|
1706
|
+
this._state = state;
|
|
1707
|
+
this.emit({
|
|
1708
|
+
type: "stateChange",
|
|
1709
|
+
state,
|
|
1710
|
+
conversationId: this._activeConversationId
|
|
1711
|
+
});
|
|
1712
|
+
}
|
|
1713
|
+
// ── Session event wiring ──────────────────────────────────────
|
|
1714
|
+
attach() {
|
|
1715
|
+
this.unsub = this.session.on((event) => {
|
|
1716
|
+
this.onSessionEvent(event);
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
onSessionEvent(event) {
|
|
1720
|
+
const convId = this.session.conversationId;
|
|
1721
|
+
if (event.type === ChatEventType.BlocksChanged) {
|
|
1722
|
+
if (this._state === "streaming" && convId) {
|
|
1723
|
+
this.emit({
|
|
1724
|
+
type: "blocksChanged",
|
|
1725
|
+
conversationId: convId,
|
|
1726
|
+
blocks: event.blocks
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
return;
|
|
1730
|
+
}
|
|
1731
|
+
this.emit({
|
|
1732
|
+
type: "event",
|
|
1733
|
+
conversationId: convId,
|
|
1734
|
+
event
|
|
1735
|
+
});
|
|
1736
|
+
if (event.type === ChatEventType.Complete) {
|
|
1737
|
+
if (this._state === "streaming") {
|
|
1738
|
+
this.setState("idle");
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
// ── Send ──────────────────────────────────────────────────────
|
|
1743
|
+
async send(content, options) {
|
|
1744
|
+
if (this._state === "streaming") return;
|
|
1745
|
+
if (!this._activeConversationId) {
|
|
1746
|
+
const id = await this.session.createNewConversation();
|
|
1747
|
+
this.setActiveConversation(id);
|
|
1748
|
+
}
|
|
1749
|
+
this.prepareUserBlock(content);
|
|
1750
|
+
this.setState("streaming");
|
|
1751
|
+
try {
|
|
1752
|
+
await this.session.send(content, {
|
|
1753
|
+
enableSearch: options?.enableSearch,
|
|
1754
|
+
agentName: options?.agentName,
|
|
1755
|
+
uploadIds: options?.uploadIds
|
|
1756
|
+
});
|
|
1757
|
+
} catch {
|
|
1758
|
+
}
|
|
1759
|
+
this.finalizeStream();
|
|
1760
|
+
}
|
|
1761
|
+
// ── Regenerate ────────────────────────────────────────────────
|
|
1762
|
+
async regenerate() {
|
|
1763
|
+
if (this._state === "streaming") return;
|
|
1764
|
+
const userMsgs = this.session.messages.filter(
|
|
1765
|
+
(m) => m.role === "user"
|
|
1766
|
+
);
|
|
1767
|
+
const lastUserMsg = userMsgs[userMsgs.length - 1];
|
|
1768
|
+
if (!lastUserMsg) return;
|
|
1769
|
+
this.prepareUserBlock(lastUserMsg.content);
|
|
1770
|
+
this.setState("streaming");
|
|
1771
|
+
try {
|
|
1772
|
+
await this.session.resendFromCheckpoint(
|
|
1773
|
+
lastUserMsg.id,
|
|
1774
|
+
lastUserMsg.content
|
|
1775
|
+
);
|
|
1776
|
+
} catch {
|
|
1777
|
+
}
|
|
1778
|
+
this.finalizeStream();
|
|
1779
|
+
}
|
|
1780
|
+
// ── Switch conversation ───────────────────────────────────────
|
|
1781
|
+
async switchTo(conversationId) {
|
|
1782
|
+
if (conversationId === this._activeConversationId) return;
|
|
1783
|
+
if (this._state === "streaming") {
|
|
1784
|
+
const oldConvId = this._activeConversationId;
|
|
1785
|
+
const jobId = this.session.currentJobId;
|
|
1786
|
+
if (oldConvId && jobId) {
|
|
1787
|
+
this._backgroundJobs.set(oldConvId, jobId);
|
|
1788
|
+
this.emit({
|
|
1789
|
+
type: "backgroundJobsChanged",
|
|
1790
|
+
jobs: this._backgroundJobs
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
this.session.detach();
|
|
1794
|
+
}
|
|
1795
|
+
if (this._backgroundJobs.has(conversationId)) {
|
|
1796
|
+
this._backgroundJobs.delete(conversationId);
|
|
1797
|
+
this.emit({
|
|
1798
|
+
type: "backgroundJobsChanged",
|
|
1799
|
+
jobs: this._backgroundJobs
|
|
1800
|
+
});
|
|
1801
|
+
}
|
|
1802
|
+
this.setActiveConversation(conversationId);
|
|
1803
|
+
await this.restore(conversationId);
|
|
1804
|
+
}
|
|
1805
|
+
// ── Create / delete conversation ──────────────────────────────
|
|
1806
|
+
async createConversation() {
|
|
1807
|
+
const id = await this.session.createNewConversation();
|
|
1808
|
+
this.setActiveConversation(id);
|
|
1809
|
+
return id;
|
|
1810
|
+
}
|
|
1811
|
+
async deleteConversation(id) {
|
|
1812
|
+
await this.session.deleteConversation(id);
|
|
1813
|
+
this._backgroundJobs.delete(id);
|
|
1814
|
+
if (this._activeConversationId === id) {
|
|
1815
|
+
this._activeConversationId = null;
|
|
1816
|
+
this.emit({ type: "conversationChanged", conversationId: null });
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
// ── Stop (explicit cancel) ────────────────────────────────────
|
|
1820
|
+
stop() {
|
|
1821
|
+
this.session.disconnect();
|
|
1822
|
+
this.setState("idle");
|
|
1823
|
+
}
|
|
1824
|
+
// ── Cleanup ───────────────────────────────────────────────────
|
|
1825
|
+
destroy() {
|
|
1826
|
+
if (this.unsub) {
|
|
1827
|
+
this.unsub();
|
|
1828
|
+
this.unsub = null;
|
|
1829
|
+
}
|
|
1830
|
+
this.handlers = [];
|
|
1831
|
+
}
|
|
1832
|
+
// ── Internal: helpers ──────────────────────────────────────────
|
|
1833
|
+
prepareUserBlock(content) {
|
|
1834
|
+
this.session.blockBuilder.reset();
|
|
1835
|
+
this.session.blockBuilder.addBlock({
|
|
1836
|
+
type: "user",
|
|
1837
|
+
id: this.session.blockBuilder.nextId(),
|
|
1838
|
+
content
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
finalizeStream() {
|
|
1842
|
+
if (this._state === "streaming") {
|
|
1843
|
+
this.setState("idle");
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
// ── Internal: restore ─────────────────────────────────────────
|
|
1847
|
+
async restore(conversationId) {
|
|
1848
|
+
this.setState("restoring");
|
|
1849
|
+
let activeJobId = null;
|
|
1850
|
+
try {
|
|
1851
|
+
const res = await this.session.client.get(`/v1/conversations/${encodeURIComponent(conversationId)}/active-job`);
|
|
1852
|
+
activeJobId = res.job_id ?? null;
|
|
1853
|
+
} catch {
|
|
1854
|
+
}
|
|
1855
|
+
if (activeJobId) {
|
|
1856
|
+
await this.session.loadConversation(conversationId);
|
|
1857
|
+
this.setState("streaming");
|
|
1858
|
+
try {
|
|
1859
|
+
await this.session.reconnectToJob(activeJobId);
|
|
1860
|
+
} catch {
|
|
1861
|
+
}
|
|
1862
|
+
if (this._state === "streaming") {
|
|
1863
|
+
this.setState("idle");
|
|
1864
|
+
}
|
|
1865
|
+
} else {
|
|
1866
|
+
await this.session.loadConversation(conversationId);
|
|
1867
|
+
try {
|
|
1868
|
+
const jobs = await this.session.client.get(`/v1/conversations/${encodeURIComponent(conversationId)}/jobs`);
|
|
1869
|
+
const completedJobs = jobs.filter(
|
|
1870
|
+
(j) => j.status === "completed"
|
|
1871
|
+
);
|
|
1872
|
+
for (const job of completedJobs) {
|
|
1873
|
+
await this.session.switchConversation(conversationId, job.job_id);
|
|
1874
|
+
}
|
|
1875
|
+
if (completedJobs.length > 0) {
|
|
1876
|
+
this.emit({
|
|
1877
|
+
type: "blocksChanged",
|
|
1878
|
+
conversationId,
|
|
1879
|
+
blocks: this.session.blockBuilder.getBlocks()
|
|
1880
|
+
});
|
|
1881
|
+
this.emit({
|
|
1882
|
+
type: "versionsReady",
|
|
1883
|
+
conversationId,
|
|
1884
|
+
count: completedJobs.length
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
} catch {
|
|
1888
|
+
}
|
|
1889
|
+
this.setState("idle");
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
// ── Internal: set active conversation ─────────────────────────
|
|
1893
|
+
setActiveConversation(id) {
|
|
1894
|
+
this._activeConversationId = id;
|
|
1895
|
+
this.emit({ type: "conversationChanged", conversationId: id });
|
|
1896
|
+
}
|
|
1897
|
+
};
|
|
1456
1898
|
export {
|
|
1457
1899
|
AstralformClient,
|
|
1458
1900
|
AstralformError,
|
|
1459
1901
|
AuthenticationError,
|
|
1460
1902
|
BlockBuilder,
|
|
1903
|
+
ChatEventType,
|
|
1461
1904
|
ChatSession,
|
|
1462
1905
|
ConnectionError,
|
|
1463
1906
|
InMemoryStorage,
|
|
@@ -1465,6 +1908,7 @@ export {
|
|
|
1465
1908
|
RateLimitError,
|
|
1466
1909
|
ServerError,
|
|
1467
1910
|
StreamAbortedError,
|
|
1911
|
+
StreamManager,
|
|
1468
1912
|
ToolRegistry,
|
|
1469
1913
|
generateId,
|
|
1470
1914
|
standardHandlers,
|