@swarmclawai/swarmclaw 0.8.4 → 0.8.7
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 +9 -9
- package/bin/swarmclaw.js +5 -1
- package/bin/worker-cmd.js +73 -0
- package/package.json +2 -1
- package/src/app/api/agents/[id]/route.ts +17 -7
- package/src/app/api/agents/route.ts +21 -8
- package/src/app/api/approvals/route.test.ts +6 -6
- package/src/app/api/approvals/route.ts +2 -1
- package/src/app/api/auth/route.ts +2 -3
- package/src/app/api/chatrooms/[id]/chat/route.test.ts +299 -0
- package/src/app/api/chatrooms/[id]/chat/route.ts +3 -2
- package/src/app/api/chatrooms/[id]/route.ts +7 -6
- package/src/app/api/chats/[id]/chat/route.test.ts +496 -0
- package/src/app/api/chats/[id]/chat/route.ts +7 -3
- package/src/app/api/chats/[id]/clear/route.ts +9 -9
- package/src/app/api/chats/[id]/devserver/route.ts +2 -1
- package/src/app/api/chats/[id]/edit-resend/route.ts +3 -4
- package/src/app/api/chats/[id]/fork/route.ts +3 -5
- package/src/app/api/chats/[id]/restore/route.ts +6 -7
- package/src/app/api/chats/[id]/retry/route.ts +3 -4
- package/src/app/api/chats/[id]/route.ts +61 -62
- package/src/app/api/chats/route.ts +7 -1
- package/src/app/api/connectors/[id]/route.ts +7 -8
- package/src/app/api/connectors/route.ts +5 -4
- package/src/app/api/eval/run/route.ts +2 -1
- package/src/app/api/eval/suite/route.ts +2 -1
- package/src/app/api/external-agents/route.test.ts +1 -1
- package/src/app/api/external-agents/route.ts +2 -2
- package/src/app/api/files/serve/route.ts +1 -1
- package/src/app/api/gateways/[id]/route.ts +7 -5
- package/src/app/api/gateways/route.ts +1 -1
- package/src/app/api/knowledge/upload/route.ts +1 -1
- package/src/app/api/logs/route.ts +5 -7
- package/src/app/api/memory-images/[filename]/route.ts +2 -3
- package/src/app/api/openclaw/agent-files/route.ts +4 -3
- package/src/app/api/openclaw/approvals/route.ts +3 -4
- package/src/app/api/openclaw/config-sync/route.ts +3 -2
- package/src/app/api/openclaw/cron/route.ts +3 -2
- package/src/app/api/openclaw/dotenv-keys/route.ts +2 -1
- package/src/app/api/openclaw/exec-config/route.ts +3 -2
- package/src/app/api/openclaw/gateway/route.ts +5 -4
- package/src/app/api/openclaw/history/route.ts +3 -2
- package/src/app/api/openclaw/media/route.ts +2 -1
- package/src/app/api/openclaw/permissions/route.ts +3 -2
- package/src/app/api/openclaw/sandbox-env/route.ts +3 -2
- package/src/app/api/openclaw/skills/install/route.ts +2 -1
- package/src/app/api/openclaw/skills/remove/route.ts +2 -1
- package/src/app/api/openclaw/skills/route.ts +3 -2
- package/src/app/api/orchestrator/run/route.ts +5 -14
- package/src/app/api/perf/route.ts +43 -0
- package/src/app/api/plugins/dependencies/route.ts +2 -1
- package/src/app/api/plugins/install/route.ts +2 -1
- package/src/app/api/plugins/marketplace/route.ts +3 -2
- package/src/app/api/plugins/settings/route.ts +2 -1
- package/src/app/api/preview-server/route.ts +11 -10
- package/src/app/api/projects/[id]/route.ts +1 -1
- package/src/app/api/schedules/[id]/route.test.ts +128 -0
- package/src/app/api/schedules/[id]/route.ts +43 -43
- package/src/app/api/schedules/[id]/run/route.ts +11 -62
- package/src/app/api/schedules/route.ts +21 -87
- package/src/app/api/settings/route.ts +2 -0
- package/src/app/api/setup/doctor/route.ts +9 -8
- package/src/app/api/tasks/[id]/approve/route.ts +33 -30
- package/src/app/api/tasks/[id]/route.ts +12 -35
- package/src/app/api/tasks/import/github/route.ts +2 -1
- package/src/app/api/tasks/route.ts +79 -91
- package/src/app/api/wallets/[id]/approve/route.ts +2 -1
- package/src/app/api/wallets/[id]/route.ts +13 -19
- package/src/app/api/wallets/[id]/send/route.ts +2 -1
- package/src/app/api/wallets/route.ts +2 -1
- package/src/app/api/webhooks/[id]/route.ts +2 -1
- package/src/app/api/webhooks/route.test.ts +3 -1
- package/src/app/page.tsx +23 -331
- package/src/cli/index.js +19 -0
- package/src/cli/index.ts +38 -7
- package/src/cli/spec.js +9 -0
- package/src/components/activity/activity-feed.tsx +7 -4
- package/src/components/agents/agent-card.tsx +32 -6
- package/src/components/agents/agent-chat-list.tsx +55 -22
- package/src/components/agents/agent-files-editor.tsx +3 -2
- package/src/components/agents/agent-sheet.tsx +123 -22
- package/src/components/agents/inspector-panel.tsx +1 -1
- package/src/components/agents/openclaw-skills-panel.tsx +2 -1
- package/src/components/agents/trash-list.tsx +1 -1
- package/src/components/auth/access-key-gate.tsx +8 -2
- package/src/components/auth/setup-wizard.tsx +10 -9
- package/src/components/auth/user-picker.tsx +3 -2
- package/src/components/chat/chat-area.tsx +20 -1
- package/src/components/chat/chat-card.tsx +18 -3
- package/src/components/chat/chat-header.tsx +24 -4
- package/src/components/chat/chat-list.tsx +2 -11
- package/src/components/chat/heartbeat-history-panel.tsx +2 -1
- package/src/components/chat/message-bubble.tsx +45 -6
- package/src/components/chat/message-list.tsx +280 -145
- package/src/components/chat/streaming-bubble.tsx +217 -60
- package/src/components/chat/swarm-panel.test.ts +274 -0
- package/src/components/chat/swarm-panel.tsx +410 -0
- package/src/components/chat/swarm-status-card.tsx +346 -0
- package/src/components/chat/tool-call-bubble.tsx +48 -23
- package/src/components/chatrooms/chatroom-list.tsx +8 -5
- package/src/components/chatrooms/chatroom-message.tsx +10 -7
- package/src/components/chatrooms/chatroom-view.tsx +12 -9
- package/src/components/connectors/connector-health.tsx +6 -4
- package/src/components/connectors/connector-list.tsx +16 -11
- package/src/components/connectors/connector-sheet.tsx +12 -6
- package/src/components/home/home-view.tsx +38 -24
- package/src/components/input/chat-input.tsx +10 -1
- package/src/components/layout/app-layout.tsx +2 -38
- package/src/components/layout/sheet-layer.tsx +50 -0
- package/src/components/mcp-servers/mcp-server-list.tsx +37 -5
- package/src/components/mcp-servers/mcp-server-sheet.tsx +12 -2
- package/src/components/plugins/plugin-list.tsx +8 -4
- package/src/components/plugins/plugin-sheet.tsx +2 -1
- package/src/components/providers/provider-list.tsx +3 -2
- package/src/components/providers/provider-sheet.tsx +2 -1
- package/src/components/runs/run-list.tsx +11 -7
- package/src/components/schedules/schedule-card.tsx +5 -3
- package/src/components/shared/agent-switch-dialog.tsx +1 -1
- package/src/components/shared/attachment-chip.tsx +19 -3
- package/src/components/shared/notification-center.tsx +6 -3
- package/src/components/shared/settings/plugin-manager.tsx +3 -2
- package/src/components/shared/settings/section-embedding.tsx +2 -1
- package/src/components/shared/settings/section-orchestrator.tsx +2 -1
- package/src/components/shared/settings/section-user-preferences.tsx +107 -0
- package/src/components/shared/settings/settings-page.tsx +13 -9
- package/src/components/skills/clawhub-browser.tsx +15 -4
- package/src/components/skills/skill-list.tsx +15 -4
- package/src/components/tasks/approvals-panel.tsx +2 -1
- package/src/components/tasks/task-board.tsx +35 -37
- package/src/components/tasks/task-sheet.tsx +4 -3
- package/src/components/ui/full-screen-loader.tsx +164 -0
- package/src/components/wallets/wallet-approval-dialog.tsx +2 -1
- package/src/components/wallets/wallet-panel.tsx +6 -5
- package/src/components/wallets/wallet-section.tsx +3 -2
- package/src/components/webhooks/webhook-list.tsx +4 -5
- package/src/components/webhooks/webhook-sheet.tsx +6 -6
- package/src/hooks/use-app-bootstrap.ts +202 -0
- package/src/hooks/use-mounted-ref.ts +14 -0
- package/src/hooks/use-now.ts +31 -0
- package/src/hooks/use-openclaw-gateway.ts +2 -1
- package/src/instrumentation.ts +20 -8
- package/src/lib/agent-default-tools.test.ts +52 -0
- package/src/lib/agent-default-tools.ts +40 -0
- package/src/lib/api-client.test.ts +21 -0
- package/src/lib/api-client.ts +6 -11
- package/src/lib/canvas-content.test.ts +360 -0
- package/src/lib/chat-streaming-state.test.ts +49 -2
- package/src/lib/chat-streaming-state.ts +26 -10
- package/src/lib/fetch-timeout.test.ts +54 -0
- package/src/lib/fetch-timeout.ts +60 -3
- package/src/lib/live-tool-events.test.ts +77 -0
- package/src/lib/live-tool-events.ts +73 -0
- package/src/lib/local-observability.test.ts +2 -2
- package/src/lib/openclaw-endpoint.test.ts +1 -1
- package/src/lib/providers/anthropic.ts +12 -16
- package/src/lib/providers/index.ts +4 -2
- package/src/lib/providers/ollama.ts +9 -6
- package/src/lib/providers/openai.ts +11 -14
- package/src/lib/runtime-env.test.ts +8 -8
- package/src/lib/schedule-dedupe-advanced.test.ts +2 -2
- package/src/lib/schedule-dedupe.test.ts +1 -1
- package/src/lib/schedule-dedupe.ts +3 -2
- package/src/lib/server/agent-thread-session.test.ts +6 -6
- package/src/lib/server/agent-thread-session.ts +6 -9
- package/src/lib/server/alert-dispatch.ts +2 -1
- package/src/lib/server/api-routes.test.ts +6 -6
- package/src/lib/server/approval-connector-notify.test.ts +4 -4
- package/src/lib/server/approvals-auto-approve.test.ts +29 -29
- package/src/lib/server/approvals.test.ts +317 -0
- package/src/lib/server/approvals.ts +5 -4
- package/src/lib/server/autonomy-runtime.test.ts +11 -11
- package/src/lib/server/browser-state.ts +2 -2
- package/src/lib/server/capability-router.test.ts +1 -1
- package/src/lib/server/capability-router.ts +3 -2
- package/src/lib/server/chat-execution-advanced.test.ts +15 -2
- package/src/lib/server/chat-execution-connector-delivery.ts +67 -0
- package/src/lib/server/chat-execution-disabled.test.ts +3 -3
- package/src/lib/server/chat-execution-eval-history.test.ts +3 -3
- package/src/lib/server/chat-execution-heartbeat.test.ts +42 -1
- package/src/lib/server/chat-execution-session-sync.test.ts +119 -0
- package/src/lib/server/chat-execution-tool-events.ts +116 -0
- package/src/lib/server/chat-execution-utils.test.ts +479 -0
- package/src/lib/server/chat-execution-utils.ts +533 -0
- package/src/lib/server/chat-execution.ts +153 -748
- package/src/lib/server/chat-streaming-utils.ts +174 -0
- package/src/lib/server/chat-turn-tool-routing.ts +310 -0
- package/src/lib/server/chatroom-session-persistence.test.ts +2 -2
- package/src/lib/server/clawhub-client.ts +2 -1
- package/src/lib/server/collection-helpers.test.ts +92 -0
- package/src/lib/server/collection-helpers.ts +25 -3
- package/src/lib/server/connectors/access.ts +146 -0
- package/src/lib/server/connectors/bluebubbles.test.ts +1 -1
- package/src/lib/server/connectors/bluebubbles.ts +4 -4
- package/src/lib/server/connectors/commands.ts +367 -0
- package/src/lib/server/connectors/connector-routing.test.ts +4 -4
- package/src/lib/server/connectors/delivery.ts +142 -0
- package/src/lib/server/connectors/discord.ts +37 -40
- package/src/lib/server/connectors/email.ts +11 -10
- package/src/lib/server/connectors/googlechat.ts +4 -4
- package/src/lib/server/connectors/inbound-audio-transcription.ts +2 -1
- package/src/lib/server/connectors/ingress-delivery.ts +23 -0
- package/src/lib/server/connectors/manager-roundtrip.test.ts +300 -0
- package/src/lib/server/connectors/manager.test.ts +352 -77
- package/src/lib/server/connectors/manager.ts +134 -673
- package/src/lib/server/connectors/matrix.ts +4 -4
- package/src/lib/server/connectors/message-sentinel.ts +7 -0
- package/src/lib/server/connectors/openclaw.test.ts +1 -1
- package/src/lib/server/connectors/openclaw.ts +8 -10
- package/src/lib/server/connectors/outbox.test.ts +192 -0
- package/src/lib/server/connectors/outbox.ts +369 -0
- package/src/lib/server/connectors/pairing.test.ts +18 -1
- package/src/lib/server/connectors/pairing.ts +49 -4
- package/src/lib/server/connectors/policy.ts +9 -3
- package/src/lib/server/connectors/reconnect-state.ts +71 -0
- package/src/lib/server/connectors/response-media.ts +256 -0
- package/src/lib/server/connectors/runtime-state.ts +67 -0
- package/src/lib/server/connectors/session.test.ts +357 -0
- package/src/lib/server/connectors/session.ts +422 -0
- package/src/lib/server/connectors/signal.ts +7 -7
- package/src/lib/server/connectors/slack.ts +43 -43
- package/src/lib/server/connectors/teams.ts +4 -4
- package/src/lib/server/connectors/telegram.ts +37 -43
- package/src/lib/server/connectors/types.ts +31 -1
- package/src/lib/server/connectors/whatsapp.test.ts +108 -0
- package/src/lib/server/connectors/whatsapp.ts +106 -34
- package/src/lib/server/context-manager.test.ts +409 -0
- package/src/lib/server/cost.test.ts +1 -1
- package/src/lib/server/daemon-policy.ts +78 -0
- package/src/lib/server/daemon-state-connectors.test.ts +167 -0
- package/src/lib/server/daemon-state.test.ts +283 -55
- package/src/lib/server/daemon-state.ts +106 -109
- package/src/lib/server/data-dir.test.ts +5 -5
- package/src/lib/server/data-dir.ts +4 -0
- package/src/lib/server/delegation-jobs-advanced.test.ts +1 -1
- package/src/lib/server/delegation-jobs.test.ts +87 -0
- package/src/lib/server/delegation-jobs.ts +42 -48
- package/src/lib/server/devserver-launch.ts +1 -1
- package/src/lib/server/document-utils.ts +7 -9
- package/src/lib/server/elevenlabs.ts +2 -1
- package/src/lib/server/embeddings.test.ts +105 -0
- package/src/lib/server/ethereum.ts +3 -2
- package/src/lib/server/eval/agent-regression.ts +3 -2
- package/src/lib/server/eval/runner.ts +2 -1
- package/src/lib/server/eval/scorer.ts +2 -1
- package/src/lib/server/evm-swap.ts +2 -1
- package/src/lib/server/gateway/protocol.test.ts +1 -1
- package/src/lib/server/guardian.ts +2 -1
- package/src/lib/server/heartbeat-blocked-suppression.test.ts +151 -0
- package/src/lib/server/heartbeat-service-timer.test.ts +6 -6
- package/src/lib/server/heartbeat-service.test.ts +406 -0
- package/src/lib/server/heartbeat-service.ts +54 -7
- package/src/lib/server/heartbeat-wake.test.ts +19 -0
- package/src/lib/server/heartbeat-wake.ts +17 -16
- package/src/lib/server/integrity-monitor.test.ts +149 -0
- package/src/lib/server/json-utils.ts +22 -0
- package/src/lib/server/knowledge-db.test.ts +13 -13
- package/src/lib/server/link-understanding.ts +2 -1
- package/src/lib/server/llm-response-cache.test.ts +1 -1
- package/src/lib/server/main-agent-loop-advanced.test.ts +65 -3
- package/src/lib/server/main-agent-loop.test.ts +6 -6
- package/src/lib/server/main-agent-loop.ts +21 -7
- package/src/lib/server/mcp-client.test.ts +1 -1
- package/src/lib/server/mcp-conformance.test.ts +1 -1
- package/src/lib/server/mcp-conformance.ts +3 -2
- package/src/lib/server/memory-consolidation.ts +2 -1
- package/src/lib/server/memory-db.test.ts +485 -0
- package/src/lib/server/memory-db.ts +39 -26
- package/src/lib/server/memory-graph.test.ts +2 -2
- package/src/lib/server/memory-policy.test.ts +7 -7
- package/src/lib/server/memory-retrieval.test.ts +1 -1
- package/src/lib/server/openclaw-config-sync.ts +2 -1
- package/src/lib/server/openclaw-deploy.test.ts +1 -1
- package/src/lib/server/openclaw-deploy.ts +8 -12
- package/src/lib/server/openclaw-exec-config.ts +2 -1
- package/src/lib/server/openclaw-gateway.ts +6 -7
- package/src/lib/server/openclaw-skills-normalize.ts +2 -1
- package/src/lib/server/openclaw-sync.ts +7 -5
- package/src/lib/server/orchestrator-lg-structure.test.ts +17 -0
- package/src/lib/server/orchestrator-lg.ts +199 -327
- package/src/lib/server/path-utils.ts +31 -0
- package/src/lib/server/perf.ts +161 -0
- package/src/lib/server/plugins-approval-guidance.ts +115 -0
- package/src/lib/server/plugins.test.ts +1 -1
- package/src/lib/server/plugins.ts +22 -132
- package/src/lib/server/process-manager.ts +5 -8
- package/src/lib/server/provider-health.test.ts +137 -0
- package/src/lib/server/provider-health.ts +3 -3
- package/src/lib/server/provider-model-discovery.ts +3 -12
- package/src/lib/server/queue-followups.test.ts +9 -9
- package/src/lib/server/queue-reconcile.test.ts +2 -2
- package/src/lib/server/queue-recovery.test.ts +269 -0
- package/src/lib/server/queue.test.ts +570 -0
- package/src/lib/server/queue.ts +62 -455
- package/src/lib/server/resolve-image.ts +30 -0
- package/src/lib/server/runtime-settings.test.ts +4 -4
- package/src/lib/server/runtime-storage-write-paths.test.ts +60 -0
- package/src/lib/server/schedule-normalization.test.ts +279 -0
- package/src/lib/server/schedule-service.ts +263 -0
- package/src/lib/server/scheduler.ts +17 -74
- package/src/lib/server/session-mailbox.test.ts +191 -0
- package/src/lib/server/session-run-manager.test.ts +640 -0
- package/src/lib/server/session-run-manager.ts +59 -15
- package/src/lib/server/session-tools/autonomy-tools.test.ts +20 -20
- package/src/lib/server/session-tools/calendar.ts +2 -1
- package/src/lib/server/session-tools/canvas.ts +2 -1
- package/src/lib/server/session-tools/chatroom.ts +2 -1
- package/src/lib/server/session-tools/connector.ts +26 -28
- package/src/lib/server/session-tools/context-mgmt.ts +3 -2
- package/src/lib/server/session-tools/crawl.ts +4 -3
- package/src/lib/server/session-tools/crud.ts +105 -324
- package/src/lib/server/session-tools/delegate-fallback.test.ts +9 -9
- package/src/lib/server/session-tools/delegate.ts +6 -8
- package/src/lib/server/session-tools/discovery-approvals.test.ts +15 -15
- package/src/lib/server/session-tools/discovery.ts +4 -3
- package/src/lib/server/session-tools/document.ts +2 -1
- package/src/lib/server/session-tools/email.ts +2 -1
- package/src/lib/server/session-tools/extract.ts +2 -1
- package/src/lib/server/session-tools/file.ts +4 -3
- package/src/lib/server/session-tools/http.ts +2 -1
- package/src/lib/server/session-tools/human-loop.ts +2 -1
- package/src/lib/server/session-tools/image-gen.ts +4 -3
- package/src/lib/server/session-tools/index.ts +26 -30
- package/src/lib/server/session-tools/mailbox.ts +2 -1
- package/src/lib/server/session-tools/manage-connectors.test.ts +4 -4
- package/src/lib/server/session-tools/manage-schedules.test.ts +12 -12
- package/src/lib/server/session-tools/manage-tasks-advanced.test.ts +5 -5
- package/src/lib/server/session-tools/manage-tasks.test.ts +2 -2
- package/src/lib/server/session-tools/monitor.ts +2 -1
- package/src/lib/server/session-tools/platform.ts +2 -1
- package/src/lib/server/session-tools/plugin-creator.ts +2 -1
- package/src/lib/server/session-tools/replicate.ts +3 -2
- package/src/lib/server/session-tools/session-tools-wiring.test.ts +6 -6
- package/src/lib/server/session-tools/shell.ts +4 -9
- package/src/lib/server/session-tools/subagent.ts +322 -170
- package/src/lib/server/session-tools/table.ts +6 -5
- package/src/lib/server/session-tools/wallet-tool.test.ts +3 -3
- package/src/lib/server/session-tools/wallet.ts +7 -6
- package/src/lib/server/session-tools/web-browser-config.test.ts +1 -0
- package/src/lib/server/session-tools/web-utils.ts +317 -0
- package/src/lib/server/session-tools/web.ts +62 -328
- package/src/lib/server/skill-prompt-budget.test.ts +1 -1
- package/src/lib/server/skills-normalize.ts +2 -1
- package/src/lib/server/storage-item-access.test.ts +302 -0
- package/src/lib/server/storage.ts +366 -314
- package/src/lib/server/stream-agent-chat.test.ts +82 -3
- package/src/lib/server/stream-agent-chat.ts +146 -510
- package/src/lib/server/stream-continuation.ts +412 -0
- package/src/lib/server/subagent-lineage.test.ts +647 -0
- package/src/lib/server/subagent-lineage.ts +435 -0
- package/src/lib/server/subagent-runtime.test.ts +484 -0
- package/src/lib/server/subagent-runtime.ts +419 -0
- package/src/lib/server/subagent-swarm.test.ts +391 -0
- package/src/lib/server/subagent-swarm.ts +564 -0
- package/src/lib/server/system-events.ts +3 -3
- package/src/lib/server/task-followups.test.ts +491 -0
- package/src/lib/server/task-followups.ts +391 -0
- package/src/lib/server/task-lifecycle.test.ts +205 -0
- package/src/lib/server/task-lifecycle.ts +200 -0
- package/src/lib/server/task-quality-gate.test.ts +1 -1
- package/src/lib/server/task-resume.ts +208 -0
- package/src/lib/server/task-service.test.ts +108 -0
- package/src/lib/server/task-service.ts +264 -0
- package/src/lib/server/task-validation.test.ts +1 -1
- package/src/lib/server/test-utils/run-with-temp-data-dir.ts +42 -0
- package/src/lib/server/tool-capability-policy.test.ts +2 -2
- package/src/lib/server/tool-capability-policy.ts +3 -2
- package/src/lib/server/tool-planning.ts +2 -1
- package/src/lib/server/tool-retry.ts +2 -3
- package/src/lib/server/wake-dispatcher.test.ts +303 -0
- package/src/lib/server/wake-dispatcher.ts +318 -0
- package/src/lib/server/wake-mode.test.ts +161 -0
- package/src/lib/server/wake-mode.ts +174 -0
- package/src/lib/server/wallet-service.ts +8 -9
- package/src/lib/server/watch-jobs.ts +2 -1
- package/src/lib/server/workspace-context.ts +2 -2
- package/src/lib/shared-utils.test.ts +142 -0
- package/src/lib/shared-utils.ts +62 -0
- package/src/lib/tool-event-summary.ts +2 -1
- package/src/lib/view-routes.test.ts +100 -0
- package/src/lib/wallet.test.ts +322 -6
- package/src/proxy.test.ts +4 -4
- package/src/proxy.ts +2 -3
- package/src/stores/set-if-changed.ts +40 -0
- package/src/stores/slices/agent-slice.ts +111 -0
- package/src/stores/slices/auth-slice.ts +25 -0
- package/src/stores/slices/data-slice.ts +301 -0
- package/src/stores/slices/index.ts +7 -0
- package/src/stores/slices/session-slice.ts +112 -0
- package/src/stores/slices/task-slice.ts +63 -0
- package/src/stores/slices/ui-slice.ts +192 -0
- package/src/stores/use-app-store.ts +17 -822
- package/src/stores/use-approval-store.ts +2 -1
- package/src/stores/use-chat-store.ts +8 -1
- package/src/types/index.ts +10 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent Lineage & Lifecycle Tracker
|
|
3
|
+
*
|
|
4
|
+
* Tracks parent → child relationships between subagent sessions and manages
|
|
5
|
+
* lifecycle state transitions. The lifecycle state lives directly on the
|
|
6
|
+
* lineage node (single source of truth), eliminating the need for a separate
|
|
7
|
+
* state machine registry.
|
|
8
|
+
*
|
|
9
|
+
* Lineage nodes are stored in-memory (globalThis-scoped for HMR safety).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { genId } from '@/lib/id'
|
|
13
|
+
import { hmrSingleton } from '@/lib/shared-utils'
|
|
14
|
+
import { notify } from './ws-hub'
|
|
15
|
+
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Lifecycle States & Events
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
export type SubagentState =
|
|
21
|
+
| 'initializing' // Being set up (session creation, lineage registration)
|
|
22
|
+
| 'ready' // Session created, queued for execution
|
|
23
|
+
| 'running' // Actively executing
|
|
24
|
+
| 'waiting' // Paused while a child subagent completes
|
|
25
|
+
| 'completed' // Finished successfully
|
|
26
|
+
| 'failed' // Finished with error
|
|
27
|
+
| 'cancelled' // Cancelled by parent or user
|
|
28
|
+
| 'timed_out' // Exceeded time limit
|
|
29
|
+
|
|
30
|
+
export type SubagentEvent =
|
|
31
|
+
| 'READY' // Setup complete, queued
|
|
32
|
+
| 'START' // Begin execution
|
|
33
|
+
| 'SPAWN_CHILD' // Spawned a child subagent, waiting
|
|
34
|
+
| 'CHILD_DONE' // Child subagent completed, resume
|
|
35
|
+
| 'COMPLETE' // Execution finished successfully
|
|
36
|
+
| 'FAIL' // Execution finished with error
|
|
37
|
+
| 'CANCEL' // Cancelled externally
|
|
38
|
+
| 'TIMEOUT' // Time limit exceeded
|
|
39
|
+
|
|
40
|
+
const TRANSITIONS: Record<SubagentState, Partial<Record<SubagentEvent, SubagentState>>> = {
|
|
41
|
+
initializing: { READY: 'ready', FAIL: 'failed', CANCEL: 'cancelled' },
|
|
42
|
+
ready: { START: 'running', FAIL: 'failed', CANCEL: 'cancelled' },
|
|
43
|
+
running: { SPAWN_CHILD: 'waiting', COMPLETE: 'completed', FAIL: 'failed', CANCEL: 'cancelled', TIMEOUT: 'timed_out' },
|
|
44
|
+
waiting: { CHILD_DONE: 'running', COMPLETE: 'completed', FAIL: 'failed', CANCEL: 'cancelled', TIMEOUT: 'timed_out' },
|
|
45
|
+
completed: {},
|
|
46
|
+
failed: {},
|
|
47
|
+
cancelled: {},
|
|
48
|
+
timed_out: {},
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function isTerminalState(state: SubagentState): boolean {
|
|
52
|
+
return state === 'completed' || state === 'failed' || state === 'cancelled' || state === 'timed_out'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Resolve next state for a (state, event) pair. Returns undefined if invalid. */
|
|
56
|
+
function resolveTransition(state: SubagentState, event: SubagentEvent): SubagentState | undefined {
|
|
57
|
+
return TRANSITIONS[state]?.[event]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check if a transition is valid without performing it.
|
|
62
|
+
*/
|
|
63
|
+
export function canTransition(nodeOrState: string | SubagentState, event: SubagentEvent): boolean {
|
|
64
|
+
// If it looks like a lineage node ID, look it up
|
|
65
|
+
const state: SubagentState | undefined =
|
|
66
|
+
(nodeOrState in TRANSITIONS)
|
|
67
|
+
? nodeOrState as SubagentState
|
|
68
|
+
: store.get(nodeOrState)?.status
|
|
69
|
+
if (!state) return false
|
|
70
|
+
return resolveTransition(state, event) !== undefined
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get valid events from a state (for tests / introspection).
|
|
75
|
+
*/
|
|
76
|
+
export function validEvents(state: SubagentState): SubagentEvent[] {
|
|
77
|
+
return Object.keys(TRANSITIONS[state] ?? {}) as SubagentEvent[]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Types
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
export interface LineageNode {
|
|
85
|
+
/** Unique lineage node ID */
|
|
86
|
+
id: string
|
|
87
|
+
/** Session ID of this subagent */
|
|
88
|
+
sessionId: string
|
|
89
|
+
/** Agent ID executing in this session */
|
|
90
|
+
agentId: string
|
|
91
|
+
/** Agent display name */
|
|
92
|
+
agentName: string
|
|
93
|
+
/** Parent lineage node ID (null for root agents) */
|
|
94
|
+
parentId: string | null
|
|
95
|
+
/** Parent session ID (null for root agents) */
|
|
96
|
+
parentSessionId: string | null
|
|
97
|
+
/** Delegation job ID that spawned this subagent */
|
|
98
|
+
jobId: string | null
|
|
99
|
+
/** Nesting depth (0 = root, 1 = first-level subagent, etc.) */
|
|
100
|
+
depth: number
|
|
101
|
+
/** Task/message that was delegated */
|
|
102
|
+
task: string
|
|
103
|
+
/** Working directory */
|
|
104
|
+
cwd: string | null
|
|
105
|
+
/** Timestamps */
|
|
106
|
+
createdAt: number
|
|
107
|
+
completedAt: number | null
|
|
108
|
+
/** Lifecycle state — single source of truth for execution status */
|
|
109
|
+
status: SubagentState
|
|
110
|
+
/** Result summary (truncated) */
|
|
111
|
+
resultPreview: string | null
|
|
112
|
+
/** Error message if failed */
|
|
113
|
+
error: string | null
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface LineageTree {
|
|
117
|
+
node: LineageNode
|
|
118
|
+
children: LineageTree[]
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export interface LineageQuery {
|
|
122
|
+
sessionId?: string
|
|
123
|
+
agentId?: string
|
|
124
|
+
parentId?: string | null
|
|
125
|
+
status?: SubagentState
|
|
126
|
+
minDepth?: number
|
|
127
|
+
maxDepth?: number
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// Storage (globalThis-scoped, HMR-safe)
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
const store = hmrSingleton('__swarmclaw_subagent_lineage__', () => new Map<string, LineageNode>())
|
|
135
|
+
|
|
136
|
+
// Session → lineage node index for fast lookup
|
|
137
|
+
const sessionIndex = hmrSingleton('__swarmclaw_lineage_session_idx__', () => new Map<string, string>())
|
|
138
|
+
|
|
139
|
+
// Debounced notification — collapses rapid-fire updates into one per microtask
|
|
140
|
+
let notifyPending = false
|
|
141
|
+
function notifyLineageChanged() {
|
|
142
|
+
if (notifyPending) return
|
|
143
|
+
notifyPending = true
|
|
144
|
+
queueMicrotask(() => {
|
|
145
|
+
notifyPending = false
|
|
146
|
+
notify('delegation_jobs')
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
// Lifecycle Transitions
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Transition a lineage node's lifecycle state. Returns the new state,
|
|
156
|
+
* or null if the transition is invalid or the node doesn't exist.
|
|
157
|
+
*/
|
|
158
|
+
export function transitionState(nodeId: string, event: SubagentEvent): SubagentState | null {
|
|
159
|
+
const node = store.get(nodeId)
|
|
160
|
+
if (!node) return null
|
|
161
|
+
const next = resolveTransition(node.status, event)
|
|
162
|
+
if (!next) return null
|
|
163
|
+
store.set(nodeId, { ...node, status: next })
|
|
164
|
+
notifyLineageChanged()
|
|
165
|
+
return next
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
// Core CRUD
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
export interface CreateLineageNodeInput {
|
|
173
|
+
sessionId: string
|
|
174
|
+
agentId: string
|
|
175
|
+
agentName: string
|
|
176
|
+
parentSessionId?: string | null
|
|
177
|
+
jobId?: string | null
|
|
178
|
+
task: string
|
|
179
|
+
cwd?: string | null
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function createLineageNode(input: CreateLineageNodeInput): LineageNode {
|
|
183
|
+
const parentNodeId = input.parentSessionId
|
|
184
|
+
? sessionIndex.get(input.parentSessionId) ?? null
|
|
185
|
+
: null
|
|
186
|
+
const parentNode = parentNodeId ? store.get(parentNodeId) ?? null : null
|
|
187
|
+
const depth = parentNode ? parentNode.depth + 1 : 0
|
|
188
|
+
|
|
189
|
+
const node: LineageNode = {
|
|
190
|
+
id: genId(10),
|
|
191
|
+
sessionId: input.sessionId,
|
|
192
|
+
agentId: input.agentId,
|
|
193
|
+
agentName: input.agentName,
|
|
194
|
+
parentId: parentNodeId,
|
|
195
|
+
parentSessionId: input.parentSessionId ?? null,
|
|
196
|
+
jobId: input.jobId ?? null,
|
|
197
|
+
depth,
|
|
198
|
+
task: input.task,
|
|
199
|
+
cwd: input.cwd ?? null,
|
|
200
|
+
createdAt: Date.now(),
|
|
201
|
+
completedAt: null,
|
|
202
|
+
status: 'initializing',
|
|
203
|
+
resultPreview: null,
|
|
204
|
+
error: null,
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
store.set(node.id, node)
|
|
208
|
+
sessionIndex.set(node.sessionId, node.id)
|
|
209
|
+
notifyLineageChanged()
|
|
210
|
+
return node
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function getLineageNode(id: string): LineageNode | null {
|
|
214
|
+
return store.get(id) ?? null
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function getLineageNodeBySession(sessionId: string): LineageNode | null {
|
|
218
|
+
const nodeId = sessionIndex.get(sessionId)
|
|
219
|
+
return nodeId ? store.get(nodeId) ?? null : null
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function updateLineageNode(
|
|
223
|
+
id: string,
|
|
224
|
+
patch: Partial<Pick<LineageNode, 'completedAt' | 'resultPreview' | 'error'>>,
|
|
225
|
+
): LineageNode | null {
|
|
226
|
+
const current = store.get(id)
|
|
227
|
+
if (!current) return null
|
|
228
|
+
const updated = { ...current, ...patch }
|
|
229
|
+
store.set(id, updated)
|
|
230
|
+
notifyLineageChanged()
|
|
231
|
+
return updated
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function completeLineageNode(id: string, resultPreview: string | null): LineageNode | null {
|
|
235
|
+
const node = store.get(id)
|
|
236
|
+
if (!node) return null
|
|
237
|
+
if (isTerminalState(node.status)) return node
|
|
238
|
+
const next = resolveTransition(node.status, 'COMPLETE')
|
|
239
|
+
if (!next) return null
|
|
240
|
+
const updated = { ...node, status: next, completedAt: Date.now(), resultPreview }
|
|
241
|
+
store.set(id, updated)
|
|
242
|
+
notifyLineageChanged()
|
|
243
|
+
return updated
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function failLineageNode(id: string, error: string): LineageNode | null {
|
|
247
|
+
const node = store.get(id)
|
|
248
|
+
if (!node) return null
|
|
249
|
+
if (isTerminalState(node.status)) return node
|
|
250
|
+
const next = resolveTransition(node.status, 'FAIL')
|
|
251
|
+
if (!next) return null
|
|
252
|
+
const updated = { ...node, status: next, completedAt: Date.now(), error }
|
|
253
|
+
store.set(id, updated)
|
|
254
|
+
notifyLineageChanged()
|
|
255
|
+
return updated
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function cancelLineageNode(id: string): LineageNode | null {
|
|
259
|
+
const node = store.get(id)
|
|
260
|
+
if (!node) return null
|
|
261
|
+
if (isTerminalState(node.status)) return node
|
|
262
|
+
const next = resolveTransition(node.status, 'CANCEL')
|
|
263
|
+
if (!next) return null
|
|
264
|
+
const updated = { ...node, status: next, completedAt: Date.now() }
|
|
265
|
+
store.set(id, updated)
|
|
266
|
+
notifyLineageChanged()
|
|
267
|
+
return updated
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ---------------------------------------------------------------------------
|
|
271
|
+
// Queries
|
|
272
|
+
// ---------------------------------------------------------------------------
|
|
273
|
+
|
|
274
|
+
export function listLineageNodes(query?: LineageQuery): LineageNode[] {
|
|
275
|
+
let nodes = Array.from(store.values())
|
|
276
|
+
|
|
277
|
+
if (query?.sessionId) {
|
|
278
|
+
nodes = nodes.filter((n) => n.sessionId === query.sessionId)
|
|
279
|
+
}
|
|
280
|
+
if (query?.agentId) {
|
|
281
|
+
nodes = nodes.filter((n) => n.agentId === query.agentId)
|
|
282
|
+
}
|
|
283
|
+
if (query?.parentId !== undefined) {
|
|
284
|
+
nodes = nodes.filter((n) => n.parentId === query.parentId)
|
|
285
|
+
}
|
|
286
|
+
if (query?.status) {
|
|
287
|
+
nodes = nodes.filter((n) => n.status === query.status)
|
|
288
|
+
}
|
|
289
|
+
if (query?.minDepth !== undefined) {
|
|
290
|
+
nodes = nodes.filter((n) => n.depth >= query.minDepth!)
|
|
291
|
+
}
|
|
292
|
+
if (query?.maxDepth !== undefined) {
|
|
293
|
+
nodes = nodes.filter((n) => n.depth <= query.maxDepth!)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return nodes.sort((a, b) => a.createdAt - b.createdAt)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** Get all ancestors of a node, from immediate parent to root */
|
|
300
|
+
export function getAncestors(nodeId: string): LineageNode[] {
|
|
301
|
+
const ancestors: LineageNode[] = []
|
|
302
|
+
let currentId: string | null = nodeId
|
|
303
|
+
const visited = new Set<string>()
|
|
304
|
+
|
|
305
|
+
while (currentId && !visited.has(currentId)) {
|
|
306
|
+
visited.add(currentId)
|
|
307
|
+
const node = store.get(currentId)
|
|
308
|
+
if (!node?.parentId) break
|
|
309
|
+
const parent = store.get(node.parentId)
|
|
310
|
+
if (!parent) break
|
|
311
|
+
ancestors.push(parent)
|
|
312
|
+
currentId = parent.id
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return ancestors
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** Get direct children of a node */
|
|
319
|
+
export function getChildren(nodeId: string): LineageNode[] {
|
|
320
|
+
return Array.from(store.values())
|
|
321
|
+
.filter((n) => n.parentId === nodeId)
|
|
322
|
+
.sort((a, b) => a.createdAt - b.createdAt)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** Get all descendants of a node (breadth-first) */
|
|
326
|
+
export function getDescendants(nodeId: string): LineageNode[] {
|
|
327
|
+
const descendants: LineageNode[] = []
|
|
328
|
+
const queue = [nodeId]
|
|
329
|
+
const visited = new Set<string>()
|
|
330
|
+
|
|
331
|
+
while (queue.length > 0) {
|
|
332
|
+
const currentId = queue.shift()!
|
|
333
|
+
if (visited.has(currentId)) continue
|
|
334
|
+
visited.add(currentId)
|
|
335
|
+
|
|
336
|
+
const children = getChildren(currentId)
|
|
337
|
+
for (const child of children) {
|
|
338
|
+
descendants.push(child)
|
|
339
|
+
queue.push(child.id)
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return descendants
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** Get siblings (other children of the same parent) */
|
|
347
|
+
export function getSiblings(nodeId: string): LineageNode[] {
|
|
348
|
+
const node = store.get(nodeId)
|
|
349
|
+
if (!node?.parentId) return []
|
|
350
|
+
return getChildren(node.parentId).filter((n) => n.id !== nodeId)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/** Build a full lineage tree starting from a node */
|
|
354
|
+
export function buildLineageTree(nodeId: string): LineageTree | null {
|
|
355
|
+
const node = store.get(nodeId)
|
|
356
|
+
if (!node) return null
|
|
357
|
+
|
|
358
|
+
const children = getChildren(nodeId)
|
|
359
|
+
.map((child) => buildLineageTree(child.id))
|
|
360
|
+
.filter((tree): tree is LineageTree => tree !== null)
|
|
361
|
+
|
|
362
|
+
return { node, children }
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/** Find all root nodes (nodes with no parent) */
|
|
366
|
+
export function getRootNodes(): LineageNode[] {
|
|
367
|
+
return Array.from(store.values())
|
|
368
|
+
.filter((n) => n.parentId === null)
|
|
369
|
+
.sort((a, b) => a.createdAt - b.createdAt)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Get the root ancestor of a node */
|
|
373
|
+
export function getRootAncestor(nodeId: string): LineageNode | null {
|
|
374
|
+
const ancestors = getAncestors(nodeId)
|
|
375
|
+
return ancestors.length > 0 ? ancestors[ancestors.length - 1] : store.get(nodeId) ?? null
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/** Get the depth of the deepest descendant */
|
|
379
|
+
export function getMaxDepth(nodeId: string): number {
|
|
380
|
+
const descendants = getDescendants(nodeId)
|
|
381
|
+
if (descendants.length === 0) {
|
|
382
|
+
const node = store.get(nodeId)
|
|
383
|
+
return node?.depth ?? 0
|
|
384
|
+
}
|
|
385
|
+
return Math.max(...descendants.map((d) => d.depth))
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** Cancel a node and all its active descendants */
|
|
389
|
+
export function cancelSubtree(nodeId: string): number {
|
|
390
|
+
let cancelled = 0
|
|
391
|
+
const node = store.get(nodeId)
|
|
392
|
+
if (node && !isTerminalState(node.status)) {
|
|
393
|
+
cancelLineageNode(nodeId)
|
|
394
|
+
cancelled++
|
|
395
|
+
}
|
|
396
|
+
for (const desc of getDescendants(nodeId)) {
|
|
397
|
+
if (!isTerminalState(desc.status)) {
|
|
398
|
+
cancelLineageNode(desc.id)
|
|
399
|
+
cancelled++
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return cancelled
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// ---------------------------------------------------------------------------
|
|
406
|
+
// Cleanup
|
|
407
|
+
// ---------------------------------------------------------------------------
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Remove terminal lineage nodes older than maxAgeMs.
|
|
411
|
+
* Returns the IDs of removed nodes so callers can clean up related resources.
|
|
412
|
+
*/
|
|
413
|
+
export function cleanupTerminalNodes(maxAgeMs = 30 * 60_000): string[] {
|
|
414
|
+
const threshold = Date.now() - maxAgeMs
|
|
415
|
+
const removed: string[] = []
|
|
416
|
+
for (const [id, node] of store.entries()) {
|
|
417
|
+
if (!isTerminalState(node.status)) continue
|
|
418
|
+
if (node.completedAt && node.completedAt < threshold) {
|
|
419
|
+
store.delete(id)
|
|
420
|
+
sessionIndex.delete(node.sessionId)
|
|
421
|
+
removed.push(id)
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return removed
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// ---------------------------------------------------------------------------
|
|
428
|
+
// Testing utilities
|
|
429
|
+
// ---------------------------------------------------------------------------
|
|
430
|
+
|
|
431
|
+
/** Clear all lineage data (for tests only) */
|
|
432
|
+
export function _clearLineage(): void {
|
|
433
|
+
store.clear()
|
|
434
|
+
sessionIndex.clear()
|
|
435
|
+
}
|