@bbigbang/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.js +380 -0
- package/dist/execution/executionDispatcher.js +3810 -0
- package/dist/main.js +90 -0
- package/dist/nodeEventHistory.js +206 -0
- package/dist/scheduler/dreamLogic.js +50 -0
- package/dist/scheduler/dreamScheduler.js +65 -0
- package/dist/services/agentFileAccessService.js +1913 -0
- package/dist/services/agentRuntimeCleanupBroker.js +62 -0
- package/dist/services/agentSkillsBroker.js +118 -0
- package/dist/services/agentSkillsService.js +83 -0
- package/dist/services/agentWorkspaceBroker.js +937 -0
- package/dist/services/agentWorkspaceService.js +70 -0
- package/dist/services/appVersion.js +14 -0
- package/dist/services/auth.js +586 -0
- package/dist/services/claudeControlBroker.js +154 -0
- package/dist/services/claudeTranscriptBroker.js +100 -0
- package/dist/services/claudeTranscriptService.js +359 -0
- package/dist/services/codexAppServerBroker.js +155 -0
- package/dist/services/codexTranscriptBroker.js +98 -0
- package/dist/services/codexTranscriptService.js +961 -0
- package/dist/services/droidMissionBroker.js +124 -0
- package/dist/services/droidMissionImporter.js +630 -0
- package/dist/services/droidModelOptions.js +165 -0
- package/dist/services/hubServerRegistrationService.js +268 -0
- package/dist/services/libraryManifest.js +43 -0
- package/dist/services/libraryScaffold.js +26 -0
- package/dist/services/libraryService.js +2263 -0
- package/dist/services/memoryService.js +386 -0
- package/dist/services/missionEvidence.js +377 -0
- package/dist/services/missionService.js +2361 -0
- package/dist/services/missionTrace.js +158 -0
- package/dist/services/nativeMissionBriefParser.js +120 -0
- package/dist/services/nativeMissionOrchestrator.js +2045 -0
- package/dist/services/nativeMissionReportGenerator.js +227 -0
- package/dist/services/nativeMissionValidationRunner.js +452 -0
- package/dist/services/nativeMissionWorkerBroker.js +190 -0
- package/dist/services/nodeRegistry.js +34 -0
- package/dist/services/nodeStateReconciler.js +97 -0
- package/dist/services/panelMediaScanner.js +119 -0
- package/dist/services/persistentRuntimeJsonlClient.js +153 -0
- package/dist/services/platformAgentPolicy.js +180 -0
- package/dist/services/platformAgentService.js +2041 -0
- package/dist/services/projectAccessResolver.js +93 -0
- package/dist/services/projectService.js +392 -0
- package/dist/services/resourceSpaceService.js +140 -0
- package/dist/services/scenarioRuntimeService.js +1130 -0
- package/dist/services/suggestedPlannerService.js +868 -0
- package/dist/services/workbenchGitBroker.js +161 -0
- package/dist/services/workbenchGitService.js +69 -0
- package/dist/services/workbenchInspectBroker.js +65 -0
- package/dist/services/workbenchNodePathService.js +79 -0
- package/dist/services/workbenchRegistryService.js +240 -0
- package/dist/services/workbenchRootService.js +181 -0
- package/dist/services/workbenchTerminalBroker.js +378 -0
- package/dist/services/workspaceRunOwnership.js +60 -0
- package/dist/services/workspaceScaffold.js +105 -0
- package/dist/services/workspaceSessionRuntimeService.js +576 -0
- package/dist/services/workspaceSessionService.js +245 -0
- package/dist/services/workspaceToolActionRunner.js +1582 -0
- package/dist/services/workspaceToolErrors.js +10 -0
- package/dist/services/workspaceToolExecutionUtils.js +895 -0
- package/dist/services/workspaceToolLatestStateProjector.js +91 -0
- package/dist/services/workspaceToolManifest.js +572 -0
- package/dist/services/workspaceToolMutationQueue.js +43 -0
- package/dist/services/workspaceToolPanelProjection.js +460 -0
- package/dist/services/workspaceToolPromotion.js +255 -0
- package/dist/services/workspaceToolPromotionState.js +224 -0
- package/dist/services/workspaceToolPublishDiagnostics.js +189 -0
- package/dist/services/workspaceToolPublishIdentityResolver.js +146 -0
- package/dist/services/workspaceToolReadModel.js +378 -0
- package/dist/services/workspaceToolRunLedger.js +239 -0
- package/dist/services/workspaceToolService.js +3067 -0
- package/dist/services/workspaceToolSnapshotPanelSync.js +293 -0
- package/dist/services/workspaceToolTerminalLifecycle.js +283 -0
- package/dist/services/workspaceToolTypes.js +1 -0
- package/dist/services/workspaceToolUploadMaterializer.js +228 -0
- package/dist/web/actionCardRoutes.js +129 -0
- package/dist/web/actionCards.js +469 -0
- package/dist/web/activationContext.js +684 -0
- package/dist/web/agentChannelGuards.js +48 -0
- package/dist/web/agentMentionCooldowns.js +32 -0
- package/dist/web/agentReminders.js +1668 -0
- package/dist/web/agentRuntimePresence.js +197 -0
- package/dist/web/agentSelfState.js +494 -0
- package/dist/web/agentTaskLinks.js +26 -0
- package/dist/web/agentVisibility.js +79 -0
- package/dist/web/assets.js +95 -0
- package/dist/web/channelActivationPrompt.js +395 -0
- package/dist/web/channelMemoryNotes.js +127 -0
- package/dist/web/channelMentions.js +10 -0
- package/dist/web/channelMessageSequences.js +19 -0
- package/dist/web/channelSubscriptions.js +26 -0
- package/dist/web/clearedTaskRoots.js +10 -0
- package/dist/web/collaborationPromptGuidance.js +36 -0
- package/dist/web/collaborationSurfaceState.js +140 -0
- package/dist/web/contextBundleRanking.js +154 -0
- package/dist/web/contextBundleResolver.js +488 -0
- package/dist/web/conversationBuiltinSkillRoots.js +50 -0
- package/dist/web/conversationControls.js +232 -0
- package/dist/web/conversationHandoffs.js +612 -0
- package/dist/web/conversationManager.js +2511 -0
- package/dist/web/conversationSummaries.js +876 -0
- package/dist/web/conversationSurfaceKinds.js +17 -0
- package/dist/web/conversationTargets.js +173 -0
- package/dist/web/directActivationPrompt.js +122 -0
- package/dist/web/directReplyTargets.js +69 -0
- package/dist/web/directThreadResolver.js +129 -0
- package/dist/web/dmTaskHandoffPrompt.js +120 -0
- package/dist/web/dmTaskThreadStatusProjection.js +229 -0
- package/dist/web/ftsQuery.js +33 -0
- package/dist/web/internalAgentRouter.js +11341 -0
- package/dist/web/libraryCuratorScheduler.js +58 -0
- package/dist/web/libraryDocumentPromptGuidance.js +8 -0
- package/dist/web/messageCheckpoints.js +19 -0
- package/dist/web/nodeWsHandler.js +2495 -0
- package/dist/web/notificationRounds.js +1061 -0
- package/dist/web/panelActionMessages.js +108 -0
- package/dist/web/panelActivationPrompt.js +18 -0
- package/dist/web/panelAudit.js +273 -0
- package/dist/web/panelLifecycle.js +222 -0
- package/dist/web/panelMediaPolicy.js +43 -0
- package/dist/web/panelPathPolicy.js +63 -0
- package/dist/web/panelPreviews.js +175 -0
- package/dist/web/panelQueryHandles.js +2749 -0
- package/dist/web/panelRoutes.js +2147 -0
- package/dist/web/panels.js +904 -0
- package/dist/web/peerInboxAggregates.js +1247 -0
- package/dist/web/planApprovalState.js +92 -0
- package/dist/web/platformAgentScheduler.js +66 -0
- package/dist/web/proactiveOpportunities.js +452 -0
- package/dist/web/promptContextSections.js +242 -0
- package/dist/web/promptHistorySanitizer.js +26 -0
- package/dist/web/promptSlashCommands.js +158 -0
- package/dist/web/rollingConversationSummary.js +453 -0
- package/dist/web/routeHelpers.js +11 -0
- package/dist/web/routes/handoff.js +288 -0
- package/dist/web/routes/history.js +345 -0
- package/dist/web/routes/memory.js +258 -0
- package/dist/web/routes/selfState.js +171 -0
- package/dist/web/routes/workspace.js +154 -0
- package/dist/web/runSurfaceWatermarks.js +431 -0
- package/dist/web/runtimeCapabilities.js +48 -0
- package/dist/web/sameAgentHandoffs.js +494 -0
- package/dist/web/server.js +15567 -0
- package/dist/web/sharedCollaborationCapsules.js +163 -0
- package/dist/web/soloSessionRelay.js +42 -0
- package/dist/web/soloWsHandler.js +138 -0
- package/dist/web/suggestedPlannerScheduler.js +56 -0
- package/dist/web/surfaceActivationPolicy.js +108 -0
- package/dist/web/surfaceCollaborators.js +61 -0
- package/dist/web/surfaceSystemStatus.js +263 -0
- package/dist/web/targetParticipants.js +77 -0
- package/dist/web/taskEvents.js +49 -0
- package/dist/web/taskLifecycleMessages.js +165 -0
- package/dist/web/taskLoops.js +732 -0
- package/dist/web/taskMemoryNotes.js +224 -0
- package/dist/web/taskNumbers.js +16 -0
- package/dist/web/taskOwnerGuards.js +49 -0
- package/dist/web/taskParticipantResolver.js +42 -0
- package/dist/web/taskParticipants.js +97 -0
- package/dist/web/taskSourceDetails.js +20 -0
- package/dist/web/taskStateViews.js +210 -0
- package/dist/web/taskStatusTransitions.js +9 -0
- package/dist/web/taskThreadFollowups.js +599 -0
- package/dist/web/taskThreadRuntimeClosure.js +685 -0
- package/dist/web/taskUpdateDelivery.js +104 -0
- package/dist/web/threadReplyContentHeuristics.js +30 -0
- package/dist/web/threadRoots.js +61 -0
- package/dist/web/threadTaskBindings.js +365 -0
- package/dist/web/uiPanelPromptGuidance.js +27 -0
- package/dist/web/workspaceMemoryHints.js +143 -0
- package/dist/web/workspaceToolPromptGuidance.js +30 -0
- package/dist/web/wsHandler.js +397 -0
- package/dist/web/wsSink.js +116 -0
- package/package.json +54 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
const MEMORY_CATEGORIES = [
|
|
3
|
+
'project_knowledge',
|
|
4
|
+
'person',
|
|
5
|
+
'preference',
|
|
6
|
+
'decision',
|
|
7
|
+
'procedure',
|
|
8
|
+
];
|
|
9
|
+
const MEMORY_NODE_STATUSES = ['draft', 'confirmed', 'retired'];
|
|
10
|
+
const MEMORY_EDGE_RELATIONS = [
|
|
11
|
+
'related_to',
|
|
12
|
+
'depends_on',
|
|
13
|
+
'contradicts',
|
|
14
|
+
'evolved_from',
|
|
15
|
+
];
|
|
16
|
+
const SNIPPET_MAX_CHARS = 200;
|
|
17
|
+
export class MemoryServiceError extends Error {
|
|
18
|
+
statusCode;
|
|
19
|
+
constructor(statusCode, message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.statusCode = statusCode;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function normalizeCategory(value) {
|
|
25
|
+
const normalized = value.trim();
|
|
26
|
+
if (!MEMORY_CATEGORIES.includes(normalized)) {
|
|
27
|
+
throw new MemoryServiceError(400, `Invalid memory category: ${value}`);
|
|
28
|
+
}
|
|
29
|
+
return normalized;
|
|
30
|
+
}
|
|
31
|
+
function normalizeStatus(value) {
|
|
32
|
+
const normalized = value.trim();
|
|
33
|
+
if (!MEMORY_NODE_STATUSES.includes(normalized)) {
|
|
34
|
+
throw new MemoryServiceError(400, `Invalid memory status: ${value}`);
|
|
35
|
+
}
|
|
36
|
+
return normalized;
|
|
37
|
+
}
|
|
38
|
+
function normalizeRelation(value) {
|
|
39
|
+
const normalized = value.trim();
|
|
40
|
+
if (!MEMORY_EDGE_RELATIONS.includes(normalized)) {
|
|
41
|
+
throw new MemoryServiceError(400, `Invalid memory relation: ${value}`);
|
|
42
|
+
}
|
|
43
|
+
return normalized;
|
|
44
|
+
}
|
|
45
|
+
function clampImportance(value) {
|
|
46
|
+
if (!Number.isFinite(value))
|
|
47
|
+
return 0.5;
|
|
48
|
+
return Math.min(1, Math.max(0, value));
|
|
49
|
+
}
|
|
50
|
+
function clampStrength(value) {
|
|
51
|
+
return clampImportance(value);
|
|
52
|
+
}
|
|
53
|
+
function parseSourceRefs(raw) {
|
|
54
|
+
if (!raw)
|
|
55
|
+
return undefined;
|
|
56
|
+
try {
|
|
57
|
+
const parsed = JSON.parse(raw);
|
|
58
|
+
if (!Array.isArray(parsed))
|
|
59
|
+
return undefined;
|
|
60
|
+
const refs = [];
|
|
61
|
+
for (const item of parsed) {
|
|
62
|
+
if (!item || typeof item !== 'object')
|
|
63
|
+
continue;
|
|
64
|
+
const messageId = typeof item.messageId === 'string'
|
|
65
|
+
? item.messageId.trim()
|
|
66
|
+
: '';
|
|
67
|
+
const snippet = typeof item.snippet === 'string'
|
|
68
|
+
? item.snippet.trim().slice(0, SNIPPET_MAX_CHARS)
|
|
69
|
+
: '';
|
|
70
|
+
if (!messageId || !snippet)
|
|
71
|
+
continue;
|
|
72
|
+
refs.push({ messageId, snippet });
|
|
73
|
+
}
|
|
74
|
+
return refs.length > 0 ? refs : undefined;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function serializeSourceRefs(refs) {
|
|
81
|
+
if (!refs || refs.length === 0)
|
|
82
|
+
return null;
|
|
83
|
+
return JSON.stringify(refs.map((ref) => ({
|
|
84
|
+
messageId: ref.messageId,
|
|
85
|
+
snippet: ref.snippet.slice(0, SNIPPET_MAX_CHARS),
|
|
86
|
+
})));
|
|
87
|
+
}
|
|
88
|
+
function rowToNode(row) {
|
|
89
|
+
const sourceRefs = parseSourceRefs(row.sourceRefsJson);
|
|
90
|
+
return {
|
|
91
|
+
nodeId: row.nodeId,
|
|
92
|
+
agentId: row.agentId,
|
|
93
|
+
topic: row.topic,
|
|
94
|
+
summary: row.summary,
|
|
95
|
+
category: normalizeCategory(row.category),
|
|
96
|
+
importance: row.importance,
|
|
97
|
+
...(sourceRefs ? { sourceRefs } : {}),
|
|
98
|
+
status: normalizeStatus(row.status),
|
|
99
|
+
firstSeenAt: row.firstSeenAt,
|
|
100
|
+
lastReinforcedAt: row.lastReinforcedAt,
|
|
101
|
+
...(row.retiredAt != null ? { retiredAt: row.retiredAt } : {}),
|
|
102
|
+
createdAt: row.createdAt,
|
|
103
|
+
updatedAt: row.updatedAt,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function rowToEdge(row) {
|
|
107
|
+
return {
|
|
108
|
+
edgeId: row.edgeId,
|
|
109
|
+
agentId: row.agentId,
|
|
110
|
+
sourceNodeId: row.sourceNodeId,
|
|
111
|
+
targetNodeId: row.targetNodeId,
|
|
112
|
+
relation: normalizeRelation(row.relation),
|
|
113
|
+
strength: row.strength,
|
|
114
|
+
createdAt: row.createdAt,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export function countAgentMessagesSinceSeq(db, agentId, sinceSeq) {
|
|
118
|
+
const row = db.prepare(`SELECT COUNT(*) as count
|
|
119
|
+
FROM channel_messages cm
|
|
120
|
+
JOIN agent_channel_memberships m ON m.channel_id = cm.channel_id
|
|
121
|
+
WHERE m.agent_id = ?
|
|
122
|
+
AND cm.deleted_at IS NULL
|
|
123
|
+
AND cm.seq > COALESCE(?, 0)`).get(agentId, sinceSeq ?? 0);
|
|
124
|
+
return row.count;
|
|
125
|
+
}
|
|
126
|
+
export function listAgentMessagesSinceSeq(db, agentId, sinceSeq, limit = 200) {
|
|
127
|
+
const safeLimit = Math.max(1, Math.min(Math.floor(limit), 500));
|
|
128
|
+
return db.prepare(`SELECT cm.message_id as messageId,
|
|
129
|
+
cm.seq as seq,
|
|
130
|
+
cm.sender_name as senderName,
|
|
131
|
+
cm.sender_type as senderType,
|
|
132
|
+
cm.content as content,
|
|
133
|
+
cm.created_at as createdAt
|
|
134
|
+
FROM channel_messages cm
|
|
135
|
+
JOIN agent_channel_memberships m ON m.channel_id = cm.channel_id
|
|
136
|
+
WHERE m.agent_id = ?
|
|
137
|
+
AND cm.deleted_at IS NULL
|
|
138
|
+
AND cm.seq > COALESCE(?, 0)
|
|
139
|
+
ORDER BY cm.seq ASC
|
|
140
|
+
LIMIT ?`).all(agentId, sinceSeq ?? 0, safeLimit);
|
|
141
|
+
}
|
|
142
|
+
export function buildDreamContextText(messages) {
|
|
143
|
+
if (messages.length === 0)
|
|
144
|
+
return null;
|
|
145
|
+
return messages.map((message) => (`[seq=${message.seq} id=${message.messageId}] ${message.senderName} (${message.senderType}): ${message.content}`)).join('\n');
|
|
146
|
+
}
|
|
147
|
+
export function getMaxAgentMessageSeq(db, agentId) {
|
|
148
|
+
const row = db.prepare(`SELECT COALESCE(MAX(cm.seq), 0) as maxSeq
|
|
149
|
+
FROM channel_messages cm
|
|
150
|
+
JOIN agent_channel_memberships m ON m.channel_id = cm.channel_id
|
|
151
|
+
WHERE m.agent_id = ?
|
|
152
|
+
AND cm.deleted_at IS NULL`).get(agentId);
|
|
153
|
+
return row.maxSeq;
|
|
154
|
+
}
|
|
155
|
+
function isDreamRunFailure(error, stopReason) {
|
|
156
|
+
if (error?.trim())
|
|
157
|
+
return true;
|
|
158
|
+
if (!stopReason?.trim())
|
|
159
|
+
return false;
|
|
160
|
+
const normalized = stopReason.trim().toLowerCase();
|
|
161
|
+
return normalized.includes('cancel') || normalized === 'error';
|
|
162
|
+
}
|
|
163
|
+
export function createMemoryNode(db, params) {
|
|
164
|
+
const now = Date.now();
|
|
165
|
+
const nodeId = randomUUID();
|
|
166
|
+
const topic = params.topic.trim();
|
|
167
|
+
const summary = params.summary.trim();
|
|
168
|
+
if (!topic || !summary) {
|
|
169
|
+
throw new MemoryServiceError(400, 'topic and summary are required');
|
|
170
|
+
}
|
|
171
|
+
const category = normalizeCategory(params.category);
|
|
172
|
+
const status = params.status ? normalizeStatus(params.status) : 'draft';
|
|
173
|
+
const importance = clampImportance(params.importance ?? 0.5);
|
|
174
|
+
const sourceRefs = params.sourceRefs
|
|
175
|
+
?? (params.sourceMessageId && params.sourceSnippet
|
|
176
|
+
? [{ messageId: params.sourceMessageId, snippet: params.sourceSnippet.slice(0, SNIPPET_MAX_CHARS) }]
|
|
177
|
+
: undefined);
|
|
178
|
+
db.prepare(`INSERT INTO memory_nodes(
|
|
179
|
+
node_id, agent_id, topic, summary, category, importance, source_refs, status,
|
|
180
|
+
first_seen_at, last_reinforced_at, retired_at, created_at, updated_at
|
|
181
|
+
) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?)`).run(nodeId, params.agentId, topic, summary, category, importance, serializeSourceRefs(sourceRefs), status, now, now, now, now);
|
|
182
|
+
return rowToNode(db.prepare(`SELECT node_id as nodeId, agent_id as agentId, topic, summary, category, importance,
|
|
183
|
+
source_refs as sourceRefsJson, status,
|
|
184
|
+
first_seen_at as firstSeenAt, last_reinforced_at as lastReinforcedAt,
|
|
185
|
+
retired_at as retiredAt, created_at as createdAt, updated_at as updatedAt
|
|
186
|
+
FROM memory_nodes
|
|
187
|
+
WHERE node_id = ?`).get(nodeId));
|
|
188
|
+
}
|
|
189
|
+
export function listMemoryNodes(db, params) {
|
|
190
|
+
const filters = ['agent_id = ?'];
|
|
191
|
+
const values = [params.agentId];
|
|
192
|
+
if (params.category) {
|
|
193
|
+
filters.push('category = ?');
|
|
194
|
+
values.push(normalizeCategory(params.category));
|
|
195
|
+
}
|
|
196
|
+
if (params.status) {
|
|
197
|
+
filters.push('status = ?');
|
|
198
|
+
values.push(normalizeStatus(params.status));
|
|
199
|
+
}
|
|
200
|
+
if (params.since != null) {
|
|
201
|
+
filters.push('updated_at >= ?');
|
|
202
|
+
values.push(params.since);
|
|
203
|
+
}
|
|
204
|
+
if (params.query?.trim()) {
|
|
205
|
+
filters.push('(topic LIKE ? OR summary LIKE ?)');
|
|
206
|
+
const pattern = `%${params.query.trim()}%`;
|
|
207
|
+
values.push(pattern, pattern);
|
|
208
|
+
}
|
|
209
|
+
const rows = db.prepare(`SELECT node_id as nodeId, agent_id as agentId, topic, summary, category, importance,
|
|
210
|
+
source_refs as sourceRefsJson, status,
|
|
211
|
+
first_seen_at as firstSeenAt, last_reinforced_at as lastReinforcedAt,
|
|
212
|
+
retired_at as retiredAt, created_at as createdAt, updated_at as updatedAt
|
|
213
|
+
FROM memory_nodes
|
|
214
|
+
WHERE ${filters.join(' AND ')}
|
|
215
|
+
ORDER BY importance DESC, last_reinforced_at DESC`).all(...values);
|
|
216
|
+
return rows.map(rowToNode);
|
|
217
|
+
}
|
|
218
|
+
export function getMemoryNode(db, agentId, nodeId) {
|
|
219
|
+
const row = db.prepare(`SELECT node_id as nodeId, agent_id as agentId, topic, summary, category, importance,
|
|
220
|
+
source_refs as sourceRefsJson, status,
|
|
221
|
+
first_seen_at as firstSeenAt, last_reinforced_at as lastReinforcedAt,
|
|
222
|
+
retired_at as retiredAt, created_at as createdAt, updated_at as updatedAt
|
|
223
|
+
FROM memory_nodes
|
|
224
|
+
WHERE node_id = ? AND agent_id = ?`).get(nodeId, agentId);
|
|
225
|
+
return row ? rowToNode(row) : null;
|
|
226
|
+
}
|
|
227
|
+
export function updateMemoryNode(db, agentId, nodeId, params) {
|
|
228
|
+
const existing = getMemoryNode(db, agentId, nodeId);
|
|
229
|
+
if (!existing)
|
|
230
|
+
throw new MemoryServiceError(404, 'Memory node not found');
|
|
231
|
+
const now = Date.now();
|
|
232
|
+
let status = existing.status;
|
|
233
|
+
let importance = existing.importance;
|
|
234
|
+
let lastReinforcedAt = existing.lastReinforcedAt;
|
|
235
|
+
let retiredAt = existing.retiredAt ?? null;
|
|
236
|
+
if (params.confirm) {
|
|
237
|
+
status = 'confirmed';
|
|
238
|
+
retiredAt = null;
|
|
239
|
+
}
|
|
240
|
+
if (params.retire) {
|
|
241
|
+
status = 'retired';
|
|
242
|
+
retiredAt = now;
|
|
243
|
+
}
|
|
244
|
+
if (params.reinforce) {
|
|
245
|
+
lastReinforcedAt = now;
|
|
246
|
+
importance = clampImportance(Math.min(1, existing.importance + 0.05));
|
|
247
|
+
if (status === 'draft')
|
|
248
|
+
status = 'confirmed';
|
|
249
|
+
}
|
|
250
|
+
const topic = params.topic?.trim() || existing.topic;
|
|
251
|
+
const summary = params.summary?.trim() || existing.summary;
|
|
252
|
+
if (params.importance != null) {
|
|
253
|
+
importance = clampImportance(params.importance);
|
|
254
|
+
}
|
|
255
|
+
db.prepare(`UPDATE memory_nodes
|
|
256
|
+
SET topic = ?, summary = ?, importance = ?, status = ?,
|
|
257
|
+
last_reinforced_at = ?, retired_at = ?, updated_at = ?
|
|
258
|
+
WHERE node_id = ? AND agent_id = ?`).run(topic, summary, importance, status, lastReinforcedAt, retiredAt, now, nodeId, agentId);
|
|
259
|
+
return getMemoryNode(db, agentId, nodeId);
|
|
260
|
+
}
|
|
261
|
+
export function deleteMemoryNode(db, agentId, nodeId) {
|
|
262
|
+
const result = db.prepare(`DELETE FROM memory_nodes WHERE node_id = ? AND agent_id = ?`).run(nodeId, agentId);
|
|
263
|
+
return result.changes > 0;
|
|
264
|
+
}
|
|
265
|
+
export function createMemoryEdge(db, params) {
|
|
266
|
+
const source = getMemoryNode(db, params.agentId, params.sourceNodeId);
|
|
267
|
+
const target = getMemoryNode(db, params.agentId, params.targetNodeId);
|
|
268
|
+
if (!source || !target)
|
|
269
|
+
throw new MemoryServiceError(404, 'Memory node not found');
|
|
270
|
+
const relation = normalizeRelation(params.relation);
|
|
271
|
+
const existing = db.prepare(`SELECT edge_id as edgeId FROM memory_edges
|
|
272
|
+
WHERE agent_id = ?
|
|
273
|
+
AND source_node_id = ?
|
|
274
|
+
AND target_node_id = ?
|
|
275
|
+
AND relation = ?`).get(params.agentId, params.sourceNodeId, params.targetNodeId, relation);
|
|
276
|
+
if (existing)
|
|
277
|
+
throw new MemoryServiceError(409, 'Memory edge already exists');
|
|
278
|
+
const edgeId = randomUUID();
|
|
279
|
+
const now = Date.now();
|
|
280
|
+
db.prepare(`INSERT INTO memory_edges(edge_id, agent_id, source_node_id, target_node_id, relation, strength, created_at)
|
|
281
|
+
VALUES(?, ?, ?, ?, ?, ?, ?)`).run(edgeId, params.agentId, params.sourceNodeId, params.targetNodeId, relation, clampStrength(params.strength ?? 0.5), now);
|
|
282
|
+
return rowToEdge(db.prepare(`SELECT edge_id as edgeId, agent_id as agentId, source_node_id as sourceNodeId,
|
|
283
|
+
target_node_id as targetNodeId, relation, strength, created_at as createdAt
|
|
284
|
+
FROM memory_edges
|
|
285
|
+
WHERE edge_id = ?`).get(edgeId));
|
|
286
|
+
}
|
|
287
|
+
export function listMemoryEdges(db, params) {
|
|
288
|
+
const filters = ['agent_id = ?'];
|
|
289
|
+
const values = [params.agentId];
|
|
290
|
+
if (params.nodeId) {
|
|
291
|
+
filters.push('(source_node_id = ? OR target_node_id = ?)');
|
|
292
|
+
values.push(params.nodeId, params.nodeId);
|
|
293
|
+
}
|
|
294
|
+
const rows = db.prepare(`SELECT edge_id as edgeId, agent_id as agentId, source_node_id as sourceNodeId,
|
|
295
|
+
target_node_id as targetNodeId, relation, strength, created_at as createdAt
|
|
296
|
+
FROM memory_edges
|
|
297
|
+
WHERE ${filters.join(' AND ')}
|
|
298
|
+
ORDER BY created_at DESC`).all(...values);
|
|
299
|
+
return rows.map(rowToEdge);
|
|
300
|
+
}
|
|
301
|
+
export function deleteMemoryEdge(db, agentId, edgeId) {
|
|
302
|
+
const result = db.prepare(`DELETE FROM memory_edges WHERE edge_id = ? AND agent_id = ?`).run(edgeId, agentId);
|
|
303
|
+
return result.changes > 0;
|
|
304
|
+
}
|
|
305
|
+
export function getMemoryGraph(db, agentId) {
|
|
306
|
+
return {
|
|
307
|
+
nodes: listMemoryNodes(db, { agentId }),
|
|
308
|
+
edges: listMemoryEdges(db, { agentId }),
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
export function countDreamMemoryActivitySince(db, agentId, sinceMs) {
|
|
312
|
+
const nodeRow = db.prepare(`SELECT COUNT(*) as count FROM memory_nodes WHERE agent_id = ? AND updated_at > ?`).get(agentId, sinceMs);
|
|
313
|
+
const edgeRow = db.prepare(`SELECT COUNT(*) as count FROM memory_edges WHERE agent_id = ? AND created_at > ?`).get(agentId, sinceMs);
|
|
314
|
+
return (nodeRow.count ?? 0) + (edgeRow.count ?? 0);
|
|
315
|
+
}
|
|
316
|
+
export function updateDreamWatermark(db, agentId, seq, options) {
|
|
317
|
+
if (!Number.isFinite(seq) || seq < 0) {
|
|
318
|
+
throw new MemoryServiceError(400, 'seq must be a non-negative number');
|
|
319
|
+
}
|
|
320
|
+
const nextSeq = Math.floor(seq);
|
|
321
|
+
const agent = db.prepare(`SELECT last_dream_seq as lastDreamSeq FROM agents WHERE agent_id = ?`).get(agentId);
|
|
322
|
+
if (!agent) {
|
|
323
|
+
throw new MemoryServiceError(404, 'Agent not found');
|
|
324
|
+
}
|
|
325
|
+
if (agent.lastDreamSeq != null && nextSeq < agent.lastDreamSeq) {
|
|
326
|
+
throw new MemoryServiceError(409, 'dream-watermark cannot move backwards');
|
|
327
|
+
}
|
|
328
|
+
if (options?.requireMemoryActivitySince != null) {
|
|
329
|
+
const activity = countDreamMemoryActivitySince(db, agentId, options.requireMemoryActivitySince);
|
|
330
|
+
if (activity <= 0) {
|
|
331
|
+
throw new MemoryServiceError(400, 'dream-watermark requires at least one bigbang memory node or edge write in this dream run');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const now = Date.now();
|
|
335
|
+
const result = db.prepare(`UPDATE agents SET last_dream_seq = ?, updated_at = ? WHERE agent_id = ?`).run(nextSeq, now, agentId);
|
|
336
|
+
if (result.changes <= 0) {
|
|
337
|
+
throw new MemoryServiceError(404, 'Agent not found');
|
|
338
|
+
}
|
|
339
|
+
return { lastDreamSeq: nextSeq };
|
|
340
|
+
}
|
|
341
|
+
export function markDreamCompleted(db, agentId) {
|
|
342
|
+
const now = Date.now();
|
|
343
|
+
db.prepare(`UPDATE agents SET last_dream_at = ?, updated_at = ? WHERE agent_id = ?`).run(now, now, agentId);
|
|
344
|
+
}
|
|
345
|
+
export function finalizeDreamRun(db, agentId, params) {
|
|
346
|
+
if (isDreamRunFailure(params.error, params.stopReason)) {
|
|
347
|
+
releaseDreamRunLock(db, agentId);
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
const agent = db.prepare(`SELECT last_dream_seq as lastDreamSeq FROM agents WHERE agent_id = ?`).get(agentId);
|
|
351
|
+
if (!agent) {
|
|
352
|
+
releaseDreamRunLock(db, agentId);
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
const baseline = params.startSeq ?? 0;
|
|
356
|
+
if ((agent.lastDreamSeq ?? 0) <= baseline) {
|
|
357
|
+
releaseDreamRunLock(db, agentId);
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
const now = Date.now();
|
|
361
|
+
db.prepare(`UPDATE agents
|
|
362
|
+
SET last_dream_at = ?, dream_run_in_progress_at = NULL, updated_at = ?
|
|
363
|
+
WHERE agent_id = ?`).run(now, now, agentId);
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
export function claimDreamRunLock(db, agentId, now = Date.now(), ttlMs = 30 * 60 * 1000) {
|
|
367
|
+
const staleBefore = now - ttlMs;
|
|
368
|
+
const result = db.prepare(`UPDATE agents
|
|
369
|
+
SET dream_run_in_progress_at = ?, updated_at = ?
|
|
370
|
+
WHERE agent_id = ?
|
|
371
|
+
AND (dream_run_in_progress_at IS NULL OR dream_run_in_progress_at < ?)`).run(now, now, agentId, staleBefore);
|
|
372
|
+
return result.changes > 0;
|
|
373
|
+
}
|
|
374
|
+
export function releaseDreamRunLock(db, agentId) {
|
|
375
|
+
const now = Date.now();
|
|
376
|
+
db.prepare(`UPDATE agents
|
|
377
|
+
SET dream_run_in_progress_at = NULL, updated_at = ?
|
|
378
|
+
WHERE agent_id = ?`).run(now, agentId);
|
|
379
|
+
}
|
|
380
|
+
export function getDreamAgentState(db, agentId) {
|
|
381
|
+
const row = db.prepare(`SELECT last_dream_seq as lastDreamSeq,
|
|
382
|
+
dream_run_in_progress_at as dreamRunInProgressAt
|
|
383
|
+
FROM agents
|
|
384
|
+
WHERE agent_id = ?`).get(agentId);
|
|
385
|
+
return row ?? null;
|
|
386
|
+
}
|