@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.
Files changed (195) hide show
  1. package/README.md +30 -6
  2. package/package.json +2 -2
  3. package/src/app/agents/[id]/page.tsx +1 -18
  4. package/src/app/api/agents/thread-route.test.ts +0 -1
  5. package/src/app/api/approvals/route.test.ts +6 -22
  6. package/src/app/api/connectors/route.ts +2 -2
  7. package/src/app/api/portability/export/route.ts +8 -0
  8. package/src/app/api/portability/import/route.test.ts +80 -0
  9. package/src/app/api/portability/import/route.ts +28 -0
  10. package/src/app/api/settings/route.ts +0 -2
  11. package/src/app/api/wallets/[id]/route.ts +15 -157
  12. package/src/app/api/wallets/generate/route.ts +22 -0
  13. package/src/app/api/wallets/route.test.ts +147 -0
  14. package/src/app/api/wallets/route.ts +13 -95
  15. package/src/app/autonomy/page.tsx +2 -57
  16. package/src/app/protocols/page.tsx +2 -21
  17. package/src/app/settings/page.tsx +0 -9
  18. package/src/app/wallets/page.tsx +105 -5
  19. package/src/cli/index.js +21 -33
  20. package/src/cli/spec.js +19 -30
  21. package/src/components/agents/agent-sheet.tsx +2 -40
  22. package/src/components/agents/inspector-panel.tsx +0 -83
  23. package/src/components/chat/chat-card.tsx +0 -31
  24. package/src/components/chat/message-bubble.tsx +1 -108
  25. package/src/components/connectors/connector-sheet.tsx +25 -1
  26. package/src/components/layout/sidebar-rail.tsx +6 -10
  27. package/src/components/projects/project-detail.tsx +3 -35
  28. package/src/components/projects/tabs/overview-tab.tsx +3 -59
  29. package/src/components/projects/tabs/work-tab.tsx +7 -77
  30. package/src/components/protocols/structured-session-launcher.tsx +1 -22
  31. package/src/components/shared/connector-platform-icon.tsx +1 -0
  32. package/src/components/tasks/task-card.tsx +4 -34
  33. package/src/components/tasks/task-sheet.tsx +6 -36
  34. package/src/components/wallets/wallet-list.tsx +150 -0
  35. package/src/lib/app/navigation.test.ts +0 -13
  36. package/src/lib/app/navigation.ts +2 -7
  37. package/src/lib/app/view-constants.ts +14 -19
  38. package/src/lib/server/agents/agent-thread-session.ts +0 -1
  39. package/src/lib/server/agents/delegation-advisory.test.ts +0 -1
  40. package/src/lib/server/agents/delegation-jobs.test.ts +0 -69
  41. package/src/lib/server/agents/delegation-jobs.ts +0 -25
  42. package/src/lib/server/agents/main-agent-loop.ts +1 -49
  43. package/src/lib/server/agents/subagent-runtime.ts +0 -1
  44. package/src/lib/server/approval-match.ts +0 -85
  45. package/src/lib/server/approvals.test.ts +6 -6
  46. package/src/lib/server/approvals.ts +0 -6
  47. package/src/lib/server/autonomy/supervisor-reflection.test.ts +0 -1
  48. package/src/lib/server/builtin-extensions.ts +0 -2
  49. package/src/lib/server/capability-router.test.ts +0 -2
  50. package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +14 -14
  51. package/src/lib/server/chat-execution/chat-execution-types.ts +0 -2
  52. package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -2
  53. package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -30
  54. package/src/lib/server/chat-execution/chat-turn-finalization.ts +1 -36
  55. package/src/lib/server/chat-execution/chat-turn-preparation.ts +2 -22
  56. package/src/lib/server/chat-execution/iteration-event-handler.ts +0 -24
  57. package/src/lib/server/chat-execution/message-classifier.test.ts +0 -45
  58. package/src/lib/server/chat-execution/message-classifier.ts +1 -16
  59. package/src/lib/server/chat-execution/prompt-builder.test.ts +0 -1
  60. package/src/lib/server/chat-execution/prompt-builder.ts +0 -30
  61. package/src/lib/server/chat-execution/prompt-sections.ts +0 -1
  62. package/src/lib/server/chat-execution/situational-awareness.test.ts +2 -73
  63. package/src/lib/server/chat-execution/situational-awareness.ts +4 -38
  64. package/src/lib/server/chat-execution/stream-agent-chat.test.ts +8 -123
  65. package/src/lib/server/chat-execution/stream-agent-chat.ts +1 -5
  66. package/src/lib/server/chat-execution/stream-continuation.test.ts +4 -52
  67. package/src/lib/server/chat-execution/stream-continuation.ts +6 -48
  68. package/src/lib/server/chatrooms/session-mailbox.ts +0 -10
  69. package/src/lib/server/chats/chat-session-service.ts +3 -5
  70. package/src/lib/server/connectors/connector-inbound.ts +0 -1
  71. package/src/lib/server/connectors/connector-lifecycle.ts +19 -3
  72. package/src/lib/server/connectors/connector-service.ts +39 -9
  73. package/src/lib/server/connectors/swarmdock-bidding.ts +74 -0
  74. package/src/lib/server/connectors/swarmdock-payloads.test.ts +85 -0
  75. package/src/lib/server/connectors/swarmdock-secret.test.ts +128 -0
  76. package/src/lib/server/connectors/swarmdock-secret.ts +152 -0
  77. package/src/lib/server/connectors/swarmdock-tasks.ts +119 -0
  78. package/src/lib/server/connectors/swarmdock.ts +255 -0
  79. package/src/lib/server/execution-brief.test.ts +2 -25
  80. package/src/lib/server/execution-brief.ts +12 -35
  81. package/src/lib/server/execution-engine/task-attempt.ts +0 -1
  82. package/src/lib/server/persistence/storage-context.ts +0 -5
  83. package/src/lib/server/portability/export.ts +109 -0
  84. package/src/lib/server/portability/import.ts +159 -0
  85. package/src/lib/server/protocols/protocol-normalization.ts +0 -4
  86. package/src/lib/server/protocols/protocol-queries.ts +0 -6
  87. package/src/lib/server/protocols/protocol-run-lifecycle.ts +4 -32
  88. package/src/lib/server/protocols/protocol-service.ts +0 -1
  89. package/src/lib/server/protocols/protocol-step-helpers.ts +0 -4
  90. package/src/lib/server/protocols/protocol-step-processors.ts +0 -6
  91. package/src/lib/server/protocols/protocol-swarm.ts +0 -2
  92. package/src/lib/server/protocols/protocol-types.ts +0 -2
  93. package/src/lib/server/provider-health.ts +0 -9
  94. package/src/lib/server/runtime/daemon-state/core.ts +0 -9
  95. package/src/lib/server/runtime/daemon-state.test.ts +0 -35
  96. package/src/lib/server/runtime/heartbeat-service.ts +3 -23
  97. package/src/lib/server/runtime/queue/core.ts +11 -33
  98. package/src/lib/server/runtime/runtime-storage-write-paths.test.ts +6 -6
  99. package/src/lib/server/runtime/scheduler.ts +0 -13
  100. package/src/lib/server/runtime/session-run-manager/drain.ts +0 -24
  101. package/src/lib/server/runtime/session-run-manager/enqueue.ts +0 -1
  102. package/src/lib/server/runtime/session-run-manager/queries.ts +0 -1
  103. package/src/lib/server/runtime/session-run-manager/recovery.ts +0 -1
  104. package/src/lib/server/runtime/session-run-manager.test.ts +0 -28
  105. package/src/lib/server/session-tools/crud.ts +0 -14
  106. package/src/lib/server/session-tools/delegate.ts +0 -4
  107. package/src/lib/server/session-tools/index.ts +0 -4
  108. package/src/lib/server/session-tools/team-context.ts +0 -3
  109. package/src/lib/server/storage-normalization.ts +8 -0
  110. package/src/lib/server/storage.ts +18 -45
  111. package/src/lib/server/tasks/task-checkout.ts +59 -0
  112. package/src/lib/server/tasks/task-lifecycle.ts +2 -0
  113. package/src/lib/server/tasks/task-route-service.ts +4 -26
  114. package/src/lib/server/tasks/task-service.ts +0 -7
  115. package/src/lib/server/tool-aliases.ts +0 -1
  116. package/src/lib/server/tool-capability-policy-advanced.test.ts +4 -4
  117. package/src/lib/server/tool-capability-policy.ts +0 -2
  118. package/src/lib/server/tool-planning.ts +0 -12
  119. package/src/lib/server/universal-tool-access.ts +0 -1
  120. package/src/lib/server/wallets/wallet-crypto.ts +33 -0
  121. package/src/lib/server/wallets/wallet-repository.ts +24 -0
  122. package/src/lib/server/wallets/wallet-service.ts +119 -0
  123. package/src/lib/server/working-state/extraction.ts +8 -42
  124. package/src/lib/server/working-state/normalization.ts +10 -103
  125. package/src/lib/server/working-state/service.ts +12 -21
  126. package/src/lib/strip-internal-metadata.test.ts +1 -1
  127. package/src/lib/strip-internal-metadata.ts +1 -1
  128. package/src/lib/tool-definitions.ts +0 -1
  129. package/src/lib/validation/schemas.ts +33 -2
  130. package/src/stores/slices/data-slice.ts +5 -1
  131. package/src/stores/slices/ui-slice.ts +0 -4
  132. package/src/types/agent.ts +0 -84
  133. package/src/types/app-settings.ts +0 -2
  134. package/src/types/approval.ts +0 -2
  135. package/src/types/connector.ts +1 -0
  136. package/src/types/index.ts +1 -1
  137. package/src/types/message.ts +0 -1
  138. package/src/types/misc.ts +0 -2
  139. package/src/types/protocol.ts +0 -2
  140. package/src/types/run.ts +0 -3
  141. package/src/types/session.ts +1 -51
  142. package/src/types/swarmdock.ts +29 -0
  143. package/src/types/task.ts +7 -3
  144. package/src/types/working-state.ts +2 -9
  145. package/src/views/settings/section-runtime-loop.tsx +0 -14
  146. package/src/app/api/canvas/[sessionId]/route.ts +0 -35
  147. package/src/app/api/missions/[id]/actions/route.ts +0 -31
  148. package/src/app/api/missions/[id]/events/route.ts +0 -14
  149. package/src/app/api/missions/[id]/route.ts +0 -10
  150. package/src/app/api/missions/route.test.ts +0 -244
  151. package/src/app/api/missions/route.ts +0 -57
  152. package/src/app/api/wallets/[id]/approve/route.ts +0 -79
  153. package/src/app/api/wallets/[id]/balance-history/route.ts +0 -18
  154. package/src/app/api/wallets/[id]/send/route.ts +0 -113
  155. package/src/app/api/wallets/[id]/transactions/route.ts +0 -18
  156. package/src/app/missions/[id]/page.tsx +0 -3
  157. package/src/app/missions/page.tsx +0 -685
  158. package/src/components/canvas/canvas-panel.tsx +0 -267
  159. package/src/components/wallets/wallet-approval-dialog.tsx +0 -107
  160. package/src/components/wallets/wallet-panel.tsx +0 -1010
  161. package/src/components/wallets/wallet-section.tsx +0 -260
  162. package/src/features/missions/queries.ts +0 -23
  163. package/src/lib/canvas-content.test.ts +0 -360
  164. package/src/lib/canvas-content.ts +0 -198
  165. package/src/lib/server/canvas-content.test.ts +0 -32
  166. package/src/lib/server/canvas-content.ts +0 -6
  167. package/src/lib/server/ethereum.ts +0 -591
  168. package/src/lib/server/evm-swap.ts +0 -476
  169. package/src/lib/server/missions/mission-intent.test.ts +0 -63
  170. package/src/lib/server/missions/mission-intent.ts +0 -569
  171. package/src/lib/server/missions/mission-repository.ts +0 -74
  172. package/src/lib/server/missions/mission-service/actions.ts +0 -6
  173. package/src/lib/server/missions/mission-service/bindings.ts +0 -9
  174. package/src/lib/server/missions/mission-service/context.ts +0 -4
  175. package/src/lib/server/missions/mission-service/core.ts +0 -2271
  176. package/src/lib/server/missions/mission-service/queries.ts +0 -12
  177. package/src/lib/server/missions/mission-service/recovery.ts +0 -5
  178. package/src/lib/server/missions/mission-service/ticks.ts +0 -9
  179. package/src/lib/server/missions/mission-service.test.ts +0 -888
  180. package/src/lib/server/missions/mission-service.ts +0 -6
  181. package/src/lib/server/session-tools/canvas.ts +0 -105
  182. package/src/lib/server/session-tools/wallet-tool.test.ts +0 -150
  183. package/src/lib/server/session-tools/wallet.ts +0 -1287
  184. package/src/lib/server/solana.ts +0 -327
  185. package/src/lib/server/wallet/wallet-execution.test.ts +0 -198
  186. package/src/lib/server/wallet/wallet-portfolio.test.ts +0 -98
  187. package/src/lib/server/wallet/wallet-portfolio.ts +0 -772
  188. package/src/lib/server/wallet/wallet-service.test.ts +0 -81
  189. package/src/lib/server/wallet/wallet-service.ts +0 -225
  190. package/src/lib/wallet/wallet-transactions.test.ts +0 -75
  191. package/src/lib/wallet/wallet-transactions.ts +0 -43
  192. package/src/lib/wallet/wallet.test.ts +0 -333
  193. package/src/lib/wallet/wallet.ts +0 -183
  194. package/src/types/mission.ts +0 -185
  195. package/src/views/settings/section-wallets.tsx +0 -35
@@ -0,0 +1,150 @@
1
+ 'use client'
2
+
3
+ import { useEffect, useState } from 'react'
4
+ import { useAppStore } from '@/stores/use-app-store'
5
+ import { AgentAvatar } from '@/components/agents/agent-avatar'
6
+ import { api } from '@/lib/app/api-client'
7
+
8
+ export function WalletList() {
9
+ const wallets = useAppStore((s) => s.wallets)
10
+ const loadWallets = useAppStore((s) => s.loadWallets)
11
+ const agents = useAppStore((s) => s.agents)
12
+ const [copiedId, setCopiedId] = useState<string | null>(null)
13
+ const [deletingId, setDeletingId] = useState<string | null>(null)
14
+
15
+ useEffect(() => {
16
+ loadWallets()
17
+ }, [loadWallets])
18
+
19
+ const handleCopy = async (e: React.MouseEvent, address: string, walletId: string) => {
20
+ e.stopPropagation()
21
+ await navigator.clipboard.writeText(address)
22
+ setCopiedId(walletId)
23
+ setTimeout(() => setCopiedId(null), 2000)
24
+ }
25
+
26
+ const handleDelete = async (e: React.MouseEvent, id: string) => {
27
+ e.stopPropagation()
28
+ if (deletingId === id) {
29
+ await api('DELETE', `/wallets/${id}`)
30
+ setDeletingId(null)
31
+ loadWallets()
32
+ } else {
33
+ setDeletingId(id)
34
+ setTimeout(() => setDeletingId(null), 3000)
35
+ }
36
+ }
37
+
38
+ const truncateAddress = (addr: string) =>
39
+ addr.length > 12 ? `${addr.slice(0, 6)}...${addr.slice(-4)}` : addr
40
+
41
+ const walletList = Object.values(wallets)
42
+
43
+ if (!walletList.length) {
44
+ return (
45
+ <div className="flex-1 flex flex-col items-center justify-center px-6 py-12 text-center">
46
+ <div className="w-12 h-12 rounded-[14px] bg-white/[0.03] border border-white/[0.06] flex items-center justify-center mb-4">
47
+ <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="text-text-3">
48
+ <rect x="2" y="6" width="20" height="14" rx="2" /><path d="M22 10H18a2 2 0 0 0 0 4h4" /><path d="M6 6V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v2" />
49
+ </svg>
50
+ </div>
51
+ <p className="text-[13px] text-text-3 mb-1 font-600">No wallets yet</p>
52
+ <p className="text-[12px] text-text-3/60">Generate a wallet for your agents to transact on Base L2</p>
53
+ </div>
54
+ )
55
+ }
56
+
57
+ return (
58
+ <div className="flex-1 overflow-y-auto px-5 pb-6">
59
+ <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3">
60
+ {walletList.map((wallet, idx) => {
61
+ const agent = agents[wallet.agentId]
62
+ return (
63
+ <div
64
+ key={wallet.id}
65
+ className="w-full text-left p-4 rounded-[14px] bg-surface border border-white/[0.06]
66
+ hover:border-white/[0.12] hover:bg-white/[0.02] transition-all group"
67
+ style={{
68
+ fontFamily: 'inherit',
69
+ animation: 'spring-in 0.5s var(--ease-spring) both',
70
+ animationDelay: `${idx * 0.05}s`,
71
+ }}
72
+ >
73
+ {/* Header: agent + delete */}
74
+ <div className="flex items-center gap-2.5 mb-2">
75
+ {agent ? (
76
+ <AgentAvatar seed={agent.avatarSeed} avatarUrl={agent.avatarUrl} name={agent.name} size={20} />
77
+ ) : (
78
+ <div className="w-5 h-5 rounded-full bg-white/[0.06]" />
79
+ )}
80
+ <span className="text-[13px] font-600 text-text truncate flex-1">
81
+ {agent?.name || 'Unknown Agent'}
82
+ </span>
83
+ <button
84
+ onClick={(e) => handleDelete(e, wallet.id)}
85
+ className={`text-[10px] font-600 px-1.5 py-0.5 rounded-[6px] transition-colors cursor-pointer ${
86
+ deletingId === wallet.id
87
+ ? 'text-red-400 bg-red-400/10'
88
+ : 'text-text-3/40 hover:text-red-400'
89
+ }`}
90
+ title={deletingId === wallet.id ? 'Click again to confirm' : 'Delete wallet'}
91
+ >
92
+ {deletingId === wallet.id ? 'Confirm?' : (
93
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
94
+ <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
95
+ </svg>
96
+ )}
97
+ </button>
98
+ </div>
99
+
100
+ {/* Address row */}
101
+ <div className="flex items-center gap-2 mb-2">
102
+ <span className="text-[12px] font-mono text-text-3 truncate">{truncateAddress(wallet.walletAddress)}</span>
103
+ <button
104
+ onClick={(e) => handleCopy(e, wallet.walletAddress, wallet.id)}
105
+ className="text-text-3/40 hover:text-text-2 transition-colors shrink-0 cursor-pointer"
106
+ title="Copy address"
107
+ >
108
+ {copiedId === wallet.id ? (
109
+ <span className="text-[10px] font-600 text-emerald-400">Copied!</span>
110
+ ) : (
111
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
112
+ <rect x="9" y="9" width="13" height="13" rx="2" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
113
+ </svg>
114
+ )}
115
+ </button>
116
+ </div>
117
+
118
+ {/* Badges row */}
119
+ <div className="flex items-center gap-2 flex-wrap">
120
+ <span className="text-[10px] font-600 px-1.5 py-0.5 rounded-[6px] bg-blue-500/10 text-blue-400">
121
+ Base L2
122
+ </span>
123
+ {wallet.requireApproval && (
124
+ <span className="text-[10px] font-600 px-1.5 py-0.5 rounded-[6px] bg-amber-500/10 text-amber-400">
125
+ Approval Required
126
+ </span>
127
+ )}
128
+ {wallet.spendingLimitUsdc && (
129
+ <span className="text-[10px] font-600 text-text-3/60">
130
+ Limit: ${wallet.spendingLimitUsdc} USDC
131
+ </span>
132
+ )}
133
+ {wallet.dailyLimitUsdc && (
134
+ <span className="text-[10px] font-600 text-text-3/60">
135
+ Daily: ${wallet.dailyLimitUsdc} USDC
136
+ </span>
137
+ )}
138
+ </div>
139
+
140
+ {/* Label */}
141
+ {wallet.label && (
142
+ <div className="mt-2 text-[11px] text-text-3/60 truncate">{wallet.label}</div>
143
+ )}
144
+ </div>
145
+ )
146
+ })}
147
+ </div>
148
+ </div>
149
+ )
150
+ }
@@ -39,19 +39,6 @@ describe('getViewPath', () => {
39
39
  })
40
40
  })
41
41
 
42
- describe('getMissionPath', () => {
43
- it('returns /missions when no ID is provided', () => {
44
- assert.equal(mod.getMissionPath(), '/missions')
45
- assert.equal(mod.getMissionPath(null), '/missions')
46
- assert.equal(mod.getMissionPath(''), '/missions')
47
- })
48
-
49
- it('returns /missions/{encoded} with an ID', () => {
50
- assert.equal(mod.getMissionPath('m-42'), '/missions/m-42')
51
- assert.equal(mod.getMissionPath('has/slash'), '/missions/has%2Fslash')
52
- })
53
- })
54
-
55
42
  describe('pathToView', () => {
56
43
  it('matches exact path', () => {
57
44
  assert.equal(mod.pathToView('/agents'), 'agents')
@@ -13,9 +13,10 @@ const VIEW_TO_PATH: Record<AppView, string> = {
13
13
  protocols: '/protocols',
14
14
  schedules: '/schedules',
15
15
  memory: '/memory',
16
- missions: '/missions',
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
- missions: 'Missions',
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
- missions: 'Durable mission control and execution state',
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, missions, or schedules without turning every surface into a workflow engine.',
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
- missions: {
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', 'missions', 'secrets', 'providers', 'skills',
219
+ 'home', 'org_chart', 'inbox', 'chatrooms', 'protocols', 'schedules', 'secrets', 'wallets', 'providers', 'skills',
225
220
  'connectors', 'webhooks', 'mcp_servers', 'knowledge', 'extensions',
226
- 'usage', 'wallets', 'runs', 'autonomy', 'logs', 'settings', 'activity', 'projects',
221
+ 'usage', 'runs', 'autonomy', 'logs', 'settings', 'activity', 'projects',
227
222
  ])
@@ -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
  }
@@ -10,7 +10,6 @@ import {
10
10
  import { loadAgents } from '@/lib/server/agents/agent-repository'
11
11
  import { assessAutonomyRun } from '@/lib/server/autonomy/supervisor-reflection'
12
12
  import { enqueueSystemEvent } from '@/lib/server/runtime/system-events'
13
- import { buildMissionHeartbeatPrompt as buildMissionHeartbeatPromptFromMission, getMissionForSession } from '@/lib/server/missions/mission-service'
14
13
  import { loadSettings } from '@/lib/server/settings/settings-repository'
15
14
  import { getSession, loadSessions } from '@/lib/server/sessions/session-repository'
16
15
  import { deleteSessionWorkingState, loadSessionWorkingState, syncWorkingStateFromMainLoopState } from '@/lib/server/working-state/service'
@@ -37,7 +36,6 @@ export interface MainLoopState {
37
36
  currentPlanStep: string | null
38
37
  reviewNote: string | null
39
38
  reviewConfidence: number | null
40
- missionTaskId: string | null
41
39
  momentumScore: number
42
40
  paused: boolean
43
41
  status: 'idle' | 'progress' | 'blocked' | 'ok'
@@ -55,8 +53,6 @@ export interface MainLoopState {
55
53
  note: string
56
54
  status?: 'idle' | 'progress' | 'blocked' | 'ok' | 'reflection'
57
55
  }>
58
- missionTokens: number
59
- missionCostUsd: number
60
56
  followupChainCount: number
61
57
  lifetimeIterations: number
62
58
  metaMissCount: number
@@ -137,15 +133,12 @@ function defaultState(): MainLoopState {
137
133
  currentPlanStep: null,
138
134
  reviewNote: null,
139
135
  reviewConfidence: null,
140
- missionTaskId: null,
141
136
  momentumScore: 0,
142
137
  paused: false,
143
138
  status: 'idle',
144
139
  autonomyMode: 'assist',
145
140
  pendingEvents: [],
146
141
  timeline: [],
147
- missionTokens: 0,
148
- missionCostUsd: 0,
149
142
  followupChainCount: 0,
150
143
  lifetimeIterations: 0,
151
144
  metaMissCount: 0,
@@ -304,8 +297,6 @@ function clampState(state: MainLoopState): MainLoopState {
304
297
  state.followupChainCount = Math.max(0, Math.min(10, Math.trunc(state.followupChainCount || 0)))
305
298
  state.lifetimeIterations = Math.max(0, Math.trunc(state.lifetimeIterations || 0))
306
299
  state.metaMissCount = Math.max(0, Math.min(100, Math.trunc(state.metaMissCount || 0)))
307
- state.missionTokens = Math.max(0, Math.trunc(state.missionTokens || 0))
308
- state.missionCostUsd = Math.max(0, Number.isFinite(state.missionCostUsd) ? Number(state.missionCostUsd) : 0)
309
300
  state.skillBlocker = normalizeSkillBlocker(state.skillBlocker)
310
301
  state.updatedAt = typeof state.updatedAt === 'number' && Number.isFinite(state.updatedAt) ? Math.trunc(state.updatedAt) : now()
311
302
  return state
@@ -325,15 +316,12 @@ function normalizeState(input?: Partial<MainLoopState> | null): MainLoopState {
325
316
  if (typeof input.reviewConfidence === 'number' || typeof input.reviewConfidence === 'string' || input.reviewConfidence === null) {
326
317
  next.reviewConfidence = normalizeConfidence(input.reviewConfidence)
327
318
  }
328
- if (typeof input.missionTaskId === 'string' || input.missionTaskId === null) next.missionTaskId = input.missionTaskId
329
319
  if (typeof input.momentumScore === 'number') next.momentumScore = input.momentumScore
330
320
  if (typeof input.paused === 'boolean') next.paused = input.paused
331
321
  if (input.status) next.status = normalizeStatus(input.status, next.status)
332
322
  if (input.autonomyMode) next.autonomyMode = normalizeAutonomyMode(input.autonomyMode, next.autonomyMode)
333
323
  if (Array.isArray(input.pendingEvents)) next.pendingEvents = [...input.pendingEvents]
334
324
  if (Array.isArray(input.timeline)) next.timeline = [...input.timeline]
335
- if (typeof input.missionTokens === 'number') next.missionTokens = input.missionTokens
336
- if (typeof input.missionCostUsd === 'number') next.missionCostUsd = input.missionCostUsd
337
325
  if (typeof input.followupChainCount === 'number') next.followupChainCount = input.followupChainCount
338
326
  if (typeof input.lifetimeIterations === 'number') next.lifetimeIterations = input.lifetimeIterations
339
327
  if (typeof input.metaMissCount === 'number') next.metaMissCount = input.metaMissCount
@@ -435,10 +423,8 @@ function persistState(sessionId: string, state: MainLoopState): void {
435
423
  upsertPersistedMainLoopState(sessionId, normalized as unknown as Record<string, unknown>)
436
424
  const session = getSession(sessionId)
437
425
  if (!session) return
438
- const mission = getMissionForSession(session)
439
426
  void syncWorkingStateFromMainLoopState({
440
427
  sessionId,
441
- mission,
442
428
  goal: normalized.goal,
443
429
  summary: normalized.summary,
444
430
  status: normalized.status === 'ok'
@@ -797,11 +783,6 @@ export function buildMainLoopHeartbeatPrompt(session: unknown, fallbackPrompt: s
797
783
  const candidate = asSession(session)
798
784
  if (!candidate?.id) return fallbackPrompt
799
785
  const persistedSession = getSession(String(candidate.id)) as Session | undefined
800
- const missionPrompt = buildMissionHeartbeatPromptFromMission(
801
- persistedSession || candidate as Session,
802
- fallbackPrompt,
803
- )
804
- if (missionPrompt) return missionPrompt
805
786
  const state = getOrCreateState(String(candidate.id))
806
787
  if (!state) return fallbackPrompt
807
788
  const latestExternalGoal = extractLatestGoal(Array.isArray(candidate.messages) ? candidate.messages as Message[] : [])
@@ -812,7 +793,6 @@ export function buildMainLoopHeartbeatPrompt(session: unknown, fallbackPrompt: s
812
793
  const heartbeatSession = (persistedSession || candidate as Session)
813
794
  const executionBrief = buildExecutionBrief({
814
795
  session: heartbeatSession,
815
- mission: getMissionForSession(heartbeatSession),
816
796
  })
817
797
  const executionBriefBlock = buildExecutionBriefContextBlock(executionBrief)
818
798
  const boundedFallbackPrompt = cleanMultiline(fallbackPrompt, 500)
@@ -969,8 +949,6 @@ export function handleMainLoopRunResult(input: HandleMainLoopRunResultInput): Ma
969
949
  const messageGoal = shouldCaptureMessageGoal ? parseGoalContractFromText(input.message || '') : null
970
950
  const nowTs = now()
971
951
  state.lifetimeIterations++
972
- const mission = session ? getMissionForSession(session) : null
973
-
974
952
  if (messageGoal) state.goalContract = mergeGoalContracts(state.goalContract, messageGoal)
975
953
  if (!state.goal && shouldCaptureMessageGoal) state.goal = cleanMultiline(input.message, 900)
976
954
  if (heartbeat?.goal) state.goal = heartbeat.goal
@@ -1011,8 +989,6 @@ export function handleMainLoopRunResult(input: HandleMainLoopRunResultInput): Ma
1011
989
 
1012
990
  state.lastTickAt = nowTs
1013
991
  state.updatedAt = nowTs
1014
- state.missionTokens += Math.max(0, Math.trunc((input.inputTokens || 0) + (input.outputTokens || 0)))
1015
- state.missionCostUsd += Math.max(0, Number(input.estimatedCost || 0))
1016
992
  const cleanedResult = persistedText.trim()
1017
993
  const waitingForExternal = extractWaitSignal(resultText)
1018
994
  const gotTerminalAck = /^HEARTBEAT_OK$/i.test(cleanedResult) || /^NO_MESSAGE$/i.test(cleanedResult)
@@ -1073,32 +1049,8 @@ export function handleMainLoopRunResult(input: HandleMainLoopRunResultInput): Ma
1073
1049
  const needsReplan = review?.needs_replan === true || ((review?.confidence ?? 1) < 0.45)
1074
1050
  const limit = followupLimit(input.sessionId)
1075
1051
 
1076
- if (mission) {
1077
- state.goal = cleanMultiline(mission.objective, 900)
1078
- state.missionTaskId = mission.rootTaskId || null
1079
- state.summary = cleanMultiline(mission.verifierSummary || mission.plannerSummary || state.summary, 500)
1080
- state.nextAction = cleanText(mission.currentStep, 280) || null
1081
- state.currentPlanStep = cleanText(mission.currentStep, 280) || null
1082
- state.planSteps = mission.currentStep ? [mission.currentStep] : []
1083
- state.status = mission.status === 'completed'
1084
- ? 'ok'
1085
- : mission.status === 'waiting' || mission.status === 'failed' || mission.status === 'cancelled'
1086
- ? 'blocked'
1087
- : 'progress'
1088
- state.paused = mission.status === 'waiting' || mission.status === 'failed' || mission.status === 'cancelled'
1089
- }
1090
-
1091
1052
  let followup: MainLoopFollowupRequest | null = null
1092
- if (mission) {
1093
- state.followupChainCount = 0
1094
- if (mission.status === 'completed') {
1095
- state.status = 'ok'
1096
- state.paused = false
1097
- }
1098
- if (mission.status === 'waiting' || mission.status === 'failed' || mission.status === 'cancelled') {
1099
- state.paused = true
1100
- }
1101
- } else if (isDirectUserChat) {
1053
+ if (isDirectUserChat) {
1102
1054
  state.followupChainCount = 0
1103
1055
  state.lifetimeIterations = 0
1104
1056
  if (successfulChatDelivery) {
@@ -237,7 +237,6 @@ async function spawnSubagentImpl(
237
237
  const job = createDelegationJob({
238
238
  kind: 'subagent',
239
239
  parentSessionId: context.sessionId || null,
240
- parentMissionId: typeof parent?.missionId === 'string' ? parent.missionId : null,
241
240
  agentId: input.agentId,
242
241
  task: input.message,
243
242
  cwd: input.cwd || context.cwd,