@swarmclawai/swarmclaw 0.7.2 → 0.7.4
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 +116 -50
- package/bin/package-manager.js +157 -0
- package/bin/package-manager.test.js +90 -0
- package/bin/server-cmd.js +38 -7
- package/bin/swarmclaw.js +54 -4
- package/bin/update-cmd.js +48 -10
- package/bin/update-cmd.test.js +55 -0
- package/package.json +8 -3
- package/scripts/postinstall.mjs +26 -0
- package/src/app/api/agents/[id]/route.ts +43 -0
- package/src/app/api/agents/[id]/thread/route.ts +39 -8
- package/src/app/api/agents/route.ts +35 -2
- package/src/app/api/auth/route.ts +77 -8
- package/src/app/api/chatrooms/[id]/chat/route.ts +22 -6
- package/src/app/api/chatrooms/[id]/pins/route.ts +2 -1
- package/src/app/api/chatrooms/[id]/reactions/route.ts +2 -1
- package/src/app/api/chatrooms/[id]/route.ts +6 -0
- package/src/app/api/chats/[id]/browser/route.ts +5 -1
- package/src/app/api/chats/[id]/chat/route.ts +7 -3
- package/src/app/api/chats/[id]/messages/route.ts +19 -13
- package/src/app/api/chats/[id]/route.ts +30 -0
- package/src/app/api/chats/[id]/stop/route.ts +6 -1
- package/src/app/api/chats/heartbeat/route.ts +2 -1
- package/src/app/api/chats/route.ts +23 -1
- package/src/app/api/connectors/[id]/doctor/route.ts +26 -0
- package/src/app/api/connectors/doctor/route.ts +13 -0
- package/src/app/api/external-agents/[id]/heartbeat/route.ts +33 -0
- package/src/app/api/external-agents/[id]/route.ts +31 -0
- package/src/app/api/external-agents/register/route.ts +3 -0
- package/src/app/api/external-agents/route.ts +66 -0
- package/src/app/api/files/open/route.ts +16 -14
- package/src/app/api/gateways/[id]/health/route.ts +28 -0
- package/src/app/api/gateways/[id]/route.ts +79 -0
- package/src/app/api/gateways/route.ts +57 -0
- package/src/app/api/memory/maintenance/route.ts +11 -1
- package/src/app/api/openclaw/agent-files/route.ts +27 -4
- package/src/app/api/openclaw/gateway/route.ts +10 -7
- package/src/app/api/openclaw/skills/route.ts +12 -4
- package/src/app/api/plugins/dependencies/route.ts +24 -0
- package/src/app/api/plugins/install/route.ts +15 -92
- package/src/app/api/plugins/route.ts +3 -26
- package/src/app/api/plugins/settings/route.ts +17 -12
- package/src/app/api/plugins/ui/route.ts +1 -0
- package/src/app/api/providers/[id]/discover-models/route.ts +27 -0
- package/src/app/api/schedules/[id]/route.ts +38 -9
- package/src/app/api/schedules/route.ts +51 -28
- package/src/app/api/settings/route.ts +55 -17
- package/src/app/api/setup/doctor/route.ts +6 -4
- package/src/app/api/tasks/[id]/route.ts +16 -6
- package/src/app/api/tasks/bulk/route.ts +3 -3
- package/src/app/api/tasks/route.ts +9 -4
- package/src/app/api/webhooks/[id]/route.ts +8 -1
- package/src/app/page.tsx +135 -17
- package/src/cli/binary.test.js +142 -0
- package/src/cli/index.js +38 -11
- package/src/cli/index.test.js +195 -0
- package/src/cli/index.ts +21 -12
- package/src/cli/server-cmd.test.js +59 -0
- package/src/cli/spec.js +20 -2
- package/src/components/agents/agent-card.tsx +15 -12
- package/src/components/agents/agent-chat-list.tsx +101 -1
- package/src/components/agents/agent-list.tsx +46 -9
- package/src/components/agents/agent-sheet.tsx +456 -23
- package/src/components/agents/inspector-panel.tsx +110 -49
- package/src/components/agents/sandbox-env-panel.tsx +4 -1
- package/src/components/auth/access-key-gate.tsx +36 -97
- package/src/components/auth/setup-wizard.tsx +970 -275
- package/src/components/chat/chat-area.tsx +70 -27
- package/src/components/chat/chat-card.tsx +6 -21
- package/src/components/chat/chat-header.tsx +263 -366
- package/src/components/chat/chat-list.tsx +62 -26
- package/src/components/chat/checkpoint-timeline.tsx +1 -1
- package/src/components/chat/message-list.tsx +145 -19
- package/src/components/chatrooms/chatroom-input.tsx +96 -33
- package/src/components/chatrooms/chatroom-list.tsx +141 -72
- package/src/components/chatrooms/chatroom-message.tsx +7 -6
- package/src/components/chatrooms/chatroom-sheet.tsx +13 -1
- package/src/components/chatrooms/chatroom-tool-request-banner.tsx +5 -2
- package/src/components/chatrooms/chatroom-view.tsx +422 -209
- package/src/components/chatrooms/reaction-picker.tsx +38 -33
- package/src/components/connectors/connector-list.tsx +265 -127
- package/src/components/connectors/connector-sheet.tsx +217 -0
- package/src/components/gateways/gateway-sheet.tsx +567 -0
- package/src/components/home/home-view.tsx +128 -4
- package/src/components/input/chat-input.tsx +135 -86
- package/src/components/layout/app-layout.tsx +385 -194
- package/src/components/layout/mobile-header.tsx +26 -8
- package/src/components/memory/memory-browser.tsx +71 -6
- package/src/components/memory/memory-card.tsx +18 -0
- package/src/components/memory/memory-detail.tsx +58 -31
- package/src/components/memory/memory-sheet.tsx +32 -4
- package/src/components/plugins/plugin-list.tsx +15 -3
- package/src/components/plugins/plugin-sheet.tsx +118 -9
- package/src/components/projects/project-detail.tsx +189 -1
- package/src/components/providers/provider-list.tsx +158 -2
- package/src/components/providers/provider-sheet.tsx +81 -70
- package/src/components/shared/agent-picker-list.tsx +2 -2
- package/src/components/shared/bottom-sheet.tsx +31 -15
- package/src/components/shared/command-palette.tsx +111 -24
- package/src/components/shared/confirm-dialog.tsx +45 -30
- package/src/components/shared/model-combobox.tsx +90 -8
- package/src/components/shared/settings/plugin-manager.tsx +20 -4
- package/src/components/shared/settings/section-capability-policy.tsx +105 -0
- package/src/components/shared/settings/section-heartbeat.tsx +88 -6
- package/src/components/shared/settings/section-orchestrator.tsx +6 -3
- package/src/components/shared/settings/section-runtime-loop.tsx +5 -5
- package/src/components/shared/settings/section-secrets.tsx +6 -6
- package/src/components/shared/settings/section-user-preferences.tsx +1 -1
- package/src/components/shared/settings/section-voice.tsx +5 -1
- package/src/components/shared/settings/section-web-search.tsx +10 -2
- package/src/components/shared/settings/settings-page.tsx +248 -47
- package/src/components/tasks/approvals-panel.tsx +211 -18
- package/src/components/tasks/task-board.tsx +242 -46
- package/src/components/ui/dialog.tsx +2 -2
- package/src/components/usage/metrics-dashboard.tsx +74 -1
- package/src/components/wallets/wallet-approval-dialog.tsx +59 -54
- package/src/components/wallets/wallet-panel.tsx +17 -5
- package/src/components/webhooks/webhook-sheet.tsx +7 -7
- package/src/lib/auth.ts +17 -0
- package/src/lib/chat-streaming-state.test.ts +108 -0
- package/src/lib/chat-streaming-state.ts +108 -0
- package/src/lib/heartbeat-defaults.ts +48 -0
- package/src/lib/memory-presentation.ts +59 -0
- package/src/lib/openclaw-agent-id.test.ts +14 -0
- package/src/lib/openclaw-agent-id.ts +31 -0
- package/src/lib/provider-model-discovery-client.ts +29 -0
- package/src/lib/providers/index.ts +12 -5
- package/src/lib/runtime-loop.ts +105 -3
- package/src/lib/safe-storage.ts +6 -1
- package/src/lib/server/agent-assignment.test.ts +112 -0
- package/src/lib/server/agent-assignment.ts +169 -0
- package/src/lib/server/agent-runtime-config.test.ts +141 -0
- package/src/lib/server/agent-runtime-config.ts +277 -0
- package/src/lib/server/approval-connector-notify.test.ts +253 -0
- package/src/lib/server/approvals-auto-approve.test.ts +264 -0
- package/src/lib/server/approvals.ts +483 -75
- package/src/lib/server/autonomy-runtime.test.ts +341 -0
- package/src/lib/server/browser-state.test.ts +118 -0
- package/src/lib/server/browser-state.ts +123 -0
- package/src/lib/server/build-llm.test.ts +44 -0
- package/src/lib/server/build-llm.ts +11 -4
- package/src/lib/server/builtin-plugins.ts +34 -0
- package/src/lib/server/chat-execution-heartbeat.test.ts +40 -0
- package/src/lib/server/chat-execution-tool-events.test.ts +219 -0
- package/src/lib/server/chat-execution.ts +402 -125
- package/src/lib/server/chatroom-health.test.ts +26 -0
- package/src/lib/server/chatroom-health.ts +2 -3
- package/src/lib/server/chatroom-helpers.test.ts +74 -2
- package/src/lib/server/chatroom-helpers.ts +144 -11
- package/src/lib/server/chatroom-session-persistence.test.ts +87 -0
- package/src/lib/server/connectors/discord.ts +175 -11
- package/src/lib/server/connectors/doctor.test.ts +80 -0
- package/src/lib/server/connectors/doctor.ts +116 -0
- package/src/lib/server/connectors/manager.ts +994 -130
- package/src/lib/server/connectors/policy.test.ts +222 -0
- package/src/lib/server/connectors/policy.ts +452 -0
- package/src/lib/server/connectors/slack.ts +189 -10
- package/src/lib/server/connectors/telegram.ts +65 -15
- package/src/lib/server/connectors/thread-context.test.ts +44 -0
- package/src/lib/server/connectors/thread-context.ts +72 -0
- package/src/lib/server/connectors/types.ts +41 -11
- package/src/lib/server/daemon-state.ts +62 -3
- package/src/lib/server/data-dir.ts +13 -0
- package/src/lib/server/delegation-jobs.test.ts +140 -0
- package/src/lib/server/delegation-jobs.ts +248 -0
- package/src/lib/server/document-utils.test.ts +47 -0
- package/src/lib/server/document-utils.ts +397 -0
- package/src/lib/server/eval/agent-regression.test.ts +47 -0
- package/src/lib/server/eval/agent-regression.ts +1742 -0
- package/src/lib/server/eval/runner.ts +11 -1
- package/src/lib/server/eval/store.ts +2 -1
- package/src/lib/server/heartbeat-service.ts +23 -43
- package/src/lib/server/heartbeat-source.test.ts +22 -0
- package/src/lib/server/heartbeat-source.ts +7 -0
- package/src/lib/server/identity-continuity.test.ts +77 -0
- package/src/lib/server/identity-continuity.ts +127 -0
- package/src/lib/server/mailbox-utils.ts +347 -0
- package/src/lib/server/main-agent-loop.ts +31 -964
- package/src/lib/server/memory-db.ts +4 -6
- package/src/lib/server/memory-tiers.ts +40 -0
- package/src/lib/server/openclaw-agent-resolver.test.ts +70 -0
- package/src/lib/server/openclaw-agent-resolver.ts +128 -0
- package/src/lib/server/openclaw-exec-config.ts +6 -5
- package/src/lib/server/openclaw-gateway.ts +123 -36
- package/src/lib/server/openclaw-skills-normalize.test.ts +56 -0
- package/src/lib/server/openclaw-skills-normalize.ts +136 -0
- package/src/lib/server/openclaw-sync.ts +3 -2
- package/src/lib/server/orchestrator-lg.ts +18 -8
- package/src/lib/server/orchestrator.ts +5 -4
- package/src/lib/server/playwright-proxy.mjs +27 -3
- package/src/lib/server/plugins.test.ts +215 -0
- package/src/lib/server/plugins.ts +832 -69
- package/src/lib/server/provider-health.ts +33 -3
- package/src/lib/server/provider-model-discovery.ts +481 -0
- package/src/lib/server/queue.ts +4 -21
- package/src/lib/server/runtime-settings.test.ts +119 -0
- package/src/lib/server/runtime-settings.ts +12 -92
- package/src/lib/server/schedule-normalization.ts +187 -0
- package/src/lib/server/scheduler.ts +2 -0
- package/src/lib/server/session-archive-memory.test.ts +85 -0
- package/src/lib/server/session-archive-memory.ts +230 -0
- package/src/lib/server/session-mailbox.ts +8 -18
- package/src/lib/server/session-reset-policy.test.ts +99 -0
- package/src/lib/server/session-reset-policy.ts +311 -0
- package/src/lib/server/session-run-manager.ts +33 -80
- package/src/lib/server/session-tools/autonomy-tools.test.ts +128 -0
- package/src/lib/server/session-tools/calendar.ts +2 -12
- package/src/lib/server/session-tools/connector.ts +109 -8
- package/src/lib/server/session-tools/context.ts +14 -2
- package/src/lib/server/session-tools/crawl.ts +447 -0
- package/src/lib/server/session-tools/crud.ts +96 -34
- package/src/lib/server/session-tools/delegate-fallback.test.ts +219 -0
- package/src/lib/server/session-tools/delegate.ts +406 -20
- package/src/lib/server/session-tools/discovery-approvals.test.ts +170 -0
- package/src/lib/server/session-tools/discovery.ts +40 -12
- package/src/lib/server/session-tools/document.ts +283 -0
- package/src/lib/server/session-tools/email.ts +1 -3
- package/src/lib/server/session-tools/extract.ts +137 -0
- package/src/lib/server/session-tools/file-normalize.test.ts +98 -0
- package/src/lib/server/session-tools/file-send.test.ts +84 -1
- package/src/lib/server/session-tools/file.ts +243 -24
- package/src/lib/server/session-tools/http.ts +9 -3
- package/src/lib/server/session-tools/human-loop.ts +227 -0
- package/src/lib/server/session-tools/image-gen.ts +1 -3
- package/src/lib/server/session-tools/index.ts +87 -2
- package/src/lib/server/session-tools/mailbox.ts +276 -0
- package/src/lib/server/session-tools/manage-schedules.test.ts +137 -0
- package/src/lib/server/session-tools/memory.ts +35 -3
- package/src/lib/server/session-tools/monitor.ts +162 -12
- package/src/lib/server/session-tools/normalize-tool-args.ts +17 -14
- package/src/lib/server/session-tools/openclaw-nodes.test.ts +111 -0
- package/src/lib/server/session-tools/openclaw-nodes.ts +86 -20
- package/src/lib/server/session-tools/platform-normalize.test.ts +142 -0
- package/src/lib/server/session-tools/platform.ts +142 -4
- package/src/lib/server/session-tools/plugin-creator.ts +95 -25
- package/src/lib/server/session-tools/primitive-tools.test.ts +257 -0
- package/src/lib/server/session-tools/replicate.ts +1 -3
- package/src/lib/server/session-tools/sandbox.ts +51 -92
- package/src/lib/server/session-tools/schedule.ts +20 -10
- package/src/lib/server/session-tools/session-info.ts +58 -4
- package/src/lib/server/session-tools/session-tools-wiring.test.ts +54 -17
- package/src/lib/server/session-tools/shell.ts +2 -2
- package/src/lib/server/session-tools/subagent.ts +195 -27
- package/src/lib/server/session-tools/table.ts +587 -0
- package/src/lib/server/session-tools/wallet.ts +13 -10
- package/src/lib/server/session-tools/web-browser-config.test.ts +39 -0
- package/src/lib/server/session-tools/web.ts +947 -108
- package/src/lib/server/storage.ts +255 -10
- package/src/lib/server/stream-agent-chat.test.ts +61 -0
- package/src/lib/server/stream-agent-chat.ts +185 -25
- package/src/lib/server/structured-extract.test.ts +72 -0
- package/src/lib/server/structured-extract.ts +373 -0
- package/src/lib/server/task-mention.test.ts +16 -2
- package/src/lib/server/task-mention.ts +61 -11
- package/src/lib/server/tool-aliases.ts +80 -12
- package/src/lib/server/tool-capability-policy.ts +7 -1
- package/src/lib/server/tool-retry.ts +2 -0
- package/src/lib/server/watch-jobs.test.ts +173 -0
- package/src/lib/server/watch-jobs.ts +532 -0
- package/src/lib/server/ws-hub.ts +5 -3
- package/src/lib/setup-defaults.ts +352 -11
- package/src/lib/tool-definitions.ts +3 -4
- package/src/lib/validation/schemas.test.ts +26 -0
- package/src/lib/validation/schemas.ts +62 -1
- package/src/lib/ws-client.ts +14 -12
- package/src/proxy.ts +5 -5
- package/src/stores/use-app-store.ts +43 -7
- package/src/stores/use-chat-store.ts +31 -2
- package/src/stores/use-chatroom-store.ts +153 -26
- package/src/types/index.ts +470 -44
- package/src/app/api/chats/[id]/main-loop/route.ts +0 -94
- package/src/components/chat/new-chat-sheet.tsx +0 -253
- package/src/lib/server/main-session.ts +0 -17
- package/src/lib/server/session-run-manager.test.ts +0 -26
|
@@ -7,7 +7,7 @@ import { api } from '@/lib/api-client'
|
|
|
7
7
|
import { BottomSheet } from '@/components/shared/bottom-sheet'
|
|
8
8
|
import { toast } from 'sonner'
|
|
9
9
|
import { ModelCombobox } from '@/components/shared/model-combobox'
|
|
10
|
-
import type { ProviderType, ClaudeSkill, AgentWallet } from '@/types'
|
|
10
|
+
import type { ProviderType, ClaudeSkill, AgentWallet, AgentPackManifest, AgentRoutingStrategy, AgentRoutingTarget } from '@/types'
|
|
11
11
|
import { WalletSection } from '@/components/wallets/wallet-section'
|
|
12
12
|
import { AVAILABLE_TOOLS, PLATFORM_TOOLS } from '@/lib/tool-definitions'
|
|
13
13
|
import { NATIVE_CAPABILITY_PROVIDER_IDS, NON_LANGGRAPH_PROVIDER_IDS } from '@/lib/provider-sets'
|
|
@@ -54,6 +54,24 @@ function parseDurationToSec(interval: string | number | null | undefined, interv
|
|
|
54
54
|
return '' // default
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
function formatIdentityList(value: string[] | null | undefined): string {
|
|
58
|
+
return Array.isArray(value) ? value.join('\n') : ''
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function parseIdentityList(value: string): string[] {
|
|
62
|
+
const seen = new Set<string>()
|
|
63
|
+
return value
|
|
64
|
+
.split('\n')
|
|
65
|
+
.map((line) => line.replace(/\s+/g, ' ').trim())
|
|
66
|
+
.filter((line) => {
|
|
67
|
+
if (!line) return false
|
|
68
|
+
const key = line.toLowerCase()
|
|
69
|
+
if (seen.has(key)) return false
|
|
70
|
+
seen.add(key)
|
|
71
|
+
return true
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
57
75
|
export function AgentSheet() {
|
|
58
76
|
const open = useAppStore((s) => s.agentSheetOpen)
|
|
59
77
|
const setOpen = useAppStore((s) => s.setAgentSheetOpen)
|
|
@@ -65,6 +83,8 @@ export function AgentSheet() {
|
|
|
65
83
|
const loadProjects = useAppStore((s) => s.loadProjects)
|
|
66
84
|
const providers = useAppStore((s) => s.providers)
|
|
67
85
|
const loadProviders = useAppStore((s) => s.loadProviders)
|
|
86
|
+
const gatewayProfiles = useAppStore((s) => s.gatewayProfiles)
|
|
87
|
+
const loadGatewayProfiles = useAppStore((s) => s.loadGatewayProfiles)
|
|
68
88
|
const credentials = useAppStore((s) => s.credentials)
|
|
69
89
|
const loadCredentials = useAppStore((s) => s.loadCredentials)
|
|
70
90
|
const appSettings = useAppStore((s) => s.appSettings)
|
|
@@ -92,7 +112,10 @@ export function AgentSheet() {
|
|
|
92
112
|
const [model, setModel] = useState('')
|
|
93
113
|
const [credentialId, setCredentialId] = useState<string | null>(null)
|
|
94
114
|
const [apiEndpoint, setApiEndpoint] = useState<string | null>(null)
|
|
95
|
-
const [
|
|
115
|
+
const [gatewayProfileId, setGatewayProfileId] = useState<string | null>(null)
|
|
116
|
+
const [routingStrategy, setRoutingStrategy] = useState<AgentRoutingStrategy>('single')
|
|
117
|
+
const [routingTargets, setRoutingTargets] = useState<AgentRoutingTarget[]>([])
|
|
118
|
+
const [platformAssignScope, setPlatformAssignScope] = useState<'self' | 'all'>('self')
|
|
96
119
|
const [subAgentIds, setAgentAgentIds] = useState<string[]>([])
|
|
97
120
|
const [tools, setTools] = useState<string[]>([])
|
|
98
121
|
const [skills, setSkills] = useState<string[]>([])
|
|
@@ -111,12 +134,25 @@ export function AgentSheet() {
|
|
|
111
134
|
const [avatarUrl, setAvatarUrl] = useState<string | null>(null)
|
|
112
135
|
const [uploading, setUploading] = useState(false)
|
|
113
136
|
const [thinkingLevel, setThinkingLevel] = useState<'' | 'minimal' | 'low' | 'medium' | 'high'>('')
|
|
137
|
+
const [memoryScopeMode, setMemoryScopeMode] = useState<'auto' | 'all' | 'global' | 'agent' | 'session' | 'project'>('auto')
|
|
138
|
+
const [memoryTierPreference, setMemoryTierPreference] = useState<'working' | 'durable' | 'archive' | 'blended'>('blended')
|
|
114
139
|
const [autoRecovery, setAutoRecovery] = useState(false)
|
|
115
140
|
const [voiceId, setVoiceId] = useState('')
|
|
116
141
|
const [heartbeatEnabled, setHeartbeatEnabled] = useState(false)
|
|
117
142
|
const [heartbeatIntervalSec, setHeartbeatIntervalSec] = useState('') // '' = default (30m)
|
|
118
143
|
const [heartbeatModel, setHeartbeatModel] = useState('')
|
|
119
144
|
const [heartbeatPrompt, setHeartbeatPrompt] = useState('')
|
|
145
|
+
const [sessionResetMode, setSessionResetMode] = useState<'' | 'idle' | 'daily'>('')
|
|
146
|
+
const [sessionIdleTimeoutSec, setSessionIdleTimeoutSec] = useState('')
|
|
147
|
+
const [sessionMaxAgeSec, setSessionMaxAgeSec] = useState('')
|
|
148
|
+
const [sessionDailyResetAt, setSessionDailyResetAt] = useState('')
|
|
149
|
+
const [sessionResetTimezone, setSessionResetTimezone] = useState('')
|
|
150
|
+
const [identityPersonaLabel, setIdentityPersonaLabel] = useState('')
|
|
151
|
+
const [identitySelfSummary, setIdentitySelfSummary] = useState('')
|
|
152
|
+
const [identityRelationshipSummary, setIdentityRelationshipSummary] = useState('')
|
|
153
|
+
const [identityToneStyle, setIdentityToneStyle] = useState('')
|
|
154
|
+
const [identityBoundariesText, setIdentityBoundariesText] = useState('')
|
|
155
|
+
const [identityContinuityNotesText, setIdentityContinuityNotesText] = useState('')
|
|
120
156
|
const [budgetEnabled, setBudgetEnabled] = useState(false)
|
|
121
157
|
const [hourlyBudget, setHourlyBudget] = useState('')
|
|
122
158
|
const [dailyBudget, setDailyBudget] = useState('')
|
|
@@ -153,6 +189,7 @@ export function AgentSheet() {
|
|
|
153
189
|
const currentProvider = providers.find((p) => p.id === provider)
|
|
154
190
|
const providerCredentials = Object.values(credentials).filter((c) => c.provider === provider)
|
|
155
191
|
const openclawCredentials = Object.values(credentials).filter((c) => c.provider === 'openclaw')
|
|
192
|
+
const openclawGatewayProfiles = gatewayProfiles.filter((item) => item.provider === 'openclaw')
|
|
156
193
|
const editing = editingId ? agents[editingId] : null
|
|
157
194
|
const hasNativeCapabilities = NATIVE_CAPABILITY_PROVIDER_IDS.has(provider)
|
|
158
195
|
|
|
@@ -164,6 +201,7 @@ export function AgentSheet() {
|
|
|
164
201
|
useEffect(() => {
|
|
165
202
|
if (open) {
|
|
166
203
|
loadProviders()
|
|
204
|
+
loadGatewayProfiles()
|
|
167
205
|
loadCredentials()
|
|
168
206
|
loadSkills()
|
|
169
207
|
loadProjects()
|
|
@@ -181,7 +219,10 @@ export function AgentSheet() {
|
|
|
181
219
|
setModel(editing.model)
|
|
182
220
|
setCredentialId(editing.credentialId || null)
|
|
183
221
|
setApiEndpoint(editing.apiEndpoint || null)
|
|
184
|
-
|
|
222
|
+
setGatewayProfileId(editing.gatewayProfileId || null)
|
|
223
|
+
setRoutingStrategy(editing.routingStrategy || 'single')
|
|
224
|
+
setRoutingTargets(editing.routingTargets || [])
|
|
225
|
+
setPlatformAssignScope(editing.platformAssignScope || 'self')
|
|
185
226
|
setAgentAgentIds(editing.subAgentIds || [])
|
|
186
227
|
setTools(editing.plugins || [])
|
|
187
228
|
setSkills(editing.skills || [])
|
|
@@ -189,7 +230,6 @@ export function AgentSheet() {
|
|
|
189
230
|
setMcpServerIds(editing.mcpServerIds || [])
|
|
190
231
|
setMcpDisabledTools(editing.mcpDisabledTools || [])
|
|
191
232
|
setFallbackCredentialIds(editing.fallbackCredentialIds || [])
|
|
192
|
-
// platformAssignScope derived from isOrchestrator — no separate state
|
|
193
233
|
setCapabilities(Array.isArray(editing.capabilities) ? editing.capabilities : [])
|
|
194
234
|
setCapInput('')
|
|
195
235
|
setOllamaMode(editing.credentialId && editing.provider === 'ollama' ? 'cloud' : 'local')
|
|
@@ -198,12 +238,25 @@ export function AgentSheet() {
|
|
|
198
238
|
setAvatarSeed(editing.avatarSeed || crypto.randomUUID().slice(0, 8))
|
|
199
239
|
setAvatarUrl(editing.avatarUrl || null)
|
|
200
240
|
setThinkingLevel(editing.thinkingLevel || '')
|
|
241
|
+
setMemoryScopeMode(editing.memoryScopeMode || 'auto')
|
|
242
|
+
setMemoryTierPreference(editing.memoryTierPreference || 'blended')
|
|
201
243
|
setAutoRecovery(editing.autoRecovery || false)
|
|
202
244
|
setVoiceId(editing.elevenLabsVoiceId || '')
|
|
203
245
|
setHeartbeatEnabled(editing.heartbeatEnabled || false)
|
|
204
246
|
setHeartbeatIntervalSec(parseDurationToSec(editing.heartbeatInterval, editing.heartbeatIntervalSec))
|
|
205
247
|
setHeartbeatModel(editing.heartbeatModel || '')
|
|
206
248
|
setHeartbeatPrompt(editing.heartbeatPrompt || '')
|
|
249
|
+
setSessionResetMode(editing.sessionResetMode || '')
|
|
250
|
+
setSessionIdleTimeoutSec(editing.sessionIdleTimeoutSec != null ? String(editing.sessionIdleTimeoutSec) : '')
|
|
251
|
+
setSessionMaxAgeSec(editing.sessionMaxAgeSec != null ? String(editing.sessionMaxAgeSec) : '')
|
|
252
|
+
setSessionDailyResetAt(editing.sessionDailyResetAt || '')
|
|
253
|
+
setSessionResetTimezone(editing.sessionResetTimezone || '')
|
|
254
|
+
setIdentityPersonaLabel(editing.identityState?.personaLabel || '')
|
|
255
|
+
setIdentitySelfSummary(editing.identityState?.selfSummary || '')
|
|
256
|
+
setIdentityRelationshipSummary(editing.identityState?.relationshipSummary || '')
|
|
257
|
+
setIdentityToneStyle(editing.identityState?.toneStyle || '')
|
|
258
|
+
setIdentityBoundariesText(formatIdentityList(editing.identityState?.boundaries))
|
|
259
|
+
setIdentityContinuityNotesText(formatIdentityList(editing.identityState?.continuityNotes))
|
|
207
260
|
setBudgetEnabled(
|
|
208
261
|
(typeof editing.hourlyBudget === 'number' && editing.hourlyBudget > 0)
|
|
209
262
|
|| (typeof editing.dailyBudget === 'number' && editing.dailyBudget > 0)
|
|
@@ -233,7 +286,10 @@ export function AgentSheet() {
|
|
|
233
286
|
setModel('')
|
|
234
287
|
setCredentialId(null)
|
|
235
288
|
setApiEndpoint(null)
|
|
236
|
-
|
|
289
|
+
setGatewayProfileId(null)
|
|
290
|
+
setRoutingStrategy('single')
|
|
291
|
+
setRoutingTargets([])
|
|
292
|
+
setPlatformAssignScope('self')
|
|
237
293
|
setAgentAgentIds([])
|
|
238
294
|
setTools([])
|
|
239
295
|
setSkills([])
|
|
@@ -247,12 +303,25 @@ export function AgentSheet() {
|
|
|
247
303
|
setProjectId(undefined)
|
|
248
304
|
setAvatarSeed('')
|
|
249
305
|
setThinkingLevel('')
|
|
306
|
+
setMemoryScopeMode('auto')
|
|
307
|
+
setMemoryTierPreference('blended')
|
|
250
308
|
setAutoRecovery(false)
|
|
251
309
|
setVoiceId('')
|
|
252
310
|
setHeartbeatEnabled(false)
|
|
253
311
|
setHeartbeatIntervalSec('')
|
|
254
312
|
setHeartbeatModel('')
|
|
255
313
|
setHeartbeatPrompt('')
|
|
314
|
+
setSessionResetMode('')
|
|
315
|
+
setSessionIdleTimeoutSec('')
|
|
316
|
+
setSessionMaxAgeSec('')
|
|
317
|
+
setSessionDailyResetAt('')
|
|
318
|
+
setSessionResetTimezone('')
|
|
319
|
+
setIdentityPersonaLabel('')
|
|
320
|
+
setIdentitySelfSummary('')
|
|
321
|
+
setIdentityRelationshipSummary('')
|
|
322
|
+
setIdentityToneStyle('')
|
|
323
|
+
setIdentityBoundariesText('')
|
|
324
|
+
setIdentityContinuityNotesText('')
|
|
256
325
|
setBudgetEnabled(false)
|
|
257
326
|
setHourlyBudget('')
|
|
258
327
|
setDailyBudget('')
|
|
@@ -319,6 +388,45 @@ export function AgentSheet() {
|
|
|
319
388
|
setEditingId(null)
|
|
320
389
|
}
|
|
321
390
|
|
|
391
|
+
const applyGatewayProfileSelection = (nextGatewayProfileId: string | null) => {
|
|
392
|
+
setGatewayProfileId(nextGatewayProfileId)
|
|
393
|
+
const gateway = openclawGatewayProfiles.find((item) => item.id === nextGatewayProfileId)
|
|
394
|
+
if (!gateway) return
|
|
395
|
+
setProvider('openclaw')
|
|
396
|
+
setOpenclawEnabled(true)
|
|
397
|
+
setApiEndpoint(gateway.endpoint)
|
|
398
|
+
if (gateway.credentialId) setCredentialId(gateway.credentialId)
|
|
399
|
+
if (!model) setModel('default')
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const updateRoutingTarget = (targetId: string, patch: Partial<AgentRoutingTarget>) => {
|
|
403
|
+
setRoutingTargets((current) => current.map((target) => (
|
|
404
|
+
target.id === targetId
|
|
405
|
+
? { ...target, ...patch }
|
|
406
|
+
: target
|
|
407
|
+
)))
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const removeRoutingTarget = (targetId: string) => {
|
|
411
|
+
setRoutingTargets((current) => current.filter((target) => target.id !== targetId))
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const addRoutingTargetFromCurrent = () => {
|
|
415
|
+
const nextTarget: AgentRoutingTarget = {
|
|
416
|
+
id: crypto.randomUUID(),
|
|
417
|
+
label: routingTargets.length === 0 ? 'Primary route' : `Route ${routingTargets.length + 1}`,
|
|
418
|
+
role: routingTargets.length === 0 ? 'primary' : 'backup',
|
|
419
|
+
provider,
|
|
420
|
+
model,
|
|
421
|
+
credentialId,
|
|
422
|
+
fallbackCredentialIds,
|
|
423
|
+
apiEndpoint,
|
|
424
|
+
gatewayProfileId,
|
|
425
|
+
priority: routingTargets.length + 1,
|
|
426
|
+
}
|
|
427
|
+
setRoutingTargets((current) => [...current, nextTarget])
|
|
428
|
+
}
|
|
429
|
+
|
|
322
430
|
const handleSave = async () => {
|
|
323
431
|
// For any endpoint, just ensure bare host:port gets a protocol prepended
|
|
324
432
|
let normalizedEndpoint = apiEndpoint
|
|
@@ -329,6 +437,22 @@ export function AgentSheet() {
|
|
|
329
437
|
const parsedHourlyBudget = budgetEnabled && hourlyBudget ? Number(hourlyBudget) : null
|
|
330
438
|
const parsedDailyBudget = budgetEnabled && dailyBudget ? Number(dailyBudget) : null
|
|
331
439
|
const parsedMonthlyBudget = budgetEnabled && monthlyBudget ? Number(monthlyBudget) : null
|
|
440
|
+
const parsedSessionIdleTimeoutSec = sessionIdleTimeoutSec ? Number(sessionIdleTimeoutSec) : null
|
|
441
|
+
const parsedSessionMaxAgeSec = sessionMaxAgeSec ? Number(sessionMaxAgeSec) : null
|
|
442
|
+
const identityBoundaries = parseIdentityList(identityBoundariesText)
|
|
443
|
+
const identityContinuityNotes = parseIdentityList(identityContinuityNotesText)
|
|
444
|
+
const identityState = (() => {
|
|
445
|
+
const value = {
|
|
446
|
+
personaLabel: identityPersonaLabel.trim() || undefined,
|
|
447
|
+
selfSummary: identitySelfSummary.trim() || undefined,
|
|
448
|
+
relationshipSummary: identityRelationshipSummary.trim() || undefined,
|
|
449
|
+
toneStyle: identityToneStyle.trim() || undefined,
|
|
450
|
+
boundaries: identityBoundaries.length ? identityBoundaries : undefined,
|
|
451
|
+
continuityNotes: identityContinuityNotes.length ? identityContinuityNotes : undefined,
|
|
452
|
+
}
|
|
453
|
+
return Object.values(value).some((entry) => Array.isArray(entry) ? entry.length > 0 : Boolean(entry)) ? value : null
|
|
454
|
+
})()
|
|
455
|
+
const canDelegateToAgents = platformAssignScope === 'all'
|
|
332
456
|
const data = {
|
|
333
457
|
name: name.trim() || 'Unnamed Agent',
|
|
334
458
|
description,
|
|
@@ -338,20 +462,27 @@ export function AgentSheet() {
|
|
|
338
462
|
model,
|
|
339
463
|
credentialId,
|
|
340
464
|
apiEndpoint: normalizedEndpoint,
|
|
341
|
-
|
|
342
|
-
|
|
465
|
+
gatewayProfileId,
|
|
466
|
+
routingStrategy,
|
|
467
|
+
routingTargets: routingTargets.map((target, index) => ({
|
|
468
|
+
...target,
|
|
469
|
+
priority: typeof target.priority === 'number' ? target.priority : index + 1,
|
|
470
|
+
})),
|
|
471
|
+
subAgentIds: canDelegateToAgents ? subAgentIds : [],
|
|
343
472
|
tools,
|
|
344
473
|
skills,
|
|
345
474
|
skillIds,
|
|
346
475
|
mcpServerIds,
|
|
347
476
|
mcpDisabledTools: mcpDisabledTools.length ? mcpDisabledTools : undefined,
|
|
348
477
|
fallbackCredentialIds,
|
|
349
|
-
platformAssignScope
|
|
478
|
+
platformAssignScope,
|
|
350
479
|
capabilities,
|
|
351
480
|
projectId: projectId || undefined,
|
|
352
481
|
avatarSeed: avatarSeed.trim() || undefined,
|
|
353
482
|
avatarUrl: avatarUrl || null,
|
|
354
483
|
thinkingLevel: thinkingLevel || undefined,
|
|
484
|
+
memoryScopeMode,
|
|
485
|
+
memoryTierPreference,
|
|
355
486
|
autoRecovery,
|
|
356
487
|
elevenLabsVoiceId: voiceId.trim() || null,
|
|
357
488
|
heartbeatEnabled,
|
|
@@ -359,6 +490,12 @@ export function AgentSheet() {
|
|
|
359
490
|
heartbeatIntervalSec: heartbeatIntervalSec ? Number(heartbeatIntervalSec) : null,
|
|
360
491
|
heartbeatModel: heartbeatModel.trim() || null,
|
|
361
492
|
heartbeatPrompt: heartbeatPrompt.trim() || null,
|
|
493
|
+
identityState,
|
|
494
|
+
sessionResetMode: sessionResetMode || null,
|
|
495
|
+
sessionIdleTimeoutSec: Number.isFinite(parsedSessionIdleTimeoutSec) && parsedSessionIdleTimeoutSec! >= 0 ? parsedSessionIdleTimeoutSec : null,
|
|
496
|
+
sessionMaxAgeSec: Number.isFinite(parsedSessionMaxAgeSec) && parsedSessionMaxAgeSec! >= 0 ? parsedSessionMaxAgeSec : null,
|
|
497
|
+
sessionDailyResetAt: sessionDailyResetAt.trim() || null,
|
|
498
|
+
sessionResetTimezone: sessionResetTimezone.trim() || null,
|
|
362
499
|
hourlyBudget: parsedHourlyBudget && parsedHourlyBudget > 0 ? parsedHourlyBudget : null,
|
|
363
500
|
dailyBudget: parsedDailyBudget && parsedDailyBudget > 0 ? parsedDailyBudget : null,
|
|
364
501
|
monthlyBudget: parsedMonthlyBudget && parsedMonthlyBudget > 0 ? parsedMonthlyBudget : null,
|
|
@@ -389,15 +526,40 @@ export function AgentSheet() {
|
|
|
389
526
|
|
|
390
527
|
const handleExport = () => {
|
|
391
528
|
if (!editing) return
|
|
392
|
-
const
|
|
393
|
-
|
|
529
|
+
const pack: AgentPackManifest = {
|
|
530
|
+
schemaVersion: 1,
|
|
531
|
+
kind: 'swarmclaw-agent-pack',
|
|
532
|
+
name: `${editing.name} Pack`,
|
|
533
|
+
description: editing.description || undefined,
|
|
534
|
+
exportedAt: Date.now(),
|
|
535
|
+
recommendedProviders: [editing.provider],
|
|
536
|
+
agents: [{
|
|
537
|
+
id: editing.name.replace(/\s+/g, '-').toLowerCase(),
|
|
538
|
+
name: editing.name,
|
|
539
|
+
description: editing.description || undefined,
|
|
540
|
+
provider: editing.provider,
|
|
541
|
+
model: editing.model,
|
|
542
|
+
credentialId: editing.credentialId || null,
|
|
543
|
+
fallbackCredentialIds: editing.fallbackCredentialIds || [],
|
|
544
|
+
apiEndpoint: editing.apiEndpoint || null,
|
|
545
|
+
gatewayProfileId: editing.gatewayProfileId || null,
|
|
546
|
+
routingStrategy: editing.routingStrategy || null,
|
|
547
|
+
routingTargets: editing.routingTargets || [],
|
|
548
|
+
tools: editing.tools,
|
|
549
|
+
plugins: editing.plugins,
|
|
550
|
+
capabilities: editing.capabilities,
|
|
551
|
+
soul: editing.soul,
|
|
552
|
+
systemPrompt: editing.systemPrompt,
|
|
553
|
+
}],
|
|
554
|
+
}
|
|
555
|
+
const blob = new Blob([JSON.stringify(pack, null, 2)], { type: 'application/json' })
|
|
394
556
|
const url = URL.createObjectURL(blob)
|
|
395
557
|
const a = document.createElement('a')
|
|
396
558
|
a.href = url
|
|
397
|
-
a.download = `${editing.name.replace(/[^a-zA-Z0-9_-]/g, '_')}.agent.json`
|
|
559
|
+
a.download = `${editing.name.replace(/[^a-zA-Z0-9_-]/g, '_')}.agent-pack.json`
|
|
398
560
|
a.click()
|
|
399
561
|
URL.revokeObjectURL(url)
|
|
400
|
-
toast.success('Agent exported')
|
|
562
|
+
toast.success('Agent pack exported')
|
|
401
563
|
}
|
|
402
564
|
|
|
403
565
|
const handleImport = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
@@ -407,11 +569,15 @@ export function AgentSheet() {
|
|
|
407
569
|
reader.onload = async (ev) => {
|
|
408
570
|
try {
|
|
409
571
|
const data = JSON.parse(ev.target?.result as string)
|
|
572
|
+
const importedAgent = data?.kind === 'swarmclaw-agent-pack'
|
|
573
|
+
? data?.agents?.[0]
|
|
574
|
+
: data
|
|
575
|
+
if (!importedAgent || typeof importedAgent !== 'object') throw new Error('Invalid agent pack')
|
|
410
576
|
// Strip IDs and timestamps
|
|
411
|
-
const { id: _id, createdAt: _ca, updatedAt: _ua, threadSessionId: _ts, ...agentData } =
|
|
577
|
+
const { id: _id, createdAt: _ca, updatedAt: _ua, threadSessionId: _ts, ...agentData } = importedAgent
|
|
412
578
|
await createAgent({ ...agentData, name: agentData.name || 'Imported Agent' })
|
|
413
579
|
await loadAgents()
|
|
414
|
-
toast.success('Agent imported')
|
|
580
|
+
toast.success(data?.kind === 'swarmclaw-agent-pack' ? 'Agent pack imported' : 'Agent imported')
|
|
415
581
|
onClose()
|
|
416
582
|
} catch (err) {
|
|
417
583
|
toast.error('Invalid agent JSON file')
|
|
@@ -473,7 +639,8 @@ export function AgentSheet() {
|
|
|
473
639
|
setSaving(false)
|
|
474
640
|
}
|
|
475
641
|
|
|
476
|
-
const
|
|
642
|
+
const canDelegateToAgents = platformAssignScope === 'all'
|
|
643
|
+
const agentOptions = Object.values(agents).filter((p) => p.id !== editingId)
|
|
477
644
|
|
|
478
645
|
const toggleAgent = (id: string) => {
|
|
479
646
|
setAgentAgentIds((prev) =>
|
|
@@ -491,7 +658,7 @@ export function AgentSheet() {
|
|
|
491
658
|
<h2 className="font-display text-[28px] font-700 tracking-[-0.03em] mb-2">
|
|
492
659
|
{editing ? 'Edit Agent' : 'New Agent'}
|
|
493
660
|
</h2>
|
|
494
|
-
<p className="text-[14px] text-text-3">Define an AI agent
|
|
661
|
+
<p className="text-[14px] text-text-3">Define an AI agent and optional multi-agent delegation behavior</p>
|
|
495
662
|
</div>
|
|
496
663
|
<div className="flex items-center gap-3 mt-1.5">
|
|
497
664
|
<label className="text-[11px] font-600 text-text-3 uppercase tracking-[0.08em]">OpenClaw</label>
|
|
@@ -510,6 +677,7 @@ export function AgentSheet() {
|
|
|
510
677
|
setModel('')
|
|
511
678
|
setApiEndpoint(null)
|
|
512
679
|
setCredentialId(null)
|
|
680
|
+
setGatewayProfileId(null)
|
|
513
681
|
setTestStatus('idle')
|
|
514
682
|
setTestMessage('')
|
|
515
683
|
setTestErrorCode(null)
|
|
@@ -699,6 +867,29 @@ export function AgentSheet() {
|
|
|
699
867
|
<p className="text-[11px] text-text-3/70 mt-1.5">Controls reasoning depth. Anthropic models use extended thinking; OpenAI o-series uses reasoning_effort. Others get system prompt guidance.</p>
|
|
700
868
|
</div>
|
|
701
869
|
|
|
870
|
+
<div className="mb-8">
|
|
871
|
+
<label className="flex items-center gap-2 font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
872
|
+
Memory Defaults <HintTip text="Controls where this agent should look first and which memory tier it should favor when writing or recalling context." />
|
|
873
|
+
</label>
|
|
874
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
875
|
+
<select value={memoryScopeMode} onChange={(e) => setMemoryScopeMode(e.target.value as typeof memoryScopeMode)} className={inputClass}>
|
|
876
|
+
<option value="auto">Scope: Auto</option>
|
|
877
|
+
<option value="all">Scope: All memories</option>
|
|
878
|
+
<option value="global">Scope: Global only</option>
|
|
879
|
+
<option value="agent">Scope: Agent memories</option>
|
|
880
|
+
<option value="session">Scope: Session memories</option>
|
|
881
|
+
<option value="project">Scope: Project memories</option>
|
|
882
|
+
</select>
|
|
883
|
+
<select value={memoryTierPreference} onChange={(e) => setMemoryTierPreference(e.target.value as typeof memoryTierPreference)} className={inputClass}>
|
|
884
|
+
<option value="blended">Tier: Blended</option>
|
|
885
|
+
<option value="working">Tier: Working</option>
|
|
886
|
+
<option value="durable">Tier: Durable</option>
|
|
887
|
+
<option value="archive">Tier: Archive</option>
|
|
888
|
+
</select>
|
|
889
|
+
</div>
|
|
890
|
+
<p className="text-[11px] text-text-3/70 mt-1.5">Use working for fast recent context, durable for facts/preferences, and archive for long-lived history.</p>
|
|
891
|
+
</div>
|
|
892
|
+
|
|
702
893
|
{/* Auto-Recovery */}
|
|
703
894
|
<div className="mb-8">
|
|
704
895
|
<div className="flex items-center justify-between mb-1.5">
|
|
@@ -981,9 +1172,147 @@ export function AgentSheet() {
|
|
|
981
1172
|
</div>
|
|
982
1173
|
)}
|
|
983
1174
|
|
|
1175
|
+
<div className="mb-8">
|
|
1176
|
+
<label className="flex items-center gap-2 font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
1177
|
+
Identity Continuity <HintTip text="Seeds the agent's continuity state so session memory can preserve a stable persona and relationship context." />
|
|
1178
|
+
</label>
|
|
1179
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 mb-3">
|
|
1180
|
+
<input
|
|
1181
|
+
type="text"
|
|
1182
|
+
value={identityPersonaLabel}
|
|
1183
|
+
onChange={(e) => setIdentityPersonaLabel(e.target.value)}
|
|
1184
|
+
placeholder="Persona label"
|
|
1185
|
+
className={inputClass}
|
|
1186
|
+
style={{ fontFamily: 'inherit' }}
|
|
1187
|
+
/>
|
|
1188
|
+
<input
|
|
1189
|
+
type="text"
|
|
1190
|
+
value={identityToneStyle}
|
|
1191
|
+
onChange={(e) => setIdentityToneStyle(e.target.value)}
|
|
1192
|
+
placeholder="Tone style"
|
|
1193
|
+
className={inputClass}
|
|
1194
|
+
style={{ fontFamily: 'inherit' }}
|
|
1195
|
+
/>
|
|
1196
|
+
</div>
|
|
1197
|
+
<div className="grid grid-cols-1 gap-3">
|
|
1198
|
+
<textarea
|
|
1199
|
+
value={identitySelfSummary}
|
|
1200
|
+
onChange={(e) => setIdentitySelfSummary(e.target.value)}
|
|
1201
|
+
placeholder="How this agent should summarize itself across sessions."
|
|
1202
|
+
rows={3}
|
|
1203
|
+
className={`${inputClass} resize-y min-h-[84px]`}
|
|
1204
|
+
style={{ fontFamily: 'inherit' }}
|
|
1205
|
+
/>
|
|
1206
|
+
<textarea
|
|
1207
|
+
value={identityRelationshipSummary}
|
|
1208
|
+
onChange={(e) => setIdentityRelationshipSummary(e.target.value)}
|
|
1209
|
+
placeholder="Relationship framing or standing context the agent should keep in mind."
|
|
1210
|
+
rows={3}
|
|
1211
|
+
className={`${inputClass} resize-y min-h-[84px]`}
|
|
1212
|
+
style={{ fontFamily: 'inherit' }}
|
|
1213
|
+
/>
|
|
1214
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
1215
|
+
<textarea
|
|
1216
|
+
value={identityBoundariesText}
|
|
1217
|
+
onChange={(e) => setIdentityBoundariesText(e.target.value)}
|
|
1218
|
+
placeholder="Boundaries, one per line."
|
|
1219
|
+
rows={4}
|
|
1220
|
+
className={`${inputClass} resize-y min-h-[108px]`}
|
|
1221
|
+
style={{ fontFamily: 'inherit' }}
|
|
1222
|
+
/>
|
|
1223
|
+
<textarea
|
|
1224
|
+
value={identityContinuityNotesText}
|
|
1225
|
+
onChange={(e) => setIdentityContinuityNotesText(e.target.value)}
|
|
1226
|
+
placeholder="Continuity notes, one per line."
|
|
1227
|
+
rows={4}
|
|
1228
|
+
className={`${inputClass} resize-y min-h-[108px]`}
|
|
1229
|
+
style={{ fontFamily: 'inherit' }}
|
|
1230
|
+
/>
|
|
1231
|
+
</div>
|
|
1232
|
+
</div>
|
|
1233
|
+
<p className="text-[12px] text-text-3/60 mt-2 leading-[1.5]">
|
|
1234
|
+
Use one line per item. Boundaries are stable guardrails; continuity notes are recurring relationship or project context worth carrying across sessions.
|
|
1235
|
+
</p>
|
|
1236
|
+
</div>
|
|
1237
|
+
|
|
1238
|
+
<div className="mb-8">
|
|
1239
|
+
<label className="flex items-center gap-2 font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
1240
|
+
Session Reset Policy <HintTip text="Controls when this agent's sessions are considered stale and should be refreshed." />
|
|
1241
|
+
</label>
|
|
1242
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 mb-3">
|
|
1243
|
+
<div>
|
|
1244
|
+
<select
|
|
1245
|
+
value={sessionResetMode}
|
|
1246
|
+
onChange={(e) => setSessionResetMode(e.target.value as typeof sessionResetMode)}
|
|
1247
|
+
className={inputClass}
|
|
1248
|
+
style={{ fontFamily: 'inherit' }}
|
|
1249
|
+
>
|
|
1250
|
+
<option value="">Inherit global default</option>
|
|
1251
|
+
<option value="idle">Idle</option>
|
|
1252
|
+
<option value="daily">Daily</option>
|
|
1253
|
+
</select>
|
|
1254
|
+
</div>
|
|
1255
|
+
<div>
|
|
1256
|
+
<input
|
|
1257
|
+
type="number"
|
|
1258
|
+
min={0}
|
|
1259
|
+
value={sessionIdleTimeoutSec}
|
|
1260
|
+
onChange={(e) => setSessionIdleTimeoutSec(e.target.value)}
|
|
1261
|
+
placeholder="Idle timeout in seconds"
|
|
1262
|
+
className={inputClass}
|
|
1263
|
+
style={{ fontFamily: 'inherit' }}
|
|
1264
|
+
/>
|
|
1265
|
+
</div>
|
|
1266
|
+
</div>
|
|
1267
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
|
|
1268
|
+
<input
|
|
1269
|
+
type="number"
|
|
1270
|
+
min={0}
|
|
1271
|
+
value={sessionMaxAgeSec}
|
|
1272
|
+
onChange={(e) => setSessionMaxAgeSec(e.target.value)}
|
|
1273
|
+
placeholder="Max age in seconds"
|
|
1274
|
+
className={inputClass}
|
|
1275
|
+
style={{ fontFamily: 'inherit' }}
|
|
1276
|
+
/>
|
|
1277
|
+
<input
|
|
1278
|
+
type="text"
|
|
1279
|
+
value={sessionDailyResetAt}
|
|
1280
|
+
onChange={(e) => setSessionDailyResetAt(e.target.value)}
|
|
1281
|
+
placeholder="Daily reset time (HH:MM)"
|
|
1282
|
+
className={inputClass}
|
|
1283
|
+
style={{ fontFamily: 'inherit' }}
|
|
1284
|
+
/>
|
|
1285
|
+
<input
|
|
1286
|
+
type="text"
|
|
1287
|
+
value={sessionResetTimezone}
|
|
1288
|
+
onChange={(e) => setSessionResetTimezone(e.target.value)}
|
|
1289
|
+
placeholder="Timezone (optional)"
|
|
1290
|
+
className={inputClass}
|
|
1291
|
+
style={{ fontFamily: 'inherit' }}
|
|
1292
|
+
/>
|
|
1293
|
+
</div>
|
|
1294
|
+
</div>
|
|
1295
|
+
|
|
984
1296
|
{/* OpenClaw Gateway Fields */}
|
|
985
1297
|
{openclawEnabled && (
|
|
986
1298
|
<div className="mb-8 space-y-5">
|
|
1299
|
+
{openclawGatewayProfiles.length > 0 && (
|
|
1300
|
+
<div>
|
|
1301
|
+
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">Gateway Profile</label>
|
|
1302
|
+
<select
|
|
1303
|
+
value={gatewayProfileId || ''}
|
|
1304
|
+
onChange={(e) => applyGatewayProfileSelection(e.target.value || null)}
|
|
1305
|
+
className={inputClass}
|
|
1306
|
+
>
|
|
1307
|
+
<option value="">Custom endpoint</option>
|
|
1308
|
+
{openclawGatewayProfiles.map((gateway) => (
|
|
1309
|
+
<option key={gateway.id} value={gateway.id}>
|
|
1310
|
+
{gateway.name}{gateway.isDefault ? ' (default)' : ''}
|
|
1311
|
+
</option>
|
|
1312
|
+
))}
|
|
1313
|
+
</select>
|
|
1314
|
+
</div>
|
|
1315
|
+
)}
|
|
987
1316
|
{/* Connection fields */}
|
|
988
1317
|
<div className="space-y-4">
|
|
989
1318
|
<div>
|
|
@@ -1178,13 +1507,14 @@ export function AgentSheet() {
|
|
|
1178
1507
|
{!openclawEnabled && <div className="mb-8">
|
|
1179
1508
|
<SectionLabel>Provider</SectionLabel>
|
|
1180
1509
|
<div className="grid grid-cols-3 gap-3">
|
|
1181
|
-
{providers.
|
|
1510
|
+
{providers.map((p) => {
|
|
1182
1511
|
const isConnected = !p.requiresApiKey || Object.values(credentials).some((c) => c.provider === p.id)
|
|
1183
1512
|
return (
|
|
1184
1513
|
<button
|
|
1185
1514
|
key={p.id}
|
|
1186
1515
|
onClick={() => {
|
|
1187
1516
|
setProvider(p.id)
|
|
1517
|
+
setGatewayProfileId(null)
|
|
1188
1518
|
}}
|
|
1189
1519
|
className={`relative py-3.5 px-4 rounded-[14px] text-center cursor-pointer transition-all duration-200
|
|
1190
1520
|
active:scale-[0.97] text-[14px] font-600 border
|
|
@@ -1212,6 +1542,9 @@ export function AgentSheet() {
|
|
|
1212
1542
|
onChange={setModel}
|
|
1213
1543
|
models={currentProvider.models}
|
|
1214
1544
|
defaultModels={currentProvider.defaultModels}
|
|
1545
|
+
credentialId={credentialId}
|
|
1546
|
+
apiEndpoint={apiEndpoint}
|
|
1547
|
+
supportsDiscovery={currentProvider.supportsModelDiscovery}
|
|
1215
1548
|
className={`${inputClass} cursor-pointer`}
|
|
1216
1549
|
/>
|
|
1217
1550
|
</div>
|
|
@@ -1365,6 +1698,108 @@ export function AgentSheet() {
|
|
|
1365
1698
|
</div>
|
|
1366
1699
|
)}
|
|
1367
1700
|
|
|
1701
|
+
<div className="mb-8">
|
|
1702
|
+
<label className="flex items-center gap-2 font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
1703
|
+
Model Routing <HintTip text="Route this agent through a provider/model pool instead of a single fixed model. The base provider remains the default when no route matches." />
|
|
1704
|
+
</label>
|
|
1705
|
+
<div className="flex items-center gap-3 mb-3">
|
|
1706
|
+
<select value={routingStrategy} onChange={(e) => setRoutingStrategy(e.target.value as AgentRoutingStrategy)} className={inputClass}>
|
|
1707
|
+
<option value="single">Single route</option>
|
|
1708
|
+
<option value="balanced">Balanced</option>
|
|
1709
|
+
<option value="economy">Economy</option>
|
|
1710
|
+
<option value="premium">Premium</option>
|
|
1711
|
+
<option value="reasoning">Reasoning</option>
|
|
1712
|
+
</select>
|
|
1713
|
+
<button
|
|
1714
|
+
type="button"
|
|
1715
|
+
onClick={addRoutingTargetFromCurrent}
|
|
1716
|
+
className="shrink-0 px-3 py-2.5 rounded-[10px] bg-accent-soft/50 text-accent-bright text-[12px] font-700 hover:bg-accent-soft transition-colors cursor-pointer border border-accent-bright/20"
|
|
1717
|
+
>
|
|
1718
|
+
+ Add Current Route
|
|
1719
|
+
</button>
|
|
1720
|
+
</div>
|
|
1721
|
+
<div className="space-y-3">
|
|
1722
|
+
{routingTargets.map((target, index) => {
|
|
1723
|
+
const targetCredentials = Object.values(credentials).filter((item) => item.provider === target.provider)
|
|
1724
|
+
return (
|
|
1725
|
+
<div key={target.id} className="p-4 rounded-[12px] border border-white/[0.08] bg-white/[0.02] space-y-3">
|
|
1726
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
1727
|
+
<input
|
|
1728
|
+
value={target.label || ''}
|
|
1729
|
+
onChange={(e) => updateRoutingTarget(target.id, { label: e.target.value })}
|
|
1730
|
+
placeholder={`Route ${index + 1} label`}
|
|
1731
|
+
className={inputClass}
|
|
1732
|
+
/>
|
|
1733
|
+
<select value={target.role || 'backup'} onChange={(e) => updateRoutingTarget(target.id, { role: e.target.value as AgentRoutingTarget['role'] })} className={inputClass}>
|
|
1734
|
+
<option value="primary">Primary</option>
|
|
1735
|
+
<option value="economy">Economy</option>
|
|
1736
|
+
<option value="premium">Premium</option>
|
|
1737
|
+
<option value="reasoning">Reasoning</option>
|
|
1738
|
+
<option value="backup">Backup</option>
|
|
1739
|
+
</select>
|
|
1740
|
+
</div>
|
|
1741
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
1742
|
+
<select value={target.provider} onChange={(e) => updateRoutingTarget(target.id, { provider: e.target.value as ProviderType, gatewayProfileId: e.target.value === 'openclaw' ? target.gatewayProfileId : null })} className={inputClass}>
|
|
1743
|
+
{providers.map((item) => (
|
|
1744
|
+
<option key={item.id} value={item.id}>{item.name}</option>
|
|
1745
|
+
))}
|
|
1746
|
+
</select>
|
|
1747
|
+
<input
|
|
1748
|
+
value={target.model}
|
|
1749
|
+
onChange={(e) => updateRoutingTarget(target.id, { model: e.target.value })}
|
|
1750
|
+
placeholder="Model"
|
|
1751
|
+
className={inputClass}
|
|
1752
|
+
/>
|
|
1753
|
+
</div>
|
|
1754
|
+
{target.provider === 'openclaw' && openclawGatewayProfiles.length > 0 && (
|
|
1755
|
+
<select
|
|
1756
|
+
value={target.gatewayProfileId || ''}
|
|
1757
|
+
onChange={(e) => {
|
|
1758
|
+
const nextId = e.target.value || null
|
|
1759
|
+
const gateway = openclawGatewayProfiles.find((item) => item.id === nextId)
|
|
1760
|
+
updateRoutingTarget(target.id, {
|
|
1761
|
+
gatewayProfileId: nextId,
|
|
1762
|
+
apiEndpoint: gateway?.endpoint || target.apiEndpoint || null,
|
|
1763
|
+
credentialId: gateway?.credentialId || target.credentialId || null,
|
|
1764
|
+
model: target.model || 'default',
|
|
1765
|
+
})
|
|
1766
|
+
}}
|
|
1767
|
+
className={inputClass}
|
|
1768
|
+
>
|
|
1769
|
+
<option value="">Custom OpenClaw endpoint</option>
|
|
1770
|
+
{openclawGatewayProfiles.map((gateway) => (
|
|
1771
|
+
<option key={gateway.id} value={gateway.id}>{gateway.name}</option>
|
|
1772
|
+
))}
|
|
1773
|
+
</select>
|
|
1774
|
+
)}
|
|
1775
|
+
<div className="grid grid-cols-1 md:grid-cols-[1fr_auto] gap-3">
|
|
1776
|
+
<input
|
|
1777
|
+
value={target.apiEndpoint || ''}
|
|
1778
|
+
onChange={(e) => updateRoutingTarget(target.id, { apiEndpoint: e.target.value || null })}
|
|
1779
|
+
placeholder="Endpoint (optional)"
|
|
1780
|
+
className={`${inputClass} font-mono text-[14px]`}
|
|
1781
|
+
/>
|
|
1782
|
+
<select value={target.credentialId || ''} onChange={(e) => updateRoutingTarget(target.id, { credentialId: e.target.value || null })} className={inputClass}>
|
|
1783
|
+
<option value="">No key</option>
|
|
1784
|
+
{targetCredentials.map((item) => (
|
|
1785
|
+
<option key={item.id} value={item.id}>{item.name}</option>
|
|
1786
|
+
))}
|
|
1787
|
+
</select>
|
|
1788
|
+
</div>
|
|
1789
|
+
<div className="flex justify-end">
|
|
1790
|
+
<button type="button" onClick={() => removeRoutingTarget(target.id)} className="px-3 py-1.5 rounded-[8px] border border-red-400/20 bg-red-400/[0.06] text-[12px] font-700 text-red-300 hover:bg-red-400/[0.1] transition-all cursor-pointer">
|
|
1791
|
+
Remove Route
|
|
1792
|
+
</button>
|
|
1793
|
+
</div>
|
|
1794
|
+
</div>
|
|
1795
|
+
)
|
|
1796
|
+
})}
|
|
1797
|
+
</div>
|
|
1798
|
+
{routingTargets.length === 0 && (
|
|
1799
|
+
<p className="text-[11px] text-text-3/70 mt-2">No route pool yet. Add one if this agent should switch between cheaper, stronger, or gateway-specific models.</p>
|
|
1800
|
+
)}
|
|
1801
|
+
</div>
|
|
1802
|
+
|
|
1368
1803
|
{/* Plugins — hidden for providers that manage capabilities outside LangGraph */}
|
|
1369
1804
|
{!hasNativeCapabilities && (
|
|
1370
1805
|
<div className="mb-8">
|
|
@@ -1584,15 +2019,13 @@ export function AgentSheet() {
|
|
|
1584
2019
|
<label className="flex items-center gap-3 cursor-pointer">
|
|
1585
2020
|
<div
|
|
1586
2021
|
onClick={() => {
|
|
1587
|
-
|
|
1588
|
-
setIsOrchestrator(next)
|
|
1589
|
-
if (next && provider === 'claude-cli') setProvider('anthropic')
|
|
2022
|
+
setPlatformAssignScope((current) => current === 'all' ? 'self' : 'all')
|
|
1590
2023
|
}}
|
|
1591
2024
|
className={`w-11 h-6 rounded-full transition-all duration-200 relative cursor-pointer
|
|
1592
|
-
${
|
|
2025
|
+
${canDelegateToAgents ? 'bg-accent-bright' : 'bg-white/[0.08]'}`}
|
|
1593
2026
|
>
|
|
1594
2027
|
<div className={`absolute top-0.5 w-5 h-5 rounded-full bg-white transition-all duration-200
|
|
1595
|
-
${
|
|
2028
|
+
${canDelegateToAgents ? 'left-[22px]' : 'left-0.5'}`} />
|
|
1596
2029
|
</div>
|
|
1597
2030
|
<span className="font-display text-[14px] font-600 text-text-2">Can Delegate to Other Agents</span>
|
|
1598
2031
|
<span className="text-[12px] text-text-3">Route work to specialized agents and coordinate multi-agent tasks</span>
|
|
@@ -1600,7 +2033,7 @@ export function AgentSheet() {
|
|
|
1600
2033
|
</div>
|
|
1601
2034
|
)}
|
|
1602
2035
|
|
|
1603
|
-
{provider !== 'openclaw' &&
|
|
2036
|
+
{provider !== 'openclaw' && canDelegateToAgents && agentOptions.length > 0 && (
|
|
1604
2037
|
<div className="mb-8">
|
|
1605
2038
|
<SectionLabel>Available Agents</SectionLabel>
|
|
1606
2039
|
<AgentPickerList
|