@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.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
AstralformError: () => AstralformError,
|
|
25
25
|
AuthenticationError: () => AuthenticationError,
|
|
26
26
|
BlockBuilder: () => BlockBuilder,
|
|
27
|
+
ChatEventType: () => ChatEventType,
|
|
27
28
|
ChatSession: () => ChatSession,
|
|
28
29
|
ConnectionError: () => ConnectionError,
|
|
29
30
|
InMemoryStorage: () => InMemoryStorage,
|
|
@@ -31,6 +32,7 @@ __export(index_exports, {
|
|
|
31
32
|
RateLimitError: () => RateLimitError,
|
|
32
33
|
ServerError: () => ServerError,
|
|
33
34
|
StreamAbortedError: () => StreamAbortedError,
|
|
35
|
+
StreamManager: () => StreamManager,
|
|
34
36
|
ToolRegistry: () => ToolRegistry,
|
|
35
37
|
generateId: () => generateId,
|
|
36
38
|
standardHandlers: () => standardHandlers,
|
|
@@ -372,6 +374,8 @@ var BlockBuilder = class {
|
|
|
372
374
|
this.activeTextId = null;
|
|
373
375
|
this.activeThinkingId = null;
|
|
374
376
|
this.thinkingStartMs = null;
|
|
377
|
+
this.activeEditorId = null;
|
|
378
|
+
this.activeTodoId = null;
|
|
375
379
|
}
|
|
376
380
|
// ── Registration ──────────────────────────────────────────────
|
|
377
381
|
on(eventType, handler) {
|
|
@@ -398,6 +402,8 @@ var BlockBuilder = class {
|
|
|
398
402
|
this.activeTextId = null;
|
|
399
403
|
this.activeThinkingId = null;
|
|
400
404
|
this.thinkingStartMs = null;
|
|
405
|
+
this.activeEditorId = null;
|
|
406
|
+
this.activeTodoId = null;
|
|
401
407
|
}
|
|
402
408
|
setOnChange(fn) {
|
|
403
409
|
this._onChange = fn;
|
|
@@ -623,7 +629,6 @@ var ChatSession = class {
|
|
|
623
629
|
this.thinkingContent = "";
|
|
624
630
|
this.isThinking = false;
|
|
625
631
|
this.activeSubagents = /* @__PURE__ */ new Map();
|
|
626
|
-
this.sources = [];
|
|
627
632
|
this.capsuleOutputs = [];
|
|
628
633
|
this.todos = [];
|
|
629
634
|
this.activeTools = /* @__PURE__ */ new Map();
|
|
@@ -727,7 +732,6 @@ var ChatSession = class {
|
|
|
727
732
|
this.thinkingContent = "";
|
|
728
733
|
this.isThinking = false;
|
|
729
734
|
this.activeSubagents.clear();
|
|
730
|
-
this.sources = [];
|
|
731
735
|
this.capsuleOutputs = [];
|
|
732
736
|
this.todos = [];
|
|
733
737
|
this.activeTools.clear();
|
|
@@ -739,10 +743,12 @@ var ChatSession = class {
|
|
|
739
743
|
try {
|
|
740
744
|
await this.consumeJobStream(request);
|
|
741
745
|
} catch (err) {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
+
if (!(err instanceof DOMException && err.name === "AbortError")) {
|
|
747
|
+
this.emit({
|
|
748
|
+
type: "error",
|
|
749
|
+
error: err instanceof Error ? err : new ConnectionError(String(err))
|
|
750
|
+
});
|
|
751
|
+
}
|
|
746
752
|
} finally {
|
|
747
753
|
this.isStreaming = false;
|
|
748
754
|
this.executingTool = null;
|
|
@@ -895,11 +901,24 @@ var ChatSession = class {
|
|
|
895
901
|
applyEvent(event) {
|
|
896
902
|
switch (event.type) {
|
|
897
903
|
case "user_message":
|
|
898
|
-
this.emit({
|
|
904
|
+
this.emit({
|
|
905
|
+
type: "user_message",
|
|
906
|
+
content: event.content,
|
|
907
|
+
createdAt: event.created_at
|
|
908
|
+
});
|
|
899
909
|
break;
|
|
900
|
-
case "title_generated":
|
|
910
|
+
case "title_generated": {
|
|
911
|
+
if (this.conversationId && event.title) {
|
|
912
|
+
const conv = this.conversations.find(
|
|
913
|
+
(c) => c.id === this.conversationId
|
|
914
|
+
);
|
|
915
|
+
if (conv) {
|
|
916
|
+
conv.title = event.title;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
901
919
|
this.emit({ type: "title_generated", title: event.title });
|
|
902
920
|
break;
|
|
921
|
+
}
|
|
903
922
|
case "message_start":
|
|
904
923
|
if (event.conversation_id && !this.conversationId) {
|
|
905
924
|
this.conversationId = event.conversation_id;
|
|
@@ -922,6 +941,23 @@ var ChatSession = class {
|
|
|
922
941
|
this.isThinking = false;
|
|
923
942
|
this.emit({ type: "thinking_complete" });
|
|
924
943
|
break;
|
|
944
|
+
case "tool_executing":
|
|
945
|
+
this.emit({
|
|
946
|
+
type: "tool_executing",
|
|
947
|
+
name: event.tool,
|
|
948
|
+
call_id: event.call_id
|
|
949
|
+
});
|
|
950
|
+
break;
|
|
951
|
+
case "tool_progress":
|
|
952
|
+
this.emit({
|
|
953
|
+
type: "tool_progress",
|
|
954
|
+
callId: event.call_id,
|
|
955
|
+
tool: event.tool,
|
|
956
|
+
index: event.index,
|
|
957
|
+
total: event.total,
|
|
958
|
+
item: event.item
|
|
959
|
+
});
|
|
960
|
+
break;
|
|
925
961
|
case "message_stop":
|
|
926
962
|
this.emit({
|
|
927
963
|
type: "complete",
|
|
@@ -1031,10 +1067,6 @@ var ChatSession = class {
|
|
|
1031
1067
|
result: event.result
|
|
1032
1068
|
});
|
|
1033
1069
|
break;
|
|
1034
|
-
case "sources":
|
|
1035
|
-
this.sources.push(...event.sources);
|
|
1036
|
-
this.emit({ type: "sources", sources: event.sources });
|
|
1037
|
-
break;
|
|
1038
1070
|
case "capsule_output": {
|
|
1039
1071
|
const capsule = {
|
|
1040
1072
|
toolName: event.tool_name,
|
|
@@ -1070,27 +1102,6 @@ var ChatSession = class {
|
|
|
1070
1102
|
sizeBytes: event.size_bytes
|
|
1071
1103
|
});
|
|
1072
1104
|
break;
|
|
1073
|
-
case "timeline_entry":
|
|
1074
|
-
this.emit({
|
|
1075
|
-
type: "timeline_entry",
|
|
1076
|
-
id: event.id,
|
|
1077
|
-
status: event.status,
|
|
1078
|
-
kind: event.kind,
|
|
1079
|
-
agent_name: event.agent_name,
|
|
1080
|
-
tool_name: event.tool_name,
|
|
1081
|
-
display_name: event.display_name,
|
|
1082
|
-
tool_category: event.tool_category,
|
|
1083
|
-
viewer: event.viewer,
|
|
1084
|
-
call_id: event.call_id,
|
|
1085
|
-
detail: event.detail,
|
|
1086
|
-
started_at: event.started_at,
|
|
1087
|
-
duration_ms: event.duration_ms,
|
|
1088
|
-
output_summary: event.output_summary,
|
|
1089
|
-
sources: event.sources,
|
|
1090
|
-
parent_id: event.parent_id,
|
|
1091
|
-
structured_output: event.structured_output
|
|
1092
|
-
});
|
|
1093
|
-
break;
|
|
1094
1105
|
case "editor_content_start":
|
|
1095
1106
|
this.emit({
|
|
1096
1107
|
type: "editor_content_start",
|
|
@@ -1212,19 +1223,26 @@ var ChatSession = class {
|
|
|
1212
1223
|
this.abortController = null;
|
|
1213
1224
|
}
|
|
1214
1225
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
});
|
|
1219
|
-
this.currentJobId = null;
|
|
1220
|
-
}
|
|
1226
|
+
/** Detach from the SSE stream without cancelling the job.
|
|
1227
|
+
* The backend job keeps running — caller can reconnect later. */
|
|
1228
|
+
detach() {
|
|
1221
1229
|
this.abortController?.abort();
|
|
1222
1230
|
this.abortController = null;
|
|
1223
1231
|
this.isStreaming = false;
|
|
1224
1232
|
this.streamingContent = "";
|
|
1225
1233
|
this.executingTool = null;
|
|
1234
|
+
this.blockBuilder.reset();
|
|
1226
1235
|
this.emit({ type: "disconnected" });
|
|
1227
1236
|
}
|
|
1237
|
+
/** Stop the job and disconnect (explicit user action). */
|
|
1238
|
+
disconnect() {
|
|
1239
|
+
if (this.currentJobId) {
|
|
1240
|
+
this.client.cancelJob(this.currentJobId).catch(() => {
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
this.detach();
|
|
1244
|
+
this.currentJobId = null;
|
|
1245
|
+
}
|
|
1228
1246
|
async createNewConversation() {
|
|
1229
1247
|
const id = generateId();
|
|
1230
1248
|
const conversation = await this.storage.createConversation(
|
|
@@ -1292,10 +1310,31 @@ function finalizeThinking(builder) {
|
|
|
1292
1310
|
builder.thinkingStartMs = null;
|
|
1293
1311
|
}
|
|
1294
1312
|
}
|
|
1313
|
+
function finalizeEditor(builder) {
|
|
1314
|
+
if (builder.activeEditorId) {
|
|
1315
|
+
builder.patchBlock(builder.activeEditorId, {
|
|
1316
|
+
isStreaming: false
|
|
1317
|
+
});
|
|
1318
|
+
builder.activeEditorId = null;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1295
1321
|
var handleUserMessage = (event, builder) => {
|
|
1296
|
-
if (builder.findBlock((b) => b.type === "user")) return;
|
|
1297
1322
|
const e = event;
|
|
1298
|
-
|
|
1323
|
+
const existing = builder.findBlock((b) => b.type === "user");
|
|
1324
|
+
if (existing) {
|
|
1325
|
+
if (e.createdAt) {
|
|
1326
|
+
builder.patchBlock(existing.id, {
|
|
1327
|
+
createdAt: e.createdAt
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
builder.addBlock({
|
|
1333
|
+
type: "user",
|
|
1334
|
+
id: builder.nextId(),
|
|
1335
|
+
content: e.content,
|
|
1336
|
+
createdAt: e.createdAt
|
|
1337
|
+
});
|
|
1299
1338
|
};
|
|
1300
1339
|
var handleChunk = (event, builder) => {
|
|
1301
1340
|
const e = event;
|
|
@@ -1337,12 +1376,26 @@ var handleToolCall = (event, builder) => {
|
|
|
1337
1376
|
var handleToolExecuting = (event, builder) => {
|
|
1338
1377
|
const e = event;
|
|
1339
1378
|
const block = builder.findBlock(
|
|
1340
|
-
(b) => b.type === "tool" && b.toolName === e.name && b.status === "calling"
|
|
1379
|
+
(b) => b.type === "tool" && (e.call_id ? b.callId === e.call_id : b.toolName === e.name) && b.status === "calling"
|
|
1341
1380
|
);
|
|
1342
1381
|
if (block) {
|
|
1343
1382
|
builder.patchBlock(block.id, { status: "executing" });
|
|
1344
1383
|
}
|
|
1345
1384
|
};
|
|
1385
|
+
var handleToolProgress = (event, builder) => {
|
|
1386
|
+
const e = event;
|
|
1387
|
+
const block = builder.findBlock(
|
|
1388
|
+
(b) => b.type === "tool" && b.callId === e.callId
|
|
1389
|
+
);
|
|
1390
|
+
if (block && block.type === "tool") {
|
|
1391
|
+
const sources = block.sources ? [...block.sources] : [];
|
|
1392
|
+
sources.push(e.item);
|
|
1393
|
+
builder.patchBlock(block.id, {
|
|
1394
|
+
sources,
|
|
1395
|
+
status: "executing"
|
|
1396
|
+
});
|
|
1397
|
+
}
|
|
1398
|
+
};
|
|
1346
1399
|
var handleToolEnd = (event, builder) => {
|
|
1347
1400
|
const e = event;
|
|
1348
1401
|
const callId = e.type === "tool_end" ? e.callId : void 0;
|
|
@@ -1455,6 +1508,7 @@ var handleSubagentEnd = (event, builder) => {
|
|
|
1455
1508
|
var handleComplete = (_event, builder) => {
|
|
1456
1509
|
finalizeText(builder);
|
|
1457
1510
|
finalizeThinking(builder);
|
|
1511
|
+
finalizeEditor(builder);
|
|
1458
1512
|
for (const b of builder.getBlocks()) {
|
|
1459
1513
|
if (b.type === "tool" && b.status !== "completed") {
|
|
1460
1514
|
builder.patchBlock(b.id, { status: "completed" });
|
|
@@ -1474,31 +1528,422 @@ var handleError = (event, builder) => {
|
|
|
1474
1528
|
var handleDisconnected = (_event, builder) => {
|
|
1475
1529
|
finalizeText(builder);
|
|
1476
1530
|
finalizeThinking(builder);
|
|
1531
|
+
finalizeEditor(builder);
|
|
1532
|
+
};
|
|
1533
|
+
var handleCapsuleOutputChunk = (event, builder) => {
|
|
1534
|
+
const e = event;
|
|
1535
|
+
const block = builder.findBlock(
|
|
1536
|
+
(b) => b.type === "capsule" && b.callId === e.callId
|
|
1537
|
+
);
|
|
1538
|
+
if (block && block.type === "capsule") {
|
|
1539
|
+
builder.patchBlock(block.id, {
|
|
1540
|
+
output: block.output + e.chunk
|
|
1541
|
+
});
|
|
1542
|
+
} else {
|
|
1543
|
+
builder.addBlock({
|
|
1544
|
+
type: "capsule",
|
|
1545
|
+
id: builder.nextId(),
|
|
1546
|
+
callId: e.callId,
|
|
1547
|
+
toolName: "",
|
|
1548
|
+
output: e.chunk,
|
|
1549
|
+
isActive: true
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
var handleCapsuleOutput = (event, builder) => {
|
|
1554
|
+
const e = event;
|
|
1555
|
+
const block = builder.findBlock(
|
|
1556
|
+
(b) => b.type === "capsule" && b.callId === (e.callId ?? "")
|
|
1557
|
+
);
|
|
1558
|
+
if (block) {
|
|
1559
|
+
builder.patchBlock(block.id, {
|
|
1560
|
+
output: e.output,
|
|
1561
|
+
command: e.command,
|
|
1562
|
+
toolName: e.toolName,
|
|
1563
|
+
durationMs: e.durationMs,
|
|
1564
|
+
isActive: false
|
|
1565
|
+
});
|
|
1566
|
+
} else {
|
|
1567
|
+
builder.addBlock({
|
|
1568
|
+
type: "capsule",
|
|
1569
|
+
id: builder.nextId(),
|
|
1570
|
+
callId: e.callId ?? "",
|
|
1571
|
+
toolName: e.toolName,
|
|
1572
|
+
command: e.command,
|
|
1573
|
+
output: e.output,
|
|
1574
|
+
durationMs: e.durationMs,
|
|
1575
|
+
isActive: false
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
};
|
|
1579
|
+
var handleAssetCreated = (event, builder) => {
|
|
1580
|
+
const e = event;
|
|
1581
|
+
builder.addBlock({
|
|
1582
|
+
type: "asset",
|
|
1583
|
+
id: builder.nextId(),
|
|
1584
|
+
assetId: e.assetId,
|
|
1585
|
+
name: e.name,
|
|
1586
|
+
url: e.url,
|
|
1587
|
+
mediaType: e.mediaType,
|
|
1588
|
+
sizeBytes: e.sizeBytes
|
|
1589
|
+
});
|
|
1590
|
+
};
|
|
1591
|
+
var handleTodoUpdate = (event, builder) => {
|
|
1592
|
+
const e = event;
|
|
1593
|
+
if (builder.activeTodoId) {
|
|
1594
|
+
builder.patchBlock(builder.activeTodoId, {
|
|
1595
|
+
todos: e.todos
|
|
1596
|
+
});
|
|
1597
|
+
} else {
|
|
1598
|
+
const id = builder.nextId();
|
|
1599
|
+
builder.activeTodoId = id;
|
|
1600
|
+
builder.addBlock({
|
|
1601
|
+
type: "todo",
|
|
1602
|
+
id,
|
|
1603
|
+
todos: e.todos
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
};
|
|
1607
|
+
var handleEditorContentStart = (event, builder) => {
|
|
1608
|
+
const e = event;
|
|
1609
|
+
const id = builder.nextId();
|
|
1610
|
+
builder.activeEditorId = id;
|
|
1611
|
+
builder.addBlock({
|
|
1612
|
+
type: "editor",
|
|
1613
|
+
id,
|
|
1614
|
+
callId: e.callId,
|
|
1615
|
+
path: e.path,
|
|
1616
|
+
language: e.language,
|
|
1617
|
+
content: "",
|
|
1618
|
+
isStreaming: true
|
|
1619
|
+
});
|
|
1620
|
+
};
|
|
1621
|
+
var handleEditorContentDelta = (event, builder) => {
|
|
1622
|
+
const e = event;
|
|
1623
|
+
const block = builder.findBlock(
|
|
1624
|
+
(b) => b.type === "editor" && b.callId === e.callId
|
|
1625
|
+
);
|
|
1626
|
+
if (block && block.type === "editor") {
|
|
1627
|
+
builder.patchBlock(block.id, {
|
|
1628
|
+
content: block.content + e.delta
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
};
|
|
1632
|
+
var handleEditorContentEnd = (event, builder) => {
|
|
1633
|
+
const e = event;
|
|
1634
|
+
const block = builder.findBlock(
|
|
1635
|
+
(b) => b.type === "editor" && b.callId === e.callId
|
|
1636
|
+
);
|
|
1637
|
+
if (block) {
|
|
1638
|
+
builder.patchBlock(block.id, {
|
|
1639
|
+
isStreaming: false
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
builder.activeEditorId = null;
|
|
1643
|
+
};
|
|
1644
|
+
var noop = () => {
|
|
1477
1645
|
};
|
|
1478
1646
|
var standardHandlers = {
|
|
1479
1647
|
user_message: handleUserMessage,
|
|
1480
1648
|
chunk: handleChunk,
|
|
1481
1649
|
tool_call: handleToolCall,
|
|
1482
1650
|
tool_executing: handleToolExecuting,
|
|
1651
|
+
tool_progress: handleToolProgress,
|
|
1483
1652
|
tool_completed: handleToolEnd,
|
|
1484
1653
|
tool_end: handleToolEnd,
|
|
1485
1654
|
agent_start: handleAgentStart,
|
|
1655
|
+
agent_end: noop,
|
|
1486
1656
|
thinking_delta: handleThinkingDelta,
|
|
1487
1657
|
thinking_complete: handleThinkingComplete,
|
|
1488
1658
|
subagent_start: handleSubagentStart,
|
|
1489
1659
|
subagent_chunk: handleSubagentChunk,
|
|
1490
1660
|
subagent_update: handleSubagentUpdate,
|
|
1491
1661
|
subagent_end: handleSubagentEnd,
|
|
1662
|
+
subagent_tool_use: noop,
|
|
1663
|
+
capsule_output: handleCapsuleOutput,
|
|
1664
|
+
capsule_output_chunk: handleCapsuleOutputChunk,
|
|
1665
|
+
asset_created: handleAssetCreated,
|
|
1666
|
+
todo_update: handleTodoUpdate,
|
|
1667
|
+
editor_content_start: handleEditorContentStart,
|
|
1668
|
+
editor_content_delta: handleEditorContentDelta,
|
|
1669
|
+
editor_content_end: handleEditorContentEnd,
|
|
1670
|
+
retry: noop,
|
|
1492
1671
|
complete: handleComplete,
|
|
1493
1672
|
error: handleError,
|
|
1494
1673
|
disconnected: handleDisconnected
|
|
1495
1674
|
};
|
|
1675
|
+
|
|
1676
|
+
// src/types.ts
|
|
1677
|
+
var ChatEventType = {
|
|
1678
|
+
Connected: "connected",
|
|
1679
|
+
BlocksChanged: "blocks_changed",
|
|
1680
|
+
UserMessage: "user_message",
|
|
1681
|
+
TitleGenerated: "title_generated",
|
|
1682
|
+
ModelInfo: "model_info",
|
|
1683
|
+
Chunk: "chunk",
|
|
1684
|
+
ToolCall: "tool_call",
|
|
1685
|
+
ToolExecuting: "tool_executing",
|
|
1686
|
+
ToolProgress: "tool_progress",
|
|
1687
|
+
ToolCompleted: "tool_completed",
|
|
1688
|
+
ToolEnd: "tool_end",
|
|
1689
|
+
AgentStart: "agent_start",
|
|
1690
|
+
AgentEnd: "agent_end",
|
|
1691
|
+
ThinkingDelta: "thinking_delta",
|
|
1692
|
+
ThinkingComplete: "thinking_complete",
|
|
1693
|
+
SubagentStart: "subagent_start",
|
|
1694
|
+
SubagentChunk: "subagent_chunk",
|
|
1695
|
+
SubagentUpdate: "subagent_update",
|
|
1696
|
+
SubagentEnd: "subagent_end",
|
|
1697
|
+
SubagentToolUse: "subagent_tool_use",
|
|
1698
|
+
CapsuleOutput: "capsule_output",
|
|
1699
|
+
CapsuleOutputChunk: "capsule_output_chunk",
|
|
1700
|
+
AssetCreated: "asset_created",
|
|
1701
|
+
TodoUpdate: "todo_update",
|
|
1702
|
+
EditorContentStart: "editor_content_start",
|
|
1703
|
+
EditorContentDelta: "editor_content_delta",
|
|
1704
|
+
EditorContentEnd: "editor_content_end",
|
|
1705
|
+
Complete: "complete",
|
|
1706
|
+
Error: "error",
|
|
1707
|
+
Disconnected: "disconnected",
|
|
1708
|
+
Retry: "retry"
|
|
1709
|
+
};
|
|
1710
|
+
|
|
1711
|
+
// src/stream-manager.ts
|
|
1712
|
+
var StreamManager = class {
|
|
1713
|
+
constructor(session) {
|
|
1714
|
+
this._state = "idle";
|
|
1715
|
+
this._activeConversationId = null;
|
|
1716
|
+
this._backgroundJobs = /* @__PURE__ */ new Map();
|
|
1717
|
+
this.handlers = [];
|
|
1718
|
+
this.unsub = null;
|
|
1719
|
+
this.session = session;
|
|
1720
|
+
this.attach();
|
|
1721
|
+
}
|
|
1722
|
+
// ── Public state ──────────────────────────────────────────────
|
|
1723
|
+
get state() {
|
|
1724
|
+
return this._state;
|
|
1725
|
+
}
|
|
1726
|
+
get activeConversationId() {
|
|
1727
|
+
return this._activeConversationId;
|
|
1728
|
+
}
|
|
1729
|
+
get backgroundJobs() {
|
|
1730
|
+
return this._backgroundJobs;
|
|
1731
|
+
}
|
|
1732
|
+
// ── Event subscription ────────────────────────────────────────
|
|
1733
|
+
on(handler) {
|
|
1734
|
+
this.handlers.push(handler);
|
|
1735
|
+
return () => {
|
|
1736
|
+
this.handlers = this.handlers.filter((h) => h !== handler);
|
|
1737
|
+
};
|
|
1738
|
+
}
|
|
1739
|
+
emit(event) {
|
|
1740
|
+
for (const handler of this.handlers) {
|
|
1741
|
+
try {
|
|
1742
|
+
handler(event);
|
|
1743
|
+
} catch {
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
setState(state) {
|
|
1748
|
+
this._state = state;
|
|
1749
|
+
this.emit({
|
|
1750
|
+
type: "stateChange",
|
|
1751
|
+
state,
|
|
1752
|
+
conversationId: this._activeConversationId
|
|
1753
|
+
});
|
|
1754
|
+
}
|
|
1755
|
+
// ── Session event wiring ──────────────────────────────────────
|
|
1756
|
+
attach() {
|
|
1757
|
+
this.unsub = this.session.on((event) => {
|
|
1758
|
+
this.onSessionEvent(event);
|
|
1759
|
+
});
|
|
1760
|
+
}
|
|
1761
|
+
onSessionEvent(event) {
|
|
1762
|
+
const convId = this.session.conversationId;
|
|
1763
|
+
if (event.type === ChatEventType.BlocksChanged) {
|
|
1764
|
+
if (this._state === "streaming" && convId) {
|
|
1765
|
+
this.emit({
|
|
1766
|
+
type: "blocksChanged",
|
|
1767
|
+
conversationId: convId,
|
|
1768
|
+
blocks: event.blocks
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
return;
|
|
1772
|
+
}
|
|
1773
|
+
this.emit({
|
|
1774
|
+
type: "event",
|
|
1775
|
+
conversationId: convId,
|
|
1776
|
+
event
|
|
1777
|
+
});
|
|
1778
|
+
if (event.type === ChatEventType.Complete) {
|
|
1779
|
+
if (this._state === "streaming") {
|
|
1780
|
+
this.setState("idle");
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
// ── Send ──────────────────────────────────────────────────────
|
|
1785
|
+
async send(content, options) {
|
|
1786
|
+
if (this._state === "streaming") return;
|
|
1787
|
+
if (!this._activeConversationId) {
|
|
1788
|
+
const id = await this.session.createNewConversation();
|
|
1789
|
+
this.setActiveConversation(id);
|
|
1790
|
+
}
|
|
1791
|
+
this.prepareUserBlock(content);
|
|
1792
|
+
this.setState("streaming");
|
|
1793
|
+
try {
|
|
1794
|
+
await this.session.send(content, {
|
|
1795
|
+
enableSearch: options?.enableSearch,
|
|
1796
|
+
agentName: options?.agentName,
|
|
1797
|
+
uploadIds: options?.uploadIds
|
|
1798
|
+
});
|
|
1799
|
+
} catch {
|
|
1800
|
+
}
|
|
1801
|
+
this.finalizeStream();
|
|
1802
|
+
}
|
|
1803
|
+
// ── Regenerate ────────────────────────────────────────────────
|
|
1804
|
+
async regenerate() {
|
|
1805
|
+
if (this._state === "streaming") return;
|
|
1806
|
+
const userMsgs = this.session.messages.filter(
|
|
1807
|
+
(m) => m.role === "user"
|
|
1808
|
+
);
|
|
1809
|
+
const lastUserMsg = userMsgs[userMsgs.length - 1];
|
|
1810
|
+
if (!lastUserMsg) return;
|
|
1811
|
+
this.prepareUserBlock(lastUserMsg.content);
|
|
1812
|
+
this.setState("streaming");
|
|
1813
|
+
try {
|
|
1814
|
+
await this.session.resendFromCheckpoint(
|
|
1815
|
+
lastUserMsg.id,
|
|
1816
|
+
lastUserMsg.content
|
|
1817
|
+
);
|
|
1818
|
+
} catch {
|
|
1819
|
+
}
|
|
1820
|
+
this.finalizeStream();
|
|
1821
|
+
}
|
|
1822
|
+
// ── Switch conversation ───────────────────────────────────────
|
|
1823
|
+
async switchTo(conversationId) {
|
|
1824
|
+
if (conversationId === this._activeConversationId) return;
|
|
1825
|
+
if (this._state === "streaming") {
|
|
1826
|
+
const oldConvId = this._activeConversationId;
|
|
1827
|
+
const jobId = this.session.currentJobId;
|
|
1828
|
+
if (oldConvId && jobId) {
|
|
1829
|
+
this._backgroundJobs.set(oldConvId, jobId);
|
|
1830
|
+
this.emit({
|
|
1831
|
+
type: "backgroundJobsChanged",
|
|
1832
|
+
jobs: this._backgroundJobs
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1835
|
+
this.session.detach();
|
|
1836
|
+
}
|
|
1837
|
+
if (this._backgroundJobs.has(conversationId)) {
|
|
1838
|
+
this._backgroundJobs.delete(conversationId);
|
|
1839
|
+
this.emit({
|
|
1840
|
+
type: "backgroundJobsChanged",
|
|
1841
|
+
jobs: this._backgroundJobs
|
|
1842
|
+
});
|
|
1843
|
+
}
|
|
1844
|
+
this.setActiveConversation(conversationId);
|
|
1845
|
+
await this.restore(conversationId);
|
|
1846
|
+
}
|
|
1847
|
+
// ── Create / delete conversation ──────────────────────────────
|
|
1848
|
+
async createConversation() {
|
|
1849
|
+
const id = await this.session.createNewConversation();
|
|
1850
|
+
this.setActiveConversation(id);
|
|
1851
|
+
return id;
|
|
1852
|
+
}
|
|
1853
|
+
async deleteConversation(id) {
|
|
1854
|
+
await this.session.deleteConversation(id);
|
|
1855
|
+
this._backgroundJobs.delete(id);
|
|
1856
|
+
if (this._activeConversationId === id) {
|
|
1857
|
+
this._activeConversationId = null;
|
|
1858
|
+
this.emit({ type: "conversationChanged", conversationId: null });
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
// ── Stop (explicit cancel) ────────────────────────────────────
|
|
1862
|
+
stop() {
|
|
1863
|
+
this.session.disconnect();
|
|
1864
|
+
this.setState("idle");
|
|
1865
|
+
}
|
|
1866
|
+
// ── Cleanup ───────────────────────────────────────────────────
|
|
1867
|
+
destroy() {
|
|
1868
|
+
if (this.unsub) {
|
|
1869
|
+
this.unsub();
|
|
1870
|
+
this.unsub = null;
|
|
1871
|
+
}
|
|
1872
|
+
this.handlers = [];
|
|
1873
|
+
}
|
|
1874
|
+
// ── Internal: helpers ──────────────────────────────────────────
|
|
1875
|
+
prepareUserBlock(content) {
|
|
1876
|
+
this.session.blockBuilder.reset();
|
|
1877
|
+
this.session.blockBuilder.addBlock({
|
|
1878
|
+
type: "user",
|
|
1879
|
+
id: this.session.blockBuilder.nextId(),
|
|
1880
|
+
content
|
|
1881
|
+
});
|
|
1882
|
+
}
|
|
1883
|
+
finalizeStream() {
|
|
1884
|
+
if (this._state === "streaming") {
|
|
1885
|
+
this.setState("idle");
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
// ── Internal: restore ─────────────────────────────────────────
|
|
1889
|
+
async restore(conversationId) {
|
|
1890
|
+
this.setState("restoring");
|
|
1891
|
+
let activeJobId = null;
|
|
1892
|
+
try {
|
|
1893
|
+
const res = await this.session.client.get(`/v1/conversations/${encodeURIComponent(conversationId)}/active-job`);
|
|
1894
|
+
activeJobId = res.job_id ?? null;
|
|
1895
|
+
} catch {
|
|
1896
|
+
}
|
|
1897
|
+
if (activeJobId) {
|
|
1898
|
+
await this.session.loadConversation(conversationId);
|
|
1899
|
+
this.setState("streaming");
|
|
1900
|
+
try {
|
|
1901
|
+
await this.session.reconnectToJob(activeJobId);
|
|
1902
|
+
} catch {
|
|
1903
|
+
}
|
|
1904
|
+
if (this._state === "streaming") {
|
|
1905
|
+
this.setState("idle");
|
|
1906
|
+
}
|
|
1907
|
+
} else {
|
|
1908
|
+
await this.session.loadConversation(conversationId);
|
|
1909
|
+
try {
|
|
1910
|
+
const jobs = await this.session.client.get(`/v1/conversations/${encodeURIComponent(conversationId)}/jobs`);
|
|
1911
|
+
const completedJobs = jobs.filter(
|
|
1912
|
+
(j) => j.status === "completed"
|
|
1913
|
+
);
|
|
1914
|
+
for (const job of completedJobs) {
|
|
1915
|
+
await this.session.switchConversation(conversationId, job.job_id);
|
|
1916
|
+
}
|
|
1917
|
+
if (completedJobs.length > 0) {
|
|
1918
|
+
this.emit({
|
|
1919
|
+
type: "blocksChanged",
|
|
1920
|
+
conversationId,
|
|
1921
|
+
blocks: this.session.blockBuilder.getBlocks()
|
|
1922
|
+
});
|
|
1923
|
+
this.emit({
|
|
1924
|
+
type: "versionsReady",
|
|
1925
|
+
conversationId,
|
|
1926
|
+
count: completedJobs.length
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
} catch {
|
|
1930
|
+
}
|
|
1931
|
+
this.setState("idle");
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
// ── Internal: set active conversation ─────────────────────────
|
|
1935
|
+
setActiveConversation(id) {
|
|
1936
|
+
this._activeConversationId = id;
|
|
1937
|
+
this.emit({ type: "conversationChanged", conversationId: id });
|
|
1938
|
+
}
|
|
1939
|
+
};
|
|
1496
1940
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1497
1941
|
0 && (module.exports = {
|
|
1498
1942
|
AstralformClient,
|
|
1499
1943
|
AstralformError,
|
|
1500
1944
|
AuthenticationError,
|
|
1501
1945
|
BlockBuilder,
|
|
1946
|
+
ChatEventType,
|
|
1502
1947
|
ChatSession,
|
|
1503
1948
|
ConnectionError,
|
|
1504
1949
|
InMemoryStorage,
|
|
@@ -1506,6 +1951,7 @@ var standardHandlers = {
|
|
|
1506
1951
|
RateLimitError,
|
|
1507
1952
|
ServerError,
|
|
1508
1953
|
StreamAbortedError,
|
|
1954
|
+
StreamManager,
|
|
1509
1955
|
ToolRegistry,
|
|
1510
1956
|
generateId,
|
|
1511
1957
|
standardHandlers,
|