@junctionpanel/server 0.1.54 → 0.1.55
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/server/client/daemon-client.d.ts +13 -0
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +89 -18
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/activity-curator.d.ts.map +1 -1
- package/dist/server/server/agent/activity-curator.js +12 -0
- package/dist/server/server/agent/activity-curator.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +8 -0
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +175 -29
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-metadata-generator.d.ts.map +1 -1
- package/dist/server/server/agent/agent-metadata-generator.js +11 -2
- package/dist/server/server/agent/agent-metadata-generator.js.map +1 -1
- package/dist/server/server/agent/agent-projections.d.ts.map +1 -1
- package/dist/server/server/agent/agent-projections.js +0 -1
- package/dist/server/server/agent/agent-projections.js.map +1 -1
- package/dist/server/server/agent/agent-response-loop.d.ts +27 -0
- package/dist/server/server/agent/agent-response-loop.d.ts.map +1 -1
- package/dist/server/server/agent/agent-response-loop.js +78 -4
- package/dist/server/server/agent/agent-response-loop.js.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +17 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.js.map +1 -1
- package/dist/server/server/agent/agent-storage.d.ts +0 -3
- package/dist/server/server/agent/agent-storage.d.ts.map +1 -1
- package/dist/server/server/agent/agent-storage.js +0 -1
- package/dist/server/server/agent/agent-storage.js.map +1 -1
- package/dist/server/server/agent/provider-model-cache.d.ts +14 -0
- package/dist/server/server/agent/provider-model-cache.d.ts.map +1 -0
- package/dist/server/server/agent/provider-model-cache.js +71 -0
- package/dist/server/server/agent/provider-model-cache.js.map +1 -0
- package/dist/server/server/agent/providers/claude/model-catalog.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/model-catalog.js +15 -1
- package/dist/server/server/agent/providers/claude/model-catalog.js.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.d.ts +1 -0
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.js +43 -12
- package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
- package/dist/server/server/agent/providers/gemini-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/gemini-agent.js +36 -1
- package/dist/server/server/agent/providers/gemini-agent.js.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.js +8 -2
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
- package/dist/server/server/persistence-hooks.js +11 -1
- package/dist/server/server/persistence-hooks.js.map +1 -1
- package/dist/server/server/session.d.ts +13 -0
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +416 -170
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/shared/messages.d.ts +16 -0
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +19 -0
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/server/shared/permission-questions.d.ts +43 -0
- package/dist/server/shared/permission-questions.d.ts.map +1 -0
- package/dist/server/shared/permission-questions.js +234 -0
- package/dist/server/shared/permission-questions.js.map +1 -0
- package/dist/server/utils/checkout-git.d.ts +1 -0
- package/dist/server/utils/checkout-git.d.ts.map +1 -1
- package/dist/server/utils/checkout-git.js +19 -6
- package/dist/server/utils/checkout-git.js.map +1 -1
- package/package.json +2 -2
|
@@ -8,7 +8,16 @@ import { AGENT_PROVIDER_IDS } from "./provider-manifest.js";
|
|
|
8
8
|
import { buildPermissionRecoveryFingerprint } from "./agent-permission-fingerprint.js";
|
|
9
9
|
import { isCodexPlanModeEnabled, normalizeCodexModeId, setCodexPlanModeEnabled, } from "./codex-config.js";
|
|
10
10
|
import { getPendingPlanReviewFingerprint, hasPendingPlanReview, } from "./pending-plan-review.js";
|
|
11
|
+
import { extractPermissionQuestionAnswersFromResponse, formatPermissionQuestionAnswers, isInteractiveQuestionPermission, } from "../../shared/permission-questions.js";
|
|
11
12
|
export { AGENT_LIFECYCLE_STATUSES };
|
|
13
|
+
function toPersistedPermissionResolution(resolution) {
|
|
14
|
+
return resolution.behavior === "deny"
|
|
15
|
+
? {
|
|
16
|
+
behavior: "deny",
|
|
17
|
+
message: resolution.message,
|
|
18
|
+
}
|
|
19
|
+
: { behavior: "allow" };
|
|
20
|
+
}
|
|
12
21
|
function attachPersistenceCwd(handle, cwd) {
|
|
13
22
|
if (!handle) {
|
|
14
23
|
return null;
|
|
@@ -157,6 +166,8 @@ export class AgentManager {
|
|
|
157
166
|
this.pendingUserInterruptAgents = new Set();
|
|
158
167
|
this.userInterruptedAgents = new Set();
|
|
159
168
|
this.backgroundTasks = new Set();
|
|
169
|
+
this.backgroundPersistQueuedAgents = new Set();
|
|
170
|
+
this.backgroundPersistDirtyAgents = new Set();
|
|
160
171
|
this.liveEventPumps = new Map();
|
|
161
172
|
this.liveEventBacklog = new Map();
|
|
162
173
|
this.liveEventBacklogFlushTimers = new Map();
|
|
@@ -511,6 +522,9 @@ export class AgentManager {
|
|
|
511
522
|
const session = handle
|
|
512
523
|
? await client.resumeSession(handle, normalizedConfig)
|
|
513
524
|
: await client.createSession(normalizedConfig);
|
|
525
|
+
if (this.backgroundPersistQueuedAgents.has(agentId)) {
|
|
526
|
+
this.backgroundPersistDirtyAgents.add(agentId);
|
|
527
|
+
}
|
|
514
528
|
// Remove the existing agent entry before swapping sessions
|
|
515
529
|
this.agents.delete(agentId);
|
|
516
530
|
this.liveEventPumps.delete(agentId);
|
|
@@ -552,6 +566,8 @@ export class AgentManager {
|
|
|
552
566
|
this.suppressedPermissionAttentionKeys.delete(agentId);
|
|
553
567
|
this.pendingUserInterruptAgents.delete(agentId);
|
|
554
568
|
this.userInterruptedAgents.delete(agentId);
|
|
569
|
+
this.backgroundPersistQueuedAgents.delete(agentId);
|
|
570
|
+
this.backgroundPersistDirtyAgents.delete(agentId);
|
|
555
571
|
const session = agent.session;
|
|
556
572
|
const closedAgent = {
|
|
557
573
|
...agent,
|
|
@@ -927,9 +943,18 @@ export class AgentManager {
|
|
|
927
943
|
async respondToPermission(agentId, requestId, response) {
|
|
928
944
|
const agent = this.requireAgent(agentId);
|
|
929
945
|
const pendingRequest = agent.pendingPermissions.get(requestId) ?? null;
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
946
|
+
if (pendingRequest &&
|
|
947
|
+
response.behavior === "allow" &&
|
|
948
|
+
isInteractiveQuestionPermission(pendingRequest)) {
|
|
949
|
+
const answers = extractPermissionQuestionAnswersFromResponse(pendingRequest, response);
|
|
950
|
+
const summary = formatPermissionQuestionAnswers(pendingRequest, answers).trim();
|
|
951
|
+
if (summary.length > 0) {
|
|
952
|
+
this.recordUserMessage(agentId, summary, {
|
|
953
|
+
emitState: false,
|
|
954
|
+
messageId: `permission-answer:${requestId}`,
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
}
|
|
933
958
|
if (pendingRequest?.kind === "plan" &&
|
|
934
959
|
response.behavior === "deny" &&
|
|
935
960
|
typeof response.message === "string") {
|
|
@@ -941,6 +966,14 @@ export class AgentManager {
|
|
|
941
966
|
});
|
|
942
967
|
}
|
|
943
968
|
}
|
|
969
|
+
await agent.session.respondToPermission(requestId, response);
|
|
970
|
+
agent.pendingPermissions.delete(requestId);
|
|
971
|
+
this.clearAttentionForUserEngagement(agent);
|
|
972
|
+
this.recordPermissionResolutionTimelineItem(agent, requestId, response, {
|
|
973
|
+
provider: agent.provider,
|
|
974
|
+
pendingRequest,
|
|
975
|
+
dispatchTimeline: true,
|
|
976
|
+
});
|
|
944
977
|
// Update currentModeId - the session may have changed mode internally
|
|
945
978
|
// (e.g., plan approval changes mode from "plan" to "acceptEdits")
|
|
946
979
|
try {
|
|
@@ -1008,15 +1041,14 @@ export class AgentManager {
|
|
|
1008
1041
|
// block before it consumes the turn_canceled event, skipping our cleanup code.
|
|
1009
1042
|
if (agent.pendingPermissions.size > 0) {
|
|
1010
1043
|
for (const [requestId] of agent.pendingPermissions) {
|
|
1011
|
-
this.
|
|
1012
|
-
type: "permission_resolved",
|
|
1044
|
+
this.resolvePendingPermission(agent, requestId, { behavior: "deny", message: "Interrupted" }, {
|
|
1013
1045
|
provider: agent.provider,
|
|
1014
|
-
|
|
1015
|
-
|
|
1046
|
+
dispatchEvent: true,
|
|
1047
|
+
dispatchTimeline: true,
|
|
1016
1048
|
});
|
|
1017
1049
|
}
|
|
1018
|
-
agent.pendingPermissions.clear();
|
|
1019
1050
|
this.emitState(agent);
|
|
1051
|
+
await this.persistSnapshot(agent);
|
|
1020
1052
|
}
|
|
1021
1053
|
return true;
|
|
1022
1054
|
}
|
|
@@ -1249,7 +1281,9 @@ export class AgentManager {
|
|
|
1249
1281
|
this.userInterruptedAgents.delete(resolvedAgentId);
|
|
1250
1282
|
const initialPersistedTitle = await this.resolveInitialPersistedTitle(resolvedAgentId, config);
|
|
1251
1283
|
const now = new Date();
|
|
1252
|
-
const initialTimeline = options?.timeline
|
|
1284
|
+
const initialTimeline = options?.timeline
|
|
1285
|
+
? [...options.timeline]
|
|
1286
|
+
: options?.timelineRows?.map((row) => row.item) ?? [];
|
|
1253
1287
|
const initialTimelineRows = options?.timelineRows?.length
|
|
1254
1288
|
? options.timelineRows.map((row) => ({ ...row }))
|
|
1255
1289
|
: this.buildTimelineRowsFromItems(initialTimeline, options?.timelineNextSeq ?? 1, (options?.updatedAt ?? options?.createdAt ?? now).toISOString());
|
|
@@ -1416,6 +1450,7 @@ export class AgentManager {
|
|
|
1416
1450
|
}
|
|
1417
1451
|
return [[messageId, row.item.text]];
|
|
1418
1452
|
}));
|
|
1453
|
+
const initialTimelineRowCount = agent.timelineRows.length;
|
|
1419
1454
|
try {
|
|
1420
1455
|
for await (const event of agent.session.streamHistory()) {
|
|
1421
1456
|
if (event.type === "timeline") {
|
|
@@ -1438,6 +1473,9 @@ export class AgentManager {
|
|
|
1438
1473
|
catch {
|
|
1439
1474
|
// ignore history failures
|
|
1440
1475
|
}
|
|
1476
|
+
if (agent.timelineRows.length > initialTimelineRowCount) {
|
|
1477
|
+
await this.persistSnapshot(agent);
|
|
1478
|
+
}
|
|
1441
1479
|
}
|
|
1442
1480
|
handleStreamEvent(agent, event, options) {
|
|
1443
1481
|
// Only update timestamp for live events, not history replay
|
|
@@ -1445,6 +1483,7 @@ export class AgentManager {
|
|
|
1445
1483
|
this.touchUpdatedAt(agent);
|
|
1446
1484
|
}
|
|
1447
1485
|
let timelineRow = null;
|
|
1486
|
+
let shouldPersistSnapshot = false;
|
|
1448
1487
|
switch (event.type) {
|
|
1449
1488
|
case "thread_started":
|
|
1450
1489
|
// Update persistence with the new session ID from the provider.
|
|
@@ -1458,6 +1497,7 @@ export class AgentManager {
|
|
|
1458
1497
|
this.emitState(agent);
|
|
1459
1498
|
}
|
|
1460
1499
|
}
|
|
1500
|
+
shouldPersistSnapshot = true;
|
|
1461
1501
|
}
|
|
1462
1502
|
break;
|
|
1463
1503
|
case "timeline":
|
|
@@ -1479,6 +1519,7 @@ export class AgentManager {
|
|
|
1479
1519
|
break;
|
|
1480
1520
|
}
|
|
1481
1521
|
timelineRow = this.recordTimeline(agent, event.item);
|
|
1522
|
+
shouldPersistSnapshot = true;
|
|
1482
1523
|
if (!options?.fromHistory &&
|
|
1483
1524
|
event.item.type === "user_message") {
|
|
1484
1525
|
agent.lastUserMessageAt = new Date();
|
|
@@ -1501,6 +1542,7 @@ export class AgentManager {
|
|
|
1501
1542
|
seq: timelineRow.seq,
|
|
1502
1543
|
epoch: this.ensureTimelineState(agent).epoch,
|
|
1503
1544
|
});
|
|
1545
|
+
shouldPersistSnapshot = true;
|
|
1504
1546
|
}
|
|
1505
1547
|
}
|
|
1506
1548
|
agent.activeTurnStartedAt = null;
|
|
@@ -1512,6 +1554,7 @@ export class AgentManager {
|
|
|
1512
1554
|
this.emitState(agent);
|
|
1513
1555
|
}
|
|
1514
1556
|
void this.refreshRuntimeInfo(agent);
|
|
1557
|
+
shouldPersistSnapshot = true;
|
|
1515
1558
|
}
|
|
1516
1559
|
break;
|
|
1517
1560
|
case "turn_failed":
|
|
@@ -1523,17 +1566,14 @@ export class AgentManager {
|
|
|
1523
1566
|
agent.activeTurnStartedAt = null;
|
|
1524
1567
|
agent.lastError = event.error;
|
|
1525
1568
|
for (const [requestId] of agent.pendingPermissions) {
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
requestId,
|
|
1532
|
-
resolution: { behavior: "deny", message: "Turn failed" },
|
|
1533
|
-
});
|
|
1534
|
-
}
|
|
1569
|
+
this.resolvePendingPermission(agent, requestId, { behavior: "deny", message: "Turn failed" }, {
|
|
1570
|
+
provider: event.provider,
|
|
1571
|
+
dispatchEvent: !options?.fromHistory,
|
|
1572
|
+
dispatchTimeline: !options?.fromHistory,
|
|
1573
|
+
});
|
|
1535
1574
|
}
|
|
1536
1575
|
this.emitState(agent);
|
|
1576
|
+
shouldPersistSnapshot = true;
|
|
1537
1577
|
break;
|
|
1538
1578
|
case "turn_canceled":
|
|
1539
1579
|
{
|
|
@@ -1549,17 +1589,15 @@ export class AgentManager {
|
|
|
1549
1589
|
agent.lastError = undefined;
|
|
1550
1590
|
if (!pendingRefresh.hasPendingPermissions) {
|
|
1551
1591
|
for (const requestId of pendingRequestIds) {
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
resolution: { behavior: "deny", message: "Interrupted" },
|
|
1558
|
-
});
|
|
1559
|
-
}
|
|
1592
|
+
this.resolvePendingPermission(agent, requestId, { behavior: "deny", message: "Interrupted" }, {
|
|
1593
|
+
provider: event.provider,
|
|
1594
|
+
dispatchEvent: !options?.fromHistory,
|
|
1595
|
+
dispatchTimeline: !options?.fromHistory,
|
|
1596
|
+
});
|
|
1560
1597
|
}
|
|
1561
1598
|
}
|
|
1562
1599
|
this.emitState(agent);
|
|
1600
|
+
shouldPersistSnapshot = true;
|
|
1563
1601
|
}
|
|
1564
1602
|
break;
|
|
1565
1603
|
case "turn_started":
|
|
@@ -1579,10 +1617,15 @@ export class AgentManager {
|
|
|
1579
1617
|
agent.lifecycle = "running";
|
|
1580
1618
|
}
|
|
1581
1619
|
this.emitState(agent);
|
|
1620
|
+
shouldPersistSnapshot = true;
|
|
1582
1621
|
break;
|
|
1583
1622
|
case "permission_requested":
|
|
1584
1623
|
{
|
|
1585
1624
|
agent.pendingPermissions.set(event.request.id, event.request);
|
|
1625
|
+
this.recordPermissionRequestTimelineItem(agent, event.request, {
|
|
1626
|
+
provider: event.provider,
|
|
1627
|
+
dispatchTimeline: !options?.fromHistory,
|
|
1628
|
+
});
|
|
1586
1629
|
const planText = extractPlanTextFromPermissionRequest(event.request);
|
|
1587
1630
|
if (planText && !options?.fromHistory) {
|
|
1588
1631
|
const planMessage = formatProposedPlanTimelineMessage(planText);
|
|
@@ -1603,10 +1646,16 @@ export class AgentManager {
|
|
|
1603
1646
|
}
|
|
1604
1647
|
}
|
|
1605
1648
|
this.emitState(agent);
|
|
1649
|
+
shouldPersistSnapshot = true;
|
|
1606
1650
|
break;
|
|
1607
1651
|
case "permission_resolved":
|
|
1608
|
-
|
|
1652
|
+
this.resolvePendingPermission(agent, event.requestId, event.resolution, {
|
|
1653
|
+
provider: event.provider,
|
|
1654
|
+
dispatchEvent: false,
|
|
1655
|
+
dispatchTimeline: !options?.fromHistory,
|
|
1656
|
+
});
|
|
1609
1657
|
this.emitState(agent);
|
|
1658
|
+
shouldPersistSnapshot = true;
|
|
1610
1659
|
break;
|
|
1611
1660
|
default:
|
|
1612
1661
|
break;
|
|
@@ -1620,6 +1669,9 @@ export class AgentManager {
|
|
|
1620
1669
|
}
|
|
1621
1670
|
: undefined);
|
|
1622
1671
|
}
|
|
1672
|
+
if (!options?.fromHistory && shouldPersistSnapshot) {
|
|
1673
|
+
this.enqueueBackgroundPersist(agent);
|
|
1674
|
+
}
|
|
1623
1675
|
}
|
|
1624
1676
|
shouldSuppressLiveUserMessageEcho(agent, event, options) {
|
|
1625
1677
|
if (options?.fromHistory || event.type !== "timeline") {
|
|
@@ -1661,6 +1713,81 @@ export class AgentManager {
|
|
|
1661
1713
|
...(durationMs != null ? { durationMs } : {}),
|
|
1662
1714
|
};
|
|
1663
1715
|
}
|
|
1716
|
+
findRecordedPermissionRequest(agent, requestId) {
|
|
1717
|
+
for (let index = agent.timelineRows.length - 1; index >= 0; index -= 1) {
|
|
1718
|
+
const row = agent.timelineRows[index];
|
|
1719
|
+
if (row?.item.type === "permission_request" &&
|
|
1720
|
+
row.item.request.id === requestId) {
|
|
1721
|
+
return structuredClone(row.item.request);
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
return null;
|
|
1725
|
+
}
|
|
1726
|
+
hasPermissionResolutionTimelineItem(agent, requestId) {
|
|
1727
|
+
return agent.timelineRows.some((row) => row.item.type === "permission_resolution" &&
|
|
1728
|
+
row.item.requestId === requestId);
|
|
1729
|
+
}
|
|
1730
|
+
recordPermissionRequestTimelineItem(agent, request, options) {
|
|
1731
|
+
if (request.kind === "plan") {
|
|
1732
|
+
return null;
|
|
1733
|
+
}
|
|
1734
|
+
if (this.findRecordedPermissionRequest(agent, request.id)) {
|
|
1735
|
+
return null;
|
|
1736
|
+
}
|
|
1737
|
+
const item = {
|
|
1738
|
+
type: "permission_request",
|
|
1739
|
+
request: structuredClone(request),
|
|
1740
|
+
};
|
|
1741
|
+
const row = this.recordTimeline(agent, item);
|
|
1742
|
+
if (options.dispatchTimeline) {
|
|
1743
|
+
this.dispatchStream(agent.id, { type: "timeline", provider: options.provider, item }, {
|
|
1744
|
+
seq: row.seq,
|
|
1745
|
+
epoch: this.ensureTimelineState(agent).epoch,
|
|
1746
|
+
});
|
|
1747
|
+
}
|
|
1748
|
+
return row;
|
|
1749
|
+
}
|
|
1750
|
+
recordPermissionResolutionTimelineItem(agent, requestId, resolution, options) {
|
|
1751
|
+
const request = options.pendingRequest ??
|
|
1752
|
+
agent.pendingPermissions.get(requestId) ??
|
|
1753
|
+
this.findRecordedPermissionRequest(agent, requestId);
|
|
1754
|
+
if (!request || request.kind === "plan") {
|
|
1755
|
+
return null;
|
|
1756
|
+
}
|
|
1757
|
+
if (this.hasPermissionResolutionTimelineItem(agent, requestId)) {
|
|
1758
|
+
return null;
|
|
1759
|
+
}
|
|
1760
|
+
const item = {
|
|
1761
|
+
type: "permission_resolution",
|
|
1762
|
+
requestId,
|
|
1763
|
+
resolution: toPersistedPermissionResolution(resolution),
|
|
1764
|
+
};
|
|
1765
|
+
const row = this.recordTimeline(agent, item);
|
|
1766
|
+
if (options.dispatchTimeline) {
|
|
1767
|
+
this.dispatchStream(agent.id, { type: "timeline", provider: options.provider, item }, {
|
|
1768
|
+
seq: row.seq,
|
|
1769
|
+
epoch: this.ensureTimelineState(agent).epoch,
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1772
|
+
return row;
|
|
1773
|
+
}
|
|
1774
|
+
resolvePendingPermission(agent, requestId, resolution, options) {
|
|
1775
|
+
const pendingRequest = agent.pendingPermissions.get(requestId) ?? null;
|
|
1776
|
+
agent.pendingPermissions.delete(requestId);
|
|
1777
|
+
this.recordPermissionResolutionTimelineItem(agent, requestId, resolution, {
|
|
1778
|
+
provider: options.provider,
|
|
1779
|
+
pendingRequest,
|
|
1780
|
+
dispatchTimeline: options.dispatchTimeline,
|
|
1781
|
+
});
|
|
1782
|
+
if (options.dispatchEvent) {
|
|
1783
|
+
this.dispatchStream(agent.id, {
|
|
1784
|
+
type: "permission_resolved",
|
|
1785
|
+
provider: options.provider,
|
|
1786
|
+
requestId,
|
|
1787
|
+
resolution,
|
|
1788
|
+
});
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1664
1791
|
recordTimeline(agent, item) {
|
|
1665
1792
|
const timelineState = this.ensureTimelineState(agent);
|
|
1666
1793
|
const row = {
|
|
@@ -1805,8 +1932,27 @@ export class AgentManager {
|
|
|
1805
1932
|
this.suppressedPermissionAttentionKeys.delete(agent.id);
|
|
1806
1933
|
}
|
|
1807
1934
|
enqueueBackgroundPersist(agent) {
|
|
1808
|
-
|
|
1809
|
-
|
|
1935
|
+
this.enqueueBackgroundPersistById(agent.id);
|
|
1936
|
+
}
|
|
1937
|
+
enqueueBackgroundPersistById(agentId) {
|
|
1938
|
+
if (this.backgroundPersistQueuedAgents.has(agentId)) {
|
|
1939
|
+
this.backgroundPersistDirtyAgents.add(agentId);
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
const currentAgent = this.agents.get(agentId);
|
|
1943
|
+
if (!currentAgent) {
|
|
1944
|
+
return;
|
|
1945
|
+
}
|
|
1946
|
+
this.backgroundPersistQueuedAgents.add(agentId);
|
|
1947
|
+
const task = this.persistSnapshot(currentAgent)
|
|
1948
|
+
.catch((err) => {
|
|
1949
|
+
this.logger.error({ err, agentId }, "Failed to persist agent snapshot");
|
|
1950
|
+
})
|
|
1951
|
+
.finally(() => {
|
|
1952
|
+
this.backgroundPersistQueuedAgents.delete(agentId);
|
|
1953
|
+
if (this.backgroundPersistDirtyAgents.delete(agentId)) {
|
|
1954
|
+
this.enqueueBackgroundPersistById(agentId);
|
|
1955
|
+
}
|
|
1810
1956
|
});
|
|
1811
1957
|
this.trackBackgroundTask(task);
|
|
1812
1958
|
}
|