@swarmclawai/swarmclaw 0.7.7 → 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 -14
- 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 +23 -2
- package/src/app/api/clawhub/install/route.ts +28 -8
- package/src/app/api/connectors/[id]/route.ts +46 -3
- package/src/app/api/connectors/route.ts +12 -8
- 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/projects/[id]/route.ts +6 -2
- package/src/app/api/projects/route.ts +4 -3
- 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/secrets/[id]/route.ts +1 -0
- package/src/app/api/secrets/route.ts +2 -1
- package/src/app/api/settings/route.ts +2 -0
- 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 +257 -38
- package/src/components/agents/inspector-panel.tsx +41 -0
- package/src/components/canvas/canvas-panel.tsx +236 -65
- package/src/components/chat/chat-area.tsx +36 -19
- package/src/components/chat/chat-card.tsx +36 -13
- package/src/components/chat/chat-header.tsx +48 -16
- package/src/components/chat/chat-list.tsx +28 -4
- package/src/components/chat/checkpoint-timeline.tsx +50 -34
- package/src/components/chat/delegation-banner.test.ts +14 -1
- package/src/components/chat/delegation-banner.tsx +1 -1
- 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/layout/app-layout.tsx +40 -23
- 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/projects/project-detail.tsx +217 -0
- package/src/components/projects/project-sheet.tsx +176 -4
- 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 +45 -3
- package/src/components/shared/settings/section-voice.tsx +11 -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 +289 -34
- package/src/components/tasks/task-board.tsx +410 -25
- package/src/components/tasks/task-card.tsx +66 -8
- package/src/components/tasks/task-sheet.tsx +16 -4
- 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 +33 -0
- package/src/lib/server/capability-router.ts +80 -19
- 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 +378 -73
- package/src/lib/server/clawhub-client.test.ts +14 -8
- package/src/lib/server/connectors/manager-reconnect.test.ts +47 -0
- package/src/lib/server/connectors/manager.test.ts +1147 -0
- package/src/lib/server/connectors/manager.ts +461 -137
- 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 +84 -47
- 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 +247 -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 +20 -11
- 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/main-agent-loop.test.ts +260 -0
- package/src/lib/server/main-agent-loop.ts +559 -14
- 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 +3 -2
- package/src/lib/server/orchestrator.ts +2 -0
- package/src/lib/server/plugins-advanced.test.ts +351 -0
- package/src/lib/server/plugins.ts +211 -6
- package/src/lib/server/project-context.ts +162 -0
- package/src/lib/server/project-utils.ts +150 -0
- package/src/lib/server/queue-advanced.test.ts +528 -0
- package/src/lib/server/queue-followups.test.ts +409 -2
- package/src/lib/server/queue-reconcile.test.ts +128 -0
- package/src/lib/server/queue.ts +527 -68
- 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 +83 -4
- package/src/lib/server/session-tools/canvas.ts +14 -12
- package/src/lib/server/session-tools/connector-inputs.test.ts +37 -0
- package/src/lib/server/session-tools/connector.test.ts +138 -0
- package/src/lib/server/session-tools/connector.ts +366 -54
- package/src/lib/server/session-tools/context.ts +17 -3
- package/src/lib/server/session-tools/crud.ts +484 -84
- package/src/lib/server/session-tools/delegate-fallback.test.ts +103 -0
- package/src/lib/server/session-tools/delegate-resume.test.ts +50 -0
- package/src/lib/server/session-tools/delegate.ts +102 -10
- 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/manage-tasks.test.ts +114 -0
- package/src/lib/server/session-tools/memory.test.ts +93 -0
- package/src/lib/server/session-tools/memory.ts +554 -75
- package/src/lib/server/session-tools/normalize-tool-args.ts +1 -1
- package/src/lib/server/session-tools/platform-access.test.ts +58 -0
- package/src/lib/server/session-tools/platform.ts +60 -19
- 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 +178 -0
- package/src/lib/server/session-tools/web.ts +621 -70
- 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 +437 -2
- package/src/lib/server/stream-agent-chat.ts +957 -79
- package/src/lib/server/system-events.ts +1 -1
- package/src/lib/server/tool-aliases.ts +2 -0
- package/src/lib/server/tool-capability-policy-advanced.test.ts +502 -0
- package/src/lib/server/tool-capability-policy.test.ts +24 -0
- package/src/lib/server/tool-capability-policy.ts +29 -1
- 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.test.ts +44 -0
- package/src/lib/server/tool-planning.ts +271 -0
- 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-definitions.ts +2 -1
- 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 +249 -14
|
@@ -7,8 +7,10 @@ const APPROVAL_CATEGORY_OPTIONS: Array<{ id: ApprovalCategory; label: string; de
|
|
|
7
7
|
{ id: 'tool_access', label: 'Plugin Access', description: 'Auto-enable requested plugins for a chat.' },
|
|
8
8
|
{ id: 'plugin_scaffold', label: 'Plugin Scaffold', description: 'Auto-create plugin files requested by agents.' },
|
|
9
9
|
{ id: 'plugin_install', label: 'Plugin Install', description: 'Auto-install plugins from approved URLs.' },
|
|
10
|
+
{ id: 'connector_sender', label: 'Connector Senders', description: 'Auto-approve new connector senders and add them to the allowlist.' },
|
|
10
11
|
{ id: 'human_loop', label: 'Human Approval Requests', description: 'Auto-approve ask-human approval prompts.' },
|
|
11
12
|
{ id: 'wallet_transfer', label: 'Wallet Transfers', description: 'Auto-approve wallet send requests. High risk.' },
|
|
13
|
+
{ id: 'wallet_action', label: 'Wallet Actions', description: 'Auto-approve wallet signatures and arbitrary transaction requests. Very high risk.' },
|
|
12
14
|
{ id: 'task_tool', label: 'Task Tool Calls', description: 'Reserved for task-level approval flows.' },
|
|
13
15
|
]
|
|
14
16
|
|
|
@@ -46,6 +48,44 @@ export function CapabilityPolicySection({ appSettings, patchSettings, inputClass
|
|
|
46
48
|
</div>
|
|
47
49
|
|
|
48
50
|
<div className="grid grid-cols-1 gap-4">
|
|
51
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
52
|
+
<div className="rounded-[12px] border border-white/[0.06] bg-bg px-4 py-4">
|
|
53
|
+
<div className="flex items-center justify-between gap-4">
|
|
54
|
+
<div>
|
|
55
|
+
<div className="text-[12px] font-600 text-text-2">Task Management</div>
|
|
56
|
+
<p className="text-[11px] text-text-3/60 mt-1 leading-relaxed">
|
|
57
|
+
Controls the task board and agent access to durable backlog tracking. Internal queue execution still works underneath.
|
|
58
|
+
</p>
|
|
59
|
+
</div>
|
|
60
|
+
<button
|
|
61
|
+
onClick={() => patchSettings({ taskManagementEnabled: !(appSettings.taskManagementEnabled ?? true) })}
|
|
62
|
+
className={`relative w-10 h-[22px] rounded-full transition-colors duration-200 cursor-pointer ${(appSettings.taskManagementEnabled ?? true) ? 'bg-accent' : 'bg-white/[0.12]'}`}
|
|
63
|
+
aria-label="Toggle task management"
|
|
64
|
+
>
|
|
65
|
+
<span className={`absolute top-[3px] left-[3px] w-4 h-4 rounded-full bg-white transition-transform duration-200 ${(appSettings.taskManagementEnabled ?? true) ? 'translate-x-[18px]' : ''}`} />
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div className="rounded-[12px] border border-white/[0.06] bg-bg px-4 py-4">
|
|
71
|
+
<div className="flex items-center justify-between gap-4">
|
|
72
|
+
<div>
|
|
73
|
+
<div className="text-[12px] font-600 text-text-2">Project Management</div>
|
|
74
|
+
<p className="text-[11px] text-text-3/60 mt-1 leading-relaxed">
|
|
75
|
+
Controls the project operating-system UI and agent access to durable project context for objectives, credentials, and heartbeat plans.
|
|
76
|
+
</p>
|
|
77
|
+
</div>
|
|
78
|
+
<button
|
|
79
|
+
onClick={() => patchSettings({ projectManagementEnabled: !(appSettings.projectManagementEnabled ?? true) })}
|
|
80
|
+
className={`relative w-10 h-[22px] rounded-full transition-colors duration-200 cursor-pointer ${(appSettings.projectManagementEnabled ?? true) ? 'bg-accent' : 'bg-white/[0.12]'}`}
|
|
81
|
+
aria-label="Toggle project management"
|
|
82
|
+
>
|
|
83
|
+
<span className={`absolute top-[3px] left-[3px] w-4 h-4 rounded-full bg-white transition-transform duration-200 ${(appSettings.projectManagementEnabled ?? true) ? 'translate-x-[18px]' : ''}`} />
|
|
84
|
+
</button>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
49
89
|
<div className="rounded-[12px] border border-white/[0.06] bg-bg px-4 py-4">
|
|
50
90
|
<div className="flex items-center justify-between gap-4">
|
|
51
91
|
<div>
|
|
@@ -55,11 +95,13 @@ export function CapabilityPolicySection({ appSettings, patchSettings, inputClass
|
|
|
55
95
|
</p>
|
|
56
96
|
</div>
|
|
57
97
|
<button
|
|
58
|
-
onClick={() => patchSettings({ approvalsEnabled: !(appSettings.approvalsEnabled ??
|
|
59
|
-
className={`
|
|
98
|
+
onClick={() => patchSettings({ approvalsEnabled: !(appSettings.approvalsEnabled ?? false) })}
|
|
99
|
+
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 ${
|
|
100
|
+
(appSettings.approvalsEnabled ?? false) ? 'justify-end bg-accent' : 'justify-start bg-white/[0.16]'
|
|
101
|
+
}`}
|
|
60
102
|
aria-label="Toggle platform approvals"
|
|
61
103
|
>
|
|
62
|
-
<span className=
|
|
104
|
+
<span className="h-4 w-4 rounded-full bg-white shadow-[0_1px_4px_rgba(0,0,0,0.35)]" />
|
|
63
105
|
</button>
|
|
64
106
|
</div>
|
|
65
107
|
</div>
|
|
@@ -5,6 +5,8 @@ import type { SettingsSectionProps } from './types'
|
|
|
5
5
|
export function VoiceSection({ appSettings, patchSettings, inputClass }: SettingsSectionProps) {
|
|
6
6
|
const enabled = appSettings.elevenLabsEnabled ?? false
|
|
7
7
|
const hasApiKey = appSettings.elevenLabsApiKeyConfigured === true
|
|
8
|
+
const defaultVoiceId = typeof appSettings.elevenLabsVoiceId === 'string' ? appSettings.elevenLabsVoiceId.trim() : ''
|
|
9
|
+
const showVoiceConfig = enabled || hasApiKey || Boolean(defaultVoiceId)
|
|
8
10
|
|
|
9
11
|
return (
|
|
10
12
|
<div className="mb-10">
|
|
@@ -12,7 +14,7 @@ export function VoiceSection({ appSettings, patchSettings, inputClass }: Setting
|
|
|
12
14
|
Voice
|
|
13
15
|
</h3>
|
|
14
16
|
<p className="text-[12px] text-text-3 mb-5">
|
|
15
|
-
Configure voice playback (TTS) and speech-to-text input.
|
|
17
|
+
Configure voice playback (TTS), the default ElevenLabs voice, and speech-to-text input.
|
|
16
18
|
</p>
|
|
17
19
|
<div className="p-6 rounded-[18px] bg-surface border border-white/[0.06]">
|
|
18
20
|
{/* ElevenLabs toggle */}
|
|
@@ -30,7 +32,7 @@ export function VoiceSection({ appSettings, patchSettings, inputClass }: Setting
|
|
|
30
32
|
</button>
|
|
31
33
|
</div>
|
|
32
34
|
|
|
33
|
-
{
|
|
35
|
+
{showVoiceConfig && (
|
|
34
36
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 mb-5">
|
|
35
37
|
<div>
|
|
36
38
|
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">API Key</label>
|
|
@@ -56,11 +58,17 @@ export function VoiceSection({ appSettings, patchSettings, inputClass }: Setting
|
|
|
56
58
|
className={inputClass}
|
|
57
59
|
style={{ fontFamily: 'inherit' }}
|
|
58
60
|
/>
|
|
59
|
-
<p className="text-[11px] text-text-3/60 mt-1.5">Fallback voice when an agent has no override set.</p>
|
|
61
|
+
<p className="text-[11px] text-text-3/60 mt-1.5">Fallback voice when an agent has no override set. Agents can override this in their own create/edit sheet.</p>
|
|
60
62
|
</div>
|
|
61
63
|
</div>
|
|
62
64
|
)}
|
|
63
65
|
|
|
66
|
+
{showVoiceConfig && !enabled && (
|
|
67
|
+
<p className="mb-5 rounded-[12px] border border-white/[0.06] bg-white/[0.03] px-3 py-2.5 text-[11px] text-text-3/70">
|
|
68
|
+
ElevenLabs credentials and default voice can be prepared here even while playback is turned off.
|
|
69
|
+
</p>
|
|
70
|
+
)}
|
|
71
|
+
|
|
64
72
|
<div>
|
|
65
73
|
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Speech Recognition Language</label>
|
|
66
74
|
<input
|
|
@@ -275,6 +275,14 @@ export function SkillList({ inSidebar }: { inSidebar?: boolean }) {
|
|
|
275
275
|
const scopedAgents = skillScope === 'agent'
|
|
276
276
|
? skillAgentIds.map((id) => agents[id]).filter(Boolean)
|
|
277
277
|
: []
|
|
278
|
+
const securityTone = skill.security?.level === 'high'
|
|
279
|
+
? 'bg-red-500/10 text-red-300 border-red-500/20'
|
|
280
|
+
: skill.security?.level === 'medium'
|
|
281
|
+
? 'bg-amber-500/10 text-amber-300 border-amber-500/20'
|
|
282
|
+
: 'bg-emerald-500/10 text-emerald-300 border-emerald-500/20'
|
|
283
|
+
const requirementCount = (skill.skillRequirements?.env?.length || 0)
|
|
284
|
+
+ (skill.skillRequirements?.bins?.length || 0)
|
|
285
|
+
+ (skill.skillRequirements?.config?.length || 0)
|
|
278
286
|
return (
|
|
279
287
|
<div
|
|
280
288
|
key={skill.id}
|
|
@@ -315,6 +323,23 @@ export function SkillList({ inSidebar }: { inSidebar?: boolean }) {
|
|
|
315
323
|
{skill.description && (
|
|
316
324
|
<p className="text-[12px] text-text-3/60 line-clamp-2">{skill.description}</p>
|
|
317
325
|
)}
|
|
326
|
+
<div className="mt-2 flex flex-wrap gap-1.5">
|
|
327
|
+
{skill.version && (
|
|
328
|
+
<span className="rounded-full border border-white/[0.08] px-2 py-1 text-[10px] font-700 text-text-3/70">
|
|
329
|
+
v{skill.version}
|
|
330
|
+
</span>
|
|
331
|
+
)}
|
|
332
|
+
{typeof requirementCount === 'number' && requirementCount > 0 && (
|
|
333
|
+
<span className="rounded-full border border-white/[0.08] px-2 py-1 text-[10px] font-700 text-text-3/70">
|
|
334
|
+
{requirementCount} reqs
|
|
335
|
+
</span>
|
|
336
|
+
)}
|
|
337
|
+
{skill.security && (
|
|
338
|
+
<span className={`rounded-full border px-2 py-1 text-[10px] font-700 uppercase tracking-[0.08em] ${securityTone}`}>
|
|
339
|
+
{skill.security.level}
|
|
340
|
+
</span>
|
|
341
|
+
)}
|
|
342
|
+
</div>
|
|
318
343
|
<div className="flex items-center gap-2 mt-1.5">
|
|
319
344
|
<span className="text-[11px] text-text-3/70">{skill.content.length} chars</span>
|
|
320
345
|
<span className="text-[11px] text-text-3/60">·</span>
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { useEffect, useState, useRef } from 'react'
|
|
3
|
+
import { useEffect, useState, useRef, type ChangeEvent } from 'react'
|
|
4
4
|
import { useAppStore } from '@/stores/use-app-store'
|
|
5
5
|
import { BottomSheet } from '@/components/shared/bottom-sheet'
|
|
6
|
+
import { ConfirmDialog } from '@/components/shared/confirm-dialog'
|
|
6
7
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
7
8
|
import { api } from '@/lib/api-client'
|
|
9
|
+
import { buildSkillSavePayload } from '@/lib/skill-save-payload'
|
|
8
10
|
import { toast } from 'sonner'
|
|
11
|
+
import type { Skill, SkillSecuritySummary } from '@/types'
|
|
9
12
|
|
|
10
13
|
export function SkillSheet() {
|
|
11
14
|
const open = useAppStore((s) => s.skillSheetOpen)
|
|
@@ -28,6 +31,9 @@ export function SkillSheet() {
|
|
|
28
31
|
const [importingUrl, setImportingUrl] = useState(false)
|
|
29
32
|
const [importError, setImportError] = useState('')
|
|
30
33
|
const [importNotice, setImportNotice] = useState('')
|
|
34
|
+
const [metadataPreview, setMetadataPreview] = useState<Partial<Skill> | null>(null)
|
|
35
|
+
const [confirmDelete, setConfirmDelete] = useState(false)
|
|
36
|
+
const [deleting, setDeleting] = useState(false)
|
|
31
37
|
|
|
32
38
|
const editing = editingId ? skills[editingId] : null
|
|
33
39
|
const agentList = Object.values(agents)
|
|
@@ -38,13 +44,14 @@ export function SkillSheet() {
|
|
|
38
44
|
setImportError('')
|
|
39
45
|
setImportNotice('')
|
|
40
46
|
try {
|
|
41
|
-
const result = await api<{ name: string; filename: string; description?: string; content: string; sourceFormat?: 'openclaw' | 'plain' }>('POST', '/skills/import', { url: importUrl.trim() })
|
|
47
|
+
const result = await api<Partial<Skill> & { name: string; filename: string; description?: string; content: string; sourceFormat?: 'openclaw' | 'plain' }>('POST', '/skills/import', { url: importUrl.trim() })
|
|
42
48
|
setName(result.name || '')
|
|
43
49
|
setFilename(result.filename || '')
|
|
44
50
|
setDescription(result.description || '')
|
|
45
51
|
setContent(result.content || '')
|
|
52
|
+
setMetadataPreview(result)
|
|
46
53
|
if (result.sourceFormat === 'openclaw') {
|
|
47
|
-
setImportNotice(
|
|
54
|
+
setImportNotice(`Imported OpenClaw SKILL.md format.${result.security ? ` Security review: ${result.security.level}.` : ''}`)
|
|
48
55
|
} else {
|
|
49
56
|
setImportNotice('Skill imported from URL.')
|
|
50
57
|
}
|
|
@@ -73,6 +80,7 @@ export function SkillSheet() {
|
|
|
73
80
|
setContent(editing.content)
|
|
74
81
|
setScope(editing.scope || 'global')
|
|
75
82
|
setAgentIds(editing.agentIds || [])
|
|
83
|
+
setMetadataPreview(editing)
|
|
76
84
|
} else {
|
|
77
85
|
setName('')
|
|
78
86
|
setFilename('')
|
|
@@ -80,16 +88,19 @@ export function SkillSheet() {
|
|
|
80
88
|
setContent('')
|
|
81
89
|
setScope('global')
|
|
82
90
|
setAgentIds([])
|
|
91
|
+
setMetadataPreview(null)
|
|
83
92
|
}
|
|
84
93
|
}
|
|
85
94
|
}, [open, editingId])
|
|
86
95
|
|
|
87
96
|
const onClose = () => {
|
|
97
|
+
setConfirmDelete(false)
|
|
98
|
+
setDeleting(false)
|
|
88
99
|
setOpen(false)
|
|
89
100
|
setEditingId(null)
|
|
90
101
|
}
|
|
91
102
|
|
|
92
|
-
const handleFileUpload = (e:
|
|
103
|
+
const handleFileUpload = (e: ChangeEvent<HTMLInputElement>) => {
|
|
93
104
|
const file = e.target.files?.[0]
|
|
94
105
|
if (!file) return
|
|
95
106
|
const reader = new FileReader()
|
|
@@ -114,14 +125,14 @@ export function SkillSheet() {
|
|
|
114
125
|
: `${agentIds.length} agent(s) selected`
|
|
115
126
|
|
|
116
127
|
const handleSave = async () => {
|
|
117
|
-
const data = {
|
|
118
|
-
name
|
|
119
|
-
filename
|
|
128
|
+
const data = buildSkillSavePayload({
|
|
129
|
+
name,
|
|
130
|
+
filename,
|
|
120
131
|
description,
|
|
121
132
|
content,
|
|
122
133
|
scope,
|
|
123
|
-
agentIds
|
|
124
|
-
}
|
|
134
|
+
agentIds,
|
|
135
|
+
}, metadataPreview)
|
|
125
136
|
try {
|
|
126
137
|
if (editing) {
|
|
127
138
|
await api('PUT', `/skills/${editing.id}`, data)
|
|
@@ -139,19 +150,25 @@ export function SkillSheet() {
|
|
|
139
150
|
|
|
140
151
|
const handleDelete = async () => {
|
|
141
152
|
if (!editing) return
|
|
142
|
-
|
|
143
|
-
|
|
153
|
+
setDeleting(true)
|
|
144
154
|
try {
|
|
145
155
|
await api('DELETE', `/skills/${editing.id}`)
|
|
146
156
|
toast.success('Skill deleted')
|
|
147
157
|
await loadSkills()
|
|
158
|
+
setConfirmDelete(false)
|
|
148
159
|
onClose()
|
|
149
160
|
} catch (err: unknown) {
|
|
150
161
|
toast.error(err instanceof Error ? err.message : 'Failed to delete skill')
|
|
162
|
+
} finally {
|
|
163
|
+
setDeleting(false)
|
|
151
164
|
}
|
|
152
165
|
}
|
|
153
166
|
|
|
154
167
|
const inputClass = "w-full px-4 py-3.5 rounded-[14px] border border-white/[0.08] bg-surface text-text text-[15px] outline-none transition-all duration-200 placeholder:text-text-3/50 focus-glow"
|
|
168
|
+
const previewSecurity = metadataPreview?.security as SkillSecuritySummary | undefined
|
|
169
|
+
const requirementCount = (metadataPreview?.skillRequirements?.env?.length || 0)
|
|
170
|
+
+ (metadataPreview?.skillRequirements?.bins?.length || 0)
|
|
171
|
+
+ (metadataPreview?.skillRequirements?.config?.length || 0)
|
|
155
172
|
|
|
156
173
|
return (
|
|
157
174
|
<BottomSheet open={open} onClose={onClose} wide>
|
|
@@ -206,6 +223,50 @@ export function SkillSheet() {
|
|
|
206
223
|
</div>
|
|
207
224
|
)}
|
|
208
225
|
|
|
226
|
+
{metadataPreview && (
|
|
227
|
+
<div className="mb-8 rounded-[14px] border border-white/[0.08] bg-white/[0.03] p-4">
|
|
228
|
+
<div className="flex items-center justify-between gap-3">
|
|
229
|
+
<div>
|
|
230
|
+
<div className="text-[11px] font-700 uppercase tracking-[0.08em] text-text-3/60">Skill Metadata</div>
|
|
231
|
+
<p className="mt-1 text-[13px] text-text-2">
|
|
232
|
+
{metadataPreview.version ? `v${metadataPreview.version}` : 'Unversioned'}
|
|
233
|
+
{metadataPreview.sourceFormat ? ` · ${metadataPreview.sourceFormat}` : ''}
|
|
234
|
+
{requirementCount > 0 ? ` · ${requirementCount} declared requirement${requirementCount === 1 ? '' : 's'}` : ''}
|
|
235
|
+
</p>
|
|
236
|
+
</div>
|
|
237
|
+
{previewSecurity && (
|
|
238
|
+
<span className={`rounded-full px-2.5 py-1 text-[10px] font-700 uppercase tracking-[0.08em] ${
|
|
239
|
+
previewSecurity.level === 'high'
|
|
240
|
+
? 'bg-red-500/10 text-red-300 border border-red-500/20'
|
|
241
|
+
: previewSecurity.level === 'medium'
|
|
242
|
+
? 'bg-amber-500/10 text-amber-300 border border-amber-500/20'
|
|
243
|
+
: 'bg-emerald-500/10 text-emerald-300 border border-emerald-500/20'
|
|
244
|
+
}`}>
|
|
245
|
+
{previewSecurity.level} risk
|
|
246
|
+
</span>
|
|
247
|
+
)}
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
{(metadataPreview.primaryEnv || metadataPreview.homepage || metadataPreview.skillKey) && (
|
|
251
|
+
<div className="mt-3 flex flex-wrap gap-2 text-[11px] text-text-3/70">
|
|
252
|
+
{metadataPreview.primaryEnv && <span className="rounded-full border border-white/[0.08] px-2 py-1">Primary env: {metadataPreview.primaryEnv}</span>}
|
|
253
|
+
{metadataPreview.skillKey && <span className="rounded-full border border-white/[0.08] px-2 py-1">Skill key: {metadataPreview.skillKey}</span>}
|
|
254
|
+
{metadataPreview.homepage && <span className="rounded-full border border-white/[0.08] px-2 py-1">Homepage linked</span>}
|
|
255
|
+
</div>
|
|
256
|
+
)}
|
|
257
|
+
|
|
258
|
+
{previewSecurity?.notes?.length ? (
|
|
259
|
+
<div className="mt-3 space-y-1">
|
|
260
|
+
{previewSecurity.notes.slice(0, 4).map((note) => (
|
|
261
|
+
<p key={note} className="text-[12px] text-text-3/75">- {note}</p>
|
|
262
|
+
))}
|
|
263
|
+
</div>
|
|
264
|
+
) : (
|
|
265
|
+
<p className="mt-3 text-[12px] text-text-3/65">No obvious requirement or security signals were detected.</p>
|
|
266
|
+
)}
|
|
267
|
+
</div>
|
|
268
|
+
)}
|
|
269
|
+
|
|
209
270
|
<div className="mb-8">
|
|
210
271
|
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Name</label>
|
|
211
272
|
<input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="e.g. Frontend Design" className={inputClass} style={{ fontFamily: 'inherit' }} />
|
|
@@ -285,7 +346,7 @@ export function SkillSheet() {
|
|
|
285
346
|
|
|
286
347
|
<div className="flex gap-3 pt-2 border-t border-white/[0.04]">
|
|
287
348
|
{editing && (
|
|
288
|
-
<button onClick={
|
|
349
|
+
<button onClick={() => setConfirmDelete(true)} className="py-3.5 px-6 rounded-[14px] border border-red-500/20 bg-transparent text-red-400 text-[15px] font-600 cursor-pointer hover:bg-red-500/10 transition-all" style={{ fontFamily: 'inherit' }}>
|
|
289
350
|
Delete
|
|
290
351
|
</button>
|
|
291
352
|
)}
|
|
@@ -296,6 +357,17 @@ export function SkillSheet() {
|
|
|
296
357
|
{editing ? 'Save' : 'Create'}
|
|
297
358
|
</button>
|
|
298
359
|
</div>
|
|
360
|
+
<ConfirmDialog
|
|
361
|
+
open={confirmDelete}
|
|
362
|
+
title="Delete Skill?"
|
|
363
|
+
message={editing ? `Delete "${editing.name}"? This will remove it from all assigned agents.` : 'Delete this skill?'}
|
|
364
|
+
confirmLabel={deleting ? 'Deleting...' : 'Delete'}
|
|
365
|
+
confirmDisabled={deleting}
|
|
366
|
+
cancelDisabled={deleting}
|
|
367
|
+
danger
|
|
368
|
+
onConfirm={() => { void handleDelete() }}
|
|
369
|
+
onCancel={() => { if (!deleting) setConfirmDelete(false) }}
|
|
370
|
+
/>
|
|
299
371
|
</BottomSheet>
|
|
300
372
|
)
|
|
301
373
|
}
|