@swarmclawai/swarmclaw 0.2.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 +577 -0
- package/bin/server-cmd.js +359 -0
- package/bin/swarmclaw.js +29 -0
- package/bin/swarmclaw.mjs +1504 -0
- package/next.config.ts +33 -0
- package/package.json +112 -0
- package/postcss.config.mjs +7 -0
- package/public/branding/swarmclaw-org-avatar.png +0 -0
- package/public/branding/swarmclaw-org-avatar.svg +58 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/next.svg +1 -0
- package/public/screenshots/agents.png +0 -0
- package/public/screenshots/connectors.png +0 -0
- package/public/screenshots/dashboard.png +0 -0
- package/public/screenshots/new-session-openclaw.png +0 -0
- package/public/screenshots/providers.png +0 -0
- package/public/screenshots/schedules.png +0 -0
- package/public/screenshots/tasks.png +0 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/src/app/api/agents/[id]/route.ts +30 -0
- package/src/app/api/agents/[id]/thread/route.ts +66 -0
- package/src/app/api/agents/generate/route.ts +42 -0
- package/src/app/api/agents/route.ts +33 -0
- package/src/app/api/auth/route.ts +25 -0
- package/src/app/api/claude-skills/route.ts +42 -0
- package/src/app/api/clawhub/install/route.ts +39 -0
- package/src/app/api/clawhub/search/route.ts +11 -0
- package/src/app/api/connectors/[id]/route.ts +79 -0
- package/src/app/api/connectors/route.ts +60 -0
- package/src/app/api/credentials/[id]/route.ts +14 -0
- package/src/app/api/credentials/route.ts +31 -0
- package/src/app/api/daemon/health-check/route.ts +11 -0
- package/src/app/api/daemon/route.ts +22 -0
- package/src/app/api/dirs/pick/route.ts +60 -0
- package/src/app/api/dirs/route.ts +29 -0
- package/src/app/api/documents/[id]/route.ts +47 -0
- package/src/app/api/documents/route.ts +93 -0
- package/src/app/api/files/serve/route.ts +69 -0
- package/src/app/api/generate/info/route.ts +12 -0
- package/src/app/api/generate/route.ts +106 -0
- package/src/app/api/ip/route.ts +6 -0
- package/src/app/api/knowledge/[id]/route.ts +61 -0
- package/src/app/api/knowledge/route.ts +48 -0
- package/src/app/api/knowledge/upload/route.ts +86 -0
- package/src/app/api/logs/route.ts +65 -0
- package/src/app/api/mcp-servers/[id]/route.ts +32 -0
- package/src/app/api/mcp-servers/[id]/test/route.ts +23 -0
- package/src/app/api/mcp-servers/[id]/tools/route.ts +32 -0
- package/src/app/api/mcp-servers/route.ts +27 -0
- package/src/app/api/memory/[id]/route.ts +126 -0
- package/src/app/api/memory/maintenance/route.ts +63 -0
- package/src/app/api/memory/route.ts +111 -0
- package/src/app/api/memory-images/[filename]/route.ts +36 -0
- package/src/app/api/orchestrator/run/route.ts +43 -0
- package/src/app/api/plugins/install/route.ts +58 -0
- package/src/app/api/plugins/marketplace/route.ts +33 -0
- package/src/app/api/plugins/route.ts +21 -0
- package/src/app/api/preview-server/route.ts +339 -0
- package/src/app/api/providers/[id]/models/route.ts +29 -0
- package/src/app/api/providers/[id]/route.ts +34 -0
- package/src/app/api/providers/configs/route.ts +7 -0
- package/src/app/api/providers/ollama/route.ts +30 -0
- package/src/app/api/providers/openclaw/health/route.ts +23 -0
- package/src/app/api/providers/route.ts +28 -0
- package/src/app/api/runs/[id]/route.ts +9 -0
- package/src/app/api/runs/route.ts +13 -0
- package/src/app/api/schedules/[id]/route.ts +28 -0
- package/src/app/api/schedules/[id]/run/route.ts +104 -0
- package/src/app/api/schedules/route.ts +78 -0
- package/src/app/api/secrets/[id]/route.ts +29 -0
- package/src/app/api/secrets/route.ts +42 -0
- package/src/app/api/sessions/[id]/browser/route.ts +13 -0
- package/src/app/api/sessions/[id]/chat/route.ts +96 -0
- package/src/app/api/sessions/[id]/clear/route.ts +19 -0
- package/src/app/api/sessions/[id]/deploy/route.ts +34 -0
- package/src/app/api/sessions/[id]/devserver/route.ts +69 -0
- package/src/app/api/sessions/[id]/mailbox/route.ts +70 -0
- package/src/app/api/sessions/[id]/main-loop/route.ts +94 -0
- package/src/app/api/sessions/[id]/messages/route.ts +9 -0
- package/src/app/api/sessions/[id]/retry/route.ts +28 -0
- package/src/app/api/sessions/[id]/route.ts +103 -0
- package/src/app/api/sessions/[id]/stop/route.ts +13 -0
- package/src/app/api/sessions/heartbeat/route.ts +26 -0
- package/src/app/api/sessions/route.ts +85 -0
- package/src/app/api/settings/route.ts +58 -0
- package/src/app/api/setup/check-provider/route.ts +326 -0
- package/src/app/api/setup/doctor/route.ts +250 -0
- package/src/app/api/skills/[id]/route.ts +40 -0
- package/src/app/api/skills/import/route.ts +69 -0
- package/src/app/api/skills/route.ts +28 -0
- package/src/app/api/tasks/[id]/route.ts +102 -0
- package/src/app/api/tasks/route.ts +115 -0
- package/src/app/api/tts/route.ts +40 -0
- package/src/app/api/upload/route.ts +18 -0
- package/src/app/api/uploads/[filename]/route.ts +59 -0
- package/src/app/api/usage/route.ts +35 -0
- package/src/app/api/version/route.ts +81 -0
- package/src/app/api/version/update/route.ts +95 -0
- package/src/app/api/webhooks/[id]/history/route.ts +13 -0
- package/src/app/api/webhooks/[id]/route.ts +204 -0
- package/src/app/api/webhooks/route.ts +37 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +370 -0
- package/src/app/layout.tsx +52 -0
- package/src/app/page.tsx +172 -0
- package/src/cli/index.js +1232 -0
- package/src/cli/index.test.js +281 -0
- package/src/cli/index.ts +1158 -0
- package/src/cli/spec.js +284 -0
- package/src/components/agents/agent-card.tsx +219 -0
- package/src/components/agents/agent-chat-list.tsx +165 -0
- package/src/components/agents/agent-list.tsx +110 -0
- package/src/components/agents/agent-sheet.tsx +1220 -0
- package/src/components/auth/access-key-gate.tsx +248 -0
- package/src/components/auth/setup-wizard.tsx +940 -0
- package/src/components/auth/user-picker.tsx +88 -0
- package/src/components/chat/chat-area.tsx +406 -0
- package/src/components/chat/chat-header.tsx +491 -0
- package/src/components/chat/chat-tool-toggles.tsx +161 -0
- package/src/components/chat/code-block.tsx +146 -0
- package/src/components/chat/dev-server-bar.tsx +39 -0
- package/src/components/chat/message-bubble.tsx +486 -0
- package/src/components/chat/message-list.tsx +299 -0
- package/src/components/chat/session-debug-panel.tsx +196 -0
- package/src/components/chat/streaming-bubble.tsx +85 -0
- package/src/components/chat/thinking-indicator.tsx +26 -0
- package/src/components/chat/tool-call-bubble.tsx +438 -0
- package/src/components/chat/tool-request-banner.tsx +103 -0
- package/src/components/connectors/connector-list.tsx +196 -0
- package/src/components/connectors/connector-sheet.tsx +804 -0
- package/src/components/input/chat-input.tsx +235 -0
- package/src/components/knowledge/knowledge-list.tsx +206 -0
- package/src/components/knowledge/knowledge-sheet.tsx +316 -0
- package/src/components/layout/app-layout.tsx +1016 -0
- package/src/components/layout/daemon-indicator.tsx +56 -0
- package/src/components/layout/mobile-header.tsx +31 -0
- package/src/components/layout/network-banner.tsx +17 -0
- package/src/components/layout/update-banner.tsx +130 -0
- package/src/components/logs/log-list.tsx +358 -0
- package/src/components/mcp-servers/mcp-server-list.tsx +122 -0
- package/src/components/mcp-servers/mcp-server-sheet.tsx +243 -0
- package/src/components/memory/memory-card.tsx +63 -0
- package/src/components/memory/memory-detail.tsx +339 -0
- package/src/components/memory/memory-list.tsx +198 -0
- package/src/components/memory/memory-sheet.tsx +70 -0
- package/src/components/plugins/plugin-list.tsx +60 -0
- package/src/components/plugins/plugin-sheet.tsx +311 -0
- package/src/components/providers/provider-list.tsx +96 -0
- package/src/components/providers/provider-sheet.tsx +542 -0
- package/src/components/runs/run-list.tsx +231 -0
- package/src/components/schedules/schedule-card.tsx +63 -0
- package/src/components/schedules/schedule-list.tsx +76 -0
- package/src/components/schedules/schedule-sheet.tsx +336 -0
- package/src/components/secrets/secret-sheet.tsx +180 -0
- package/src/components/secrets/secrets-list.tsx +91 -0
- package/src/components/sessions/new-session-sheet.tsx +478 -0
- package/src/components/sessions/session-card.tsx +144 -0
- package/src/components/sessions/session-list.tsx +202 -0
- package/src/components/shared/ai-gen-block.tsx +77 -0
- package/src/components/shared/avatar.tsx +48 -0
- package/src/components/shared/bottom-sheet.tsx +30 -0
- package/src/components/shared/confirm-dialog.tsx +47 -0
- package/src/components/shared/connector-platform-icon.tsx +113 -0
- package/src/components/shared/dir-browser.tsx +285 -0
- package/src/components/shared/dropdown.tsx +55 -0
- package/src/components/shared/icon-button.tsx +25 -0
- package/src/components/shared/settings/plugin-manager.tsx +207 -0
- package/src/components/shared/settings/section-capability-policy.tsx +93 -0
- package/src/components/shared/settings/section-embedding.tsx +99 -0
- package/src/components/shared/settings/section-heartbeat.tsx +168 -0
- package/src/components/shared/settings/section-memory.tsx +77 -0
- package/src/components/shared/settings/section-orchestrator.tsx +108 -0
- package/src/components/shared/settings/section-providers.tsx +181 -0
- package/src/components/shared/settings/section-runtime-loop.tsx +183 -0
- package/src/components/shared/settings/section-secrets.tsx +132 -0
- package/src/components/shared/settings/section-user-preferences.tsx +24 -0
- package/src/components/shared/settings/section-voice.tsx +53 -0
- package/src/components/shared/settings/settings-sheet.tsx +88 -0
- package/src/components/shared/settings/types.ts +7 -0
- package/src/components/shared/settings/utils.ts +13 -0
- package/src/components/shared/settings-sheet.tsx +1 -0
- package/src/components/shared/skeleton.tsx +19 -0
- package/src/components/shared/usage-badge.tsx +28 -0
- package/src/components/skills/clawhub-browser.tsx +225 -0
- package/src/components/skills/skill-list.tsx +70 -0
- package/src/components/skills/skill-sheet.tsx +254 -0
- package/src/components/tasks/task-board.tsx +96 -0
- package/src/components/tasks/task-card.tsx +179 -0
- package/src/components/tasks/task-column.tsx +73 -0
- package/src/components/tasks/task-list.tsx +118 -0
- package/src/components/tasks/task-sheet.tsx +415 -0
- package/src/components/ui/avatar.tsx +109 -0
- package/src/components/ui/badge.tsx +48 -0
- package/src/components/ui/button.tsx +64 -0
- package/src/components/ui/card.tsx +92 -0
- package/src/components/ui/dialog.tsx +158 -0
- package/src/components/ui/dropdown-menu.tsx +257 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/scroll-area.tsx +58 -0
- package/src/components/ui/select.tsx +190 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/sheet.tsx +143 -0
- package/src/components/ui/sonner.tsx +22 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/tooltip.tsx +56 -0
- package/src/components/usage/usage-list.tsx +105 -0
- package/src/components/webhooks/webhook-list.tsx +166 -0
- package/src/components/webhooks/webhook-sheet.tsx +402 -0
- package/src/hooks/use-auto-resize.ts +20 -0
- package/src/hooks/use-media-query.ts +21 -0
- package/src/hooks/use-speech-recognition.ts +83 -0
- package/src/instrumentation.ts +8 -0
- package/src/lib/agents.ts +13 -0
- package/src/lib/api-client.ts +100 -0
- package/src/lib/chat.ts +60 -0
- package/src/lib/memory.ts +42 -0
- package/src/lib/openclaw-endpoint.test.ts +48 -0
- package/src/lib/openclaw-endpoint.ts +67 -0
- package/src/lib/provider-config.ts +13 -0
- package/src/lib/providers/anthropic.ts +135 -0
- package/src/lib/providers/claude-cli.ts +202 -0
- package/src/lib/providers/codex-cli.ts +260 -0
- package/src/lib/providers/index.ts +351 -0
- package/src/lib/providers/ollama.ts +131 -0
- package/src/lib/providers/openai.ts +164 -0
- package/src/lib/providers/openclaw.ts +330 -0
- package/src/lib/providers/opencode-cli.ts +164 -0
- package/src/lib/runtime-loop.ts +15 -0
- package/src/lib/schedule-dedupe.test.ts +84 -0
- package/src/lib/schedule-dedupe.ts +174 -0
- package/src/lib/schedule-name.ts +62 -0
- package/src/lib/schedules.ts +16 -0
- package/src/lib/server/agent-registry.ts +70 -0
- package/src/lib/server/api-routes.test.ts +362 -0
- package/src/lib/server/autonomy-contract.ts +200 -0
- package/src/lib/server/build-llm.ts +155 -0
- package/src/lib/server/capability-router.test.ts +21 -0
- package/src/lib/server/capability-router.ts +172 -0
- package/src/lib/server/chat-execution.ts +894 -0
- package/src/lib/server/clawhub-client.test.ts +161 -0
- package/src/lib/server/clawhub-client.ts +26 -0
- package/src/lib/server/connectors/connector-routing.test.ts +243 -0
- package/src/lib/server/connectors/discord.ts +116 -0
- package/src/lib/server/connectors/googlechat.ts +66 -0
- package/src/lib/server/connectors/manager.ts +559 -0
- package/src/lib/server/connectors/matrix.ts +78 -0
- package/src/lib/server/connectors/media.ts +149 -0
- package/src/lib/server/connectors/openclaw.test.ts +375 -0
- package/src/lib/server/connectors/openclaw.ts +1132 -0
- package/src/lib/server/connectors/signal.ts +183 -0
- package/src/lib/server/connectors/slack.ts +258 -0
- package/src/lib/server/connectors/teams.ts +94 -0
- package/src/lib/server/connectors/telegram.ts +221 -0
- package/src/lib/server/connectors/types.ts +62 -0
- package/src/lib/server/connectors/whatsapp.ts +349 -0
- package/src/lib/server/context-manager.ts +232 -0
- package/src/lib/server/cost.ts +31 -0
- package/src/lib/server/daemon-state.ts +354 -0
- package/src/lib/server/data-dir.ts +3 -0
- package/src/lib/server/embeddings.ts +111 -0
- package/src/lib/server/execution-log.ts +257 -0
- package/src/lib/server/gateway/protocol.test.ts +54 -0
- package/src/lib/server/gateway/protocol.ts +114 -0
- package/src/lib/server/heartbeat-service.ts +366 -0
- package/src/lib/server/knowledge-db.test.ts +441 -0
- package/src/lib/server/logger.ts +47 -0
- package/src/lib/server/main-agent-loop.ts +1017 -0
- package/src/lib/server/mcp-client.test.ts +342 -0
- package/src/lib/server/mcp-client.ts +130 -0
- package/src/lib/server/memory-db.ts +1078 -0
- package/src/lib/server/memory-graph.test.ts +153 -0
- package/src/lib/server/memory-graph.ts +138 -0
- package/src/lib/server/openclaw-health.ts +245 -0
- package/src/lib/server/orchestrator-lg.ts +431 -0
- package/src/lib/server/orchestrator.ts +364 -0
- package/src/lib/server/playwright-proxy.mjs +70 -0
- package/src/lib/server/plugins.ts +229 -0
- package/src/lib/server/process-manager.ts +327 -0
- package/src/lib/server/provider-health.ts +113 -0
- package/src/lib/server/queue.ts +859 -0
- package/src/lib/server/runtime-settings.ts +119 -0
- package/src/lib/server/scheduler.ts +196 -0
- package/src/lib/server/session-mailbox.ts +129 -0
- package/src/lib/server/session-run-manager.ts +512 -0
- package/src/lib/server/session-tools/connector.ts +124 -0
- package/src/lib/server/session-tools/context-mgmt.ts +103 -0
- package/src/lib/server/session-tools/context.ts +114 -0
- package/src/lib/server/session-tools/crud.ts +673 -0
- package/src/lib/server/session-tools/delegate.ts +708 -0
- package/src/lib/server/session-tools/file.ts +264 -0
- package/src/lib/server/session-tools/index.ts +164 -0
- package/src/lib/server/session-tools/memory.ts +230 -0
- package/src/lib/server/session-tools/session-info.ts +422 -0
- package/src/lib/server/session-tools/session-tools-wiring.test.ts +166 -0
- package/src/lib/server/session-tools/shell.ts +171 -0
- package/src/lib/server/session-tools/web.ts +408 -0
- package/src/lib/server/session-tools.ts +9 -0
- package/src/lib/server/skills-normalize.ts +130 -0
- package/src/lib/server/storage-mcp.test.ts +161 -0
- package/src/lib/server/storage.ts +670 -0
- package/src/lib/server/stream-agent-chat.ts +571 -0
- package/src/lib/server/task-reports.ts +122 -0
- package/src/lib/server/task-result.ts +161 -0
- package/src/lib/server/task-validation.test.ts +27 -0
- package/src/lib/server/task-validation.ts +90 -0
- package/src/lib/server/tool-capability-policy.test.ts +58 -0
- package/src/lib/server/tool-capability-policy.ts +262 -0
- package/src/lib/sessions.ts +68 -0
- package/src/lib/tasks.ts +20 -0
- package/src/lib/tts.ts +42 -0
- package/src/lib/upload.ts +10 -0
- package/src/lib/utils.ts +6 -0
- package/src/proxy.ts +43 -0
- package/src/stores/use-app-store.ts +468 -0
- package/src/stores/use-chat-store.ts +323 -0
- package/src/types/index.ts +621 -0
- package/tsconfig.json +34 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_AGENT_LOOP_RECURSION_LIMIT,
|
|
5
|
+
DEFAULT_CLAUDE_CODE_TIMEOUT_SEC,
|
|
6
|
+
DEFAULT_CLI_PROCESS_TIMEOUT_SEC,
|
|
7
|
+
DEFAULT_LEGACY_ORCHESTRATOR_MAX_TURNS,
|
|
8
|
+
DEFAULT_ONGOING_LOOP_MAX_ITERATIONS,
|
|
9
|
+
DEFAULT_ONGOING_LOOP_MAX_RUNTIME_MINUTES,
|
|
10
|
+
DEFAULT_ORCHESTRATOR_LOOP_RECURSION_LIMIT,
|
|
11
|
+
DEFAULT_SHELL_COMMAND_TIMEOUT_SEC,
|
|
12
|
+
} from '@/lib/runtime-loop'
|
|
13
|
+
import type { LoopMode } from '@/types'
|
|
14
|
+
import type { SettingsSectionProps } from './types'
|
|
15
|
+
|
|
16
|
+
export function RuntimeLoopSection({ appSettings, patchSettings, inputClass }: SettingsSectionProps) {
|
|
17
|
+
const loopMode: LoopMode = appSettings.loopMode === 'ongoing' ? 'ongoing' : 'bounded'
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div className="mb-10">
|
|
21
|
+
<h3 className="font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
22
|
+
Runtime & Loop Controls
|
|
23
|
+
</h3>
|
|
24
|
+
<p className="text-[12px] text-text-3 mb-5">
|
|
25
|
+
Choose bounded or ongoing agent loops and set safety guards for task execution.
|
|
26
|
+
</p>
|
|
27
|
+
<div className="p-6 rounded-[18px] bg-surface border border-white/[0.06]">
|
|
28
|
+
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-3">Loop Mode</label>
|
|
29
|
+
<div className="grid grid-cols-2 gap-2 mb-5">
|
|
30
|
+
{([
|
|
31
|
+
{ id: 'bounded' as const, name: 'Bounded' },
|
|
32
|
+
{ id: 'ongoing' as const, name: 'Ongoing' },
|
|
33
|
+
]).map((mode) => (
|
|
34
|
+
<button
|
|
35
|
+
key={mode.id}
|
|
36
|
+
onClick={() => patchSettings({ loopMode: mode.id })}
|
|
37
|
+
className={`py-3 px-3 rounded-[12px] text-center cursor-pointer transition-all text-[13px] font-600 border
|
|
38
|
+
${loopMode === mode.id
|
|
39
|
+
? 'bg-accent-soft border-accent-bright/25 text-accent-bright'
|
|
40
|
+
: 'bg-bg border-white/[0.06] text-text-2 hover:bg-surface-2'}`}
|
|
41
|
+
style={{ fontFamily: 'inherit' }}
|
|
42
|
+
>
|
|
43
|
+
{mode.name}
|
|
44
|
+
</button>
|
|
45
|
+
))}
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
{loopMode === 'bounded' ? (
|
|
49
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-3 mb-5">
|
|
50
|
+
<div>
|
|
51
|
+
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Agent Steps</label>
|
|
52
|
+
<input
|
|
53
|
+
type="number"
|
|
54
|
+
min={1}
|
|
55
|
+
max={200}
|
|
56
|
+
value={appSettings.agentLoopRecursionLimit ?? DEFAULT_AGENT_LOOP_RECURSION_LIMIT}
|
|
57
|
+
onChange={(e) => {
|
|
58
|
+
const n = Number.parseInt(e.target.value, 10)
|
|
59
|
+
patchSettings({ agentLoopRecursionLimit: Number.isFinite(n) ? n : DEFAULT_AGENT_LOOP_RECURSION_LIMIT })
|
|
60
|
+
}}
|
|
61
|
+
className={inputClass}
|
|
62
|
+
style={{ fontFamily: 'inherit' }}
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
<div>
|
|
66
|
+
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Orchestrator Steps</label>
|
|
67
|
+
<input
|
|
68
|
+
type="number"
|
|
69
|
+
min={1}
|
|
70
|
+
max={300}
|
|
71
|
+
value={appSettings.orchestratorLoopRecursionLimit ?? DEFAULT_ORCHESTRATOR_LOOP_RECURSION_LIMIT}
|
|
72
|
+
onChange={(e) => {
|
|
73
|
+
const n = Number.parseInt(e.target.value, 10)
|
|
74
|
+
patchSettings({ orchestratorLoopRecursionLimit: Number.isFinite(n) ? n : DEFAULT_ORCHESTRATOR_LOOP_RECURSION_LIMIT })
|
|
75
|
+
}}
|
|
76
|
+
className={inputClass}
|
|
77
|
+
style={{ fontFamily: 'inherit' }}
|
|
78
|
+
/>
|
|
79
|
+
</div>
|
|
80
|
+
<div>
|
|
81
|
+
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Legacy Turns</label>
|
|
82
|
+
<input
|
|
83
|
+
type="number"
|
|
84
|
+
min={1}
|
|
85
|
+
max={300}
|
|
86
|
+
value={appSettings.legacyOrchestratorMaxTurns ?? DEFAULT_LEGACY_ORCHESTRATOR_MAX_TURNS}
|
|
87
|
+
onChange={(e) => {
|
|
88
|
+
const n = Number.parseInt(e.target.value, 10)
|
|
89
|
+
patchSettings({ legacyOrchestratorMaxTurns: Number.isFinite(n) ? n : DEFAULT_LEGACY_ORCHESTRATOR_MAX_TURNS })
|
|
90
|
+
}}
|
|
91
|
+
className={inputClass}
|
|
92
|
+
style={{ fontFamily: 'inherit' }}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
) : (
|
|
97
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 mb-5">
|
|
98
|
+
<div>
|
|
99
|
+
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Max Steps (Safety Cap)</label>
|
|
100
|
+
<input
|
|
101
|
+
type="number"
|
|
102
|
+
min={10}
|
|
103
|
+
max={5000}
|
|
104
|
+
value={appSettings.ongoingLoopMaxIterations ?? DEFAULT_ONGOING_LOOP_MAX_ITERATIONS}
|
|
105
|
+
onChange={(e) => {
|
|
106
|
+
const n = Number.parseInt(e.target.value, 10)
|
|
107
|
+
patchSettings({ ongoingLoopMaxIterations: Number.isFinite(n) ? n : DEFAULT_ONGOING_LOOP_MAX_ITERATIONS })
|
|
108
|
+
}}
|
|
109
|
+
className={inputClass}
|
|
110
|
+
style={{ fontFamily: 'inherit' }}
|
|
111
|
+
/>
|
|
112
|
+
</div>
|
|
113
|
+
<div>
|
|
114
|
+
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Max Runtime (Minutes)</label>
|
|
115
|
+
<input
|
|
116
|
+
type="number"
|
|
117
|
+
min={0}
|
|
118
|
+
max={1440}
|
|
119
|
+
value={appSettings.ongoingLoopMaxRuntimeMinutes ?? DEFAULT_ONGOING_LOOP_MAX_RUNTIME_MINUTES}
|
|
120
|
+
onChange={(e) => {
|
|
121
|
+
const n = Number.parseInt(e.target.value, 10)
|
|
122
|
+
patchSettings({ ongoingLoopMaxRuntimeMinutes: Number.isFinite(n) ? n : DEFAULT_ONGOING_LOOP_MAX_RUNTIME_MINUTES })
|
|
123
|
+
}}
|
|
124
|
+
className={inputClass}
|
|
125
|
+
style={{ fontFamily: 'inherit' }}
|
|
126
|
+
/>
|
|
127
|
+
<p className="text-[11px] text-text-3/60 mt-2">Set to 0 to disable the runtime guard.</p>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
131
|
+
|
|
132
|
+
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-3">Execution Timeouts (Seconds)</label>
|
|
133
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
|
|
134
|
+
<div>
|
|
135
|
+
<label className="block text-[11px] text-text-3 mb-2">Shell</label>
|
|
136
|
+
<input
|
|
137
|
+
type="number"
|
|
138
|
+
min={1}
|
|
139
|
+
max={600}
|
|
140
|
+
value={appSettings.shellCommandTimeoutSec ?? DEFAULT_SHELL_COMMAND_TIMEOUT_SEC}
|
|
141
|
+
onChange={(e) => {
|
|
142
|
+
const n = Number.parseInt(e.target.value, 10)
|
|
143
|
+
patchSettings({ shellCommandTimeoutSec: Number.isFinite(n) ? n : DEFAULT_SHELL_COMMAND_TIMEOUT_SEC })
|
|
144
|
+
}}
|
|
145
|
+
className={inputClass}
|
|
146
|
+
style={{ fontFamily: 'inherit' }}
|
|
147
|
+
/>
|
|
148
|
+
</div>
|
|
149
|
+
<div>
|
|
150
|
+
<label className="block text-[11px] text-text-3 mb-2">Claude Code Tool</label>
|
|
151
|
+
<input
|
|
152
|
+
type="number"
|
|
153
|
+
min={5}
|
|
154
|
+
max={7200}
|
|
155
|
+
value={appSettings.claudeCodeTimeoutSec ?? DEFAULT_CLAUDE_CODE_TIMEOUT_SEC}
|
|
156
|
+
onChange={(e) => {
|
|
157
|
+
const n = Number.parseInt(e.target.value, 10)
|
|
158
|
+
patchSettings({ claudeCodeTimeoutSec: Number.isFinite(n) ? n : DEFAULT_CLAUDE_CODE_TIMEOUT_SEC })
|
|
159
|
+
}}
|
|
160
|
+
className={inputClass}
|
|
161
|
+
style={{ fontFamily: 'inherit' }}
|
|
162
|
+
/>
|
|
163
|
+
</div>
|
|
164
|
+
<div>
|
|
165
|
+
<label className="block text-[11px] text-text-3 mb-2">CLI Provider Process</label>
|
|
166
|
+
<input
|
|
167
|
+
type="number"
|
|
168
|
+
min={10}
|
|
169
|
+
max={7200}
|
|
170
|
+
value={appSettings.cliProcessTimeoutSec ?? DEFAULT_CLI_PROCESS_TIMEOUT_SEC}
|
|
171
|
+
onChange={(e) => {
|
|
172
|
+
const n = Number.parseInt(e.target.value, 10)
|
|
173
|
+
patchSettings({ cliProcessTimeoutSec: Number.isFinite(n) ? n : DEFAULT_CLI_PROCESS_TIMEOUT_SEC })
|
|
174
|
+
}}
|
|
175
|
+
className={inputClass}
|
|
176
|
+
style={{ fontFamily: 'inherit' }}
|
|
177
|
+
/>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
)
|
|
183
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { useAppStore } from '@/stores/use-app-store'
|
|
5
|
+
import { api } from '@/lib/api-client'
|
|
6
|
+
import { toast } from 'sonner'
|
|
7
|
+
import type { SettingsSectionProps } from './types'
|
|
8
|
+
|
|
9
|
+
export function SecretsSection({ appSettings, inputClass }: SettingsSectionProps) {
|
|
10
|
+
const secrets = useAppStore((s) => s.secrets)
|
|
11
|
+
const loadSecrets = useAppStore((s) => s.loadSecrets)
|
|
12
|
+
const agents = useAppStore((s) => s.agents)
|
|
13
|
+
|
|
14
|
+
const [addingSecret, setAddingSecret] = useState(false)
|
|
15
|
+
const [secretName, setSecretName] = useState('')
|
|
16
|
+
const [secretService, setSecretService] = useState('')
|
|
17
|
+
const [secretValue, setSecretValue] = useState('')
|
|
18
|
+
const [secretScope, setSecretScope] = useState<'global' | 'agent'>('global')
|
|
19
|
+
const [secretAgentIds, setSecretAgentIds] = useState<string[]>([])
|
|
20
|
+
const [deletingSecret, setDeletingSecret] = useState<string | null>(null)
|
|
21
|
+
|
|
22
|
+
const handleAddSecret = async () => {
|
|
23
|
+
if (!secretName.trim() || !secretValue.trim()) return
|
|
24
|
+
try {
|
|
25
|
+
await api('POST', '/secrets', {
|
|
26
|
+
name: secretName,
|
|
27
|
+
service: secretService || 'custom',
|
|
28
|
+
value: secretValue,
|
|
29
|
+
scope: secretScope,
|
|
30
|
+
agentIds: secretScope === 'agent' ? secretAgentIds : [],
|
|
31
|
+
})
|
|
32
|
+
await loadSecrets()
|
|
33
|
+
setAddingSecret(false)
|
|
34
|
+
setSecretName('')
|
|
35
|
+
setSecretService('')
|
|
36
|
+
setSecretValue('')
|
|
37
|
+
setSecretScope('global')
|
|
38
|
+
setSecretAgentIds([])
|
|
39
|
+
toast.success('Credential added')
|
|
40
|
+
} catch (err: unknown) {
|
|
41
|
+
toast.error(err instanceof Error ? err.message : 'Failed to add credential')
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const handleDeleteSecret = async (id: string) => {
|
|
46
|
+
try {
|
|
47
|
+
await api('DELETE', `/secrets/${id}`)
|
|
48
|
+
await loadSecrets()
|
|
49
|
+
setDeletingSecret(null)
|
|
50
|
+
toast.success('Credential deleted')
|
|
51
|
+
} catch (err: unknown) {
|
|
52
|
+
toast.error(err instanceof Error ? err.message : 'Failed to delete credential')
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const orchestrators = Object.values(agents).filter((p) => p.isOrchestrator)
|
|
57
|
+
const secretList = Object.entries(secrets).map(([rowId, secret]) => ({ ...secret, rowId }))
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div className="mb-10">
|
|
61
|
+
<h3 className="font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
62
|
+
Service Credentials
|
|
63
|
+
</h3>
|
|
64
|
+
<p className="text-[12px] text-text-3 mb-5">
|
|
65
|
+
Credentials for external services (Gmail, APIs, etc.) that orchestrators can use during task execution.
|
|
66
|
+
</p>
|
|
67
|
+
|
|
68
|
+
{secretList.length > 0 && (
|
|
69
|
+
<div className="space-y-2.5 mb-4">
|
|
70
|
+
{secretList.map((secret) => (
|
|
71
|
+
<div key={secret.rowId} className="flex items-center gap-3 py-3 px-4 rounded-[14px] bg-surface border border-white/[0.06]">
|
|
72
|
+
<div className="flex-1 min-w-0">
|
|
73
|
+
<div className="text-[14px] font-600 text-text truncate">{secret.name}</div>
|
|
74
|
+
<div className="flex items-center gap-2 mt-0.5">
|
|
75
|
+
<span className="text-[11px] font-mono text-text-3">{secret.service}</span>
|
|
76
|
+
<span className={`text-[10px] font-600 px-1.5 py-0.5 rounded-[4px] ${
|
|
77
|
+
secret.scope === 'global'
|
|
78
|
+
? 'bg-emerald-500/10 text-emerald-400'
|
|
79
|
+
: 'bg-amber-500/10 text-amber-400'
|
|
80
|
+
}`}>
|
|
81
|
+
{secret.scope === 'global' ? 'All orchestrators' : `${secret.agentIds.length} orchestrator(s)`}
|
|
82
|
+
</span>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
{deletingSecret === secret.rowId ? (
|
|
86
|
+
<div className="flex gap-2">
|
|
87
|
+
<button onClick={() => setDeletingSecret(null)} className="px-3 py-1.5 text-[13px] font-600 bg-transparent border-none text-text-3 cursor-pointer hover:text-text-2 transition-colors" style={{ fontFamily: 'inherit' }}>Keep</button>
|
|
88
|
+
<button onClick={() => handleDeleteSecret(secret.rowId)} className="px-3 py-1.5 text-[13px] font-600 bg-danger text-white border-none cursor-pointer rounded-[8px] transition-colors hover:brightness-110" style={{ fontFamily: 'inherit' }}>Delete</button>
|
|
89
|
+
</div>
|
|
90
|
+
) : (
|
|
91
|
+
<button onClick={() => setDeletingSecret(secret.rowId)} className="px-3 py-1.5 text-[13px] font-500 bg-transparent border-none text-text-3 cursor-pointer hover:text-danger transition-colors" style={{ fontFamily: 'inherit' }}>Remove</button>
|
|
92
|
+
)}
|
|
93
|
+
</div>
|
|
94
|
+
))}
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
97
|
+
|
|
98
|
+
{addingSecret ? (
|
|
99
|
+
<div className="p-6 rounded-[18px] bg-surface border border-white/[0.06] space-y-4">
|
|
100
|
+
<div className="font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em]">New Secret</div>
|
|
101
|
+
<input type="text" value={secretName} onChange={(e) => setSecretName(e.target.value)} placeholder="Name (e.g. My Gmail)" className={inputClass} style={{ fontFamily: 'inherit' }} />
|
|
102
|
+
<input type="text" value={secretService} onChange={(e) => setSecretService(e.target.value)} placeholder="Service (e.g. gmail, ahrefs, custom)" className={inputClass} style={{ fontFamily: 'inherit' }} />
|
|
103
|
+
<input type="password" value={secretValue} onChange={(e) => setSecretValue(e.target.value)} placeholder="Value (API key, password, token...)" className={inputClass} style={{ fontFamily: 'inherit' }} />
|
|
104
|
+
|
|
105
|
+
<div>
|
|
106
|
+
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Scope</label>
|
|
107
|
+
<div className="flex p-1 rounded-[12px] bg-bg border border-white/[0.06]">
|
|
108
|
+
{(['global', 'agent'] as const).map((s) => (
|
|
109
|
+
<button key={s} onClick={() => setSecretScope(s)} className={`flex-1 py-2.5 rounded-[10px] text-center cursor-pointer transition-all text-[13px] font-600 capitalize ${secretScope === s ? 'bg-accent-soft text-accent-bright' : 'bg-transparent text-text-3 hover:text-text-2'}`} style={{ fontFamily: 'inherit' }}>{s === 'global' ? 'All Orchestrators' : 'Specific'}</button>
|
|
110
|
+
))}
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
{secretScope === 'agent' && orchestrators.length > 0 && (
|
|
115
|
+
<div className="flex flex-wrap gap-2">
|
|
116
|
+
{orchestrators.map((p) => (
|
|
117
|
+
<button key={p.id} onClick={() => setSecretAgentIds((prev) => prev.includes(p.id) ? prev.filter((x) => x !== p.id) : [...prev, p.id])} className={`px-3 py-2 rounded-[10px] text-[12px] font-600 cursor-pointer transition-all border ${secretAgentIds.includes(p.id) ? 'bg-accent-soft border-accent-bright/25 text-accent-bright' : 'bg-bg border-white/[0.06] text-text-3 hover:text-text-2'}`} style={{ fontFamily: 'inherit' }}>{p.name}</button>
|
|
118
|
+
))}
|
|
119
|
+
</div>
|
|
120
|
+
)}
|
|
121
|
+
|
|
122
|
+
<div className="flex gap-3 pt-2">
|
|
123
|
+
<button onClick={() => setAddingSecret(false)} className="flex-1 py-3 rounded-[14px] border border-white/[0.08] bg-transparent text-text-2 text-[14px] font-600 cursor-pointer hover:bg-surface-2 transition-colors" style={{ fontFamily: 'inherit' }}>Cancel</button>
|
|
124
|
+
<button onClick={handleAddSecret} disabled={!secretName.trim() || !secretValue.trim()} className="flex-1 py-3 rounded-[14px] border-none bg-[#6366F1] text-white text-[14px] font-600 cursor-pointer disabled:opacity-30 transition-all hover:brightness-110" style={{ fontFamily: 'inherit' }}>Save Secret</button>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
) : (
|
|
128
|
+
<button onClick={() => setAddingSecret(true)} className="w-full py-3 rounded-[12px] border border-dashed border-white/[0.1] bg-transparent text-text-3 text-[13px] font-600 cursor-pointer hover:border-accent-bright/30 hover:text-accent-bright hover:bg-accent-soft transition-all duration-200" style={{ fontFamily: 'inherit' }}>+ Add Service Credential</button>
|
|
129
|
+
)}
|
|
130
|
+
</div>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import type { SettingsSectionProps } from './types'
|
|
4
|
+
|
|
5
|
+
export function UserPreferencesSection({ appSettings, patchSettings, inputClass }: SettingsSectionProps) {
|
|
6
|
+
return (
|
|
7
|
+
<div className="mb-10">
|
|
8
|
+
<h3 className="font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
9
|
+
User Preferences
|
|
10
|
+
</h3>
|
|
11
|
+
<p className="text-[12px] text-text-3 mb-5">
|
|
12
|
+
Global instructions injected into ALL agent system prompts. Define your style, rules, and preferences.
|
|
13
|
+
</p>
|
|
14
|
+
<textarea
|
|
15
|
+
value={appSettings.userPrompt || ''}
|
|
16
|
+
onChange={(e) => patchSettings({ userPrompt: e.target.value })}
|
|
17
|
+
placeholder="e.g. Always respond concisely. Use TypeScript over JavaScript. Prefer functional patterns. My timezone is PST."
|
|
18
|
+
rows={4}
|
|
19
|
+
className={`${inputClass} resize-y min-h-[100px]`}
|
|
20
|
+
style={{ fontFamily: 'inherit' }}
|
|
21
|
+
/>
|
|
22
|
+
</div>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import type { SettingsSectionProps } from './types'
|
|
4
|
+
|
|
5
|
+
export function VoiceSection({ appSettings, patchSettings, inputClass }: SettingsSectionProps) {
|
|
6
|
+
return (
|
|
7
|
+
<div className="mb-10">
|
|
8
|
+
<h3 className="font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
9
|
+
Voice
|
|
10
|
+
</h3>
|
|
11
|
+
<p className="text-[12px] text-text-3 mb-5">
|
|
12
|
+
Configure voice playback (TTS) and speech-to-text input.
|
|
13
|
+
</p>
|
|
14
|
+
<div className="p-6 rounded-[18px] bg-surface border border-white/[0.06]">
|
|
15
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 mb-5">
|
|
16
|
+
<div>
|
|
17
|
+
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">ElevenLabs API Key</label>
|
|
18
|
+
<input
|
|
19
|
+
type="password"
|
|
20
|
+
value={appSettings.elevenLabsApiKey || ''}
|
|
21
|
+
onChange={(e) => patchSettings({ elevenLabsApiKey: e.target.value || null })}
|
|
22
|
+
placeholder="sk_..."
|
|
23
|
+
className={inputClass}
|
|
24
|
+
style={{ fontFamily: 'inherit' }}
|
|
25
|
+
/>
|
|
26
|
+
</div>
|
|
27
|
+
<div>
|
|
28
|
+
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">ElevenLabs Voice ID</label>
|
|
29
|
+
<input
|
|
30
|
+
type="text"
|
|
31
|
+
value={appSettings.elevenLabsVoiceId || ''}
|
|
32
|
+
onChange={(e) => patchSettings({ elevenLabsVoiceId: e.target.value || null })}
|
|
33
|
+
placeholder="JBFqnCBsd6RMkjVDRZzb"
|
|
34
|
+
className={inputClass}
|
|
35
|
+
style={{ fontFamily: 'inherit' }}
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<div>
|
|
40
|
+
<label className="block font-display text-[11px] font-600 text-text-3 uppercase tracking-[0.08em] mb-2">Speech Recognition Language</label>
|
|
41
|
+
<input
|
|
42
|
+
type="text"
|
|
43
|
+
value={appSettings.speechRecognitionLang || ''}
|
|
44
|
+
onChange={(e) => patchSettings({ speechRecognitionLang: e.target.value || null })}
|
|
45
|
+
placeholder="en-US (blank = browser default)"
|
|
46
|
+
className={inputClass}
|
|
47
|
+
style={{ fontFamily: 'inherit' }}
|
|
48
|
+
/>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect } from 'react'
|
|
4
|
+
import { useAppStore } from '@/stores/use-app-store'
|
|
5
|
+
import { BottomSheet } from '../bottom-sheet'
|
|
6
|
+
import { inputClass } from './utils'
|
|
7
|
+
import { UserPreferencesSection } from './section-user-preferences'
|
|
8
|
+
import { OrchestratorSection } from './section-orchestrator'
|
|
9
|
+
import { RuntimeLoopSection } from './section-runtime-loop'
|
|
10
|
+
import { CapabilityPolicySection } from './section-capability-policy'
|
|
11
|
+
import { VoiceSection } from './section-voice'
|
|
12
|
+
import { HeartbeatSection } from './section-heartbeat'
|
|
13
|
+
import { EmbeddingSection } from './section-embedding'
|
|
14
|
+
import { MemorySection } from './section-memory'
|
|
15
|
+
import { SecretsSection } from './section-secrets'
|
|
16
|
+
import { ProvidersSection } from './section-providers'
|
|
17
|
+
import { PluginManager } from './plugin-manager'
|
|
18
|
+
|
|
19
|
+
export function SettingsSheet() {
|
|
20
|
+
const open = useAppStore((s) => s.settingsOpen)
|
|
21
|
+
const setOpen = useAppStore((s) => s.setSettingsOpen)
|
|
22
|
+
const loadProviders = useAppStore((s) => s.loadProviders)
|
|
23
|
+
const loadCredentials = useAppStore((s) => s.loadCredentials)
|
|
24
|
+
const appSettings = useAppStore((s) => s.appSettings)
|
|
25
|
+
const loadSettings = useAppStore((s) => s.loadSettings)
|
|
26
|
+
const updateSettings = useAppStore((s) => s.updateSettings)
|
|
27
|
+
const loadSecrets = useAppStore((s) => s.loadSecrets)
|
|
28
|
+
const loadAgents = useAppStore((s) => s.loadAgents)
|
|
29
|
+
const credentials = useAppStore((s) => s.credentials)
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (open) {
|
|
33
|
+
loadProviders()
|
|
34
|
+
loadCredentials()
|
|
35
|
+
loadSettings()
|
|
36
|
+
loadSecrets()
|
|
37
|
+
loadAgents()
|
|
38
|
+
}
|
|
39
|
+
}, [open])
|
|
40
|
+
|
|
41
|
+
const credList = Object.values(credentials)
|
|
42
|
+
const patchSettings = updateSettings
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<BottomSheet open={open} onClose={() => setOpen(false)} wide>
|
|
46
|
+
{/* Header */}
|
|
47
|
+
<div className="mb-10">
|
|
48
|
+
<h2 className="font-display text-[28px] font-700 tracking-[-0.03em] mb-2">Settings</h2>
|
|
49
|
+
<p className="text-[14px] text-text-3">Manage providers, API keys & orchestrator engine</p>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<UserPreferencesSection appSettings={appSettings} patchSettings={patchSettings} inputClass={inputClass} />
|
|
53
|
+
<OrchestratorSection appSettings={appSettings} patchSettings={patchSettings} inputClass={inputClass} />
|
|
54
|
+
<RuntimeLoopSection appSettings={appSettings} patchSettings={patchSettings} inputClass={inputClass} />
|
|
55
|
+
<CapabilityPolicySection appSettings={appSettings} patchSettings={patchSettings} inputClass={inputClass} />
|
|
56
|
+
<VoiceSection appSettings={appSettings} patchSettings={patchSettings} inputClass={inputClass} />
|
|
57
|
+
<HeartbeatSection appSettings={appSettings} patchSettings={patchSettings} inputClass={inputClass} />
|
|
58
|
+
<EmbeddingSection appSettings={appSettings} patchSettings={patchSettings} inputClass={inputClass} credList={credList} />
|
|
59
|
+
<MemorySection appSettings={appSettings} patchSettings={patchSettings} inputClass={inputClass} />
|
|
60
|
+
<SecretsSection appSettings={appSettings} patchSettings={patchSettings} inputClass={inputClass} />
|
|
61
|
+
<ProvidersSection appSettings={appSettings} patchSettings={patchSettings} inputClass={inputClass} />
|
|
62
|
+
|
|
63
|
+
{/* Plugins */}
|
|
64
|
+
<div className="mb-10">
|
|
65
|
+
<h3 className="font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
66
|
+
Plugins
|
|
67
|
+
</h3>
|
|
68
|
+
<p className="text-[12px] text-text-3 mb-5">
|
|
69
|
+
Extend agent behavior with hooks. Install from the marketplace, a URL, or drop .js files into <code className="text-[11px] font-mono text-text-2">data/plugins/</code>.
|
|
70
|
+
<span className="text-text-3/70 ml-1">OpenClaw plugins are also supported.</span>
|
|
71
|
+
</p>
|
|
72
|
+
<PluginManager />
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
{/* Done */}
|
|
76
|
+
<div className="pt-2 border-t border-white/[0.04]">
|
|
77
|
+
<button
|
|
78
|
+
onClick={() => setOpen(false)}
|
|
79
|
+
className="w-full py-3.5 rounded-[14px] border border-white/[0.08] bg-transparent text-text-2 text-[15px] font-600 cursor-pointer
|
|
80
|
+
hover:bg-surface-2 transition-all duration-200"
|
|
81
|
+
style={{ fontFamily: 'inherit' }}
|
|
82
|
+
>
|
|
83
|
+
Done
|
|
84
|
+
</button>
|
|
85
|
+
</div>
|
|
86
|
+
</BottomSheet>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
2
|
+
import { useAppStore } from '@/stores/use-app-store'
|
|
3
|
+
import type { AppSettings } from '@/types'
|
|
4
|
+
|
|
5
|
+
export const inputClass = "w-full px-4 py-3.5 rounded-[14px] border border-white/[0.08] bg-bg text-text text-[15px] outline-none transition-all duration-200 placeholder:text-text-3/50 focus-glow"
|
|
6
|
+
|
|
7
|
+
export function usePatchSettings() {
|
|
8
|
+
const updateSettings = useAppStore((s) => s.updateSettings)
|
|
9
|
+
return useCallback(
|
|
10
|
+
(patch: Partial<AppSettings>) => updateSettings(patch),
|
|
11
|
+
[updateSettings],
|
|
12
|
+
)
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SettingsSheet } from './settings/settings-sheet'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
className?: string
|
|
5
|
+
width?: string | number
|
|
6
|
+
height?: string | number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function Skeleton({ className = '', width, height }: Props) {
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
className={`bg-white/[0.06] animate-pulse rounded ${className}`}
|
|
13
|
+
style={{
|
|
14
|
+
width: typeof width === 'number' ? `${width}px` : width,
|
|
15
|
+
height: typeof height === 'number' ? `${height}px` : height,
|
|
16
|
+
}}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
inputTokens: number
|
|
5
|
+
outputTokens: number
|
|
6
|
+
totalTokens: number
|
|
7
|
+
estimatedCost: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function UsageBadge({ totalTokens, estimatedCost }: Props) {
|
|
11
|
+
if (!totalTokens) return null
|
|
12
|
+
|
|
13
|
+
const costStr = estimatedCost < 0.001
|
|
14
|
+
? '<$0.001'
|
|
15
|
+
: `$${estimatedCost.toFixed(3)}`
|
|
16
|
+
|
|
17
|
+
const tokenStr = totalTokens >= 1000
|
|
18
|
+
? `${(totalTokens / 1000).toFixed(1)}k`
|
|
19
|
+
: String(totalTokens)
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<span className="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-[7px] bg-white/[0.04] text-[10px] font-mono text-text-3/60">
|
|
23
|
+
<span>{tokenStr} tok</span>
|
|
24
|
+
<span className="text-text-3/60">·</span>
|
|
25
|
+
<span className="text-emerald-400/60">{costStr}</span>
|
|
26
|
+
</span>
|
|
27
|
+
)
|
|
28
|
+
}
|