@swarmclawai/swarmclaw 1.1.3 → 1.1.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 +16 -3
- package/package.json +1 -1
- package/src/app/api/agents/[id]/route.ts +23 -0
- package/src/app/api/agents/route.ts +14 -0
- package/src/app/autonomy/page.tsx +136 -3
- package/src/app/chatrooms/page.tsx +38 -16
- package/src/components/agents/agent-sheet.tsx +110 -0
- package/src/components/auth/setup-wizard/index.tsx +6 -0
- package/src/components/auth/setup-wizard/step-agents.tsx +35 -0
- package/src/components/auth/setup-wizard/types.ts +2 -0
- package/src/components/auth/setup-wizard/utils.ts +2 -0
- package/src/components/chatrooms/chatroom-list.tsx +11 -8
- package/src/components/tasks/task-column.tsx +1 -0
- package/src/components/tasks/task-list.tsx +1 -0
- package/src/lib/keyed-queue.test.ts +52 -0
- package/src/lib/keyed-queue.ts +33 -0
- package/src/lib/orchestrator-config.test.ts +45 -0
- package/src/lib/orchestrator-config.ts +72 -0
- package/src/lib/providers/error-classification.test.ts +35 -0
- package/src/lib/providers/error-classification.ts +70 -0
- package/src/lib/providers/index.ts +9 -18
- package/src/lib/server/agents/agent-runtime-config.ts +1 -0
- package/src/lib/server/agents/subagent-swarm.ts +59 -4
- package/src/lib/server/autonomy/supervisor-reflection.ts +54 -2
- package/src/lib/server/build-llm.ts +6 -2
- package/src/lib/server/chat-execution/situational-awareness.ts +85 -1
- package/src/lib/server/connectors/manager.ts +3 -0
- package/src/lib/server/provider-endpoint.ts +13 -2
- package/src/lib/server/provider-health.ts +30 -2
- package/src/lib/server/runtime/daemon-state.ts +13 -2
- package/src/lib/server/runtime/heartbeat-service.ts +289 -9
- package/src/lib/server/runtime/orchestrator-events.ts +18 -0
- package/src/lib/server/runtime/queue.ts +192 -33
- package/src/lib/server/runtime/system-events.ts +35 -0
- package/src/lib/server/session-tools/chatroom.ts +24 -1
- package/src/lib/server/storage.ts +2 -0
- package/src/lib/server/tool-retry.ts +2 -2
- package/src/lib/shared-utils.ts +10 -0
- package/src/lib/validation/schemas.test.ts +20 -0
- package/src/lib/validation/schemas.ts +6 -1
- package/src/types/index.ts +14 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<img src="https://raw.githubusercontent.com/swarmclawai/swarmclaw/main/public/branding/swarmclaw-org-avatar.png" alt="SwarmClaw lobster logo" width="120" />
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
-
SwarmClaw is a self-hosted AI runtime for OpenClaw and multi-agent work. It helps you run autonomous agents with heartbeats, schedules, delegation, memory, runtime skills, and reviewed conversation-to-skill learning across OpenClaw gateways and other providers.
|
|
11
|
+
SwarmClaw is a self-hosted AI runtime for OpenClaw and multi-agent work. It helps you run autonomous agents and orchestrators with heartbeats, schedules, delegation, memory, runtime skills, and reviewed conversation-to-skill learning across OpenClaw gateways and other providers.
|
|
12
12
|
|
|
13
13
|
GitHub: https://github.com/swarmclawai/swarmclaw
|
|
14
14
|
Docs: https://swarmclaw.ai/docs
|
|
@@ -177,6 +177,19 @@ The building blocks are the same: **agents, tools, memory, delegation, schedules
|
|
|
177
177
|
|
|
178
178
|
## Release Notes
|
|
179
179
|
|
|
180
|
+
### v1.1.4 Highlights
|
|
181
|
+
|
|
182
|
+
- **Orchestrator agents return as a first-class autonomy mode**: eligible agents can now run scheduled orchestrator wake cycles with their own mission, governance policy, wake interval, cycle cap, Autonomy-desk controls, and setup/editor support.
|
|
183
|
+
- **Runtime durability is much harder to knock over**: the task queue now supports parallel execution with restart-safe swarm state, orphaned running-task recovery, stuck-task idle timeout detection, and provider-health persistence across daemon restarts.
|
|
184
|
+
- **Recovery and safety paths are tighter**: provider errors are classified for smarter failover, unavailable agents defer work instead of burning it, supervisor blocks can create executable notifications, and agent budget limits now gate task execution before work starts.
|
|
185
|
+
- **Temporary session rooms are easier to inspect**: chatrooms now split persistent rooms from temporary session-style rooms so orchestrator or structured-session conversations can stay visible without polluting the normal room list.
|
|
186
|
+
|
|
187
|
+
### v1.1.3 Highlights
|
|
188
|
+
|
|
189
|
+
- **Release integrity repair**: `build:ci` no longer trips over the langgraph checkpoint duplicate-column path, which restores clean build validation for the release line.
|
|
190
|
+
- **Storage writes are safer**: credential and agent saves were tightened to upsert-only behavior and bulk-delete safety guards so tests or scripts cannot accidentally wipe live state.
|
|
191
|
+
- **Plugin-to-extension cleanup finished**: remaining rename residue in scripts and tests was cleaned up so packaging and release tooling stay aligned with the current extensions model.
|
|
192
|
+
|
|
180
193
|
### v1.1.2 Highlights
|
|
181
194
|
|
|
182
195
|
- **Structured Sessions expanded into richer orchestration**: ProtocolRun-based sessions now support dependency-aware step graphs, reusable step outputs, and a broader advanced execution model on the same durable runtime instead of bringing back a separate orchestrator.
|
|
@@ -207,9 +220,9 @@ The building blocks are the same: **agents, tools, memory, delegation, schedules
|
|
|
207
220
|
|
|
208
221
|
## What SwarmClaw Focuses On
|
|
209
222
|
|
|
210
|
-
- **Delegation and background execution**: delegated work, subagents, durable jobs, checkpointing, and background task execution.
|
|
223
|
+
- **Delegation, orchestrators, and background execution**: delegated work, orchestrator agents, subagents, durable jobs, checkpointing, and background task execution.
|
|
211
224
|
- **Structured Sessions and orchestration**: temporary bounded runs for one agent or many, launched from context and backed by durable templates, branching, loops, parallel joins, transcripts, outputs, operator controls, and chatroom breakout flows.
|
|
212
|
-
- **Autonomy and memory**: heartbeats, schedules, long-running execution, durable memory, reflection memory, human-context learning, document recall, and project-aware context.
|
|
225
|
+
- **Autonomy and memory**: heartbeats, orchestrator wake cycles, schedules, long-running execution, durable memory, reflection memory, human-context learning, document recall, and project-aware context.
|
|
213
226
|
- **OpenClaw integration**: named gateway profiles, external runtimes, deploy helpers, config sync, approval handling, and OpenClaw agent file editing.
|
|
214
227
|
- **Runtime skills**: pinned skills, OpenClaw-compatible `SKILL.md` import, on-demand skill execution, and configurable keyword or embedding-based recommendation.
|
|
215
228
|
- **Conversation-to-skill drafts**: draft a reusable skill from a real chat, review it, then approve it into the skill library.
|
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import { suspendAgentReferences } from '@/lib/server/agents/agent-cascade'
|
|
|
7
7
|
import { notify } from '@/lib/server/ws-hub'
|
|
8
8
|
import { normalizeAgentSandboxConfig } from '@/lib/agent-sandbox-defaults'
|
|
9
9
|
import { normalizeCapabilitySelection } from '@/lib/capability-selection'
|
|
10
|
+
import { normalizeOrchestratorConfig } from '@/lib/orchestrator-config'
|
|
10
11
|
|
|
11
12
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
13
|
const ops: CollectionOps<any> = { load: () => loadAgents({ includeTrashed: true }), save: saveAgents, topic: 'agents', table: 'agents' }
|
|
@@ -50,6 +51,28 @@ export async function PUT(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
50
51
|
if (body.sandboxConfig !== undefined) {
|
|
51
52
|
agent.sandboxConfig = normalizeAgentSandboxConfig(body.sandboxConfig)
|
|
52
53
|
}
|
|
54
|
+
if (
|
|
55
|
+
body.provider !== undefined
|
|
56
|
+
|| body.orchestratorEnabled !== undefined
|
|
57
|
+
|| body.orchestratorMission !== undefined
|
|
58
|
+
|| body.orchestratorWakeInterval !== undefined
|
|
59
|
+
|| body.orchestratorGovernance !== undefined
|
|
60
|
+
|| body.orchestratorMaxCyclesPerDay !== undefined
|
|
61
|
+
) {
|
|
62
|
+
const orchestratorConfig = normalizeOrchestratorConfig({
|
|
63
|
+
provider: typeof body.provider === 'string' ? body.provider : agent.provider,
|
|
64
|
+
orchestratorEnabled: body.orchestratorEnabled ?? agent.orchestratorEnabled,
|
|
65
|
+
orchestratorMission: body.orchestratorMission ?? agent.orchestratorMission,
|
|
66
|
+
orchestratorWakeInterval: body.orchestratorWakeInterval ?? agent.orchestratorWakeInterval,
|
|
67
|
+
orchestratorGovernance: body.orchestratorGovernance ?? agent.orchestratorGovernance,
|
|
68
|
+
orchestratorMaxCyclesPerDay: body.orchestratorMaxCyclesPerDay ?? agent.orchestratorMaxCyclesPerDay,
|
|
69
|
+
})
|
|
70
|
+
agent.orchestratorEnabled = orchestratorConfig.orchestratorEnabled
|
|
71
|
+
agent.orchestratorMission = orchestratorConfig.orchestratorMission
|
|
72
|
+
agent.orchestratorWakeInterval = orchestratorConfig.orchestratorWakeInterval
|
|
73
|
+
agent.orchestratorGovernance = orchestratorConfig.orchestratorGovernance
|
|
74
|
+
agent.orchestratorMaxCyclesPerDay = orchestratorConfig.orchestratorMaxCyclesPerDay
|
|
75
|
+
}
|
|
53
76
|
if (body.preferredGatewayTags !== undefined) {
|
|
54
77
|
agent.preferredGatewayTags = Array.isArray(body.preferredGatewayTags)
|
|
55
78
|
? body.preferredGatewayTags.filter((tag: unknown): tag is string => typeof tag === 'string' && tag.trim().length > 0)
|
|
@@ -7,6 +7,7 @@ import { notify } from '@/lib/server/ws-hub'
|
|
|
7
7
|
import { getAgentSpendWindows } from '@/lib/server/cost'
|
|
8
8
|
import { resolveAgentToolSelection } from '@/lib/agent-default-tools'
|
|
9
9
|
import { normalizeAgentSandboxConfig } from '@/lib/agent-sandbox-defaults'
|
|
10
|
+
import { normalizeOrchestratorConfig } from '@/lib/orchestrator-config'
|
|
10
11
|
import { AgentCreateSchema, formatZodError } from '@/lib/validation/schemas'
|
|
11
12
|
import { z } from 'zod'
|
|
12
13
|
export const dynamic = 'force-dynamic'
|
|
@@ -63,6 +64,14 @@ export async function POST(req: Request) {
|
|
|
63
64
|
return NextResponse.json(formatZodError(parsed.error as z.ZodError), { status: 400 })
|
|
64
65
|
}
|
|
65
66
|
const body = parsed.data
|
|
67
|
+
const orchestratorConfig = normalizeOrchestratorConfig({
|
|
68
|
+
provider: body.provider,
|
|
69
|
+
orchestratorEnabled: body.orchestratorEnabled,
|
|
70
|
+
orchestratorMission: body.orchestratorMission,
|
|
71
|
+
orchestratorWakeInterval: body.orchestratorWakeInterval,
|
|
72
|
+
orchestratorGovernance: body.orchestratorGovernance,
|
|
73
|
+
orchestratorMaxCyclesPerDay: body.orchestratorMaxCyclesPerDay,
|
|
74
|
+
})
|
|
66
75
|
const capabilitySelection = resolveAgentToolSelection({
|
|
67
76
|
hasExplicitTools: Boolean(rawRecord && Object.prototype.hasOwnProperty.call(rawRecord, 'tools')),
|
|
68
77
|
hasExplicitExtensions: Boolean(rawRecord && Object.prototype.hasOwnProperty.call(rawRecord, 'extensions')),
|
|
@@ -110,6 +119,11 @@ export async function POST(req: Request) {
|
|
|
110
119
|
heartbeatIntervalSec: body.heartbeatIntervalSec,
|
|
111
120
|
heartbeatModel: body.heartbeatModel,
|
|
112
121
|
heartbeatPrompt: body.heartbeatPrompt,
|
|
122
|
+
orchestratorEnabled: orchestratorConfig.orchestratorEnabled,
|
|
123
|
+
orchestratorMission: orchestratorConfig.orchestratorMission,
|
|
124
|
+
orchestratorWakeInterval: orchestratorConfig.orchestratorWakeInterval,
|
|
125
|
+
orchestratorGovernance: orchestratorConfig.orchestratorGovernance,
|
|
126
|
+
orchestratorMaxCyclesPerDay: orchestratorConfig.orchestratorMaxCyclesPerDay,
|
|
113
127
|
elevenLabsVoiceId: body.elevenLabsVoiceId,
|
|
114
128
|
monthlyBudget: body.monthlyBudget ?? null,
|
|
115
129
|
dailyBudget: body.dailyBudget ?? null,
|
|
@@ -4,8 +4,10 @@ import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
|
4
4
|
import { api } from '@/lib/app/api-client'
|
|
5
5
|
import { FilterPill } from '@/components/ui/filter-pill'
|
|
6
6
|
import { StatCard } from '@/components/ui/stat-card'
|
|
7
|
+
import { isOrchestratorEligible } from '@/lib/orchestrator-config'
|
|
7
8
|
import { timeAgo } from '@/lib/time-format'
|
|
8
|
-
import
|
|
9
|
+
import { useWs } from '@/hooks/use-ws'
|
|
10
|
+
import type { Agent, ApprovalRequest, EstopState, Mission, SupervisorIncident } from '@/types'
|
|
9
11
|
|
|
10
12
|
type EstopResponse = EstopState & {
|
|
11
13
|
ok?: boolean
|
|
@@ -107,11 +109,12 @@ export default function AutonomyPage() {
|
|
|
107
109
|
const [estop, setEstop] = useState<EstopResponse | null>(null)
|
|
108
110
|
const [incidents, setIncidents] = useState<SupervisorIncident[]>([])
|
|
109
111
|
const [missions, setMissions] = useState<Mission[]>([])
|
|
112
|
+
const [agents, setAgents] = useState<Agent[]>([])
|
|
110
113
|
const [loading, setLoading] = useState(true)
|
|
111
114
|
const [refreshing, setRefreshing] = useState(false)
|
|
112
115
|
const [error, setError] = useState<string | null>(null)
|
|
113
116
|
const [actionMessage, setActionMessage] = useState<string | null>(null)
|
|
114
|
-
const [pendingAction, setPendingAction] = useState<'autonomy' | 'all' | 'resume' | 'refresh' | 'policy' | 'approve' | 'reject' | null>(null)
|
|
117
|
+
const [pendingAction, setPendingAction] = useState<'autonomy' | 'all' | 'resume' | 'refresh' | 'policy' | 'approve' | 'reject' | 'orchestrator-toggle' | null>(null)
|
|
115
118
|
const [incidentFilter, setIncidentFilter] = useState<IncidentFilter>('all')
|
|
116
119
|
const [refreshedAt, setRefreshedAt] = useState<number | null>(null)
|
|
117
120
|
|
|
@@ -119,14 +122,16 @@ export default function AutonomyPage() {
|
|
|
119
122
|
if (mode === 'initial') setLoading(true)
|
|
120
123
|
else setRefreshing(true)
|
|
121
124
|
try {
|
|
122
|
-
const [estopState, incidentList, missionList] = await Promise.all([
|
|
125
|
+
const [estopState, incidentList, missionList, agentMap] = await Promise.all([
|
|
123
126
|
api<EstopResponse>('GET', '/autonomy/estop'),
|
|
124
127
|
api<SupervisorIncident[]>('GET', '/autonomy/incidents?limit=60'),
|
|
125
128
|
api<Mission[]>('GET', '/missions?status=non_terminal&limit=20'),
|
|
129
|
+
api<Record<string, Agent>>('GET', '/agents'),
|
|
126
130
|
])
|
|
127
131
|
setEstop(estopState)
|
|
128
132
|
setIncidents(Array.isArray(incidentList) ? incidentList : [])
|
|
129
133
|
setMissions(Array.isArray(missionList) ? missionList : [])
|
|
134
|
+
setAgents(agentMap ? Object.values(agentMap) : [])
|
|
130
135
|
setRefreshedAt(Date.now())
|
|
131
136
|
setError(null)
|
|
132
137
|
} catch (err) {
|
|
@@ -255,6 +260,29 @@ export default function AutonomyPage() {
|
|
|
255
260
|
}
|
|
256
261
|
}, [load])
|
|
257
262
|
|
|
263
|
+
const loadAgents = useCallback(async () => {
|
|
264
|
+
try {
|
|
265
|
+
const agentMap = await api<Record<string, Agent>>('GET', '/agents')
|
|
266
|
+
setAgents(agentMap ? Object.values(agentMap) : [])
|
|
267
|
+
} catch { /* swallow — load() will surface errors */ }
|
|
268
|
+
}, [])
|
|
269
|
+
useWs('agents', loadAgents, 30_000)
|
|
270
|
+
|
|
271
|
+
async function toggleOrchestrator(agent: Agent) {
|
|
272
|
+
setPendingAction('orchestrator-toggle')
|
|
273
|
+
try {
|
|
274
|
+
const next = !agent.orchestratorEnabled
|
|
275
|
+
await api('PUT', `/agents/${agent.id}`, { orchestratorEnabled: next })
|
|
276
|
+
setActionMessage(`${agent.name} orchestrator ${next ? 'enabled' : 'disabled'}.`)
|
|
277
|
+
setError(null)
|
|
278
|
+
await loadAgents()
|
|
279
|
+
} catch (err) {
|
|
280
|
+
setError(err instanceof Error ? err.message : 'Unable to toggle orchestrator.')
|
|
281
|
+
} finally {
|
|
282
|
+
setPendingAction(null)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
258
286
|
const sortedIncidents = useMemo(
|
|
259
287
|
() => [...incidents].sort((left, right) => right.createdAt - left.createdAt),
|
|
260
288
|
[incidents],
|
|
@@ -273,6 +301,11 @@ export default function AutonomyPage() {
|
|
|
273
301
|
return sortedIncidents
|
|
274
302
|
}, [incidentFilter, sortedIncidents])
|
|
275
303
|
|
|
304
|
+
const orchestrators = useMemo(
|
|
305
|
+
() => agents.filter((a) => a.orchestratorEnabled && !a.trashedAt && isOrchestratorEligible(a)),
|
|
306
|
+
[agents],
|
|
307
|
+
)
|
|
308
|
+
|
|
276
309
|
const latestIncident = sortedIncidents[0] || null
|
|
277
310
|
const highSeverityCount = sortedIncidents.filter((incident) => incident.severity === 'high').length
|
|
278
311
|
const runtimeFailureCount = sortedIncidents.filter((incident) => incident.kind === 'runtime_failure').length
|
|
@@ -502,6 +535,106 @@ export default function AutonomyPage() {
|
|
|
502
535
|
)}
|
|
503
536
|
</section>
|
|
504
537
|
|
|
538
|
+
<section className="rounded-[20px] border border-white/[0.06] bg-surface p-5">
|
|
539
|
+
<div className="mb-4 flex items-start justify-between gap-4">
|
|
540
|
+
<div>
|
|
541
|
+
<h2 className="font-display text-[18px] font-700 tracking-[-0.02em] text-text">Orchestrators</h2>
|
|
542
|
+
<p className="mt-1 text-[12px] leading-[1.7] text-text-3/72">
|
|
543
|
+
Agents running in orchestrator mode with autonomous wake cycles. Toggle individual orchestrators on or off without leaving the safety desk.
|
|
544
|
+
</p>
|
|
545
|
+
</div>
|
|
546
|
+
<div className="rounded-full border border-white/[0.08] bg-white/[0.03] px-3 py-1 text-[11px] text-text-3/72">
|
|
547
|
+
{orchestrators.length} active
|
|
548
|
+
</div>
|
|
549
|
+
</div>
|
|
550
|
+
|
|
551
|
+
{orchestrators.length === 0 ? (
|
|
552
|
+
<div className="flex min-h-[120px] items-center justify-center rounded-[16px] border border-dashed border-white/[0.08] bg-white/[0.02] p-6 text-center">
|
|
553
|
+
<div className="max-w-[320px]">
|
|
554
|
+
<h3 className="font-display text-[14px] font-700 tracking-[-0.02em] text-text">No orchestrators configured</h3>
|
|
555
|
+
<p className="mt-2 text-[12px] leading-[1.7] text-text-3/70">
|
|
556
|
+
Enable orchestrator mode on an agent to have it appear here with autonomous wake cycles.
|
|
557
|
+
</p>
|
|
558
|
+
</div>
|
|
559
|
+
</div>
|
|
560
|
+
) : (
|
|
561
|
+
<div className="grid gap-3 lg:grid-cols-2">
|
|
562
|
+
{orchestrators.map((agent) => {
|
|
563
|
+
const governanceLabel = agent.orchestratorGovernance === 'approval-required'
|
|
564
|
+
? 'Approval required'
|
|
565
|
+
: agent.orchestratorGovernance === 'notify-only'
|
|
566
|
+
? 'Notify only'
|
|
567
|
+
: 'Autonomous'
|
|
568
|
+
const governanceTone = agent.orchestratorGovernance === 'approval-required'
|
|
569
|
+
? 'bg-amber-500/12 text-amber-300'
|
|
570
|
+
: agent.orchestratorGovernance === 'notify-only'
|
|
571
|
+
? 'bg-sky-500/12 text-sky-300'
|
|
572
|
+
: 'bg-emerald-500/12 text-emerald-300'
|
|
573
|
+
const isDisabled = agent.disabled === true
|
|
574
|
+
return (
|
|
575
|
+
<div
|
|
576
|
+
key={agent.id}
|
|
577
|
+
className={`rounded-[16px] border p-4 ${isDisabled ? 'border-white/[0.04] bg-white/[0.01] opacity-60' : 'border-white/[0.06] bg-white/[0.02]'}`}
|
|
578
|
+
>
|
|
579
|
+
<div className="mb-2 flex items-center justify-between gap-3">
|
|
580
|
+
<div className="flex items-center gap-2">
|
|
581
|
+
<span className={`rounded-full px-2.5 py-1 text-[10px] font-700 uppercase tracking-[0.08em] ${governanceTone}`}>
|
|
582
|
+
{governanceLabel}
|
|
583
|
+
</span>
|
|
584
|
+
<span className={`rounded-full px-2.5 py-1 text-[10px] font-700 uppercase tracking-[0.08em] ${
|
|
585
|
+
isDisabled
|
|
586
|
+
? 'bg-white/[0.06] text-text-3/55'
|
|
587
|
+
: 'bg-emerald-500/12 text-emerald-300'
|
|
588
|
+
}`}>
|
|
589
|
+
{isDisabled ? 'Disabled' : 'Enabled'}
|
|
590
|
+
</span>
|
|
591
|
+
</div>
|
|
592
|
+
<button
|
|
593
|
+
type="button"
|
|
594
|
+
onClick={() => void toggleOrchestrator(agent)}
|
|
595
|
+
disabled={pendingAction !== null}
|
|
596
|
+
aria-pressed={agent.orchestratorEnabled}
|
|
597
|
+
aria-label={`${agent.orchestratorEnabled ? 'Disable' : 'Enable'} orchestrator for ${agent.name}`}
|
|
598
|
+
className={`flex h-6 w-11 shrink-0 items-center rounded-full border px-[3px] transition-all duration-200 cursor-pointer ${
|
|
599
|
+
agent.orchestratorEnabled
|
|
600
|
+
? 'border-accent-bright/35 bg-accent shadow-[0_0_0_1px_rgba(89,153,255,0.12)]'
|
|
601
|
+
: 'border-white/[0.10] bg-white/[0.08]'
|
|
602
|
+
} disabled:cursor-default disabled:opacity-45`}
|
|
603
|
+
>
|
|
604
|
+
<span className={`h-4 w-4 rounded-full bg-white shadow-[0_1px_3px_rgba(0,0,0,0.35)] transition-transform duration-200 ${
|
|
605
|
+
agent.orchestratorEnabled ? 'translate-x-[20px]' : 'translate-x-0'
|
|
606
|
+
}`} />
|
|
607
|
+
</button>
|
|
608
|
+
</div>
|
|
609
|
+
<div className="text-[14px] font-600 text-text">{agent.name}</div>
|
|
610
|
+
{agent.description && (
|
|
611
|
+
<div className="mt-1 text-[12px] leading-[1.7] text-text-3/72">{agent.description}</div>
|
|
612
|
+
)}
|
|
613
|
+
{agent.orchestratorMission && (
|
|
614
|
+
<div className="mt-2 text-[12px] leading-[1.7] text-text-2/82">
|
|
615
|
+
{agent.orchestratorMission.length > 120
|
|
616
|
+
? `${agent.orchestratorMission.slice(0, 119).trimEnd()}…`
|
|
617
|
+
: agent.orchestratorMission}
|
|
618
|
+
</div>
|
|
619
|
+
)}
|
|
620
|
+
<div className="mt-3 flex flex-wrap gap-x-4 gap-y-1 text-[11px] text-text-3/58">
|
|
621
|
+
{agent.orchestratorLastWakeAt && (
|
|
622
|
+
<span>Last wake {timeAgo(agent.orchestratorLastWakeAt, now)}</span>
|
|
623
|
+
)}
|
|
624
|
+
{typeof agent.orchestratorCycleCount === 'number' && (
|
|
625
|
+
<span>{agent.orchestratorCycleCount} cycle{agent.orchestratorCycleCount === 1 ? '' : 's'}</span>
|
|
626
|
+
)}
|
|
627
|
+
{agent.orchestratorWakeInterval && (
|
|
628
|
+
<span>Every {agent.orchestratorWakeInterval}</span>
|
|
629
|
+
)}
|
|
630
|
+
</div>
|
|
631
|
+
</div>
|
|
632
|
+
)
|
|
633
|
+
})}
|
|
634
|
+
</div>
|
|
635
|
+
)}
|
|
636
|
+
</section>
|
|
637
|
+
|
|
505
638
|
<div className="grid gap-5 xl:grid-cols-[360px_minmax(0,1fr)]">
|
|
506
639
|
<section className="rounded-[20px] border border-white/[0.06] bg-surface p-5">
|
|
507
640
|
<div className="mb-4 flex items-start gap-3">
|
|
@@ -1,33 +1,55 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
+
import { useState } from 'react'
|
|
3
4
|
import { useChatroomStore } from '@/stores/use-chatroom-store'
|
|
4
5
|
import { ChatroomList } from '@/components/chatrooms/chatroom-list'
|
|
5
6
|
import { ChatroomView } from '@/components/chatrooms/chatroom-view'
|
|
6
7
|
import { MainContent } from '@/components/layout/main-content'
|
|
7
8
|
|
|
8
9
|
export default function ChatroomsPage() {
|
|
10
|
+
const [viewMode, setViewMode] = useState<'chatrooms' | 'sessions'>('chatrooms')
|
|
11
|
+
|
|
9
12
|
return (
|
|
10
13
|
<MainContent>
|
|
11
14
|
<div className="flex-1 flex h-full min-w-0">
|
|
12
15
|
<div className="w-[280px] shrink-0 border-r border-white/[0.06] flex flex-col">
|
|
13
16
|
<div className="flex items-center px-4 pt-4 pb-2 shrink-0">
|
|
14
|
-
<h2 className="font-display text-[14px] font-600 text-text-2 tracking-[-0.01em] flex-1">
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
<h2 className="font-display text-[14px] font-600 text-text-2 tracking-[-0.01em] flex-1">
|
|
18
|
+
{viewMode === 'sessions' ? 'Sessions' : 'Chatrooms'}
|
|
19
|
+
</h2>
|
|
20
|
+
{viewMode === 'chatrooms' && (
|
|
21
|
+
<button
|
|
22
|
+
onClick={() => {
|
|
23
|
+
useChatroomStore.getState().setEditingChatroomId(null)
|
|
24
|
+
useChatroomStore.getState().setChatroomSheetOpen(true)
|
|
25
|
+
}}
|
|
26
|
+
className="flex items-center gap-1 px-2 py-1 rounded-[6px] text-[11px] font-600 text-accent-bright bg-accent-soft hover:bg-accent-bright/15 transition-all cursor-pointer"
|
|
27
|
+
style={{ fontFamily: 'inherit' }}
|
|
28
|
+
>
|
|
29
|
+
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
|
|
30
|
+
<line x1="12" y1="5" x2="12" y2="19" />
|
|
31
|
+
<line x1="5" y1="12" x2="19" y2="12" />
|
|
32
|
+
</svg>
|
|
33
|
+
New
|
|
34
|
+
</button>
|
|
35
|
+
)}
|
|
36
|
+
</div>
|
|
37
|
+
<div className="flex items-center gap-1 px-3 pb-2 shrink-0">
|
|
38
|
+
{(['chatrooms', 'sessions'] as const).map((mode) => (
|
|
39
|
+
<button
|
|
40
|
+
key={mode}
|
|
41
|
+
type="button"
|
|
42
|
+
onClick={() => setViewMode(mode)}
|
|
43
|
+
data-active={viewMode === mode || undefined}
|
|
44
|
+
className="rounded-[8px] border-none px-3 py-1.5 text-[11px] font-600 capitalize cursor-pointer transition-all focus-visible:ring-1 focus-visible:ring-accent-bright/50
|
|
45
|
+
data-[active]:bg-accent-soft data-[active]:text-accent-bright
|
|
46
|
+
bg-transparent text-text-3 hover:text-text-2 hover:bg-white/[0.04]"
|
|
47
|
+
>
|
|
48
|
+
{mode}
|
|
49
|
+
</button>
|
|
50
|
+
))}
|
|
29
51
|
</div>
|
|
30
|
-
<ChatroomList />
|
|
52
|
+
<ChatroomList viewMode={viewMode} />
|
|
31
53
|
</div>
|
|
32
54
|
<ChatroomView />
|
|
33
55
|
</div>
|
|
@@ -14,6 +14,7 @@ import type { ProviderType, ClaudeSkill, AgentWallet, AgentPackManifest, AgentRo
|
|
|
14
14
|
import { WalletSection } from '@/components/wallets/wallet-section'
|
|
15
15
|
import { AVAILABLE_TOOLS, PLATFORM_TOOLS } from '@/lib/tool-definitions'
|
|
16
16
|
import { NATIVE_CAPABILITY_PROVIDER_IDS, NON_LANGGRAPH_PROVIDER_IDS } from '@/lib/provider-sets'
|
|
17
|
+
import { isOrchestratorProviderEligible } from '@/lib/orchestrator-config'
|
|
17
18
|
import { AgentAvatar } from './agent-avatar'
|
|
18
19
|
import { AgentPickerList } from '@/components/shared/agent-picker-list'
|
|
19
20
|
import { randomSoul } from '@/lib/soul-suggestions'
|
|
@@ -239,6 +240,11 @@ export function AgentSheet() {
|
|
|
239
240
|
const [heartbeatIntervalSec, setHeartbeatIntervalSec] = useState('') // '' = default (30m)
|
|
240
241
|
const [heartbeatModel, setHeartbeatModel] = useState('')
|
|
241
242
|
const [heartbeatPrompt, setHeartbeatPrompt] = useState('')
|
|
243
|
+
const [orchestratorEnabled, setOrchestratorEnabled] = useState(false)
|
|
244
|
+
const [orchestratorMission, setOrchestratorMission] = useState('')
|
|
245
|
+
const [orchestratorWakeInterval, setOrchestratorWakeInterval] = useState('5m')
|
|
246
|
+
const [orchestratorGovernance, setOrchestratorGovernance] = useState<'autonomous' | 'approval-required' | 'notify-only'>('autonomous')
|
|
247
|
+
const [orchestratorMaxCyclesPerDay, setOrchestratorMaxCyclesPerDay] = useState<string>('')
|
|
242
248
|
const [sessionResetMode, setSessionResetMode] = useState<'' | 'idle' | 'daily' | 'isolated'>('')
|
|
243
249
|
const [sessionIdleTimeoutSec, setSessionIdleTimeoutSec] = useState('')
|
|
244
250
|
const [sessionMaxAgeSec, setSessionMaxAgeSec] = useState('')
|
|
@@ -440,6 +446,11 @@ export function AgentSheet() {
|
|
|
440
446
|
setHeartbeatIntervalSec(parseDurationToSec(editing.heartbeatInterval, editing.heartbeatIntervalSec))
|
|
441
447
|
setHeartbeatModel(editing.heartbeatModel || '')
|
|
442
448
|
setHeartbeatPrompt(editing.heartbeatPrompt || '')
|
|
449
|
+
setOrchestratorEnabled(editing.orchestratorEnabled || false)
|
|
450
|
+
setOrchestratorMission(editing.orchestratorMission || '')
|
|
451
|
+
setOrchestratorWakeInterval(typeof editing.orchestratorWakeInterval === 'string' ? editing.orchestratorWakeInterval : typeof editing.orchestratorWakeInterval === 'number' ? `${editing.orchestratorWakeInterval}s` : '5m')
|
|
452
|
+
setOrchestratorGovernance(editing.orchestratorGovernance || 'autonomous')
|
|
453
|
+
setOrchestratorMaxCyclesPerDay(editing.orchestratorMaxCyclesPerDay != null ? String(editing.orchestratorMaxCyclesPerDay) : '')
|
|
443
454
|
setSessionResetMode(editing.sessionResetMode || '')
|
|
444
455
|
setSessionIdleTimeoutSec(editing.sessionIdleTimeoutSec != null ? String(editing.sessionIdleTimeoutSec) : '')
|
|
445
456
|
setSessionMaxAgeSec(editing.sessionMaxAgeSec != null ? String(editing.sessionMaxAgeSec) : '')
|
|
@@ -505,6 +516,11 @@ export function AgentSheet() {
|
|
|
505
516
|
setHeartbeatIntervalSec('')
|
|
506
517
|
setHeartbeatModel('')
|
|
507
518
|
setHeartbeatPrompt('')
|
|
519
|
+
setOrchestratorEnabled(false)
|
|
520
|
+
setOrchestratorMission('')
|
|
521
|
+
setOrchestratorWakeInterval('5m')
|
|
522
|
+
setOrchestratorGovernance('autonomous')
|
|
523
|
+
setOrchestratorMaxCyclesPerDay('')
|
|
508
524
|
setSessionResetMode('')
|
|
509
525
|
setSessionIdleTimeoutSec('')
|
|
510
526
|
setSessionMaxAgeSec('')
|
|
@@ -704,6 +720,11 @@ export function AgentSheet() {
|
|
|
704
720
|
heartbeatIntervalSec: heartbeatIntervalSec ? Number(heartbeatIntervalSec) : null,
|
|
705
721
|
heartbeatModel: heartbeatModel.trim() || null,
|
|
706
722
|
heartbeatPrompt: heartbeatPrompt.trim() || null,
|
|
723
|
+
orchestratorEnabled,
|
|
724
|
+
orchestratorMission: orchestratorMission.trim() || undefined,
|
|
725
|
+
orchestratorWakeInterval: orchestratorWakeInterval.trim() || null,
|
|
726
|
+
orchestratorGovernance,
|
|
727
|
+
orchestratorMaxCyclesPerDay: orchestratorMaxCyclesPerDay ? Number(orchestratorMaxCyclesPerDay) : null,
|
|
707
728
|
identityState,
|
|
708
729
|
sessionResetMode: sessionResetMode || null,
|
|
709
730
|
sessionIdleTimeoutSec: Number.isFinite(parsedSessionIdleTimeoutSec) && parsedSessionIdleTimeoutSec! >= 0 ? parsedSessionIdleTimeoutSec : null,
|
|
@@ -898,6 +919,7 @@ export function AgentSheet() {
|
|
|
898
919
|
if (skills.length > 0 || skillIds.length > 0 || mcpServerIds.length > 0 || mcpDisabledTools.length > 0) badges.push('Skills & MCP')
|
|
899
920
|
if (toolsDifferFromDefault || filesystemScope === 'machine' || delegationEnabled || delegationTargetMode === 'selected' || delegationTargetAgentIds.length > 0) badges.push('Tools')
|
|
900
921
|
if (budgetEnabled) badges.push('Budget')
|
|
922
|
+
if (orchestratorEnabled) badges.push('Orchestrator')
|
|
901
923
|
if (disabled) badges.push('Disabled')
|
|
902
924
|
if (autoRecovery) badges.push('Recovery')
|
|
903
925
|
if (projectId) badges.push('Project')
|
|
@@ -919,6 +941,7 @@ export function AgentSheet() {
|
|
|
919
941
|
mcpServerIds.length,
|
|
920
942
|
memoryScopeMode,
|
|
921
943
|
memoryTierPreference,
|
|
944
|
+
orchestratorEnabled,
|
|
922
945
|
proactiveMemory,
|
|
923
946
|
projectId,
|
|
924
947
|
routingStrategy,
|
|
@@ -1631,6 +1654,93 @@ export function AgentSheet() {
|
|
|
1631
1654
|
</div>
|
|
1632
1655
|
</SectionCard>
|
|
1633
1656
|
|
|
1657
|
+
{isOrchestratorProviderEligible(provider) && (
|
|
1658
|
+
<SectionCard
|
|
1659
|
+
title="Orchestrator"
|
|
1660
|
+
description="Turn this agent into a self-directing orchestrator that wakes on a schedule and manages the platform."
|
|
1661
|
+
>
|
|
1662
|
+
<div className="flex items-center justify-between gap-4 rounded-[14px] border border-white/[0.06] bg-white/[0.02] px-4 py-4">
|
|
1663
|
+
<div className="min-w-0">
|
|
1664
|
+
<p className="text-[14px] font-600 text-text">Orchestrator Mode</p>
|
|
1665
|
+
<p className="mt-1 text-[12px] leading-[1.6] text-text-3/75">
|
|
1666
|
+
Enable autonomous platform management — wakes on a schedule, reviews state, and delegates work.
|
|
1667
|
+
</p>
|
|
1668
|
+
</div>
|
|
1669
|
+
<button
|
|
1670
|
+
type="button"
|
|
1671
|
+
onClick={() => setOrchestratorEnabled((current) => !current)}
|
|
1672
|
+
className={`relative h-6 w-11 shrink-0 rounded-full border-none transition-colors duration-200 ${orchestratorEnabled ? 'bg-accent-bright' : 'bg-white/[0.12]'}`}
|
|
1673
|
+
aria-pressed={orchestratorEnabled}
|
|
1674
|
+
>
|
|
1675
|
+
<span className={`absolute top-0.5 left-0.5 h-5 w-5 rounded-full bg-white transition-transform duration-200 ${orchestratorEnabled ? 'translate-x-5' : 'translate-x-0'}`} />
|
|
1676
|
+
</button>
|
|
1677
|
+
</div>
|
|
1678
|
+
|
|
1679
|
+
{orchestratorEnabled && (
|
|
1680
|
+
<div className="mt-4 space-y-4">
|
|
1681
|
+
<div>
|
|
1682
|
+
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
1683
|
+
Mission
|
|
1684
|
+
</label>
|
|
1685
|
+
<textarea
|
|
1686
|
+
value={orchestratorMission}
|
|
1687
|
+
onChange={(e) => setOrchestratorMission(e.target.value)}
|
|
1688
|
+
placeholder="Describe the orchestrator's mission — what should it manage, optimize, or oversee?"
|
|
1689
|
+
rows={3}
|
|
1690
|
+
className={`${inputClass} resize-y min-h-[84px]`}
|
|
1691
|
+
style={{ fontFamily: 'inherit' }}
|
|
1692
|
+
/>
|
|
1693
|
+
</div>
|
|
1694
|
+
|
|
1695
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
|
|
1696
|
+
<div>
|
|
1697
|
+
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
1698
|
+
Wake Interval
|
|
1699
|
+
</label>
|
|
1700
|
+
<input
|
|
1701
|
+
type="text"
|
|
1702
|
+
value={orchestratorWakeInterval}
|
|
1703
|
+
onChange={(e) => setOrchestratorWakeInterval(e.target.value)}
|
|
1704
|
+
placeholder="5m"
|
|
1705
|
+
className={inputClass}
|
|
1706
|
+
style={{ fontFamily: 'inherit' }}
|
|
1707
|
+
/>
|
|
1708
|
+
</div>
|
|
1709
|
+
<div>
|
|
1710
|
+
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
1711
|
+
Governance
|
|
1712
|
+
</label>
|
|
1713
|
+
<select
|
|
1714
|
+
value={orchestratorGovernance}
|
|
1715
|
+
onChange={(e) => setOrchestratorGovernance(e.target.value as typeof orchestratorGovernance)}
|
|
1716
|
+
className={inputClass}
|
|
1717
|
+
style={{ fontFamily: 'inherit' }}
|
|
1718
|
+
>
|
|
1719
|
+
<option value="autonomous">Autonomous</option>
|
|
1720
|
+
<option value="approval-required">Approval Required</option>
|
|
1721
|
+
<option value="notify-only">Notify Only</option>
|
|
1722
|
+
</select>
|
|
1723
|
+
</div>
|
|
1724
|
+
<div>
|
|
1725
|
+
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-2">
|
|
1726
|
+
Max Cycles/Day
|
|
1727
|
+
</label>
|
|
1728
|
+
<input
|
|
1729
|
+
type="number"
|
|
1730
|
+
value={orchestratorMaxCyclesPerDay}
|
|
1731
|
+
onChange={(e) => setOrchestratorMaxCyclesPerDay(e.target.value)}
|
|
1732
|
+
placeholder="No limit"
|
|
1733
|
+
min={1}
|
|
1734
|
+
className={inputClass}
|
|
1735
|
+
style={{ fontFamily: 'inherit' }}
|
|
1736
|
+
/>
|
|
1737
|
+
</div>
|
|
1738
|
+
</div>
|
|
1739
|
+
</div>
|
|
1740
|
+
)}
|
|
1741
|
+
</SectionCard>
|
|
1742
|
+
)}
|
|
1743
|
+
|
|
1634
1744
|
<AdvancedSettingsSection
|
|
1635
1745
|
open={showAdvancedSettings}
|
|
1636
1746
|
onToggle={() => setShowAdvancedSettings((current) => !current)}
|
|
@@ -136,6 +136,8 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
136
136
|
delegationTargetMode: 'all',
|
|
137
137
|
delegationTargetAgentIds: [],
|
|
138
138
|
autoDraftSkillSuggestions: true,
|
|
139
|
+
orchestratorEnabled: false,
|
|
140
|
+
orchestratorMission: '',
|
|
139
141
|
avatarSeed: crypto.randomUUID().slice(0, 8),
|
|
140
142
|
avatarUrl: null,
|
|
141
143
|
enabled: true,
|
|
@@ -195,6 +197,8 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
195
197
|
delegationTargetMode: 'all',
|
|
196
198
|
delegationTargetAgentIds: [],
|
|
197
199
|
autoDraftSkillSuggestions: true,
|
|
200
|
+
orchestratorEnabled: false,
|
|
201
|
+
orchestratorMission: '',
|
|
198
202
|
avatarSeed: crypto.randomUUID().slice(0, 8),
|
|
199
203
|
avatarUrl: null,
|
|
200
204
|
enabled: true,
|
|
@@ -327,6 +331,8 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
327
331
|
delegationTargetMode: draft.delegationTargetMode,
|
|
328
332
|
delegationTargetAgentIds: draft.delegationTargetMode === 'selected' ? draft.delegationTargetAgentIds : [],
|
|
329
333
|
autoDraftSkillSuggestions: draft.autoDraftSkillSuggestions,
|
|
334
|
+
orchestratorEnabled: draft.orchestratorEnabled,
|
|
335
|
+
orchestratorMission: draft.orchestratorMission.trim() || undefined,
|
|
330
336
|
avatarSeed: draft.avatarSeed.trim() || undefined,
|
|
331
337
|
avatarUrl: draft.avatarUrl || null,
|
|
332
338
|
}
|
|
@@ -10,6 +10,7 @@ import type { ProviderModelDiscoveryResult } from '@/types'
|
|
|
10
10
|
import { StepShell, SkipLink } from './shared'
|
|
11
11
|
import { AVAILABLE_TOOLS, PLATFORM_TOOLS } from '@/lib/tool-definitions'
|
|
12
12
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
13
|
+
import { isOrchestratorProviderEligible } from '@/lib/orchestrator-config'
|
|
13
14
|
|
|
14
15
|
/* ── Model combobox: search discovered models or type a custom one ── */
|
|
15
16
|
|
|
@@ -478,6 +479,40 @@ export function StepAgents({
|
|
|
478
479
|
</div>
|
|
479
480
|
</div>
|
|
480
481
|
</div>
|
|
482
|
+
{matchedProvider && isOrchestratorProviderEligible(matchedProvider.provider) && (
|
|
483
|
+
<div className="md:col-span-2">
|
|
484
|
+
<div className="flex items-center justify-between rounded-[12px] border border-white/[0.08] bg-bg px-4 py-3">
|
|
485
|
+
<div>
|
|
486
|
+
<div className="text-[12px] font-600 text-text">Enable Orchestrator</div>
|
|
487
|
+
<div className="mt-1 text-[11px] text-text-3">
|
|
488
|
+
Allow this agent to autonomously manage the platform
|
|
489
|
+
</div>
|
|
490
|
+
</div>
|
|
491
|
+
<button
|
|
492
|
+
type="button"
|
|
493
|
+
onClick={() => onUpdateDraft(draft.id, { orchestratorEnabled: !draft.orchestratorEnabled })}
|
|
494
|
+
className={`w-9 h-5 rounded-full transition-all relative cursor-pointer shrink-0 ${draft.orchestratorEnabled ? 'bg-accent-bright' : 'bg-white/[0.08]'}`}
|
|
495
|
+
aria-pressed={draft.orchestratorEnabled}
|
|
496
|
+
>
|
|
497
|
+
<div className={`absolute top-0.5 w-4 h-4 rounded-full bg-white transition-all ${draft.orchestratorEnabled ? 'left-[18px]' : 'left-0.5'}`} />
|
|
498
|
+
</button>
|
|
499
|
+
</div>
|
|
500
|
+
{draft.orchestratorEnabled && (
|
|
501
|
+
<div className="mt-2">
|
|
502
|
+
<label className="block text-[12px] text-text-3 font-500 mb-1.5 ml-1">Mission (optional)</label>
|
|
503
|
+
<textarea
|
|
504
|
+
value={draft.orchestratorMission}
|
|
505
|
+
onChange={(e) => onUpdateDraft(draft.id, { orchestratorMission: e.target.value })}
|
|
506
|
+
rows={2}
|
|
507
|
+
placeholder="e.g. Monitor system health and restart failing services"
|
|
508
|
+
className="w-full px-4 py-3 rounded-[12px] border border-white/[0.08] bg-bg
|
|
509
|
+
text-text text-[14px] outline-none transition-all duration-200 resize-none
|
|
510
|
+
focus:border-accent-bright/30 focus:shadow-[0_0_30px_rgba(99,102,241,0.1)]"
|
|
511
|
+
/>
|
|
512
|
+
</div>
|
|
513
|
+
)}
|
|
514
|
+
</div>
|
|
515
|
+
)}
|
|
481
516
|
</div>
|
|
482
517
|
|
|
483
518
|
<details className="mt-4 rounded-[12px] border border-white/[0.08] bg-bg px-4 py-3">
|
|
@@ -67,6 +67,8 @@ export interface StarterDraftAgent {
|
|
|
67
67
|
delegationTargetMode: 'all' | 'selected'
|
|
68
68
|
delegationTargetAgentIds: string[]
|
|
69
69
|
autoDraftSkillSuggestions: boolean
|
|
70
|
+
orchestratorEnabled: boolean
|
|
71
|
+
orchestratorMission: string
|
|
70
72
|
avatarSeed: string
|
|
71
73
|
avatarUrl: string | null
|
|
72
74
|
enabled: boolean
|