@swarmclawai/swarmclaw 1.2.8 → 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 +30 -6
- package/package.json +2 -2
- 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/connectors/route.ts +2 -2
- 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/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-sheet.tsx +2 -40
- package/src/components/agents/inspector-panel.tsx +0 -83
- package/src/components/chat/chat-card.tsx +0 -31
- package/src/components/chat/message-bubble.tsx +1 -108
- package/src/components/connectors/connector-sheet.tsx +25 -1
- 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/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/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 +0 -2
- package/src/lib/server/capability-router.test.ts +0 -2
- package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +14 -14
- package/src/lib/server/chat-execution/chat-execution-types.ts +0 -2
- package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -2
- 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 +2 -22
- package/src/lib/server/chat-execution/iteration-event-handler.ts +0 -24
- package/src/lib/server/chat-execution/message-classifier.test.ts +0 -45
- package/src/lib/server/chat-execution/message-classifier.ts +1 -16
- package/src/lib/server/chat-execution/prompt-builder.test.ts +0 -1
- package/src/lib/server/chat-execution/prompt-builder.ts +0 -30
- 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 +8 -123
- package/src/lib/server/chat-execution/stream-agent-chat.ts +1 -5
- 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/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/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/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/persistence/storage-context.ts +0 -5
- 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 +0 -9
- 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/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 +0 -1
- package/src/lib/server/runtime/session-run-manager/recovery.ts +0 -1
- package/src/lib/server/runtime/session-run-manager.test.ts +0 -28
- package/src/lib/server/session-tools/crud.ts +0 -14
- package/src/lib/server/session-tools/delegate.ts +0 -4
- package/src/lib/server/session-tools/index.ts +0 -4
- package/src/lib/server/session-tools/team-context.ts +0 -3
- package/src/lib/server/storage-normalization.ts +8 -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 +0 -1
- package/src/lib/server/tool-capability-policy-advanced.test.ts +4 -4
- package/src/lib/server/tool-capability-policy.ts +0 -2
- package/src/lib/server/tool-planning.ts +0 -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/strip-internal-metadata.test.ts +1 -1
- package/src/lib/strip-internal-metadata.ts +1 -1
- package/src/lib/tool-definitions.ts +0 -1
- package/src/lib/validation/schemas.ts +33 -2
- package/src/stores/slices/data-slice.ts +5 -1
- package/src/stores/slices/ui-slice.ts +0 -4
- package/src/types/agent.ts +0 -84
- package/src/types/app-settings.ts +0 -2
- package/src/types/approval.ts +0 -2
- package/src/types/connector.ts +1 -0
- package/src/types/index.ts +1 -1
- package/src/types/message.ts +0 -1
- package/src/types/misc.ts +0 -2
- package/src/types/protocol.ts +0 -2
- package/src/types/run.ts +0 -3
- package/src/types/session.ts +1 -51
- package/src/types/swarmdock.ts +29 -0
- package/src/types/task.ts +7 -3
- package/src/types/working-state.ts +2 -9
- 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/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/types/mission.ts +0 -185
- package/src/views/settings/section-wallets.tsx +0 -35
package/src/types/session.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { ProviderId, OllamaMode } from './provider'
|
|
2
2
|
import type { ConnectorPlatform } from './connector'
|
|
3
3
|
import type { Message } from './message'
|
|
4
|
-
import type { MissionSummary } from './mission'
|
|
5
4
|
|
|
6
5
|
export type SessionResetMode = 'idle' | 'daily' | 'isolated'
|
|
7
6
|
export type SessionResetType = 'direct' | 'group' | 'thread' | 'main'
|
|
@@ -33,51 +32,6 @@ export interface SessionSkillRuntimeState {
|
|
|
33
32
|
lastRunToolName?: string | null
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
export interface CanvasMetricItem {
|
|
37
|
-
label: string
|
|
38
|
-
value: string
|
|
39
|
-
detail?: string
|
|
40
|
-
tone?: 'default' | 'positive' | 'negative' | 'warning'
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface CanvasCardItem {
|
|
44
|
-
title: string
|
|
45
|
-
body?: string
|
|
46
|
-
meta?: string
|
|
47
|
-
tone?: 'default' | 'positive' | 'negative' | 'warning'
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface CanvasActionItem {
|
|
51
|
-
label: string
|
|
52
|
-
href?: string
|
|
53
|
-
note?: string
|
|
54
|
-
intent?: 'primary' | 'secondary' | 'success' | 'danger'
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface CanvasTableData {
|
|
58
|
-
columns: string[]
|
|
59
|
-
rows: Array<Array<string | number | boolean | null>>
|
|
60
|
-
caption?: string
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export type CanvasBlock =
|
|
64
|
-
| { type: 'markdown'; title?: string; markdown: string }
|
|
65
|
-
| { type: 'metrics'; title?: string; items: CanvasMetricItem[] }
|
|
66
|
-
| { type: 'cards'; title?: string; items: CanvasCardItem[] }
|
|
67
|
-
| { type: 'table'; title?: string; table: CanvasTableData }
|
|
68
|
-
| { type: 'code'; title?: string; code: string; language?: string }
|
|
69
|
-
| { type: 'actions'; title?: string; items: CanvasActionItem[] }
|
|
70
|
-
|
|
71
|
-
export interface CanvasDocument {
|
|
72
|
-
kind: 'structured'
|
|
73
|
-
title?: string
|
|
74
|
-
subtitle?: string
|
|
75
|
-
theme?: 'slate' | 'sky' | 'emerald' | 'amber' | 'rose'
|
|
76
|
-
blocks: CanvasBlock[]
|
|
77
|
-
updatedAt?: number | null
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export type CanvasContent = string | CanvasDocument | null
|
|
81
35
|
|
|
82
36
|
export interface MailboxEnvelope {
|
|
83
37
|
id: string
|
|
@@ -204,8 +158,6 @@ export interface Session {
|
|
|
204
158
|
lastSessionResetReason?: string | null
|
|
205
159
|
identityState?: IdentityContinuityState | null
|
|
206
160
|
sessionArchiveState?: SessionArchiveState | null
|
|
207
|
-
missionId?: string | null
|
|
208
|
-
missionSummary?: MissionSummary | null
|
|
209
161
|
skillRuntimeState?: SessionSkillRuntimeState | null
|
|
210
162
|
pinned?: boolean
|
|
211
163
|
file?: string | null
|
|
@@ -217,7 +169,6 @@ export interface Session {
|
|
|
217
169
|
vibe?: string
|
|
218
170
|
theme?: string
|
|
219
171
|
avatar?: string
|
|
220
|
-
canvasContent?: CanvasContent
|
|
221
172
|
/** Tracks how many times each memory ID has been injected via proactive recall in this session. */
|
|
222
173
|
injectedMemoryIds?: Record<string, number>
|
|
223
174
|
/** Structured working memory that survives compaction and flows through delegation. */
|
|
@@ -251,7 +202,6 @@ export type SessionTool =
|
|
|
251
202
|
| 'edit_file'
|
|
252
203
|
| 'process'
|
|
253
204
|
| 'spawn_subagent'
|
|
254
|
-
| 'canvas'
|
|
255
205
|
| 'http_request'
|
|
256
206
|
| 'git'
|
|
257
207
|
| 'mailbox'
|
|
@@ -262,4 +212,4 @@ export type SessionTool =
|
|
|
262
212
|
| 'crawl'
|
|
263
213
|
|
|
264
214
|
export type SessionType = 'human'
|
|
265
|
-
export type AppView = 'home' | 'agents' | 'org_chart' | 'inbox' | 'chatrooms' | 'protocols' | 'schedules' | 'memory' | '
|
|
215
|
+
export type AppView = 'home' | 'agents' | 'org_chart' | 'inbox' | 'chatrooms' | 'protocols' | 'schedules' | 'memory' | 'tasks' | 'secrets' | 'wallets' | 'providers' | 'skills' | 'connectors' | 'webhooks' | 'mcp_servers' | 'knowledge' | 'extensions' | 'usage' | 'runs' | 'autonomy' | 'logs' | 'settings' | 'projects' | 'activity'
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// --- SwarmDock Marketplace Types ---
|
|
2
|
+
|
|
3
|
+
export interface AgentWallet {
|
|
4
|
+
id: string
|
|
5
|
+
agentId: string
|
|
6
|
+
walletAddress: string
|
|
7
|
+
chain: 'base'
|
|
8
|
+
label?: string
|
|
9
|
+
encryptedPrivateKey?: string | null
|
|
10
|
+
spendingLimitUsdc?: string | null
|
|
11
|
+
dailyLimitUsdc?: string | null
|
|
12
|
+
requireApproval?: boolean
|
|
13
|
+
swarmdockAgentId?: string | null
|
|
14
|
+
swarmdockDid?: string | null
|
|
15
|
+
createdAt: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type SafeWallet = Omit<AgentWallet, 'encryptedPrivateKey'>
|
|
19
|
+
|
|
20
|
+
export interface WalletTransaction {
|
|
21
|
+
id: string
|
|
22
|
+
walletId: string
|
|
23
|
+
swarmdockTaskId?: string | null
|
|
24
|
+
amount: string
|
|
25
|
+
direction: 'in' | 'out'
|
|
26
|
+
txHash?: string | null
|
|
27
|
+
status: 'pending' | 'confirmed' | 'failed'
|
|
28
|
+
createdAt: number
|
|
29
|
+
}
|
package/src/types/task.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { MissionSummary } from './mission'
|
|
2
1
|
import type { GoalContract } from './app-settings'
|
|
3
2
|
|
|
4
3
|
// --- Task Board ---
|
|
@@ -28,9 +27,12 @@ export interface BoardTask {
|
|
|
28
27
|
description: string
|
|
29
28
|
status: BoardTaskStatus
|
|
30
29
|
agentId: string
|
|
31
|
-
missionId?: string | null
|
|
32
30
|
protocolRunId?: string | null
|
|
33
|
-
|
|
31
|
+
// Objective tracking (absorbed from missions)
|
|
32
|
+
objective?: string | null
|
|
33
|
+
successCriteria?: string[] | null
|
|
34
|
+
verificationSummary?: string | null
|
|
35
|
+
rootTaskId?: string | null
|
|
34
36
|
projectId?: string
|
|
35
37
|
goalContract?: GoalContract | null
|
|
36
38
|
cwd?: string | null
|
|
@@ -137,4 +139,6 @@ export interface BoardTask {
|
|
|
137
139
|
}>
|
|
138
140
|
repairRunId?: string | null
|
|
139
141
|
lastRepairAttemptAt?: number | null
|
|
142
|
+
// Atomic checkout — prevents two runners from starting the same task
|
|
143
|
+
checkoutRunId?: string | null
|
|
140
144
|
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import type { MissionStatus, MissionPhase, MissionWaitState } from './mission'
|
|
2
1
|
|
|
3
2
|
export type WorkingStateStatus = 'idle' | 'progress' | 'blocked' | 'waiting' | 'completed'
|
|
4
3
|
export type WorkingStateItemStatus = 'active' | 'resolved' | 'superseded'
|
|
5
4
|
|
|
6
5
|
export interface EvidenceRef {
|
|
7
6
|
id: string
|
|
8
|
-
type: 'tool' | 'message' | '
|
|
7
|
+
type: 'tool' | 'message' | 'task' | 'artifact' | 'error' | 'approval'
|
|
9
8
|
summary: string
|
|
10
9
|
value?: string | null
|
|
11
10
|
toolName?: string | null
|
|
12
11
|
toolCallId?: string | null
|
|
13
12
|
runId?: string | null
|
|
14
13
|
sessionId?: string | null
|
|
15
|
-
missionId?: string | null
|
|
16
14
|
taskId?: string | null
|
|
17
15
|
createdAt: number
|
|
18
16
|
}
|
|
@@ -28,7 +26,7 @@ export interface WorkingPlanStep {
|
|
|
28
26
|
export interface WorkingFact {
|
|
29
27
|
id: string
|
|
30
28
|
statement: string
|
|
31
|
-
source: 'user' | 'tool' | 'assistant' | '
|
|
29
|
+
source: 'user' | 'tool' | 'assistant' | 'system'
|
|
32
30
|
status: WorkingStateItemStatus
|
|
33
31
|
evidenceIds?: string[]
|
|
34
32
|
createdAt: number
|
|
@@ -165,7 +163,6 @@ export interface WorkingStatePatch {
|
|
|
165
163
|
|
|
166
164
|
export interface SessionWorkingState {
|
|
167
165
|
sessionId: string
|
|
168
|
-
missionId?: string | null
|
|
169
166
|
objective?: string | null
|
|
170
167
|
summary?: string | null
|
|
171
168
|
constraints: string[]
|
|
@@ -192,7 +189,6 @@ export interface ExecutionBriefPlanStep {
|
|
|
192
189
|
|
|
193
190
|
export interface ExecutionBrief {
|
|
194
191
|
sessionId?: string | null
|
|
195
|
-
missionId?: string | null
|
|
196
192
|
objective: string | null
|
|
197
193
|
summary: string | null
|
|
198
194
|
status: WorkingStateStatus
|
|
@@ -203,9 +199,6 @@ export interface ExecutionBrief {
|
|
|
203
199
|
artifacts: string[]
|
|
204
200
|
constraints: string[]
|
|
205
201
|
successCriteria: string[]
|
|
206
|
-
missionStatus?: MissionStatus | null
|
|
207
|
-
missionPhase?: MissionPhase | null
|
|
208
|
-
waitState?: MissionWaitState | null
|
|
209
202
|
evidenceRefs: EvidenceRef[]
|
|
210
203
|
parentContext: string | null
|
|
211
204
|
}
|
|
@@ -55,20 +55,6 @@ export function RuntimeLoopSection({ appSettings, patchSettings, inputClass }: S
|
|
|
55
55
|
</div>
|
|
56
56
|
</div>
|
|
57
57
|
|
|
58
|
-
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-3">Mission Human Loop</label>
|
|
59
|
-
<div className="flex items-center gap-3 mb-6">
|
|
60
|
-
<button
|
|
61
|
-
onClick={() => patchSettings({ missionHumanLoopEnabled: !(appSettings.missionHumanLoopEnabled ?? false) })}
|
|
62
|
-
className={`relative w-10 h-[22px] rounded-full transition-colors duration-200 cursor-pointer ${(appSettings.missionHumanLoopEnabled ?? false) ? 'bg-accent' : 'bg-white/[0.12]'}`}
|
|
63
|
-
>
|
|
64
|
-
<span className={`absolute top-[3px] left-[3px] w-4 h-4 rounded-full bg-white transition-transform duration-200 ${(appSettings.missionHumanLoopEnabled ?? false) ? 'translate-x-[18px]' : ''}`} />
|
|
65
|
-
</button>
|
|
66
|
-
<div>
|
|
67
|
-
<div className="text-[12px] text-text-2">Allow missions to stay open waiting for a human follow-up</div>
|
|
68
|
-
<div className="text-[11px] text-text-3/60 mt-1">Off by default for new users. When disabled, generic mission handoffs like “waiting for your next instruction” are closed instead of lingering as open waiting missions. Explicit tool approvals and real external blockers still apply.</div>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
|
|
72
58
|
<label className="flex items-center gap-1.5 font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-3">Loop Mode <HintTip text="Bounded = fixed max steps. Ongoing = runs until the task completes (with a safety cap)" /></label>
|
|
73
59
|
<div className="grid grid-cols-2 gap-2 mb-5">
|
|
74
60
|
{([
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from 'next/server'
|
|
2
|
-
import { loadSessions, saveSessions } from '@/lib/server/storage'
|
|
3
|
-
import { notify } from '@/lib/server/ws-hub'
|
|
4
|
-
import { normalizeCanvasContent } from '@/lib/canvas-content'
|
|
5
|
-
import { safeParseBody } from '@/lib/server/safe-parse-body'
|
|
6
|
-
|
|
7
|
-
export async function GET(_req: Request, { params }: { params: Promise<{ sessionId: string }> }) {
|
|
8
|
-
const { sessionId } = await params
|
|
9
|
-
const sessions = loadSessions()
|
|
10
|
-
const session = sessions[sessionId]
|
|
11
|
-
if (!session) return NextResponse.json({ error: 'Session not found' }, { status: 404 })
|
|
12
|
-
|
|
13
|
-
return NextResponse.json({
|
|
14
|
-
sessionId,
|
|
15
|
-
content: (session as unknown as Record<string, unknown>).canvasContent || null,
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export async function POST(req: Request, { params }: { params: Promise<{ sessionId: string }> }) {
|
|
20
|
-
const { sessionId } = await params
|
|
21
|
-
const { data: body, error } = await safeParseBody(req)
|
|
22
|
-
if (error) return error
|
|
23
|
-
const sessions = loadSessions()
|
|
24
|
-
const session = sessions[sessionId]
|
|
25
|
-
if (!session) return NextResponse.json({ error: 'Session not found' }, { status: 404 })
|
|
26
|
-
|
|
27
|
-
const nextContent = normalizeCanvasContent(body.document ?? body.content)
|
|
28
|
-
;(session as unknown as Record<string, unknown>).canvasContent = nextContent
|
|
29
|
-
session.lastActiveAt = Date.now()
|
|
30
|
-
sessions[sessionId] = session
|
|
31
|
-
saveSessions(sessions)
|
|
32
|
-
|
|
33
|
-
notify(`canvas:${sessionId}`)
|
|
34
|
-
return NextResponse.json({ ok: true, sessionId })
|
|
35
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from 'next/server'
|
|
2
|
-
import { notFound } from '@/lib/server/collection-helpers'
|
|
3
|
-
import { loadMissionById, performMissionAction } from '@/lib/server/missions/mission-service'
|
|
4
|
-
|
|
5
|
-
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
6
|
-
const { id } = await params
|
|
7
|
-
const mission = loadMissionById(id)
|
|
8
|
-
if (!mission) return notFound()
|
|
9
|
-
|
|
10
|
-
const body = await req.json().catch(() => ({}))
|
|
11
|
-
const action = body?.action
|
|
12
|
-
if (action !== 'resume' && action !== 'replan' && action !== 'cancel' && action !== 'retry_verification' && action !== 'wait') {
|
|
13
|
-
return NextResponse.json({ error: 'Invalid mission action.' }, { status: 400 })
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const result = performMissionAction({
|
|
17
|
-
missionId: id,
|
|
18
|
-
action,
|
|
19
|
-
reason: typeof body.reason === 'string' ? body.reason : null,
|
|
20
|
-
waitKind: typeof body.waitKind === 'string' ? body.waitKind : undefined,
|
|
21
|
-
untilAt: typeof body.untilAt === 'number' ? body.untilAt : null,
|
|
22
|
-
})
|
|
23
|
-
if (!result) {
|
|
24
|
-
return NextResponse.json({ error: 'Unable to update mission.' }, { status: 409 })
|
|
25
|
-
}
|
|
26
|
-
return NextResponse.json({
|
|
27
|
-
ok: true,
|
|
28
|
-
mission: result.mission,
|
|
29
|
-
appendedEvent: result.event,
|
|
30
|
-
})
|
|
31
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from 'next/server'
|
|
2
|
-
import { notFound } from '@/lib/server/collection-helpers'
|
|
3
|
-
import { listMissionEventsForMission, loadMissionById } from '@/lib/server/missions/mission-service'
|
|
4
|
-
|
|
5
|
-
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
6
|
-
const { id } = await params
|
|
7
|
-
const mission = loadMissionById(id)
|
|
8
|
-
if (!mission) return notFound()
|
|
9
|
-
|
|
10
|
-
const { searchParams } = new URL(req.url)
|
|
11
|
-
const limitParam = searchParams.get('limit')
|
|
12
|
-
const limit = limitParam ? Number.parseInt(limitParam, 10) : undefined
|
|
13
|
-
return NextResponse.json(listMissionEventsForMission(id, Number.isFinite(limit) ? limit : undefined))
|
|
14
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from 'next/server'
|
|
2
|
-
import { notFound } from '@/lib/server/collection-helpers'
|
|
3
|
-
import { getMissionDetail } from '@/lib/server/missions/mission-service'
|
|
4
|
-
|
|
5
|
-
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
6
|
-
const { id } = await params
|
|
7
|
-
const mission = getMissionDetail(id)
|
|
8
|
-
if (!mission) return notFound()
|
|
9
|
-
return NextResponse.json(mission)
|
|
10
|
-
}
|
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict'
|
|
2
|
-
import test from 'node:test'
|
|
3
|
-
|
|
4
|
-
import { runWithTempDataDir } from '@/lib/server/test-utils/run-with-temp-data-dir'
|
|
5
|
-
|
|
6
|
-
test('missions routes list, detail, and events expose durable mission state', () => {
|
|
7
|
-
const output = runWithTempDataDir<{
|
|
8
|
-
listCount: number
|
|
9
|
-
firstMissionId: string | null
|
|
10
|
-
detailMissionId: string | null
|
|
11
|
-
linkedTaskId: string | null
|
|
12
|
-
parentMissionId: string | null
|
|
13
|
-
eventsCount: number
|
|
14
|
-
latestEventType: string | null
|
|
15
|
-
}>(`
|
|
16
|
-
const storageMod = await import('./src/lib/server/storage')
|
|
17
|
-
const listRouteMod = await import('./src/app/api/missions/route')
|
|
18
|
-
const detailRouteMod = await import('./src/app/api/missions/[id]/route')
|
|
19
|
-
const eventsRouteMod = await import('./src/app/api/missions/[id]/events/route')
|
|
20
|
-
const storage = storageMod.default || storageMod
|
|
21
|
-
const listRoute = listRouteMod.default || listRouteMod
|
|
22
|
-
const detailRoute = detailRouteMod.default || detailRouteMod
|
|
23
|
-
const eventsRoute = eventsRouteMod.default || eventsRouteMod
|
|
24
|
-
|
|
25
|
-
storage.saveAgents({
|
|
26
|
-
agentA: {
|
|
27
|
-
id: 'agentA',
|
|
28
|
-
name: 'Agent A',
|
|
29
|
-
provider: 'ollama',
|
|
30
|
-
model: 'test-model',
|
|
31
|
-
systemPrompt: 'test',
|
|
32
|
-
},
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
storage.saveTasks({
|
|
36
|
-
taskA: {
|
|
37
|
-
id: 'taskA',
|
|
38
|
-
title: 'Prepare release summary',
|
|
39
|
-
description: 'Create the release summary.',
|
|
40
|
-
status: 'backlog',
|
|
41
|
-
agentId: 'agentA',
|
|
42
|
-
createdAt: 1,
|
|
43
|
-
updatedAt: 1,
|
|
44
|
-
missionId: 'missionA',
|
|
45
|
-
},
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
storage.saveMissions({
|
|
49
|
-
missionParent: {
|
|
50
|
-
id: 'missionParent',
|
|
51
|
-
source: 'chat',
|
|
52
|
-
sourceRef: { kind: 'chat', sessionId: 'sessionA' },
|
|
53
|
-
objective: 'Parent mission',
|
|
54
|
-
status: 'active',
|
|
55
|
-
phase: 'planning',
|
|
56
|
-
sessionId: 'sessionA',
|
|
57
|
-
agentId: 'agentA',
|
|
58
|
-
taskIds: [],
|
|
59
|
-
childMissionIds: ['missionA'],
|
|
60
|
-
dependencyMissionIds: [],
|
|
61
|
-
dependencyTaskIds: [],
|
|
62
|
-
createdAt: 1,
|
|
63
|
-
updatedAt: 1,
|
|
64
|
-
},
|
|
65
|
-
missionA: {
|
|
66
|
-
id: 'missionA',
|
|
67
|
-
source: 'chat',
|
|
68
|
-
sourceRef: { kind: 'chat', sessionId: 'sessionA' },
|
|
69
|
-
objective: 'Prepare the release handoff',
|
|
70
|
-
status: 'waiting',
|
|
71
|
-
phase: 'waiting',
|
|
72
|
-
sessionId: 'sessionA',
|
|
73
|
-
agentId: 'agentA',
|
|
74
|
-
parentMissionId: 'missionParent',
|
|
75
|
-
rootMissionId: 'missionParent',
|
|
76
|
-
taskIds: ['taskA'],
|
|
77
|
-
childMissionIds: [],
|
|
78
|
-
dependencyMissionIds: [],
|
|
79
|
-
dependencyTaskIds: [],
|
|
80
|
-
waitState: { kind: 'approval', reason: 'Waiting for release approval.' },
|
|
81
|
-
plannerSummary: 'Track the release handoff.',
|
|
82
|
-
currentStep: 'Wait for approval',
|
|
83
|
-
createdAt: 2,
|
|
84
|
-
updatedAt: 3,
|
|
85
|
-
},
|
|
86
|
-
missionB: {
|
|
87
|
-
id: 'missionB',
|
|
88
|
-
source: 'manual',
|
|
89
|
-
sourceRef: { kind: 'manual' },
|
|
90
|
-
objective: 'Unrelated completed mission',
|
|
91
|
-
status: 'completed',
|
|
92
|
-
phase: 'completed',
|
|
93
|
-
sessionId: 'sessionB',
|
|
94
|
-
agentId: 'agentA',
|
|
95
|
-
taskIds: [],
|
|
96
|
-
childMissionIds: [],
|
|
97
|
-
dependencyMissionIds: [],
|
|
98
|
-
dependencyTaskIds: [],
|
|
99
|
-
createdAt: 1,
|
|
100
|
-
updatedAt: 1,
|
|
101
|
-
},
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
storage.saveMissionEvents({
|
|
105
|
-
eventCreated: {
|
|
106
|
-
id: 'eventCreated',
|
|
107
|
-
missionId: 'missionA',
|
|
108
|
-
type: 'created',
|
|
109
|
-
source: 'chat',
|
|
110
|
-
summary: 'Mission created.',
|
|
111
|
-
sessionId: 'sessionA',
|
|
112
|
-
createdAt: 2,
|
|
113
|
-
},
|
|
114
|
-
eventWaiting: {
|
|
115
|
-
id: 'eventWaiting',
|
|
116
|
-
missionId: 'missionA',
|
|
117
|
-
type: 'waiting',
|
|
118
|
-
source: 'system',
|
|
119
|
-
summary: 'Waiting for release approval.',
|
|
120
|
-
sessionId: 'sessionA',
|
|
121
|
-
createdAt: 3,
|
|
122
|
-
},
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
const listResponse = await listRoute.GET(new Request('http://local/api/missions?status=waiting&sessionId=sessionA&limit=1'))
|
|
126
|
-
const listPayload = await listResponse.json()
|
|
127
|
-
|
|
128
|
-
const detailResponse = await detailRoute.GET(
|
|
129
|
-
new Request('http://local/api/missions/missionA'),
|
|
130
|
-
{ params: Promise.resolve({ id: 'missionA' }) },
|
|
131
|
-
)
|
|
132
|
-
const detailPayload = await detailResponse.json()
|
|
133
|
-
|
|
134
|
-
const eventsResponse = await eventsRoute.GET(
|
|
135
|
-
new Request('http://local/api/missions/missionA/events?limit=1'),
|
|
136
|
-
{ params: Promise.resolve({ id: 'missionA' }) },
|
|
137
|
-
)
|
|
138
|
-
const eventsPayload = await eventsResponse.json()
|
|
139
|
-
|
|
140
|
-
console.log(JSON.stringify({
|
|
141
|
-
listCount: Array.isArray(listPayload) ? listPayload.length : -1,
|
|
142
|
-
firstMissionId: Array.isArray(listPayload) ? listPayload[0]?.id || null : null,
|
|
143
|
-
detailMissionId: detailPayload?.mission?.id || null,
|
|
144
|
-
linkedTaskId: Array.isArray(detailPayload?.linkedTasks) ? detailPayload.linkedTasks[0]?.id || null : null,
|
|
145
|
-
parentMissionId: detailPayload?.parent?.id || null,
|
|
146
|
-
eventsCount: Array.isArray(eventsPayload) ? eventsPayload.length : -1,
|
|
147
|
-
latestEventType: Array.isArray(eventsPayload) ? eventsPayload[0]?.type || null : null,
|
|
148
|
-
}))
|
|
149
|
-
`, { prefix: 'swarmclaw-missions-route-' })
|
|
150
|
-
|
|
151
|
-
assert.equal(output.listCount, 1)
|
|
152
|
-
assert.equal(output.firstMissionId, 'missionA')
|
|
153
|
-
assert.equal(output.detailMissionId, 'missionA')
|
|
154
|
-
assert.equal(output.linkedTaskId, 'taskA')
|
|
155
|
-
assert.equal(output.parentMissionId, 'missionParent')
|
|
156
|
-
assert.equal(output.eventsCount, 1)
|
|
157
|
-
assert.equal(output.latestEventType, 'waiting')
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
test('mission actions route validates input and persists operator wait actions', () => {
|
|
161
|
-
const output = runWithTempDataDir<{
|
|
162
|
-
invalidStatus: number
|
|
163
|
-
invalidError: string | null
|
|
164
|
-
waitStatus: number
|
|
165
|
-
waitOk: boolean
|
|
166
|
-
missionStatus: string | null
|
|
167
|
-
missionPhase: string | null
|
|
168
|
-
waitKind: string | null
|
|
169
|
-
waitReason: string | null
|
|
170
|
-
eventType: string | null
|
|
171
|
-
eventAction: string | null
|
|
172
|
-
}>(`
|
|
173
|
-
const storageMod = await import('./src/lib/server/storage')
|
|
174
|
-
const actionsRouteMod = await import('./src/app/api/missions/[id]/actions/route')
|
|
175
|
-
const storage = storageMod.default || storageMod
|
|
176
|
-
const actionsRoute = actionsRouteMod.default || actionsRouteMod
|
|
177
|
-
|
|
178
|
-
storage.saveMissions({
|
|
179
|
-
missionA: {
|
|
180
|
-
id: 'missionA',
|
|
181
|
-
source: 'chat',
|
|
182
|
-
sourceRef: { kind: 'chat', sessionId: 'sessionA' },
|
|
183
|
-
objective: 'Prepare the release handoff',
|
|
184
|
-
status: 'active',
|
|
185
|
-
phase: 'planning',
|
|
186
|
-
sessionId: 'sessionA',
|
|
187
|
-
taskIds: [],
|
|
188
|
-
childMissionIds: [],
|
|
189
|
-
dependencyMissionIds: [],
|
|
190
|
-
dependencyTaskIds: [],
|
|
191
|
-
createdAt: 1,
|
|
192
|
-
updatedAt: 1,
|
|
193
|
-
},
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
const invalidResponse = await actionsRoute.POST(
|
|
197
|
-
new Request('http://local/api/missions/missionA/actions', {
|
|
198
|
-
method: 'POST',
|
|
199
|
-
headers: { 'content-type': 'application/json' },
|
|
200
|
-
body: JSON.stringify({ action: 'ship_it' }),
|
|
201
|
-
}),
|
|
202
|
-
{ params: Promise.resolve({ id: 'missionA' }) },
|
|
203
|
-
)
|
|
204
|
-
const invalidPayload = await invalidResponse.json()
|
|
205
|
-
|
|
206
|
-
const waitResponse = await actionsRoute.POST(
|
|
207
|
-
new Request('http://local/api/missions/missionA/actions', {
|
|
208
|
-
method: 'POST',
|
|
209
|
-
headers: { 'content-type': 'application/json' },
|
|
210
|
-
body: JSON.stringify({
|
|
211
|
-
action: 'wait',
|
|
212
|
-
reason: 'Waiting for operator confirmation.',
|
|
213
|
-
waitKind: 'approval',
|
|
214
|
-
}),
|
|
215
|
-
}),
|
|
216
|
-
{ params: Promise.resolve({ id: 'missionA' }) },
|
|
217
|
-
)
|
|
218
|
-
const waitPayload = await waitResponse.json()
|
|
219
|
-
|
|
220
|
-
console.log(JSON.stringify({
|
|
221
|
-
invalidStatus: invalidResponse.status,
|
|
222
|
-
invalidError: invalidPayload?.error || null,
|
|
223
|
-
waitStatus: waitResponse.status,
|
|
224
|
-
waitOk: waitPayload?.ok === true,
|
|
225
|
-
missionStatus: waitPayload?.mission?.status || null,
|
|
226
|
-
missionPhase: waitPayload?.mission?.phase || null,
|
|
227
|
-
waitKind: waitPayload?.mission?.waitState?.kind || null,
|
|
228
|
-
waitReason: waitPayload?.mission?.waitState?.reason || null,
|
|
229
|
-
eventType: waitPayload?.appendedEvent?.type || null,
|
|
230
|
-
eventAction: waitPayload?.appendedEvent?.data?.action || null,
|
|
231
|
-
}))
|
|
232
|
-
`, { prefix: 'swarmclaw-missions-route-' })
|
|
233
|
-
|
|
234
|
-
assert.equal(output.invalidStatus, 400)
|
|
235
|
-
assert.match(String(output.invalidError || ''), /invalid mission action/i)
|
|
236
|
-
assert.equal(output.waitStatus, 200)
|
|
237
|
-
assert.equal(output.waitOk, true)
|
|
238
|
-
assert.equal(output.missionStatus, 'waiting')
|
|
239
|
-
assert.equal(output.missionPhase, 'waiting')
|
|
240
|
-
assert.equal(output.waitKind, 'approval')
|
|
241
|
-
assert.equal(output.waitReason, 'Waiting for operator confirmation.')
|
|
242
|
-
assert.equal(output.eventType, 'operator_action')
|
|
243
|
-
assert.equal(output.eventAction, 'wait')
|
|
244
|
-
})
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from 'next/server'
|
|
2
|
-
import type { MissionPhase, MissionSource, MissionStatus } from '@/types'
|
|
3
|
-
import { listMissions } from '@/lib/server/missions/mission-service'
|
|
4
|
-
|
|
5
|
-
export const dynamic = 'force-dynamic'
|
|
6
|
-
|
|
7
|
-
export async function GET(req: Request) {
|
|
8
|
-
const { searchParams } = new URL(req.url)
|
|
9
|
-
const sessionId = searchParams.get('sessionId')
|
|
10
|
-
const agentId = searchParams.get('agentId')
|
|
11
|
-
const projectId = searchParams.get('projectId')
|
|
12
|
-
const parentMissionId = searchParams.get('parentMissionId')
|
|
13
|
-
const limitParam = searchParams.get('limit')
|
|
14
|
-
const rawStatus = searchParams.get('status')
|
|
15
|
-
const rawPhase = searchParams.get('phase')
|
|
16
|
-
const rawSource = searchParams.get('source')
|
|
17
|
-
const limit = limitParam ? Number.parseInt(limitParam, 10) : undefined
|
|
18
|
-
const status = rawStatus === 'non_terminal'
|
|
19
|
-
|| rawStatus === 'active'
|
|
20
|
-
|| rawStatus === 'waiting'
|
|
21
|
-
|| rawStatus === 'completed'
|
|
22
|
-
|| rawStatus === 'failed'
|
|
23
|
-
|| rawStatus === 'cancelled'
|
|
24
|
-
? rawStatus as MissionStatus | 'non_terminal'
|
|
25
|
-
: undefined
|
|
26
|
-
const phase = rawPhase === 'intake'
|
|
27
|
-
|| rawPhase === 'planning'
|
|
28
|
-
|| rawPhase === 'dispatching'
|
|
29
|
-
|| rawPhase === 'executing'
|
|
30
|
-
|| rawPhase === 'verifying'
|
|
31
|
-
|| rawPhase === 'waiting'
|
|
32
|
-
|| rawPhase === 'completed'
|
|
33
|
-
|| rawPhase === 'failed'
|
|
34
|
-
? rawPhase as MissionPhase
|
|
35
|
-
: undefined
|
|
36
|
-
const source = rawSource === 'chat'
|
|
37
|
-
|| rawSource === 'connector'
|
|
38
|
-
|| rawSource === 'heartbeat'
|
|
39
|
-
|| rawSource === 'main-loop-followup'
|
|
40
|
-
|| rawSource === 'task'
|
|
41
|
-
|| rawSource === 'schedule'
|
|
42
|
-
|| rawSource === 'delegation'
|
|
43
|
-
|| rawSource === 'manual'
|
|
44
|
-
? rawSource as MissionSource
|
|
45
|
-
: undefined
|
|
46
|
-
|
|
47
|
-
return NextResponse.json(listMissions({
|
|
48
|
-
...(sessionId ? { sessionId } : {}),
|
|
49
|
-
...(agentId ? { agentId } : {}),
|
|
50
|
-
...(projectId ? { projectId } : {}),
|
|
51
|
-
...(parentMissionId ? { parentMissionId } : {}),
|
|
52
|
-
...(status ? { status } : {}),
|
|
53
|
-
...(phase ? { phase } : {}),
|
|
54
|
-
...(source ? { source } : {}),
|
|
55
|
-
...(Number.isFinite(limit) ? { limit } : {}),
|
|
56
|
-
}))
|
|
57
|
-
}
|