@swarmclawai/swarmclaw 1.2.4 → 1.2.6
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/README.md +14 -0
- package/bin/daemon-cmd.js +169 -0
- package/bin/server-cmd.js +3 -0
- package/bin/swarmclaw.js +11 -0
- package/package.json +17 -16
- package/src/app/api/agents/[id]/clone/route.ts +3 -32
- package/src/app/api/agents/[id]/route.ts +6 -158
- package/src/app/api/agents/[id]/status/route.ts +2 -3
- package/src/app/api/agents/[id]/thread/route.ts +4 -17
- package/src/app/api/agents/bulk/route.ts +5 -47
- package/src/app/api/agents/route.ts +5 -119
- package/src/app/api/agents/trash/route.ts +13 -24
- package/src/app/api/auth/route.ts +3 -9
- package/src/app/api/autonomy/estop/route.ts +5 -5
- package/src/app/api/chatrooms/[id]/chat/route.ts +11 -5
- package/src/app/api/chatrooms/[id]/route.ts +23 -2
- package/src/app/api/chatrooms/route.ts +13 -2
- package/src/app/api/chats/[id]/clear/route.ts +2 -13
- package/src/app/api/chats/[id]/deploy/route.ts +2 -3
- package/src/app/api/chats/[id]/edit-resend/route.ts +7 -13
- package/src/app/api/chats/[id]/mailbox/route.ts +6 -8
- package/src/app/api/chats/[id]/queue/route.ts +17 -64
- package/src/app/api/chats/[id]/retry/route.ts +4 -22
- package/src/app/api/chats/[id]/route.ts +10 -138
- package/src/app/api/chats/heartbeat/route.ts +2 -1
- package/src/app/api/chats/migrate-messages/route.ts +7 -0
- package/src/app/api/chats/route.ts +13 -134
- package/src/app/api/connectors/[id]/access/route.ts +12 -229
- package/src/app/api/connectors/[id]/doctor/route.ts +1 -1
- package/src/app/api/connectors/[id]/health/route.ts +12 -39
- package/src/app/api/connectors/[id]/route.ts +14 -122
- package/src/app/api/connectors/[id]/webhook/route.ts +1 -1
- package/src/app/api/connectors/doctor/route.ts +1 -1
- package/src/app/api/connectors/route.ts +12 -70
- package/src/app/api/credentials/[id]/route.ts +2 -4
- package/src/app/api/credentials/route.ts +10 -19
- package/src/app/api/daemon/health-check/route.ts +3 -4
- package/src/app/api/daemon/route.ts +10 -8
- package/src/app/api/documents/route.ts +11 -10
- package/src/app/api/external-agents/route.ts +3 -3
- package/src/app/api/gateways/[id]/health/route.ts +2 -3
- package/src/app/api/gateways/[id]/route.ts +7 -122
- package/src/app/api/gateways/route.ts +3 -103
- package/src/app/api/mcp-servers/[id]/tools/route.ts +5 -5
- package/src/app/api/openclaw/dashboard-url/route.ts +8 -16
- package/src/app/api/openclaw/directory/route.ts +2 -2
- package/src/app/api/openclaw/history/route.ts +3 -5
- package/src/app/api/providers/[id]/route.test.ts +49 -0
- package/src/app/api/providers/ollama/route.ts +6 -5
- package/src/app/api/schedules/[id]/route.ts +14 -108
- package/src/app/api/schedules/[id]/run/route.ts +6 -67
- package/src/app/api/schedules/route.ts +9 -51
- package/src/app/api/settings/route.ts +4 -3
- package/src/app/api/setup/check-provider/route.ts +23 -1
- package/src/app/api/setup/openclaw-device/route.ts +2 -2
- package/src/app/api/system/status/route.ts +2 -2
- package/src/app/api/tasks/[id]/route.ts +16 -202
- package/src/app/api/tasks/bulk/route.ts +5 -86
- package/src/app/api/tasks/metrics/route.ts +2 -1
- package/src/app/api/tasks/route.ts +11 -171
- package/src/app/api/upload/route.ts +1 -1
- package/src/app/api/uploads/[filename]/route.ts +1 -1
- package/src/app/api/uploads/route.ts +1 -1
- package/src/app/api/webhooks/[id]/history/route.ts +2 -2
- package/src/app/layout.tsx +9 -6
- package/src/app/protocols/page.tsx +71 -89
- package/src/app/tasks/page.tsx +32 -32
- package/src/cli/index.js +1 -0
- package/src/cli/spec.js +1 -0
- package/src/components/agents/agent-sheet.tsx +5 -5
- package/src/components/auth/setup-wizard/index.tsx +4 -4
- package/src/components/auth/setup-wizard/step-agents.tsx +1 -1
- package/src/components/auth/setup-wizard/step-connect.tsx +1 -1
- package/src/components/auth/setup-wizard/utils.ts +1 -1
- package/src/components/chatrooms/chatroom-sheet.tsx +16 -276
- package/src/components/connectors/connector-list.tsx +26 -40
- package/src/components/connectors/connector-sheet.tsx +95 -149
- package/src/components/gateways/gateway-sheet.tsx +61 -110
- package/src/components/layout/live-query-sync.tsx +121 -0
- package/src/components/protocols/structured-session-launcher.tsx +24 -45
- package/src/components/providers/app-query-provider.tsx +17 -0
- package/src/components/providers/provider-list.tsx +60 -61
- package/src/components/providers/provider-sheet.tsx +74 -56
- package/src/components/skills/skill-list.tsx +5 -18
- package/src/components/skills/skill-sheet.tsx +21 -20
- package/src/components/skills/skills-workspace.tsx +48 -87
- package/src/components/tasks/task-card.tsx +20 -13
- package/src/components/tasks/task-column.tsx +22 -7
- package/src/components/tasks/task-list.tsx +8 -11
- package/src/components/tasks/task-sheet.tsx +111 -103
- package/src/features/agents/queries.ts +20 -0
- package/src/features/chatrooms/queries.ts +20 -0
- package/src/features/chats/queries.ts +27 -0
- package/src/features/connectors/queries.ts +145 -0
- package/src/features/credentials/queries.ts +37 -0
- package/src/features/extensions/queries.ts +26 -0
- package/src/features/external-agents/queries.ts +36 -0
- package/src/features/gateways/queries.ts +274 -0
- package/src/features/missions/queries.ts +23 -0
- package/src/features/projects/queries.ts +20 -0
- package/src/features/protocols/queries.ts +149 -0
- package/src/features/providers/queries.ts +142 -0
- package/src/features/settings/queries.ts +20 -0
- package/src/features/skills/queries.ts +182 -0
- package/src/features/tasks/queries.ts +189 -0
- package/src/hooks/use-ws.ts +3 -2
- package/src/lib/app/api-client.ts +2 -2
- package/src/lib/providers/index.test.ts +108 -0
- package/src/lib/providers/index.ts +38 -15
- package/src/lib/query/client.ts +17 -0
- package/src/lib/server/agents/agent-runtime-config.ts +1 -1
- package/src/lib/server/agents/agent-service.ts +429 -0
- package/src/lib/server/agents/agent-thread-session.ts +6 -5
- package/src/lib/server/agents/autonomy-contract.ts +1 -4
- package/src/lib/server/agents/delegation-advisory.test.ts +206 -0
- package/src/lib/server/agents/delegation-advisory.ts +251 -0
- package/src/lib/server/agents/main-agent-loop.ts +98 -40
- package/src/lib/server/agents/subagent-runtime.ts +12 -0
- package/src/lib/server/autonomy/supervisor-reflection.test.ts +20 -1
- package/src/lib/server/autonomy/supervisor-reflection.ts +39 -19
- package/src/lib/server/build-llm.ts +7 -15
- package/src/lib/server/capability-router.test.ts +70 -1
- package/src/lib/server/capability-router.ts +24 -99
- package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -15
- package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -4
- package/src/lib/server/chat-execution/chat-turn-finalization.ts +77 -12
- package/src/lib/server/chat-execution/chat-turn-partial-persistence.ts +4 -4
- package/src/lib/server/chat-execution/chat-turn-preflight.ts +2 -2
- package/src/lib/server/chat-execution/chat-turn-preparation.ts +41 -17
- package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -2
- package/src/lib/server/chat-execution/chat-turn-tool-routing.test.ts +45 -0
- package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +48 -17
- package/src/lib/server/chat-execution/continuation-evaluator.ts +4 -1
- package/src/lib/server/chat-execution/direct-memory-intent.test.ts +9 -0
- package/src/lib/server/chat-execution/direct-memory-intent.ts +12 -2
- package/src/lib/server/chat-execution/message-classifier.test.ts +35 -23
- package/src/lib/server/chat-execution/message-classifier.ts +74 -32
- package/src/lib/server/chat-execution/prompt-builder.test.ts +29 -0
- package/src/lib/server/chat-execution/prompt-builder.ts +37 -2
- package/src/lib/server/chat-execution/prompt-sections.test.ts +56 -0
- package/src/lib/server/chat-execution/prompt-sections.ts +193 -0
- package/src/lib/server/chat-execution/stream-agent-chat.ts +63 -7
- package/src/lib/server/chat-execution/stream-continuation.test.ts +36 -0
- package/src/lib/server/chat-execution/stream-continuation.ts +28 -13
- package/src/lib/server/chatrooms/chatroom-agent-signals.ts +26 -18
- package/src/lib/server/chatrooms/chatroom-helpers.ts +19 -18
- package/src/lib/server/chatrooms/chatroom-repository.ts +16 -0
- package/src/lib/server/chatrooms/chatroom-routing.test.ts +96 -0
- package/src/lib/server/chatrooms/chatroom-routing.ts +207 -53
- package/src/lib/server/chatrooms/mailbox-utils.ts +4 -2
- package/src/lib/server/chatrooms/session-mailbox.ts +50 -40
- package/src/lib/server/chats/chat-session-service.ts +410 -0
- package/src/lib/server/connectors/access.ts +1 -1
- package/src/lib/server/connectors/commands.ts +7 -6
- package/src/lib/server/connectors/connector-inbound.ts +14 -7
- package/src/lib/server/connectors/connector-outbound.ts +16 -11
- package/src/lib/server/connectors/connector-service.ts +453 -0
- package/src/lib/server/connectors/delivery.ts +17 -12
- package/src/lib/server/connectors/inbound-audio-transcription.ts +5 -14
- package/src/lib/server/connectors/media.ts +1 -1
- package/src/lib/server/connectors/response-media.ts +1 -1
- package/src/lib/server/connectors/session-consolidation.ts +11 -7
- package/src/lib/server/connectors/session.ts +9 -7
- package/src/lib/server/connectors/voice-note.ts +2 -1
- package/src/lib/server/context-manager.ts +20 -1
- package/src/lib/server/cost.ts +2 -3
- package/src/lib/server/credentials/credential-repository.ts +43 -4
- package/src/lib/server/credentials/credential-service.ts +112 -0
- package/src/lib/server/daemon/admin-metadata.ts +64 -0
- package/src/lib/server/daemon/controller.ts +577 -0
- package/src/lib/server/daemon/daemon-runtime.ts +352 -0
- package/src/lib/server/daemon/daemon-status-repository.ts +63 -0
- package/src/lib/server/daemon/types.ts +101 -0
- package/src/lib/server/embeddings.ts +3 -9
- package/src/lib/server/eval/agent-regression.ts +3 -2
- package/src/lib/server/eval/runner.ts +2 -2
- package/src/lib/server/execution-brief.test.ts +167 -0
- package/src/lib/server/execution-brief.ts +295 -0
- package/src/lib/server/execution-engine/chat-turn.ts +9 -0
- package/src/lib/server/execution-engine/import-boundary.test.ts +44 -0
- package/src/lib/server/execution-engine/index.ts +35 -0
- package/src/lib/server/execution-engine/task-attempt.ts +303 -0
- package/src/lib/server/execution-engine/types.ts +33 -0
- package/src/lib/server/gateways/gateway-profile-repository.ts +47 -3
- package/src/lib/server/gateways/gateway-profile-service.ts +200 -0
- package/src/lib/server/memory/session-archive-memory.ts +12 -10
- package/src/lib/server/messages/message-repository.ts +330 -0
- package/src/lib/server/missions/mission-service/core.ts +8 -6
- package/src/lib/server/openclaw/agent-resolver.ts +2 -3
- package/src/lib/server/openclaw/doctor.ts +1 -1
- package/src/lib/server/openclaw/gateway.test.ts +10 -1
- package/src/lib/server/openclaw/gateway.ts +5 -14
- package/src/lib/server/openclaw/health.ts +3 -11
- package/src/lib/server/openclaw/sync.ts +8 -6
- package/src/lib/server/persistence/storage-context.ts +3 -0
- package/src/lib/server/protocols/protocol-agent-turn.ts +25 -17
- package/src/lib/server/protocols/protocol-normalization.ts +1 -1
- package/src/lib/server/protocols/protocol-queries.ts +13 -7
- package/src/lib/server/protocols/protocol-run-lifecycle.ts +16 -20
- package/src/lib/server/protocols/protocol-run-repository.ts +81 -0
- package/src/lib/server/protocols/protocol-step-processors.ts +23 -31
- package/src/lib/server/protocols/protocol-swarm.ts +8 -8
- package/src/lib/server/protocols/protocol-template-repository.ts +42 -0
- package/src/lib/server/protocols/protocol-templates.ts +4 -2
- package/src/lib/server/protocols/protocol-types.ts +10 -7
- package/src/lib/server/provider-endpoint.ts +7 -12
- package/src/lib/server/provider-model-discovery.ts +2 -11
- package/src/lib/server/query-expansion.ts +5 -6
- package/src/lib/server/run-context.test.ts +365 -0
- package/src/lib/server/run-context.ts +367 -0
- package/src/lib/server/runtime/heartbeat-service.ts +7 -5
- package/src/lib/server/runtime/queue/core.ts +61 -190
- package/src/lib/server/runtime/run-ledger.ts +8 -0
- package/src/lib/server/runtime/session-run-manager/drain.ts +2 -2
- package/src/lib/server/runtime/session-run-manager/enqueue.ts +6 -0
- package/src/lib/server/runtime/session-run-manager/state.ts +4 -0
- package/src/lib/server/schedules/schedule-route-service.ts +230 -0
- package/src/lib/server/service-result.ts +16 -0
- package/src/lib/server/session-note.ts +2 -3
- package/src/lib/server/session-reset-policy.ts +4 -3
- package/src/lib/server/session-tools/connector.ts +9 -6
- package/src/lib/server/session-tools/context-mgmt.ts +58 -9
- package/src/lib/server/session-tools/crud.ts +162 -10
- package/src/lib/server/session-tools/delegate.ts +1 -1
- package/src/lib/server/session-tools/manage-tasks.test.ts +152 -0
- package/src/lib/server/session-tools/memory.ts +6 -4
- package/src/lib/server/session-tools/session-info.test.ts +56 -0
- package/src/lib/server/session-tools/session-info.ts +119 -12
- package/src/lib/server/session-tools/skill-runtime.ts +3 -1
- package/src/lib/server/session-tools/skills.ts +15 -15
- package/src/lib/server/session-tools/subagent.test.ts +115 -1
- package/src/lib/server/session-tools/subagent.ts +125 -7
- package/src/lib/server/session-tools/team-context.ts +4 -3
- package/src/lib/server/session-tools/wallet.ts +0 -58
- package/src/lib/server/sessions/session-lineage.ts +55 -0
- package/src/lib/server/sessions/session-repository.ts +2 -2
- package/src/lib/server/skills/learned-skills.ts +24 -23
- package/src/lib/server/skills/runtime-skill-resolver.ts +2 -1
- package/src/lib/server/skills/skill-repository.ts +136 -13
- package/src/lib/server/skills/skill-suggestions.ts +25 -28
- package/src/lib/server/storage-normalization.test.ts +44 -267
- package/src/lib/server/storage-normalization.ts +75 -0
- package/src/lib/server/storage.ts +19 -0
- package/src/lib/server/structured-extract.ts +3 -14
- package/src/lib/server/tasks/task-followups.ts +16 -11
- package/src/lib/server/tasks/task-result.test.ts +25 -29
- package/src/lib/server/tasks/task-result.ts +5 -9
- package/src/lib/server/tasks/task-route-service.ts +449 -0
- package/src/lib/server/text-normalization.ts +41 -0
- package/src/lib/server/tool-planning.ts +6 -42
- package/src/lib/server/upload-path.ts +5 -0
- package/src/lib/server/working-state/extraction.ts +614 -0
- package/src/lib/server/working-state/normalization.ts +866 -0
- package/src/lib/server/working-state/prompt.ts +60 -0
- package/src/lib/server/working-state/repository.ts +38 -0
- package/src/lib/server/working-state/service.test.ts +253 -0
- package/src/lib/server/working-state/service.ts +293 -0
- package/src/lib/validation/schemas.ts +1 -0
- package/src/lib/ws-client.ts +3 -3
- package/src/stores/slices/task-slice.ts +1 -4
- package/src/stores/use-chatroom-store.ts +2 -2
- package/src/types/index.ts +277 -12
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import type { Message, Session } from '@/types'
|
|
2
|
+
import { perf } from '@/lib/server/runtime/perf'
|
|
3
|
+
import { log } from '@/lib/server/logger'
|
|
4
|
+
import { getDb, withTransaction, loadSession, patchSession } from '@/lib/server/storage'
|
|
5
|
+
import { notify } from '@/lib/server/ws-hub'
|
|
6
|
+
|
|
7
|
+
const TAG = 'message-repo'
|
|
8
|
+
const MAX_SUMMARY_TEXT = 280
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Prepared statements — lazily created so the db is fully initialised first
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
type Stmts = ReturnType<typeof buildStatements>
|
|
15
|
+
let _stmts: Stmts | null = null
|
|
16
|
+
|
|
17
|
+
function stmts(): Stmts {
|
|
18
|
+
if (!_stmts) _stmts = buildStatements()
|
|
19
|
+
return _stmts
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function buildStatements() {
|
|
23
|
+
const db = getDb()
|
|
24
|
+
return {
|
|
25
|
+
selectAll: db.prepare(
|
|
26
|
+
'SELECT data FROM session_messages WHERE session_id = ? ORDER BY seq ASC',
|
|
27
|
+
),
|
|
28
|
+
selectCount: db.prepare(
|
|
29
|
+
'SELECT COUNT(*) as count FROM session_messages WHERE session_id = ?',
|
|
30
|
+
),
|
|
31
|
+
selectLast: db.prepare(
|
|
32
|
+
'SELECT data FROM session_messages WHERE session_id = ? ORDER BY seq DESC LIMIT 1',
|
|
33
|
+
),
|
|
34
|
+
selectRecent: db.prepare(
|
|
35
|
+
'SELECT data FROM session_messages WHERE session_id = ? ORDER BY seq DESC LIMIT ?',
|
|
36
|
+
),
|
|
37
|
+
selectMaxSeq: db.prepare(
|
|
38
|
+
'SELECT MAX(seq) as maxSeq FROM session_messages WHERE session_id = ?',
|
|
39
|
+
),
|
|
40
|
+
insert: db.prepare(
|
|
41
|
+
'INSERT INTO session_messages (session_id, seq, data) VALUES (?, ?, ?)',
|
|
42
|
+
),
|
|
43
|
+
update: db.prepare(
|
|
44
|
+
'UPDATE session_messages SET data = ? WHERE session_id = ? AND seq = ?',
|
|
45
|
+
),
|
|
46
|
+
deleteAfter: db.prepare(
|
|
47
|
+
'DELETE FROM session_messages WHERE session_id = ? AND seq > ?',
|
|
48
|
+
),
|
|
49
|
+
deleteAll: db.prepare(
|
|
50
|
+
'DELETE FROM session_messages WHERE session_id = ?',
|
|
51
|
+
),
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Internal helpers
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
function nextSeq(sessionId: string): number {
|
|
60
|
+
const row = stmts().selectMaxSeq.get(sessionId) as { maxSeq: number | null } | undefined
|
|
61
|
+
return (row?.maxSeq ?? -1) + 1
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function rowCount(sessionId: string): number {
|
|
65
|
+
return (stmts().selectCount.get(sessionId) as { count: number }).count
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function parseMsg(raw: string): Message | null {
|
|
69
|
+
try {
|
|
70
|
+
return JSON.parse(raw) as Message
|
|
71
|
+
} catch {
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function summarizeForMeta(message: Message): Message {
|
|
77
|
+
return {
|
|
78
|
+
role: message.role,
|
|
79
|
+
text: typeof message.text === 'string' ? message.text.slice(0, MAX_SUMMARY_TEXT) : '',
|
|
80
|
+
time: message.time,
|
|
81
|
+
kind: message.kind,
|
|
82
|
+
source: message.source,
|
|
83
|
+
suppressed: message.suppressed,
|
|
84
|
+
streaming: message.streaming,
|
|
85
|
+
bookmarked: message.bookmarked,
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Session metadata sync — keeps messageCount / lastMessageSummary on the blob
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
function syncSessionMeta(sessionId: string): void {
|
|
94
|
+
const count = rowCount(sessionId)
|
|
95
|
+
const lastRow = stmts().selectLast.get(sessionId) as { data: string } | undefined
|
|
96
|
+
const lastMsg = lastRow ? parseMsg(lastRow.data) : null
|
|
97
|
+
|
|
98
|
+
patchSession(sessionId, (current) => {
|
|
99
|
+
if (!current) return null
|
|
100
|
+
current.messageCount = count
|
|
101
|
+
current.lastMessageSummary = lastMsg ? summarizeForMeta(lastMsg) : null
|
|
102
|
+
if (lastMsg?.role === 'assistant' && typeof lastMsg.time === 'number') {
|
|
103
|
+
current.lastAssistantAt = lastMsg.time
|
|
104
|
+
}
|
|
105
|
+
current.lastActiveAt = Date.now()
|
|
106
|
+
return current
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// Lazy migration — copies blob messages → table on first access
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
function ensureMigrated(sessionId: string): void {
|
|
115
|
+
if (rowCount(sessionId) > 0) return
|
|
116
|
+
lazyMigrateSession(sessionId)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function lazyMigrateSession(sessionId: string): Message[] | null {
|
|
120
|
+
const session = loadSession(sessionId)
|
|
121
|
+
if (!session || !Array.isArray(session.messages) || session.messages.length === 0) {
|
|
122
|
+
return null
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const messages = session.messages
|
|
126
|
+
log.info(TAG, `Lazy-migrating ${messages.length} messages for session ${sessionId}`)
|
|
127
|
+
|
|
128
|
+
withTransaction(() => {
|
|
129
|
+
// Double-check inside transaction to prevent duplicate migration
|
|
130
|
+
if (rowCount(sessionId) > 0) return
|
|
131
|
+
|
|
132
|
+
const ins = stmts().insert
|
|
133
|
+
for (let i = 0; i < messages.length; i++) {
|
|
134
|
+
ins.run(sessionId, i, JSON.stringify(messages[i]))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Compute metadata on the blob (keep messages intact for backward compat)
|
|
138
|
+
const lastMsg = messages[messages.length - 1]
|
|
139
|
+
let lastAssistantAt: number | null = null
|
|
140
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
141
|
+
if (messages[i].role === 'assistant' && typeof messages[i].time === 'number') {
|
|
142
|
+
lastAssistantAt = messages[i].time
|
|
143
|
+
break
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
patchSession(sessionId, (current) => {
|
|
148
|
+
if (!current) return null
|
|
149
|
+
current.messageCount = messages.length
|
|
150
|
+
current.lastMessageSummary = lastMsg ? summarizeForMeta(lastMsg) : null
|
|
151
|
+
if (lastAssistantAt !== null && typeof current.lastAssistantAt !== 'number') {
|
|
152
|
+
current.lastAssistantAt = lastAssistantAt
|
|
153
|
+
}
|
|
154
|
+
return current
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
return messages
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
// Public API
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
|
|
165
|
+
/** Return all messages for a session, ordered by sequence. */
|
|
166
|
+
export function getMessages(sessionId: string): Message[] {
|
|
167
|
+
return perf.measureSync('message-repo', 'getMessages', () => {
|
|
168
|
+
const rows = stmts().selectAll.all(sessionId) as Array<{ data: string }>
|
|
169
|
+
|
|
170
|
+
// Lazy migration: populate table from session blob on first read
|
|
171
|
+
if (rows.length === 0) {
|
|
172
|
+
const migrated = lazyMigrateSession(sessionId)
|
|
173
|
+
if (migrated) return migrated
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const out: Message[] = []
|
|
177
|
+
for (const row of rows) {
|
|
178
|
+
const m = parseMsg(row.data)
|
|
179
|
+
if (m) out.push(m)
|
|
180
|
+
}
|
|
181
|
+
return out
|
|
182
|
+
}, { sessionId })
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Return message count (from table, with blob fallback pre-migration). */
|
|
186
|
+
export function getMessageCount(sessionId: string): number {
|
|
187
|
+
return perf.measureSync('message-repo', 'getMessageCount', () => {
|
|
188
|
+
const count = rowCount(sessionId)
|
|
189
|
+
if (count > 0) return count
|
|
190
|
+
// Pre-migration fallback
|
|
191
|
+
const session = loadSession(sessionId)
|
|
192
|
+
return Array.isArray(session?.messages) ? session.messages.length : 0
|
|
193
|
+
}, { sessionId })
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Return the last message (from table, with blob fallback). */
|
|
197
|
+
export function getLastMessage(sessionId: string): Message | null {
|
|
198
|
+
return perf.measureSync('message-repo', 'getLastMessage', () => {
|
|
199
|
+
const row = stmts().selectLast.get(sessionId) as { data: string } | undefined
|
|
200
|
+
if (row) return parseMsg(row.data)
|
|
201
|
+
const session = loadSession(sessionId)
|
|
202
|
+
const msgs = session?.messages
|
|
203
|
+
return Array.isArray(msgs) && msgs.length > 0 ? msgs[msgs.length - 1] : null
|
|
204
|
+
}, { sessionId })
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Return the last N messages in chronological order. */
|
|
208
|
+
export function getRecentMessages(sessionId: string, n: number): Message[] {
|
|
209
|
+
return perf.measureSync('message-repo', 'getRecentMessages', () => {
|
|
210
|
+
const rows = stmts().selectRecent.all(sessionId, n) as Array<{ data: string }>
|
|
211
|
+
if (rows.length > 0) {
|
|
212
|
+
const out: Message[] = []
|
|
213
|
+
for (const row of rows) {
|
|
214
|
+
const m = parseMsg(row.data)
|
|
215
|
+
if (m) out.push(m)
|
|
216
|
+
}
|
|
217
|
+
return out.reverse() // DESC → ASC
|
|
218
|
+
}
|
|
219
|
+
// Pre-migration fallback
|
|
220
|
+
const session = loadSession(sessionId)
|
|
221
|
+
return Array.isArray(session?.messages) ? session.messages.slice(-n) : []
|
|
222
|
+
}, { sessionId, n })
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Append a single message. Returns the assigned sequence number. */
|
|
226
|
+
export function appendMessage(sessionId: string, message: Message): number {
|
|
227
|
+
return perf.measureSync('message-repo', 'appendMessage', () => {
|
|
228
|
+
ensureMigrated(sessionId)
|
|
229
|
+
const seq = nextSeq(sessionId)
|
|
230
|
+
stmts().insert.run(sessionId, seq, JSON.stringify(message))
|
|
231
|
+
syncSessionMeta(sessionId)
|
|
232
|
+
notify('messages', 'append', sessionId)
|
|
233
|
+
return seq
|
|
234
|
+
}, { sessionId })
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Append multiple messages in a single transaction. */
|
|
238
|
+
export function appendMessages(sessionId: string, messages: Message[]): void {
|
|
239
|
+
if (!messages.length) return
|
|
240
|
+
perf.measureSync('message-repo', 'appendMessages', () => {
|
|
241
|
+
ensureMigrated(sessionId)
|
|
242
|
+
withTransaction(() => {
|
|
243
|
+
let seq = nextSeq(sessionId)
|
|
244
|
+
const ins = stmts().insert
|
|
245
|
+
for (const msg of messages) {
|
|
246
|
+
ins.run(sessionId, seq++, JSON.stringify(msg))
|
|
247
|
+
}
|
|
248
|
+
})
|
|
249
|
+
syncSessionMeta(sessionId)
|
|
250
|
+
notify('messages', 'append', sessionId)
|
|
251
|
+
}, { sessionId, count: messages.length })
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Replace the message at a given sequence number (e.g. replace-last-assistant). */
|
|
255
|
+
export function replaceMessageAt(sessionId: string, seq: number, message: Message): void {
|
|
256
|
+
perf.measureSync('message-repo', 'replaceMessageAt', () => {
|
|
257
|
+
stmts().update.run(JSON.stringify(message), sessionId, seq)
|
|
258
|
+
syncSessionMeta(sessionId)
|
|
259
|
+
notify('messages', 'update', sessionId)
|
|
260
|
+
}, { sessionId, seq })
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Delete all messages with seq > the given value (edit-and-resend). */
|
|
264
|
+
export function truncateAfter(sessionId: string, seq: number): void {
|
|
265
|
+
perf.measureSync('message-repo', 'truncateAfter', () => {
|
|
266
|
+
stmts().deleteAfter.run(sessionId, seq)
|
|
267
|
+
syncSessionMeta(sessionId)
|
|
268
|
+
notify('messages', 'truncate', sessionId)
|
|
269
|
+
}, { sessionId, seq })
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Remove all messages for a session. */
|
|
273
|
+
export function clearMessages(sessionId: string): void {
|
|
274
|
+
perf.measureSync('message-repo', 'clearMessages', () => {
|
|
275
|
+
stmts().deleteAll.run(sessionId)
|
|
276
|
+
syncSessionMeta(sessionId)
|
|
277
|
+
notify('messages', 'clear', sessionId)
|
|
278
|
+
}, { sessionId })
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** Replace the entire message list (used after in-memory prune operations). */
|
|
282
|
+
export function replaceAllMessages(sessionId: string, messages: Message[]): void {
|
|
283
|
+
perf.measureSync('message-repo', 'replaceAllMessages', () => {
|
|
284
|
+
withTransaction(() => {
|
|
285
|
+
stmts().deleteAll.run(sessionId)
|
|
286
|
+
const ins = stmts().insert
|
|
287
|
+
for (let i = 0; i < messages.length; i++) {
|
|
288
|
+
ins.run(sessionId, i, JSON.stringify(messages[i]))
|
|
289
|
+
}
|
|
290
|
+
})
|
|
291
|
+
syncSessionMeta(sessionId)
|
|
292
|
+
notify('messages', 'replace', sessionId)
|
|
293
|
+
}, { sessionId, count: messages.length })
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** Cleanup: delete all rows for a session (called on session delete). */
|
|
297
|
+
export function deleteSessionMessages(sessionId: string): void {
|
|
298
|
+
stmts().deleteAll.run(sessionId)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ---------------------------------------------------------------------------
|
|
302
|
+
// Bulk migration (for CLI / admin endpoint)
|
|
303
|
+
// ---------------------------------------------------------------------------
|
|
304
|
+
|
|
305
|
+
export function migrateAllSessions(): { migrated: number; skipped: number; total: number } {
|
|
306
|
+
const db = getDb()
|
|
307
|
+
const rows = db.prepare('SELECT id, data FROM sessions').all() as Array<{ id: string; data: string }>
|
|
308
|
+
let migrated = 0
|
|
309
|
+
let skipped = 0
|
|
310
|
+
|
|
311
|
+
for (const row of rows) {
|
|
312
|
+
try {
|
|
313
|
+
const session = JSON.parse(row.data) as Session
|
|
314
|
+
if (!Array.isArray(session.messages) || session.messages.length === 0) {
|
|
315
|
+
skipped++
|
|
316
|
+
continue
|
|
317
|
+
}
|
|
318
|
+
if (rowCount(row.id) > 0) {
|
|
319
|
+
skipped++
|
|
320
|
+
continue
|
|
321
|
+
}
|
|
322
|
+
lazyMigrateSession(row.id)
|
|
323
|
+
migrated++
|
|
324
|
+
} catch {
|
|
325
|
+
skipped++
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return { migrated, skipped, total: rows.length }
|
|
330
|
+
}
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
SessionQueuedTurn,
|
|
19
19
|
SessionRunRecord,
|
|
20
20
|
} from '@/types'
|
|
21
|
+
import { getMessages } from '@/lib/server/messages/message-repository'
|
|
21
22
|
import { loadApprovals } from '@/lib/server/approvals/approval-repository'
|
|
22
23
|
import { loadDelegationJob } from '@/lib/server/agents/delegation-job-repository'
|
|
23
24
|
import { logActivity } from '@/lib/server/activity/activity-log'
|
|
@@ -49,6 +50,8 @@ import { errorMessage, hmrSingleton } from '@/lib/shared-utils'
|
|
|
49
50
|
import { getSessionQueueSnapshot, listRuns } from '@/lib/server/runtime/session-run-manager'
|
|
50
51
|
import { loadTask, loadTasks, patchTask } from '@/lib/server/tasks/task-repository'
|
|
51
52
|
import { notify } from '@/lib/server/ws-hub'
|
|
53
|
+
import { buildExecutionBrief, buildExecutionBriefContextBlock } from '@/lib/server/execution-brief'
|
|
54
|
+
import { cleanText } from '@/lib/server/text-normalization'
|
|
52
55
|
|
|
53
56
|
const TAG = 'mission-service'
|
|
54
57
|
|
|
@@ -56,10 +59,6 @@ function now(): number {
|
|
|
56
59
|
return Date.now()
|
|
57
60
|
}
|
|
58
61
|
|
|
59
|
-
function cleanText(value: unknown, max = 320): string {
|
|
60
|
-
return typeof value === 'string' ? value.replace(/\s+/g, ' ').trim().slice(0, max) : ''
|
|
61
|
-
}
|
|
62
|
-
|
|
63
62
|
function uniqueStrings(values: unknown, maxItems: number, maxChars = 180): string[] {
|
|
64
63
|
const source = Array.isArray(values) ? values : []
|
|
65
64
|
const out: string[] = []
|
|
@@ -1571,7 +1570,7 @@ export async function resolveMissionForTurn(params: {
|
|
|
1571
1570
|
sessionId: params.session.id,
|
|
1572
1571
|
agentId: params.session.agentId || null,
|
|
1573
1572
|
message: params.message,
|
|
1574
|
-
recentMessages:
|
|
1573
|
+
recentMessages: getMessages(params.session.id),
|
|
1575
1574
|
currentMission: currentMission ? buildMissionSummary(currentMission) : null,
|
|
1576
1575
|
session: params.session,
|
|
1577
1576
|
}, params.generateText ? { generateText: params.generateText } : undefined)
|
|
@@ -2254,7 +2253,10 @@ export function buildMissionContextBlock(mission: Mission | null | undefined): s
|
|
|
2254
2253
|
export function buildMissionHeartbeatPrompt(session: Session, fallbackPrompt: string): string | null {
|
|
2255
2254
|
const mission = getMissionForSession(session)
|
|
2256
2255
|
if (!mission || isMissionTerminal(mission.status)) return null
|
|
2257
|
-
const contextBlock =
|
|
2256
|
+
const contextBlock = buildExecutionBriefContextBlock(buildExecutionBrief({
|
|
2257
|
+
session,
|
|
2258
|
+
mission,
|
|
2259
|
+
}))
|
|
2258
2260
|
return [
|
|
2259
2261
|
'MAIN_AGENT_HEARTBEAT_TICK',
|
|
2260
2262
|
`Time: ${new Date().toISOString()}`,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Agent } from '@/types'
|
|
2
2
|
import { normalizeOpenClawAgentId } from '@/lib/openclaw/openclaw-agent-id'
|
|
3
|
+
import { loadAgent } from '@/lib/server/agents/agent-repository'
|
|
3
4
|
import { ensureGatewayConnected, type OpenClawGateway } from './gateway'
|
|
4
|
-
import { loadAgents } from '../storage'
|
|
5
5
|
|
|
6
6
|
export interface OpenClawGatewayAgentSummary {
|
|
7
7
|
id: string
|
|
@@ -101,8 +101,7 @@ export async function resolveOpenClawGatewayAgentId(
|
|
|
101
101
|
throw new Error('Missing agentId')
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
const
|
|
105
|
-
const localAgent = localAgents[trimmedRef] || null
|
|
104
|
+
const localAgent = loadAgent(trimmedRef, { includeTrashed: true }) as Agent | null
|
|
106
105
|
if (localAgent && localAgent.provider !== 'openclaw') {
|
|
107
106
|
throw new Error(`Agent "${localAgent.name}" is not an OpenClaw agent`)
|
|
108
107
|
}
|
|
@@ -2,7 +2,7 @@ import { execFile } from 'child_process'
|
|
|
2
2
|
import { promisify } from 'util'
|
|
3
3
|
import * as path from 'path'
|
|
4
4
|
import * as os from 'os'
|
|
5
|
-
import { loadSettings } from '../
|
|
5
|
+
import { loadSettings } from '../settings/settings-repository'
|
|
6
6
|
|
|
7
7
|
const execFileAsync = promisify(execFile)
|
|
8
8
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import assert from 'node:assert/strict'
|
|
2
|
-
import { afterEach, test } from 'node:test'
|
|
2
|
+
import { afterEach, beforeEach, test } from 'node:test'
|
|
3
3
|
|
|
4
4
|
import type { Agent, GatewayProfile } from '@/types'
|
|
5
5
|
import {
|
|
6
|
+
deleteAgent,
|
|
6
7
|
encryptKey,
|
|
7
8
|
loadAgents,
|
|
8
9
|
loadCredentials,
|
|
@@ -24,6 +25,14 @@ const originalCredentials = loadCredentials()
|
|
|
24
25
|
const originalGateways = loadGatewayProfiles()
|
|
25
26
|
const originalAgents = loadAgents({ includeTrashed: true })
|
|
26
27
|
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
saveCredentials({})
|
|
30
|
+
saveGatewayProfiles({})
|
|
31
|
+
for (const agentId of Object.keys(loadAgents({ includeTrashed: true }))) {
|
|
32
|
+
deleteAgent(agentId)
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
27
36
|
afterEach(() => {
|
|
28
37
|
disconnectGateway()
|
|
29
38
|
saveCredentials(originalCredentials)
|
|
@@ -2,7 +2,8 @@ import { WebSocket } from 'ws'
|
|
|
2
2
|
import { randomUUID } from 'crypto'
|
|
3
3
|
import { wsConnect } from '@/lib/providers/openclaw'
|
|
4
4
|
import { deriveOpenClawWsUrl } from '@/lib/openclaw/openclaw-endpoint'
|
|
5
|
-
import {
|
|
5
|
+
import { loadAgent, loadAgents } from '@/lib/server/agents/agent-repository'
|
|
6
|
+
import { resolveCredentialSecret } from '@/lib/server/credentials/credential-service'
|
|
6
7
|
import { notify, notifyWithPayload } from '../ws-hub'
|
|
7
8
|
import { getGatewayProfile, getGatewayProfiles, resolvePrimaryAgentRoute } from '@/lib/server/agents/agent-runtime-config'
|
|
8
9
|
import { isAgentDisabled } from '@/lib/server/agents/agent-availability'
|
|
@@ -80,16 +81,7 @@ function normalizeWsUrl(raw: string): string {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
function resolveTokenForCredential(credentialId?: string | null): string | undefined {
|
|
83
|
-
|
|
84
|
-
if (!id) return undefined
|
|
85
|
-
const creds = loadCredentials()
|
|
86
|
-
const cred = creds[id]
|
|
87
|
-
if (!cred?.encryptedKey) return undefined
|
|
88
|
-
try {
|
|
89
|
-
return decryptKey(cred.encryptedKey)
|
|
90
|
-
} catch {
|
|
91
|
-
return undefined
|
|
92
|
-
}
|
|
84
|
+
return resolveCredentialSecret(credentialId) || undefined
|
|
93
85
|
}
|
|
94
86
|
|
|
95
87
|
export function resolveGatewayConfig(target?: {
|
|
@@ -110,8 +102,7 @@ export function resolveGatewayConfig(target?: {
|
|
|
110
102
|
|
|
111
103
|
const agentId = typeof target?.agentId === 'string' ? target.agentId.trim() : ''
|
|
112
104
|
if (agentId) {
|
|
113
|
-
const
|
|
114
|
-
const agent = agents[agentId] as Agent | undefined
|
|
105
|
+
const agent = loadAgent(agentId, { includeTrashed: true }) as Agent | null
|
|
115
106
|
const config = agent ? buildGatewayConfigFromAgent(agent, { allowDisabled: true, allowTrashed: true }) : null
|
|
116
107
|
if (config) return config
|
|
117
108
|
}
|
|
@@ -236,7 +227,7 @@ export class OpenClawGateway {
|
|
|
236
227
|
}
|
|
237
228
|
|
|
238
229
|
private rejectAllPending(reason: string) {
|
|
239
|
-
for (const
|
|
230
|
+
for (const p of this.pending.values()) {
|
|
240
231
|
clearTimeout(p.timer)
|
|
241
232
|
p.reject(new Error(reason))
|
|
242
233
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { deriveOpenClawWsUrl, normalizeOpenClawEndpoint } from '@/lib/openclaw/openclaw-endpoint'
|
|
2
2
|
import { wsConnect } from '@/lib/providers/openclaw'
|
|
3
|
-
import {
|
|
3
|
+
import { resolveCredentialSecret } from '@/lib/server/credentials/credential-service'
|
|
4
|
+
import { loadGatewayProfiles, saveGatewayProfiles } from '@/lib/server/gateways/gateway-profile-repository'
|
|
4
5
|
import { notify } from '../ws-hub'
|
|
5
6
|
import type { GatewayProfile } from '@/types'
|
|
6
7
|
|
|
@@ -60,16 +61,7 @@ function getErrorMessage(err: unknown): string | undefined {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
function resolveCredentialToken(credentialId?: string | null): string | null {
|
|
63
|
-
|
|
64
|
-
if (!id) return null
|
|
65
|
-
const credentials = loadCredentials()
|
|
66
|
-
const credential = credentials[id]
|
|
67
|
-
if (!credential?.encryptedKey) return null
|
|
68
|
-
try {
|
|
69
|
-
return decryptKey(credential.encryptedKey)
|
|
70
|
-
} catch {
|
|
71
|
-
return null
|
|
72
|
-
}
|
|
64
|
+
return resolveCredentialSecret(normalizeToken(credentialId))
|
|
73
65
|
}
|
|
74
66
|
|
|
75
67
|
function extractModels(payload: unknown): string[] {
|
|
@@ -4,8 +4,11 @@ import path from 'node:path'
|
|
|
4
4
|
import crypto from 'node:crypto'
|
|
5
5
|
import { DATA_DIR } from '../data-dir'
|
|
6
6
|
import { normalizeOpenClawAgentId } from '@/lib/openclaw/openclaw-agent-id'
|
|
7
|
-
import {
|
|
7
|
+
import { loadAgents, upsertAgent } from '@/lib/server/agents/agent-repository'
|
|
8
|
+
import { decryptKey, encryptKey, loadCredentials, saveCredentials } from '@/lib/server/credentials/credential-repository'
|
|
8
9
|
import { getMemoryDb } from '@/lib/server/memory/memory-db'
|
|
10
|
+
import { loadSchedules, upsertSchedules } from '@/lib/server/schedules/schedule-repository'
|
|
11
|
+
import { loadSettings } from '@/lib/server/settings/settings-repository'
|
|
9
12
|
import type { AppSettings, MemoryEntry, Schedule } from '@/types'
|
|
10
13
|
|
|
11
14
|
export interface OpenClawSyncConfig {
|
|
@@ -289,7 +292,7 @@ export function pullSchedulesFromOpenClaw(): { imported: number } {
|
|
|
289
292
|
if (existingNames.has(key)) continue
|
|
290
293
|
|
|
291
294
|
const id = crypto.randomUUID()
|
|
292
|
-
const schedule = {
|
|
295
|
+
const schedule: Schedule = {
|
|
293
296
|
id,
|
|
294
297
|
name: job.name,
|
|
295
298
|
agentId: job.agentId || '',
|
|
@@ -299,8 +302,8 @@ export function pullSchedulesFromOpenClaw(): { imported: number } {
|
|
|
299
302
|
status: 'active',
|
|
300
303
|
createdAt: Date.now(),
|
|
301
304
|
}
|
|
302
|
-
schedules[id] = schedule
|
|
303
|
-
importedEntries.push([id, schedule
|
|
305
|
+
schedules[id] = schedule
|
|
306
|
+
importedEntries.push([id, schedule])
|
|
304
307
|
existingNames.add(key)
|
|
305
308
|
imported++
|
|
306
309
|
}
|
|
@@ -324,8 +327,7 @@ export async function pullCredentialsFromOpenClaw(): Promise<{ imported: number
|
|
|
324
327
|
return { imported: 0 }
|
|
325
328
|
}
|
|
326
329
|
|
|
327
|
-
const
|
|
328
|
-
const creds = loadCreds()
|
|
330
|
+
const creds = loadCredentials()
|
|
329
331
|
const existingProviders = new Set(Object.values(creds).map((c: Record<string, unknown>) => c.provider))
|
|
330
332
|
let imported = 0
|
|
331
333
|
|
|
@@ -4,6 +4,7 @@ import { agentRepository } from '@/lib/server/agents/agent-repository'
|
|
|
4
4
|
import { approvalRepository } from '@/lib/server/approvals/approval-repository'
|
|
5
5
|
import { chatroomRepository } from '@/lib/server/chatrooms/chatroom-repository'
|
|
6
6
|
import { connectorRepository } from '@/lib/server/connectors/connector-repository'
|
|
7
|
+
import * as messageRepository from '@/lib/server/messages/message-repository'
|
|
7
8
|
import { missionEventRepository, missionRepository } from '@/lib/server/missions/mission-repository'
|
|
8
9
|
import { projectRepository } from '@/lib/server/projects/project-repository'
|
|
9
10
|
import { scheduleRepository } from '@/lib/server/schedules/schedule-repository'
|
|
@@ -17,6 +18,7 @@ export interface StorageTxContext {
|
|
|
17
18
|
approvals: typeof approvalRepository
|
|
18
19
|
chatrooms: typeof chatroomRepository
|
|
19
20
|
connectors: typeof connectorRepository
|
|
21
|
+
messages: typeof messageRepository
|
|
20
22
|
missions: typeof missionRepository
|
|
21
23
|
missionEvents: typeof missionEventRepository
|
|
22
24
|
projects: typeof projectRepository
|
|
@@ -34,6 +36,7 @@ export function createStorageTxContext(): StorageTxContext {
|
|
|
34
36
|
approvals: approvalRepository,
|
|
35
37
|
chatrooms: chatroomRepository,
|
|
36
38
|
connectors: connectorRepository,
|
|
39
|
+
messages: messageRepository,
|
|
37
40
|
missions: missionRepository,
|
|
38
41
|
missionEvents: missionEventRepository,
|
|
39
42
|
projects: projectRepository,
|
|
@@ -29,14 +29,19 @@ import {
|
|
|
29
29
|
import { streamAgentChat } from '@/lib/server/chat-execution/stream-agent-chat'
|
|
30
30
|
import { shouldSuppressHiddenControlText, stripHiddenControlTokens } from '@/lib/server/agents/assistant-control'
|
|
31
31
|
import { resolvePrimaryAgentRoute } from '@/lib/server/agents/agent-runtime-config'
|
|
32
|
+
import { getAgent, getAgents } from '@/lib/server/agents/agent-repository'
|
|
32
33
|
import { buildLLM } from '@/lib/server/build-llm'
|
|
33
34
|
import {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
patchProtocolRun,
|
|
35
|
+
loadChatroom,
|
|
36
|
+
patchChatroom,
|
|
37
37
|
upsertChatroom,
|
|
38
|
+
} from '@/lib/server/chatrooms/chatroom-repository'
|
|
39
|
+
import {
|
|
40
|
+
loadProtocolRunEventsByRunId,
|
|
41
|
+
patchProtocolRun,
|
|
42
|
+
upsertProtocolRun,
|
|
38
43
|
upsertProtocolRunEvent,
|
|
39
|
-
} from '@/lib/server/
|
|
44
|
+
} from '@/lib/server/protocols/protocol-run-repository'
|
|
40
45
|
import { notify } from '@/lib/server/ws-hub'
|
|
41
46
|
import { errorMessage } from '@/lib/shared-utils'
|
|
42
47
|
import { AGENT_TURN_TIMEOUT_MS, cleanText, now } from '@/lib/server/protocols/protocol-types'
|
|
@@ -76,22 +81,24 @@ export function appendProtocolEvent(runId: string, event: Omit<ProtocolRunEvent,
|
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
export function listEvents(runId: string): ProtocolRunEvent[] {
|
|
79
|
-
const { loadProtocolRunEventsByRunId } = require('@/lib/server/storage') as typeof import('@/lib/server/storage')
|
|
80
84
|
return loadProtocolRunEventsByRunId(runId)
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
export function appendTranscriptMessage(chatroomId: string, message: Omit<ChatroomMessage, 'id' | 'time'>, deps?: ProtocolRunDeps): ChatroomMessage | null {
|
|
84
|
-
const chatrooms = loadChatrooms()
|
|
85
|
-
const chatroom = chatrooms[chatroomId]
|
|
86
|
-
if (!chatroom) return null
|
|
87
88
|
const nextMessage: ChatroomMessage = {
|
|
88
89
|
...message,
|
|
89
90
|
id: genId(),
|
|
90
91
|
time: now(deps),
|
|
91
92
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
const updated = patchChatroom(chatroomId, (current) => {
|
|
94
|
+
if (!current) return null
|
|
95
|
+
return {
|
|
96
|
+
...current,
|
|
97
|
+
messages: Array.isArray(current.messages) ? [...current.messages, nextMessage] : [nextMessage],
|
|
98
|
+
updatedAt: nextMessage.time,
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
if (!updated) return null
|
|
95
102
|
notify(`chatroom:${chatroomId}`)
|
|
96
103
|
return nextMessage
|
|
97
104
|
}
|
|
@@ -184,8 +191,7 @@ export async function defaultExecuteAgentTurn(params: {
|
|
|
184
191
|
agentId: string
|
|
185
192
|
prompt: string
|
|
186
193
|
}): Promise<ProtocolAgentTurnResult> {
|
|
187
|
-
const
|
|
188
|
-
const agent = agents[params.agentId]
|
|
194
|
+
const agent = getAgent(params.agentId) as Agent | null
|
|
189
195
|
if (!agent) throw new Error(`Agent not found: ${params.agentId}`)
|
|
190
196
|
let run = params.run
|
|
191
197
|
if (!run.transcriptChatroomId) {
|
|
@@ -201,8 +207,12 @@ export async function defaultExecuteAgentTurn(params: {
|
|
|
201
207
|
updatedAt: Date.now(),
|
|
202
208
|
})
|
|
203
209
|
}
|
|
204
|
-
const chatroom =
|
|
210
|
+
const chatroom = loadChatroom(run.transcriptChatroomId!)
|
|
205
211
|
if (!chatroom) throw new Error(`Structured session transcript room not found: ${run.transcriptChatroomId}`)
|
|
212
|
+
const agents = {
|
|
213
|
+
...getAgents(chatroom.agentIds),
|
|
214
|
+
[agent.id]: agent,
|
|
215
|
+
} as Record<string, Agent>
|
|
206
216
|
|
|
207
217
|
const route = resolvePrimaryAgentRoute(agent)
|
|
208
218
|
const apiKey = resolveApiKey(route?.credentialId || agent.credentialId)
|
|
@@ -369,8 +379,7 @@ export function createTranscriptRoom(input: {
|
|
|
369
379
|
participantAgentIds: string[]
|
|
370
380
|
parentChatroomId?: string | null
|
|
371
381
|
}, deps?: ProtocolRunDeps): Chatroom {
|
|
372
|
-
const
|
|
373
|
-
const parentChatroom = input.parentChatroomId ? chatrooms[input.parentChatroomId] || null : null
|
|
382
|
+
const parentChatroom = input.parentChatroomId ? loadChatroom(input.parentChatroomId) : null
|
|
374
383
|
const room: Chatroom = {
|
|
375
384
|
id: genId(),
|
|
376
385
|
name: transcriptRoomName(input.title, parentChatroom),
|
|
@@ -404,7 +413,6 @@ export function createArtifact(run: ProtocolRun, phase: ProtocolPhaseDefinition,
|
|
|
404
413
|
|
|
405
414
|
export function persistRun(run: ProtocolRun): ProtocolRun {
|
|
406
415
|
const normalized = normalizeProtocolRun(run)
|
|
407
|
-
const { upsertProtocolRun } = require('@/lib/server/storage') as typeof import('@/lib/server/storage')
|
|
408
416
|
upsertProtocolRun(normalized.id, normalized)
|
|
409
417
|
notify('protocol_runs')
|
|
410
418
|
notify(`protocol_run:${normalized.id}`)
|