@swarmclawai/swarmclaw 1.1.0 → 1.1.3
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 +178 -1
- package/package.json +1 -1
- package/src/app/api/agents/[id]/route.ts +6 -0
- package/src/app/api/agents/route.ts +2 -0
- package/src/app/api/agents/thread-route.test.ts +3 -3
- package/src/app/api/autonomy/estop/route.ts +1 -1
- package/src/app/api/chatrooms/[id]/chat/route.test.ts +6 -6
- package/src/app/api/chatrooms/route.ts +6 -1
- package/src/app/api/chats/[id]/chat/route.test.ts +23 -23
- package/src/app/api/chats/[id]/messages/route.ts +4 -5
- package/src/app/api/chats/[id]/route.ts +5 -0
- package/src/app/api/chats/messages-route.test.ts +65 -0
- package/src/app/api/chats/route.ts +1 -0
- package/src/app/api/credentials/[id]/route.ts +2 -3
- package/src/app/api/daemon/route.ts +1 -1
- package/src/app/api/extensions/builtins/route.ts +40 -0
- package/src/app/api/extensions/dependencies/route.ts +3 -3
- package/src/app/api/extensions/install/route.ts +19 -19
- package/src/app/api/extensions/marketplace/route.ts +18 -22
- package/src/app/api/extensions/route.ts +13 -13
- package/src/app/api/extensions/settings/route.ts +19 -19
- package/src/app/api/extensions/ui/route.ts +3 -3
- package/src/app/api/memory/maintenance/route.ts +51 -41
- package/src/app/api/protocols/runs/[id]/actions/route.ts +26 -0
- package/src/app/api/protocols/runs/[id]/events/route.ts +16 -0
- package/src/app/api/protocols/runs/[id]/route.ts +10 -0
- package/src/app/api/protocols/runs/route.test.ts +173 -0
- package/src/app/api/protocols/runs/route.ts +51 -0
- package/src/app/api/protocols/templates/[id]/route.ts +50 -0
- package/src/app/api/protocols/templates/route.test.ts +109 -0
- package/src/app/api/protocols/templates/route.ts +30 -0
- package/src/app/api/providers/[id]/discover-models/route.ts +1 -0
- package/src/app/api/schedules/[id]/route.test.ts +1 -1
- package/src/app/api/schedules/route.test.ts +1 -1
- package/src/app/api/setup/check-provider/route.ts +27 -9
- package/src/app/api/setup/doctor/route.ts +7 -7
- package/src/app/api/tasks/[id]/route.ts +9 -7
- package/src/app/api/tasks/claim/route.test.ts +58 -0
- package/src/app/api/tasks/claim/route.ts +18 -0
- package/src/app/api/tasks/route.ts +5 -5
- package/src/app/api/usage/route.ts +16 -16
- package/src/app/api/webhooks/[id]/helpers.ts +4 -3
- package/src/app/chatrooms/[id]/page.tsx +49 -0
- package/src/app/extensions/layout.tsx +3 -3
- package/src/app/extensions/page.tsx +3 -3
- package/src/app/missions/page.tsx +53 -0
- package/src/app/protocols/page.tsx +1284 -0
- package/src/app/usage/page.tsx +8 -8
- package/src/cli/index.js +20 -2
- package/src/cli/spec.js +2 -2
- package/src/components/agents/agent-sheet.tsx +83 -39
- package/src/components/chat/chat-area.tsx +10 -10
- package/src/components/chat/chat-header.tsx +67 -1
- package/src/components/chat/chat-tool-toggles.tsx +80 -39
- package/src/components/chat/file-path-chip.tsx +4 -3
- package/src/components/chat/message-bubble.test.ts +160 -2
- package/src/components/chat/message-bubble.tsx +208 -108
- package/src/components/chat/message-list.tsx +111 -80
- package/src/components/chat/tool-request-banner.tsx +17 -17
- package/src/components/chatrooms/breakout-command.test.ts +86 -0
- package/src/components/chatrooms/breakout-command.ts +119 -0
- package/src/components/chatrooms/chatroom-input.tsx +218 -71
- package/src/components/chatrooms/chatroom-view.tsx +247 -25
- package/src/components/connectors/connector-sheet.tsx +5 -5
- package/src/components/{plugins/plugin-list.tsx → extensions/extension-list.tsx} +84 -84
- package/src/components/{plugins/plugin-sheet.tsx → extensions/extension-sheet.tsx} +59 -59
- package/src/components/input/chat-input.tsx +81 -78
- package/src/components/input/composer-shell.tsx +44 -0
- package/src/components/layout/dashboard-shell.tsx +4 -4
- package/src/components/layout/sheet-layer.tsx +2 -2
- package/src/components/layout/sidebar-rail.tsx +6 -0
- package/src/components/mcp-servers/mcp-server-list.tsx +1 -1
- package/src/components/protocols/structured-session-launcher.tsx +491 -0
- package/src/components/schedules/schedule-sheet.tsx +57 -8
- package/src/components/shared/model-combobox.tsx +6 -3
- package/src/components/tasks/task-sheet.tsx +65 -0
- package/src/instrumentation.ts +1 -1
- package/src/lib/agent-default-tools.test.ts +24 -30
- package/src/lib/app/api-client.test.ts +3 -3
- package/src/lib/app/navigation.ts +1 -0
- package/src/lib/app/view-constants.ts +9 -1
- package/src/lib/canvas-content.test.ts +1 -1
- package/src/lib/capability-selection.test.ts +1 -1
- package/src/lib/chat/chat-streaming-state.test.ts +3 -6
- package/src/lib/chat/chat-streaming-state.ts +6 -6
- package/src/lib/chat/message-list-utils.test.ts +31 -0
- package/src/lib/chat/message-list-utils.ts +5 -0
- package/src/lib/chat/queued-message-queue.ts +12 -1
- package/src/lib/{plugin-install-cors.ts → extension-install-cors.ts} +4 -4
- package/src/lib/{plugin-sources.ts → extension-sources.ts} +17 -17
- package/src/lib/ollama-mode.test.ts +33 -0
- package/src/lib/ollama-mode.ts +28 -0
- package/src/lib/plugin-sources.test.ts +18 -18
- package/src/lib/provider-model-discovery-client.ts +2 -0
- package/src/lib/providers/anthropic.ts +5 -4
- package/src/lib/providers/index.ts +43 -9
- package/src/lib/providers/ollama.ts +7 -5
- package/src/lib/providers/openai.ts +51 -25
- package/src/lib/server/agents/agent-runtime-config.test.ts +37 -1
- package/src/lib/server/agents/agent-runtime-config.ts +9 -0
- package/src/lib/server/agents/agent-thread-session.test.ts +9 -5
- package/src/lib/server/agents/agent-thread-session.ts +1 -0
- package/src/lib/server/agents/main-agent-loop.ts +15 -0
- package/src/lib/server/agents/subagent-runtime.test.ts +57 -53
- package/src/lib/server/agents/subagent-runtime.ts +19 -19
- package/src/lib/server/approval-match.ts +4 -4
- package/src/lib/server/approvals.ts +3 -2
- package/src/lib/server/autonomy/supervisor-reflection.ts +17 -0
- package/src/lib/server/build-llm.test.ts +65 -2
- package/src/lib/server/build-llm.ts +11 -3
- package/src/lib/server/{builtin-plugins.ts → builtin-extensions.ts} +2 -9
- package/src/lib/server/capability-router.ts +9 -9
- package/src/lib/server/chat-execution/chat-execution-advanced.test.ts +5 -5
- package/src/lib/server/chat-execution/chat-execution-disabled.test.ts +1 -1
- package/src/lib/server/chat-execution/chat-execution-eval-history.test.ts +1 -1
- package/src/lib/server/chat-execution/chat-execution-heartbeat.test.ts +1 -1
- package/src/lib/server/chat-execution/chat-execution-session-sync.test.ts +15 -15
- package/src/lib/server/chat-execution/chat-execution-tool-events.test.ts +4 -4
- package/src/lib/server/chat-execution/chat-execution-utils.ts +3 -9
- package/src/lib/server/chat-execution/chat-execution.ts +264 -184
- package/src/lib/server/chat-execution/chat-streaming-utils.ts +8 -7
- package/src/lib/server/chat-execution/chat-turn-tool-routing.test.ts +144 -10
- package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +152 -18
- package/src/lib/server/chat-execution/direct-memory-intent.test.ts +15 -0
- package/src/lib/server/chat-execution/direct-memory-intent.ts +6 -3
- package/src/lib/server/chat-execution/exact-output-contract.test.ts +91 -0
- package/src/lib/server/chat-execution/exact-output-contract.ts +220 -0
- package/src/lib/server/chat-execution/memory-mutation-tools.ts +2 -2
- package/src/lib/server/chat-execution/situational-awareness.test.ts +318 -0
- package/src/lib/server/chat-execution/situational-awareness.ts +273 -0
- package/src/lib/server/chat-execution/stream-agent-chat.test.ts +99 -11
- package/src/lib/server/chat-execution/stream-agent-chat.ts +166 -84
- package/src/lib/server/chat-execution/stream-continuation.ts +4 -4
- package/src/lib/server/chatrooms/chatroom-helpers.test.ts +1 -0
- package/src/lib/server/chatrooms/chatroom-helpers.ts +3 -1
- package/src/lib/server/chatrooms/chatroom-session-persistence.test.ts +3 -3
- package/src/lib/server/chatrooms/mailbox-utils.ts +5 -5
- package/src/lib/server/chatrooms/session-mailbox.test.ts +6 -0
- package/src/lib/server/connectors/connector-routing.test.ts +59 -1
- package/src/lib/server/connectors/inbound-audio-transcription.test.ts +5 -5
- package/src/lib/server/connectors/manager-roundtrip.test.ts +14 -14
- package/src/lib/server/connectors/manager.test.ts +142 -142
- package/src/lib/server/connectors/manager.ts +8 -8
- package/src/lib/server/connectors/outbox.test.ts +11 -11
- package/src/lib/server/connectors/response-media.ts +3 -0
- package/src/lib/server/connectors/session.test.ts +10 -10
- package/src/lib/server/cost.ts +9 -9
- package/src/lib/server/dag-validation.ts +10 -0
- package/src/lib/server/data-dir.test.ts +8 -8
- package/src/lib/server/eval/agent-regression-advanced.test.ts +66 -66
- package/src/lib/server/eval/agent-regression.test.ts +7 -7
- package/src/lib/server/eval/agent-regression.ts +104 -103
- package/src/lib/server/{plugins-approval-guidance.ts → extensions-approval-guidance.ts} +31 -31
- package/src/lib/server/{plugins.test.ts → extensions.test.ts} +104 -105
- package/src/lib/server/{plugins.ts → extensions.ts} +501 -483
- package/src/lib/server/integrity-monitor.test.ts +21 -21
- package/src/lib/server/integrity-monitor.ts +10 -6
- package/src/lib/server/knowledge-db.test.ts +4 -0
- package/src/lib/server/langgraph-checkpoint.test.ts +6 -6
- package/src/lib/server/langgraph-checkpoint.ts +6 -1
- package/src/lib/server/memory/memory-consolidation.test.ts +89 -0
- package/src/lib/server/memory/memory-consolidation.ts +143 -3
- package/src/lib/server/memory/memory-db.ts +17 -5
- package/src/lib/server/memory/memory-integration.test.ts +11 -14
- package/src/lib/server/missions/mission-service.ts +53 -1
- package/src/lib/server/native-capabilities.test.ts +7 -7
- package/src/lib/server/native-capabilities.ts +85 -85
- package/src/lib/server/ollama-runtime.test.ts +41 -0
- package/src/lib/server/ollama-runtime.ts +13 -18
- package/src/lib/server/openclaw/gateway.test.ts +157 -1
- package/src/lib/server/openclaw/gateway.ts +55 -34
- package/src/lib/server/openclaw/sync.ts +15 -15
- package/src/lib/server/plugins-advanced.test.ts +86 -87
- package/src/lib/server/protocols/dag-scheduler.ts +103 -0
- package/src/lib/server/protocols/protocol-service.test.ts +585 -0
- package/src/lib/server/protocols/protocol-service.ts +3937 -0
- package/src/lib/server/protocols/step-dag-validation.ts +86 -0
- package/src/lib/server/protocols/step-outputs.ts +57 -0
- package/src/lib/server/provider-endpoint.ts +2 -0
- package/src/lib/server/provider-health.ts +2 -0
- package/src/lib/server/provider-model-discovery.test.ts +23 -0
- package/src/lib/server/provider-model-discovery.ts +23 -5
- package/src/lib/server/resolve-image.ts +41 -9
- package/src/lib/server/runtime/daemon-guards.test.ts +74 -0
- package/src/lib/server/runtime/daemon-state-connectors.test.ts +10 -10
- package/src/lib/server/runtime/daemon-state.test.ts +18 -18
- package/src/lib/server/runtime/daemon-state.ts +188 -24
- package/src/lib/server/runtime/heartbeat-service-timer.test.ts +16 -13
- package/src/lib/server/runtime/heartbeat-service.ts +100 -42
- package/src/lib/server/runtime/idle-window.ts +84 -0
- package/src/lib/server/runtime/process-manager.ts +45 -2
- package/src/lib/server/runtime/queue-followups.test.ts +2 -2
- package/src/lib/server/runtime/queue.test.ts +28 -3
- package/src/lib/server/runtime/queue.ts +104 -12
- package/src/lib/server/runtime/scheduler.test.ts +79 -0
- package/src/lib/server/runtime/scheduler.ts +26 -39
- package/src/lib/server/runtime/session-run-manager.test.ts +9 -0
- package/src/lib/server/runtime/session-run-manager.ts +36 -3
- package/src/lib/server/runtime/wake-dispatcher.ts +9 -9
- package/src/lib/server/runtime/watch-jobs.ts +5 -3
- package/src/lib/server/schedules/schedule-lifecycle.test.ts +1 -1
- package/src/lib/server/schedules/schedule-normalization.ts +23 -3
- package/src/lib/server/session-tools/autonomy-tools.test.ts +11 -33
- package/src/lib/server/session-tools/canvas.ts +7 -7
- package/src/lib/server/session-tools/chatroom.ts +7 -7
- package/src/lib/server/session-tools/connector.test.ts +2 -2
- package/src/lib/server/session-tools/connector.ts +7 -7
- package/src/lib/server/session-tools/context-mgmt.ts +7 -7
- package/src/lib/server/session-tools/context.ts +5 -5
- package/src/lib/server/session-tools/crud.test.ts +5 -5
- package/src/lib/server/session-tools/crud.ts +13 -244
- package/src/lib/server/session-tools/delegate-fallback.test.ts +16 -16
- package/src/lib/server/session-tools/delegate.ts +14 -14
- package/src/lib/server/session-tools/discovery-approvals.test.ts +2 -2
- package/src/lib/server/session-tools/discovery.ts +43 -45
- package/src/lib/server/session-tools/edit_file.ts +8 -8
- package/src/lib/server/session-tools/email.ts +11 -11
- package/src/lib/server/session-tools/{plugin-creator.ts → extension-creator.ts} +61 -60
- package/src/lib/server/session-tools/file.ts +9 -9
- package/src/lib/server/session-tools/google-workspace.test.ts +5 -5
- package/src/lib/server/session-tools/google-workspace.ts +11 -10
- package/src/lib/server/session-tools/http.ts +9 -9
- package/src/lib/server/session-tools/human-loop.ts +7 -7
- package/src/lib/server/session-tools/image-gen.ts +20 -20
- package/src/lib/server/session-tools/index.test.ts +8 -0
- package/src/lib/server/session-tools/index.ts +48 -65
- package/src/lib/server/session-tools/mailbox.ts +7 -7
- package/src/lib/server/session-tools/manage-connectors.test.ts +2 -2
- package/src/lib/server/session-tools/manage-schedules-advanced.test.ts +1 -1
- package/src/lib/server/session-tools/manage-schedules.test.ts +11 -11
- package/src/lib/server/session-tools/manage-skills.test.ts +5 -5
- package/src/lib/server/session-tools/manage-tasks-advanced.test.ts +3 -3
- package/src/lib/server/session-tools/manage-tasks.test.ts +1 -1
- package/src/lib/server/session-tools/memory.ts +41 -11
- package/src/lib/server/session-tools/monitor.ts +14 -77
- package/src/lib/server/session-tools/openclaw-nodes.ts +8 -8
- package/src/lib/server/session-tools/openclaw-workspace.ts +7 -7
- package/src/lib/server/session-tools/platform-access.test.ts +4 -4
- package/src/lib/server/session-tools/platform.ts +19 -19
- package/src/lib/server/session-tools/primitive-tools.test.ts +3 -124
- package/src/lib/server/session-tools/replicate.ts +9 -9
- package/src/lib/server/session-tools/sandbox.ts +6 -86
- package/src/lib/server/session-tools/schedule.ts +10 -9
- package/src/lib/server/session-tools/session-info.ts +16 -20
- package/src/lib/server/session-tools/session-tools-wiring.test.ts +13 -38
- package/src/lib/server/session-tools/shell.ts +37 -13
- package/src/lib/server/session-tools/skill-runtime.test.ts +3 -3
- package/src/lib/server/session-tools/skill-runtime.ts +9 -9
- package/src/lib/server/session-tools/skills.ts +4 -4
- package/src/lib/server/session-tools/subagent.ts +7 -7
- package/src/lib/server/session-tools/wallet-tool.test.ts +4 -4
- package/src/lib/server/session-tools/wallet.ts +9 -9
- package/src/lib/server/session-tools/web-browser-config.test.ts +4 -3
- package/src/lib/server/session-tools/web-utils.ts +4 -2
- package/src/lib/server/session-tools/web.ts +68 -15
- package/src/lib/server/skills/clawhub-client.test.ts +2 -2
- package/src/lib/server/skills/discovered-skill-prompt.test.ts +10 -10
- package/src/lib/server/skills/discovered-skill-prompt.ts +10 -10
- package/src/lib/server/skills/learned-skills.ts +54 -2
- package/src/lib/server/skills/runtime-skill-resolver.test.ts +3 -3
- package/src/lib/server/skills/runtime-skill-resolver.ts +24 -24
- package/src/lib/server/skills/skill-suggestions.test.ts +1 -1
- package/src/lib/server/storage-item-access.test.ts +109 -1
- package/src/lib/server/storage.ts +91 -8
- package/src/lib/server/tasks/task-followups.test.ts +21 -11
- package/src/lib/server/tool-aliases.ts +37 -43
- package/src/lib/server/tool-capability-policy-advanced.test.ts +108 -108
- package/src/lib/server/tool-capability-policy.test.ts +13 -13
- package/src/lib/server/tool-capability-policy.ts +32 -37
- package/src/lib/server/tool-loop-detection.ts +9 -9
- package/src/lib/server/tool-planning.test.ts +8 -8
- package/src/lib/server/tool-planning.ts +21 -21
- package/src/lib/server/universal-tool-access.ts +11 -18
- package/src/lib/setup-defaults.ts +38 -0
- package/src/lib/tool-definitions.ts +16 -16
- package/src/lib/validation/schemas.ts +263 -0
- package/src/proxy.test.ts +2 -2
- package/src/proxy.ts +12 -12
- package/src/stores/slices/data-slice.ts +4 -4
- package/src/stores/slices/ui-slice.ts +8 -8
- package/src/stores/use-app-store.test.ts +2 -2
- package/src/stores/use-chat-store.test.ts +3 -3
- package/src/stores/use-chat-store.ts +22 -8
- package/src/stores/use-chatroom-store.ts +19 -1
- package/src/types/index.ts +526 -65
- package/src/views/settings/{plugin-manager.tsx → extension-manager.tsx} +36 -36
- package/src/lib/server/session-tools/calendar.ts +0 -367
- package/src/lib/server/session-tools/crawl.ts +0 -449
- package/src/lib/server/session-tools/document.ts +0 -285
- package/src/lib/server/session-tools/extract.ts +0 -139
- package/src/lib/server/session-tools/git.ts +0 -111
- package/src/lib/server/session-tools/table.ts +0 -589
package/README.md
CHANGED
|
@@ -15,8 +15,182 @@ Docs: https://swarmclaw.ai/docs
|
|
|
15
15
|
Website: https://swarmclaw.ai
|
|
16
16
|
Extension tutorial: https://swarmclaw.ai/docs/extension-tutorial
|
|
17
17
|
|
|
18
|
+
<div align="center">
|
|
19
|
+
<table>
|
|
20
|
+
<tr>
|
|
21
|
+
<td align="center"><strong>Works<br>with</strong></td>
|
|
22
|
+
<td align="center"><img src="doc/assets/logos/openclaw.svg" width="32" alt="OpenClaw"><br><sub>OpenClaw</sub></td>
|
|
23
|
+
<td align="center"><img src="doc/assets/logos/claude-code.svg" width="32" alt="Claude Code"><br><sub>Claude Code</sub></td>
|
|
24
|
+
<td align="center"><img src="doc/assets/logos/codex.svg" width="32" alt="Codex"><br><sub>Codex</sub></td>
|
|
25
|
+
<td align="center"><img src="doc/assets/logos/gemini-cli.svg" width="32" alt="Gemini CLI"><br><sub>Gemini CLI</sub></td>
|
|
26
|
+
<td align="center"><img src="doc/assets/logos/opencode.svg" width="32" alt="OpenCode"><br><sub>OpenCode</sub></td>
|
|
27
|
+
<td align="center"><img src="doc/assets/logos/anthropic.svg" width="32" alt="Anthropic"><br><sub>Anthropic</sub></td>
|
|
28
|
+
<td align="center"><img src="doc/assets/logos/openai.svg" width="32" alt="OpenAI"><br><sub>OpenAI</sub></td>
|
|
29
|
+
<td align="center"><img src="doc/assets/logos/google.svg" width="32" alt="Google Gemini"><br><sub>Gemini</sub></td>
|
|
30
|
+
<td align="center"><img src="doc/assets/logos/ollama.svg" width="32" alt="Ollama"><br><sub>Ollama</sub></td>
|
|
31
|
+
<td align="center"><img src="doc/assets/logos/deepseek.svg" width="32" alt="DeepSeek"><br><sub>DeepSeek</sub></td>
|
|
32
|
+
<td align="center"><img src="doc/assets/logos/groq.svg" width="32" alt="Groq"><br><sub>Groq</sub></td>
|
|
33
|
+
<td align="center"><img src="doc/assets/logos/together.svg" width="32" alt="Together AI"><br><sub>Together</sub></td>
|
|
34
|
+
<td align="center"><img src="doc/assets/logos/mistral.svg" width="32" alt="Mistral AI"><br><sub>Mistral</sub></td>
|
|
35
|
+
<td align="center"><img src="doc/assets/logos/xai.svg" width="32" alt="xAI"><br><sub>xAI</sub></td>
|
|
36
|
+
<td align="center"><img src="doc/assets/logos/fireworks.svg" width="32" alt="Fireworks AI"><br><sub>Fireworks</sub></td>
|
|
37
|
+
<td align="center"><img src="doc/assets/logos/nebius.svg" width="32" alt="Nebius"><br><sub>Nebius</sub></td>
|
|
38
|
+
<td align="center"><img src="doc/assets/logos/deepinfra.svg" width="32" alt="DeepInfra"><br><sub>DeepInfra</sub></td>
|
|
39
|
+
</tr>
|
|
40
|
+
</table>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
## Use Cases
|
|
44
|
+
|
|
45
|
+
SwarmClaw is a general-purpose agent runtime. Here are some of the ways people use it.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### Personal Assistant
|
|
50
|
+
|
|
51
|
+
A single agent with memory, web access, scheduling, and file tools — your always-available copilot.
|
|
52
|
+
|
|
53
|
+
> *"Remember that I prefer window seats. Book research time every Monday at 9am. Summarize the articles I saved last week."*
|
|
54
|
+
|
|
55
|
+
- Remembers preferences, contacts, and decisions across conversations
|
|
56
|
+
- Schedules reminders, recurring check-ins, and follow-ups
|
|
57
|
+
- Researches, drafts, plans, and manages your day-to-day
|
|
58
|
+
- Bridges to WhatsApp or Telegram so you can message your agent on the go
|
|
59
|
+
|
|
60
|
+
**Starter kit:** Personal Assistant → 1 agent, ready in under a minute.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### Virtual Company
|
|
65
|
+
|
|
66
|
+
Build a full org chart of specialized agents that collaborate, delegate, and report up — a lightweight simulation of a real company.
|
|
67
|
+
|
|
68
|
+
| Role | Agent | Responsibilities |
|
|
69
|
+
|------|-------|-----------------|
|
|
70
|
+
| **CEO** | Strategist | Sets objectives, reviews progress, delegates to department heads |
|
|
71
|
+
| **CTO** | Builder | Owns technical execution, code reviews, architecture decisions |
|
|
72
|
+
| **CFO** | Analyst | Tracks budgets, monitors token spend, produces cost reports |
|
|
73
|
+
| **CMO** | Marketer | Drafts campaigns, manages content calendar, monitors channels |
|
|
74
|
+
| **COO** | Operator | Coordinates cross-agent work, manages schedules, unblocks tasks |
|
|
75
|
+
|
|
76
|
+
- Each agent has its own provider, model, personality (soul), and tool access
|
|
77
|
+
- The CEO delegates via the task board; department heads pick up work autonomously
|
|
78
|
+
- Heartbeat loops let agents check in on their own, surface blockers, and request approvals
|
|
79
|
+
- Memory means every agent remembers past decisions and context
|
|
80
|
+
- Connect the CMO to Discord/Slack so it can post updates directly
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### Development Team
|
|
85
|
+
|
|
86
|
+
A squad of agents mirroring a real engineering team — planning, building, reviewing, and testing in parallel.
|
|
87
|
+
|
|
88
|
+
| Role | Agent | Tools |
|
|
89
|
+
|------|-------|-------|
|
|
90
|
+
| **Lead** | Architect | Delegation, tasks, schedules, missions |
|
|
91
|
+
| **Dev** | Builder | Shell, files, Claude Code / Codex / OpenCode |
|
|
92
|
+
| **QA** | Tester | Shell, browser, files, web search |
|
|
93
|
+
| **Designer** | Creative | Image generation, browser, web search, files |
|
|
94
|
+
| **Reviewer** | Critic | Files, web search, memory |
|
|
95
|
+
|
|
96
|
+
- The Lead creates missions and breaks them into tasks on the board
|
|
97
|
+
- Dev agents pick up tasks and delegate to Claude Code, Codex, or OpenCode for implementation
|
|
98
|
+
- QA runs tests, takes screenshots, and files bugs back on the task board
|
|
99
|
+
- The Reviewer audits PRs and flags regressions
|
|
100
|
+
- Structured Sessions let you run a bounded sprint — plan → build → test → review — with durable transcripts
|
|
101
|
+
|
|
102
|
+
**Starter kit:** Builder Studio → pre-configured Builder + Reviewer pair.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### Research Bureau
|
|
107
|
+
|
|
108
|
+
Multiple research agents working in parallel, each with different search strategies, then synthesizing findings.
|
|
109
|
+
|
|
110
|
+
- Spawn a swarm of researchers across different topics or sources
|
|
111
|
+
- Each agent searches, fetches, reads, and summarizes independently
|
|
112
|
+
- A lead agent collects outputs into a structured report with citations
|
|
113
|
+
- Memory stores findings for future reference across conversations
|
|
114
|
+
- Schedule recurring research runs (daily digest, weekly competitive scan)
|
|
115
|
+
|
|
116
|
+
**Starter kit:** Research Copilot → 1 focused researcher, scale up with subagents.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
### OpenClaw Fleet
|
|
121
|
+
|
|
122
|
+
Distribute autonomous agents across multiple machines using OpenClaw gateways — one control plane, many runtimes.
|
|
123
|
+
|
|
124
|
+
- Deploy OpenClaw runtimes on local machines, VPS nodes, or Tailnet peers
|
|
125
|
+
- Each agent targets a different gateway profile (one for code, one for research, one for ops)
|
|
126
|
+
- The operator agent coordinates work across the fleet via delegation and the task board
|
|
127
|
+
- Gateway health, runtime state, and version info visible from the Providers screen
|
|
128
|
+
- Import `SKILL.md` files from any OpenClaw instance into SwarmClaw's skill library
|
|
129
|
+
|
|
130
|
+
**Starter kit:** OpenClaw Fleet → Operator + Remote Builder + Remote Researcher.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
### Content Studio
|
|
135
|
+
|
|
136
|
+
A writer/editor pipeline for blogs, docs, newsletters, marketing copy, or social posts.
|
|
137
|
+
|
|
138
|
+
- **Writer** drafts content based on briefs, outlines, and style guides
|
|
139
|
+
- **Editor** tightens structure, fixes tone, and flags missing evidence
|
|
140
|
+
- Schedule daily or weekly content runs with automatic handoff
|
|
141
|
+
- Connect to Slack or Discord to publish directly from the pipeline
|
|
142
|
+
- Image generation agent produces visuals alongside copy
|
|
143
|
+
|
|
144
|
+
**Starter kit:** Content Studio → Writer + Editor pair.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### Customer Support Desk
|
|
149
|
+
|
|
150
|
+
Agents answering questions on every platform your users are on, with shared memory and escalation paths.
|
|
151
|
+
|
|
152
|
+
- Bridge a support agent to Discord, Slack, Telegram, WhatsApp, and Teams simultaneously
|
|
153
|
+
- The agent remembers each sender's history, preferences, and open issues
|
|
154
|
+
- Unanswerable questions escalate via `ask_human` or get routed to a specialist agent
|
|
155
|
+
- Schedule a nightly agent to review open threads, follow up on stale conversations, and summarize trends
|
|
156
|
+
- Skills let you codify common support workflows so the agent improves over time
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### Crypto Operations
|
|
161
|
+
|
|
162
|
+
Agents with linked wallets for on-chain work — monitoring, trading, signing, and reporting.
|
|
163
|
+
|
|
164
|
+
- Attach Solana or Ethereum wallets to any agent
|
|
165
|
+
- Agents can check balances, simulate transactions, and execute swaps
|
|
166
|
+
- Approval gates require human sign-off before spending above a threshold
|
|
167
|
+
- Schedule periodic balance checks or price-alert sweeps
|
|
168
|
+
- The operator agent coordinates across multiple wallet-holding agents
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### Mix and Match
|
|
173
|
+
|
|
174
|
+
These aren't exclusive templates — they're patterns you combine. A virtual company can have a dev team inside it. A personal assistant can spin up a research swarm on demand. An OpenClaw fleet can run your customer support desk.
|
|
175
|
+
|
|
176
|
+
The building blocks are the same: **agents, tools, memory, delegation, schedules, connectors, and skills**. SwarmClaw just gives you the control plane to wire them together.
|
|
177
|
+
|
|
18
178
|
## Release Notes
|
|
19
179
|
|
|
180
|
+
### v1.1.2 Highlights
|
|
181
|
+
|
|
182
|
+
- **Structured Sessions expanded into richer orchestration**: ProtocolRun-based sessions now support dependency-aware step graphs, reusable step outputs, and a broader advanced execution model on the same durable runtime instead of bringing back a separate orchestrator.
|
|
183
|
+
- **Explicit Ollama local/cloud routing**: agents and sessions now persist the user-selected Ollama mode directly, so local Ollama no longer flips to cloud because of model naming or leftover credentials.
|
|
184
|
+
- **Chat and runtime regression hardening**: live-streamed inline media, stale streaming cleanup, exact-output handling, and chat rendering bugs were tightened again, including the recent message-row and avatar rendering regressions.
|
|
185
|
+
- **Nebius and DeepInfra as built-in providers**: both are now first-class providers with setup wizard entries, model discovery, and pre-configured defaults instead of requiring the custom provider workaround.
|
|
186
|
+
- **`stream_options` resilience**: the OpenAI-compatible streaming handler now retries without `stream_options` if a provider rejects it with 400, fixing connectivity for strict endpoints.
|
|
187
|
+
|
|
188
|
+
### v1.1.1 Highlights
|
|
189
|
+
|
|
190
|
+
- **Structured Sessions are now contextual**: start bounded structured runs from direct chats, chatrooms, tasks, missions, or schedules, including a new chatroom `/breakout` command that spins up a focused session from the current room with auto-filled participants and kickoff context.
|
|
191
|
+
- **ProtocolRun orchestration matured**: structured sessions now run on the same durable engine for step-based branching, repeat loops, parallel branches, and explicit joins instead of growing a separate orchestration subsystem.
|
|
192
|
+
- **Live-agent runtime hardening**: exact-output contracts, memory preflight behavior, same-channel delivery rendering, inline media, and grounded runtime inspection were all tightened through live-agent validation before release.
|
|
193
|
+
|
|
20
194
|
### v1.1.0 Highlights
|
|
21
195
|
|
|
22
196
|
- **Mission controller and Missions UI**: SwarmClaw now tracks durable multi-step objectives as missions with status, phase, linked tasks, queued turns, recent runs, event history, and operator actions from the new **Missions** surface.
|
|
@@ -34,6 +208,7 @@ Extension tutorial: https://swarmclaw.ai/docs/extension-tutorial
|
|
|
34
208
|
## What SwarmClaw Focuses On
|
|
35
209
|
|
|
36
210
|
- **Delegation and background execution**: delegated work, subagents, durable jobs, checkpointing, and background task execution.
|
|
211
|
+
- **Structured Sessions and orchestration**: temporary bounded runs for one agent or many, launched from context and backed by durable templates, branching, loops, parallel joins, transcripts, outputs, operator controls, and chatroom breakout flows.
|
|
37
212
|
- **Autonomy and memory**: heartbeats, schedules, long-running execution, durable memory, reflection memory, human-context learning, document recall, and project-aware context.
|
|
38
213
|
- **OpenClaw integration**: named gateway profiles, external runtimes, deploy helpers, config sync, approval handling, and OpenClaw agent file editing.
|
|
39
214
|
- **Runtime skills**: pinned skills, OpenClaw-compatible `SKILL.md` import, on-demand skill execution, and configurable keyword or embedding-based recommendation.
|
|
@@ -113,9 +288,11 @@ Then open `http://localhost:3456`.
|
|
|
113
288
|
|
|
114
289
|
## Core Capabilities
|
|
115
290
|
|
|
116
|
-
- **Providers**: OpenClaw, OpenAI, Anthropic, Ollama, Google, DeepSeek, Groq, Together, Mistral, xAI, Fireworks, plus compatible custom endpoints.
|
|
291
|
+
- **Providers**: OpenClaw, OpenAI, Anthropic, Ollama, Google, DeepSeek, Groq, Together, Mistral, xAI, Fireworks, Nebius, DeepInfra, plus compatible custom endpoints.
|
|
117
292
|
- **Delegation**: built-in delegation to Claude Code, Codex CLI, OpenCode CLI, Gemini CLI, and native SwarmClaw subagents.
|
|
118
293
|
- **Autonomy**: heartbeat loops, schedules, background jobs, task execution, supervisor recovery, mission control, and agent wakeups.
|
|
294
|
+
- **Orchestration**: durable structured execution with branching, repeat loops, parallel branches, explicit joins, restart-safe run state, and contextual launch from chats, chatrooms, tasks, missions, schedules, and API flows.
|
|
295
|
+
- **Structured Sessions**: reusable bounded runs with templates, facilitators, participants, hidden live rooms, chatroom `/breakout`, durable transcripts, outputs, and operator controls.
|
|
119
296
|
- **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.
|
|
120
297
|
- **Wallets**: balances, transfers, signatures, EVM call/quote/swap flows, and approval-gated execution.
|
|
121
298
|
- **Connectors**: Discord, Slack, Telegram, WhatsApp, Teams, Matrix, OpenClaw, and more.
|
package/package.json
CHANGED
|
@@ -44,6 +44,9 @@ export async function PUT(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
44
44
|
body.apiEndpoint,
|
|
45
45
|
)
|
|
46
46
|
}
|
|
47
|
+
if (body.provider !== undefined && body.provider !== 'ollama' && body.ollamaMode === undefined) {
|
|
48
|
+
agent.ollamaMode = null
|
|
49
|
+
}
|
|
47
50
|
if (body.sandboxConfig !== undefined) {
|
|
48
51
|
agent.sandboxConfig = normalizeAgentSandboxConfig(body.sandboxConfig)
|
|
49
52
|
}
|
|
@@ -64,6 +67,9 @@ export async function PUT(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
64
67
|
role: target.role,
|
|
65
68
|
provider: (typeof target.provider === 'string' && target.provider.trim() ? target.provider : agent.provider),
|
|
66
69
|
model: typeof target.model === 'string' ? target.model : '',
|
|
70
|
+
ollamaMode: (typeof target.provider === 'string' ? target.provider : agent.provider) === 'ollama'
|
|
71
|
+
? (target.ollamaMode === 'cloud' ? 'cloud' : 'local')
|
|
72
|
+
: null,
|
|
67
73
|
credentialId: target.credentialId ?? null,
|
|
68
74
|
fallbackCredentialIds: Array.isArray(target.fallbackCredentialIds) ? target.fallbackCredentialIds : [],
|
|
69
75
|
apiEndpoint: normalizeProviderEndpoint(
|
|
@@ -79,6 +79,7 @@ export async function POST(req: Request) {
|
|
|
79
79
|
systemPrompt: body.systemPrompt,
|
|
80
80
|
provider: body.provider,
|
|
81
81
|
model: body.model,
|
|
82
|
+
ollamaMode: body.provider === 'ollama' ? (body.ollamaMode || 'local') : null,
|
|
82
83
|
credentialId: body.credentialId,
|
|
83
84
|
fallbackCredentialIds: body.fallbackCredentialIds,
|
|
84
85
|
apiEndpoint: normalizeProviderEndpoint(body.provider, body.apiEndpoint || null),
|
|
@@ -88,6 +89,7 @@ export async function POST(req: Request) {
|
|
|
88
89
|
routingStrategy: body.routingStrategy,
|
|
89
90
|
routingTargets: body.routingTargets?.map((target) => ({
|
|
90
91
|
...target,
|
|
92
|
+
ollamaMode: target.provider === 'ollama' ? (target.ollamaMode || 'local') : null,
|
|
91
93
|
apiEndpoint: normalizeProviderEndpoint(target.provider, target.apiEndpoint || null),
|
|
92
94
|
})),
|
|
93
95
|
delegationEnabled: body.delegationEnabled ?? false,
|
|
@@ -25,7 +25,7 @@ function seedAgent(id: string, overrides: Record<string, unknown> = {}) {
|
|
|
25
25
|
fallbackCredentialIds: [],
|
|
26
26
|
apiEndpoint: null,
|
|
27
27
|
gatewayProfileId: null,
|
|
28
|
-
|
|
28
|
+
extensions: ['memory'],
|
|
29
29
|
createdAt: now,
|
|
30
30
|
updatedAt: now,
|
|
31
31
|
...overrides,
|
|
@@ -84,7 +84,7 @@ test('POST /api/agents/[id]/thread reuses an existing thread for a disabled agen
|
|
|
84
84
|
sessionType: 'human',
|
|
85
85
|
agentId: 'agent-thread-disabled-existing',
|
|
86
86
|
parentSessionId: null,
|
|
87
|
-
|
|
87
|
+
extensions: ['memory'],
|
|
88
88
|
tools: ['memory'],
|
|
89
89
|
heartbeatEnabled: false,
|
|
90
90
|
heartbeatIntervalSec: null,
|
|
@@ -104,7 +104,7 @@ test('POST /api/agents/[id]/thread reuses an existing thread for a disabled agen
|
|
|
104
104
|
connectorIdleTimeoutSec: null,
|
|
105
105
|
connectorMaxAgeSec: null,
|
|
106
106
|
mailbox: null,
|
|
107
|
-
connectorContext:
|
|
107
|
+
connectorContext: undefined,
|
|
108
108
|
lastAutoMemoryAt: null,
|
|
109
109
|
lastHeartbeatText: null,
|
|
110
110
|
lastHeartbeatSentAt: null,
|
|
@@ -37,7 +37,7 @@ export async function POST(req: Request) {
|
|
|
37
37
|
reason: typeof body.reason === 'string' ? body.reason : null,
|
|
38
38
|
engagedBy: typeof body.engagedBy === 'string' ? body.engagedBy : 'user',
|
|
39
39
|
})
|
|
40
|
-
stopDaemon({ source: `api/autonomy/estop:${level}` })
|
|
40
|
+
await stopDaemon({ source: `api/autonomy/estop:${level}` })
|
|
41
41
|
const cancelled = level === 'all'
|
|
42
42
|
? cancelAllRuns('Cancelled because all estop is engaged.')
|
|
43
43
|
: { cancelledQueued: 0, abortedRunning: 0 }
|
|
@@ -35,7 +35,7 @@ test('chatroom route prevents duplicate chained replies when an already-queued a
|
|
|
35
35
|
name: 'Alpha',
|
|
36
36
|
provider: 'chatroom-provider',
|
|
37
37
|
model: 'room-model',
|
|
38
|
-
|
|
38
|
+
extensions: [],
|
|
39
39
|
createdAt: now,
|
|
40
40
|
updatedAt: now,
|
|
41
41
|
},
|
|
@@ -44,7 +44,7 @@ test('chatroom route prevents duplicate chained replies when an already-queued a
|
|
|
44
44
|
name: 'Beta',
|
|
45
45
|
provider: 'chatroom-provider',
|
|
46
46
|
model: 'room-model',
|
|
47
|
-
|
|
47
|
+
extensions: [],
|
|
48
48
|
createdAt: now,
|
|
49
49
|
updatedAt: now,
|
|
50
50
|
},
|
|
@@ -183,7 +183,7 @@ test('chatroom route forwards tool activity and records one reply per participat
|
|
|
183
183
|
name: 'Alpha',
|
|
184
184
|
provider: 'chatroom-tool-provider',
|
|
185
185
|
model: 'room-tool-model',
|
|
186
|
-
|
|
186
|
+
extensions: ['shell'],
|
|
187
187
|
createdAt: now,
|
|
188
188
|
updatedAt: now,
|
|
189
189
|
},
|
|
@@ -192,7 +192,7 @@ test('chatroom route forwards tool activity and records one reply per participat
|
|
|
192
192
|
name: 'Beta',
|
|
193
193
|
provider: 'chatroom-tool-provider',
|
|
194
194
|
model: 'room-tool-model',
|
|
195
|
-
|
|
195
|
+
extensions: ['shell'],
|
|
196
196
|
createdAt: now,
|
|
197
197
|
updatedAt: now,
|
|
198
198
|
},
|
|
@@ -256,7 +256,7 @@ test('chatroom route forwards tool activity and records one reply per participat
|
|
|
256
256
|
return { fullText: reply, finalResponse: reply }
|
|
257
257
|
}
|
|
258
258
|
if (agentId === 'beta') {
|
|
259
|
-
const reply = 'Beta reviewed the
|
|
259
|
+
const reply = 'Beta reviewed the extension path and agrees with Alpha.'
|
|
260
260
|
opts.write('data: ' + JSON.stringify({ t: 'r', text: reply }) + '\\n')
|
|
261
261
|
return { fullText: reply, finalResponse: reply }
|
|
262
262
|
}
|
|
@@ -268,7 +268,7 @@ test('chatroom route forwards tool activity and records one reply per participat
|
|
|
268
268
|
new Request('http://local/api/chatrooms/room_1/chat', {
|
|
269
269
|
method: 'POST',
|
|
270
270
|
headers: { 'content-type': 'application/json' },
|
|
271
|
-
body: JSON.stringify({ senderId: 'user', text: 'Please inspect the workspace and
|
|
271
|
+
body: JSON.stringify({ senderId: 'user', text: 'Please inspect the workspace and extension path.' }),
|
|
272
272
|
}),
|
|
273
273
|
{ params: Promise.resolve({ id: 'room_1' }) },
|
|
274
274
|
)
|
|
@@ -10,7 +10,12 @@ export const dynamic = 'force-dynamic'
|
|
|
10
10
|
|
|
11
11
|
export async function GET() {
|
|
12
12
|
const chatrooms = loadChatrooms()
|
|
13
|
-
|
|
13
|
+
const filtered: typeof chatrooms = {}
|
|
14
|
+
for (const [id, chatroom] of Object.entries(chatrooms)) {
|
|
15
|
+
if (chatroom.hidden === true || chatroom.archivedAt) continue
|
|
16
|
+
filtered[id] = chatroom
|
|
17
|
+
}
|
|
18
|
+
return NextResponse.json(filtered)
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
export async function POST(req: Request) {
|
|
@@ -48,7 +48,7 @@ test('chat route keeps long-lived user runs alive after stream disconnect and re
|
|
|
48
48
|
name: 'Workbench Agent',
|
|
49
49
|
provider: 'workbench-provider',
|
|
50
50
|
model: 'wb-model',
|
|
51
|
-
|
|
51
|
+
extensions: [],
|
|
52
52
|
createdAt: now,
|
|
53
53
|
updatedAt: now,
|
|
54
54
|
},
|
|
@@ -67,7 +67,7 @@ test('chat route keeps long-lived user runs alive after stream disconnect and re
|
|
|
67
67
|
lastActiveAt: now,
|
|
68
68
|
sessionType: 'human',
|
|
69
69
|
agentId: 'agent_1',
|
|
70
|
-
|
|
70
|
+
extensions: [],
|
|
71
71
|
},
|
|
72
72
|
})
|
|
73
73
|
|
|
@@ -159,7 +159,7 @@ test('chat route heartbeat runs stay internal and do not persist terminal ack te
|
|
|
159
159
|
name: 'Heartbeat Agent',
|
|
160
160
|
provider: 'heartbeat-provider',
|
|
161
161
|
model: 'hb-model',
|
|
162
|
-
|
|
162
|
+
extensions: [],
|
|
163
163
|
heartbeatEnabled: true,
|
|
164
164
|
createdAt: now,
|
|
165
165
|
updatedAt: now,
|
|
@@ -180,7 +180,7 @@ test('chat route heartbeat runs stay internal and do not persist terminal ack te
|
|
|
180
180
|
sessionType: 'human',
|
|
181
181
|
agentId: 'agent_1',
|
|
182
182
|
heartbeatEnabled: true,
|
|
183
|
-
|
|
183
|
+
extensions: [],
|
|
184
184
|
},
|
|
185
185
|
})
|
|
186
186
|
|
|
@@ -279,7 +279,7 @@ test('chat route queues a second user message behind the first run and completes
|
|
|
279
279
|
name: 'Queue Agent',
|
|
280
280
|
provider: 'queue-provider',
|
|
281
281
|
model: 'queue-model',
|
|
282
|
-
|
|
282
|
+
extensions: [],
|
|
283
283
|
createdAt: now,
|
|
284
284
|
updatedAt: now,
|
|
285
285
|
},
|
|
@@ -298,7 +298,7 @@ test('chat route queues a second user message behind the first run and completes
|
|
|
298
298
|
lastActiveAt: now,
|
|
299
299
|
sessionType: 'human',
|
|
300
300
|
agentId: 'agent_1',
|
|
301
|
-
|
|
301
|
+
extensions: [],
|
|
302
302
|
},
|
|
303
303
|
})
|
|
304
304
|
|
|
@@ -356,7 +356,7 @@ test('chat route queues a second user message behind the first run and completes
|
|
|
356
356
|
assistantReplies,
|
|
357
357
|
runStatuses: runs.listRuns({ sessionId: 'sess_1' }).map((entry) => entry.status),
|
|
358
358
|
}))
|
|
359
|
-
`, { prefix: 'swarmclaw-chat-route-
|
|
359
|
+
`, { prefix: 'swarmclaw-chat-route-extensions-' })
|
|
360
360
|
|
|
361
361
|
assert.match(output.firstRunMeta, /"position":0/)
|
|
362
362
|
assert.match(output.secondRunMeta, /"position":1/)
|
|
@@ -367,7 +367,7 @@ test('chat route queues a second user message behind the first run and completes
|
|
|
367
367
|
assert.deepEqual(output.runStatuses, ['completed', 'completed'])
|
|
368
368
|
})
|
|
369
369
|
|
|
370
|
-
test('chat route forwards
|
|
370
|
+
test('chat route forwards extension-path tool activity when an extension-enabled run uses streamAgentChat', () => {
|
|
371
371
|
const output = runWithTempDataDir<{
|
|
372
372
|
toolCalls: string[]
|
|
373
373
|
toolResults: string[]
|
|
@@ -382,10 +382,10 @@ test('chat route forwards plugin-path tool activity when a plugin-enabled run us
|
|
|
382
382
|
const route = routeMod.default || routeMod
|
|
383
383
|
const stream = streamMod.default || streamMod
|
|
384
384
|
|
|
385
|
-
providers.PROVIDERS['
|
|
386
|
-
id: '
|
|
387
|
-
name: '
|
|
388
|
-
models: ['
|
|
385
|
+
providers.PROVIDERS['extension-provider'] = {
|
|
386
|
+
id: 'extension-provider',
|
|
387
|
+
name: 'Extension Provider',
|
|
388
|
+
models: ['extension-model'],
|
|
389
389
|
requiresApiKey: false,
|
|
390
390
|
requiresEndpoint: false,
|
|
391
391
|
handler: { streamChat: async () => '' },
|
|
@@ -395,10 +395,10 @@ test('chat route forwards plugin-path tool activity when a plugin-enabled run us
|
|
|
395
395
|
storage.saveAgents({
|
|
396
396
|
agent_1: {
|
|
397
397
|
id: 'agent_1',
|
|
398
|
-
name: '
|
|
399
|
-
provider: '
|
|
400
|
-
model: '
|
|
401
|
-
|
|
398
|
+
name: 'Extension Agent',
|
|
399
|
+
provider: 'extension-provider',
|
|
400
|
+
model: 'extension-model',
|
|
401
|
+
extensions: ['web'],
|
|
402
402
|
createdAt: now,
|
|
403
403
|
updatedAt: now,
|
|
404
404
|
},
|
|
@@ -406,18 +406,18 @@ test('chat route forwards plugin-path tool activity when a plugin-enabled run us
|
|
|
406
406
|
storage.saveSessions({
|
|
407
407
|
sess_1: {
|
|
408
408
|
id: 'sess_1',
|
|
409
|
-
name: '
|
|
409
|
+
name: 'Extension Session',
|
|
410
410
|
cwd: process.env.WORKSPACE_DIR,
|
|
411
411
|
user: 'workbench',
|
|
412
|
-
provider: '
|
|
413
|
-
model: '
|
|
412
|
+
provider: 'extension-provider',
|
|
413
|
+
model: 'extension-model',
|
|
414
414
|
claudeSessionId: null,
|
|
415
415
|
messages: [],
|
|
416
416
|
createdAt: now,
|
|
417
417
|
lastActiveAt: now,
|
|
418
418
|
sessionType: 'human',
|
|
419
419
|
agentId: 'agent_1',
|
|
420
|
-
|
|
420
|
+
extensions: ['web'],
|
|
421
421
|
},
|
|
422
422
|
})
|
|
423
423
|
|
|
@@ -460,7 +460,7 @@ test('chat route forwards plugin-path tool activity when a plugin-enabled run us
|
|
|
460
460
|
toolOutput: 'Fetched queue health summary',
|
|
461
461
|
toolCallId: 'tool-1',
|
|
462
462
|
}) + '\\n')
|
|
463
|
-
const reply = 'Queue looks healthy and no
|
|
463
|
+
const reply = 'Queue looks healthy and no extension errors were observed.'
|
|
464
464
|
opts.write('data: ' + JSON.stringify({ t: 'r', text: reply }) + '\\n')
|
|
465
465
|
return { fullText: reply, finalResponse: reply }
|
|
466
466
|
})
|
|
@@ -488,9 +488,9 @@ test('chat route forwards plugin-path tool activity when a plugin-enabled run us
|
|
|
488
488
|
} finally {
|
|
489
489
|
stream.setStreamAgentChatForTest(null)
|
|
490
490
|
}
|
|
491
|
-
`, { prefix: 'swarmclaw-chat-route-
|
|
491
|
+
`, { prefix: 'swarmclaw-chat-route-extension-events-' })
|
|
492
492
|
|
|
493
493
|
assert.deepEqual(output.toolCalls, ['web'])
|
|
494
494
|
assert.deepEqual(output.toolResults, ['Fetched queue health summary'])
|
|
495
|
-
assert.deepEqual(output.assistantReplies, ['Queue looks healthy and no
|
|
495
|
+
assert.deepEqual(output.assistantReplies, ['Queue looks healthy and no extension errors were observed.'])
|
|
496
496
|
})
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import {
|
|
2
|
+
import { loadStoredItem, upsertStoredItem } from '@/lib/server/storage'
|
|
3
3
|
import { notFound } from '@/lib/server/collection-helpers'
|
|
4
|
-
import { getSessionRunState } from '@/lib/server/runtime/session-run-manager'
|
|
5
4
|
import { materializeStreamingAssistantArtifacts } from '@/lib/chat/chat-streaming-state'
|
|
6
5
|
import { appendSessionNote } from '@/lib/server/session-note'
|
|
7
6
|
import type { Message, Session } from '@/types'
|
|
@@ -12,9 +11,9 @@ export async function GET(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
12
11
|
if (!session) return notFound()
|
|
13
12
|
session.messages = Array.isArray(session.messages) ? session.messages : []
|
|
14
13
|
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
if (!
|
|
14
|
+
const sessionClaimsActive = session.active === true
|
|
15
|
+
|| (typeof session.currentRunId === 'string' && session.currentRunId.trim().length > 0)
|
|
16
|
+
if (!sessionClaimsActive && materializeStreamingAssistantArtifacts(session.messages)) {
|
|
18
17
|
upsertStoredItem('sessions', id, session)
|
|
19
18
|
}
|
|
20
19
|
|
|
@@ -64,6 +64,11 @@ export async function PUT(req: Request, { params }: { params: Promise<{ id: stri
|
|
|
64
64
|
else if (agentIdUpdateProvided && linkedRoute?.model) session.model = linkedRoute.model
|
|
65
65
|
else if (agentIdUpdateProvided && linkedAgent?.model !== undefined) session.model = linkedAgent.model
|
|
66
66
|
|
|
67
|
+
if (updates.ollamaMode !== undefined) session.ollamaMode = updates.ollamaMode
|
|
68
|
+
else if (updates.provider !== undefined && updates.provider !== 'ollama') session.ollamaMode = null
|
|
69
|
+
else if (agentIdUpdateProvided && linkedRoute) session.ollamaMode = linkedRoute.ollamaMode ?? null
|
|
70
|
+
else if (agentIdUpdateProvided && linkedAgent) session.ollamaMode = linkedAgent.ollamaMode ?? null
|
|
71
|
+
|
|
67
72
|
if (updates.credentialId !== undefined) session.credentialId = updates.credentialId
|
|
68
73
|
else if (agentIdUpdateProvided && linkedRoute) session.credentialId = linkedRoute.credentialId ?? null
|
|
69
74
|
else if (agentIdUpdateProvided && linkedAgent) session.credentialId = linkedAgent.credentialId ?? null
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import test from 'node:test'
|
|
3
|
+
|
|
4
|
+
import { runWithTempDataDir } from '@/lib/server/test-utils/run-with-temp-data-dir'
|
|
5
|
+
|
|
6
|
+
test('chat messages route materializes stale streaming artifacts even if runtime memory is stale', () => {
|
|
7
|
+
const output = runWithTempDataDir<{
|
|
8
|
+
status: number
|
|
9
|
+
returnedStreaming: boolean | null
|
|
10
|
+
returnedText: string | null
|
|
11
|
+
persistedStreaming: boolean | null
|
|
12
|
+
persistedText: string | null
|
|
13
|
+
}>(`
|
|
14
|
+
const storageMod = await import('./src/lib/server/storage')
|
|
15
|
+
const routeMod = await import('./src/app/api/chats/[id]/messages/route')
|
|
16
|
+
const storage = storageMod.default || storageMod
|
|
17
|
+
const route = routeMod.default || routeMod
|
|
18
|
+
|
|
19
|
+
storage.upsertStoredItem('sessions', 'session-stale', {
|
|
20
|
+
id: 'session-stale',
|
|
21
|
+
name: 'Stale session',
|
|
22
|
+
provider: 'ollama',
|
|
23
|
+
model: 'test-model',
|
|
24
|
+
createdAt: 1,
|
|
25
|
+
updatedAt: 1,
|
|
26
|
+
active: false,
|
|
27
|
+
currentRunId: null,
|
|
28
|
+
messages: [
|
|
29
|
+
{ role: 'user', text: 'hello', time: 1 },
|
|
30
|
+
{
|
|
31
|
+
role: 'assistant',
|
|
32
|
+
text: 'partial reply',
|
|
33
|
+
time: 2,
|
|
34
|
+
streaming: true,
|
|
35
|
+
toolEvents: [{ name: 'http_request', input: '{}', output: '{"ok":true}' }],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
storage.active.set('session-stale', { kill() {} })
|
|
41
|
+
|
|
42
|
+
const response = await route.GET(
|
|
43
|
+
new Request('http://local/api/chats/session-stale/messages'),
|
|
44
|
+
{ params: Promise.resolve({ id: 'session-stale' }) },
|
|
45
|
+
)
|
|
46
|
+
const payload = await response.json()
|
|
47
|
+
const persisted = storage.loadSession('session-stale')
|
|
48
|
+
const returned = Array.isArray(payload) ? payload[payload.length - 1] : null
|
|
49
|
+
const saved = Array.isArray(persisted?.messages) ? persisted.messages[persisted.messages.length - 1] : null
|
|
50
|
+
|
|
51
|
+
console.log(JSON.stringify({
|
|
52
|
+
status: response.status,
|
|
53
|
+
returnedStreaming: returned?.streaming === true,
|
|
54
|
+
returnedText: returned?.text || null,
|
|
55
|
+
persistedStreaming: saved?.streaming === true,
|
|
56
|
+
persistedText: saved?.text || null,
|
|
57
|
+
}))
|
|
58
|
+
`, { prefix: 'swarmclaw-chat-messages-route-' })
|
|
59
|
+
|
|
60
|
+
assert.equal(output.status, 200)
|
|
61
|
+
assert.equal(output.returnedStreaming, false)
|
|
62
|
+
assert.equal(output.persistedStreaming, false)
|
|
63
|
+
assert.equal(output.returnedText, 'partial reply')
|
|
64
|
+
assert.equal(output.persistedText, 'partial reply')
|
|
65
|
+
})
|
|
@@ -131,6 +131,7 @@ export async function POST(req: Request) {
|
|
|
131
131
|
user: body.user || 'user',
|
|
132
132
|
provider: body.provider || agent?.provider || 'claude-cli',
|
|
133
133
|
model: body.model || agent?.model || '',
|
|
134
|
+
ollamaMode: body.ollamaMode ?? agent?.ollamaMode ?? ((body.provider || agent?.provider) === 'ollama' ? 'local' : null),
|
|
134
135
|
credentialId: body.credentialId || agent?.credentialId || null,
|
|
135
136
|
fallbackCredentialIds: body.fallbackCredentialIds || agent?.fallbackCredentialIds || [],
|
|
136
137
|
apiEndpoint: normalizeProviderEndpoint(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import { loadCredentials,
|
|
2
|
+
import { loadCredentials, deleteCredential } from '@/lib/server/storage'
|
|
3
3
|
import { notFound } from '@/lib/server/collection-helpers'
|
|
4
4
|
|
|
5
5
|
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
@@ -8,8 +8,7 @@ export async function DELETE(_req: Request, { params }: { params: Promise<{ id:
|
|
|
8
8
|
if (!creds[credId]) {
|
|
9
9
|
return notFound()
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
saveCredentials(creds)
|
|
11
|
+
deleteCredential(credId)
|
|
13
12
|
console.log(`[credentials] deleted ${credId}`)
|
|
14
13
|
return new NextResponse('OK')
|
|
15
14
|
}
|
|
@@ -19,7 +19,7 @@ export async function POST(req: Request) {
|
|
|
19
19
|
return NextResponse.json({ ok: true, status: 'running' })
|
|
20
20
|
} else if (action === 'stop') {
|
|
21
21
|
const { stopDaemon } = await import('@/lib/server/runtime/daemon-state')
|
|
22
|
-
stopDaemon({ source: 'api/daemon:post:stop', manualStop: true })
|
|
22
|
+
await stopDaemon({ source: 'api/daemon:post:stop', manualStop: true })
|
|
23
23
|
notify('daemon')
|
|
24
24
|
return NextResponse.json({ ok: true, status: 'stopped' })
|
|
25
25
|
}
|