@swarmclawai/swarmclaw 1.2.3 → 1.2.5
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 +20 -0
- package/bin/daemon-cmd.js +169 -0
- package/bin/server-cmd.js +3 -0
- package/bin/swarmclaw.js +11 -0
- package/package.json +17 -16
- package/src/app/api/agents/[id]/clone/route.ts +3 -32
- package/src/app/api/agents/[id]/route.ts +6 -158
- package/src/app/api/agents/[id]/status/route.ts +2 -3
- package/src/app/api/agents/[id]/thread/route.ts +4 -17
- package/src/app/api/agents/bulk/route.ts +5 -47
- package/src/app/api/agents/route.ts +5 -119
- package/src/app/api/agents/trash/route.ts +13 -24
- package/src/app/api/auth/route.ts +3 -9
- package/src/app/api/autonomy/estop/route.ts +5 -5
- package/src/app/api/chatrooms/[id]/chat/route.ts +11 -5
- package/src/app/api/chatrooms/[id]/route.ts +23 -2
- package/src/app/api/chatrooms/route.ts +13 -2
- package/src/app/api/chats/[id]/clear/route.ts +2 -13
- package/src/app/api/chats/[id]/deploy/route.ts +2 -3
- package/src/app/api/chats/[id]/edit-resend/route.ts +7 -13
- package/src/app/api/chats/[id]/mailbox/route.ts +6 -8
- package/src/app/api/chats/[id]/queue/route.ts +17 -64
- package/src/app/api/chats/[id]/retry/route.ts +4 -22
- package/src/app/api/chats/[id]/route.ts +10 -138
- package/src/app/api/chats/heartbeat/route.ts +2 -1
- package/src/app/api/chats/migrate-messages/route.ts +7 -0
- package/src/app/api/chats/route.ts +13 -134
- package/src/app/api/connectors/[id]/access/route.ts +12 -229
- package/src/app/api/connectors/[id]/doctor/route.ts +1 -1
- package/src/app/api/connectors/[id]/health/route.ts +12 -39
- package/src/app/api/connectors/[id]/route.ts +14 -122
- package/src/app/api/connectors/[id]/webhook/route.ts +1 -1
- package/src/app/api/connectors/doctor/route.ts +1 -1
- package/src/app/api/connectors/route.ts +12 -70
- package/src/app/api/credentials/[id]/route.ts +2 -4
- package/src/app/api/credentials/route.ts +10 -19
- package/src/app/api/daemon/health-check/route.ts +3 -4
- package/src/app/api/daemon/route.ts +10 -8
- package/src/app/api/documents/route.ts +11 -10
- package/src/app/api/external-agents/route.ts +3 -3
- package/src/app/api/gateways/[id]/health/route.ts +2 -3
- package/src/app/api/gateways/[id]/route.ts +7 -122
- package/src/app/api/gateways/route.ts +3 -103
- package/src/app/api/mcp-servers/[id]/tools/route.ts +5 -5
- package/src/app/api/openclaw/dashboard-url/route.ts +8 -16
- package/src/app/api/openclaw/directory/route.ts +2 -2
- package/src/app/api/openclaw/history/route.ts +3 -5
- package/src/app/api/providers/[id]/models/route.test.ts +60 -0
- package/src/app/api/providers/[id]/models/route.ts +33 -1
- package/src/app/api/providers/[id]/route.test.ts +49 -0
- package/src/app/api/providers/[id]/route.ts +30 -1
- package/src/app/api/providers/ollama/route.ts +6 -5
- package/src/app/api/schedules/[id]/route.ts +14 -108
- package/src/app/api/schedules/[id]/run/route.ts +6 -67
- package/src/app/api/schedules/route.ts +9 -51
- package/src/app/api/settings/route.ts +4 -3
- package/src/app/api/setup/check-provider/route.ts +15 -1
- package/src/app/api/setup/openclaw-device/route.ts +2 -2
- package/src/app/api/system/status/route.ts +2 -2
- package/src/app/api/tasks/[id]/route.ts +16 -202
- package/src/app/api/tasks/bulk/route.ts +5 -86
- package/src/app/api/tasks/metrics/route.ts +2 -1
- package/src/app/api/tasks/route.ts +11 -171
- package/src/app/api/upload/route.ts +1 -1
- package/src/app/api/uploads/[filename]/route.ts +1 -1
- package/src/app/api/uploads/route.ts +1 -1
- package/src/app/api/webhooks/[id]/history/route.ts +2 -2
- package/src/app/layout.tsx +9 -6
- package/src/app/protocols/page.tsx +71 -89
- package/src/app/tasks/page.tsx +32 -32
- package/src/cli/index.js +1 -0
- package/src/cli/spec.js +1 -0
- package/src/components/agents/agent-sheet.tsx +51 -25
- package/src/components/agents/inspector-panel.tsx +15 -4
- package/src/components/auth/setup-wizard/index.tsx +27 -18
- package/src/components/auth/setup-wizard/shared.tsx +2 -2
- package/src/components/auth/setup-wizard/step-agents.tsx +51 -38
- package/src/components/auth/setup-wizard/step-connect.tsx +48 -17
- package/src/components/auth/setup-wizard/types.ts +6 -4
- package/src/components/auth/setup-wizard/utils.test.ts +38 -8
- package/src/components/auth/setup-wizard/utils.ts +14 -8
- package/src/components/chatrooms/chatroom-sheet.tsx +16 -276
- package/src/components/connectors/connector-list.tsx +26 -40
- package/src/components/connectors/connector-sheet.tsx +95 -149
- package/src/components/gateways/gateway-sheet.tsx +61 -110
- package/src/components/layout/live-query-sync.tsx +121 -0
- package/src/components/protocols/structured-session-launcher.tsx +24 -45
- package/src/components/providers/app-query-provider.tsx +17 -0
- package/src/components/providers/provider-list.tsx +150 -77
- package/src/components/providers/provider-sheet.tsx +102 -77
- package/src/components/shared/model-combobox.tsx +5 -4
- package/src/components/skills/skill-list.tsx +5 -18
- package/src/components/skills/skill-sheet.tsx +21 -20
- package/src/components/skills/skills-workspace.tsx +48 -87
- package/src/components/tasks/task-card.tsx +20 -13
- package/src/components/tasks/task-column.tsx +22 -7
- package/src/components/tasks/task-list.tsx +8 -11
- package/src/components/tasks/task-sheet.tsx +111 -103
- package/src/features/agents/queries.ts +20 -0
- package/src/features/chatrooms/queries.ts +20 -0
- package/src/features/chats/queries.ts +27 -0
- package/src/features/connectors/queries.ts +145 -0
- package/src/features/credentials/queries.ts +37 -0
- package/src/features/extensions/queries.ts +26 -0
- package/src/features/external-agents/queries.ts +36 -0
- package/src/features/gateways/queries.ts +274 -0
- package/src/features/missions/queries.ts +23 -0
- package/src/features/projects/queries.ts +20 -0
- package/src/features/protocols/queries.ts +149 -0
- package/src/features/providers/queries.ts +142 -0
- package/src/features/settings/queries.ts +20 -0
- package/src/features/skills/queries.ts +182 -0
- package/src/features/tasks/queries.ts +189 -0
- package/src/hooks/use-ws.ts +3 -2
- package/src/lib/agent-provider-options.test.ts +152 -0
- package/src/lib/agent-provider-options.ts +84 -0
- package/src/lib/app/api-client.ts +2 -2
- package/src/lib/providers/index.test.ts +78 -0
- package/src/lib/providers/index.ts +13 -10
- package/src/lib/query/client.ts +17 -0
- package/src/lib/server/agents/agent-runtime-config.ts +6 -6
- package/src/lib/server/agents/agent-service.ts +429 -0
- package/src/lib/server/agents/agent-thread-session.ts +6 -5
- package/src/lib/server/agents/autonomy-contract.ts +1 -4
- package/src/lib/server/agents/delegation-advisory.test.ts +206 -0
- package/src/lib/server/agents/delegation-advisory.ts +251 -0
- package/src/lib/server/agents/main-agent-loop.ts +98 -40
- package/src/lib/server/agents/subagent-runtime.ts +12 -0
- package/src/lib/server/autonomy/supervisor-reflection.test.ts +20 -1
- package/src/lib/server/autonomy/supervisor-reflection.ts +39 -19
- package/src/lib/server/build-llm.ts +7 -15
- package/src/lib/server/capability-router.test.ts +70 -1
- package/src/lib/server/capability-router.ts +24 -99
- package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -15
- package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -4
- package/src/lib/server/chat-execution/chat-turn-finalization.ts +77 -12
- package/src/lib/server/chat-execution/chat-turn-partial-persistence.ts +4 -4
- package/src/lib/server/chat-execution/chat-turn-preflight.ts +2 -2
- package/src/lib/server/chat-execution/chat-turn-preparation.ts +41 -17
- package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -2
- package/src/lib/server/chat-execution/chat-turn-tool-routing.test.ts +45 -0
- package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +48 -17
- package/src/lib/server/chat-execution/continuation-evaluator.ts +4 -1
- package/src/lib/server/chat-execution/direct-memory-intent.test.ts +9 -0
- package/src/lib/server/chat-execution/direct-memory-intent.ts +12 -2
- package/src/lib/server/chat-execution/message-classifier.test.ts +35 -23
- package/src/lib/server/chat-execution/message-classifier.ts +74 -32
- package/src/lib/server/chat-execution/prompt-builder.test.ts +29 -0
- package/src/lib/server/chat-execution/prompt-builder.ts +37 -2
- package/src/lib/server/chat-execution/prompt-sections.test.ts +56 -0
- package/src/lib/server/chat-execution/prompt-sections.ts +193 -0
- package/src/lib/server/chat-execution/stream-agent-chat.ts +63 -7
- package/src/lib/server/chat-execution/stream-continuation.test.ts +36 -0
- package/src/lib/server/chat-execution/stream-continuation.ts +28 -13
- package/src/lib/server/chatrooms/chatroom-agent-signals.ts +26 -18
- package/src/lib/server/chatrooms/chatroom-helpers.ts +19 -18
- package/src/lib/server/chatrooms/chatroom-repository.ts +16 -0
- package/src/lib/server/chatrooms/chatroom-routing.test.ts +96 -0
- package/src/lib/server/chatrooms/chatroom-routing.ts +207 -53
- package/src/lib/server/chatrooms/mailbox-utils.ts +4 -2
- package/src/lib/server/chatrooms/session-mailbox.ts +50 -40
- package/src/lib/server/chats/chat-session-service.ts +410 -0
- package/src/lib/server/connectors/access.ts +1 -1
- package/src/lib/server/connectors/commands.ts +7 -6
- package/src/lib/server/connectors/connector-inbound.ts +14 -7
- package/src/lib/server/connectors/connector-outbound.ts +16 -11
- package/src/lib/server/connectors/connector-service.ts +453 -0
- package/src/lib/server/connectors/delivery.ts +17 -12
- package/src/lib/server/connectors/inbound-audio-transcription.ts +5 -14
- package/src/lib/server/connectors/media.ts +1 -1
- package/src/lib/server/connectors/response-media.ts +1 -1
- package/src/lib/server/connectors/session-consolidation.ts +11 -7
- package/src/lib/server/connectors/session.ts +9 -7
- package/src/lib/server/connectors/voice-note.ts +2 -1
- package/src/lib/server/context-manager.ts +20 -1
- package/src/lib/server/cost.ts +2 -3
- package/src/lib/server/credentials/credential-repository.ts +43 -4
- package/src/lib/server/credentials/credential-service.ts +112 -0
- package/src/lib/server/daemon/admin-metadata.ts +64 -0
- package/src/lib/server/daemon/controller.ts +577 -0
- package/src/lib/server/daemon/daemon-runtime.ts +352 -0
- package/src/lib/server/daemon/daemon-status-repository.ts +63 -0
- package/src/lib/server/daemon/types.ts +101 -0
- package/src/lib/server/embeddings.ts +3 -9
- package/src/lib/server/eval/agent-regression.ts +3 -2
- package/src/lib/server/eval/runner.ts +2 -2
- package/src/lib/server/execution-brief.test.ts +167 -0
- package/src/lib/server/execution-brief.ts +295 -0
- package/src/lib/server/execution-engine/chat-turn.ts +9 -0
- package/src/lib/server/execution-engine/import-boundary.test.ts +44 -0
- package/src/lib/server/execution-engine/index.ts +35 -0
- package/src/lib/server/execution-engine/task-attempt.ts +303 -0
- package/src/lib/server/execution-engine/types.ts +33 -0
- package/src/lib/server/gateways/gateway-profile-repository.ts +47 -3
- package/src/lib/server/gateways/gateway-profile-service.ts +200 -0
- package/src/lib/server/memory/session-archive-memory.ts +12 -10
- package/src/lib/server/messages/message-repository.ts +330 -0
- package/src/lib/server/missions/mission-service/core.ts +8 -6
- package/src/lib/server/openclaw/agent-resolver.ts +2 -3
- package/src/lib/server/openclaw/doctor.ts +1 -1
- package/src/lib/server/openclaw/gateway.test.ts +10 -1
- package/src/lib/server/openclaw/gateway.ts +5 -14
- package/src/lib/server/openclaw/health.ts +3 -11
- package/src/lib/server/openclaw/sync.ts +8 -6
- package/src/lib/server/persistence/storage-context.ts +3 -0
- package/src/lib/server/protocols/protocol-agent-turn.ts +25 -17
- package/src/lib/server/protocols/protocol-normalization.ts +1 -1
- package/src/lib/server/protocols/protocol-queries.ts +13 -7
- package/src/lib/server/protocols/protocol-run-lifecycle.ts +16 -20
- package/src/lib/server/protocols/protocol-run-repository.ts +81 -0
- package/src/lib/server/protocols/protocol-step-processors.ts +23 -31
- package/src/lib/server/protocols/protocol-swarm.ts +8 -8
- package/src/lib/server/protocols/protocol-template-repository.ts +42 -0
- package/src/lib/server/protocols/protocol-templates.ts +4 -2
- package/src/lib/server/protocols/protocol-types.ts +10 -7
- package/src/lib/server/provider-endpoint.ts +7 -12
- package/src/lib/server/provider-model-discovery.ts +2 -11
- package/src/lib/server/query-expansion.ts +5 -6
- package/src/lib/server/run-context.test.ts +365 -0
- package/src/lib/server/run-context.ts +367 -0
- package/src/lib/server/runtime/heartbeat-service.ts +7 -5
- package/src/lib/server/runtime/queue/core.ts +61 -190
- package/src/lib/server/runtime/run-ledger.ts +8 -0
- package/src/lib/server/runtime/session-run-manager/drain.ts +2 -2
- package/src/lib/server/runtime/session-run-manager/enqueue.ts +6 -0
- package/src/lib/server/runtime/session-run-manager/state.ts +4 -0
- package/src/lib/server/schedules/schedule-route-service.ts +230 -0
- package/src/lib/server/service-result.ts +16 -0
- package/src/lib/server/session-note.ts +2 -3
- package/src/lib/server/session-reset-policy.ts +4 -3
- package/src/lib/server/session-tools/connector.ts +9 -6
- package/src/lib/server/session-tools/context-mgmt.ts +58 -9
- package/src/lib/server/session-tools/crud.ts +162 -10
- package/src/lib/server/session-tools/delegate.ts +1 -1
- package/src/lib/server/session-tools/manage-tasks.test.ts +152 -0
- package/src/lib/server/session-tools/memory.ts +6 -4
- package/src/lib/server/session-tools/session-info.test.ts +56 -0
- package/src/lib/server/session-tools/session-info.ts +119 -12
- package/src/lib/server/session-tools/skill-runtime.ts +3 -1
- package/src/lib/server/session-tools/skills.ts +15 -15
- package/src/lib/server/session-tools/subagent.test.ts +115 -1
- package/src/lib/server/session-tools/subagent.ts +125 -7
- package/src/lib/server/session-tools/team-context.ts +4 -3
- package/src/lib/server/session-tools/wallet.ts +0 -58
- package/src/lib/server/sessions/session-lineage.ts +55 -0
- package/src/lib/server/sessions/session-repository.ts +2 -2
- package/src/lib/server/skills/learned-skills.ts +24 -23
- package/src/lib/server/skills/runtime-skill-resolver.ts +2 -1
- package/src/lib/server/skills/skill-repository.ts +136 -13
- package/src/lib/server/skills/skill-suggestions.ts +25 -28
- package/src/lib/server/storage-normalization.test.ts +42 -215
- package/src/lib/server/storage-normalization.ts +98 -0
- package/src/lib/server/storage.ts +19 -0
- package/src/lib/server/structured-extract.ts +3 -14
- package/src/lib/server/tasks/task-followups.ts +16 -11
- package/src/lib/server/tasks/task-result.test.ts +25 -29
- package/src/lib/server/tasks/task-result.ts +5 -9
- package/src/lib/server/tasks/task-route-service.ts +449 -0
- package/src/lib/server/text-normalization.ts +41 -0
- package/src/lib/server/tool-planning.ts +6 -42
- package/src/lib/server/upload-path.ts +5 -0
- package/src/lib/server/working-state/extraction.ts +614 -0
- package/src/lib/server/working-state/normalization.ts +866 -0
- package/src/lib/server/working-state/prompt.ts +60 -0
- package/src/lib/server/working-state/repository.ts +38 -0
- package/src/lib/server/working-state/service.test.ts +253 -0
- package/src/lib/server/working-state/service.ts +293 -0
- package/src/lib/validation/schemas.ts +1 -0
- package/src/lib/ws-client.ts +3 -3
- package/src/stores/slices/task-slice.ts +1 -4
- package/src/stores/use-chatroom-store.ts +2 -2
- package/src/types/index.ts +288 -22
- package/src/views/settings/section-providers.tsx +2 -2
|
@@ -7,146 +7,10 @@ import { BottomSheet } from '@/components/shared/bottom-sheet'
|
|
|
7
7
|
import { ConfirmDialog } from '@/components/shared/confirm-dialog'
|
|
8
8
|
import { toast } from 'sonner'
|
|
9
9
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
10
|
-
import type { Agent
|
|
10
|
+
import type { Agent } from '@/types'
|
|
11
11
|
import { CheckIcon } from '@/components/shared/check-icon'
|
|
12
12
|
import { WORKER_ONLY_PROVIDER_IDS } from '@/lib/provider-sets'
|
|
13
13
|
|
|
14
|
-
function genRuleId(): string {
|
|
15
|
-
return `rule-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface RuleFormState {
|
|
19
|
-
type: 'keyword' | 'capability'
|
|
20
|
-
pattern: string
|
|
21
|
-
keywords: string
|
|
22
|
-
agentId: string
|
|
23
|
-
priority: number
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const emptyRuleForm: RuleFormState = {
|
|
27
|
-
type: 'keyword',
|
|
28
|
-
pattern: '',
|
|
29
|
-
keywords: '',
|
|
30
|
-
agentId: '',
|
|
31
|
-
priority: 10,
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function RoutingRuleForm({
|
|
35
|
-
rule,
|
|
36
|
-
memberAgents,
|
|
37
|
-
onSave,
|
|
38
|
-
onCancel,
|
|
39
|
-
}: {
|
|
40
|
-
rule: RuleFormState
|
|
41
|
-
memberAgents: Agent[]
|
|
42
|
-
onSave: (form: RuleFormState) => void
|
|
43
|
-
onCancel: () => void
|
|
44
|
-
}) {
|
|
45
|
-
const [form, setForm] = useState<RuleFormState>(rule)
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<div className="p-3 rounded-[8px] bg-white/[0.04] border border-white/[0.08] space-y-3">
|
|
49
|
-
<div className="flex gap-2">
|
|
50
|
-
{(['keyword', 'capability'] as const).map((t) => (
|
|
51
|
-
<button
|
|
52
|
-
key={t}
|
|
53
|
-
type="button"
|
|
54
|
-
onClick={() => setForm((f) => ({ ...f, type: t }))}
|
|
55
|
-
className={`flex-1 py-1.5 text-[11px] font-600 capitalize rounded-[6px] cursor-pointer transition-all ${
|
|
56
|
-
form.type === t
|
|
57
|
-
? 'bg-accent-soft text-accent-bright'
|
|
58
|
-
: 'bg-white/[0.04] text-text-3 hover:text-text-2'
|
|
59
|
-
}`}
|
|
60
|
-
>
|
|
61
|
-
{t}
|
|
62
|
-
</button>
|
|
63
|
-
))}
|
|
64
|
-
</div>
|
|
65
|
-
|
|
66
|
-
{form.type === 'keyword' && (
|
|
67
|
-
<>
|
|
68
|
-
<div>
|
|
69
|
-
<label className="block text-[11px] font-600 text-text-3 mb-1">Keywords (comma-separated)</label>
|
|
70
|
-
<input
|
|
71
|
-
type="text"
|
|
72
|
-
value={form.keywords}
|
|
73
|
-
onChange={(e) => setForm((f) => ({ ...f, keywords: e.target.value }))}
|
|
74
|
-
placeholder="e.g. deploy, devops, infrastructure"
|
|
75
|
-
className="w-full px-2.5 py-1.5 rounded-[6px] bg-white/[0.06] border border-white/[0.08] text-[12px] text-text placeholder:text-text-3 focus:outline-none focus:border-accent-bright/40"
|
|
76
|
-
/>
|
|
77
|
-
</div>
|
|
78
|
-
<div>
|
|
79
|
-
<label className="block text-[11px] font-600 text-text-3 mb-1">Regex pattern (optional)</label>
|
|
80
|
-
<input
|
|
81
|
-
type="text"
|
|
82
|
-
value={form.pattern}
|
|
83
|
-
onChange={(e) => setForm((f) => ({ ...f, pattern: e.target.value }))}
|
|
84
|
-
placeholder="e.g. deploy|release|ship"
|
|
85
|
-
className="w-full px-2.5 py-1.5 rounded-[6px] bg-white/[0.06] border border-white/[0.08] text-[12px] text-text placeholder:text-text-3 focus:outline-none focus:border-accent-bright/40"
|
|
86
|
-
/>
|
|
87
|
-
</div>
|
|
88
|
-
</>
|
|
89
|
-
)}
|
|
90
|
-
|
|
91
|
-
{form.type === 'capability' && (
|
|
92
|
-
<div>
|
|
93
|
-
<label className="block text-[11px] font-600 text-text-3 mb-1">Capability pattern</label>
|
|
94
|
-
<input
|
|
95
|
-
type="text"
|
|
96
|
-
value={form.pattern}
|
|
97
|
-
onChange={(e) => setForm((f) => ({ ...f, pattern: e.target.value }))}
|
|
98
|
-
placeholder="e.g. frontend, research, devops"
|
|
99
|
-
className="w-full px-2.5 py-1.5 rounded-[6px] bg-white/[0.06] border border-white/[0.08] text-[12px] text-text placeholder:text-text-3 focus:outline-none focus:border-accent-bright/40"
|
|
100
|
-
/>
|
|
101
|
-
</div>
|
|
102
|
-
)}
|
|
103
|
-
|
|
104
|
-
<div className="flex gap-2">
|
|
105
|
-
<div className="flex-1">
|
|
106
|
-
<label className="block text-[11px] font-600 text-text-3 mb-1">Route to agent</label>
|
|
107
|
-
<select
|
|
108
|
-
value={form.agentId}
|
|
109
|
-
onChange={(e) => setForm((f) => ({ ...f, agentId: e.target.value }))}
|
|
110
|
-
className="w-full px-2.5 py-1.5 rounded-[6px] bg-white/[0.06] border border-white/[0.08] text-[12px] text-text focus:outline-none focus:border-accent-bright/40"
|
|
111
|
-
>
|
|
112
|
-
<option value="">Select agent...</option>
|
|
113
|
-
{memberAgents.map((a) => (
|
|
114
|
-
<option key={a.id} value={a.id}>{a.name}</option>
|
|
115
|
-
))}
|
|
116
|
-
</select>
|
|
117
|
-
</div>
|
|
118
|
-
<div className="w-20">
|
|
119
|
-
<label className="block text-[11px] font-600 text-text-3 mb-1">Priority</label>
|
|
120
|
-
<input
|
|
121
|
-
type="number"
|
|
122
|
-
value={form.priority}
|
|
123
|
-
onChange={(e) => setForm((f) => ({ ...f, priority: parseInt(e.target.value, 10) || 0 }))}
|
|
124
|
-
className="w-full px-2.5 py-1.5 rounded-[6px] bg-white/[0.06] border border-white/[0.08] text-[12px] text-text focus:outline-none focus:border-accent-bright/40"
|
|
125
|
-
/>
|
|
126
|
-
</div>
|
|
127
|
-
</div>
|
|
128
|
-
|
|
129
|
-
<div className="flex gap-2 justify-end">
|
|
130
|
-
<button
|
|
131
|
-
type="button"
|
|
132
|
-
onClick={onCancel}
|
|
133
|
-
className="px-3 py-1.5 text-[11px] font-600 text-text-3 hover:text-text-2 cursor-pointer"
|
|
134
|
-
>
|
|
135
|
-
Cancel
|
|
136
|
-
</button>
|
|
137
|
-
<button
|
|
138
|
-
type="button"
|
|
139
|
-
onClick={() => onSave(form)}
|
|
140
|
-
disabled={!form.agentId || (form.type === 'keyword' && !form.keywords.trim() && !form.pattern.trim()) || (form.type === 'capability' && !form.pattern.trim())}
|
|
141
|
-
className="px-3 py-1.5 text-[11px] font-600 bg-accent-bright text-white rounded-[6px] hover:bg-accent-bright/90 disabled:opacity-50 cursor-pointer"
|
|
142
|
-
>
|
|
143
|
-
Save Rule
|
|
144
|
-
</button>
|
|
145
|
-
</div>
|
|
146
|
-
</div>
|
|
147
|
-
)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
14
|
export function ChatroomSheet() {
|
|
151
15
|
const open = useChatroomStore((s) => s.chatroomSheetOpen)
|
|
152
16
|
const editingId = useChatroomStore((s) => s.editingChatroomId)
|
|
@@ -163,10 +27,8 @@ export function ChatroomSheet() {
|
|
|
163
27
|
const [selectedAgentIds, setSelectedAgentIds] = useState<string[]>([])
|
|
164
28
|
const [chatMode, setChatMode] = useState<'sequential' | 'parallel'>('sequential')
|
|
165
29
|
const [autoAddress, setAutoAddress] = useState(false)
|
|
166
|
-
const [
|
|
30
|
+
const [routingGuidance, setRoutingGuidance] = useState('')
|
|
167
31
|
const [saving, setSaving] = useState(false)
|
|
168
|
-
const [addingRule, setAddingRule] = useState(false)
|
|
169
|
-
const [editingRuleId, setEditingRuleId] = useState<string | null>(null)
|
|
170
32
|
const [confirmDelete, setConfirmDelete] = useState(false)
|
|
171
33
|
|
|
172
34
|
const editing = editingId ? chatrooms[editingId] : null
|
|
@@ -178,17 +40,15 @@ export function ChatroomSheet() {
|
|
|
178
40
|
setSelectedAgentIds([...editing.agentIds])
|
|
179
41
|
setChatMode(editing.chatMode || 'sequential')
|
|
180
42
|
setAutoAddress(editing.autoAddress || false)
|
|
181
|
-
|
|
43
|
+
setRoutingGuidance(editing.routingGuidance || '')
|
|
182
44
|
} else {
|
|
183
45
|
setName('')
|
|
184
46
|
setDescription('')
|
|
185
47
|
setSelectedAgentIds([])
|
|
186
48
|
setChatMode('sequential')
|
|
187
49
|
setAutoAddress(false)
|
|
188
|
-
|
|
50
|
+
setRoutingGuidance('')
|
|
189
51
|
}
|
|
190
|
-
setAddingRule(false)
|
|
191
|
-
setEditingRuleId(null)
|
|
192
52
|
setConfirmDelete(false)
|
|
193
53
|
}, [editing, open])
|
|
194
54
|
|
|
@@ -206,7 +66,7 @@ export function ChatroomSheet() {
|
|
|
206
66
|
agentIds: selectedAgentIds,
|
|
207
67
|
chatMode,
|
|
208
68
|
autoAddress,
|
|
209
|
-
|
|
69
|
+
routingGuidance: routingGuidance.trim() || null,
|
|
210
70
|
}
|
|
211
71
|
if (editing) {
|
|
212
72
|
await updateChatroom(editing.id, payload)
|
|
@@ -245,53 +105,10 @@ export function ChatroomSheet() {
|
|
|
245
105
|
)
|
|
246
106
|
}
|
|
247
107
|
|
|
248
|
-
const handleAddRule = (form: RuleFormState) => {
|
|
249
|
-
const rule: ChatroomRoutingRule = {
|
|
250
|
-
id: genRuleId(),
|
|
251
|
-
type: form.type,
|
|
252
|
-
agentId: form.agentId,
|
|
253
|
-
priority: form.priority,
|
|
254
|
-
...(form.pattern.trim() ? { pattern: form.pattern.trim() } : {}),
|
|
255
|
-
...(form.type === 'keyword' && form.keywords.trim()
|
|
256
|
-
? { keywords: form.keywords.split(',').map((k) => k.trim()).filter(Boolean) }
|
|
257
|
-
: {}),
|
|
258
|
-
}
|
|
259
|
-
setRoutingRules((prev) => [...prev, rule].sort((a, b) => a.priority - b.priority))
|
|
260
|
-
setAddingRule(false)
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const handleEditRule = (form: RuleFormState) => {
|
|
264
|
-
setRoutingRules((prev) =>
|
|
265
|
-
prev.map((r) =>
|
|
266
|
-
r.id === editingRuleId
|
|
267
|
-
? {
|
|
268
|
-
...r,
|
|
269
|
-
type: form.type,
|
|
270
|
-
agentId: form.agentId,
|
|
271
|
-
priority: form.priority,
|
|
272
|
-
pattern: form.pattern.trim() || undefined,
|
|
273
|
-
keywords:
|
|
274
|
-
form.type === 'keyword' && form.keywords.trim()
|
|
275
|
-
? form.keywords.split(',').map((k) => k.trim()).filter(Boolean)
|
|
276
|
-
: undefined,
|
|
277
|
-
}
|
|
278
|
-
: r,
|
|
279
|
-
).sort((a, b) => a.priority - b.priority),
|
|
280
|
-
)
|
|
281
|
-
setEditingRuleId(null)
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const removeRule = (ruleId: string) => {
|
|
285
|
-
setRoutingRules((prev) => prev.filter((r) => r.id !== ruleId))
|
|
286
|
-
}
|
|
287
|
-
|
|
288
108
|
const agentList = Object.values(agents).filter(
|
|
289
109
|
(a: Agent) => !a.trashedAt && !WORKER_ONLY_PROVIDER_IDS.has(a.provider)
|
|
290
110
|
) as Agent[]
|
|
291
111
|
|
|
292
|
-
const memberAgents = agentList.filter((a) => selectedAgentIds.includes(a.id))
|
|
293
|
-
const sortedRules = [...routingRules].sort((a, b) => a.priority - b.priority)
|
|
294
|
-
|
|
295
112
|
return (
|
|
296
113
|
<BottomSheet open={open} onClose={() => setChatroomSheetOpen(false)}>
|
|
297
114
|
<div className="p-6 max-w-[560px] mx-auto">
|
|
@@ -350,7 +167,7 @@ export function ChatroomSheet() {
|
|
|
350
167
|
<div>
|
|
351
168
|
<button
|
|
352
169
|
type="button"
|
|
353
|
-
onClick={() => setAutoAddress((
|
|
170
|
+
onClick={() => setAutoAddress((value) => !value)}
|
|
354
171
|
className="w-full flex items-center gap-2.5 px-3 py-2.5 rounded-[8px] border border-white/[0.08] bg-white/[0.03] cursor-pointer transition-all hover:bg-white/[0.05]"
|
|
355
172
|
>
|
|
356
173
|
<div className={`w-8 h-[18px] rounded-full transition-all relative ${autoAddress ? 'bg-accent-bright' : 'bg-white/[0.12]'}`}>
|
|
@@ -361,7 +178,7 @@ export function ChatroomSheet() {
|
|
|
361
178
|
<p className="text-[11px] text-text-3 mt-0.5">
|
|
362
179
|
{autoAddress
|
|
363
180
|
? 'Every message is sent to all agents, no @mention needed'
|
|
364
|
-
: 'Only agents you @mention
|
|
181
|
+
: 'Only agents you @mention respond unless routing guidance selects someone'}
|
|
365
182
|
</p>
|
|
366
183
|
</div>
|
|
367
184
|
</button>
|
|
@@ -405,95 +222,18 @@ export function ChatroomSheet() {
|
|
|
405
222
|
)}
|
|
406
223
|
</div>
|
|
407
224
|
|
|
408
|
-
{/* Routing Rules */}
|
|
409
225
|
<div>
|
|
410
|
-
<label className="block text-[12px] font-600 text-text-2 mb-1.5">
|
|
411
|
-
Routing Rules ({sortedRules.length})
|
|
412
|
-
</label>
|
|
226
|
+
<label className="block text-[12px] font-600 text-text-2 mb-1.5">Routing Guidance</label>
|
|
413
227
|
<p className="text-[11px] text-text-3 mb-2">
|
|
414
|
-
|
|
228
|
+
Optional. Used only when there is no explicit @mention and auto-address is off. Describe which kinds of messages should go to which members.
|
|
415
229
|
</p>
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
<RoutingRuleForm
|
|
424
|
-
key={rule.id}
|
|
425
|
-
rule={{
|
|
426
|
-
type: rule.type,
|
|
427
|
-
pattern: rule.pattern || '',
|
|
428
|
-
keywords: rule.keywords?.join(', ') || '',
|
|
429
|
-
agentId: rule.agentId,
|
|
430
|
-
priority: rule.priority,
|
|
431
|
-
}}
|
|
432
|
-
memberAgents={memberAgents}
|
|
433
|
-
onSave={handleEditRule}
|
|
434
|
-
onCancel={() => setEditingRuleId(null)}
|
|
435
|
-
/>
|
|
436
|
-
)
|
|
437
|
-
}
|
|
438
|
-
return (
|
|
439
|
-
<div
|
|
440
|
-
key={rule.id}
|
|
441
|
-
className="flex items-center gap-2 px-3 py-2 rounded-[8px] bg-white/[0.04] border border-white/[0.08]"
|
|
442
|
-
>
|
|
443
|
-
<span className="text-[10px] font-700 text-text-3 bg-white/[0.06] px-1.5 py-0.5 rounded">
|
|
444
|
-
P{rule.priority}
|
|
445
|
-
</span>
|
|
446
|
-
<span className="text-[10px] font-600 text-accent-bright/70 uppercase">
|
|
447
|
-
{rule.type}
|
|
448
|
-
</span>
|
|
449
|
-
<span className="text-[12px] text-text-2 flex-1 truncate">
|
|
450
|
-
{rule.type === 'keyword'
|
|
451
|
-
? (rule.keywords?.join(', ') || rule.pattern || '(no match)')
|
|
452
|
-
: (rule.pattern || '(no pattern)')}
|
|
453
|
-
</span>
|
|
454
|
-
<span className="text-[11px] text-text-3 truncate max-w-[100px]">
|
|
455
|
-
{agent?.name || 'Unknown'}
|
|
456
|
-
</span>
|
|
457
|
-
<button
|
|
458
|
-
type="button"
|
|
459
|
-
onClick={() => setEditingRuleId(rule.id)}
|
|
460
|
-
className="text-[11px] text-text-3 hover:text-text-2 cursor-pointer px-1"
|
|
461
|
-
>
|
|
462
|
-
Edit
|
|
463
|
-
</button>
|
|
464
|
-
<button
|
|
465
|
-
type="button"
|
|
466
|
-
onClick={() => removeRule(rule.id)}
|
|
467
|
-
className="text-[11px] text-red-400 hover:text-red-300 cursor-pointer px-1"
|
|
468
|
-
>
|
|
469
|
-
Remove
|
|
470
|
-
</button>
|
|
471
|
-
</div>
|
|
472
|
-
)
|
|
473
|
-
})}
|
|
474
|
-
</div>
|
|
475
|
-
)}
|
|
476
|
-
|
|
477
|
-
{addingRule ? (
|
|
478
|
-
<RoutingRuleForm
|
|
479
|
-
rule={emptyRuleForm}
|
|
480
|
-
memberAgents={memberAgents}
|
|
481
|
-
onSave={handleAddRule}
|
|
482
|
-
onCancel={() => setAddingRule(false)}
|
|
483
|
-
/>
|
|
484
|
-
) : (
|
|
485
|
-
<button
|
|
486
|
-
type="button"
|
|
487
|
-
onClick={() => setAddingRule(true)}
|
|
488
|
-
disabled={memberAgents.length === 0}
|
|
489
|
-
className="w-full py-2 rounded-[8px] border border-dashed border-white/[0.12] text-[12px] font-600 text-text-3 hover:text-text-2 hover:border-white/[0.2] cursor-pointer transition-all disabled:opacity-40 disabled:cursor-not-allowed"
|
|
490
|
-
>
|
|
491
|
-
+ Add Rule
|
|
492
|
-
</button>
|
|
493
|
-
)}
|
|
494
|
-
{memberAgents.length === 0 && (
|
|
495
|
-
<p className="text-[11px] text-text-3 mt-1">Add members first to create routing rules.</p>
|
|
496
|
-
)}
|
|
230
|
+
<textarea
|
|
231
|
+
value={routingGuidance}
|
|
232
|
+
onChange={(e) => setRoutingGuidance(e.target.value)}
|
|
233
|
+
placeholder={'Examples:\nRoute deployment issues to Ops.\nPrefer Maya for design reviews and UI polish.\nSend pricing or market-analysis requests to Research.'}
|
|
234
|
+
rows={6}
|
|
235
|
+
className="w-full px-3 py-2 rounded-[8px] bg-white/[0.06] border border-white/[0.08] text-[13px] text-text placeholder:text-text-3 focus:outline-none focus:border-accent-bright/40 resize-y min-h-[132px]"
|
|
236
|
+
/>
|
|
497
237
|
</div>
|
|
498
238
|
</div>
|
|
499
239
|
|
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
4
4
|
import { useAppStore } from '@/stores/use-app-store'
|
|
5
|
-
import { useChatroomStore } from '@/stores/use-chatroom-store'
|
|
6
|
-
import { useWs } from '@/hooks/use-ws'
|
|
7
|
-
import { useMountedRef } from '@/hooks/use-mounted-ref'
|
|
8
|
-
import { api } from '@/lib/app/api-client'
|
|
9
5
|
import type { Connector } from '@/types'
|
|
10
6
|
import {
|
|
11
7
|
ConnectorPlatformIcon,
|
|
@@ -16,6 +12,9 @@ import {
|
|
|
16
12
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
17
13
|
import { PageLoader } from '@/components/ui/page-loader'
|
|
18
14
|
import { StatusDot } from '@/components/ui/status-dot'
|
|
15
|
+
import { useConnectorsQuery, useConnectorActionMutation } from '@/features/connectors/queries'
|
|
16
|
+
import { useAgentsQuery } from '@/features/agents/queries'
|
|
17
|
+
import { useChatroomsQuery } from '@/features/chatrooms/queries'
|
|
19
18
|
|
|
20
19
|
function relativeTime(ts: number): string {
|
|
21
20
|
const diff = Date.now() - ts
|
|
@@ -45,33 +44,24 @@ function getConnectorGroup(connector: Connector): ConnectorGroup {
|
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
export function ConnectorList({ inSidebar }: { inSidebar?: boolean }) {
|
|
48
|
-
const connectors = useAppStore((s) => s.connectors)
|
|
49
|
-
const loadConnectors = useAppStore((s) => s.loadConnectors)
|
|
50
47
|
const setConnectorSheetOpen = useAppStore((s) => s.setConnectorSheetOpen)
|
|
51
48
|
const setEditingConnectorId = useAppStore((s) => s.setEditingConnectorId)
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
49
|
+
const connectorsQuery = useConnectorsQuery()
|
|
50
|
+
const agentsQuery = useAgentsQuery()
|
|
51
|
+
const chatroomsQuery = useChatroomsQuery()
|
|
52
|
+
const connectorActionMutation = useConnectorActionMutation()
|
|
53
|
+
const connectors = useMemo(() => connectorsQuery.data ?? {}, [connectorsQuery.data])
|
|
54
|
+
const agents = agentsQuery.data ?? {}
|
|
55
|
+
const chatrooms = chatroomsQuery.data ?? {}
|
|
56
56
|
const [toggling, setToggling] = useState<string | null>(null)
|
|
57
57
|
const [reconnecting, setReconnecting] = useState<string | null>(null)
|
|
58
|
-
const [loaded, setLoaded] = useState(false)
|
|
59
58
|
const [error, setError] = useState<string | null>(null)
|
|
60
59
|
const [groupFilter, setGroupFilter] = useState<'all' | ConnectorGroup>('all')
|
|
61
|
-
const mountedRef = useMountedRef()
|
|
62
60
|
const openConnector = useCallback((id: string | null) => {
|
|
63
61
|
setEditingConnectorId(id)
|
|
64
62
|
setConnectorSheetOpen(true)
|
|
65
63
|
}, [setEditingConnectorId, setConnectorSheetOpen])
|
|
66
64
|
|
|
67
|
-
const refresh = useCallback(async () => {
|
|
68
|
-
await Promise.all([loadConnectors(), loadAgents(), loadChatrooms()])
|
|
69
|
-
if (mountedRef.current) setLoaded(true)
|
|
70
|
-
}, [loadConnectors, loadAgents, loadChatrooms, mountedRef])
|
|
71
|
-
|
|
72
|
-
useEffect(() => { void refresh() }, [refresh])
|
|
73
|
-
useWs('connectors', loadConnectors, 15_000)
|
|
74
|
-
|
|
75
65
|
// Auto-clear error after 5s
|
|
76
66
|
useEffect(() => {
|
|
77
67
|
if (error) { const t = setTimeout(() => setError(null), 5000); return () => clearTimeout(t) }
|
|
@@ -80,38 +70,34 @@ export function ConnectorList({ inSidebar }: { inSidebar?: boolean }) {
|
|
|
80
70
|
const handleToggle = async (e: React.MouseEvent, c: Connector) => {
|
|
81
71
|
e.stopPropagation()
|
|
82
72
|
const action = c.status === 'running' ? 'stop' : 'start'
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
setError(null)
|
|
86
|
-
}
|
|
73
|
+
setToggling(c.id)
|
|
74
|
+
setError(null)
|
|
87
75
|
try {
|
|
88
|
-
await
|
|
89
|
-
await refresh()
|
|
76
|
+
await connectorActionMutation.mutateAsync({ id: c.id, action })
|
|
90
77
|
} catch (err: unknown) {
|
|
91
78
|
const msg = err instanceof Error && err.message ? err.message : `Failed to ${action}`
|
|
92
|
-
|
|
93
|
-
await refresh()
|
|
79
|
+
setError(msg)
|
|
94
80
|
} finally {
|
|
95
|
-
|
|
81
|
+
setToggling(null)
|
|
96
82
|
}
|
|
97
83
|
}
|
|
98
84
|
|
|
99
85
|
const handleReconnect = async (e: React.MouseEvent, c: Connector) => {
|
|
100
86
|
e.stopPropagation()
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
setError(null)
|
|
104
|
-
}
|
|
87
|
+
setReconnecting(c.id)
|
|
88
|
+
setError(null)
|
|
105
89
|
try {
|
|
106
|
-
try {
|
|
107
|
-
|
|
108
|
-
|
|
90
|
+
try {
|
|
91
|
+
await connectorActionMutation.mutateAsync({ id: c.id, action: 'stop' })
|
|
92
|
+
} catch {
|
|
93
|
+
// Connector may already be stopped.
|
|
94
|
+
}
|
|
95
|
+
await connectorActionMutation.mutateAsync({ id: c.id, action: 'start' })
|
|
109
96
|
} catch (err: unknown) {
|
|
110
97
|
const msg = err instanceof Error && err.message ? err.message : 'Failed to reconnect'
|
|
111
|
-
|
|
112
|
-
await refresh()
|
|
98
|
+
setError(msg)
|
|
113
99
|
} finally {
|
|
114
|
-
|
|
100
|
+
setReconnecting(null)
|
|
115
101
|
}
|
|
116
102
|
}
|
|
117
103
|
|
|
@@ -158,7 +144,7 @@ export function ConnectorList({ inSidebar }: { inSidebar?: boolean }) {
|
|
|
158
144
|
},
|
|
159
145
|
}
|
|
160
146
|
|
|
161
|
-
if (
|
|
147
|
+
if (connectorsQuery.isPending || agentsQuery.isPending || chatroomsQuery.isPending) {
|
|
162
148
|
return <PageLoader label="Loading connectors..." />
|
|
163
149
|
}
|
|
164
150
|
|