@swarmclawai/swarmclaw 0.7.8 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -15
- package/next.config.ts +13 -2
- package/package.json +4 -2
- package/src/app/api/agents/[id]/thread/route.ts +9 -0
- package/src/app/api/agents/route.ts +4 -0
- package/src/app/api/agents/thread-route.test.ts +133 -0
- package/src/app/api/approvals/route.test.ts +148 -0
- package/src/app/api/canvas/[sessionId]/route.ts +3 -1
- package/src/app/api/chatrooms/[id]/chat/route.ts +4 -2
- package/src/app/api/chats/[id]/devserver/route.ts +48 -7
- package/src/app/api/chats/[id]/messages/route.ts +42 -18
- package/src/app/api/chats/[id]/route.ts +1 -1
- package/src/app/api/chats/[id]/stop/route.ts +5 -4
- package/src/app/api/chats/route.ts +22 -2
- package/src/app/api/clawhub/install/route.ts +28 -8
- package/src/app/api/connectors/[id]/route.ts +26 -1
- package/src/app/api/external-agents/route.test.ts +165 -0
- package/src/app/api/gateways/[id]/health/route.ts +27 -12
- package/src/app/api/gateways/[id]/route.ts +2 -0
- package/src/app/api/gateways/health-route.test.ts +135 -0
- package/src/app/api/gateways/route.ts +2 -0
- package/src/app/api/mcp-servers/route.test.ts +130 -0
- package/src/app/api/openclaw/deploy/route.ts +38 -5
- package/src/app/api/plugins/install/route.ts +46 -6
- package/src/app/api/plugins/marketplace/route.ts +48 -15
- package/src/app/api/preview-server/route.ts +26 -11
- package/src/app/api/schedules/[id]/run/route.ts +4 -0
- package/src/app/api/schedules/route.test.ts +86 -0
- package/src/app/api/schedules/route.ts +6 -1
- package/src/app/api/setup/check-provider/route.test.ts +19 -0
- package/src/app/api/setup/check-provider/route.ts +40 -10
- package/src/app/api/skills/[id]/route.ts +12 -0
- package/src/app/api/skills/import/route.ts +14 -12
- package/src/app/api/skills/route.ts +13 -1
- package/src/app/api/tasks/[id]/route.ts +10 -1
- package/src/app/api/tasks/import/github/route.test.ts +65 -0
- package/src/app/api/tasks/import/github/route.ts +337 -0
- package/src/app/api/wallets/[id]/approve/route.ts +17 -3
- package/src/app/api/wallets/[id]/route.ts +79 -33
- package/src/app/api/wallets/[id]/send/route.ts +19 -33
- package/src/app/api/wallets/route.ts +78 -61
- package/src/app/api/webhooks/[id]/route.ts +33 -6
- package/src/app/api/webhooks/route.test.ts +272 -0
- package/src/cli/index.js +1 -0
- package/src/cli/spec.js +1 -0
- package/src/components/agents/agent-card.tsx +9 -2
- package/src/components/agents/agent-chat-list.tsx +18 -2
- package/src/components/agents/agent-list.tsx +1 -0
- package/src/components/agents/agent-sheet.tsx +73 -24
- package/src/components/agents/inspector-panel.tsx +41 -0
- package/src/components/canvas/canvas-panel.tsx +236 -65
- package/src/components/chat/chat-card.tsx +36 -13
- package/src/components/chat/chat-header.tsx +44 -16
- package/src/components/chat/chat-list.tsx +28 -4
- package/src/components/chat/checkpoint-timeline.tsx +50 -34
- package/src/components/chat/message-bubble.tsx +208 -145
- package/src/components/chat/message-list.tsx +48 -19
- package/src/components/chatrooms/chatroom-message.tsx +2 -2
- package/src/components/chatrooms/chatroom-sheet.tsx +16 -2
- package/src/components/connectors/connector-health.tsx +1 -1
- package/src/components/connectors/connector-list.tsx +7 -2
- package/src/components/connectors/connector-sheet.tsx +337 -148
- package/src/components/gateways/gateway-sheet.tsx +2 -2
- package/src/components/mcp-servers/mcp-server-list.tsx +26 -5
- package/src/components/mcp-servers/mcp-server-sheet.tsx +19 -2
- package/src/components/openclaw/openclaw-deploy-panel.tsx +269 -21
- package/src/components/plugins/plugin-list.tsx +45 -9
- package/src/components/plugins/plugin-sheet.tsx +55 -7
- package/src/components/providers/provider-list.tsx +2 -1
- package/src/components/providers/provider-sheet.tsx +21 -2
- package/src/components/schedules/schedule-card.tsx +25 -1
- package/src/components/schedules/schedule-sheet.tsx +44 -2
- package/src/components/secrets/secret-sheet.tsx +21 -2
- package/src/components/shared/agent-switch-dialog.tsx +12 -1
- package/src/components/shared/bottom-sheet.tsx +13 -3
- package/src/components/shared/command-palette.tsx +8 -1
- package/src/components/shared/confirm-dialog.tsx +19 -4
- package/src/components/shared/connector-platform-icon.test.ts +28 -0
- package/src/components/shared/connector-platform-icon.tsx +39 -6
- package/src/components/shared/settings/plugin-manager.tsx +29 -6
- package/src/components/shared/settings/section-capability-policy.tsx +7 -3
- package/src/components/skills/skill-list.tsx +25 -0
- package/src/components/skills/skill-sheet.tsx +84 -12
- package/src/components/tasks/approvals-panel.tsx +191 -95
- package/src/components/tasks/task-board.tsx +273 -2
- package/src/components/tasks/task-card.tsx +38 -9
- package/src/components/ui/dialog.tsx +2 -2
- package/src/components/wallets/wallet-approval-dialog.tsx +4 -2
- package/src/components/wallets/wallet-panel.tsx +435 -90
- package/src/components/wallets/wallet-section.tsx +198 -48
- package/src/components/webhooks/webhook-sheet.tsx +22 -2
- package/src/lib/approval-display.ts +20 -0
- package/src/lib/canvas-content.ts +198 -0
- package/src/lib/chat-artifact-summary.ts +165 -0
- package/src/lib/chat-display.test.ts +91 -0
- package/src/lib/chat-display.ts +58 -0
- package/src/lib/chat-streaming-state.test.ts +47 -1
- package/src/lib/chat-streaming-state.ts +42 -0
- package/src/lib/ollama-model.ts +10 -0
- package/src/lib/openclaw-endpoint.test.ts +8 -0
- package/src/lib/openclaw-endpoint.ts +6 -1
- package/src/lib/plugin-install-cors.ts +46 -0
- package/src/lib/plugin-sources.test.ts +43 -0
- package/src/lib/plugin-sources.ts +77 -0
- package/src/lib/providers/ollama.ts +16 -6
- package/src/lib/providers/openclaw.test.ts +54 -0
- package/src/lib/providers/openclaw.ts +127 -11
- package/src/lib/schedule-dedupe-advanced.test.ts +1335 -0
- package/src/lib/schedule-dedupe.test.ts +66 -1
- package/src/lib/schedule-dedupe.ts +169 -12
- package/src/lib/schedule-origin.test.ts +20 -0
- package/src/lib/schedule-origin.ts +15 -0
- package/src/lib/server/__fixtures__/fake-mcp-stdio-server.mjs +27 -0
- package/src/lib/server/agent-availability.ts +16 -0
- package/src/lib/server/agent-runtime-config.ts +12 -4
- package/src/lib/server/agent-thread-session.test.ts +51 -0
- package/src/lib/server/agent-thread-session.ts +7 -0
- package/src/lib/server/approval-match.ts +205 -0
- package/src/lib/server/approvals-auto-approve.test.ts +538 -1
- package/src/lib/server/approvals.ts +214 -1
- package/src/lib/server/assistant-control.test.ts +29 -0
- package/src/lib/server/assistant-control.ts +23 -0
- package/src/lib/server/build-llm.test.ts +79 -0
- package/src/lib/server/build-llm.ts +14 -4
- package/src/lib/server/canvas-content.test.ts +32 -0
- package/src/lib/server/canvas-content.ts +6 -0
- package/src/lib/server/capability-router.test.ts +11 -0
- package/src/lib/server/capability-router.ts +26 -1
- package/src/lib/server/chat-execution-advanced.test.ts +651 -0
- package/src/lib/server/chat-execution-disabled.test.ts +94 -0
- package/src/lib/server/chat-execution-tool-events.test.ts +157 -0
- package/src/lib/server/chat-execution.ts +353 -72
- package/src/lib/server/clawhub-client.test.ts +14 -8
- package/src/lib/server/connectors/manager.test.ts +1147 -0
- package/src/lib/server/connectors/manager.ts +362 -63
- package/src/lib/server/connectors/pairing.ts +26 -5
- package/src/lib/server/connectors/types.ts +2 -0
- package/src/lib/server/connectors/whatsapp.test.ts +134 -0
- package/src/lib/server/connectors/whatsapp.ts +271 -47
- package/src/lib/server/context-manager.ts +6 -1
- package/src/lib/server/daemon-state.ts +1 -1
- package/src/lib/server/data-dir.test.ts +37 -0
- package/src/lib/server/data-dir.ts +20 -1
- package/src/lib/server/delegation-jobs-advanced.test.ts +513 -0
- package/src/lib/server/devserver-launch.test.ts +60 -0
- package/src/lib/server/devserver-launch.ts +85 -0
- package/src/lib/server/elevenlabs.test.ts +189 -1
- package/src/lib/server/elevenlabs.ts +147 -43
- package/src/lib/server/ethereum.ts +590 -0
- package/src/lib/server/eval/agent-regression-advanced.test.ts +302 -0
- package/src/lib/server/eval/agent-regression.test.ts +18 -1
- package/src/lib/server/eval/agent-regression.ts +383 -11
- package/src/lib/server/evm-swap.ts +475 -0
- package/src/lib/server/execution-log.ts +1 -0
- package/src/lib/server/heartbeat-service-timer.test.ts +173 -0
- package/src/lib/server/heartbeat-service.ts +15 -10
- package/src/lib/server/heartbeat-wake.test.ts +112 -0
- package/src/lib/server/heartbeat-wake.ts +338 -57
- package/src/lib/server/main-agent-loop-advanced.test.ts +538 -0
- package/src/lib/server/mcp-client.test.ts +16 -0
- package/src/lib/server/mcp-client.ts +25 -0
- package/src/lib/server/memory-integration.test.ts +719 -0
- package/src/lib/server/memory-policy.test.ts +43 -0
- package/src/lib/server/memory-policy.ts +132 -0
- package/src/lib/server/memory-tiers.test.ts +60 -0
- package/src/lib/server/memory-tiers.ts +16 -0
- package/src/lib/server/ollama-runtime.ts +58 -0
- package/src/lib/server/openclaw-deploy.test.ts +109 -1
- package/src/lib/server/openclaw-deploy.ts +557 -81
- package/src/lib/server/openclaw-gateway.test.ts +131 -0
- package/src/lib/server/openclaw-gateway.ts +10 -4
- package/src/lib/server/openclaw-health.test.ts +35 -0
- package/src/lib/server/openclaw-health.ts +215 -47
- package/src/lib/server/orchestrator-lg.ts +2 -2
- package/src/lib/server/plugins-advanced.test.ts +351 -0
- package/src/lib/server/plugins.ts +205 -5
- package/src/lib/server/queue-advanced.test.ts +528 -0
- package/src/lib/server/queue-followups.test.ts +262 -0
- package/src/lib/server/queue-reconcile.test.ts +128 -0
- package/src/lib/server/queue.ts +293 -61
- package/src/lib/server/scheduler.ts +29 -1
- package/src/lib/server/session-note.test.ts +36 -0
- package/src/lib/server/session-note.ts +42 -0
- package/src/lib/server/session-run-manager.ts +52 -4
- package/src/lib/server/session-tools/canvas.ts +14 -12
- package/src/lib/server/session-tools/connector.test.ts +138 -0
- package/src/lib/server/session-tools/connector.ts +348 -61
- package/src/lib/server/session-tools/context.ts +12 -3
- package/src/lib/server/session-tools/crud.ts +221 -10
- package/src/lib/server/session-tools/delegate-fallback.test.ts +103 -0
- package/src/lib/server/session-tools/delegate.ts +64 -8
- package/src/lib/server/session-tools/discovery-approvals.test.ts +142 -0
- package/src/lib/server/session-tools/discovery.ts +80 -12
- package/src/lib/server/session-tools/file-normalize.test.ts +36 -0
- package/src/lib/server/session-tools/file.ts +43 -4
- package/src/lib/server/session-tools/human-loop.ts +35 -5
- package/src/lib/server/session-tools/index.ts +44 -9
- package/src/lib/server/session-tools/manage-connectors.test.ts +139 -0
- package/src/lib/server/session-tools/manage-schedules-advanced.test.ts +564 -0
- package/src/lib/server/session-tools/manage-schedules.test.ts +283 -0
- package/src/lib/server/session-tools/manage-tasks-advanced.test.ts +852 -0
- package/src/lib/server/session-tools/memory.test.ts +93 -0
- package/src/lib/server/session-tools/memory.ts +546 -79
- package/src/lib/server/session-tools/normalize-tool-args.ts +1 -1
- package/src/lib/server/session-tools/plugin-creator.ts +57 -1
- package/src/lib/server/session-tools/primitive-tools.test.ts +6 -0
- package/src/lib/server/session-tools/schedule.ts +6 -1
- package/src/lib/server/session-tools/shell-normalize.test.ts +25 -1
- package/src/lib/server/session-tools/shell.ts +22 -3
- package/src/lib/server/session-tools/wallet-tool.test.ts +254 -0
- package/src/lib/server/session-tools/wallet.ts +1374 -139
- package/src/lib/server/session-tools/web-inputs.test.ts +162 -1
- package/src/lib/server/session-tools/web.ts +468 -64
- package/src/lib/server/skill-discovery.ts +128 -0
- package/src/lib/server/skill-eligibility.test.ts +84 -0
- package/src/lib/server/skill-eligibility.ts +95 -0
- package/src/lib/server/skill-prompt-budget.test.ts +102 -0
- package/src/lib/server/skill-prompt-budget.ts +125 -0
- package/src/lib/server/skills-normalize.test.ts +54 -0
- package/src/lib/server/skills-normalize.ts +372 -26
- package/src/lib/server/solana.ts +214 -29
- package/src/lib/server/storage.ts +65 -36
- package/src/lib/server/stream-agent-chat.test.ts +419 -9
- package/src/lib/server/stream-agent-chat.ts +887 -83
- package/src/lib/server/system-events.ts +1 -1
- package/src/lib/server/tool-capability-policy-advanced.test.ts +502 -0
- package/src/lib/server/tool-loop-detection.test.ts +105 -0
- package/src/lib/server/tool-loop-detection.ts +260 -0
- package/src/lib/server/tool-planning.ts +4 -2
- package/src/lib/server/wallet-execution.test.ts +198 -0
- package/src/lib/server/wallet-portfolio.test.ts +98 -0
- package/src/lib/server/wallet-portfolio.ts +724 -0
- package/src/lib/server/wallet-service.test.ts +57 -0
- package/src/lib/server/wallet-service.ts +213 -0
- package/src/lib/server/watch-jobs-advanced.test.ts +594 -0
- package/src/lib/server/watch-jobs.ts +17 -2
- package/src/lib/server/workspace-context.ts +111 -0
- package/src/lib/skill-save-payload.test.ts +39 -0
- package/src/lib/skill-save-payload.ts +37 -0
- package/src/lib/tasks.ts +28 -0
- package/src/lib/tool-event-summary.test.ts +30 -0
- package/src/lib/tool-event-summary.ts +37 -0
- package/src/lib/validation/schemas.ts +1 -0
- package/src/lib/wallet-transactions.test.ts +75 -0
- package/src/lib/wallet-transactions.ts +43 -0
- package/src/lib/wallet.test.ts +17 -0
- package/src/lib/wallet.ts +183 -0
- package/src/proxy.test.ts +31 -0
- package/src/proxy.ts +34 -2
- package/src/stores/use-chat-store.ts +15 -1
- package/src/types/index.ts +210 -14
|
@@ -13,27 +13,33 @@ import type { AppSettings, ApprovalCategory, ApprovalRequest } from '@/types'
|
|
|
13
13
|
const CATEGORY_LABELS: Record<string, string> = {
|
|
14
14
|
tool_access: 'Plugin Access',
|
|
15
15
|
wallet_transfer: 'Wallet Transfer',
|
|
16
|
+
wallet_action: 'Wallet Action',
|
|
16
17
|
plugin_scaffold: 'Plugin Creation',
|
|
17
18
|
plugin_install: 'Plugin Install',
|
|
19
|
+
connector_sender: 'Connector Sender',
|
|
18
20
|
task_tool: 'Task Plugin Call',
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
const CATEGORY_ICONS: Record<string, string> = {
|
|
22
24
|
tool_access: '🔑',
|
|
23
25
|
wallet_transfer: '💰',
|
|
26
|
+
wallet_action: '✍️',
|
|
24
27
|
plugin_scaffold: '🔌',
|
|
25
28
|
plugin_install: '📦',
|
|
29
|
+
connector_sender: '📲',
|
|
26
30
|
task_tool: '🤖',
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
type ApprovalScope = 'all' | 'execution' | 'workflow' | 'task'
|
|
30
34
|
|
|
31
|
-
const AUTO_APPROVE_OPTIONS: Array<{ id: ApprovalCategory; label: string; description: string }> = [
|
|
35
|
+
const AUTO_APPROVE_OPTIONS: Array<{ id: ApprovalCategory; label: string; description: string; risk?: 'high' | 'very-high' }> = [
|
|
32
36
|
{ id: 'tool_access', label: 'Plugin Access', description: 'Auto-enable requested plugins for a chat.' },
|
|
33
37
|
{ id: 'plugin_scaffold', label: 'Plugin Scaffold', description: 'Auto-create plugin files requested by agents.' },
|
|
34
38
|
{ id: 'plugin_install', label: 'Plugin Install', description: 'Auto-install plugins from approved URLs.' },
|
|
39
|
+
{ id: 'connector_sender', label: 'Connector Senders', description: 'Auto-approve new connector senders and add them to the allowlist.' },
|
|
35
40
|
{ id: 'human_loop', label: 'Human Approval Requests', description: 'Auto-approve ask-human approval prompts.' },
|
|
36
|
-
{ id: 'wallet_transfer', label: 'Wallet Transfers', description: 'Auto-approve wallet send requests.
|
|
41
|
+
{ id: 'wallet_transfer', label: 'Wallet Transfers', description: 'Auto-approve wallet send requests.', risk: 'high' },
|
|
42
|
+
{ id: 'wallet_action', label: 'Wallet Actions', description: 'Auto-approve wallet signatures and arbitrary transaction requests.', risk: 'very-high' },
|
|
37
43
|
{ id: 'task_tool', label: 'Task Tool Calls', description: 'Auto-approve task-level tool approvals.' },
|
|
38
44
|
]
|
|
39
45
|
|
|
@@ -174,31 +180,37 @@ export function ApprovalsPanel() {
|
|
|
174
180
|
label: 'Execution',
|
|
175
181
|
value: sortedExecApprovals.length,
|
|
176
182
|
tone: 'text-amber-400',
|
|
183
|
+
dotClass: 'bg-amber-400',
|
|
177
184
|
hint: 'Command approvals from OpenClaw',
|
|
178
185
|
},
|
|
179
186
|
{
|
|
180
187
|
label: 'Workflow',
|
|
181
188
|
value: sessionApprovals.length,
|
|
182
189
|
tone: 'text-sky-400',
|
|
190
|
+
dotClass: 'bg-sky-400',
|
|
183
191
|
hint: 'Agent and plugin governance requests',
|
|
184
192
|
},
|
|
185
193
|
{
|
|
186
194
|
label: 'Task Calls',
|
|
187
195
|
value: taskApprovals.length,
|
|
188
196
|
tone: 'text-violet-400',
|
|
197
|
+
dotClass: 'bg-violet-400',
|
|
189
198
|
hint: 'Tasks waiting on tool approval',
|
|
190
199
|
},
|
|
191
200
|
{
|
|
192
201
|
label: 'Recently Active',
|
|
193
202
|
value: workflowApprovals.filter((req) => now - req.updatedAt < 60 * 60 * 1000).length,
|
|
194
203
|
tone: 'text-emerald-400',
|
|
204
|
+
dotClass: 'bg-emerald-400',
|
|
195
205
|
hint: 'Updated in the last hour',
|
|
196
206
|
},
|
|
197
207
|
]
|
|
198
208
|
|
|
199
209
|
const autoApproved = useMemo(() => new Set(appSettings.approvalAutoApproveCategories || []), [appSettings.approvalAutoApproveCategories])
|
|
200
|
-
const approvalsEnabled = appSettings.approvalsEnabled ??
|
|
210
|
+
const approvalsEnabled = appSettings.approvalsEnabled ?? false
|
|
201
211
|
const outboundApprovalEnabled = appSettings.safetyRequireApprovalForOutbound ?? false
|
|
212
|
+
const autoApproveEnabledCount = autoApproved.size
|
|
213
|
+
const autoApproveManualCount = AUTO_APPROVE_OPTIONS.length - autoApproveEnabledCount
|
|
202
214
|
|
|
203
215
|
const saveApprovalSettings = async (patch: Partial<AppSettings>, successMessage: string, key: string) => {
|
|
204
216
|
try {
|
|
@@ -230,117 +242,181 @@ export function ApprovalsPanel() {
|
|
|
230
242
|
|
|
231
243
|
return (
|
|
232
244
|
<div className="flex-1 overflow-y-auto px-6 py-8">
|
|
233
|
-
<div className="max-w-
|
|
234
|
-
<div className="flex items-
|
|
245
|
+
<div className="max-w-5xl mx-auto space-y-6">
|
|
246
|
+
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
|
235
247
|
<div>
|
|
236
248
|
<h1 className="font-display text-[28px] font-700 tracking-[-0.03em] mb-1">Approvals</h1>
|
|
237
249
|
<p className="text-[13px] text-text-3">Execution, task, and governance requests queued for review</p>
|
|
238
250
|
</div>
|
|
239
|
-
<div className="
|
|
240
|
-
{
|
|
251
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
252
|
+
<div className={`px-3 py-1.5 rounded-full border text-[11px] font-700 ${
|
|
253
|
+
approvalsEnabled
|
|
254
|
+
? 'bg-amber-500/10 border-amber-500/20 text-amber-300'
|
|
255
|
+
: 'bg-emerald-500/10 border-emerald-500/20 text-emerald-300'
|
|
256
|
+
}`}>
|
|
257
|
+
{approvalsEnabled ? 'Manual approvals enabled' : 'Approvals auto-run'}
|
|
258
|
+
</div>
|
|
259
|
+
<div className="px-3 py-1.5 rounded-full bg-white/[0.04] border border-white/[0.06] text-text-2 text-[11px] font-600">
|
|
260
|
+
{pendingCount} pending
|
|
261
|
+
</div>
|
|
241
262
|
</div>
|
|
242
263
|
</div>
|
|
243
264
|
|
|
244
|
-
<div className="grid grid-cols-2
|
|
265
|
+
<div className="grid grid-cols-2 xl:grid-cols-4 gap-3">
|
|
245
266
|
{summaryCards.map((card) => (
|
|
246
|
-
<div key={card.label} className="rounded-[
|
|
267
|
+
<div key={card.label} className="relative overflow-hidden rounded-[16px] border border-white/[0.06] bg-white/[0.02] px-4 py-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]">
|
|
268
|
+
<div className="flex items-center justify-between gap-3">
|
|
269
|
+
<div className="text-[11px] font-700 uppercase tracking-[0.08em] text-text-3/65">{card.label}</div>
|
|
270
|
+
<div className={`h-2.5 w-2.5 rounded-full ${card.dotClass}`} />
|
|
271
|
+
</div>
|
|
247
272
|
<div className={`text-[22px] font-display font-700 tracking-[-0.03em] ${card.tone}`}>
|
|
248
273
|
{card.value}
|
|
249
274
|
</div>
|
|
250
|
-
<
|
|
251
|
-
<p className="text-[10px] text-text-3/50 mt-1 leading-relaxed">{card.hint}</p>
|
|
275
|
+
<p className="text-[10px] text-text-3/55 mt-1.5 leading-relaxed">{card.hint}</p>
|
|
252
276
|
</div>
|
|
253
277
|
))}
|
|
254
278
|
</div>
|
|
255
279
|
|
|
256
|
-
<div className="
|
|
257
|
-
<div className="
|
|
258
|
-
<div className="flex
|
|
280
|
+
<div className="grid gap-4 xl:grid-cols-[320px_minmax(0,1fr)]">
|
|
281
|
+
<div className="rounded-[18px] border border-white/[0.06] bg-white/[0.02] p-5 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]">
|
|
282
|
+
<div className="flex items-center justify-between gap-3 mb-4">
|
|
259
283
|
<div>
|
|
260
|
-
<
|
|
261
|
-
<
|
|
262
|
-
|
|
263
|
-
</
|
|
284
|
+
<div className="text-[11px] font-700 uppercase tracking-[0.08em] text-text-3/65">Approval Mode</div>
|
|
285
|
+
<div className="text-[16px] font-display font-700 tracking-[-0.02em] text-text mt-1">
|
|
286
|
+
{approvalsEnabled ? 'Manual review queue' : 'Auto-run workflow mode'}
|
|
287
|
+
</div>
|
|
264
288
|
</div>
|
|
265
|
-
<div className={`px-
|
|
289
|
+
<div className={`px-2.5 py-1 rounded-full text-[10px] font-700 border ${
|
|
266
290
|
approvalsEnabled
|
|
267
|
-
? 'bg-amber-500/10 border
|
|
268
|
-
: 'bg-emerald-500/10 border
|
|
291
|
+
? 'bg-amber-500/10 border-amber-500/20 text-amber-300'
|
|
292
|
+
: 'bg-emerald-500/10 border-emerald-500/20 text-emerald-300'
|
|
269
293
|
}`}>
|
|
270
|
-
{approvalsEnabled ? '
|
|
294
|
+
{approvalsEnabled ? 'On' : 'Off'}
|
|
271
295
|
</div>
|
|
272
296
|
</div>
|
|
297
|
+
<p className="text-[12px] text-text-3/70 leading-relaxed">
|
|
298
|
+
{approvalsEnabled
|
|
299
|
+
? 'Requests pause here until someone approves or rejects them. Auto-approve lets you carve out safe request classes without disabling oversight entirely.'
|
|
300
|
+
: 'Workflow approvals will auto-run by default. Use outbound and category-specific controls below to keep higher-risk actions gated.'}
|
|
301
|
+
</p>
|
|
302
|
+
<div className="grid grid-cols-1 gap-2 mt-5">
|
|
303
|
+
<div className="rounded-[12px] border border-white/[0.06] bg-black/20 px-3.5 py-3">
|
|
304
|
+
<div className="text-[10px] font-700 uppercase tracking-[0.08em] text-text-3/55">Queue</div>
|
|
305
|
+
<div className="mt-1 flex items-center justify-between gap-3">
|
|
306
|
+
<span className="text-[13px] font-600 text-text-2">Pending right now</span>
|
|
307
|
+
<span className="text-[13px] font-700 text-text">{pendingCount}</span>
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
<div className="rounded-[12px] border border-white/[0.06] bg-black/20 px-3.5 py-3">
|
|
311
|
+
<div className="text-[10px] font-700 uppercase tracking-[0.08em] text-text-3/55">Auto-Approve</div>
|
|
312
|
+
<div className="mt-1 flex items-center justify-between gap-3">
|
|
313
|
+
<span className="text-[13px] font-600 text-text-2">Categories enabled</span>
|
|
314
|
+
<span className="text-[13px] font-700 text-text">{autoApproveEnabledCount}</span>
|
|
315
|
+
</div>
|
|
316
|
+
<div className="text-[11px] text-text-3/55 mt-1">{autoApproveManualCount} still require manual review</div>
|
|
317
|
+
</div>
|
|
318
|
+
<div className="rounded-[12px] border border-white/[0.06] bg-black/20 px-3.5 py-3">
|
|
319
|
+
<div className="text-[10px] font-700 uppercase tracking-[0.08em] text-text-3/55">Outbound Sends</div>
|
|
320
|
+
<div className="mt-1 flex items-center justify-between gap-3">
|
|
321
|
+
<span className="text-[13px] font-600 text-text-2">Connector message sends</span>
|
|
322
|
+
<span className={`text-[11px] font-700 ${outboundApprovalEnabled ? 'text-amber-300' : 'text-emerald-300'}`}>
|
|
323
|
+
{outboundApprovalEnabled ? 'Needs approval' : 'Direct send'}
|
|
324
|
+
</span>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
</div>
|
|
273
329
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
</div>
|
|
283
|
-
<button
|
|
284
|
-
type="button"
|
|
285
|
-
disabled={savingSetting === 'approvalsEnabled'}
|
|
286
|
-
onClick={() => {
|
|
287
|
-
const next = !approvalsEnabled
|
|
288
|
-
void saveApprovalSettings(
|
|
289
|
-
{ approvalsEnabled: next },
|
|
290
|
-
next ? 'Platform approvals enabled' : 'Platform approvals disabled',
|
|
291
|
-
'approvalsEnabled',
|
|
292
|
-
)
|
|
293
|
-
}}
|
|
294
|
-
className={`relative w-10 h-[22px] rounded-full transition-colors duration-200 cursor-pointer disabled:opacity-50 ${approvalsEnabled ? 'bg-accent' : 'bg-white/[0.12]'}`}
|
|
295
|
-
aria-label="Toggle platform approvals"
|
|
296
|
-
>
|
|
297
|
-
<span className={`absolute top-[3px] left-[3px] w-4 h-4 rounded-full bg-white transition-transform duration-200 ${approvalsEnabled ? 'translate-x-[18px]' : ''}`} />
|
|
298
|
-
</button>
|
|
330
|
+
<div className="rounded-[18px] border border-white/[0.06] bg-white/[0.02] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]">
|
|
331
|
+
<div className="flex flex-col gap-4">
|
|
332
|
+
<div className="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-3">
|
|
333
|
+
<div>
|
|
334
|
+
<h2 className="text-[13px] font-700 text-text">Approval Controls</h2>
|
|
335
|
+
<p className="text-[12px] text-text-3/70 mt-1 max-w-[640px]">
|
|
336
|
+
Control whether actions queue for review, which approval types auto-run, and whether outbound connector sends need explicit confirmation.
|
|
337
|
+
</p>
|
|
299
338
|
</div>
|
|
300
339
|
</div>
|
|
301
340
|
|
|
302
|
-
<div className="
|
|
303
|
-
<div className="
|
|
304
|
-
<div>
|
|
305
|
-
<div
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
341
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
342
|
+
<div className="rounded-[14px] border border-white/[0.06] bg-black/20 px-4 py-4">
|
|
343
|
+
<div className="flex items-center justify-between gap-4">
|
|
344
|
+
<div>
|
|
345
|
+
<div className="text-[12px] font-600 text-text-2">Platform Approvals</div>
|
|
346
|
+
<p className="text-[11px] text-text-3/60 mt-1 leading-relaxed">
|
|
347
|
+
Turn this off to auto-approve workflow approvals across the app. Audit records are still kept.
|
|
348
|
+
</p>
|
|
349
|
+
</div>
|
|
350
|
+
<button
|
|
351
|
+
type="button"
|
|
352
|
+
disabled={savingSetting === 'approvalsEnabled'}
|
|
353
|
+
onClick={() => {
|
|
354
|
+
const next = !approvalsEnabled
|
|
355
|
+
void saveApprovalSettings(
|
|
356
|
+
{ approvalsEnabled: next },
|
|
357
|
+
next ? 'Platform approvals enabled' : 'Platform approvals disabled',
|
|
358
|
+
'approvalsEnabled',
|
|
359
|
+
)
|
|
360
|
+
}}
|
|
361
|
+
className={`inline-flex h-[22px] w-10 shrink-0 items-center rounded-full border border-white/[0.08] p-[3px] transition-colors duration-200 cursor-pointer disabled:opacity-50 ${
|
|
362
|
+
approvalsEnabled ? 'justify-end bg-accent' : 'justify-start bg-white/[0.16]'
|
|
363
|
+
}`}
|
|
364
|
+
aria-label="Toggle platform approvals"
|
|
365
|
+
>
|
|
366
|
+
<span className="h-4 w-4 rounded-full bg-white shadow-[0_1px_4px_rgba(0,0,0,0.35)]" />
|
|
367
|
+
</button>
|
|
309
368
|
</div>
|
|
310
|
-
<button
|
|
311
|
-
type="button"
|
|
312
|
-
disabled={savingSetting === 'safetyRequireApprovalForOutbound'}
|
|
313
|
-
onClick={() => {
|
|
314
|
-
const next = !outboundApprovalEnabled
|
|
315
|
-
void saveApprovalSettings(
|
|
316
|
-
{ safetyRequireApprovalForOutbound: next },
|
|
317
|
-
next ? 'Outbound send approvals enabled' : 'Outbound send approvals disabled',
|
|
318
|
-
'safetyRequireApprovalForOutbound',
|
|
319
|
-
)
|
|
320
|
-
}}
|
|
321
|
-
className={`relative w-10 h-[22px] rounded-full transition-colors duration-200 cursor-pointer disabled:opacity-50 ${outboundApprovalEnabled ? 'bg-accent' : 'bg-white/[0.12]'}`}
|
|
322
|
-
aria-label="Toggle outbound send approvals"
|
|
323
|
-
>
|
|
324
|
-
<span className={`absolute top-[3px] left-[3px] w-4 h-4 rounded-full bg-white transition-transform duration-200 ${outboundApprovalEnabled ? 'translate-x-[18px]' : ''}`} />
|
|
325
|
-
</button>
|
|
326
369
|
</div>
|
|
327
|
-
</div>
|
|
328
|
-
</div>
|
|
329
370
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
371
|
+
<div className="rounded-[14px] border border-white/[0.06] bg-black/20 px-4 py-4">
|
|
372
|
+
<div className="flex items-center justify-between gap-4">
|
|
373
|
+
<div>
|
|
374
|
+
<div className="text-[12px] font-600 text-text-2">Outbound Send Approvals</div>
|
|
375
|
+
<p className="text-[11px] text-text-3/60 mt-1 leading-relaxed">
|
|
376
|
+
Require explicit approval before agents send messages or media over connectors.
|
|
377
|
+
</p>
|
|
378
|
+
</div>
|
|
379
|
+
<button
|
|
380
|
+
type="button"
|
|
381
|
+
disabled={savingSetting === 'safetyRequireApprovalForOutbound'}
|
|
382
|
+
onClick={() => {
|
|
383
|
+
const next = !outboundApprovalEnabled
|
|
384
|
+
void saveApprovalSettings(
|
|
385
|
+
{ safetyRequireApprovalForOutbound: next },
|
|
386
|
+
next ? 'Outbound send approvals enabled' : 'Outbound send approvals disabled',
|
|
387
|
+
'safetyRequireApprovalForOutbound',
|
|
388
|
+
)
|
|
389
|
+
}}
|
|
390
|
+
className={`inline-flex h-[22px] w-10 shrink-0 items-center rounded-full border border-white/[0.08] p-[3px] transition-colors duration-200 cursor-pointer disabled:opacity-50 ${
|
|
391
|
+
outboundApprovalEnabled ? 'justify-end bg-accent' : 'justify-start bg-white/[0.16]'
|
|
392
|
+
}`}
|
|
393
|
+
aria-label="Toggle outbound send approvals"
|
|
394
|
+
>
|
|
395
|
+
<span className="h-4 w-4 rounded-full bg-white shadow-[0_1px_4px_rgba(0,0,0,0.35)]" />
|
|
396
|
+
</button>
|
|
397
|
+
</div>
|
|
335
398
|
</div>
|
|
336
399
|
</div>
|
|
337
|
-
|
|
400
|
+
|
|
401
|
+
<div>
|
|
402
|
+
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 mb-3">
|
|
403
|
+
<div>
|
|
404
|
+
<div className="text-[12px] font-600 text-text-2">Auto-Approve Categories</div>
|
|
405
|
+
<p className="text-[11px] text-text-3/60 mt-1">
|
|
406
|
+
Keep the approval system on, but let low-friction request types flow through automatically.
|
|
407
|
+
</p>
|
|
408
|
+
</div>
|
|
409
|
+
<div className="text-[11px] text-text-3/60">
|
|
410
|
+
{autoApproveEnabledCount} enabled
|
|
411
|
+
</div>
|
|
412
|
+
</div>
|
|
413
|
+
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-2">
|
|
338
414
|
{AUTO_APPROVE_OPTIONS.map((option) => {
|
|
339
415
|
const checked = autoApproved.has(option.id)
|
|
340
416
|
return (
|
|
341
417
|
<label
|
|
342
418
|
key={option.id}
|
|
343
|
-
className={`rounded-[
|
|
419
|
+
className={`rounded-[14px] border px-3 py-3 cursor-pointer transition-all ${
|
|
344
420
|
checked
|
|
345
421
|
? 'border-accent-bright/30 bg-accent-soft/60'
|
|
346
422
|
: 'border-white/[0.06] bg-black/20 hover:bg-white/[0.04]'
|
|
@@ -364,24 +440,35 @@ export function ApprovalsPanel() {
|
|
|
364
440
|
className="mt-0.5"
|
|
365
441
|
/>
|
|
366
442
|
<div>
|
|
367
|
-
<div className="
|
|
443
|
+
<div className="flex items-center gap-2 flex-wrap">
|
|
444
|
+
<div className="text-[12px] font-600 text-text-2">{option.label}</div>
|
|
445
|
+
{option.risk && (
|
|
446
|
+
<span className={`px-1.5 py-0.5 rounded-full text-[9px] font-700 uppercase tracking-[0.08em] ${
|
|
447
|
+
option.risk === 'very-high'
|
|
448
|
+
? 'bg-red-500/10 text-red-300 border border-red-500/20'
|
|
449
|
+
: 'bg-amber-500/10 text-amber-300 border border-amber-500/20'
|
|
450
|
+
}`}>
|
|
451
|
+
{option.risk === 'very-high' ? 'Very high risk' : 'High risk'}
|
|
452
|
+
</span>
|
|
453
|
+
)}
|
|
454
|
+
</div>
|
|
368
455
|
<p className="text-[11px] text-text-3/60 mt-1 leading-relaxed">{option.description}</p>
|
|
369
456
|
</div>
|
|
370
457
|
</div>
|
|
371
458
|
</label>
|
|
372
459
|
)
|
|
373
460
|
})}
|
|
461
|
+
</div>
|
|
374
462
|
</div>
|
|
375
|
-
<p className="text-[11px] text-text-3/60 mt-2">
|
|
376
|
-
Use category auto-approval when you still want the approval system on, but you do not want these request types to pause execution.
|
|
377
|
-
</p>
|
|
378
463
|
</div>
|
|
379
464
|
</div>
|
|
380
465
|
</div>
|
|
381
466
|
|
|
382
|
-
<div className="rounded-[
|
|
383
|
-
<div className="flex flex-col lg:flex-row
|
|
384
|
-
<div className="flex
|
|
467
|
+
<div className="rounded-[18px] border border-white/[0.06] bg-white/[0.02] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]">
|
|
468
|
+
<div className="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
|
|
469
|
+
<div className="flex-1">
|
|
470
|
+
<div className="text-[11px] font-700 uppercase tracking-[0.08em] text-text-3/60 mb-2">Queue Filters</div>
|
|
471
|
+
<div className="flex flex-wrap gap-2">
|
|
385
472
|
{([
|
|
386
473
|
['all', `All (${pendingCount})`],
|
|
387
474
|
['execution', `Execution (${sortedExecApprovals.length})`],
|
|
@@ -401,10 +488,11 @@ export function ApprovalsPanel() {
|
|
|
401
488
|
{label}
|
|
402
489
|
</button>
|
|
403
490
|
))}
|
|
491
|
+
</div>
|
|
404
492
|
</div>
|
|
405
493
|
|
|
406
|
-
<div className="flex items-center gap-2">
|
|
407
|
-
<div className="text-[11px] text-text-3/60 font-600">
|
|
494
|
+
<div className="flex items-center gap-2 justify-between lg:justify-end">
|
|
495
|
+
<div className="text-[11px] text-text-3/60 font-600 whitespace-nowrap">
|
|
408
496
|
Showing {visibleCount} of {pendingCount}
|
|
409
497
|
</div>
|
|
410
498
|
{workflowCategories.length > 1 && scope !== 'execution' && (
|
|
@@ -425,7 +513,7 @@ export function ApprovalsPanel() {
|
|
|
425
513
|
</div>
|
|
426
514
|
</div>
|
|
427
515
|
|
|
428
|
-
<div className="mt-
|
|
516
|
+
<div className="mt-1">
|
|
429
517
|
<input
|
|
430
518
|
value={search}
|
|
431
519
|
onChange={(e) => setSearch(e.target.value)}
|
|
@@ -437,7 +525,7 @@ export function ApprovalsPanel() {
|
|
|
437
525
|
</div>
|
|
438
526
|
|
|
439
527
|
{filteredExecApprovals.length > 0 && (
|
|
440
|
-
<div
|
|
528
|
+
<div>
|
|
441
529
|
<h2 className="text-[12px] font-700 uppercase tracking-[0.1em] text-amber-400/90 mb-2">Execution Approvals</h2>
|
|
442
530
|
<div className="grid grid-cols-1 gap-3">
|
|
443
531
|
{filteredExecApprovals.map((approval) => (
|
|
@@ -548,26 +636,34 @@ export function ApprovalsPanel() {
|
|
|
548
636
|
)}
|
|
549
637
|
|
|
550
638
|
{visibleCount === 0 && pendingCount > 0 && (
|
|
551
|
-
<div className="rounded-[
|
|
639
|
+
<div className="rounded-[18px] border border-dashed border-white/[0.08] bg-white/[0.015] px-6 py-10 text-center">
|
|
552
640
|
<p className="text-[13px] font-600 text-text-2 mb-1">No approvals match the current filters</p>
|
|
553
641
|
<p className="text-[12px] text-text-3/60">Try clearing the search or switching the queue scope.</p>
|
|
554
642
|
</div>
|
|
555
643
|
)}
|
|
556
644
|
|
|
557
645
|
{pendingCount === 0 && (
|
|
558
|
-
<div className="
|
|
559
|
-
<div className="w-16 h-16 rounded-[24px] bg-white/[0.02] border border-white/[0.04] flex items-center justify-center mb-6">
|
|
646
|
+
<div className="rounded-[20px] border border-white/[0.06] bg-white/[0.02] px-8 py-12 text-center shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]">
|
|
647
|
+
<div className="w-16 h-16 rounded-[24px] bg-white/[0.02] border border-white/[0.04] flex items-center justify-center mx-auto mb-6">
|
|
560
648
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" className="text-text-3/40">
|
|
561
649
|
<path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"/>
|
|
562
650
|
<path d="m9 12 2 2 4-4"/>
|
|
563
651
|
</svg>
|
|
564
652
|
</div>
|
|
565
|
-
<h2 className="font-display text-[
|
|
566
|
-
<p className="text-[13px] text-text-3/60 max-w-[
|
|
653
|
+
<h2 className="font-display text-[20px] font-600 text-text-2 mb-2">No pending approvals</h2>
|
|
654
|
+
<p className="text-[13px] text-text-3/60 max-w-[420px] mx-auto">
|
|
567
655
|
{approvalsEnabled
|
|
568
656
|
? 'Your swarm is operating autonomously. Actions requiring oversight will appear here.'
|
|
569
657
|
: 'Approvals are currently disabled, so eligible requests will auto-run instead of queuing here.'}
|
|
570
658
|
</p>
|
|
659
|
+
<div className={`inline-flex items-center gap-2 mt-5 px-3 py-1.5 rounded-full border text-[11px] font-700 ${
|
|
660
|
+
approvalsEnabled
|
|
661
|
+
? 'bg-amber-500/10 border-amber-500/20 text-amber-300'
|
|
662
|
+
: 'bg-emerald-500/10 border-emerald-500/20 text-emerald-300'
|
|
663
|
+
}`}>
|
|
664
|
+
<span className={`w-2 h-2 rounded-full ${approvalsEnabled ? 'bg-amber-300' : 'bg-emerald-300'}`} />
|
|
665
|
+
{approvalsEnabled ? 'Manual approvals active' : 'Workflow approvals auto-run'}
|
|
666
|
+
</div>
|
|
571
667
|
</div>
|
|
572
668
|
)}
|
|
573
669
|
</div>
|