@swarmclawai/swarmclaw 1.4.9 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/package.json +1 -1
- package/src/app/home/page.tsx +62 -0
- package/src/app/protocols/page.tsx +31 -0
- package/src/app/setup/page.tsx +4 -2
- package/src/components/auth/setup-wizard/index.tsx +66 -74
- package/src/components/auth/setup-wizard/step-next.tsx +60 -48
- package/src/components/auth/setup-wizard/step-path.tsx +159 -0
- package/src/components/auth/setup-wizard/step-progress.tsx +1 -0
- package/src/components/auth/setup-wizard/step-providers.tsx +9 -0
- package/src/components/auth/setup-wizard/types.test.ts +4 -4
- package/src/components/auth/setup-wizard/types.ts +22 -5
- package/src/components/auth/setup-wizard/utils.test.ts +73 -6
- package/src/components/auth/setup-wizard/utils.ts +13 -0
- package/src/components/home/home-launchpad.tsx +135 -0
- package/src/components/protocols/builder/template-gallery.tsx +23 -16
- package/src/components/shared/launch-action-card.tsx +27 -0
- package/src/lib/home-launchpad.test.ts +49 -0
- package/src/lib/home-launchpad.ts +30 -0
- package/src/lib/setup-defaults.ts +13 -6
package/README.md
CHANGED
|
@@ -215,6 +215,12 @@ SwarmClaw agents can join [SwarmFeed](https://swarmfeed.ai) — a social network
|
|
|
215
215
|
|
|
216
216
|
Read the docs at [swarmclaw.ai/docs/swarmfeed](https://swarmclaw.ai/docs/swarmfeed) and visit [swarmfeed.ai](https://swarmfeed.ai) for the platform itself.
|
|
217
217
|
|
|
218
|
+
### v1.5.0 Highlights
|
|
219
|
+
|
|
220
|
+
- **First-run activation refresh**: setup now includes a dedicated start-path step, broad starter shapes instead of niche presets, and draft agents generated directly from the chosen setup shape.
|
|
221
|
+
- **Guided post-setup launchpad**: finishing setup now routes through action-oriented next steps such as opening the first agent chat, launching a structured session, connecting platforms, or reviewing usage.
|
|
222
|
+
- **State-aware home and protocols**: fresh workspaces now open on a launchpad instead of a sparse ops dashboard, and the Protocols page now surfaces the visual builder and template gallery directly.
|
|
223
|
+
|
|
218
224
|
### v1.4.9 Highlights
|
|
219
225
|
|
|
220
226
|
- **Standalone build reliability**: `public/`, `.next/static/`, and `css-tree/data/` are now automatically copied into the standalone build output, fixing runtime crashes and missing assets when running the standalone bundle. (Community contribution by [@borislavnnikolov](https://github.com/borislavnnikolov) — PR #34)
|
|
@@ -355,7 +361,7 @@ Then open `http://localhost:3456`.
|
|
|
355
361
|
- **Delegation**: built-in delegation to Claude Code, Codex CLI, OpenCode CLI, Gemini CLI, and native SwarmClaw subagents.
|
|
356
362
|
- **Autonomy**: heartbeat loops, schedules, background jobs, task execution, supervisor recovery, and agent wakeups.
|
|
357
363
|
- **Orchestration**: durable structured execution with branching, repeat loops, parallel branches, explicit joins, restart-safe run state, and contextual launch from chats, chatrooms, tasks, schedules, and API flows.
|
|
358
|
-
- **Structured Sessions**: reusable bounded runs with templates, facilitators, participants, hidden live rooms, chatroom `/breakout`, durable transcripts, outputs, and
|
|
364
|
+
- **Structured Sessions**: reusable bounded runs with templates, facilitators, participants, hidden live rooms, chatroom `/breakout`, durable transcripts, outputs, operator controls, and a visible protocols template gallery plus visual builder.
|
|
359
365
|
- **Memory**: hybrid recall, graph traversal, journaling, durable documents, project-scoped context, automatic reflection memory, communication preferences, profile and boundary memory, significant events, and open follow-up loops.
|
|
360
366
|
- **Wallets**: linked Base wallet generation, address management, approval-oriented limits, and agent payout identity.
|
|
361
367
|
- **Connectors**: Discord, Slack, Telegram, WhatsApp, Teams, Matrix, OpenClaw, SwarmDock, SwarmFeed, and more.
|
package/package.json
CHANGED
package/src/app/home/page.tsx
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { useEffect, useMemo, useState } from 'react'
|
|
4
|
+
import { useRouter } from 'next/navigation'
|
|
4
5
|
import { AreaChart, Area, ResponsiveContainer, Tooltip } from 'recharts'
|
|
5
6
|
import { useAppStore } from '@/stores/use-app-store'
|
|
6
7
|
import { useChatStore } from '@/stores/use-chat-store'
|
|
7
8
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
9
|
+
import { HomeLaunchpad } from '@/components/home/home-launchpad'
|
|
8
10
|
import { useMountedRef } from '@/hooks/use-mounted-ref'
|
|
9
11
|
import { useNow } from '@/hooks/use-now'
|
|
10
12
|
import { api } from '@/lib/app/api-client'
|
|
11
13
|
import { useNavigate } from '@/lib/app/navigation'
|
|
14
|
+
import { safeStorageGet, safeStorageRemove } from '@/lib/app/safe-storage'
|
|
12
15
|
import { isLocalhostBrowser, isVisibleSessionForViewer } from '@/lib/observability/local-observability'
|
|
13
16
|
import { getSessionLastMessage } from '@/lib/chat/session-summary'
|
|
17
|
+
import { DEFAULT_BUILDER_ROUTE, deriveHomeMode, HOME_LAUNCHPAD_AFTER_SETUP_KEY } from '@/lib/home-launchpad'
|
|
14
18
|
import { getNotificationActivityAt, getNotificationOccurrenceCount } from '@/lib/notifications/notification-utils'
|
|
15
19
|
import { timeAgo, timeUntil } from '@/lib/time-format'
|
|
16
20
|
import type { Agent, Session, BoardTask, AppNotification, ActivityEntry } from '@/types'
|
|
@@ -79,6 +83,7 @@ const PLATFORM_LABELS: Record<string, string> = {
|
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
export default function HomePage() {
|
|
86
|
+
const router = useRouter()
|
|
82
87
|
const now = useNow()
|
|
83
88
|
const agents = useAppStore((s) => s.agents)
|
|
84
89
|
const sessions = useAppStore((s) => s.sessions)
|
|
@@ -103,14 +108,22 @@ export default function HomePage() {
|
|
|
103
108
|
const [costTrend, setCostTrend] = useState<{ cost: number; bucket: string }[]>([])
|
|
104
109
|
const [localhostBrowser, setLocalhostBrowser] = useState(false)
|
|
105
110
|
const [pageReady, setPageReady] = useState(false)
|
|
111
|
+
const [launchpadFlag, setLaunchpadFlag] = useState(false)
|
|
106
112
|
const mountedRef = useMountedRef()
|
|
107
113
|
|
|
108
114
|
useEffect(() => {
|
|
109
115
|
setLocalhostBrowser(isLocalhostBrowser())
|
|
110
116
|
}, [])
|
|
111
117
|
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
const hasFlag = safeStorageGet(HOME_LAUNCHPAD_AFTER_SETUP_KEY) === '1'
|
|
120
|
+
setLaunchpadFlag(hasFlag)
|
|
121
|
+
if (hasFlag) safeStorageRemove(HOME_LAUNCHPAD_AFTER_SETUP_KEY)
|
|
122
|
+
}, [])
|
|
123
|
+
|
|
112
124
|
const allAgents = Object.values(agents).filter((a) => !a.trashedAt)
|
|
113
125
|
const pinnedAgents = allAgents.filter((a) => a.pinned)
|
|
126
|
+
const firstAgent = allAgents[0] || null
|
|
114
127
|
|
|
115
128
|
const recentChats = useMemo(
|
|
116
129
|
() =>
|
|
@@ -123,10 +136,14 @@ export default function HomePage() {
|
|
|
123
136
|
|
|
124
137
|
// Quick stats
|
|
125
138
|
const agentCount = allAgents.length
|
|
139
|
+
const sessionCount = Object.keys(sessions).length
|
|
126
140
|
const allTasks = Object.values(tasks)
|
|
141
|
+
const totalTaskCount = allTasks.length
|
|
127
142
|
const activeTaskCount = allTasks.filter((t) => t.status === 'running' || t.status === 'queued').length
|
|
128
143
|
const allConnectors = Object.values(connectors)
|
|
129
144
|
const activeConnectorCount = allConnectors.filter((c) => c.status === 'running').length
|
|
145
|
+
const connectorCount = allConnectors.length
|
|
146
|
+
const scheduleCount = Object.keys(schedules).length
|
|
130
147
|
|
|
131
148
|
// Agents with running tasks
|
|
132
149
|
const runningAgentIds = useMemo(() => {
|
|
@@ -223,6 +240,51 @@ export default function HomePage() {
|
|
|
223
240
|
)
|
|
224
241
|
}
|
|
225
242
|
|
|
243
|
+
const homeMode = deriveHomeMode({
|
|
244
|
+
hasLaunchpadFlag: launchpadFlag,
|
|
245
|
+
agentCount,
|
|
246
|
+
sessionCount,
|
|
247
|
+
taskCount: totalTaskCount,
|
|
248
|
+
scheduleCount,
|
|
249
|
+
connectorCount,
|
|
250
|
+
todayCost,
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
const openFirstAgent = () => {
|
|
254
|
+
if (firstAgent) {
|
|
255
|
+
navigateTo('agents', firstAgent.id)
|
|
256
|
+
return
|
|
257
|
+
}
|
|
258
|
+
navigateTo('agents')
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const openBuilder = () => {
|
|
262
|
+
router.push(DEFAULT_BUILDER_ROUTE)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (homeMode === 'launchpad') {
|
|
266
|
+
return (
|
|
267
|
+
<MainContent>
|
|
268
|
+
<div className="flex-1 overflow-y-auto">
|
|
269
|
+
<HomeLaunchpad
|
|
270
|
+
firstAgent={firstAgent}
|
|
271
|
+
agentCount={agentCount}
|
|
272
|
+
sessionCount={sessionCount}
|
|
273
|
+
taskCount={totalTaskCount}
|
|
274
|
+
scheduleCount={scheduleCount}
|
|
275
|
+
connectorCount={connectorCount}
|
|
276
|
+
todayCost={todayCost}
|
|
277
|
+
onOpenFirstAgent={openFirstAgent}
|
|
278
|
+
onOpenProtocols={() => navigateTo('protocols')}
|
|
279
|
+
onOpenBuilder={openBuilder}
|
|
280
|
+
onOpenConnectors={() => navigateTo('connectors')}
|
|
281
|
+
onOpenUsage={() => navigateTo('usage')}
|
|
282
|
+
/>
|
|
283
|
+
</div>
|
|
284
|
+
</MainContent>
|
|
285
|
+
)
|
|
286
|
+
}
|
|
287
|
+
|
|
226
288
|
return (
|
|
227
289
|
<MainContent>
|
|
228
290
|
<div className="flex-1 overflow-y-auto">
|
|
@@ -16,7 +16,9 @@ import {
|
|
|
16
16
|
import { useTasksQuery } from '@/features/tasks/queries'
|
|
17
17
|
import { MainContent } from '@/components/layout/main-content'
|
|
18
18
|
import { StructuredSessionLauncher } from '@/components/protocols/structured-session-launcher'
|
|
19
|
+
import { TemplateGallery } from '@/components/protocols/builder/template-gallery'
|
|
19
20
|
import { GroundingPanel } from '@/components/knowledge/grounding-panel'
|
|
21
|
+
import { DEFAULT_BUILDER_ROUTE } from '@/lib/home-launchpad'
|
|
20
22
|
import { timeAgo } from '@/lib/time-format'
|
|
21
23
|
import type {
|
|
22
24
|
BoardTask,
|
|
@@ -390,6 +392,13 @@ export default function ProtocolsPage() {
|
|
|
390
392
|
>
|
|
391
393
|
New template
|
|
392
394
|
</button>
|
|
395
|
+
<button
|
|
396
|
+
type="button"
|
|
397
|
+
onClick={() => router.push(DEFAULT_BUILDER_ROUTE)}
|
|
398
|
+
className="rounded-[10px] border border-white/[0.08] bg-white/[0.04] px-3 py-2 text-[12px] font-700 text-text-2 transition-all hover:bg-white/[0.08] cursor-pointer"
|
|
399
|
+
>
|
|
400
|
+
Open visual builder
|
|
401
|
+
</button>
|
|
393
402
|
</div>
|
|
394
403
|
</div>
|
|
395
404
|
|
|
@@ -417,6 +426,28 @@ export default function ProtocolsPage() {
|
|
|
417
426
|
</div>
|
|
418
427
|
</div>
|
|
419
428
|
|
|
429
|
+
<div className="mt-4 rounded-[16px] border border-white/[0.06] bg-white/[0.03] p-4">
|
|
430
|
+
<div className="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
|
|
431
|
+
<div className="max-w-[720px]">
|
|
432
|
+
<div className="text-[11px] font-700 uppercase tracking-[0.12em] text-text-3/55">Visual Workflow Templates</div>
|
|
433
|
+
<div className="mt-2 text-[15px] font-700 text-text">Pick a built-in protocol and open it in the builder.</div>
|
|
434
|
+
<div className="mt-2 text-[13px] leading-relaxed text-text-3/72">
|
|
435
|
+
Use the gallery for the fastest path into structured workflows. Custom templates stay here too, so teams can refine reusable runs without dropping straight into JSON first.
|
|
436
|
+
</div>
|
|
437
|
+
</div>
|
|
438
|
+
<button
|
|
439
|
+
type="button"
|
|
440
|
+
onClick={() => router.push(DEFAULT_BUILDER_ROUTE)}
|
|
441
|
+
className="rounded-[10px] bg-accent-bright px-3 py-2 text-[12px] font-700 text-black transition-all hover:opacity-90 cursor-pointer"
|
|
442
|
+
>
|
|
443
|
+
Open builder
|
|
444
|
+
</button>
|
|
445
|
+
</div>
|
|
446
|
+
<div className="mt-4">
|
|
447
|
+
<TemplateGallery templates={templates} />
|
|
448
|
+
</div>
|
|
449
|
+
</div>
|
|
450
|
+
|
|
420
451
|
<details className="mt-4 rounded-[16px] border border-white/[0.06] bg-white/[0.03] p-4">
|
|
421
452
|
<summary className="cursor-pointer list-none text-[11px] font-700 uppercase tracking-[0.12em] text-text-3/55">
|
|
422
453
|
Advanced Manual Run Builder
|
package/src/app/setup/page.tsx
CHANGED
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
import { useRouter } from 'next/navigation'
|
|
4
4
|
import { safeStorageSet } from '@/lib/app/safe-storage'
|
|
5
|
+
import { HOME_LAUNCHPAD_AFTER_SETUP_KEY } from '@/lib/home-launchpad'
|
|
5
6
|
import { SetupWizard } from '@/components/auth/setup-wizard'
|
|
6
7
|
|
|
7
8
|
export default function SetupPage() {
|
|
8
9
|
const router = useRouter()
|
|
9
10
|
return (
|
|
10
11
|
<SetupWizard
|
|
11
|
-
onComplete={() => {
|
|
12
|
+
onComplete={(destination) => {
|
|
12
13
|
safeStorageSet('sc_setup_done', '1')
|
|
14
|
+
safeStorageSet(HOME_LAUNCHPAD_AFTER_SETUP_KEY, '1')
|
|
13
15
|
window.dispatchEvent(new Event('sc:setup-complete'))
|
|
14
|
-
router.replace('/home')
|
|
16
|
+
router.replace(destination || '/home')
|
|
15
17
|
}}
|
|
16
18
|
/>
|
|
17
19
|
)
|
|
@@ -7,11 +7,11 @@ import { dedup, errorMessage } from '@/lib/shared-utils'
|
|
|
7
7
|
import type { ProviderId, GatewayProfile } from '@/types'
|
|
8
8
|
import {
|
|
9
9
|
SETUP_PROVIDERS,
|
|
10
|
-
SWARMCLAW_ASSISTANT_PROMPT,
|
|
11
10
|
getDefaultModelForProvider,
|
|
11
|
+
type OnboardingPath,
|
|
12
12
|
type SetupProvider,
|
|
13
13
|
} from '@/lib/setup-defaults'
|
|
14
|
-
import {
|
|
14
|
+
import { DEFAULT_BUILDER_ROUTE } from '@/lib/home-launchpad'
|
|
15
15
|
import type {
|
|
16
16
|
SetupStep,
|
|
17
17
|
SetupWizardProps,
|
|
@@ -21,9 +21,10 @@ import type {
|
|
|
21
21
|
ProviderCheckResponse,
|
|
22
22
|
} from './types'
|
|
23
23
|
import { STEP_ORDER } from './types'
|
|
24
|
-
import { requiresSetupProviderVerification, stepIndex } from './utils'
|
|
24
|
+
import { buildStarterDrafts, defaultKitForPath, getStarterKitsForPath, requiresSetupProviderVerification, stepIndex } from './utils'
|
|
25
25
|
import { SparkleIcon } from './shared'
|
|
26
26
|
import { StepProgress } from './step-progress'
|
|
27
|
+
import { StepPath } from './step-path'
|
|
27
28
|
import { StepProviders } from './step-providers'
|
|
28
29
|
import { StepConnect } from './step-connect'
|
|
29
30
|
import { StepAgents } from './step-agents'
|
|
@@ -34,6 +35,9 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
34
35
|
const setUser = useAppStore((s) => s.setUser)
|
|
35
36
|
const loadSettings = useAppStore((s) => s.loadSettings)
|
|
36
37
|
const [step, setStep] = useState<SetupStep>('profile')
|
|
38
|
+
const [onboardingPath, setOnboardingPath] = useState<OnboardingPath>('quick')
|
|
39
|
+
const [starterKitId, setStarterKitId] = useState<string>(defaultKitForPath('quick'))
|
|
40
|
+
const [intentText, setIntentText] = useState('')
|
|
37
41
|
|
|
38
42
|
const [activeProvider, setActiveProvider] = useState<SetupProvider | null>(null)
|
|
39
43
|
const [editingProviderId, setEditingProviderId] = useState<string | null>(null)
|
|
@@ -41,6 +45,7 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
41
45
|
|
|
42
46
|
const [configuredProviders, setConfiguredProviders] = useState<ConfiguredProvider[]>([])
|
|
43
47
|
const [draftAgents, setDraftAgents] = useState<StarterDraftAgent[]>([])
|
|
48
|
+
const [createdAgents, setCreatedAgents] = useState<CreatedAgentSummary[]>([])
|
|
44
49
|
const [saving, setSaving] = useState(false)
|
|
45
50
|
const [error, setError] = useState('')
|
|
46
51
|
|
|
@@ -56,13 +61,23 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
56
61
|
const configuredProviderIds = new Set(configuredProviders.map((cp) => cp.setupProvider))
|
|
57
62
|
const canContinueFromProviders = configuredProviders.length > 0
|
|
58
63
|
|
|
64
|
+
const ensureStarterDrafts = (providers: ConfiguredProvider[], previousDrafts: StarterDraftAgent[] = draftAgents) => {
|
|
65
|
+
if (previousDrafts.length > 0) return previousDrafts
|
|
66
|
+
return buildStarterDrafts({
|
|
67
|
+
starterKitId,
|
|
68
|
+
intentText,
|
|
69
|
+
configuredProviders: providers,
|
|
70
|
+
previousDrafts,
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
59
74
|
const skip = async () => {
|
|
60
75
|
try {
|
|
61
76
|
await api('PUT', '/settings', { setupCompleted: true })
|
|
62
77
|
} catch {
|
|
63
78
|
// Continue anyway.
|
|
64
79
|
}
|
|
65
|
-
onComplete()
|
|
80
|
+
onComplete('/home')
|
|
66
81
|
}
|
|
67
82
|
|
|
68
83
|
const handleProfileContinue = async (userName: string, avatarSeed: string) => {
|
|
@@ -71,6 +86,20 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
71
86
|
} catch { /* still set locally */ }
|
|
72
87
|
setUser(userName)
|
|
73
88
|
loadSettings()
|
|
89
|
+
setStep('path')
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const handlePathChange = (path: OnboardingPath) => {
|
|
93
|
+
setOnboardingPath(path)
|
|
94
|
+
const visibleKits = getStarterKitsForPath(path)
|
|
95
|
+
const currentVisible = visibleKits.some((kit) => kit.id === starterKitId)
|
|
96
|
+
if (!currentVisible) {
|
|
97
|
+
setStarterKitId(defaultKitForPath(path))
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const handlePathContinue = () => {
|
|
102
|
+
setError('')
|
|
74
103
|
setStep('providers')
|
|
75
104
|
}
|
|
76
105
|
|
|
@@ -117,33 +146,8 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
117
146
|
|
|
118
147
|
// If this is the first provider and there are no agents yet, create a default agent
|
|
119
148
|
if (!editingProviderId && draftAgents.length === 0) {
|
|
120
|
-
const
|
|
121
|
-
setDraftAgents(
|
|
122
|
-
id: `auto:${Math.random().toString(36).slice(2, 10)}`,
|
|
123
|
-
templateId: 'auto',
|
|
124
|
-
name: 'Assistant',
|
|
125
|
-
description: 'A helpful assistant.',
|
|
126
|
-
systemPrompt: SWARMCLAW_ASSISTANT_PROMPT,
|
|
127
|
-
soul: '',
|
|
128
|
-
providerConfigId: cp.id,
|
|
129
|
-
setupProvider: cp.setupProvider,
|
|
130
|
-
provider: cp.provider,
|
|
131
|
-
model: cp.defaultModel,
|
|
132
|
-
credentialId: cp.credentialId,
|
|
133
|
-
apiEndpoint: cp.endpoint,
|
|
134
|
-
gatewayProfileId: cp.gatewayProfileId,
|
|
135
|
-
tools: getDefaultAgentToolIds(),
|
|
136
|
-
capabilities: [],
|
|
137
|
-
delegationEnabled: false,
|
|
138
|
-
delegationTargetMode: 'all',
|
|
139
|
-
delegationTargetAgentIds: [],
|
|
140
|
-
autoDraftSkillSuggestions: true,
|
|
141
|
-
orchestratorEnabled: false,
|
|
142
|
-
orchestratorMission: '',
|
|
143
|
-
avatarSeed: Math.random().toString(36).slice(2, 10),
|
|
144
|
-
avatarUrl: null,
|
|
145
|
-
enabled: true,
|
|
146
|
-
}])
|
|
149
|
+
const starterDrafts = ensureStarterDrafts(nextConfigured, [])
|
|
150
|
+
setDraftAgents(starterDrafts)
|
|
147
151
|
} else {
|
|
148
152
|
// Update existing agents that reference the edited provider
|
|
149
153
|
if (editingProviderId) {
|
|
@@ -175,41 +179,13 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
175
179
|
}
|
|
176
180
|
|
|
177
181
|
const goToAgentReview = () => {
|
|
182
|
+
if (draftAgents.length === 0) {
|
|
183
|
+
setDraftAgents(ensureStarterDrafts(configuredProviders, []))
|
|
184
|
+
}
|
|
178
185
|
setError('')
|
|
179
186
|
setStep('agents')
|
|
180
187
|
}
|
|
181
188
|
|
|
182
|
-
const addBlankAgent = () => {
|
|
183
|
-
const defaultProvider = configuredProviders[0] || null
|
|
184
|
-
const newAgent: StarterDraftAgent = {
|
|
185
|
-
id: `custom:${Math.random().toString(36).slice(2, 10)}`,
|
|
186
|
-
templateId: 'custom',
|
|
187
|
-
name: `Agent ${draftAgents.length + 1}`,
|
|
188
|
-
description: '',
|
|
189
|
-
systemPrompt: '',
|
|
190
|
-
soul: '',
|
|
191
|
-
providerConfigId: defaultProvider?.id || null,
|
|
192
|
-
setupProvider: defaultProvider?.setupProvider || null,
|
|
193
|
-
provider: defaultProvider?.provider || null,
|
|
194
|
-
model: defaultProvider?.defaultModel || '',
|
|
195
|
-
credentialId: defaultProvider?.credentialId || null,
|
|
196
|
-
apiEndpoint: defaultProvider?.endpoint || null,
|
|
197
|
-
gatewayProfileId: defaultProvider?.gatewayProfileId || null,
|
|
198
|
-
tools: getDefaultAgentToolIds(),
|
|
199
|
-
capabilities: [],
|
|
200
|
-
delegationEnabled: false,
|
|
201
|
-
delegationTargetMode: 'all',
|
|
202
|
-
delegationTargetAgentIds: [],
|
|
203
|
-
autoDraftSkillSuggestions: true,
|
|
204
|
-
orchestratorEnabled: false,
|
|
205
|
-
orchestratorMission: '',
|
|
206
|
-
avatarSeed: Math.random().toString(36).slice(2, 10),
|
|
207
|
-
avatarUrl: null,
|
|
208
|
-
enabled: true,
|
|
209
|
-
}
|
|
210
|
-
setDraftAgents((current) => [...current, newAgent])
|
|
211
|
-
}
|
|
212
|
-
|
|
213
189
|
const removeAgent = (id: string) => {
|
|
214
190
|
setDraftAgents((current) => current.filter((draft) => draft.id !== id))
|
|
215
191
|
}
|
|
@@ -393,6 +369,7 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
393
369
|
await appState.setCurrentAgent(created[0].id)
|
|
394
370
|
}
|
|
395
371
|
|
|
372
|
+
setCreatedAgents(created)
|
|
396
373
|
setStep('next')
|
|
397
374
|
} catch (err: unknown) {
|
|
398
375
|
setError(errorMessage(err))
|
|
@@ -405,24 +382,20 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
405
382
|
const enabledDrafts = draftAgents.filter((draft) => draft.enabled)
|
|
406
383
|
if (enabledDrafts.length === 0) {
|
|
407
384
|
// No agents — go straight to "next" step
|
|
385
|
+
setCreatedAgents([])
|
|
408
386
|
setStep('next')
|
|
409
387
|
return
|
|
410
388
|
}
|
|
411
389
|
await createAgentsAndFinish()
|
|
412
390
|
}
|
|
413
391
|
|
|
414
|
-
const finishSetup = async () => {
|
|
392
|
+
const finishSetup = async (destination = '/home') => {
|
|
415
393
|
try {
|
|
416
394
|
await api('PUT', '/settings', { setupCompleted: true })
|
|
417
395
|
} catch {
|
|
418
396
|
// Continue anyway
|
|
419
397
|
}
|
|
420
|
-
onComplete()
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
const handleNextAddAgent = () => {
|
|
424
|
-
addBlankAgent()
|
|
425
|
-
setStep('agents')
|
|
398
|
+
onComplete(destination)
|
|
426
399
|
}
|
|
427
400
|
|
|
428
401
|
return (
|
|
@@ -447,12 +420,27 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
447
420
|
/>
|
|
448
421
|
)}
|
|
449
422
|
|
|
423
|
+
{step === 'path' && (
|
|
424
|
+
<StepPath
|
|
425
|
+
onboardingPath={onboardingPath}
|
|
426
|
+
starterKitId={starterKitId}
|
|
427
|
+
intentText={intentText}
|
|
428
|
+
onPathChange={handlePathChange}
|
|
429
|
+
onStarterKitChange={setStarterKitId}
|
|
430
|
+
onIntentTextChange={setIntentText}
|
|
431
|
+
onContinue={handlePathContinue}
|
|
432
|
+
onBack={() => setStep('profile')}
|
|
433
|
+
onSkip={skip}
|
|
434
|
+
/>
|
|
435
|
+
)}
|
|
436
|
+
|
|
450
437
|
{step === 'providers' && (
|
|
451
438
|
<StepProviders
|
|
452
439
|
configuredProviders={configuredProviders}
|
|
453
440
|
configuredProviderIds={configuredProviderIds}
|
|
454
441
|
error={error}
|
|
455
442
|
canContinue={canContinueFromProviders}
|
|
443
|
+
onBack={() => setStep('path')}
|
|
456
444
|
onSelectProvider={selectProvider}
|
|
457
445
|
onRemoveProvider={removeProvider}
|
|
458
446
|
onContinue={goToAgentReview}
|
|
@@ -467,8 +455,8 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
467
455
|
initialLabel={activeProviderLabel}
|
|
468
456
|
editingProvider={editingProvider}
|
|
469
457
|
configuredProviders={configuredProviders}
|
|
470
|
-
starterKitId={
|
|
471
|
-
intentText=
|
|
458
|
+
starterKitId={starterKitId}
|
|
459
|
+
intentText={intentText}
|
|
472
460
|
onSaveProvider={handleSaveProvider}
|
|
473
461
|
onBack={handleBackFromConnect}
|
|
474
462
|
onSkip={skip}
|
|
@@ -492,9 +480,13 @@ export function SetupWizard({ onComplete }: SetupWizardProps) {
|
|
|
492
480
|
|
|
493
481
|
{step === 'next' && (
|
|
494
482
|
<StepNext
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
483
|
+
createdAgents={createdAgents}
|
|
484
|
+
onContinueToDashboard={() => finishSetup('/home')}
|
|
485
|
+
onOpenFirstAgent={() => finishSetup(createdAgents[0]?.id ? `/agents/${encodeURIComponent(createdAgents[0].id)}` : '/agents')}
|
|
486
|
+
onOpenProtocols={() => finishSetup('/protocols')}
|
|
487
|
+
onOpenBuilder={() => finishSetup(DEFAULT_BUILDER_ROUTE)}
|
|
488
|
+
onOpenConnectors={() => finishSetup('/connectors')}
|
|
489
|
+
onOpenUsage={() => finishSetup('/usage')}
|
|
498
490
|
/>
|
|
499
491
|
)}
|
|
500
492
|
|
|
@@ -1,68 +1,80 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
+
import { LaunchActionCard } from '@/components/shared/launch-action-card'
|
|
3
4
|
import type { StepNextProps } from './types'
|
|
4
5
|
import { StepShell } from './shared'
|
|
5
6
|
|
|
6
7
|
export function StepNext({
|
|
7
|
-
|
|
8
|
-
onAddAgent,
|
|
8
|
+
createdAgents,
|
|
9
9
|
onContinueToDashboard,
|
|
10
|
+
onOpenFirstAgent,
|
|
11
|
+
onOpenProtocols,
|
|
12
|
+
onOpenBuilder,
|
|
13
|
+
onOpenConnectors,
|
|
14
|
+
onOpenUsage,
|
|
10
15
|
}: StepNextProps) {
|
|
16
|
+
const firstAgent = createdAgents[0] || null
|
|
17
|
+
|
|
11
18
|
return (
|
|
12
|
-
<StepShell>
|
|
19
|
+
<StepShell wide>
|
|
13
20
|
<h1 className="font-display text-[36px] font-800 leading-[1.05] tracking-[-0.04em] mb-3">
|
|
14
|
-
|
|
21
|
+
Launch Your Workspace
|
|
15
22
|
</h1>
|
|
16
|
-
<p className="text-[15px] text-text-2 mb-
|
|
17
|
-
|
|
23
|
+
<p className="text-[15px] text-text-2 mb-2">
|
|
24
|
+
Setup is complete. Start from the path that gets you to an actual result fastest.
|
|
25
|
+
</p>
|
|
26
|
+
<p className="text-[13px] text-text-3 mb-7">
|
|
27
|
+
{firstAgent
|
|
28
|
+
? `${firstAgent.name} is ready to use.`
|
|
29
|
+
: 'You finished setup without starter agents, so the launch options below focus on wiring up the rest of the workspace.'}
|
|
18
30
|
</p>
|
|
19
31
|
|
|
20
|
-
<div className="
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
32
|
+
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3 mb-8">
|
|
33
|
+
<LaunchActionCard
|
|
34
|
+
title={firstAgent ? 'Open First Agent Chat' : 'Open Agents'}
|
|
35
|
+
description={firstAgent
|
|
36
|
+
? `Jump straight into ${firstAgent.name} and start working from the workspace you just created.`
|
|
37
|
+
: 'Open the agents workspace so you can create or tune the first agent manually.'}
|
|
38
|
+
actionLabel={firstAgent ? 'Open Chat' : 'Open Agents'}
|
|
39
|
+
onClick={onOpenFirstAgent}
|
|
40
|
+
tone="primary"
|
|
41
|
+
/>
|
|
42
|
+
<LaunchActionCard
|
|
43
|
+
title="Start Structured Session"
|
|
44
|
+
description="Open bounded collaboration runs for reviews, planning rounds, decision-making, or focused multi-agent work."
|
|
45
|
+
actionLabel="Open Protocols"
|
|
46
|
+
onClick={onOpenProtocols}
|
|
47
|
+
/>
|
|
48
|
+
<LaunchActionCard
|
|
49
|
+
title="Open Workflow Builder"
|
|
50
|
+
description="Jump into the visual protocol builder if you want a reusable orchestration graph instead of a one-off run."
|
|
51
|
+
actionLabel="Open Builder"
|
|
52
|
+
onClick={onOpenBuilder}
|
|
53
|
+
/>
|
|
54
|
+
<LaunchActionCard
|
|
55
|
+
title="Connect a Platform"
|
|
56
|
+
description="Bridge agents into Discord, Slack, Telegram, WhatsApp, or other runtime connectors."
|
|
57
|
+
actionLabel="Open Connectors"
|
|
58
|
+
onClick={onOpenConnectors}
|
|
59
|
+
/>
|
|
60
|
+
<LaunchActionCard
|
|
61
|
+
title="Review Usage"
|
|
62
|
+
description="Inspect cost, provider health, and agent activity so the workspace stays observable from day one."
|
|
63
|
+
actionLabel="Open Usage"
|
|
64
|
+
onClick={onOpenUsage}
|
|
65
|
+
/>
|
|
66
|
+
<LaunchActionCard
|
|
67
|
+
title="Go to Dashboard"
|
|
68
|
+
description="Land on the main home view. Fresh workspaces open in guided launch mode before switching to the normal ops dashboard."
|
|
69
|
+
actionLabel="Open Home"
|
|
70
|
+
onClick={onContinueToDashboard}
|
|
71
|
+
/>
|
|
59
72
|
</div>
|
|
60
73
|
|
|
61
74
|
<button
|
|
75
|
+
type="button"
|
|
62
76
|
onClick={onContinueToDashboard}
|
|
63
|
-
className="px-10 py-3.5 rounded-[14px] border-none bg-accent-bright text-white text-[15px] font-display font-600
|
|
64
|
-
cursor-pointer hover:brightness-110 active:scale-[0.97] transition-all duration-200
|
|
65
|
-
shadow-[0_6px_28px_rgba(99,102,241,0.3)]"
|
|
77
|
+
className="px-10 py-3.5 rounded-[14px] border-none bg-accent-bright text-white text-[15px] font-display font-600 cursor-pointer hover:brightness-110 active:scale-[0.97] transition-all duration-200 shadow-[0_6px_28px_rgba(99,102,241,0.3)]"
|
|
66
78
|
>
|
|
67
79
|
Continue to Dashboard
|
|
68
80
|
</button>
|