@swarmclawai/swarmclaw 1.2.6 → 1.2.9
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 +54 -23
- package/next.config.ts +1 -0
- package/package.json +4 -3
- package/scripts/easy-setup.mjs +1 -1
- package/scripts/postinstall.mjs +1 -1
- package/skills/swarmclaw.md +115 -0
- package/skills/tools/browser.md +131 -0
- package/skills/tools/execute.md +98 -0
- package/skills/tools/files.md +98 -0
- package/skills/tools/memory.md +104 -0
- package/skills/tools/platform.md +144 -0
- package/skills/tools/skills.md +83 -0
- package/src/app/agents/[id]/page.tsx +1 -18
- package/src/app/api/agents/thread-route.test.ts +0 -1
- package/src/app/api/approvals/route.test.ts +6 -22
- package/src/app/api/chats/[id]/messages/route.ts +23 -19
- package/src/app/api/chats/messages-route.test.ts +105 -51
- package/src/app/api/connectors/route.ts +2 -2
- package/src/app/api/mcp-servers/[id]/test/route.ts +3 -2
- package/src/app/api/openclaw/deploy/route.ts +2 -0
- package/src/app/api/portability/export/route.ts +8 -0
- package/src/app/api/portability/import/route.test.ts +80 -0
- package/src/app/api/portability/import/route.ts +28 -0
- package/src/app/api/settings/route.ts +0 -2
- package/src/app/api/setup/doctor/route.ts +4 -4
- package/src/app/api/wallets/[id]/route.ts +15 -157
- package/src/app/api/wallets/generate/route.ts +22 -0
- package/src/app/api/wallets/route.test.ts +147 -0
- package/src/app/api/wallets/route.ts +13 -95
- package/src/app/autonomy/page.tsx +2 -57
- package/src/app/protocols/page.tsx +2 -21
- package/src/app/settings/page.tsx +0 -9
- package/src/app/wallets/page.tsx +105 -5
- package/src/cli/index.js +21 -33
- package/src/cli/spec.js +19 -30
- package/src/components/agents/agent-chat-list.tsx +23 -1
- package/src/components/agents/agent-sheet.tsx +2 -40
- package/src/components/agents/inspector-panel.tsx +165 -131
- package/src/components/chat/chat-area.tsx +38 -9
- package/src/components/chat/chat-card.tsx +0 -31
- package/src/components/chat/message-bubble.tsx +1 -108
- package/src/components/chat/message-list.tsx +33 -19
- package/src/components/connectors/connector-sheet.tsx +25 -1
- package/src/components/gateways/gateway-sheet.tsx +5 -2
- package/src/components/layout/sidebar-rail.tsx +6 -10
- package/src/components/projects/project-detail.tsx +3 -35
- package/src/components/projects/tabs/overview-tab.tsx +3 -59
- package/src/components/projects/tabs/work-tab.tsx +7 -77
- package/src/components/protocols/structured-session-launcher.tsx +1 -22
- package/src/components/shared/connector-platform-icon.tsx +1 -0
- package/src/components/tasks/task-card.tsx +4 -34
- package/src/components/tasks/task-sheet.tsx +6 -36
- package/src/components/wallets/wallet-list.tsx +150 -0
- package/src/lib/agent-execute-defaults.test.ts +24 -0
- package/src/lib/agent-execute-defaults.ts +62 -0
- package/src/lib/app/navigation.test.ts +0 -13
- package/src/lib/app/navigation.ts +2 -7
- package/src/lib/app/view-constants.ts +14 -19
- package/src/lib/chat/queued-message-queue.test.ts +134 -1
- package/src/lib/chat/queued-message-queue.ts +77 -2
- package/src/lib/server/agents/agent-service.ts +5 -0
- package/src/lib/server/agents/agent-thread-session.ts +0 -1
- package/src/lib/server/agents/delegation-advisory.test.ts +0 -1
- package/src/lib/server/agents/delegation-jobs.test.ts +0 -69
- package/src/lib/server/agents/delegation-jobs.ts +0 -25
- package/src/lib/server/agents/main-agent-loop.ts +1 -49
- package/src/lib/server/agents/subagent-runtime.ts +0 -1
- package/src/lib/server/approval-match.ts +0 -85
- package/src/lib/server/approvals.test.ts +6 -6
- package/src/lib/server/approvals.ts +0 -6
- package/src/lib/server/autonomy/supervisor-reflection.test.ts +0 -1
- package/src/lib/server/builtin-extensions.ts +1 -2
- package/src/lib/server/capability-router.test.ts +0 -2
- package/src/lib/server/chat-execution/chat-execution-advanced.test.ts +1 -1
- package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +15 -14
- package/src/lib/server/chat-execution/chat-execution-types.ts +0 -2
- package/src/lib/server/chat-execution/chat-execution-utils.ts +2 -4
- package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -30
- package/src/lib/server/chat-execution/chat-turn-finalization.ts +1 -36
- package/src/lib/server/chat-execution/chat-turn-preparation.ts +81 -64
- package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -0
- package/src/lib/server/chat-execution/continuation-evaluator.ts +8 -0
- package/src/lib/server/chat-execution/iteration-event-handler.ts +0 -24
- package/src/lib/server/chat-execution/memory-mutation-tools.ts +1 -1
- package/src/lib/server/chat-execution/message-classifier.test.ts +0 -45
- package/src/lib/server/chat-execution/message-classifier.ts +11 -16
- package/src/lib/server/chat-execution/prompt-builder.test.ts +27 -0
- package/src/lib/server/chat-execution/prompt-builder.ts +14 -31
- package/src/lib/server/chat-execution/prompt-mode.test.ts +24 -0
- package/src/lib/server/chat-execution/prompt-mode.ts +5 -1
- package/src/lib/server/chat-execution/prompt-sections.ts +0 -1
- package/src/lib/server/chat-execution/situational-awareness.test.ts +2 -73
- package/src/lib/server/chat-execution/situational-awareness.ts +4 -38
- package/src/lib/server/chat-execution/stream-agent-chat.test.ts +13 -126
- package/src/lib/server/chat-execution/stream-agent-chat.ts +46 -21
- package/src/lib/server/chat-execution/stream-continuation.test.ts +4 -52
- package/src/lib/server/chat-execution/stream-continuation.ts +6 -48
- package/src/lib/server/chatrooms/chatroom-routing.test.ts +4 -0
- package/src/lib/server/chatrooms/session-mailbox.ts +0 -10
- package/src/lib/server/chats/chat-session-service.ts +3 -5
- package/src/lib/server/connectors/connector-inbound.ts +0 -1
- package/src/lib/server/connectors/connector-lifecycle.ts +19 -3
- package/src/lib/server/connectors/connector-service.ts +39 -9
- package/src/lib/server/connectors/discord.ts +2 -2
- package/src/lib/server/connectors/matrix.ts +3 -2
- package/src/lib/server/connectors/signal.ts +5 -4
- package/src/lib/server/connectors/slack.ts +10 -9
- package/src/lib/server/connectors/swarmdock-bidding.ts +74 -0
- package/src/lib/server/connectors/swarmdock-payloads.test.ts +85 -0
- package/src/lib/server/connectors/swarmdock-secret.test.ts +128 -0
- package/src/lib/server/connectors/swarmdock-secret.ts +152 -0
- package/src/lib/server/connectors/swarmdock-tasks.ts +119 -0
- package/src/lib/server/connectors/swarmdock.ts +255 -0
- package/src/lib/server/connectors/teams.ts +3 -2
- package/src/lib/server/connectors/telegram.ts +4 -4
- package/src/lib/server/connectors/whatsapp.ts +2 -2
- package/src/lib/server/daemon/controller.ts +7 -0
- package/src/lib/server/execution-brief.test.ts +2 -25
- package/src/lib/server/execution-brief.ts +12 -35
- package/src/lib/server/execution-engine/task-attempt.ts +0 -1
- package/src/lib/server/gateways/gateway-profile-service.ts +19 -1
- package/src/lib/server/messages/message-repository.test.ts +70 -0
- package/src/lib/server/messages/message-repository.ts +11 -6
- package/src/lib/server/openclaw/deploy.ts +32 -2
- package/src/lib/server/persistence/storage-context.ts +0 -5
- package/src/lib/server/plugins-advanced.test.ts +1 -2
- package/src/lib/server/portability/export.ts +109 -0
- package/src/lib/server/portability/import.ts +159 -0
- package/src/lib/server/protocols/protocol-normalization.ts +0 -4
- package/src/lib/server/protocols/protocol-queries.ts +0 -6
- package/src/lib/server/protocols/protocol-run-lifecycle.ts +4 -32
- package/src/lib/server/protocols/protocol-service.ts +0 -1
- package/src/lib/server/protocols/protocol-step-helpers.ts +0 -4
- package/src/lib/server/protocols/protocol-step-processors.ts +0 -6
- package/src/lib/server/protocols/protocol-swarm.ts +0 -2
- package/src/lib/server/protocols/protocol-types.ts +0 -2
- package/src/lib/server/provider-health.ts +1 -10
- package/src/lib/server/runtime/daemon-state/core.ts +0 -9
- package/src/lib/server/runtime/daemon-state.test.ts +0 -35
- package/src/lib/server/runtime/heartbeat-service.ts +3 -23
- package/src/lib/server/runtime/process-manager.ts +13 -9
- package/src/lib/server/runtime/queue/core.ts +11 -33
- package/src/lib/server/runtime/runtime-storage-write-paths.test.ts +6 -6
- package/src/lib/server/runtime/scheduler.ts +0 -13
- package/src/lib/server/runtime/session-run-manager/drain.ts +0 -24
- package/src/lib/server/runtime/session-run-manager/enqueue.ts +0 -1
- package/src/lib/server/runtime/session-run-manager/queries.ts +15 -1
- package/src/lib/server/runtime/session-run-manager/recovery.ts +0 -1
- package/src/lib/server/runtime/session-run-manager.test.ts +58 -28
- package/src/lib/server/sandbox/session-runtime.test.ts +18 -1
- package/src/lib/server/sandbox/session-runtime.ts +40 -28
- package/src/lib/server/session-tools/autonomy-tools.test.ts +7 -9
- package/src/lib/server/session-tools/context.ts +1 -1
- package/src/lib/server/session-tools/credential-env.ts +109 -0
- package/src/lib/server/session-tools/crud.ts +3 -17
- package/src/lib/server/session-tools/delegate.ts +0 -4
- package/src/lib/server/session-tools/edit_file.ts +3 -2
- package/src/lib/server/session-tools/execute.test.ts +58 -0
- package/src/lib/server/session-tools/execute.ts +334 -0
- package/src/lib/server/session-tools/files-tool.ts +635 -0
- package/src/lib/server/session-tools/index.ts +14 -8
- package/src/lib/server/session-tools/memory-tool.ts +242 -0
- package/src/lib/server/session-tools/memory.ts +1 -1
- package/src/lib/server/session-tools/openclaw-nodes.ts +3 -2
- package/src/lib/server/session-tools/openclaw-workspace.ts +3 -2
- package/src/lib/server/session-tools/platform-tool.ts +617 -0
- package/src/lib/server/session-tools/session-info.ts +3 -2
- package/src/lib/server/session-tools/session-tools-wiring.test.ts +3 -4
- package/src/lib/server/session-tools/shell.ts +7 -122
- package/src/lib/server/session-tools/skills-tool.ts +396 -0
- package/src/lib/server/session-tools/team-context.ts +0 -3
- package/src/lib/server/session-tools/web.ts +2 -2
- package/src/lib/server/storage-normalization.ts +10 -0
- package/src/lib/server/storage.ts +18 -45
- package/src/lib/server/tasks/task-checkout.ts +59 -0
- package/src/lib/server/tasks/task-lifecycle.ts +2 -0
- package/src/lib/server/tasks/task-route-service.ts +4 -26
- package/src/lib/server/tasks/task-service.ts +0 -7
- package/src/lib/server/tool-aliases.ts +2 -2
- package/src/lib/server/tool-capability-policy-advanced.test.ts +13 -6
- package/src/lib/server/tool-capability-policy.test.ts +2 -1
- package/src/lib/server/tool-capability-policy.ts +60 -35
- package/src/lib/server/tool-planning.ts +11 -12
- package/src/lib/server/universal-tool-access.ts +0 -1
- package/src/lib/server/wallets/wallet-crypto.ts +33 -0
- package/src/lib/server/wallets/wallet-repository.ts +24 -0
- package/src/lib/server/wallets/wallet-service.ts +119 -0
- package/src/lib/server/working-state/extraction.ts +8 -42
- package/src/lib/server/working-state/normalization.ts +10 -103
- package/src/lib/server/working-state/service.ts +12 -21
- package/src/lib/setup-defaults.ts +5 -0
- package/src/lib/strip-internal-metadata.test.ts +1 -1
- package/src/lib/strip-internal-metadata.ts +1 -1
- package/src/lib/tool-definitions.ts +1 -1
- package/src/lib/validation/schemas.test.ts +16 -0
- package/src/lib/validation/schemas.ts +49 -2
- package/src/stores/slices/data-slice.ts +5 -1
- package/src/stores/slices/ui-slice.ts +0 -4
- package/src/stores/use-chat-store.test.ts +231 -0
- package/src/stores/use-chat-store.ts +62 -13
- package/src/types/agent.ts +264 -0
- package/src/types/app-settings.ts +173 -0
- package/src/types/approval.ts +25 -0
- package/src/types/connector.ts +188 -0
- package/src/types/extension.ts +386 -0
- package/src/types/index.ts +16 -3555
- package/src/types/message.ts +56 -0
- package/src/types/misc.ts +737 -0
- package/src/types/protocol.ts +420 -0
- package/src/types/provider.ts +52 -0
- package/src/types/run.ts +180 -0
- package/src/types/schedule.ts +59 -0
- package/src/types/session.ts +215 -0
- package/src/types/skill.ts +157 -0
- package/src/types/swarmdock.ts +29 -0
- package/src/types/task.ts +144 -0
- package/src/types/working-state.ts +204 -0
- package/src/views/settings/section-heartbeat.tsx +2 -2
- package/src/views/settings/section-runtime-loop.tsx +0 -14
- package/src/app/api/canvas/[sessionId]/route.ts +0 -35
- package/src/app/api/missions/[id]/actions/route.ts +0 -31
- package/src/app/api/missions/[id]/events/route.ts +0 -14
- package/src/app/api/missions/[id]/route.ts +0 -10
- package/src/app/api/missions/route.test.ts +0 -244
- package/src/app/api/missions/route.ts +0 -57
- package/src/app/api/wallets/[id]/approve/route.ts +0 -79
- package/src/app/api/wallets/[id]/balance-history/route.ts +0 -18
- package/src/app/api/wallets/[id]/send/route.ts +0 -113
- package/src/app/api/wallets/[id]/transactions/route.ts +0 -18
- package/src/app/missions/[id]/page.tsx +0 -3
- package/src/app/missions/page.tsx +0 -685
- package/src/components/canvas/canvas-panel.tsx +0 -267
- package/src/components/wallets/wallet-approval-dialog.tsx +0 -107
- package/src/components/wallets/wallet-panel.tsx +0 -1010
- package/src/components/wallets/wallet-section.tsx +0 -260
- package/src/features/missions/queries.ts +0 -23
- package/src/lib/canvas-content.test.ts +0 -360
- package/src/lib/canvas-content.ts +0 -198
- package/src/lib/server/canvas-content.test.ts +0 -32
- package/src/lib/server/canvas-content.ts +0 -6
- package/src/lib/server/ethereum.ts +0 -591
- package/src/lib/server/evm-swap.ts +0 -476
- package/src/lib/server/missions/mission-intent.test.ts +0 -63
- package/src/lib/server/missions/mission-intent.ts +0 -569
- package/src/lib/server/missions/mission-repository.ts +0 -74
- package/src/lib/server/missions/mission-service/actions.ts +0 -6
- package/src/lib/server/missions/mission-service/bindings.ts +0 -9
- package/src/lib/server/missions/mission-service/context.ts +0 -4
- package/src/lib/server/missions/mission-service/core.ts +0 -2271
- package/src/lib/server/missions/mission-service/queries.ts +0 -12
- package/src/lib/server/missions/mission-service/recovery.ts +0 -5
- package/src/lib/server/missions/mission-service/ticks.ts +0 -9
- package/src/lib/server/missions/mission-service.test.ts +0 -888
- package/src/lib/server/missions/mission-service.ts +0 -6
- package/src/lib/server/session-tools/canvas.ts +0 -105
- package/src/lib/server/session-tools/sandbox.ts +0 -281
- package/src/lib/server/session-tools/wallet-tool.test.ts +0 -150
- package/src/lib/server/session-tools/wallet.ts +0 -1287
- package/src/lib/server/solana.ts +0 -327
- package/src/lib/server/wallet/wallet-execution.test.ts +0 -198
- package/src/lib/server/wallet/wallet-portfolio.test.ts +0 -98
- package/src/lib/server/wallet/wallet-portfolio.ts +0 -772
- package/src/lib/server/wallet/wallet-service.test.ts +0 -81
- package/src/lib/server/wallet/wallet-service.ts +0 -225
- package/src/lib/wallet/wallet-transactions.test.ts +0 -75
- package/src/lib/wallet/wallet-transactions.ts +0 -43
- package/src/lib/wallet/wallet.test.ts +0 -333
- package/src/lib/wallet/wallet.ts +0 -183
- package/src/views/settings/section-wallets.tsx +0 -35
|
@@ -13,9 +13,10 @@ const VIEW_TO_PATH: Record<AppView, string> = {
|
|
|
13
13
|
protocols: '/protocols',
|
|
14
14
|
schedules: '/schedules',
|
|
15
15
|
memory: '/memory',
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
tasks: '/tasks',
|
|
18
18
|
secrets: '/secrets',
|
|
19
|
+
wallets: '/wallets',
|
|
19
20
|
providers: '/providers',
|
|
20
21
|
skills: '/skills',
|
|
21
22
|
connectors: '/connectors',
|
|
@@ -25,7 +26,6 @@ const VIEW_TO_PATH: Record<AppView, string> = {
|
|
|
25
26
|
logs: '/logs',
|
|
26
27
|
extensions: '/extensions',
|
|
27
28
|
usage: '/usage',
|
|
28
|
-
wallets: '/wallets',
|
|
29
29
|
runs: '/runs',
|
|
30
30
|
autonomy: '/autonomy',
|
|
31
31
|
settings: '/settings',
|
|
@@ -42,11 +42,6 @@ export function getViewPath(view: AppView, id?: string | null): string {
|
|
|
42
42
|
return base
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export function getMissionPath(missionId?: string | null): string {
|
|
46
|
-
if (!missionId) return VIEW_TO_PATH.missions
|
|
47
|
-
return `${VIEW_TO_PATH.missions}/${encodeURIComponent(missionId)}`
|
|
48
|
-
}
|
|
49
|
-
|
|
50
45
|
/** Map a pathname back to an AppView. Returns null for unknown paths. */
|
|
51
46
|
export function pathToView(pathname: string): AppView | null {
|
|
52
47
|
for (const [view, path] of Object.entries(VIEW_TO_PATH)) {
|
|
@@ -9,9 +9,10 @@ export const VIEW_LABELS: Record<AppView, string> = {
|
|
|
9
9
|
protocols: 'Sessions',
|
|
10
10
|
schedules: 'Schedules',
|
|
11
11
|
memory: 'Memory',
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
tasks: 'Tasks',
|
|
14
14
|
secrets: 'Secrets',
|
|
15
|
+
wallets: 'Wallets',
|
|
15
16
|
providers: 'Providers',
|
|
16
17
|
skills: 'Skills',
|
|
17
18
|
connectors: 'Connectors',
|
|
@@ -21,7 +22,6 @@ export const VIEW_LABELS: Record<AppView, string> = {
|
|
|
21
22
|
logs: 'Logs',
|
|
22
23
|
extensions: 'Extensions',
|
|
23
24
|
usage: 'Usage',
|
|
24
|
-
wallets: 'Wallets',
|
|
25
25
|
runs: 'Runs',
|
|
26
26
|
autonomy: 'Autonomy',
|
|
27
27
|
settings: 'Settings',
|
|
@@ -53,9 +53,10 @@ export const VIEW_DESCRIPTIONS: Record<AppView, string> = {
|
|
|
53
53
|
protocols: 'Temporary structured sessions and protocol-driven runs',
|
|
54
54
|
schedules: 'Automated task schedules',
|
|
55
55
|
memory: 'Long-term agent memory store',
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
tasks: 'Task board for agent work and queued runs',
|
|
58
58
|
secrets: 'API keys, tokens, and encrypted credentials',
|
|
59
|
+
wallets: 'Crypto wallets for agent-initiated on-chain transactions',
|
|
59
60
|
providers: 'LLM providers & custom endpoints',
|
|
60
61
|
skills: 'Reusable instruction sets for agents',
|
|
61
62
|
connectors: 'Chat platform bridges (Discord, Slack, etc.)',
|
|
@@ -65,7 +66,6 @@ export const VIEW_DESCRIPTIONS: Record<AppView, string> = {
|
|
|
65
66
|
logs: 'Application logs & error tracking',
|
|
66
67
|
extensions: 'Manage external extensions and marketplace installs',
|
|
67
68
|
usage: 'Usage metrics, cost tracking & agent performance',
|
|
68
|
-
wallets: 'Agent crypto wallets — hold funds, send SOL, manage spending',
|
|
69
69
|
runs: 'Live run monitoring & history',
|
|
70
70
|
autonomy: 'Estops, incidents, and runtime autonomy controls',
|
|
71
71
|
settings: 'Manage defaults, providers, secrets, and automation settings',
|
|
@@ -89,7 +89,7 @@ export const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents' | 'home'>, { ic
|
|
|
89
89
|
protocols: {
|
|
90
90
|
icon: 'list',
|
|
91
91
|
title: 'Structured Sessions',
|
|
92
|
-
description: 'Run temporary bounded sessions from chats, chatrooms, tasks,
|
|
92
|
+
description: 'Run temporary bounded sessions from chats, chatrooms, tasks, or schedules without turning every surface into a workflow engine.',
|
|
93
93
|
features: ['Start one-agent or multi-agent structured sessions from context', 'Use neutral built-in templates like review, discussion, and decision rounds', 'Keep a hidden transcript plus durable run events', 'Archive the outcome and post a compact summary back when needed'],
|
|
94
94
|
},
|
|
95
95
|
schedules: {
|
|
@@ -104,12 +104,7 @@ export const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents' | 'home'>, { ic
|
|
|
104
104
|
description: 'Long-term memory store for AI agents so they can retain useful context across conversations.',
|
|
105
105
|
features: ['Agents store findings and learnings automatically', 'Full-text search across all stored memories', 'Organized by categories and agents', 'Persists across conversations for continuity'],
|
|
106
106
|
},
|
|
107
|
-
|
|
108
|
-
icon: 'target',
|
|
109
|
-
title: 'Missions',
|
|
110
|
-
description: 'Track durable objectives, blockers, waits, verification, and linked work across chats, schedules, and delegation.',
|
|
111
|
-
features: ['Inspect active and waiting missions', 'Review child missions and linked tasks', 'Understand why a mission is blocked or complete', 'Resume, replan, or retry verification from one place'],
|
|
112
|
-
},
|
|
107
|
+
|
|
113
108
|
tasks: {
|
|
114
109
|
icon: 'clipboard',
|
|
115
110
|
title: 'Task Board',
|
|
@@ -122,6 +117,12 @@ export const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents' | 'home'>, { ic
|
|
|
122
117
|
description: 'Manage API keys and credentials that agents and integrations can access securely.',
|
|
123
118
|
features: ['Store keys for external services (Gmail, APIs, etc.)', 'Scope secrets globally or to specific agents', 'Encrypted at rest with AES-256-GCM', 'Agents retrieve secrets through configured tools'],
|
|
124
119
|
},
|
|
120
|
+
wallets: {
|
|
121
|
+
icon: 'wallet',
|
|
122
|
+
title: 'Wallets',
|
|
123
|
+
description: 'Manage crypto wallets that agents use for on-chain transactions and payments.',
|
|
124
|
+
features: ['Generate wallets with encrypted private keys', 'Assign wallets to specific agents', 'Set spending and daily USDC limits', 'Require human approval for transactions'],
|
|
125
|
+
},
|
|
125
126
|
providers: {
|
|
126
127
|
icon: 'zap',
|
|
127
128
|
title: 'Providers',
|
|
@@ -212,16 +213,10 @@ export const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents' | 'home'>, { ic
|
|
|
212
213
|
description: 'Audit trail of all entity mutations across the system.',
|
|
213
214
|
features: ['Track agent, task, and connector changes', 'Filter by entity type and action', 'Real-time updates via WebSocket', 'Relative timestamps'],
|
|
214
215
|
},
|
|
215
|
-
wallets: {
|
|
216
|
-
icon: 'wallet',
|
|
217
|
-
title: 'Wallets',
|
|
218
|
-
description: 'Agent crypto wallets for autonomous financial operations on Solana.',
|
|
219
|
-
features: ['Create Solana wallets for agents', 'Per-transaction and daily spending limits', 'User approval for transactions', 'Balance tracking and transaction history'],
|
|
220
|
-
},
|
|
221
216
|
}
|
|
222
217
|
|
|
223
218
|
export const FULL_WIDTH_VIEWS = new Set<AppView>([
|
|
224
|
-
'home', 'org_chart', 'inbox', 'chatrooms', 'protocols', 'schedules', '
|
|
219
|
+
'home', 'org_chart', 'inbox', 'chatrooms', 'protocols', 'schedules', 'secrets', 'wallets', 'providers', 'skills',
|
|
225
220
|
'connectors', 'webhooks', 'mcp_servers', 'knowledge', 'extensions',
|
|
226
|
-
'usage', '
|
|
221
|
+
'usage', 'runs', 'autonomy', 'logs', 'settings', 'activity', 'projects',
|
|
227
222
|
])
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import assert from 'node:assert/strict'
|
|
2
2
|
import { describe, it } from 'node:test'
|
|
3
3
|
import {
|
|
4
|
+
buildQueuedTranscriptMessages,
|
|
4
5
|
createOptimisticQueuedMessage,
|
|
5
6
|
clearQueuedMessagesForSession,
|
|
6
7
|
listQueuedMessagesForSession,
|
|
8
|
+
mergeQueuedTranscriptMessages,
|
|
7
9
|
removeQueuedMessageById,
|
|
8
10
|
replaceQueuedMessagesForSession,
|
|
9
11
|
snapshotToQueuedMessages,
|
|
@@ -82,12 +84,22 @@ describe('queued-message-queue', () => {
|
|
|
82
84
|
const queued = snapshotToQueuedMessages({
|
|
83
85
|
sessionId: 'session-a',
|
|
84
86
|
activeRunId: 'run-active',
|
|
87
|
+
activeTurn: {
|
|
88
|
+
runId: 'run-active',
|
|
89
|
+
sessionId: 'session-a',
|
|
90
|
+
text: 'sending now',
|
|
91
|
+
queuedAt: 4,
|
|
92
|
+
position: 0,
|
|
93
|
+
},
|
|
85
94
|
queueLength: 1,
|
|
86
95
|
items: [
|
|
87
96
|
{ runId: 'run-queued', sessionId: 'session-a', text: 'queued', queuedAt: 5, position: 1 },
|
|
88
97
|
],
|
|
89
98
|
})
|
|
90
|
-
assert.deepEqual(
|
|
99
|
+
assert.deepEqual(
|
|
100
|
+
queued.map((item) => [item.runId, item.sending === true]),
|
|
101
|
+
[['run-active', true], ['run-queued', false]],
|
|
102
|
+
)
|
|
91
103
|
})
|
|
92
104
|
|
|
93
105
|
it('preserves attachment and reply metadata from queue snapshots', () => {
|
|
@@ -123,6 +135,27 @@ describe('queued-message-queue', () => {
|
|
|
123
135
|
})
|
|
124
136
|
})
|
|
125
137
|
|
|
138
|
+
it('deduplicates an active turn when the snapshot also contains it in the queued items', () => {
|
|
139
|
+
const queued = snapshotToQueuedMessages({
|
|
140
|
+
sessionId: 'session-a',
|
|
141
|
+
activeRunId: 'run-active',
|
|
142
|
+
activeTurn: {
|
|
143
|
+
runId: 'run-active',
|
|
144
|
+
sessionId: 'session-a',
|
|
145
|
+
text: 'already running',
|
|
146
|
+
queuedAt: 6,
|
|
147
|
+
position: 0,
|
|
148
|
+
},
|
|
149
|
+
queueLength: 1,
|
|
150
|
+
items: [
|
|
151
|
+
{ runId: 'run-active', sessionId: 'session-a', text: 'already running', queuedAt: 6, position: 1 },
|
|
152
|
+
],
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
assert.deepEqual(queued.map((item) => item.runId), ['run-active'])
|
|
156
|
+
assert.equal(queued[0]?.sending, true)
|
|
157
|
+
})
|
|
158
|
+
|
|
126
159
|
it('sorts queued messages by position and queued time within a session', () => {
|
|
127
160
|
const unsorted: QueuedSessionMessage[] = [
|
|
128
161
|
{ runId: 'q4', sessionId: 'session-a', text: 'later', queuedAt: 9, position: 2 },
|
|
@@ -135,4 +168,104 @@ describe('queued-message-queue', () => {
|
|
|
135
168
|
['q5', 'q6', 'q4'],
|
|
136
169
|
)
|
|
137
170
|
})
|
|
171
|
+
|
|
172
|
+
it('builds transcript-ready user messages from sending queued turns', () => {
|
|
173
|
+
const transcript = buildQueuedTranscriptMessages([
|
|
174
|
+
{ runId: 'q1', sessionId: 'session-a', text: 'sending row', queuedAt: 20, position: 0, sending: true },
|
|
175
|
+
{ runId: 'q2', sessionId: 'session-a', text: 'pending row', queuedAt: 21, position: 1 },
|
|
176
|
+
{ runId: 'q3', sessionId: 'session-b', text: 'other session', queuedAt: 22, position: 0, sending: true },
|
|
177
|
+
], 'session-a')
|
|
178
|
+
|
|
179
|
+
assert.deepEqual(transcript, [
|
|
180
|
+
{
|
|
181
|
+
role: 'user',
|
|
182
|
+
text: 'sending row',
|
|
183
|
+
time: 20,
|
|
184
|
+
kind: 'chat',
|
|
185
|
+
clientRenderId: 'queued:q1',
|
|
186
|
+
imagePath: undefined,
|
|
187
|
+
imageUrl: undefined,
|
|
188
|
+
attachedFiles: undefined,
|
|
189
|
+
replyToId: undefined,
|
|
190
|
+
runId: 'q1',
|
|
191
|
+
},
|
|
192
|
+
])
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('merges sending queued turns into the transcript ahead of later assistant output', () => {
|
|
196
|
+
const merged = mergeQueuedTranscriptMessages([
|
|
197
|
+
{ role: 'assistant', text: 'Thinking...', time: 25, streaming: true, runId: 'run-active' },
|
|
198
|
+
], [
|
|
199
|
+
{ runId: 'run-active', sessionId: 'session-a', text: 'queued first', queuedAt: 20, position: 0, sending: true },
|
|
200
|
+
], 'session-a')
|
|
201
|
+
|
|
202
|
+
assert.deepEqual(merged.map((message) => [message.role, message.text, message.runId]), [
|
|
203
|
+
['user', 'queued first', 'run-active'],
|
|
204
|
+
['assistant', 'Thinking...', 'run-active'],
|
|
205
|
+
])
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('preserves existing sending items when replacing queue for a session', () => {
|
|
209
|
+
const queueWithSending: QueuedSessionMessage[] = [
|
|
210
|
+
{ runId: 'sending-1', sessionId: 'session-a', text: 'already sending', queuedAt: 1, position: 0, sending: true },
|
|
211
|
+
{ runId: 'q3', sessionId: 'session-a', text: 'queued', queuedAt: 2, position: 1 },
|
|
212
|
+
{ runId: 'q2', sessionId: 'session-b', text: 'other', queuedAt: 3, position: 1 },
|
|
213
|
+
]
|
|
214
|
+
const replaced = replaceQueuedMessagesForSession(queueWithSending, 'session-a', [
|
|
215
|
+
{ runId: 'q4', sessionId: 'session-a', text: 'new queued', queuedAt: 4, position: 1 },
|
|
216
|
+
], { activeRunId: null })
|
|
217
|
+
|
|
218
|
+
const forSession = listQueuedMessagesForSession(replaced, 'session-a')
|
|
219
|
+
assert.deepEqual(
|
|
220
|
+
forSession.map((item) => [item.runId, item.sending === true]),
|
|
221
|
+
[['sending-1', true], ['q4', false]],
|
|
222
|
+
)
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it('deduplicates sending items that appear in nextItems', () => {
|
|
226
|
+
const queueWithSending: QueuedSessionMessage[] = [
|
|
227
|
+
{ runId: 'run-active', sessionId: 'session-a', text: 'sending', queuedAt: 1, position: 0, sending: true },
|
|
228
|
+
]
|
|
229
|
+
const replaced = replaceQueuedMessagesForSession(queueWithSending, 'session-a', [
|
|
230
|
+
{ runId: 'run-active', sessionId: 'session-a', text: 'sending', queuedAt: 1, position: 0, sending: true },
|
|
231
|
+
{ runId: 'q5', sessionId: 'session-a', text: 'next', queuedAt: 2, position: 1 },
|
|
232
|
+
], { activeRunId: 'run-active' })
|
|
233
|
+
|
|
234
|
+
const forSession = listQueuedMessagesForSession(replaced, 'session-a')
|
|
235
|
+
assert.deepEqual(
|
|
236
|
+
forSession.map((item) => item.runId),
|
|
237
|
+
['run-active', 'q5'],
|
|
238
|
+
)
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it('inserts sending messages after last persisted message, not by timestamp', () => {
|
|
242
|
+
const merged = mergeQueuedTranscriptMessages([
|
|
243
|
+
{ role: 'user', text: 'First', time: 100 },
|
|
244
|
+
{ role: 'assistant', text: 'Reply', time: 200 },
|
|
245
|
+
{ role: 'user', text: 'Second', time: 300 },
|
|
246
|
+
{ role: 'assistant', text: 'Reply 2', time: 400 },
|
|
247
|
+
], [
|
|
248
|
+
// queuedAt is earlier than the last persisted message
|
|
249
|
+
{ runId: 'run-late', sessionId: 'session-a', text: 'queued early', queuedAt: 150, position: 0, sending: true },
|
|
250
|
+
], 'session-a')
|
|
251
|
+
|
|
252
|
+
// Should appear at the END, not spliced into the middle at time=150
|
|
253
|
+
assert.deepEqual(merged.map((msg) => msg.text), [
|
|
254
|
+
'First', 'Reply', 'Second', 'Reply 2', 'queued early',
|
|
255
|
+
])
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
it('skips a sending queued turn once the persisted user message is already present', () => {
|
|
259
|
+
const merged = mergeQueuedTranscriptMessages([
|
|
260
|
+
{ role: 'user', text: 'queued first', time: 20, runId: 'run-active' },
|
|
261
|
+
{ role: 'assistant', text: 'Thinking...', time: 25, streaming: true, runId: 'run-active' },
|
|
262
|
+
], [
|
|
263
|
+
{ runId: 'run-active', sessionId: 'session-a', text: 'queued first', queuedAt: 20, position: 0, sending: true },
|
|
264
|
+
], 'session-a')
|
|
265
|
+
|
|
266
|
+
assert.deepEqual(merged.map((message) => [message.role, message.text, message.runId]), [
|
|
267
|
+
['user', 'queued first', 'run-active'],
|
|
268
|
+
['assistant', 'Thinking...', 'run-active'],
|
|
269
|
+
])
|
|
270
|
+
})
|
|
138
271
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SessionQueueSnapshot, SessionQueuedTurn } from '@/types'
|
|
1
|
+
import type { Message, SessionQueueSnapshot, SessionQueuedTurn } from '@/types'
|
|
2
2
|
|
|
3
3
|
export interface QueuedSessionMessage extends SessionQueuedTurn {
|
|
4
4
|
optimistic?: boolean
|
|
@@ -38,7 +38,23 @@ export function createOptimisticQueuedMessage(
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export function snapshotToQueuedMessages(snapshot: SessionQueueSnapshot): QueuedSessionMessage[] {
|
|
41
|
-
|
|
41
|
+
const activeRunId = typeof snapshot.activeRunId === 'string' && snapshot.activeRunId.trim()
|
|
42
|
+
? snapshot.activeRunId
|
|
43
|
+
: null
|
|
44
|
+
const nextItems: QueuedSessionMessage[] = []
|
|
45
|
+
if (snapshot.activeTurn && activeRunId && snapshot.activeTurn.runId === activeRunId) {
|
|
46
|
+
nextItems.push({
|
|
47
|
+
...snapshot.activeTurn,
|
|
48
|
+
sending: true,
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
const seenRunIds = new Set(nextItems.map((item) => item.runId))
|
|
52
|
+
for (const item of snapshot.items) {
|
|
53
|
+
if (seenRunIds.has(item.runId)) continue
|
|
54
|
+
nextItems.push({ ...item })
|
|
55
|
+
seenRunIds.add(item.runId)
|
|
56
|
+
}
|
|
57
|
+
return nextItems
|
|
42
58
|
}
|
|
43
59
|
|
|
44
60
|
interface ReplaceQueuedMessagesOptions {
|
|
@@ -60,11 +76,17 @@ export function replaceQueuedMessagesForSession(
|
|
|
60
76
|
const activeRunId = typeof options.activeRunId === 'string' && options.activeRunId.trim()
|
|
61
77
|
? options.activeRunId
|
|
62
78
|
: null
|
|
79
|
+
// Preserve existing "sending" items not covered by the new snapshot —
|
|
80
|
+
// they'll be cleaned up later by setMessages or the timeout.
|
|
81
|
+
const existingSending = queue.filter((item) =>
|
|
82
|
+
item.sessionId === sessionId && item.sending && !nextRunIds.has(item.runId),
|
|
83
|
+
)
|
|
63
84
|
const consumed = previousForSession
|
|
64
85
|
.filter((item) => !item.optimistic && !nextRunIds.has(item.runId) && activeRunId === item.runId)
|
|
65
86
|
.map((item) => ({ ...item, sending: true }))
|
|
66
87
|
return [
|
|
67
88
|
...otherSessions,
|
|
89
|
+
...existingSending,
|
|
68
90
|
...consumed,
|
|
69
91
|
...nextItems,
|
|
70
92
|
]
|
|
@@ -80,6 +102,59 @@ export function listQueuedMessagesForSession(
|
|
|
80
102
|
.sort((left, right) => left.position - right.position || left.queuedAt - right.queuedAt)
|
|
81
103
|
}
|
|
82
104
|
|
|
105
|
+
export function buildQueuedTranscriptMessages(
|
|
106
|
+
queue: QueuedSessionMessage[],
|
|
107
|
+
sessionId: string | null | undefined,
|
|
108
|
+
): Message[] {
|
|
109
|
+
return listQueuedMessagesForSession(queue, sessionId)
|
|
110
|
+
.filter((item) => item.sending === true)
|
|
111
|
+
.map((item) => ({
|
|
112
|
+
role: 'user',
|
|
113
|
+
text: item.text,
|
|
114
|
+
time: item.queuedAt,
|
|
115
|
+
kind: 'chat',
|
|
116
|
+
clientRenderId: `queued:${item.runId}`,
|
|
117
|
+
imagePath: item.imagePath,
|
|
118
|
+
imageUrl: item.imageUrl,
|
|
119
|
+
attachedFiles: item.attachedFiles,
|
|
120
|
+
replyToId: item.replyToId,
|
|
121
|
+
runId: item.runId,
|
|
122
|
+
}))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function mergeQueuedTranscriptMessages(
|
|
126
|
+
messages: Message[],
|
|
127
|
+
queue: QueuedSessionMessage[],
|
|
128
|
+
sessionId: string | null | undefined,
|
|
129
|
+
): Message[] {
|
|
130
|
+
const queuedTranscript = buildQueuedTranscriptMessages(queue, sessionId)
|
|
131
|
+
if (queuedTranscript.length === 0) return messages
|
|
132
|
+
const merged = [...messages]
|
|
133
|
+
for (const queuedMessage of queuedTranscript) {
|
|
134
|
+
const queuedRunId = typeof queuedMessage.runId === 'string' && queuedMessage.runId.trim()
|
|
135
|
+
? queuedMessage.runId
|
|
136
|
+
: null
|
|
137
|
+
if (queuedRunId && merged.some((message) => message.role === 'user' && message.runId === queuedRunId)) {
|
|
138
|
+
continue
|
|
139
|
+
}
|
|
140
|
+
// Place queued user message before its corresponding assistant response
|
|
141
|
+
// (same runId), otherwise append after the last persisted message.
|
|
142
|
+
const sameRunAssistantIndex = queuedRunId
|
|
143
|
+
? merged.findIndex((msg) => msg.role === 'assistant' && msg.runId === queuedRunId)
|
|
144
|
+
: -1
|
|
145
|
+
if (sameRunAssistantIndex >= 0) {
|
|
146
|
+
merged.splice(sameRunAssistantIndex, 0, queuedMessage)
|
|
147
|
+
} else {
|
|
148
|
+
const lastPersistedIndex = merged.findLastIndex(
|
|
149
|
+
(msg) => !msg.clientRenderId?.startsWith('queued:'),
|
|
150
|
+
)
|
|
151
|
+
const insertAt = lastPersistedIndex >= 0 ? lastPersistedIndex + 1 : merged.length
|
|
152
|
+
merged.splice(insertAt, 0, queuedMessage)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return merged
|
|
156
|
+
}
|
|
157
|
+
|
|
83
158
|
export function removeQueuedMessageById(
|
|
84
159
|
queue: QueuedSessionMessage[],
|
|
85
160
|
id: string,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { genId } from '@/lib/id'
|
|
2
2
|
import { resolveAgentToolSelection } from '@/lib/agent-default-tools'
|
|
3
|
+
import { normalizeAgentExecuteConfig } from '@/lib/agent-execute-defaults'
|
|
3
4
|
import { normalizeAgentSandboxConfig } from '@/lib/agent-sandbox-defaults'
|
|
4
5
|
import { normalizeCapabilitySelection } from '@/lib/capability-selection'
|
|
5
6
|
import { normalizeProviderEndpoint } from '@/lib/openclaw/openclaw-endpoint'
|
|
@@ -180,6 +181,7 @@ export function createAgent(input: {
|
|
|
180
181
|
sessionDailyResetAt: typeof body.sessionDailyResetAt === 'string' ? body.sessionDailyResetAt : null,
|
|
181
182
|
sessionResetTimezone: typeof body.sessionResetTimezone === 'string' ? body.sessionResetTimezone : null,
|
|
182
183
|
sandboxConfig: normalizeAgentSandboxConfig(body.sandboxConfig),
|
|
184
|
+
executeConfig: body.executeConfig === null ? null : normalizeAgentExecuteConfig(body.executeConfig),
|
|
183
185
|
createdAt: now,
|
|
184
186
|
updatedAt: now,
|
|
185
187
|
}
|
|
@@ -225,6 +227,9 @@ export function updateAgent(agentId: string, body: Record<string, unknown>): Age
|
|
|
225
227
|
if (body.sandboxConfig !== undefined) {
|
|
226
228
|
agent.sandboxConfig = normalizeAgentSandboxConfig(body.sandboxConfig)
|
|
227
229
|
}
|
|
230
|
+
if (body.executeConfig !== undefined) {
|
|
231
|
+
agent.executeConfig = body.executeConfig === null ? null : normalizeAgentExecuteConfig(body.executeConfig)
|
|
232
|
+
}
|
|
228
233
|
if (
|
|
229
234
|
body.provider !== undefined
|
|
230
235
|
|| body.orchestratorEnabled !== undefined
|
|
@@ -89,7 +89,6 @@ function buildThreadSession(agent: Agent, sessionId: string, user: string, creat
|
|
|
89
89
|
vibe: existing?.vibe,
|
|
90
90
|
theme: existing?.theme,
|
|
91
91
|
avatar: existing?.avatar,
|
|
92
|
-
canvasContent: existing?.canvasContent || null,
|
|
93
92
|
}
|
|
94
93
|
return applyResolvedRoute(
|
|
95
94
|
baseSession,
|
|
@@ -62,7 +62,6 @@ function makeClassification(overrides: Partial<MessageClassification>): MessageC
|
|
|
62
62
|
taskIntent: 'general',
|
|
63
63
|
isDeliverableTask: false,
|
|
64
64
|
isBroadGoal: false,
|
|
65
|
-
walletIntent: 'none',
|
|
66
65
|
hasHumanSignals: false,
|
|
67
66
|
hasSignificantEvent: false,
|
|
68
67
|
isResearchSynthesis: false,
|
|
@@ -225,73 +225,4 @@ describe('delegation-jobs', () => {
|
|
|
225
225
|
)
|
|
226
226
|
})
|
|
227
227
|
|
|
228
|
-
it('creates and syncs a child mission for delegation jobs', async () => {
|
|
229
|
-
const storage = await import('@/lib/server/storage')
|
|
230
|
-
const missions = await import('@/lib/server/missions/mission-service')
|
|
231
|
-
|
|
232
|
-
storage.saveSessions({
|
|
233
|
-
'mission-parent-session': {
|
|
234
|
-
id: 'mission-parent-session',
|
|
235
|
-
name: 'Parent Session',
|
|
236
|
-
cwd: process.cwd(),
|
|
237
|
-
user: 'tester',
|
|
238
|
-
provider: 'ollama',
|
|
239
|
-
model: 'test-model',
|
|
240
|
-
messages: [],
|
|
241
|
-
createdAt: Date.now(),
|
|
242
|
-
lastActiveAt: Date.now(),
|
|
243
|
-
agentId: 'agent-parent',
|
|
244
|
-
},
|
|
245
|
-
})
|
|
246
|
-
storage.saveAgents({
|
|
247
|
-
'agent-parent': {
|
|
248
|
-
id: 'agent-parent',
|
|
249
|
-
name: 'Parent Agent',
|
|
250
|
-
provider: 'ollama',
|
|
251
|
-
model: 'test-model',
|
|
252
|
-
systemPrompt: 'test',
|
|
253
|
-
},
|
|
254
|
-
'agent-child': {
|
|
255
|
-
id: 'agent-child',
|
|
256
|
-
name: 'Child Agent',
|
|
257
|
-
provider: 'ollama',
|
|
258
|
-
model: 'test-model',
|
|
259
|
-
systemPrompt: 'test',
|
|
260
|
-
},
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
const parentMission = await missions.resolveMissionForTurn({
|
|
264
|
-
session: storage.loadSessions()['mission-parent-session'],
|
|
265
|
-
message: 'Build the release pipeline and delegate the test matrix.',
|
|
266
|
-
source: 'chat',
|
|
267
|
-
internal: false,
|
|
268
|
-
runId: 'run-parent',
|
|
269
|
-
generateText: async () => JSON.stringify({
|
|
270
|
-
action: 'create_new',
|
|
271
|
-
objective: 'Build the release pipeline',
|
|
272
|
-
successCriteria: ['delegated matrix completes'],
|
|
273
|
-
currentStep: 'Delegate the test matrix',
|
|
274
|
-
}),
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
const job = delegationJobs.createDelegationJob({
|
|
278
|
-
kind: 'subagent',
|
|
279
|
-
parentSessionId: 'mission-parent-session',
|
|
280
|
-
parentMissionId: parentMission?.id || null,
|
|
281
|
-
childSessionId: 'child-session-1',
|
|
282
|
-
agentId: 'agent-child',
|
|
283
|
-
task: 'Run the test matrix',
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
const started = delegationJobs.startDelegationJob(job.id, { childSessionId: 'child-session-1' })
|
|
287
|
-
const completed = delegationJobs.completeDelegationJob(job.id, 'Matrix passed')
|
|
288
|
-
const childMission = completed?.missionId ? missions.loadMissionById(completed.missionId) : null
|
|
289
|
-
const refreshedParent = parentMission?.id ? missions.loadMissionById(parentMission.id) : null
|
|
290
|
-
|
|
291
|
-
assert.ok(started?.missionId)
|
|
292
|
-
assert.equal(started?.parentMissionId, parentMission?.id || null)
|
|
293
|
-
assert.equal(childMission?.parentMissionId, parentMission?.id || null)
|
|
294
|
-
assert.equal(childMission?.status, 'completed')
|
|
295
|
-
assert.ok(refreshedParent?.childMissionIds?.includes(childMission?.id || ''))
|
|
296
|
-
})
|
|
297
228
|
})
|
|
@@ -13,8 +13,6 @@ import { log } from '@/lib/server/logger'
|
|
|
13
13
|
import { debug } from '@/lib/server/debug'
|
|
14
14
|
import { createNotification } from '@/lib/server/create-notification'
|
|
15
15
|
import { enqueueSystemEvent } from '@/lib/server/runtime/system-events'
|
|
16
|
-
import { ensureDelegationMission, syncDelegationMissionFromJob } from '@/lib/server/missions/mission-service'
|
|
17
|
-
import { loadSession } from '@/lib/server/sessions/session-repository'
|
|
18
16
|
import { notify } from '@/lib/server/ws-hub'
|
|
19
17
|
|
|
20
18
|
interface DelegationRuntimeHandle {
|
|
@@ -42,8 +40,6 @@ export interface CreateDelegationJobInput {
|
|
|
42
40
|
kind: DelegationJobRecord['kind']
|
|
43
41
|
task: string
|
|
44
42
|
backend?: DelegationJobRecord['backend']
|
|
45
|
-
missionId?: string | null
|
|
46
|
-
parentMissionId?: string | null
|
|
47
43
|
parentSessionId?: string | null
|
|
48
44
|
childSessionId?: string | null
|
|
49
45
|
agentId?: string | null
|
|
@@ -53,15 +49,11 @@ export interface CreateDelegationJobInput {
|
|
|
53
49
|
|
|
54
50
|
export function createDelegationJob(input: CreateDelegationJobInput): DelegationJobRecord {
|
|
55
51
|
const createdAt = Date.now()
|
|
56
|
-
const inferredParentMissionId = input.parentMissionId
|
|
57
|
-
|| (input.parentSessionId ? loadSession(input.parentSessionId)?.missionId || null : null)
|
|
58
52
|
const job: DelegationJobRecord = {
|
|
59
53
|
id: genId(10),
|
|
60
54
|
kind: input.kind,
|
|
61
55
|
status: 'queued',
|
|
62
56
|
backend: input.backend ?? null,
|
|
63
|
-
missionId: input.missionId ?? null,
|
|
64
|
-
parentMissionId: inferredParentMissionId,
|
|
65
57
|
parentSessionId: input.parentSessionId ?? null,
|
|
66
58
|
childSessionId: input.childSessionId ?? null,
|
|
67
59
|
agentId: input.agentId ?? null,
|
|
@@ -85,22 +77,6 @@ export function createDelegationJob(input: CreateDelegationJobInput): Delegation
|
|
|
85
77
|
completedAt: null,
|
|
86
78
|
}
|
|
87
79
|
upsertDelegationJob(job.id, job)
|
|
88
|
-
if (!job.missionId && inferredParentMissionId) {
|
|
89
|
-
const mission = ensureDelegationMission({
|
|
90
|
-
task: job.task,
|
|
91
|
-
backend: job.backend,
|
|
92
|
-
parentSessionId: job.parentSessionId || null,
|
|
93
|
-
childSessionId: job.childSessionId || null,
|
|
94
|
-
agentId: job.agentId || null,
|
|
95
|
-
parentMissionId: inferredParentMissionId,
|
|
96
|
-
jobId: job.id,
|
|
97
|
-
})
|
|
98
|
-
if (mission) {
|
|
99
|
-
job.missionId = mission.id
|
|
100
|
-
upsertDelegationJob(job.id, job)
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
syncDelegationMissionFromJob(job.id)
|
|
104
80
|
notifyDelegationJobsChanged()
|
|
105
81
|
|
|
106
82
|
const sid = job.childSessionId || job.parentSessionId || ''
|
|
@@ -151,7 +127,6 @@ export function updateDelegationJob(
|
|
|
151
127
|
}
|
|
152
128
|
})
|
|
153
129
|
if (!result) return null
|
|
154
|
-
syncDelegationMissionFromJob(id)
|
|
155
130
|
notifyDelegationJobsChanged()
|
|
156
131
|
return getDelegationJob(id) || result
|
|
157
132
|
}
|