@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
|
@@ -21,8 +21,7 @@ import {
|
|
|
21
21
|
decryptKey,
|
|
22
22
|
} from '../storage'
|
|
23
23
|
import { resolveScheduleName } from '@/lib/schedule-name'
|
|
24
|
-
import {
|
|
25
|
-
import { computeTaskFingerprint, findDuplicateTask } from '@/lib/task-dedupe'
|
|
24
|
+
import type { ScheduleLike } from '@/lib/schedule-dedupe'
|
|
26
25
|
import {
|
|
27
26
|
hasManagedAgentAssignmentInput,
|
|
28
27
|
isDelegationTaskPayload,
|
|
@@ -30,13 +29,23 @@ import {
|
|
|
30
29
|
resolveManagedAgentAssignment,
|
|
31
30
|
validateManagedAgentAssignment,
|
|
32
31
|
} from '@/lib/server/agent-assignment'
|
|
33
|
-
import { normalizeTaskQualityGate } from '@/lib/server/task-quality-gate'
|
|
34
|
-
import { normalizeSchedulePayload } from '@/lib/server/schedule-normalization'
|
|
35
32
|
import { buildProjectSnapshot, ensureProjectWorkspace, normalizeProjectCreateInput, normalizeProjectPatchInput } from '@/lib/server/project-utils'
|
|
33
|
+
import {
|
|
34
|
+
getScheduleClusterIds,
|
|
35
|
+
prepareScheduleCreate,
|
|
36
|
+
prepareScheduleUpdate,
|
|
37
|
+
} from '@/lib/server/schedule-service'
|
|
38
|
+
import {
|
|
39
|
+
applyTaskContinuationDefaults,
|
|
40
|
+
applyTaskPatch,
|
|
41
|
+
deriveTaskTitle,
|
|
42
|
+
prepareTaskCreation,
|
|
43
|
+
} from '@/lib/server/task-service'
|
|
36
44
|
import type { ToolBuildContext } from './context'
|
|
37
45
|
import { safePath, findBinaryOnPath } from './context'
|
|
38
46
|
import { normalizeToolInputArgs } from './normalize-tool-args'
|
|
39
47
|
import type { BoardTask } from '@/types'
|
|
48
|
+
import { dedup } from '@/lib/shared-utils'
|
|
40
49
|
|
|
41
50
|
// ---------------------------------------------------------------------------
|
|
42
51
|
// Document helpers
|
|
@@ -67,7 +76,7 @@ function extractDocumentText(filePath: string): { text: string; method: string }
|
|
|
67
76
|
return { text: out.stdout || '', method: 'pdftotext' }
|
|
68
77
|
}
|
|
69
78
|
|
|
70
|
-
if (['.txt', '.md', '.markdown', '.json', '.csv', '
|
|
79
|
+
if (['.txt', '.md', '.markdown', '.json', '.csv', '', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.py', '.go', '.rs', '.java', '.yaml', '.yml'].includes(ext)) {
|
|
71
80
|
return { text: readUtf8Text(), method: 'utf8' }
|
|
72
81
|
}
|
|
73
82
|
|
|
@@ -100,24 +109,6 @@ function trimDocumentContent(text: string): string {
|
|
|
100
109
|
return normalized.slice(0, MAX_DOCUMENT_TEXT_CHARS)
|
|
101
110
|
}
|
|
102
111
|
|
|
103
|
-
function deriveTaskTitle(input: { title?: unknown; description?: unknown }): string {
|
|
104
|
-
const explicit = typeof input.title === 'string' ? input.title.replace(/\s+/g, ' ').trim() : ''
|
|
105
|
-
if (explicit && !/^untitled task$/i.test(explicit)) return explicit.slice(0, 120)
|
|
106
|
-
|
|
107
|
-
const description = typeof input.description === 'string'
|
|
108
|
-
? input.description.replace(/\s+/g, ' ').trim()
|
|
109
|
-
: ''
|
|
110
|
-
if (!description) return ''
|
|
111
|
-
|
|
112
|
-
const firstSentence = description.split(/[.!?]\s+/)[0] || description
|
|
113
|
-
const compact = firstSentence
|
|
114
|
-
.replace(/^please\s+/i, '')
|
|
115
|
-
.replace(/^(create|make|build|implement|write)\s+/i, '')
|
|
116
|
-
.trim()
|
|
117
|
-
if (!compact) return ''
|
|
118
|
-
return compact.slice(0, 120)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
112
|
function validateAgentSoulPayload(value: unknown): string | null {
|
|
122
113
|
if (value === undefined) return null
|
|
123
114
|
if (typeof value === 'string') return null
|
|
@@ -235,60 +226,6 @@ function sanitizeConnectorCrudPayload(
|
|
|
235
226
|
return out
|
|
236
227
|
}
|
|
237
228
|
|
|
238
|
-
const TASK_STATUS_VALUES = new Set([
|
|
239
|
-
'backlog',
|
|
240
|
-
'queued',
|
|
241
|
-
'running',
|
|
242
|
-
'completed',
|
|
243
|
-
'failed',
|
|
244
|
-
'archived',
|
|
245
|
-
])
|
|
246
|
-
|
|
247
|
-
function normalizeTaskStatusInput(status: unknown, prevStatus?: string): string | null {
|
|
248
|
-
if (typeof status !== 'string') return null
|
|
249
|
-
const normalized = status.trim().toLowerCase()
|
|
250
|
-
if (!TASK_STATUS_VALUES.has(normalized)) return null
|
|
251
|
-
if (normalized === 'running' && prevStatus !== 'running') return 'queued'
|
|
252
|
-
return normalized
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
function normalizeTaskIdList(value: unknown): string[] {
|
|
256
|
-
const rawValues = Array.isArray(value)
|
|
257
|
-
? value
|
|
258
|
-
: typeof value === 'string'
|
|
259
|
-
? value.split(',')
|
|
260
|
-
: []
|
|
261
|
-
const seen = new Set<string>()
|
|
262
|
-
const out: string[] = []
|
|
263
|
-
for (const entry of rawValues) {
|
|
264
|
-
const normalized = typeof entry === 'string' ? entry.trim() : ''
|
|
265
|
-
if (!normalized || seen.has(normalized)) continue
|
|
266
|
-
seen.add(normalized)
|
|
267
|
-
out.push(normalized)
|
|
268
|
-
}
|
|
269
|
-
return out
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function pickFirstTaskId(value: unknown): string | null {
|
|
273
|
-
const ids = normalizeTaskIdList(value)
|
|
274
|
-
return ids[0] || null
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function buildScheduleCreatorScope(schedule: Record<string, unknown> | null | undefined): {
|
|
278
|
-
agentId?: string | null
|
|
279
|
-
sessionId?: string | null
|
|
280
|
-
} | null {
|
|
281
|
-
if (!schedule || typeof schedule !== 'object') return null
|
|
282
|
-
const agentId = typeof schedule.createdByAgentId === 'string' && schedule.createdByAgentId.trim()
|
|
283
|
-
? schedule.createdByAgentId.trim()
|
|
284
|
-
: null
|
|
285
|
-
const sessionId = typeof schedule.createdInSessionId === 'string' && schedule.createdInSessionId.trim()
|
|
286
|
-
? schedule.createdInSessionId.trim()
|
|
287
|
-
: null
|
|
288
|
-
if (!agentId && !sessionId) return null
|
|
289
|
-
return { agentId, sessionId }
|
|
290
|
-
}
|
|
291
|
-
|
|
292
229
|
function deriveScheduleFollowupTarget(sessionId: string | null | undefined): {
|
|
293
230
|
followupConnectorId?: string | null
|
|
294
231
|
followupChannelId?: string | null
|
|
@@ -336,103 +273,6 @@ function deriveScheduleFollowupTarget(sessionId: string | null | undefined): {
|
|
|
336
273
|
return {}
|
|
337
274
|
}
|
|
338
275
|
|
|
339
|
-
function findRelatedScheduleIds(
|
|
340
|
-
schedules: Record<string, ScheduleLike>,
|
|
341
|
-
schedule: Record<string, unknown> | null | undefined,
|
|
342
|
-
opts: { ignoreId?: string | null } = {},
|
|
343
|
-
): string[] {
|
|
344
|
-
if (!schedule || typeof schedule !== 'object') return []
|
|
345
|
-
const scope = buildScheduleCreatorScope(schedule)
|
|
346
|
-
if (!scope?.sessionId) return []
|
|
347
|
-
const matches = findEquivalentSchedules(schedules, {
|
|
348
|
-
id: typeof schedule.id === 'string' ? schedule.id : null,
|
|
349
|
-
agentId: typeof schedule.agentId === 'string' ? schedule.agentId : null,
|
|
350
|
-
taskPrompt: typeof schedule.taskPrompt === 'string' ? schedule.taskPrompt : null,
|
|
351
|
-
scheduleType: typeof schedule.scheduleType === 'string' ? schedule.scheduleType : null,
|
|
352
|
-
cron: typeof schedule.cron === 'string' ? schedule.cron : null,
|
|
353
|
-
intervalMs: typeof schedule.intervalMs === 'number' ? schedule.intervalMs : null,
|
|
354
|
-
runAt: typeof schedule.runAt === 'number' ? schedule.runAt : null,
|
|
355
|
-
createdByAgentId: scope.agentId,
|
|
356
|
-
createdInSessionId: scope.sessionId,
|
|
357
|
-
}, {
|
|
358
|
-
ignoreId: opts.ignoreId || (typeof schedule.id === 'string' ? schedule.id : null),
|
|
359
|
-
creatorScope: scope,
|
|
360
|
-
})
|
|
361
|
-
return Array.from(new Set(matches
|
|
362
|
-
.map((entry) => (typeof entry.id === 'string' ? entry.id : ''))
|
|
363
|
-
.filter(Boolean)))
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
function applyTaskContinuationDefaults(
|
|
367
|
-
parsed: Record<string, unknown>,
|
|
368
|
-
tasks: Record<string, BoardTask>,
|
|
369
|
-
explicitInput?: Record<string, unknown>,
|
|
370
|
-
): string | null {
|
|
371
|
-
const explicit = explicitInput || parsed
|
|
372
|
-
const continuationTaskId = pickFirstTaskId(parsed.continueFromTaskId)
|
|
373
|
-
|| pickFirstTaskId(parsed.followUpToTaskId)
|
|
374
|
-
|| pickFirstTaskId(parsed.resumeFromTaskId)
|
|
375
|
-
const blockedBy = [
|
|
376
|
-
...normalizeTaskIdList(parsed.blockedBy),
|
|
377
|
-
...normalizeTaskIdList(parsed.dependsOn),
|
|
378
|
-
...normalizeTaskIdList(parsed.dependsOnTaskIds),
|
|
379
|
-
...normalizeTaskIdList(parsed.prerequisiteTaskIds),
|
|
380
|
-
]
|
|
381
|
-
if (continuationTaskId && !blockedBy.includes(continuationTaskId)) {
|
|
382
|
-
blockedBy.unshift(continuationTaskId)
|
|
383
|
-
}
|
|
384
|
-
if (blockedBy.length > 0) parsed.blockedBy = blockedBy
|
|
385
|
-
|
|
386
|
-
if (continuationTaskId) {
|
|
387
|
-
const sourceTask = tasks[continuationTaskId]
|
|
388
|
-
if (!sourceTask) return `Error: source task "${continuationTaskId}" not found.`
|
|
389
|
-
|
|
390
|
-
if (!Object.prototype.hasOwnProperty.call(explicit, 'projectId') && typeof sourceTask.projectId === 'string' && sourceTask.projectId.trim()) {
|
|
391
|
-
parsed.projectId = sourceTask.projectId.trim()
|
|
392
|
-
}
|
|
393
|
-
if (
|
|
394
|
-
!Object.prototype.hasOwnProperty.call(explicit, 'agentId')
|
|
395
|
-
&& !hasManagedAgentAssignmentInput(explicit)
|
|
396
|
-
&& typeof sourceTask.agentId === 'string'
|
|
397
|
-
&& sourceTask.agentId.trim()
|
|
398
|
-
) {
|
|
399
|
-
parsed.agentId = sourceTask.agentId.trim()
|
|
400
|
-
}
|
|
401
|
-
if (!Object.prototype.hasOwnProperty.call(explicit, 'cwd') && typeof sourceTask.cwd === 'string' && sourceTask.cwd.trim()) {
|
|
402
|
-
parsed.cwd = sourceTask.cwd.trim()
|
|
403
|
-
}
|
|
404
|
-
const sourceSessionId = typeof sourceTask.checkpoint?.lastSessionId === 'string' && sourceTask.checkpoint.lastSessionId.trim()
|
|
405
|
-
? sourceTask.checkpoint.lastSessionId.trim()
|
|
406
|
-
: typeof sourceTask.sessionId === 'string' && sourceTask.sessionId.trim()
|
|
407
|
-
? sourceTask.sessionId.trim()
|
|
408
|
-
: ''
|
|
409
|
-
if (!Object.prototype.hasOwnProperty.call(explicit, 'sessionId') && sourceSessionId) {
|
|
410
|
-
parsed.sessionId = sourceSessionId
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
const resumeFieldMap: Array<[keyof BoardTask, string]> = [
|
|
414
|
-
['cliResumeId', 'cliResumeId'],
|
|
415
|
-
['cliProvider', 'cliProvider'],
|
|
416
|
-
['claudeResumeId', 'claudeResumeId'],
|
|
417
|
-
['codexResumeId', 'codexResumeId'],
|
|
418
|
-
['opencodeResumeId', 'opencodeResumeId'],
|
|
419
|
-
['geminiResumeId', 'geminiResumeId'],
|
|
420
|
-
]
|
|
421
|
-
for (const [sourceKey, targetKey] of resumeFieldMap) {
|
|
422
|
-
const value = sourceTask[sourceKey]
|
|
423
|
-
if (Object.prototype.hasOwnProperty.call(explicit, targetKey)) continue
|
|
424
|
-
if (typeof value === 'string' && value.trim()) {
|
|
425
|
-
parsed[targetKey] = value.trim()
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
for (const aliasKey of ['continueFromTaskId', 'followUpToTaskId', 'resumeFromTaskId', 'dependsOn', 'dependsOnTaskIds', 'prerequisiteTaskIds']) {
|
|
431
|
-
delete parsed[aliasKey]
|
|
432
|
-
}
|
|
433
|
-
return null
|
|
434
|
-
}
|
|
435
|
-
|
|
436
276
|
// ---------------------------------------------------------------------------
|
|
437
277
|
// RESOURCE_DEFAULTS
|
|
438
278
|
// ---------------------------------------------------------------------------
|
|
@@ -722,68 +562,55 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
722
562
|
if (assignmentError) return assignmentError
|
|
723
563
|
parsed.agentId = resolution.agentId
|
|
724
564
|
}
|
|
565
|
+
let preparedManagedTask: BoardTask | null = null
|
|
566
|
+
let preparedManagedSchedule: any = null
|
|
725
567
|
if (toolKey === 'manage_schedules') {
|
|
726
|
-
const
|
|
727
|
-
|
|
568
|
+
const prepared = prepareScheduleCreate({
|
|
569
|
+
input: parsed as Record<string, unknown>,
|
|
570
|
+
schedules: all as Record<string, ScheduleLike>,
|
|
728
571
|
now,
|
|
729
|
-
|
|
730
|
-
if (!normalizedSchedule.ok) return normalizedSchedule.error
|
|
731
|
-
Object.assign(parsed, normalizedSchedule.value)
|
|
732
|
-
const duplicate = findDuplicateSchedule(all as Record<string, ScheduleLike>, {
|
|
733
|
-
agentId: parsed.agentId || null,
|
|
734
|
-
taskPrompt: parsed.taskPrompt || '',
|
|
735
|
-
scheduleType: parsed.scheduleType || 'interval',
|
|
736
|
-
cron: parsed.cron,
|
|
737
|
-
intervalMs: parsed.intervalMs,
|
|
738
|
-
runAt: parsed.runAt,
|
|
739
|
-
createdByAgentId: ctx?.agentId || null,
|
|
740
|
-
createdInSessionId: ctx?.sessionId || null,
|
|
741
|
-
}, {
|
|
572
|
+
cwd,
|
|
742
573
|
creatorScope: {
|
|
743
574
|
agentId: ctx?.agentId || null,
|
|
744
575
|
sessionId: ctx?.sessionId || null,
|
|
745
576
|
},
|
|
577
|
+
dedupeCreatorScope: {
|
|
578
|
+
agentId: ctx?.agentId || null,
|
|
579
|
+
sessionId: ctx?.sessionId || null,
|
|
580
|
+
},
|
|
581
|
+
followupTarget: deriveScheduleFollowupTarget(ctx?.sessionId || null),
|
|
746
582
|
})
|
|
747
|
-
if (
|
|
748
|
-
|
|
749
|
-
const duplicateId
|
|
750
|
-
|
|
751
|
-
name: parsed.name ?? duplicate.name,
|
|
752
|
-
taskPrompt: parsed.taskPrompt ?? duplicate.taskPrompt,
|
|
753
|
-
})
|
|
754
|
-
if (nextName && nextName !== duplicate.name) {
|
|
755
|
-
duplicate.name = nextName
|
|
756
|
-
changed = true
|
|
757
|
-
}
|
|
758
|
-
const normalizedStatus = typeof parsed.status === 'string' ? parsed.status.trim().toLowerCase() : ''
|
|
759
|
-
if ((normalizedStatus === 'active' || normalizedStatus === 'paused') && duplicate.status !== normalizedStatus) {
|
|
760
|
-
duplicate.status = normalizedStatus
|
|
761
|
-
changed = true
|
|
762
|
-
}
|
|
763
|
-
if (changed) {
|
|
764
|
-
duplicate.updatedAt = now
|
|
765
|
-
if (duplicateId) all[duplicateId] = duplicate
|
|
766
|
-
res.save(all)
|
|
583
|
+
if (!prepared.ok) return prepared.error
|
|
584
|
+
if (prepared.kind === 'duplicate') {
|
|
585
|
+
for (const [duplicateId, schedule] of prepared.entries) {
|
|
586
|
+
all[duplicateId] = schedule
|
|
767
587
|
}
|
|
588
|
+
if (prepared.entries.length > 0) res.save(all)
|
|
768
589
|
return JSON.stringify({
|
|
769
|
-
...
|
|
590
|
+
...prepared.schedule,
|
|
770
591
|
deduplicated: true,
|
|
771
592
|
})
|
|
772
593
|
}
|
|
594
|
+
preparedManagedSchedule = prepared.schedule
|
|
773
595
|
}
|
|
774
596
|
if (toolKey === 'manage_tasks') {
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
597
|
+
const prepared = prepareTaskCreation({
|
|
598
|
+
id: genId(),
|
|
599
|
+
input: parsed as Record<string, unknown>,
|
|
600
|
+
tasks: all as Record<string, BoardTask>,
|
|
601
|
+
now,
|
|
602
|
+
settings: loadSettings(),
|
|
603
|
+
fallbackAgentId: ctx?.agentId || null,
|
|
604
|
+
defaultCwd: cwd,
|
|
605
|
+
deriveTitleFromDescription: true,
|
|
606
|
+
requireMeaningfulTitle: true,
|
|
607
|
+
seed: parsed as Record<string, unknown>,
|
|
608
|
+
})
|
|
609
|
+
if (!prepared.ok) return prepared.error
|
|
610
|
+
if (prepared.duplicate) {
|
|
611
|
+
return JSON.stringify({ ...prepared.duplicate, deduplicated: true })
|
|
786
612
|
}
|
|
613
|
+
preparedManagedTask = prepared.task
|
|
787
614
|
}
|
|
788
615
|
if (toolKey === 'manage_agents' && Object.prototype.hasOwnProperty.call(parsed, 'soul')) {
|
|
789
616
|
const soulError = validateAgentSoulPayload((parsed as Record<string, unknown>).soul)
|
|
@@ -795,38 +622,33 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
795
622
|
return JSON.stringify({ ...duplicateAgent, deduplicated: true })
|
|
796
623
|
}
|
|
797
624
|
}
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
createdInSessionId: ctx?.sessionId || null,
|
|
816
|
-
...scheduleFollowupTarget,
|
|
817
|
-
createdAt: now,
|
|
818
|
-
updatedAt: now,
|
|
819
|
-
}
|
|
625
|
+
const newId = preparedManagedTask?.id || preparedManagedSchedule?.id || genId()
|
|
626
|
+
const entry = toolKey === 'manage_tasks' && preparedManagedTask
|
|
627
|
+
? {
|
|
628
|
+
...preparedManagedTask,
|
|
629
|
+
createdByAgentId: ctx?.agentId || null,
|
|
630
|
+
createdInSessionId: ctx?.sessionId || null,
|
|
631
|
+
}
|
|
632
|
+
: toolKey === 'manage_schedules' && preparedManagedSchedule
|
|
633
|
+
? preparedManagedSchedule
|
|
634
|
+
: {
|
|
635
|
+
id: newId,
|
|
636
|
+
...parsed,
|
|
637
|
+
createdByAgentId: ctx?.agentId || null,
|
|
638
|
+
createdInSessionId: ctx?.sessionId || null,
|
|
639
|
+
createdAt: now,
|
|
640
|
+
updatedAt: now,
|
|
641
|
+
}
|
|
820
642
|
let responseEntry: unknown = entry
|
|
821
643
|
if (toolKey === 'manage_secrets') {
|
|
822
644
|
const secretValue = typeof parsed.value === 'string' ? parsed.value : null
|
|
823
645
|
if (!secretValue) return 'Error: data.value is required to create a secret.'
|
|
824
646
|
const normalizedScope = parsed.scope === 'agent' ? 'agent' : 'global'
|
|
825
647
|
const normalizedAgentIds = normalizedScope === 'agent'
|
|
826
|
-
?
|
|
827
|
-
...(Array.isArray(parsed.agentIds) ? parsed.agentIds.filter((x:
|
|
648
|
+
? dedup([
|
|
649
|
+
...(Array.isArray(parsed.agentIds) ? parsed.agentIds.filter((x: unknown) => typeof x === 'string') as string[] : []),
|
|
828
650
|
...(ctx?.agentId ? [ctx.agentId] : []),
|
|
829
|
-
])
|
|
651
|
+
])
|
|
830
652
|
: []
|
|
831
653
|
const stored = {
|
|
832
654
|
...entry,
|
|
@@ -847,21 +669,6 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
847
669
|
all[newId] = entry
|
|
848
670
|
}
|
|
849
671
|
|
|
850
|
-
if (toolKey === 'manage_tasks' && entry.status === 'completed') {
|
|
851
|
-
const { formatValidationFailure, validateTaskCompletion } = await import('../task-validation')
|
|
852
|
-
const { ensureTaskCompletionReport } = await import('../task-reports')
|
|
853
|
-
const settings = loadSettings()
|
|
854
|
-
const report = ensureTaskCompletionReport(entry as any)
|
|
855
|
-
if (report?.relativePath) (entry as any).completionReportPath = report.relativePath
|
|
856
|
-
const validation = validateTaskCompletion(entry as any, { report, settings })
|
|
857
|
-
;(entry as any).validation = validation
|
|
858
|
-
if (!validation.ok) {
|
|
859
|
-
entry.status = 'failed'
|
|
860
|
-
;(entry as any).completedAt = null
|
|
861
|
-
;(entry as any).error = formatValidationFailure(validation.reasons).slice(0, 500)
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
|
|
865
672
|
res.save(all)
|
|
866
673
|
if (toolKey === 'manage_tasks' && entry.status === 'queued') {
|
|
867
674
|
const { enqueueTask } = await import('../queue')
|
|
@@ -898,32 +705,23 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
898
705
|
if (continuationError) return continuationError
|
|
899
706
|
}
|
|
900
707
|
const prevStatus = all[effectiveId]?.status
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
}
|
|
906
|
-
if (toolKey === 'manage_tasks' && Object.prototype.hasOwnProperty.call(parsedRecord, 'qualityGate')) {
|
|
907
|
-
const settings = loadSettings()
|
|
908
|
-
parsedRecord.qualityGate = parsedRecord.qualityGate
|
|
909
|
-
? normalizeTaskQualityGate(parsedRecord.qualityGate, settings)
|
|
910
|
-
: null
|
|
911
|
-
}
|
|
912
|
-
if (toolKey === 'manage_tasks' || toolKey === 'manage_schedules') {
|
|
913
|
-
const agents = loadAgents()
|
|
708
|
+
const managedAgents = toolKey === 'manage_tasks' || toolKey === 'manage_schedules'
|
|
709
|
+
? loadAgents()
|
|
710
|
+
: null
|
|
711
|
+
if (managedAgents) {
|
|
914
712
|
const requestedClear = Object.prototype.hasOwnProperty.call(parsedRecord, 'agentId') && parsedRecord.agentId == null
|
|
915
713
|
const shouldResolveAssignment = requestedClear
|
|
916
714
|
|| hasManagedAgentAssignmentInput(parsedRecord)
|
|
917
715
|
if (shouldResolveAssignment) {
|
|
918
716
|
const resolution = resolveManagedAgentAssignment(
|
|
919
717
|
parsedRecord,
|
|
920
|
-
|
|
718
|
+
managedAgents,
|
|
921
719
|
null,
|
|
922
720
|
{ allowDescription: false },
|
|
923
721
|
)
|
|
924
722
|
const assignmentError = validateManagedAgentAssignment({
|
|
925
723
|
resourceLabel: res.label,
|
|
926
|
-
agents,
|
|
724
|
+
agents: managedAgents,
|
|
927
725
|
assignScope,
|
|
928
726
|
currentAgentId: ctx?.agentId || null,
|
|
929
727
|
targetAgentId: requestedClear ? null : resolution.agentId,
|
|
@@ -939,40 +737,40 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
939
737
|
? resolveDelegatorAgentId({
|
|
940
738
|
...all[effectiveId],
|
|
941
739
|
...parsedRecord,
|
|
942
|
-
},
|
|
740
|
+
}, managedAgents, ctx?.agentId || null)
|
|
943
741
|
: null,
|
|
944
742
|
})
|
|
945
743
|
if (assignmentError) return assignmentError
|
|
946
744
|
if (!requestedClear) parsedRecord.agentId = resolution.agentId
|
|
947
745
|
}
|
|
948
746
|
}
|
|
949
|
-
all[effectiveId] = { ...all[effectiveId], ...parsed, updatedAt: Date.now() }
|
|
950
747
|
if (toolKey === 'manage_schedules') {
|
|
951
|
-
const
|
|
952
|
-
|
|
748
|
+
const prepared = prepareScheduleUpdate({
|
|
749
|
+
id: effectiveId,
|
|
750
|
+
current: all[effectiveId] as Record<string, unknown>,
|
|
751
|
+
patch: parsedRecord,
|
|
752
|
+
schedules: all as Record<string, ScheduleLike>,
|
|
953
753
|
now: Date.now(),
|
|
754
|
+
cwd,
|
|
755
|
+
agentExists: (agentId) => Boolean(managedAgents?.[agentId]),
|
|
756
|
+
propagateEquivalentStatuses: true,
|
|
757
|
+
propagationSource: previousEntry as Record<string, unknown>,
|
|
954
758
|
})
|
|
955
|
-
if (!
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
...normalizedSchedule.value,
|
|
959
|
-
updatedAt: Date.now(),
|
|
960
|
-
}
|
|
961
|
-
const nextStatus = typeof all[effectiveId].status === 'string' ? all[effectiveId].status.trim().toLowerCase() : ''
|
|
962
|
-
if (nextStatus === 'paused' || nextStatus === 'completed' || nextStatus === 'failed') {
|
|
963
|
-
const relatedIds = findRelatedScheduleIds(all as Record<string, ScheduleLike>, previousEntry, {
|
|
964
|
-
ignoreId: effectiveId,
|
|
965
|
-
})
|
|
966
|
-
for (const relatedId of relatedIds) {
|
|
967
|
-
if (!all[relatedId]) continue
|
|
968
|
-
all[relatedId] = {
|
|
969
|
-
...all[relatedId],
|
|
970
|
-
status: nextStatus,
|
|
971
|
-
updatedAt: Date.now(),
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
affectedScheduleIds = [effectiveId, ...relatedIds]
|
|
759
|
+
if (!prepared.ok) return prepared.error
|
|
760
|
+
for (const [scheduleId, schedule] of prepared.entries) {
|
|
761
|
+
all[scheduleId] = schedule
|
|
975
762
|
}
|
|
763
|
+
affectedScheduleIds = prepared.affectedScheduleIds.length > 1 ? prepared.affectedScheduleIds : null
|
|
764
|
+
} else if (toolKey === 'manage_tasks') {
|
|
765
|
+
applyTaskPatch({
|
|
766
|
+
task: all[effectiveId] as BoardTask,
|
|
767
|
+
patch: parsedRecord,
|
|
768
|
+
now: Date.now(),
|
|
769
|
+
settings: loadSettings(),
|
|
770
|
+
preserveCompletedAt: true,
|
|
771
|
+
})
|
|
772
|
+
} else {
|
|
773
|
+
all[effectiveId] = { ...all[effectiveId], ...parsed, updatedAt: Date.now() }
|
|
976
774
|
}
|
|
977
775
|
if (toolKey === 'manage_secrets') {
|
|
978
776
|
if (!canAccessSecret(all[effectiveId])) return 'Error: you do not have access to this secret.'
|
|
@@ -987,10 +785,10 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
987
785
|
: Array.isArray(all[effectiveId].agentIds)
|
|
988
786
|
? all[effectiveId].agentIds
|
|
989
787
|
: []
|
|
990
|
-
all[effectiveId].agentIds =
|
|
788
|
+
all[effectiveId].agentIds = dedup([
|
|
991
789
|
...incomingIds,
|
|
992
790
|
...(ctx?.agentId ? [ctx.agentId] : []),
|
|
993
|
-
])
|
|
791
|
+
])
|
|
994
792
|
} else {
|
|
995
793
|
all[effectiveId].agentIds = []
|
|
996
794
|
}
|
|
@@ -1006,23 +804,6 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
1006
804
|
delete all[effectiveId].value
|
|
1007
805
|
}
|
|
1008
806
|
|
|
1009
|
-
if (toolKey === 'manage_tasks' && all[effectiveId].status === 'completed') {
|
|
1010
|
-
const { formatValidationFailure, validateTaskCompletion } = await import('../task-validation')
|
|
1011
|
-
const { ensureTaskCompletionReport } = await import('../task-reports')
|
|
1012
|
-
const settings = loadSettings()
|
|
1013
|
-
const report = ensureTaskCompletionReport(all[effectiveId] as any)
|
|
1014
|
-
if (report?.relativePath) (all[effectiveId] as any).completionReportPath = report.relativePath
|
|
1015
|
-
const validation = validateTaskCompletion(all[effectiveId] as any, { report, settings })
|
|
1016
|
-
;(all[effectiveId] as any).validation = validation
|
|
1017
|
-
if (!validation.ok) {
|
|
1018
|
-
all[effectiveId].status = 'failed'
|
|
1019
|
-
;(all[effectiveId] as any).completedAt = null
|
|
1020
|
-
;(all[effectiveId] as any).error = formatValidationFailure(validation.reasons).slice(0, 500)
|
|
1021
|
-
} else if ((all[effectiveId] as any).completedAt == null) {
|
|
1022
|
-
;(all[effectiveId] as any).completedAt = Date.now()
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
807
|
res.save(all)
|
|
1027
808
|
if (toolKey === 'manage_projects') {
|
|
1028
809
|
ensureProjectWorkspace(effectiveId, all[effectiveId].name)
|
|
@@ -1063,7 +844,7 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
1063
844
|
return 'Error: you do not have access to this secret.'
|
|
1064
845
|
}
|
|
1065
846
|
const deletedIds = toolKey === 'manage_schedules'
|
|
1066
|
-
?
|
|
847
|
+
? getScheduleClusterIds(all as Record<string, ScheduleLike>, all[effectiveId])
|
|
1067
848
|
: [effectiveId]
|
|
1068
849
|
for (const deleteId of deletedIds) {
|
|
1069
850
|
delete all[deleteId]
|
|
@@ -1082,10 +863,10 @@ export function buildCrudTools(bctx: ToolBuildContext): StructuredToolInterface[
|
|
|
1082
863
|
if (changed) save(items)
|
|
1083
864
|
}
|
|
1084
865
|
clearProjectId(loadAgents, saveAgents)
|
|
1085
|
-
clearProjectId(loadTasks, saveTasks)
|
|
1086
|
-
clearProjectId(loadSchedules, saveSchedules)
|
|
1087
|
-
clearProjectId(loadSkills, saveSkills)
|
|
1088
|
-
clearProjectId(loadSecrets, saveSecrets)
|
|
866
|
+
clearProjectId(loadTasks, saveTasks as any)
|
|
867
|
+
clearProjectId(loadSchedules, saveSchedules as any)
|
|
868
|
+
clearProjectId(loadSkills, saveSkills as any)
|
|
869
|
+
clearProjectId(loadSecrets, saveSecrets as any)
|
|
1089
870
|
}
|
|
1090
871
|
return JSON.stringify({
|
|
1091
872
|
deleted: effectiveId,
|
|
@@ -63,7 +63,7 @@ exit 2
|
|
|
63
63
|
describe('delegate fallback', () => {
|
|
64
64
|
it('falls back to another backend when Claude Code is unavailable', () => {
|
|
65
65
|
const output = runWithFakeDelegates(`
|
|
66
|
-
const mod = await import('./src/lib/server/session-tools/delegate
|
|
66
|
+
const mod = await import('./src/lib/server/session-tools/delegate')
|
|
67
67
|
const { buildDelegateTools } = mod.default || mod['module.exports'] || mod
|
|
68
68
|
|
|
69
69
|
const tools = buildDelegateTools({
|
|
@@ -93,7 +93,7 @@ describe('delegate fallback', () => {
|
|
|
93
93
|
|
|
94
94
|
it('accepts wrapped function-call payloads with tool_name aliases', () => {
|
|
95
95
|
const output = runWithFakeDelegates(`
|
|
96
|
-
const mod = await import('./src/lib/server/session-tools/delegate
|
|
96
|
+
const mod = await import('./src/lib/server/session-tools/delegate')
|
|
97
97
|
const { buildDelegateTools } = mod.default || mod['module.exports'] || mod
|
|
98
98
|
|
|
99
99
|
const tools = buildDelegateTools({
|
|
@@ -133,7 +133,7 @@ describe('delegate fallback', () => {
|
|
|
133
133
|
|
|
134
134
|
it('rejects delegating a locally available tool call', () => {
|
|
135
135
|
const output = runWithFakeDelegates(`
|
|
136
|
-
const mod = await import('./src/lib/server/session-tools/delegate
|
|
136
|
+
const mod = await import('./src/lib/server/session-tools/delegate')
|
|
137
137
|
const { buildDelegateTools } = mod.default || mod['module.exports'] || mod
|
|
138
138
|
|
|
139
139
|
const tools = buildDelegateTools({
|
|
@@ -169,7 +169,7 @@ describe('delegate fallback', () => {
|
|
|
169
169
|
|
|
170
170
|
it('synthesizes a delegated task from write-style payloads', () => {
|
|
171
171
|
const output = runWithFakeDelegates(`
|
|
172
|
-
const mod = await import('./src/lib/server/session-tools/delegate
|
|
172
|
+
const mod = await import('./src/lib/server/session-tools/delegate')
|
|
173
173
|
const { buildDelegateTools } = mod.default || mod['module.exports'] || mod
|
|
174
174
|
|
|
175
175
|
const tools = buildDelegateTools({
|
|
@@ -205,7 +205,7 @@ describe('delegate fallback', () => {
|
|
|
205
205
|
|
|
206
206
|
it('synthesizes a delegated task for action=start payloads that only provide files', () => {
|
|
207
207
|
const output = runWithFakeDelegates(`
|
|
208
|
-
const mod = await import('./src/lib/server/session-tools/delegate
|
|
208
|
+
const mod = await import('./src/lib/server/session-tools/delegate')
|
|
209
209
|
const { buildDelegateTools } = mod.default || mod['module.exports'] || mod
|
|
210
210
|
|
|
211
211
|
const tools = buildDelegateTools({
|
|
@@ -244,7 +244,7 @@ describe('delegate fallback', () => {
|
|
|
244
244
|
|
|
245
245
|
it('uses nested data.task payloads from recent tool-call wrappers', () => {
|
|
246
246
|
const output = runWithFakeDelegates(`
|
|
247
|
-
const mod = await import('./src/lib/server/session-tools/delegate
|
|
247
|
+
const mod = await import('./src/lib/server/session-tools/delegate')
|
|
248
248
|
const { buildDelegateTools } = mod.default || mod['module.exports'] || mod
|
|
249
249
|
|
|
250
250
|
const tools = buildDelegateTools({
|
|
@@ -280,7 +280,7 @@ describe('delegate fallback', () => {
|
|
|
280
280
|
|
|
281
281
|
it('falls back to reason text when malformed delegate wrappers omit task', () => {
|
|
282
282
|
const output = runWithFakeDelegates(`
|
|
283
|
-
const mod = await import('./src/lib/server/session-tools/delegate
|
|
283
|
+
const mod = await import('./src/lib/server/session-tools/delegate')
|
|
284
284
|
const { buildDelegateTools } = mod.default || mod['module.exports'] || mod
|
|
285
285
|
|
|
286
286
|
const tools = buildDelegateTools({
|
|
@@ -319,7 +319,7 @@ describe('delegate fallback', () => {
|
|
|
319
319
|
|
|
320
320
|
it('accepts legacy id fields for lifecycle delegate actions', () => {
|
|
321
321
|
const output = runWithFakeDelegates(`
|
|
322
|
-
const mod = await import('./src/lib/server/session-tools/delegate
|
|
322
|
+
const mod = await import('./src/lib/server/session-tools/delegate')
|
|
323
323
|
const { buildDelegateTools } = mod.default || mod['module.exports'] || mod
|
|
324
324
|
|
|
325
325
|
const tools = buildDelegateTools({
|
|
@@ -347,7 +347,7 @@ describe('delegate fallback', () => {
|
|
|
347
347
|
|
|
348
348
|
it('ranks authenticated delegate backends ahead of unauthenticated ones', () => {
|
|
349
349
|
const output = runWithFakeDelegates(`
|
|
350
|
-
const mod = await import('./src/lib/server/provider-health
|
|
350
|
+
const mod = await import('./src/lib/server/provider-health')
|
|
351
351
|
const { rankDelegatesByHealth } = mod.default || mod['module.exports'] || mod
|
|
352
352
|
const ranked = rankDelegatesByHealth(['delegate_to_claude_code', 'delegate_to_codex_cli'])
|
|
353
353
|
console.log(JSON.stringify(ranked))
|