@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
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from 'next/server'
|
|
2
|
-
import { enqueueSessionRun } from '@/lib/server/session-run-manager'
|
|
3
|
-
import { loadSessions } from '@/lib/server/storage'
|
|
4
|
-
import {
|
|
5
|
-
buildMainLoopHeartbeatPrompt,
|
|
6
|
-
getMainLoopStateForSession,
|
|
7
|
-
isMainSession,
|
|
8
|
-
pushMainLoopEventToMainSessions,
|
|
9
|
-
setMainLoopStateForSession,
|
|
10
|
-
} from '@/lib/server/main-agent-loop'
|
|
11
|
-
|
|
12
|
-
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
13
|
-
const { id } = await params
|
|
14
|
-
const sessions = loadSessions()
|
|
15
|
-
const session = sessions[id]
|
|
16
|
-
if (!session) return new NextResponse('Session not found', { status: 404 })
|
|
17
|
-
if (!isMainSession(session)) return new NextResponse('Main-loop controls only apply to agent thread sessions', { status: 400 })
|
|
18
|
-
const state = getMainLoopStateForSession(id)
|
|
19
|
-
return NextResponse.json({ sessionId: id, state })
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
23
|
-
const { id } = await params
|
|
24
|
-
const body = await req.json().catch(() => ({}))
|
|
25
|
-
const action = typeof body.action === 'string' ? body.action.trim() : ''
|
|
26
|
-
|
|
27
|
-
const sessions = loadSessions()
|
|
28
|
-
const session = sessions[id]
|
|
29
|
-
if (!session) return new NextResponse('Session not found', { status: 404 })
|
|
30
|
-
if (!isMainSession(session)) return new NextResponse('Main-loop controls only apply to agent thread sessions', { status: 400 })
|
|
31
|
-
|
|
32
|
-
if (action === 'pause') {
|
|
33
|
-
const state = setMainLoopStateForSession(id, { paused: true })
|
|
34
|
-
return NextResponse.json({ ok: true, action, state })
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (action === 'resume') {
|
|
38
|
-
const state = setMainLoopStateForSession(id, { paused: false })
|
|
39
|
-
return NextResponse.json({ ok: true, action, state })
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (action === 'set_goal') {
|
|
43
|
-
const goal = typeof body.goal === 'string' ? body.goal.trim() : ''
|
|
44
|
-
if (!goal) return new NextResponse('goal is required for set_goal', { status: 400 })
|
|
45
|
-
const state = setMainLoopStateForSession(id, {
|
|
46
|
-
goal,
|
|
47
|
-
status: 'progress',
|
|
48
|
-
paused: false,
|
|
49
|
-
followupChainCount: 0,
|
|
50
|
-
})
|
|
51
|
-
pushMainLoopEventToMainSessions({
|
|
52
|
-
type: 'operator_goal',
|
|
53
|
-
text: `Operator set mission goal: ${goal}`,
|
|
54
|
-
user: session.user || null,
|
|
55
|
-
})
|
|
56
|
-
return NextResponse.json({ ok: true, action, state })
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (action === 'set_mode') {
|
|
60
|
-
const mode = body.mode === 'assist' ? 'assist' : body.mode === 'autonomous' ? 'autonomous' : null
|
|
61
|
-
if (!mode) return new NextResponse('mode must be "assist" or "autonomous"', { status: 400 })
|
|
62
|
-
const state = setMainLoopStateForSession(id, { autonomyMode: mode })
|
|
63
|
-
return NextResponse.json({ ok: true, action, state })
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (action === 'clear_events') {
|
|
67
|
-
const state = setMainLoopStateForSession(id, { pendingEvents: [] })
|
|
68
|
-
return NextResponse.json({ ok: true, action, state })
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (action === 'nudge') {
|
|
72
|
-
const state = getMainLoopStateForSession(id)
|
|
73
|
-
if (state?.paused) {
|
|
74
|
-
return new NextResponse('Mission loop is paused; resume first', { status: 409 })
|
|
75
|
-
}
|
|
76
|
-
const note = typeof body.note === 'string' ? body.note.trim() : ''
|
|
77
|
-
const prompt = buildMainLoopHeartbeatPrompt(
|
|
78
|
-
session,
|
|
79
|
-
'Operator requested manual nudge: execute one concrete next step now and report concise progress.',
|
|
80
|
-
)
|
|
81
|
-
const message = note ? `${prompt}\nOperator note: ${note.slice(0, 500)}` : prompt
|
|
82
|
-
const run = enqueueSessionRun({
|
|
83
|
-
sessionId: id,
|
|
84
|
-
message,
|
|
85
|
-
internal: true,
|
|
86
|
-
source: 'mission-control',
|
|
87
|
-
mode: 'collect',
|
|
88
|
-
dedupeKey: `mission-control:nudge:${id}`,
|
|
89
|
-
})
|
|
90
|
-
return NextResponse.json({ ok: true, action, runId: run.runId, position: run.position, deduped: run.deduped || false, state })
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return new NextResponse('Unknown action. Use pause, resume, set_goal, set_mode, clear_events, or nudge.', { status: 400 })
|
|
94
|
-
}
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState, useMemo } from 'react'
|
|
4
|
-
import { BottomSheet } from '@/components/shared/bottom-sheet'
|
|
5
|
-
import { SectionLabel } from '@/components/shared/section-label'
|
|
6
|
-
import { useAppStore } from '@/stores/use-app-store'
|
|
7
|
-
import { api } from '@/lib/api-client'
|
|
8
|
-
import { PROVIDERS } from '@/lib/providers'
|
|
9
|
-
import { TOOL_LABELS, TOOL_DESCRIPTIONS } from '@/components/chat/tool-call-bubble'
|
|
10
|
-
import { toast } from 'sonner'
|
|
11
|
-
import { useRouter } from 'next/navigation'
|
|
12
|
-
import { genId } from '@/lib/id'
|
|
13
|
-
import type { ProviderType, SessionTool } from '@/types'
|
|
14
|
-
|
|
15
|
-
interface Props {
|
|
16
|
-
open: boolean
|
|
17
|
-
onClose: () => void
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function NewChatSheet({ open, onClose }: Props) {
|
|
21
|
-
const router = useRouter()
|
|
22
|
-
const agents = useAppStore((s) => s.agents)
|
|
23
|
-
const loadSessions = useAppStore((s) => s.loadSessions)
|
|
24
|
-
|
|
25
|
-
const [selectedAgentId, setSelectedAgentId] = useState<string>('')
|
|
26
|
-
const [provider, setProvider] = useState<ProviderType>('openai')
|
|
27
|
-
const [model, setModel] = useState<string>('')
|
|
28
|
-
const [endpoint, setEndpoint] = useState('')
|
|
29
|
-
const [selectedTools, setSelectedTools] = useState<SessionTool[]>([])
|
|
30
|
-
const [loading, setLoading] = useState(false)
|
|
31
|
-
|
|
32
|
-
const agentList = useMemo(() => Object.values(agents).sort((a, b) => b.updatedAt - a.updatedAt), [agents])
|
|
33
|
-
const currentProvider = PROVIDERS[provider]
|
|
34
|
-
|
|
35
|
-
const reset = () => {
|
|
36
|
-
setSelectedAgentId('')
|
|
37
|
-
setProvider('openai')
|
|
38
|
-
setModel('')
|
|
39
|
-
setEndpoint('')
|
|
40
|
-
setSelectedTools([])
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const handleCreate = async () => {
|
|
44
|
-
setLoading(true)
|
|
45
|
-
try {
|
|
46
|
-
const agent = selectedAgentId ? agents[selectedAgentId] : null
|
|
47
|
-
const id = genId(8)
|
|
48
|
-
const now = Date.now()
|
|
49
|
-
|
|
50
|
-
const agentTools = agent?.plugins || (selectedTools.length ? selectedTools : undefined)
|
|
51
|
-
|
|
52
|
-
const session = {
|
|
53
|
-
id,
|
|
54
|
-
name: agent ? `Chat with ${agent.name}` : `New Session (${model || provider})`,
|
|
55
|
-
provider: agent ? agent.provider : provider,
|
|
56
|
-
model: agent ? agent.model : model,
|
|
57
|
-
apiEndpoint: agent ? agent.apiEndpoint : (endpoint || undefined),
|
|
58
|
-
credentialId: agent ? agent.credentialId : undefined,
|
|
59
|
-
plugins: agentTools || undefined,
|
|
60
|
-
messages: [],
|
|
61
|
-
createdAt: now,
|
|
62
|
-
updatedAt: now,
|
|
63
|
-
active: true,
|
|
64
|
-
agentId: selectedAgentId || undefined,
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
await api('POST', '/chats', session)
|
|
68
|
-
await loadSessions()
|
|
69
|
-
router.push(`/chat?session=${id}`)
|
|
70
|
-
onClose()
|
|
71
|
-
reset()
|
|
72
|
-
} catch (err: unknown) {
|
|
73
|
-
toast.error(err instanceof Error ? err.message : 'Failed to create session')
|
|
74
|
-
} finally {
|
|
75
|
-
setLoading(false)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const inputClass = "w-full py-3 px-4 rounded-[14px] bg-surface border border-white/[0.06] text-text placeholder:text-text-3/50 outline-none focus:border-accent-bright/30 transition-all"
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<BottomSheet open={open} onClose={onClose}>
|
|
83
|
-
<div className="mb-10">
|
|
84
|
-
<h2 className="font-display text-[28px] font-700 tracking-[-0.03em] mb-2">New Session</h2>
|
|
85
|
-
<p className="text-[14px] text-text-3">Start a new conversation with an agent or a direct model.</p>
|
|
86
|
-
</div>
|
|
87
|
-
|
|
88
|
-
<div className="mb-8">
|
|
89
|
-
<SectionLabel>Select Agent</SectionLabel>
|
|
90
|
-
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
|
91
|
-
<button
|
|
92
|
-
onClick={() => setSelectedAgentId('')}
|
|
93
|
-
className={`flex flex-col items-center justify-center gap-2 p-4 rounded-[18px] border transition-all duration-200 cursor-pointer
|
|
94
|
-
${!selectedAgentId
|
|
95
|
-
? 'bg-accent-soft border-accent-bright/25 text-accent-bright shadow-[0_0_25px_rgba(99,102,241,0.12)]'
|
|
96
|
-
: 'bg-surface border-white/[0.06] text-text-3 hover:bg-surface-2 hover:border-white/[0.08]'}`}
|
|
97
|
-
>
|
|
98
|
-
<div className={`w-10 h-10 rounded-full flex items-center justify-center ${!selectedAgentId ? 'bg-accent-bright/20' : 'bg-white/[0.04]'}`}>
|
|
99
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
100
|
-
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" /><circle cx="12" cy="7" r="4" />
|
|
101
|
-
</svg>
|
|
102
|
-
</div>
|
|
103
|
-
<span className="text-[13px] font-600">Direct Model</span>
|
|
104
|
-
</button>
|
|
105
|
-
|
|
106
|
-
{agentList.map((a) => (
|
|
107
|
-
<button
|
|
108
|
-
key={a.id}
|
|
109
|
-
onClick={() => setSelectedAgentId(a.id)}
|
|
110
|
-
className={`flex flex-col items-center justify-center gap-2 p-4 rounded-[18px] border transition-all duration-200 cursor-pointer
|
|
111
|
-
${selectedAgentId === a.id
|
|
112
|
-
? 'bg-accent-soft border-accent-bright/25 text-accent-bright shadow-[0_0_25px_rgba(99,102,241,0.12)]'
|
|
113
|
-
: 'bg-surface border-white/[0.06] text-text-3 hover:bg-surface-2 hover:border-white/[0.08]'}`}
|
|
114
|
-
>
|
|
115
|
-
<div className="w-10 h-10 rounded-full bg-accent-bright/10 overflow-hidden">
|
|
116
|
-
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
117
|
-
<img src={`https://api.dicebear.com/7.x/bottts-neutral/svg?seed=${a.avatarSeed || a.id}`} alt="" />
|
|
118
|
-
</div>
|
|
119
|
-
<span className="text-[13px] font-600 truncate w-full text-center px-1">{a.name}</span>
|
|
120
|
-
</button>
|
|
121
|
-
))}
|
|
122
|
-
</div>
|
|
123
|
-
</div>
|
|
124
|
-
|
|
125
|
-
{!selectedAgentId && (
|
|
126
|
-
<>
|
|
127
|
-
<div className="grid grid-cols-2 gap-4 mb-6">
|
|
128
|
-
<div>
|
|
129
|
-
<SectionLabel>Provider</SectionLabel>
|
|
130
|
-
<select
|
|
131
|
-
value={provider}
|
|
132
|
-
onChange={(e) => {
|
|
133
|
-
const p = e.target.value as ProviderType
|
|
134
|
-
setProvider(p)
|
|
135
|
-
setModel(PROVIDERS[p].models[0])
|
|
136
|
-
}}
|
|
137
|
-
className={`${inputClass} appearance-none cursor-pointer`}
|
|
138
|
-
style={{ fontFamily: 'inherit' }}
|
|
139
|
-
>
|
|
140
|
-
{Object.values(PROVIDERS).map((p) => (
|
|
141
|
-
<option key={p.id} value={p.id}>{p.name}</option>
|
|
142
|
-
))}
|
|
143
|
-
</select>
|
|
144
|
-
</div>
|
|
145
|
-
<div>
|
|
146
|
-
<SectionLabel>Model</SectionLabel>
|
|
147
|
-
<select
|
|
148
|
-
value={model}
|
|
149
|
-
onChange={(e) => setModel(e.target.value)}
|
|
150
|
-
className={`${inputClass} appearance-none cursor-pointer`}
|
|
151
|
-
style={{ fontFamily: 'inherit' }}
|
|
152
|
-
>
|
|
153
|
-
{currentProvider.models.map((m) => (
|
|
154
|
-
<option key={m} value={m}>{m}</option>
|
|
155
|
-
))}
|
|
156
|
-
</select>
|
|
157
|
-
</div>
|
|
158
|
-
</div>
|
|
159
|
-
|
|
160
|
-
{currentProvider.requiresEndpoint && (
|
|
161
|
-
<div className="mb-8">
|
|
162
|
-
<SectionLabel>{provider === 'openclaw' ? 'OpenClaw Endpoint' : 'Endpoint'}</SectionLabel>
|
|
163
|
-
<input
|
|
164
|
-
type="text"
|
|
165
|
-
value={endpoint}
|
|
166
|
-
onChange={(e) => setEndpoint(e.target.value)}
|
|
167
|
-
placeholder={currentProvider.defaultEndpoint || 'http://localhost:11434'}
|
|
168
|
-
className={`${inputClass} font-mono text-[14px]`}
|
|
169
|
-
/>
|
|
170
|
-
{provider === 'openclaw' && (
|
|
171
|
-
<p className="text-[11px] text-text-3/60 mt-2">
|
|
172
|
-
The /v1 endpoint of your remote OpenClaw instance
|
|
173
|
-
</p>
|
|
174
|
-
)}
|
|
175
|
-
</div>
|
|
176
|
-
)}
|
|
177
|
-
|
|
178
|
-
{/* Plugins (Capability enablement) */}
|
|
179
|
-
<div className="mb-8">
|
|
180
|
-
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">
|
|
181
|
-
Plugins <span className="normal-case tracking-normal font-normal text-text-3">(optional)</span>
|
|
182
|
-
</label>
|
|
183
|
-
<p className="text-[12px] text-text-3/60 mb-3">Allow this model to execute commands and access files.</p>
|
|
184
|
-
<div className="flex flex-wrap gap-2.5">
|
|
185
|
-
{([
|
|
186
|
-
{ id: 'shell' as SessionTool, label: 'Shell' },
|
|
187
|
-
{ id: 'files' as SessionTool, label: 'Files' },
|
|
188
|
-
{ id: 'edit_file' as SessionTool, label: 'Edit File' },
|
|
189
|
-
{ id: 'web_search' as SessionTool, label: 'Web Search' },
|
|
190
|
-
{ id: 'web_fetch' as SessionTool, label: 'Web Fetch' },
|
|
191
|
-
{ id: 'claude_code' as SessionTool, label: 'Claude Code' },
|
|
192
|
-
{ id: 'codex_cli' as SessionTool, label: 'Codex CLI' },
|
|
193
|
-
{ id: 'opencode_cli' as SessionTool, label: 'OpenCode CLI' },
|
|
194
|
-
]).map(({ id, label }) => {
|
|
195
|
-
const active = selectedTools.includes(id)
|
|
196
|
-
return (
|
|
197
|
-
<button
|
|
198
|
-
key={id}
|
|
199
|
-
onClick={() => {
|
|
200
|
-
setSelectedTools((prev) =>
|
|
201
|
-
active ? prev.filter((t) => t !== id) : [...prev, id],
|
|
202
|
-
)
|
|
203
|
-
}}
|
|
204
|
-
className={`px-4 py-2.5 rounded-[12px] text-[13px] font-600 border cursor-pointer transition-all duration-200 active:scale-[0.97]
|
|
205
|
-
${active
|
|
206
|
-
? 'bg-accent-soft border-accent-bright/25 text-accent-bright shadow-[0_0_20px_rgba(99,102,241,0.1)]'
|
|
207
|
-
: 'bg-surface border-white/[0.06] text-text-3 hover:bg-surface-2 hover:border-white/[0.08]'}`}
|
|
208
|
-
style={{ fontFamily: 'inherit' }}
|
|
209
|
-
>
|
|
210
|
-
{label}
|
|
211
|
-
</button>
|
|
212
|
-
)
|
|
213
|
-
})}
|
|
214
|
-
</div>
|
|
215
|
-
</div>
|
|
216
|
-
</>
|
|
217
|
-
)}
|
|
218
|
-
|
|
219
|
-
{/* Summary when agent selected */}
|
|
220
|
-
{selectedAgentId && agents[selectedAgentId] && (
|
|
221
|
-
<div className="mb-8 px-4 py-3 rounded-[14px] bg-surface border border-white/[0.06]">
|
|
222
|
-
<span className="text-[13px] text-text-3">
|
|
223
|
-
Using <span className="text-text-2 font-600">{agents[selectedAgentId].provider}</span>
|
|
224
|
-
{' / '}
|
|
225
|
-
<span className="text-text-2 font-600">{agents[selectedAgentId].model}</span>
|
|
226
|
-
{agents[selectedAgentId].plugins?.length ? (
|
|
227
|
-
<>
|
|
228
|
-
{' + '}
|
|
229
|
-
{agents[selectedAgentId].plugins!.map((tool, i) => (
|
|
230
|
-
<span key={tool}>
|
|
231
|
-
{i > 0 && ', '}
|
|
232
|
-
<span className="text-sky-400/70 font-600 cursor-help" title={TOOL_DESCRIPTIONS[tool] || tool}>
|
|
233
|
-
{TOOL_LABELS[tool] || tool.replace(/_/g, ' ')}
|
|
234
|
-
</span>
|
|
235
|
-
</span>
|
|
236
|
-
))}
|
|
237
|
-
</>
|
|
238
|
-
) : null}
|
|
239
|
-
</span>
|
|
240
|
-
</div>
|
|
241
|
-
)}
|
|
242
|
-
|
|
243
|
-
<button
|
|
244
|
-
onClick={handleCreate}
|
|
245
|
-
disabled={loading || (!selectedAgentId && !model)}
|
|
246
|
-
className="w-full py-4 rounded-[18px] bg-accent-bright text-white font-display text-[15px] font-700 shadow-[0_0_30px_rgba(56,189,248,0.3)] hover:shadow-[0_0_40px_rgba(56,189,248,0.45)] hover:scale-[1.01] active:scale-[0.99] transition-all disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100 disabled:shadow-none"
|
|
247
|
-
style={{ fontFamily: 'inherit' }}
|
|
248
|
-
>
|
|
249
|
-
{loading ? 'Creating...' : 'Start Session'}
|
|
250
|
-
</button>
|
|
251
|
-
</BottomSheet>
|
|
252
|
-
)
|
|
253
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Returns true for sessions that participate in the main-agent-loop
|
|
3
|
-
* (autonomous followups, mission tracking, etc).
|
|
4
|
-
* This includes agent thread sessions and orchestrated task sessions.
|
|
5
|
-
*/
|
|
6
|
-
export function isMainLoopSession(session: any): boolean {
|
|
7
|
-
if (!session || typeof session !== 'object') return false
|
|
8
|
-
if (session.sessionType === 'orchestrated') return true
|
|
9
|
-
|
|
10
|
-
const id = typeof session.id === 'string' ? session.id.trim() : ''
|
|
11
|
-
if (id.startsWith('agent-thread-')) return true
|
|
12
|
-
|
|
13
|
-
const name = typeof session.name === 'string' ? session.name.trim() : ''
|
|
14
|
-
if (name.startsWith('agent-thread:')) return true
|
|
15
|
-
|
|
16
|
-
return false
|
|
17
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import { isMainMissionSession } from './session-run-manager'
|
|
4
|
-
|
|
5
|
-
describe('isMainMissionSession', () => {
|
|
6
|
-
it('accepts agent-thread sessions', () => {
|
|
7
|
-
assert.equal(
|
|
8
|
-
isMainMissionSession({ id: 'agent-thread-agent_coder-123', name: 'agent-thread:agent_coder', sessionType: 'human' }),
|
|
9
|
-
true,
|
|
10
|
-
)
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('accepts orchestrated sessions', () => {
|
|
14
|
-
assert.equal(
|
|
15
|
-
isMainMissionSession({ id: 'agent-thread-worker-1', name: 'agent-thread:worker', sessionType: 'orchestrated' }),
|
|
16
|
-
true,
|
|
17
|
-
)
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('rejects regular chat sessions', () => {
|
|
21
|
-
assert.equal(
|
|
22
|
-
isMainMissionSession({ id: 'abc123', name: 'New Chat', sessionType: 'human' }),
|
|
23
|
-
false,
|
|
24
|
-
)
|
|
25
|
-
})
|
|
26
|
-
})
|