@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
package/dist/main.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { config as loadDotenv } from 'dotenv';
|
|
5
|
+
import { acquireProcessLock, openDb, migrate, log } from '@bbigbang/runtime-acp';
|
|
6
|
+
import { resolveGatewayHomeDir, loadConfig } from './config.js';
|
|
7
|
+
import { ConversationManager } from './web/conversationManager.js';
|
|
8
|
+
import { startServer } from './web/server.js';
|
|
9
|
+
import { NodeRegistry } from './services/nodeRegistry.js';
|
|
10
|
+
import { AgentWorkspaceBroker } from './services/agentWorkspaceBroker.js';
|
|
11
|
+
import { CodexAppServerBroker } from './services/codexAppServerBroker.js';
|
|
12
|
+
import { AgentRuntimeCleanupBroker } from './services/agentRuntimeCleanupBroker.js';
|
|
13
|
+
import { reconcileNodeStateOnStartup } from './services/nodeStateReconciler.js';
|
|
14
|
+
import { hasAdminUser, createInviteToken } from './services/auth.js';
|
|
15
|
+
loadDotenv({
|
|
16
|
+
path: path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..', '.env'),
|
|
17
|
+
});
|
|
18
|
+
async function main() {
|
|
19
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
20
|
+
console.log('Usage: bigbang-core');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const gatewayHome = resolveGatewayHomeDir();
|
|
24
|
+
const lock = acquireProcessLock(path.join(gatewayHome, 'gateway.lock'));
|
|
25
|
+
const cleanup = () => {
|
|
26
|
+
lock.release();
|
|
27
|
+
};
|
|
28
|
+
process.on('exit', cleanup);
|
|
29
|
+
process.on('SIGINT', () => {
|
|
30
|
+
cleanup();
|
|
31
|
+
process.exit(0);
|
|
32
|
+
});
|
|
33
|
+
process.on('SIGTERM', () => {
|
|
34
|
+
cleanup();
|
|
35
|
+
process.exit(0);
|
|
36
|
+
});
|
|
37
|
+
const config = await loadConfig({ interactiveBootstrap: true });
|
|
38
|
+
const db = openDb(config.dbPath);
|
|
39
|
+
migrate(db);
|
|
40
|
+
reconcileNodeStateOnStartup(db);
|
|
41
|
+
// On first startup with no admin user, generate an invite token and print it
|
|
42
|
+
if (!hasAdminUser(db)) {
|
|
43
|
+
const invite = createInviteToken(db);
|
|
44
|
+
const inviteUrl = `http://localhost:${config.webPort}/?invite=${invite.token}`;
|
|
45
|
+
log.info('');
|
|
46
|
+
log.info('═══════════════════════════════════════════════════');
|
|
47
|
+
log.info(' No admin account found. Complete initial setup:');
|
|
48
|
+
log.info(` ${inviteUrl}`);
|
|
49
|
+
log.info(` Token expires in 24 hours.`);
|
|
50
|
+
log.info('═══════════════════════════════════════════════════');
|
|
51
|
+
log.info('');
|
|
52
|
+
}
|
|
53
|
+
const nodeRegistry = new NodeRegistry();
|
|
54
|
+
const workspaceBroker = new AgentWorkspaceBroker({ nodeRegistry });
|
|
55
|
+
const codexAppServerBroker = new CodexAppServerBroker({ nodeRegistry });
|
|
56
|
+
const agentRuntimeCleanupBroker = new AgentRuntimeCleanupBroker({ nodeRegistry });
|
|
57
|
+
const manager = new ConversationManager({
|
|
58
|
+
db,
|
|
59
|
+
config,
|
|
60
|
+
nodeRegistry,
|
|
61
|
+
codexAppServerBroker,
|
|
62
|
+
agentRuntimeCleanupBroker,
|
|
63
|
+
});
|
|
64
|
+
manager.start();
|
|
65
|
+
await startServer({
|
|
66
|
+
port: config.webPort,
|
|
67
|
+
host: config.webHost,
|
|
68
|
+
conversationManager: manager,
|
|
69
|
+
db,
|
|
70
|
+
nodeRegistry,
|
|
71
|
+
workspaceBroker,
|
|
72
|
+
codexAppServerBroker,
|
|
73
|
+
agentRuntimeCleanupBroker,
|
|
74
|
+
});
|
|
75
|
+
log.info('agent-node started', {
|
|
76
|
+
port: config.webPort,
|
|
77
|
+
host: config.webHost,
|
|
78
|
+
workspaceRoot: config.workspaceRoot,
|
|
79
|
+
dbPath: path.resolve(config.dbPath),
|
|
80
|
+
});
|
|
81
|
+
const shutdown = () => {
|
|
82
|
+
log.warn('Shutting down...');
|
|
83
|
+
manager.close();
|
|
84
|
+
db.close();
|
|
85
|
+
process.exit(0);
|
|
86
|
+
};
|
|
87
|
+
process.on('SIGINT', shutdown);
|
|
88
|
+
process.on('SIGTERM', shutdown);
|
|
89
|
+
}
|
|
90
|
+
await main();
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
export const MAX_SAFE_NODE_EVENT_PAYLOAD_BYTES = 512 * 1024;
|
|
2
|
+
export const MAX_NODE_EVENT_FIELD_PREVIEW_CHARS = 8 * 1024;
|
|
3
|
+
function buildNodeEventTypeExpression() {
|
|
4
|
+
return `CASE
|
|
5
|
+
WHEN json_valid(payload_json) THEN json_extract(payload_json, '$.type')
|
|
6
|
+
ELSE NULL
|
|
7
|
+
END`;
|
|
8
|
+
}
|
|
9
|
+
function buildNodeEventByteLengthExpression() {
|
|
10
|
+
return `length(CAST(payload_json AS BLOB))`;
|
|
11
|
+
}
|
|
12
|
+
function buildExactJsonExtract(path) {
|
|
13
|
+
return `CASE
|
|
14
|
+
WHEN json_valid(payload_json) THEN json_extract(payload_json, '${path}')
|
|
15
|
+
ELSE NULL
|
|
16
|
+
END`;
|
|
17
|
+
}
|
|
18
|
+
function parseProjectedStructuredValue(value) {
|
|
19
|
+
if (typeof value !== 'string')
|
|
20
|
+
return value;
|
|
21
|
+
const trimmed = value.trim();
|
|
22
|
+
if (!trimmed)
|
|
23
|
+
return value;
|
|
24
|
+
if (!trimmed.startsWith('{') && !trimmed.startsWith('['))
|
|
25
|
+
return value;
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(trimmed);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function toOptionalNumber(value) {
|
|
34
|
+
return typeof value === 'number' ? value : undefined;
|
|
35
|
+
}
|
|
36
|
+
function materializeProjectedNodeEvent(row) {
|
|
37
|
+
switch (row.type) {
|
|
38
|
+
case 'content.delta':
|
|
39
|
+
return typeof row.text === 'string'
|
|
40
|
+
? { type: 'content.delta', text: row.text }
|
|
41
|
+
: null;
|
|
42
|
+
case 'activity.delta':
|
|
43
|
+
return typeof row.text === 'string'
|
|
44
|
+
? { type: 'activity.delta', text: row.text }
|
|
45
|
+
: null;
|
|
46
|
+
case 'thinking.delta':
|
|
47
|
+
return typeof row.text === 'string'
|
|
48
|
+
? { type: 'thinking.delta', text: row.text }
|
|
49
|
+
: null;
|
|
50
|
+
case 'plan.update':
|
|
51
|
+
return typeof row.title === 'string'
|
|
52
|
+
? {
|
|
53
|
+
type: 'plan.update',
|
|
54
|
+
title: row.title,
|
|
55
|
+
...(typeof row.detail === 'string' ? { detail: row.detail } : {}),
|
|
56
|
+
...(typeof row.eventCreatedAt === 'number' ? { createdAt: row.eventCreatedAt } : {}),
|
|
57
|
+
}
|
|
58
|
+
: null;
|
|
59
|
+
case 'task.update':
|
|
60
|
+
return typeof row.title === 'string'
|
|
61
|
+
? {
|
|
62
|
+
type: 'task.update',
|
|
63
|
+
title: row.title,
|
|
64
|
+
...(typeof row.detail === 'string' ? { detail: row.detail } : {}),
|
|
65
|
+
...(typeof row.eventCreatedAt === 'number' ? { createdAt: row.eventCreatedAt } : {}),
|
|
66
|
+
}
|
|
67
|
+
: null;
|
|
68
|
+
case 'tool.call':
|
|
69
|
+
return typeof row.toolCallId === 'string' && typeof row.name === 'string'
|
|
70
|
+
? {
|
|
71
|
+
type: 'tool.call',
|
|
72
|
+
toolCallId: row.toolCallId,
|
|
73
|
+
name: row.name,
|
|
74
|
+
input: parseProjectedStructuredValue(row.inputJson),
|
|
75
|
+
...(typeof row.status === 'string' ? { status: row.status } : {}),
|
|
76
|
+
...(typeof row.startedAt === 'number' ? { startedAt: row.startedAt } : {}),
|
|
77
|
+
}
|
|
78
|
+
: null;
|
|
79
|
+
case 'tool.result':
|
|
80
|
+
return typeof row.toolCallId === 'string'
|
|
81
|
+
? {
|
|
82
|
+
type: 'tool.result',
|
|
83
|
+
toolCallId: row.toolCallId,
|
|
84
|
+
output: row.output ?? '',
|
|
85
|
+
...(row.error == null ? {} : { error: Boolean(row.error) }),
|
|
86
|
+
...(typeof row.status === 'string' ? { status: row.status } : {}),
|
|
87
|
+
...(typeof row.endedAt === 'number' ? { endedAt: row.endedAt } : {}),
|
|
88
|
+
}
|
|
89
|
+
: null;
|
|
90
|
+
case 'run.usage':
|
|
91
|
+
const inputTokens = toOptionalNumber(row.inputTokens);
|
|
92
|
+
const cachedInputTokens = toOptionalNumber(row.cachedInputTokens);
|
|
93
|
+
const outputTokens = toOptionalNumber(row.outputTokens);
|
|
94
|
+
const reasoningOutputTokens = toOptionalNumber(row.reasoningOutputTokens);
|
|
95
|
+
const totalTokens = toOptionalNumber(row.totalTokens);
|
|
96
|
+
const currentInputTokens = toOptionalNumber(row.currentInputTokens);
|
|
97
|
+
const currentCachedInputTokens = toOptionalNumber(row.currentCachedInputTokens);
|
|
98
|
+
const modelContextWindow = toOptionalNumber(row.modelContextWindow);
|
|
99
|
+
const createdAt = toOptionalNumber(row.eventCreatedAt);
|
|
100
|
+
return {
|
|
101
|
+
type: 'run.usage',
|
|
102
|
+
...(inputTokens !== undefined ? { inputTokens } : {}),
|
|
103
|
+
...(cachedInputTokens !== undefined ? { cachedInputTokens } : {}),
|
|
104
|
+
...(outputTokens !== undefined ? { outputTokens } : {}),
|
|
105
|
+
...(reasoningOutputTokens !== undefined ? { reasoningOutputTokens } : {}),
|
|
106
|
+
...(totalTokens !== undefined ? { totalTokens } : {}),
|
|
107
|
+
...(currentInputTokens !== undefined ? { currentInputTokens } : {}),
|
|
108
|
+
...(currentCachedInputTokens !== undefined ? { currentCachedInputTokens } : {}),
|
|
109
|
+
...(modelContextWindow !== undefined ? { modelContextWindow } : {}),
|
|
110
|
+
...(createdAt !== undefined ? { createdAt } : {}),
|
|
111
|
+
};
|
|
112
|
+
case 'runtime.compact':
|
|
113
|
+
return typeof row.threadId === 'string' && typeof row.turnId === 'string' && typeof row.eventKey === 'string'
|
|
114
|
+
? {
|
|
115
|
+
type: 'runtime.compact',
|
|
116
|
+
threadId: row.threadId,
|
|
117
|
+
turnId: row.turnId,
|
|
118
|
+
...(typeof row.itemId === 'string' ? { itemId: row.itemId } : {}),
|
|
119
|
+
source: row.source === 'raw_response_item' || row.source === 'thread_item'
|
|
120
|
+
? row.source
|
|
121
|
+
: 'thread_compacted',
|
|
122
|
+
eventKey: row.eventKey,
|
|
123
|
+
...(typeof row.eventCreatedAt === 'number' ? { createdAt: row.eventCreatedAt } : {}),
|
|
124
|
+
}
|
|
125
|
+
: null;
|
|
126
|
+
case 'run.steer.result':
|
|
127
|
+
return typeof row.requestId === 'string' && typeof row.eventRunId === 'string' && row.ok !== null
|
|
128
|
+
? {
|
|
129
|
+
type: 'run.steer.result',
|
|
130
|
+
requestId: row.requestId,
|
|
131
|
+
runId: row.eventRunId,
|
|
132
|
+
ok: Boolean(row.ok),
|
|
133
|
+
...(typeof row.errorText === 'string' ? { error: row.errorText } : {}),
|
|
134
|
+
...(typeof row.eventCreatedAt === 'number' ? { createdAt: row.eventCreatedAt } : {}),
|
|
135
|
+
}
|
|
136
|
+
: null;
|
|
137
|
+
default:
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export function* iterateParsedNodeEvents(db, params) {
|
|
142
|
+
if (params.types.length === 0)
|
|
143
|
+
return;
|
|
144
|
+
const typeExpr = buildNodeEventTypeExpression();
|
|
145
|
+
const byteLengthExpr = buildNodeEventByteLengthExpression();
|
|
146
|
+
const maxPayloadBytes = params.maxPayloadBytes ?? MAX_SAFE_NODE_EVENT_PAYLOAD_BYTES;
|
|
147
|
+
const previewingExtract = (path) => `CASE
|
|
148
|
+
WHEN ${byteLengthExpr} <= ${maxPayloadBytes} THEN ${buildExactJsonExtract(path)}
|
|
149
|
+
WHEN NOT json_valid(payload_json) THEN NULL
|
|
150
|
+
WHEN json_extract(payload_json, '${path}') IS NULL THEN NULL
|
|
151
|
+
WHEN length(CAST(json_extract(payload_json, '${path}') AS BLOB)) <= ${MAX_NODE_EVENT_FIELD_PREVIEW_CHARS}
|
|
152
|
+
THEN json_extract(payload_json, '${path}')
|
|
153
|
+
WHEN typeof(json_extract(payload_json, '${path}')) = 'text'
|
|
154
|
+
THEN substr(json_extract(payload_json, '${path}'), 1, ${MAX_NODE_EVENT_FIELD_PREVIEW_CHARS}) || '... [truncated]'
|
|
155
|
+
ELSE substr(CAST(json_extract(payload_json, '${path}') AS TEXT), 1, ${MAX_NODE_EVENT_FIELD_PREVIEW_CHARS}) || '... [truncated]'
|
|
156
|
+
END`;
|
|
157
|
+
const placeholders = params.types.map(() => '?').join(', ');
|
|
158
|
+
const rows = db.prepare(`SELECT seq,
|
|
159
|
+
created_at as createdAt,
|
|
160
|
+
${byteLengthExpr} as payloadBytes,
|
|
161
|
+
${typeExpr} as type,
|
|
162
|
+
${previewingExtract('$.text')} as text,
|
|
163
|
+
${previewingExtract('$.title')} as title,
|
|
164
|
+
${previewingExtract('$.detail')} as detail,
|
|
165
|
+
${buildExactJsonExtract('$.toolCallId')} as toolCallId,
|
|
166
|
+
${buildExactJsonExtract('$.requestId')} as requestId,
|
|
167
|
+
${buildExactJsonExtract('$.runId')} as eventRunId,
|
|
168
|
+
${previewingExtract('$.name')} as name,
|
|
169
|
+
${previewingExtract('$.input')} as inputJson,
|
|
170
|
+
${previewingExtract('$.output')} as output,
|
|
171
|
+
${buildExactJsonExtract('$.error')} as error,
|
|
172
|
+
${previewingExtract('$.error')} as errorText,
|
|
173
|
+
${buildExactJsonExtract('$.ok')} as ok,
|
|
174
|
+
${buildExactJsonExtract('$.status')} as status,
|
|
175
|
+
${buildExactJsonExtract('$.startedAt')} as startedAt,
|
|
176
|
+
${buildExactJsonExtract('$.endedAt')} as endedAt,
|
|
177
|
+
${buildExactJsonExtract('$.createdAt')} as eventCreatedAt,
|
|
178
|
+
${buildExactJsonExtract('$.inputTokens')} as inputTokens,
|
|
179
|
+
${buildExactJsonExtract('$.cachedInputTokens')} as cachedInputTokens,
|
|
180
|
+
${buildExactJsonExtract('$.outputTokens')} as outputTokens,
|
|
181
|
+
${buildExactJsonExtract('$.reasoningOutputTokens')} as reasoningOutputTokens,
|
|
182
|
+
${buildExactJsonExtract('$.totalTokens')} as totalTokens,
|
|
183
|
+
${buildExactJsonExtract('$.currentInputTokens')} as currentInputTokens,
|
|
184
|
+
${buildExactJsonExtract('$.currentCachedInputTokens')} as currentCachedInputTokens,
|
|
185
|
+
${buildExactJsonExtract('$.modelContextWindow')} as modelContextWindow,
|
|
186
|
+
${buildExactJsonExtract('$.threadId')} as threadId,
|
|
187
|
+
${buildExactJsonExtract('$.turnId')} as turnId,
|
|
188
|
+
${buildExactJsonExtract('$.itemId')} as itemId,
|
|
189
|
+
${buildExactJsonExtract('$.source')} as source,
|
|
190
|
+
${buildExactJsonExtract('$.eventKey')} as eventKey
|
|
191
|
+
FROM events
|
|
192
|
+
WHERE run_id = ?
|
|
193
|
+
AND method = 'node/event'
|
|
194
|
+
AND ${typeExpr} IN (${placeholders})
|
|
195
|
+
ORDER BY seq ASC`).iterate(params.runId, ...params.types);
|
|
196
|
+
for (const row of rows) {
|
|
197
|
+
const event = materializeProjectedNodeEvent(row);
|
|
198
|
+
yield {
|
|
199
|
+
seq: row.seq,
|
|
200
|
+
createdAt: row.createdAt,
|
|
201
|
+
payloadBytes: row.payloadBytes,
|
|
202
|
+
event,
|
|
203
|
+
skippedOversize: row.payloadBytes > maxPayloadBytes,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const BEIJING_OFFSET_MS = 8 * 60 * 60 * 1000;
|
|
2
|
+
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
|
3
|
+
export function parseDreamScheduleHourMinute(schedule) {
|
|
4
|
+
const match = /^(\d{1,2}):(\d{2})$/.exec(schedule.trim());
|
|
5
|
+
if (!match)
|
|
6
|
+
return null;
|
|
7
|
+
const hour = Number(match[1]);
|
|
8
|
+
const minute = Number(match[2]);
|
|
9
|
+
if (!Number.isInteger(hour) || !Number.isInteger(minute))
|
|
10
|
+
return null;
|
|
11
|
+
if (hour < 0 || hour > 23 || minute < 0 || minute > 59)
|
|
12
|
+
return null;
|
|
13
|
+
return { hour, minute };
|
|
14
|
+
}
|
|
15
|
+
export function getBeijingDateParts(nowMs) {
|
|
16
|
+
const beijing = new Date(nowMs + BEIJING_OFFSET_MS);
|
|
17
|
+
return {
|
|
18
|
+
year: beijing.getUTCFullYear(),
|
|
19
|
+
month: beijing.getUTCMonth(),
|
|
20
|
+
day: beijing.getUTCDate(),
|
|
21
|
+
hour: beijing.getUTCHours(),
|
|
22
|
+
minute: beijing.getUTCMinutes(),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function isDreamScheduleDue(schedule, nowMs, lastDreamAt) {
|
|
26
|
+
const parsed = parseDreamScheduleHourMinute(schedule);
|
|
27
|
+
if (!parsed)
|
|
28
|
+
return false;
|
|
29
|
+
const beijing = getBeijingDateParts(nowMs);
|
|
30
|
+
const scheduleMinutes = parsed.hour * 60 + parsed.minute;
|
|
31
|
+
const nowMinutes = beijing.hour * 60 + beijing.minute;
|
|
32
|
+
if (nowMinutes < scheduleMinutes)
|
|
33
|
+
return false;
|
|
34
|
+
if (lastDreamAt == null)
|
|
35
|
+
return true;
|
|
36
|
+
if (nowMs - lastDreamAt < ONE_DAY_MS)
|
|
37
|
+
return false;
|
|
38
|
+
const lastBeijing = getBeijingDateParts(lastDreamAt);
|
|
39
|
+
const sameBeijingDay = lastBeijing.year === beijing.year
|
|
40
|
+
&& lastBeijing.month === beijing.month
|
|
41
|
+
&& lastBeijing.day === beijing.day;
|
|
42
|
+
return !sameBeijingDay;
|
|
43
|
+
}
|
|
44
|
+
export function shouldTriggerDream(params) {
|
|
45
|
+
if (!params.dreamEnabled)
|
|
46
|
+
return false;
|
|
47
|
+
if (!isDreamScheduleDue(params.dreamSchedule, params.nowMs, params.lastDreamAt))
|
|
48
|
+
return false;
|
|
49
|
+
return params.newMessageCount >= Math.max(1, params.dreamMinMessages);
|
|
50
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { log } from '@bbigbang/runtime-acp';
|
|
2
|
+
import { countAgentMessagesSinceSeq } from '../services/memoryService.js';
|
|
3
|
+
import { shouldTriggerDream } from './dreamLogic.js';
|
|
4
|
+
export function startDreamScheduler(params) {
|
|
5
|
+
const intervalMs = params.intervalMs ?? 60_000;
|
|
6
|
+
const inFlight = new Set();
|
|
7
|
+
const tick = async () => {
|
|
8
|
+
const nowMs = Date.now();
|
|
9
|
+
const agents = params.db.prepare(`SELECT agent_id as agentId,
|
|
10
|
+
memory_network_enabled as memoryNetworkEnabled,
|
|
11
|
+
dream_enabled as dreamEnabled,
|
|
12
|
+
dream_schedule as dreamSchedule,
|
|
13
|
+
dream_min_messages as dreamMinMessages,
|
|
14
|
+
last_dream_at as lastDreamAt,
|
|
15
|
+
last_dream_seq as lastDreamSeq,
|
|
16
|
+
node_id as nodeId,
|
|
17
|
+
dream_run_in_progress_at as dreamRunInProgressAt
|
|
18
|
+
FROM agents
|
|
19
|
+
WHERE deleted_at IS NULL
|
|
20
|
+
AND COALESCE(agent_role, 'user') = 'user'
|
|
21
|
+
AND memory_network_enabled = 1
|
|
22
|
+
AND dream_enabled = 1
|
|
23
|
+
AND node_id IS NOT NULL
|
|
24
|
+
AND (dream_run_in_progress_at IS NULL OR dream_run_in_progress_at < ?)`).all(nowMs - 30 * 60 * 1000);
|
|
25
|
+
for (const agent of agents) {
|
|
26
|
+
if (inFlight.has(agent.agentId))
|
|
27
|
+
continue;
|
|
28
|
+
const newMessageCount = countAgentMessagesSinceSeq(params.db, agent.agentId, agent.lastDreamSeq);
|
|
29
|
+
const eligible = shouldTriggerDream({
|
|
30
|
+
dreamEnabled: agent.dreamEnabled === 1,
|
|
31
|
+
dreamSchedule: agent.dreamSchedule ?? '02:00',
|
|
32
|
+
dreamMinMessages: agent.dreamMinMessages ?? 5,
|
|
33
|
+
lastDreamAt: agent.lastDreamAt,
|
|
34
|
+
newMessageCount,
|
|
35
|
+
nowMs,
|
|
36
|
+
});
|
|
37
|
+
if (!eligible)
|
|
38
|
+
continue;
|
|
39
|
+
inFlight.add(agent.agentId);
|
|
40
|
+
try {
|
|
41
|
+
log.info('[dream-scheduler] triggering dream', {
|
|
42
|
+
agentId: agent.agentId,
|
|
43
|
+
newMessageCount,
|
|
44
|
+
});
|
|
45
|
+
await params.dispatchDream(agent.agentId);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
log.warn('[dream-scheduler] dream dispatch failed', {
|
|
49
|
+
agentId: agent.agentId,
|
|
50
|
+
error: String(error?.message ?? error),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
inFlight.delete(agent.agentId);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const timer = setInterval(() => {
|
|
59
|
+
void tick();
|
|
60
|
+
}, intervalMs);
|
|
61
|
+
timer.unref?.();
|
|
62
|
+
return {
|
|
63
|
+
stop: () => clearInterval(timer),
|
|
64
|
+
};
|
|
65
|
+
}
|