@desplega.ai/agent-swarm 1.20.0 → 1.51.2
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 +271 -169
- package/openapi.json +5015 -0
- package/package.json +40 -7
- package/plugin/commands/close-issue.md +7 -3
- package/plugin/commands/create-pr.md +18 -12
- package/plugin/commands/implement-issue.md +7 -3
- package/plugin/commands/respond-github.md +8 -4
- package/plugin/commands/review-pr.md +44 -10
- package/plugin/commands/start-leader.md +1 -3
- package/plugin/commands/start-worker.md +1 -3
- package/plugin/commands/work-on-task.md +22 -3
- package/plugin/pi-skills/close-issue/SKILL.md +90 -0
- package/plugin/pi-skills/create-pr/SKILL.md +99 -0
- package/plugin/pi-skills/implement-issue/SKILL.md +135 -0
- package/plugin/pi-skills/investigate-sentry-issue/SKILL.md +138 -0
- package/plugin/pi-skills/respond-github/SKILL.md +98 -0
- package/plugin/pi-skills/review-offered-task/SKILL.md +45 -0
- package/plugin/pi-skills/review-pr/SKILL.md +261 -0
- package/plugin/pi-skills/start-leader/SKILL.md +121 -0
- package/plugin/pi-skills/start-worker/SKILL.md +60 -0
- package/plugin/pi-skills/swarm-chat/SKILL.md +82 -0
- package/plugin/pi-skills/todos/SKILL.md +66 -0
- package/plugin/pi-skills/work-on-task/SKILL.md +65 -0
- package/plugin/skills/artifacts/examples/approval-flow.ts +34 -0
- package/plugin/skills/artifacts/examples/hono-dashboard.ts +31 -0
- package/plugin/skills/artifacts/examples/multi-artifact.ts +20 -0
- package/plugin/skills/artifacts/examples/static-report.sh +17 -0
- package/plugin/skills/artifacts/skill.md +71 -0
- package/src/agentmail/app.ts +65 -0
- package/src/agentmail/handlers.ts +262 -0
- package/src/agentmail/index.ts +9 -0
- package/src/agentmail/templates.ts +111 -0
- package/src/agentmail/types.ts +51 -0
- package/src/artifact-sdk/browser-sdk.ts +30 -0
- package/src/artifact-sdk/index.ts +2 -0
- package/src/artifact-sdk/localtunnel.d.ts +20 -0
- package/src/artifact-sdk/port.ts +12 -0
- package/src/artifact-sdk/server.ts +156 -0
- package/src/artifact-sdk/tunnel.ts +19 -0
- package/src/be/chunking.ts +193 -0
- package/src/be/db-queries/oauth.ts +90 -0
- package/src/be/db-queries/tracker.ts +182 -0
- package/src/be/db.ts +3327 -784
- package/src/be/embedding.ts +80 -0
- package/src/be/migrations/001_initial.sql +409 -0
- package/src/be/migrations/002_one_time_schedules.sql +59 -0
- package/src/be/migrations/003_workflows.sql +51 -0
- package/src/be/migrations/004_workflow_source.sql +81 -0
- package/src/be/migrations/005_epic_next_steps.sql +2 -0
- package/src/be/migrations/006_vcs_provider.sql +94 -0
- package/src/be/migrations/007_task_dir.sql +2 -0
- package/src/be/migrations/008_workflow_redesign.sql +85 -0
- package/src/be/migrations/009_tracker_integration.sql +144 -0
- package/src/be/migrations/010_step_diagnostics.sql +1 -0
- package/src/be/migrations/011_step_next_port.sql +1 -0
- package/src/be/migrations/012_trigger_schema.sql +1 -0
- package/src/be/migrations/013_task_output_schema.sql +2 -0
- package/src/be/migrations/014_prompt_templates.sql +33 -0
- package/src/be/migrations/015_workflow_workspace.sql +3 -0
- package/src/be/migrations/016_active_session_runner_session.sql +4 -0
- package/src/be/migrations/017_channel_activity_cursors.sql +6 -0
- package/src/be/migrations/018_fix_seed_double_version.sql +30 -0
- package/src/be/migrations/runner.ts +188 -0
- package/src/be/seed.ts +62 -0
- package/src/cli.tsx +231 -299
- package/src/commands/artifact.ts +241 -0
- package/src/commands/onboard/compose-generator.ts +169 -0
- package/src/commands/onboard/env-generator.ts +79 -0
- package/src/commands/onboard/manifest.ts +37 -0
- package/src/commands/onboard/presets.ts +85 -0
- package/src/commands/onboard/service-names.ts +47 -0
- package/src/commands/onboard/steps/core-credentials.tsx +111 -0
- package/src/commands/onboard/steps/custom-templates.tsx +168 -0
- package/src/commands/onboard/steps/generate.tsx +154 -0
- package/src/commands/onboard/steps/harness-credentials.tsx +195 -0
- package/src/commands/onboard/steps/harness.tsx +21 -0
- package/src/commands/onboard/steps/health-check.tsx +171 -0
- package/src/commands/onboard/steps/integration-github.tsx +105 -0
- package/src/commands/onboard/steps/integration-gitlab.tsx +79 -0
- package/src/commands/onboard/steps/integration-menu.tsx +58 -0
- package/src/commands/onboard/steps/integration-sentry.tsx +79 -0
- package/src/commands/onboard/steps/integration-slack.tsx +165 -0
- package/src/commands/onboard/steps/post-connect.tsx +145 -0
- package/src/commands/onboard/steps/post-dashboard.tsx +34 -0
- package/src/commands/onboard/steps/post-task.tsx +103 -0
- package/src/commands/onboard/steps/prereq-check.tsx +178 -0
- package/src/commands/onboard/steps/review.tsx +82 -0
- package/src/commands/onboard/steps/start.tsx +97 -0
- package/src/commands/onboard/templates.ts +34 -0
- package/src/commands/onboard/types.ts +259 -0
- package/src/commands/onboard.tsx +425 -0
- package/src/commands/runner.ts +1540 -630
- package/src/commands/setup.tsx +23 -38
- package/src/commands/shared/client-config.ts +41 -0
- package/src/commands/templates.ts +172 -0
- package/src/github/app.ts +8 -0
- package/src/github/handlers.ts +384 -151
- package/src/github/index.ts +1 -0
- package/src/github/mentions-aliases.test.ts +73 -0
- package/src/github/mentions.test.ts +3 -3
- package/src/github/mentions.ts +32 -6
- package/src/github/templates.ts +398 -0
- package/src/github/types.ts +1 -0
- package/src/gitlab/auth.ts +63 -0
- package/src/gitlab/handlers.ts +368 -0
- package/src/gitlab/index.ts +19 -0
- package/src/gitlab/reactions.ts +104 -0
- package/src/gitlab/templates.ts +140 -0
- package/src/gitlab/types.ts +130 -0
- package/src/heartbeat/heartbeat.ts +434 -0
- package/src/heartbeat/index.ts +1 -0
- package/src/heartbeat/templates.ts +30 -0
- package/src/hooks/hook.ts +555 -4
- package/src/hooks/tool-loop-detection.test.ts +158 -0
- package/src/hooks/tool-loop-detection.ts +167 -0
- package/src/http/active-sessions.ts +199 -0
- package/src/http/agents.ts +328 -0
- package/src/http/config.ts +191 -0
- package/src/http/core.ts +309 -0
- package/src/http/db-query.ts +91 -0
- package/src/http/ecosystem.ts +63 -0
- package/src/http/epics.ts +460 -0
- package/src/http/index.ts +216 -0
- package/src/http/mcp.ts +77 -0
- package/src/http/memory.ts +168 -0
- package/src/http/openapi.ts +109 -0
- package/src/http/poll.ts +299 -0
- package/src/http/prompt-templates.ts +412 -0
- package/src/http/repos.ts +195 -0
- package/src/http/route-def.ts +123 -0
- package/src/http/schedules.ts +426 -0
- package/src/http/session-data.ts +241 -0
- package/src/http/stats.ts +174 -0
- package/src/http/tasks.ts +468 -0
- package/src/http/trackers/index.ts +10 -0
- package/src/http/trackers/linear.ts +187 -0
- package/src/http/types.ts +12 -0
- package/src/http/utils.ts +87 -0
- package/src/http/webhooks.ts +432 -0
- package/src/http/workflows.ts +530 -0
- package/src/http.ts +1 -1890
- package/src/linear/README.md +65 -0
- package/src/linear/app.ts +48 -0
- package/src/linear/client.ts +18 -0
- package/src/linear/index.ts +1 -0
- package/src/linear/oauth.ts +35 -0
- package/src/linear/outbound.ts +212 -0
- package/src/linear/sync.ts +567 -0
- package/src/linear/templates.ts +47 -0
- package/src/linear/types.ts +7 -0
- package/src/linear/webhook.ts +104 -0
- package/src/oauth/README.md +66 -0
- package/src/oauth/index.ts +6 -0
- package/src/oauth/wrapper.ts +204 -0
- package/src/prompts/base-prompt.ts +150 -265
- package/src/prompts/defaults.ts +196 -0
- package/src/prompts/registry.ts +57 -0
- package/src/prompts/resolver.ts +296 -0
- package/src/prompts/session-templates.ts +604 -0
- package/src/providers/claude-adapter.ts +442 -0
- package/src/providers/index.ts +24 -0
- package/src/providers/pi-mono-adapter.ts +442 -0
- package/src/providers/pi-mono-extension.ts +624 -0
- package/src/providers/pi-mono-mcp-client.ts +124 -0
- package/src/providers/types.ts +75 -0
- package/src/scheduler/scheduler.test.ts +2 -0
- package/src/scheduler/scheduler.ts +231 -40
- package/src/server.ts +97 -6
- package/src/slack/HEURISTICS.md +105 -0
- package/src/slack/actions.ts +133 -0
- package/src/slack/app.ts +7 -0
- package/src/slack/assistant.ts +118 -0
- package/src/slack/blocks.ts +233 -0
- package/src/slack/channel-activity.ts +177 -0
- package/src/slack/commands.ts +31 -17
- package/src/slack/files.ts +1 -1
- package/src/slack/handlers.test.ts +114 -1
- package/src/slack/handlers.ts +230 -55
- package/src/slack/responses.ts +120 -67
- package/src/slack/router.ts +17 -99
- package/src/slack/templates.ts +55 -0
- package/src/slack/thread-buffer.ts +213 -0
- package/src/slack/watcher.ts +119 -4
- package/src/tests/agent-activity.test.ts +247 -0
- package/src/tests/agentmail-filters.test.ts +97 -0
- package/src/tests/artifact-sdk.test.ts +800 -0
- package/src/tests/base-prompt.test.ts +264 -0
- package/src/tests/build-pi-skills.test.ts +127 -0
- package/src/tests/channel-activity.test.ts +363 -0
- package/src/tests/claude-adapter.test.ts +126 -0
- package/src/tests/context-versioning.test.ts +425 -0
- package/src/tests/db-queries-oauth.test.ts +197 -0
- package/src/tests/db-queries-tracker.test.ts +230 -0
- package/src/tests/epics.test.ts +3 -3
- package/src/tests/error-tracker.test.ts +368 -0
- package/src/tests/fetch-resolved-env.test.ts +167 -0
- package/src/tests/generate-default-claude-md.test.ts +9 -1
- package/src/tests/generate-identity-templates.test.ts +124 -0
- package/src/tests/gitlab-auth.test.ts +109 -0
- package/src/tests/gitlab-handlers.test.ts +691 -0
- package/src/tests/gitlab-vcs-db.test.ts +177 -0
- package/src/tests/heartbeat.test.ts +364 -0
- package/src/tests/http-api-integration.test.ts +1698 -0
- package/src/tests/linear-outbound-sync.test.ts +200 -0
- package/src/tests/linear-webhook.test.ts +406 -0
- package/src/tests/match-route.test.ts +187 -0
- package/src/tests/memory.test.ts +737 -0
- package/src/tests/migration-runner-regressions.test.ts +86 -0
- package/src/tests/model-control.test.ts +338 -0
- package/src/tests/oauth-wrapper.test.ts +147 -0
- package/src/tests/onboard-compose.test.ts +138 -0
- package/src/tests/onboard-env.test.ts +174 -0
- package/src/tests/onboard-manifest.test.ts +137 -0
- package/src/tests/pi-mono-adapter.test.ts +234 -0
- package/src/tests/pool-session-logs.test.ts +199 -0
- package/src/tests/progress-dedup.test.ts +98 -0
- package/src/tests/prompt-template-github.test.ts +682 -0
- package/src/tests/prompt-template-remaining.test.ts +504 -0
- package/src/tests/prompt-template-resolver.test.ts +621 -0
- package/src/tests/prompt-template-session.test.ts +363 -0
- package/src/tests/prompt-templates-db.test.ts +616 -0
- package/src/tests/provider-adapter.test.ts +122 -0
- package/src/tests/provider-command-format.test.ts +98 -0
- package/src/tests/reload-config.test.ts +170 -0
- package/src/tests/runner-polling-api.test.ts +25 -20
- package/src/tests/scheduled-tasks.test.ts +104 -0
- package/src/tests/scheduler-backoff.test.ts +166 -0
- package/src/tests/self-improvement.test.ts +541 -0
- package/src/tests/session-attach.test.ts +536 -0
- package/src/tests/session-costs.test.ts +267 -1
- package/src/tests/slack-actions.test.ts +133 -0
- package/src/tests/slack-assistant.test.ts +136 -0
- package/src/tests/slack-blocks.test.ts +246 -0
- package/src/tests/slack-metadata-inheritance.test.ts +243 -0
- package/src/tests/slack-queue-offline.test.ts +174 -0
- package/src/tests/slack-router.test.ts +181 -0
- package/src/tests/slack-thread-buffer.test.ts +305 -0
- package/src/tests/slack-thread-followups.test.ts +298 -0
- package/src/tests/slack-watcher.test.ts +101 -0
- package/src/tests/structured-output.test.ts +307 -0
- package/src/tests/swarm-repos.test.ts +198 -0
- package/src/tests/task-cancellation.test.ts +6 -4
- package/src/tests/task-working-dir.test.ts +176 -0
- package/src/tests/template-fetch.test.ts +490 -0
- package/src/tests/tool-annotations.test.ts +371 -0
- package/src/tests/tracker-tools.test.ts +184 -0
- package/src/tests/update-profile-agentid.test.ts +248 -0
- package/src/tests/update-profile-api.test.ts +143 -3
- package/src/tests/update-profile-auth.test.ts +195 -0
- package/src/tests/validation-adapters.test.ts +86 -0
- package/src/tests/vcs-provider.test.ts +27 -0
- package/src/tests/workflow-agent-task.test.ts +196 -0
- package/src/tests/workflow-async-v2.test.ts +508 -0
- package/src/tests/workflow-convergence.test.ts +541 -0
- package/src/tests/workflow-definition-validation.test.ts +366 -0
- package/src/tests/workflow-engine-v2.test.ts +691 -0
- package/src/tests/workflow-executors.test.ts +736 -0
- package/src/tests/workflow-http-v2.test.ts +599 -0
- package/src/tests/workflow-integration-io.test.ts +902 -0
- package/src/tests/workflow-io-schemas.test.ts +624 -0
- package/src/tests/workflow-registry.test.ts +592 -0
- package/src/tests/workflow-retry-v2.test.ts +401 -0
- package/src/tests/workflow-retry-validation.test.ts +282 -0
- package/src/tests/workflow-schedule-trigger.test.ts +104 -0
- package/src/tests/workflow-template.test.ts +288 -0
- package/src/tests/workflow-trigger-schema.test.ts +359 -0
- package/src/tests/workflow-triggers-v2.test.ts +264 -0
- package/src/tests/workflow-versions.test.ts +208 -0
- package/src/tests/workflow-workspace.test.ts +272 -0
- package/src/tests/x402-client.test.ts +117 -0
- package/src/tests/x402-config.test.ts +182 -0
- package/src/tests/x402-spending-tracker.test.ts +185 -0
- package/src/tools/cancel-task.ts +2 -0
- package/src/tools/context-diff.ts +171 -0
- package/src/tools/context-history.ts +138 -0
- package/src/tools/create-channel.ts +1 -0
- package/src/tools/db-query.ts +78 -0
- package/src/tools/delete-channel.ts +132 -0
- package/src/tools/epics/assign-task-to-epic.ts +1 -0
- package/src/tools/epics/create-epic.ts +3 -2
- package/src/tools/epics/delete-epic.ts +2 -0
- package/src/tools/epics/get-epic-details.ts +2 -0
- package/src/tools/epics/list-epics.ts +2 -0
- package/src/tools/epics/unassign-task-from-epic.ts +1 -0
- package/src/tools/epics/update-epic.ts +7 -4
- package/src/tools/get-swarm.ts +2 -0
- package/src/tools/get-task-details.ts +2 -0
- package/src/tools/get-tasks.ts +27 -1
- package/src/tools/inject-learning.ts +106 -0
- package/src/tools/join-swarm.ts +17 -7
- package/src/tools/list-channels.ts +2 -0
- package/src/tools/list-services.ts +2 -0
- package/src/tools/memory-get.ts +56 -0
- package/src/tools/memory-search.ts +131 -0
- package/src/tools/my-agent-info.ts +2 -0
- package/src/tools/poll-task.ts +2 -20
- package/src/tools/post-message.ts +1 -0
- package/src/tools/prompt-templates/delete.ts +86 -0
- package/src/tools/prompt-templates/get.ts +89 -0
- package/src/tools/prompt-templates/index.ts +5 -0
- package/src/tools/prompt-templates/list.ts +95 -0
- package/src/tools/prompt-templates/preview.ts +84 -0
- package/src/tools/prompt-templates/set.ts +117 -0
- package/src/tools/read-messages.ts +2 -0
- package/src/tools/register-agentmail-inbox.ts +166 -0
- package/src/tools/register-service.ts +2 -0
- package/src/tools/schedules/create-schedule.ts +134 -24
- package/src/tools/schedules/delete-schedule.ts +2 -0
- package/src/tools/schedules/list-schedules.ts +20 -4
- package/src/tools/schedules/run-schedule-now.ts +1 -0
- package/src/tools/schedules/update-schedule.ts +49 -17
- package/src/tools/send-task.ts +132 -10
- package/src/tools/slack-download-file.ts +4 -2
- package/src/tools/slack-list-channels.ts +2 -0
- package/src/tools/slack-post.ts +2 -0
- package/src/tools/slack-read.ts +2 -0
- package/src/tools/slack-reply.ts +2 -0
- package/src/tools/slack-upload-file.ts +2 -0
- package/src/tools/store-progress.ts +205 -4
- package/src/tools/swarm-config/delete-config.ts +87 -0
- package/src/tools/swarm-config/get-config.ts +108 -0
- package/src/tools/swarm-config/index.ts +4 -0
- package/src/tools/swarm-config/list-config.ts +99 -0
- package/src/tools/swarm-config/set-config.ts +118 -0
- package/src/tools/task-action.ts +50 -5
- package/src/tools/task-dedup.ts +97 -0
- package/src/tools/templates.ts +53 -0
- package/src/tools/tool-config.ts +124 -0
- package/src/tools/tracker/index.ts +6 -0
- package/src/tools/tracker/tracker-link-epic.ts +64 -0
- package/src/tools/tracker/tracker-link-task.ts +64 -0
- package/src/tools/tracker/tracker-map-agent.ts +57 -0
- package/src/tools/tracker/tracker-status.ts +56 -0
- package/src/tools/tracker/tracker-sync-status.ts +42 -0
- package/src/tools/tracker/tracker-unlink.ts +41 -0
- package/src/tools/unregister-service.ts +2 -0
- package/src/tools/update-profile.ts +172 -17
- package/src/tools/update-service-status.ts +2 -0
- package/src/tools/utils.ts +10 -1
- package/src/tools/workflows/create-workflow.ts +129 -0
- package/src/tools/workflows/delete-workflow.ts +42 -0
- package/src/tools/workflows/get-workflow-run.ts +59 -0
- package/src/tools/workflows/get-workflow.ts +53 -0
- package/src/tools/workflows/index.ts +9 -0
- package/src/tools/workflows/list-workflow-runs.ts +48 -0
- package/src/tools/workflows/list-workflows.ts +42 -0
- package/src/tools/workflows/retry-workflow-run.ts +40 -0
- package/src/tools/workflows/trigger-workflow.ts +96 -0
- package/src/tools/workflows/update-workflow.ts +133 -0
- package/src/tracker/types.ts +51 -0
- package/src/types.ts +530 -14
- package/src/utils/credentials.test.ts +156 -0
- package/src/utils/credentials.ts +50 -0
- package/src/utils/error-tracker.ts +190 -0
- package/src/vcs/index.ts +15 -0
- package/src/vcs/types.ts +5 -0
- package/src/workflows/checkpoint.ts +121 -0
- package/src/workflows/cooldown.ts +28 -0
- package/src/workflows/definition.ts +235 -0
- package/src/workflows/engine.ts +580 -0
- package/src/workflows/event-bus.ts +29 -0
- package/src/workflows/executors/agent-task.ts +103 -0
- package/src/workflows/executors/base.ts +86 -0
- package/src/workflows/executors/code-match.ts +88 -0
- package/src/workflows/executors/index.ts +16 -0
- package/src/workflows/executors/notify.ts +93 -0
- package/src/workflows/executors/property-match.ts +104 -0
- package/src/workflows/executors/raw-llm.ts +83 -0
- package/src/workflows/executors/registry.ts +76 -0
- package/src/workflows/executors/script.ts +103 -0
- package/src/workflows/executors/validate.ts +215 -0
- package/src/workflows/executors/vcs.ts +58 -0
- package/src/workflows/index.ts +61 -0
- package/src/workflows/input.ts +46 -0
- package/src/workflows/json-schema-validator.ts +118 -0
- package/src/workflows/recovery.ts +139 -0
- package/src/workflows/resume.ts +229 -0
- package/src/workflows/retry-poller.ts +216 -0
- package/src/workflows/template.ts +74 -0
- package/src/workflows/templates.ts +86 -0
- package/src/workflows/triggers.ts +124 -0
- package/src/workflows/validation.ts +104 -0
- package/src/workflows/version.ts +44 -0
- package/src/x402/cli.ts +140 -0
- package/src/x402/client.ts +192 -0
- package/src/x402/config.ts +131 -0
- package/src/x402/index.ts +37 -0
- package/src/x402/openfort-signer.ts +83 -0
- package/src/x402/spending-tracker.ts +109 -0
- package/templates/official/coder/CLAUDE.md +49 -0
- package/templates/official/coder/IDENTITY.md +28 -0
- package/templates/official/coder/SOUL.md +43 -0
- package/templates/official/coder/TOOLS.md +40 -0
- package/templates/official/coder/config.json +23 -0
- package/templates/official/coder/start-up.sh +23 -0
- package/templates/official/content-reviewer/CLAUDE.md +68 -0
- package/templates/official/content-reviewer/IDENTITY.md +28 -0
- package/templates/official/content-reviewer/SOUL.md +44 -0
- package/templates/official/content-reviewer/TOOLS.md +37 -0
- package/templates/official/content-reviewer/config.json +23 -0
- package/templates/official/content-reviewer/start-up.sh +23 -0
- package/templates/official/content-strategist/CLAUDE.md +63 -0
- package/templates/official/content-strategist/IDENTITY.md +33 -0
- package/templates/official/content-strategist/SOUL.md +48 -0
- package/templates/official/content-strategist/TOOLS.md +47 -0
- package/templates/official/content-strategist/config.json +23 -0
- package/templates/official/content-strategist/start-up.sh +23 -0
- package/templates/official/content-writer/CLAUDE.md +72 -0
- package/templates/official/content-writer/IDENTITY.md +30 -0
- package/templates/official/content-writer/SOUL.md +46 -0
- package/templates/official/content-writer/TOOLS.md +44 -0
- package/templates/official/content-writer/config.json +23 -0
- package/templates/official/content-writer/start-up.sh +23 -0
- package/templates/official/forward-deployed-engineer/CLAUDE.md +54 -0
- package/templates/official/forward-deployed-engineer/IDENTITY.md +37 -0
- package/templates/official/forward-deployed-engineer/SOUL.md +55 -0
- package/templates/official/forward-deployed-engineer/config.json +21 -0
- package/templates/official/lead/CLAUDE.md +33 -0
- package/templates/official/lead/IDENTITY.md +36 -0
- package/templates/official/lead/SOUL.md +51 -0
- package/templates/official/lead/config.json +22 -0
- package/templates/official/researcher/CLAUDE.md +46 -0
- package/templates/official/researcher/IDENTITY.md +28 -0
- package/templates/official/researcher/SOUL.md +43 -0
- package/templates/official/researcher/config.json +21 -0
- package/templates/official/reviewer/CLAUDE.md +63 -0
- package/templates/official/reviewer/IDENTITY.md +28 -0
- package/templates/official/reviewer/SOUL.md +45 -0
- package/templates/official/reviewer/config.json +21 -0
- package/templates/official/tester/CLAUDE.md +53 -0
- package/templates/official/tester/IDENTITY.md +28 -0
- package/templates/official/tester/SOUL.md +55 -0
- package/templates/official/tester/config.json +21 -0
- package/templates/schema.ts +35 -0
- package/.claude/settings.local.json +0 -115
- package/.dockerignore +0 -61
- package/.editorconfig +0 -15
- package/.env.docker.example +0 -39
- package/.env.example +0 -40
- package/.github/workflows/ci.yml +0 -76
- package/.github/workflows/docker-and-deploy.yml +0 -117
- package/.wts-config.json +0 -4
- package/.wts-setup.ts +0 -102
- package/CLAUDE.md +0 -104
- package/CONTRIBUTING.md +0 -270
- package/DEPLOYMENT.md +0 -605
- package/Dockerfile +0 -57
- package/Dockerfile.worker +0 -157
- package/FAQ.md +0 -19
- package/MCP.md +0 -406
- package/UI.md +0 -40
- package/assets/agent-swarm-logo-orange.png +0 -0
- package/assets/agent-swarm-logo.png +0 -0
- package/assets/agent-swarm.mp4 +0 -0
- package/assets/agent-swarm.png +0 -0
- package/biome.json +0 -39
- package/deploy/DEPLOY.md +0 -60
- package/deploy/agent-swarm.service +0 -17
- package/deploy/docker-push.ts +0 -30
- package/deploy/install.ts +0 -85
- package/deploy/prod-db.ts +0 -42
- package/deploy/uninstall.ts +0 -12
- package/deploy/update.ts +0 -21
- package/docker-compose.example.yml +0 -159
- package/docker-entrypoint.sh +0 -352
- package/ecosystem.config.cjs +0 -66
- package/plugin/README.md +0 -1
- package/plugin/hooks/hooks.json +0 -71
- package/pyproject.toml +0 -9
- package/scripts/generate-mcp-docs.ts +0 -415
- package/slack-manifest.json +0 -71
- package/src/tests/get-inbox-message.test.ts +0 -145
- package/src/tools/get-inbox-message.ts +0 -89
- package/src/tools/inbox-delegate.ts +0 -113
- package/thoughts/shared/plans/2025-12-18-slack-integration.md +0 -1195
- package/thoughts/shared/plans/2025-12-19-agent-log-streaming.md +0 -732
- package/thoughts/shared/plans/2025-12-19-role-based-swarm-plugin.md +0 -361
- package/thoughts/shared/plans/2025-12-20-mobile-responsive-ui.md +0 -501
- package/thoughts/shared/plans/2025-12-20-startup-team-swarm.md +0 -560
- package/thoughts/shared/plans/2025-12-23-runner-level-polling.md +0 -934
- package/thoughts/shared/plans/2025-12-23-runner-session-logs.md +0 -1000
- package/thoughts/shared/plans/2025-12-23-worker-lead-spawn-triggers.md +0 -568
- package/thoughts/shared/plans/2026-01-09-inverse-teleport.md +0 -1516
- package/thoughts/shared/plans/2026-01-12-agent-rename-pm2-control.md +0 -1133
- package/thoughts/shared/plans/2026-01-12-github-app-integration.md +0 -380
- package/thoughts/shared/plans/2026-01-12-lead-inbox-model.md +0 -876
- package/thoughts/shared/plans/2026-01-12-ralph-wiggum-integration.md +0 -463
- package/thoughts/shared/plans/2026-01-13-agent-concurrency.md +0 -691
- package/thoughts/shared/plans/2026-01-13-github-assignment-handling.md +0 -690
- package/thoughts/shared/plans/2026-01-13-prevent-duplicate-trigger-processing.md +0 -1071
- package/thoughts/shared/plans/2026-01-14-fix-slack-thread-context.md +0 -507
- package/thoughts/shared/plans/2026-01-15-scheduled-tasks-implementation.md +0 -565
- package/thoughts/shared/plans/2026-01-15-usage-cost-tracking-ui.md +0 -1479
- package/thoughts/shared/plans/2026-01-16-epics-feature-implementation.md +0 -1230
- package/thoughts/shared/research/.gitkeep +0 -0
- package/thoughts/shared/research/2025-01-09-inverse-teleport-plan-review.md +0 -420
- package/thoughts/shared/research/2025-12-18-slack-integration.md +0 -442
- package/thoughts/shared/research/2025-12-19-agent-log-streaming.md +0 -339
- package/thoughts/shared/research/2025-12-19-agent-secrets-cli-research.md +0 -390
- package/thoughts/shared/research/2025-12-21-gemini-cli-integration.md +0 -376
- package/thoughts/shared/research/2025-12-22-runner-loop-architecture.md +0 -582
- package/thoughts/shared/research/2025-12-22-setup-experience-improvements.md +0 -264
- package/thoughts/shared/research/2026-01-13-lead-duplicate-trigger-processing.md +0 -223
- package/thoughts/shared/research/2026-01-14-lead-slack-thread-context.md +0 -277
- package/thoughts/shared/research/2026-01-15-ai-tracker-agent-swarm-integration.md +0 -376
- package/thoughts/shared/research/2026-01-15-auto-starting-processes-in-worker-containers.md +0 -787
- package/thoughts/shared/research/2026-01-15-scheduled-tasks.md +0 -390
- package/thoughts/shared/research/2026-01-16-epics-feature-research.md +0 -437
- package/thoughts/taras/plans/2026-01-22-agent-swarm-schemas.md +0 -98
- package/thoughts/taras/plans/2026-01-28-per-worker-claude-md.md +0 -617
- package/thoughts/taras/plans/2026-01-28-sentry-cli-integration.md +0 -214
- package/thoughts/taras/research/2026-01-22-vercel-cli-integration.md +0 -287
- package/thoughts/taras/research/2026-01-27-excessive-polling-issue.md +0 -311
- package/thoughts/taras/research/2026-01-28-per-worker-claude-md.md +0 -383
- package/thoughts/taras/research/2026-01-28-sentry-cli-integration.md +0 -240
- package/tsconfig.json +0 -37
- package/ui/CLAUDE.md +0 -49
- package/ui/bun.lock +0 -771
- package/ui/index.html +0 -22
- package/ui/package-lock.json +0 -5290
- package/ui/package.json +0 -33
- package/ui/pnpm-lock.yaml +0 -3341
- package/ui/postcss.config.js +0 -6
- package/ui/public/logo.png +0 -0
- package/ui/src/App.tsx +0 -63
- package/ui/src/components/ActivityFeed.tsx +0 -440
- package/ui/src/components/AgentDetailPanel.tsx +0 -733
- package/ui/src/components/AgentsPanel.tsx +0 -815
- package/ui/src/components/ChatPanel.tsx +0 -1920
- package/ui/src/components/ConfigModal.tsx +0 -253
- package/ui/src/components/Dashboard.tsx +0 -832
- package/ui/src/components/EditAgentProfileModal.tsx +0 -433
- package/ui/src/components/EpicDetailPage.tsx +0 -741
- package/ui/src/components/EpicsPanel.tsx +0 -566
- package/ui/src/components/Header.tsx +0 -160
- package/ui/src/components/JsonViewer.tsx +0 -171
- package/ui/src/components/ScheduledTaskDetailPanel.tsx +0 -517
- package/ui/src/components/ScheduledTasksPanel.tsx +0 -639
- package/ui/src/components/ServicesPanel.tsx +0 -622
- package/ui/src/components/SessionLogPanel.tsx +0 -1219
- package/ui/src/components/StatsBar.tsx +0 -321
- package/ui/src/components/StatusBadge.tsx +0 -168
- package/ui/src/components/TaskDetailPanel.tsx +0 -903
- package/ui/src/components/TasksPanel.tsx +0 -614
- package/ui/src/components/UsageCharts.tsx +0 -216
- package/ui/src/components/UsageTab.tsx +0 -394
- package/ui/src/hooks/queries.ts +0 -353
- package/ui/src/hooks/useAutoScroll.ts +0 -83
- package/ui/src/index.css +0 -257
- package/ui/src/lib/api.ts +0 -268
- package/ui/src/lib/config.ts +0 -35
- package/ui/src/lib/contentPreview.ts +0 -208
- package/ui/src/lib/theme.ts +0 -214
- package/ui/src/lib/utils.ts +0 -88
- package/ui/src/main.tsx +0 -28
- package/ui/src/types/api.ts +0 -323
- package/ui/src/vite-env.d.ts +0 -1
- package/ui/tailwind.config.js +0 -37
- package/ui/tsconfig.json +0 -31
- package/ui/vite.config.ts +0 -35
- /package/{thoughts/shared/plans → templates/community}/.gitkeep +0 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { unlink } from "node:fs/promises";
|
|
3
|
+
import {
|
|
4
|
+
closeDb,
|
|
5
|
+
createScheduledTask,
|
|
6
|
+
getScheduledTaskById,
|
|
7
|
+
initDb,
|
|
8
|
+
updateScheduledTask,
|
|
9
|
+
} from "../be/db";
|
|
10
|
+
|
|
11
|
+
const TEST_DB_PATH = "./test-scheduler-backoff.sqlite";
|
|
12
|
+
|
|
13
|
+
describe("scheduler exponential backoff", () => {
|
|
14
|
+
beforeAll(() => {
|
|
15
|
+
initDb(TEST_DB_PATH);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterAll(async () => {
|
|
19
|
+
closeDb();
|
|
20
|
+
try {
|
|
21
|
+
await unlink(TEST_DB_PATH);
|
|
22
|
+
await unlink(`${TEST_DB_PATH}-wal`);
|
|
23
|
+
await unlink(`${TEST_DB_PATH}-shm`);
|
|
24
|
+
} catch {
|
|
25
|
+
// ignore
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("new scheduled tasks have consecutiveErrors = 0", () => {
|
|
30
|
+
const schedule = createScheduledTask({
|
|
31
|
+
name: "backoff-test-1",
|
|
32
|
+
taskTemplate: "Test task",
|
|
33
|
+
intervalMs: 60000,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(schedule.consecutiveErrors).toBe(0);
|
|
37
|
+
expect(schedule.lastErrorAt).toBeUndefined();
|
|
38
|
+
expect(schedule.lastErrorMessage).toBeUndefined();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("updateScheduledTask can set error tracking fields", () => {
|
|
42
|
+
const schedule = createScheduledTask({
|
|
43
|
+
name: "backoff-test-2",
|
|
44
|
+
taskTemplate: "Test task",
|
|
45
|
+
intervalMs: 60000,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const now = new Date().toISOString();
|
|
49
|
+
const updated = updateScheduledTask(schedule.id, {
|
|
50
|
+
consecutiveErrors: 3,
|
|
51
|
+
lastErrorAt: now,
|
|
52
|
+
lastErrorMessage: "Connection refused",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(updated).not.toBeNull();
|
|
56
|
+
expect(updated!.consecutiveErrors).toBe(3);
|
|
57
|
+
expect(updated!.lastErrorAt).toBe(now);
|
|
58
|
+
expect(updated!.lastErrorMessage).toBe("Connection refused");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("error tracking can be reset to 0 on success", () => {
|
|
62
|
+
const schedule = createScheduledTask({
|
|
63
|
+
name: "backoff-test-3",
|
|
64
|
+
taskTemplate: "Test task",
|
|
65
|
+
intervalMs: 60000,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Simulate errors
|
|
69
|
+
updateScheduledTask(schedule.id, {
|
|
70
|
+
consecutiveErrors: 4,
|
|
71
|
+
lastErrorAt: new Date().toISOString(),
|
|
72
|
+
lastErrorMessage: "Some error",
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Simulate successful execution — reset errors
|
|
76
|
+
const updated = updateScheduledTask(schedule.id, {
|
|
77
|
+
consecutiveErrors: 0,
|
|
78
|
+
lastErrorAt: null,
|
|
79
|
+
lastErrorMessage: null,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
expect(updated!.consecutiveErrors).toBe(0);
|
|
83
|
+
expect(updated!.lastErrorAt).toBeUndefined();
|
|
84
|
+
expect(updated!.lastErrorMessage).toBeUndefined();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("schedule can be auto-disabled via enabled = false", () => {
|
|
88
|
+
const schedule = createScheduledTask({
|
|
89
|
+
name: "backoff-test-4",
|
|
90
|
+
taskTemplate: "Test task",
|
|
91
|
+
intervalMs: 60000,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
expect(schedule.enabled).toBe(true);
|
|
95
|
+
|
|
96
|
+
// Simulate auto-disable after MAX_CONSECUTIVE_ERRORS
|
|
97
|
+
const updated = updateScheduledTask(schedule.id, {
|
|
98
|
+
consecutiveErrors: 5,
|
|
99
|
+
lastErrorAt: new Date().toISOString(),
|
|
100
|
+
lastErrorMessage: "Repeated failure",
|
|
101
|
+
enabled: false,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(updated!.enabled).toBe(false);
|
|
105
|
+
expect(updated!.consecutiveErrors).toBe(5);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("nextRunAt can be pushed forward for backoff", () => {
|
|
109
|
+
const schedule = createScheduledTask({
|
|
110
|
+
name: "backoff-test-5",
|
|
111
|
+
taskTemplate: "Test task",
|
|
112
|
+
intervalMs: 60000,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const now = new Date();
|
|
116
|
+
const backoffMs = 300_000; // 5 minutes
|
|
117
|
+
const backoffTime = new Date(now.getTime() + backoffMs).toISOString();
|
|
118
|
+
|
|
119
|
+
const updated = updateScheduledTask(schedule.id, {
|
|
120
|
+
consecutiveErrors: 2,
|
|
121
|
+
lastErrorAt: now.toISOString(),
|
|
122
|
+
lastErrorMessage: "Timeout",
|
|
123
|
+
nextRunAt: backoffTime,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
expect(updated!.nextRunAt).toBe(backoffTime);
|
|
127
|
+
expect(updated!.consecutiveErrors).toBe(2);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("error message is truncated to 500 chars", () => {
|
|
131
|
+
const schedule = createScheduledTask({
|
|
132
|
+
name: "backoff-test-6",
|
|
133
|
+
taskTemplate: "Test task",
|
|
134
|
+
intervalMs: 60000,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const longMessage = "x".repeat(1000);
|
|
138
|
+
const updated = updateScheduledTask(schedule.id, {
|
|
139
|
+
consecutiveErrors: 1,
|
|
140
|
+
lastErrorAt: new Date().toISOString(),
|
|
141
|
+
lastErrorMessage: longMessage.slice(0, 500),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
expect(updated!.lastErrorMessage!.length).toBe(500);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("consecutiveErrors persists across reads", () => {
|
|
148
|
+
const schedule = createScheduledTask({
|
|
149
|
+
name: "backoff-test-7",
|
|
150
|
+
taskTemplate: "Test task",
|
|
151
|
+
intervalMs: 60000,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
updateScheduledTask(schedule.id, {
|
|
155
|
+
consecutiveErrors: 3,
|
|
156
|
+
lastErrorAt: new Date().toISOString(),
|
|
157
|
+
lastErrorMessage: "Error 3",
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Read back from DB
|
|
161
|
+
const reloaded = getScheduledTaskById(schedule.id);
|
|
162
|
+
expect(reloaded).not.toBeNull();
|
|
163
|
+
expect(reloaded!.consecutiveErrors).toBe(3);
|
|
164
|
+
expect(reloaded!.lastErrorMessage).toBe("Error 3");
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { unlink } from "node:fs/promises";
|
|
3
|
+
import {
|
|
4
|
+
closeDb,
|
|
5
|
+
completeTask,
|
|
6
|
+
createAgent,
|
|
7
|
+
createEpic,
|
|
8
|
+
createMemory,
|
|
9
|
+
createTaskExtended,
|
|
10
|
+
failTask,
|
|
11
|
+
getAgentById,
|
|
12
|
+
initDb,
|
|
13
|
+
searchMemoriesByVector,
|
|
14
|
+
updateMemoryEmbedding,
|
|
15
|
+
} from "../be/db";
|
|
16
|
+
import { serializeEmbedding } from "../be/embedding";
|
|
17
|
+
import { getBasePrompt } from "../prompts/base-prompt";
|
|
18
|
+
|
|
19
|
+
const TEST_DB_PATH = "./test-self-improvement.sqlite";
|
|
20
|
+
|
|
21
|
+
describe("Self-Improvement Mechanisms", () => {
|
|
22
|
+
const leadId = "aaaa0000-0000-4000-8000-000000000001";
|
|
23
|
+
const workerId = "bbbb0000-0000-4000-8000-000000000002";
|
|
24
|
+
const otherWorkerId = "cccc0000-0000-4000-8000-000000000003";
|
|
25
|
+
|
|
26
|
+
beforeAll(async () => {
|
|
27
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
28
|
+
try {
|
|
29
|
+
await unlink(TEST_DB_PATH + suffix);
|
|
30
|
+
} catch {
|
|
31
|
+
// File doesn't exist
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
closeDb();
|
|
36
|
+
initDb(TEST_DB_PATH);
|
|
37
|
+
|
|
38
|
+
createAgent({ id: leadId, name: "Test Lead", isLead: true, status: "idle" });
|
|
39
|
+
createAgent({ id: workerId, name: "Test Worker", isLead: false, status: "idle" });
|
|
40
|
+
createAgent({ id: otherWorkerId, name: "Other Worker", isLead: false, status: "idle" });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
afterAll(async () => {
|
|
44
|
+
closeDb();
|
|
45
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
46
|
+
try {
|
|
47
|
+
await unlink(TEST_DB_PATH + suffix);
|
|
48
|
+
} catch {
|
|
49
|
+
// File doesn't exist
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// ==========================================================================
|
|
55
|
+
// P2: store-progress memory indexing for completed and failed tasks
|
|
56
|
+
// ==========================================================================
|
|
57
|
+
|
|
58
|
+
describe("store-progress memory indexing", () => {
|
|
59
|
+
test("completed task creates agent-scoped memory with output", () => {
|
|
60
|
+
const task = createTaskExtended("Test task for completion", {
|
|
61
|
+
agentId: workerId,
|
|
62
|
+
source: "mcp",
|
|
63
|
+
priority: 50,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const output = "Successfully completed the task with great results";
|
|
67
|
+
completeTask(task.id, output);
|
|
68
|
+
|
|
69
|
+
// Simulate what store-progress does: create memory for completed task
|
|
70
|
+
const taskContent = `Task: ${task.task}\n\nOutput:\n${output}`;
|
|
71
|
+
const memory = createMemory({
|
|
72
|
+
agentId: workerId,
|
|
73
|
+
content: taskContent,
|
|
74
|
+
name: `Task: ${task.task.slice(0, 80)}`,
|
|
75
|
+
scope: "agent",
|
|
76
|
+
source: "task_completion",
|
|
77
|
+
sourceTaskId: task.id,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(memory.scope).toBe("agent");
|
|
81
|
+
expect(memory.source).toBe("task_completion");
|
|
82
|
+
expect(memory.sourceTaskId).toBe(task.id);
|
|
83
|
+
expect(memory.content).toContain("Output:");
|
|
84
|
+
expect(memory.content).toContain(output);
|
|
85
|
+
expect(memory.content).not.toContain("undefined");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("completed task with undefined output uses fallback", () => {
|
|
89
|
+
const task = createTaskExtended("Task without output", {
|
|
90
|
+
agentId: workerId,
|
|
91
|
+
source: "mcp",
|
|
92
|
+
priority: 50,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const output: string | undefined = undefined;
|
|
96
|
+
completeTask(task.id, output);
|
|
97
|
+
|
|
98
|
+
// Simulate store-progress logic with undefined guard
|
|
99
|
+
const taskContent = `Task: ${task.task}\n\nOutput:\n${output || "(no output)"}`;
|
|
100
|
+
|
|
101
|
+
expect(taskContent).toContain("(no output)");
|
|
102
|
+
expect(taskContent).not.toContain("undefined");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("failed task creates memory with failure reason", () => {
|
|
106
|
+
const task = createTaskExtended("Task that will fail", {
|
|
107
|
+
agentId: workerId,
|
|
108
|
+
source: "mcp",
|
|
109
|
+
priority: 50,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const failureReason = "Could not connect to external API";
|
|
113
|
+
failTask(task.id, failureReason);
|
|
114
|
+
|
|
115
|
+
// Simulate store-progress failed task memory creation
|
|
116
|
+
const taskContent = `Task: ${task.task}\n\nFailure reason:\n${failureReason}\n\nThis task failed. Learn from this to avoid repeating the mistake.`;
|
|
117
|
+
const memory = createMemory({
|
|
118
|
+
agentId: workerId,
|
|
119
|
+
content: taskContent,
|
|
120
|
+
name: `Task: ${task.task.slice(0, 80)}`,
|
|
121
|
+
scope: "agent",
|
|
122
|
+
source: "task_completion",
|
|
123
|
+
sourceTaskId: task.id,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
expect(memory.source).toBe("task_completion");
|
|
127
|
+
expect(memory.content).toContain("Failure reason:");
|
|
128
|
+
expect(memory.content).toContain(failureReason);
|
|
129
|
+
expect(memory.content).toContain("Learn from this");
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("failed task with undefined failureReason uses fallback", () => {
|
|
133
|
+
const failureReason: string | undefined = undefined;
|
|
134
|
+
|
|
135
|
+
// Simulate store-progress logic with undefined guard
|
|
136
|
+
const taskContent = `Task: Some task\n\nFailure reason:\n${failureReason || "No reason provided"}\n\nThis task failed.`;
|
|
137
|
+
|
|
138
|
+
expect(taskContent).toContain("No reason provided");
|
|
139
|
+
expect(taskContent).not.toContain("undefined");
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("short task content is skipped (< 30 chars)", () => {
|
|
143
|
+
// Simulate the length check in store-progress
|
|
144
|
+
const shortContent = "Task: X\n\nOutput:\n";
|
|
145
|
+
expect(shortContent.length).toBeLessThan(30);
|
|
146
|
+
// In store-progress, this would return early without creating memory
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// ==========================================================================
|
|
151
|
+
// P3: Swarm memory auto-promotion
|
|
152
|
+
// ==========================================================================
|
|
153
|
+
|
|
154
|
+
describe("swarm memory auto-promotion", () => {
|
|
155
|
+
test("research task type promotes to swarm scope", () => {
|
|
156
|
+
const task = createTaskExtended("Research best practices for testing", {
|
|
157
|
+
agentId: workerId,
|
|
158
|
+
source: "mcp",
|
|
159
|
+
priority: 50,
|
|
160
|
+
taskType: "research",
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
completeTask(task.id, "Found several useful patterns");
|
|
164
|
+
|
|
165
|
+
// Simulate the shouldShareWithSwarm logic
|
|
166
|
+
const shouldShareWithSwarm =
|
|
167
|
+
task.taskType === "research" ||
|
|
168
|
+
task.tags?.includes("knowledge") ||
|
|
169
|
+
task.tags?.includes("shared");
|
|
170
|
+
|
|
171
|
+
expect(shouldShareWithSwarm).toBe(true);
|
|
172
|
+
|
|
173
|
+
// Verify swarm memory can be created
|
|
174
|
+
const swarmMemory = createMemory({
|
|
175
|
+
agentId: workerId,
|
|
176
|
+
scope: "swarm",
|
|
177
|
+
name: `Shared: ${task.task.slice(0, 80)}`,
|
|
178
|
+
content: `Task completed by agent ${workerId}:\n\nTask: ${task.task}\n\nOutput:\nFound several useful patterns`,
|
|
179
|
+
source: "task_completion",
|
|
180
|
+
sourceTaskId: task.id,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
expect(swarmMemory.scope).toBe("swarm");
|
|
184
|
+
expect(swarmMemory.source).toBe("task_completion");
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("knowledge-tagged task promotes to swarm scope", () => {
|
|
188
|
+
const task = createTaskExtended("Document API conventions", {
|
|
189
|
+
agentId: workerId,
|
|
190
|
+
source: "mcp",
|
|
191
|
+
priority: 50,
|
|
192
|
+
tags: ["knowledge"],
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const shouldShareWithSwarm =
|
|
196
|
+
task.taskType === "research" ||
|
|
197
|
+
task.tags?.includes("knowledge") ||
|
|
198
|
+
task.tags?.includes("shared");
|
|
199
|
+
|
|
200
|
+
expect(shouldShareWithSwarm).toBe(true);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("shared-tagged task promotes to swarm scope", () => {
|
|
204
|
+
const task = createTaskExtended("Build shared utility", {
|
|
205
|
+
agentId: workerId,
|
|
206
|
+
source: "mcp",
|
|
207
|
+
priority: 50,
|
|
208
|
+
tags: ["shared", "utility"],
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const shouldShareWithSwarm =
|
|
212
|
+
task.taskType === "research" ||
|
|
213
|
+
task.tags?.includes("knowledge") ||
|
|
214
|
+
task.tags?.includes("shared");
|
|
215
|
+
|
|
216
|
+
expect(shouldShareWithSwarm).toBe(true);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test("epic-linked task promotes to swarm scope", () => {
|
|
220
|
+
const epic = createEpic({
|
|
221
|
+
name: "Test Epic for Promotion",
|
|
222
|
+
goal: "Test that epic-linked tasks promote to swarm scope",
|
|
223
|
+
createdByAgentId: leadId,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const task = createTaskExtended("Implement feature X for epic", {
|
|
227
|
+
agentId: workerId,
|
|
228
|
+
source: "mcp",
|
|
229
|
+
priority: 50,
|
|
230
|
+
taskType: "implementation",
|
|
231
|
+
epicId: epic.id,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const shouldShareWithSwarm =
|
|
235
|
+
task.taskType === "research" ||
|
|
236
|
+
task.tags?.includes("knowledge") ||
|
|
237
|
+
task.tags?.includes("shared") ||
|
|
238
|
+
task.epicId != null;
|
|
239
|
+
|
|
240
|
+
expect(shouldShareWithSwarm).toBe(true);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("regular task without epicId does NOT promote to swarm scope", () => {
|
|
244
|
+
const task = createTaskExtended("Fix a typo", {
|
|
245
|
+
agentId: workerId,
|
|
246
|
+
source: "mcp",
|
|
247
|
+
priority: 50,
|
|
248
|
+
taskType: "quick-fix",
|
|
249
|
+
tags: ["bug-fix"],
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const shouldShareWithSwarm =
|
|
253
|
+
task.taskType === "research" ||
|
|
254
|
+
task.tags?.includes("knowledge") ||
|
|
255
|
+
task.tags?.includes("shared") ||
|
|
256
|
+
task.epicId != null;
|
|
257
|
+
|
|
258
|
+
expect(shouldShareWithSwarm).toBe(false);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("failed task does NOT promote to swarm scope", () => {
|
|
262
|
+
const task = createTaskExtended("Research something", {
|
|
263
|
+
agentId: workerId,
|
|
264
|
+
source: "mcp",
|
|
265
|
+
priority: 50,
|
|
266
|
+
taskType: "research",
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const status = "failed";
|
|
270
|
+
// In store-progress, shouldShareWithSwarm only fires for status === "completed"
|
|
271
|
+
const shouldShareWithSwarm =
|
|
272
|
+
status === "completed" &&
|
|
273
|
+
(task.taskType === "research" ||
|
|
274
|
+
task.tags?.includes("knowledge") ||
|
|
275
|
+
task.tags?.includes("shared") ||
|
|
276
|
+
task.epicId != null);
|
|
277
|
+
|
|
278
|
+
expect(shouldShareWithSwarm).toBe(false);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// ==========================================================================
|
|
283
|
+
// P6: inject-learning tool
|
|
284
|
+
// ==========================================================================
|
|
285
|
+
|
|
286
|
+
describe("inject-learning tool logic", () => {
|
|
287
|
+
test("lead agent can inject learning into worker memory (swarm-scoped)", () => {
|
|
288
|
+
const callerAgent = getAgentById(leadId);
|
|
289
|
+
expect(callerAgent).not.toBeNull();
|
|
290
|
+
expect(callerAgent!.isLead).toBe(true);
|
|
291
|
+
|
|
292
|
+
const category = "best-practice";
|
|
293
|
+
const learning = "Always run lint before committing";
|
|
294
|
+
const content = `[Lead Feedback — ${category}]\n\n${learning}`;
|
|
295
|
+
|
|
296
|
+
const memory = createMemory({
|
|
297
|
+
agentId: workerId,
|
|
298
|
+
scope: "swarm",
|
|
299
|
+
name: `Lead feedback: ${category} — ${learning.slice(0, 60)}`,
|
|
300
|
+
content,
|
|
301
|
+
source: "manual",
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
expect(memory.agentId).toBe(workerId);
|
|
305
|
+
expect(memory.scope).toBe("swarm");
|
|
306
|
+
expect(memory.content).toContain("[Lead Feedback — best-practice]");
|
|
307
|
+
expect(memory.content).toContain(learning);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
test("non-lead agent is rejected", () => {
|
|
311
|
+
const callerAgent = getAgentById(workerId);
|
|
312
|
+
expect(callerAgent).not.toBeNull();
|
|
313
|
+
expect(callerAgent!.isLead).toBe(false);
|
|
314
|
+
|
|
315
|
+
// In the tool handler, this check prevents non-leads from injecting
|
|
316
|
+
const canInject = callerAgent!.isLead;
|
|
317
|
+
expect(canInject).toBe(false);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("injected learning is visible to target worker in memory search", () => {
|
|
321
|
+
// Create memory with embedding for searchability
|
|
322
|
+
const content = "[Lead Feedback — mistake-pattern]\n\nNever force-push to main branch";
|
|
323
|
+
const memory = createMemory({
|
|
324
|
+
agentId: workerId,
|
|
325
|
+
scope: "agent",
|
|
326
|
+
name: "Lead feedback: mistake-pattern — Never force-push to main branch",
|
|
327
|
+
content,
|
|
328
|
+
source: "manual",
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
const embedding = new Float32Array([0.7, 0.3, 0.0]);
|
|
332
|
+
updateMemoryEmbedding(memory.id, serializeEmbedding(embedding));
|
|
333
|
+
|
|
334
|
+
// Worker can find it via search
|
|
335
|
+
const results = searchMemoriesByVector(new Float32Array([0.7, 0.3, 0.0]), workerId, {
|
|
336
|
+
isLead: false,
|
|
337
|
+
scope: "agent",
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
const found = results.find((r) => r.id === memory.id);
|
|
341
|
+
expect(found).toBeDefined();
|
|
342
|
+
expect(found!.content).toContain("Never force-push");
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
test("injected learning is NOT visible to other workers", () => {
|
|
346
|
+
const content = "[Lead Feedback — preference]\n\nUse bun instead of npm";
|
|
347
|
+
const memory = createMemory({
|
|
348
|
+
agentId: workerId,
|
|
349
|
+
scope: "agent",
|
|
350
|
+
name: "Lead feedback: preference — Use bun instead of npm",
|
|
351
|
+
content,
|
|
352
|
+
source: "manual",
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const embedding = new Float32Array([0.2, 0.8, 0.1]);
|
|
356
|
+
updateMemoryEmbedding(memory.id, serializeEmbedding(embedding));
|
|
357
|
+
|
|
358
|
+
// Other worker should NOT see it
|
|
359
|
+
const results = searchMemoriesByVector(new Float32Array([0.2, 0.8, 0.1]), otherWorkerId, {
|
|
360
|
+
isLead: false,
|
|
361
|
+
scope: "agent",
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
const found = results.find((r) => r.id === memory.id);
|
|
365
|
+
expect(found).toBeUndefined();
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test("learning categories are properly formatted", () => {
|
|
369
|
+
const categories = ["mistake-pattern", "best-practice", "codebase-knowledge", "preference"];
|
|
370
|
+
|
|
371
|
+
for (const category of categories) {
|
|
372
|
+
const content = `[Lead Feedback — ${category}]\n\nSome learning`;
|
|
373
|
+
expect(content).toContain(`[Lead Feedback — ${category}]`);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// ==========================================================================
|
|
379
|
+
// P7: Memory search agent ID security
|
|
380
|
+
// ==========================================================================
|
|
381
|
+
|
|
382
|
+
describe("memory search agent ID security", () => {
|
|
383
|
+
test("agent can only search their own memories (not others)", () => {
|
|
384
|
+
// Create private memories for worker and other worker
|
|
385
|
+
const workerMemory = createMemory({
|
|
386
|
+
agentId: workerId,
|
|
387
|
+
scope: "agent",
|
|
388
|
+
name: "Worker Private Secret",
|
|
389
|
+
content: "My secret API key pattern",
|
|
390
|
+
source: "manual",
|
|
391
|
+
});
|
|
392
|
+
updateMemoryEmbedding(workerMemory.id, serializeEmbedding(new Float32Array([0.5, 0.5, 0.0])));
|
|
393
|
+
|
|
394
|
+
const otherMemory = createMemory({
|
|
395
|
+
agentId: otherWorkerId,
|
|
396
|
+
scope: "agent",
|
|
397
|
+
name: "Other Worker Secret",
|
|
398
|
+
content: "Other agent's private data",
|
|
399
|
+
source: "manual",
|
|
400
|
+
});
|
|
401
|
+
updateMemoryEmbedding(otherMemory.id, serializeEmbedding(new Float32Array([0.5, 0.5, 0.0])));
|
|
402
|
+
|
|
403
|
+
// Worker searching with their own ID should see their memory but not other's
|
|
404
|
+
const workerResults = searchMemoriesByVector(new Float32Array([0.5, 0.5, 0.0]), workerId, {
|
|
405
|
+
isLead: false,
|
|
406
|
+
scope: "all",
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
const workerNames = workerResults.map((r) => r.name);
|
|
410
|
+
expect(workerNames).toContain("Worker Private Secret");
|
|
411
|
+
expect(workerNames).not.toContain("Other Worker Secret");
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
test("missing agent ID should be rejected (endpoint logic)", () => {
|
|
415
|
+
// Simulate the endpoint logic: searchAgentId = myAgentId (from header only)
|
|
416
|
+
const myAgentId: string | undefined = undefined;
|
|
417
|
+
const searchAgentId = myAgentId; // No fallback to body.agentId
|
|
418
|
+
|
|
419
|
+
// The endpoint requires both query and searchAgentId
|
|
420
|
+
const isValid = !!searchAgentId;
|
|
421
|
+
expect(isValid).toBe(false);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
test("agent ID from header is used, not from body", () => {
|
|
425
|
+
// Simulate the fixed logic
|
|
426
|
+
const headerAgentId = workerId;
|
|
427
|
+
const _bodyAgentId = otherWorkerId; // attacker trying to access other agent's memories
|
|
428
|
+
|
|
429
|
+
// Fixed code: searchAgentId = myAgentId (from header only)
|
|
430
|
+
const searchAgentId = headerAgentId; // NOT: headerAgentId || bodyAgentId
|
|
431
|
+
|
|
432
|
+
expect(searchAgentId).toBe(workerId);
|
|
433
|
+
expect(searchAgentId).not.toBe(otherWorkerId);
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// ==========================================================================
|
|
438
|
+
// P2: Self-awareness in base prompt
|
|
439
|
+
// ==========================================================================
|
|
440
|
+
|
|
441
|
+
describe("base prompt self-awareness", () => {
|
|
442
|
+
test("base prompt includes 'How You Are Built' section", async () => {
|
|
443
|
+
const prompt = await getBasePrompt({
|
|
444
|
+
role: "worker",
|
|
445
|
+
agentId: workerId,
|
|
446
|
+
swarmUrl: "test.example.com",
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
expect(prompt).toContain("### How You Are Built");
|
|
450
|
+
expect(prompt).toContain("desplega-ai/agent-swarm");
|
|
451
|
+
expect(prompt).toContain("src/commands/runner.ts");
|
|
452
|
+
expect(prompt).toContain("src/hooks/hook.ts");
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
test("self-awareness section includes change proposal instructions", async () => {
|
|
456
|
+
const prompt = await getBasePrompt({
|
|
457
|
+
role: "worker",
|
|
458
|
+
agentId: workerId,
|
|
459
|
+
swarmUrl: "test.example.com",
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
expect(prompt).toContain("Proposing changes");
|
|
463
|
+
expect(prompt).toContain("@tarasyarema");
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
test("self-awareness is included for both worker and lead roles", async () => {
|
|
467
|
+
const workerPrompt = await getBasePrompt({
|
|
468
|
+
role: "worker",
|
|
469
|
+
agentId: workerId,
|
|
470
|
+
swarmUrl: "test.example.com",
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
const leadPrompt = await getBasePrompt({
|
|
474
|
+
role: "lead",
|
|
475
|
+
agentId: leadId,
|
|
476
|
+
swarmUrl: "test.example.com",
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
expect(workerPrompt).toContain("### How You Are Built");
|
|
480
|
+
expect(leadPrompt).toContain("### How You Are Built");
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// ==========================================================================
|
|
485
|
+
// P4: Session summary "no significant learnings" filter
|
|
486
|
+
// ==========================================================================
|
|
487
|
+
|
|
488
|
+
describe("session summary filtering", () => {
|
|
489
|
+
test("'no significant learnings' response is filtered out", () => {
|
|
490
|
+
const summary = "No significant learnings.";
|
|
491
|
+
|
|
492
|
+
const shouldIndex =
|
|
493
|
+
summary &&
|
|
494
|
+
summary.length > 20 &&
|
|
495
|
+
!summary.trim().toLowerCase().includes("no significant learnings");
|
|
496
|
+
|
|
497
|
+
expect(shouldIndex).toBe(false);
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
test("summary with actual learnings passes filter", () => {
|
|
501
|
+
const summary =
|
|
502
|
+
"- Discovered that the API requires Bearer prefix on auth headers\n- Found that bun test runs faster with --bail flag";
|
|
503
|
+
|
|
504
|
+
const shouldIndex =
|
|
505
|
+
summary &&
|
|
506
|
+
summary.length > 20 &&
|
|
507
|
+
!summary.trim().toLowerCase().includes("no significant learnings");
|
|
508
|
+
|
|
509
|
+
expect(shouldIndex).toBe(true);
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
test("very short summary is filtered out", () => {
|
|
513
|
+
const summary = "Done.";
|
|
514
|
+
|
|
515
|
+
const shouldIndex =
|
|
516
|
+
summary &&
|
|
517
|
+
summary.length > 20 &&
|
|
518
|
+
!summary.trim().toLowerCase().includes("no significant learnings");
|
|
519
|
+
|
|
520
|
+
expect(shouldIndex).toBe(false);
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
test("case-insensitive matching for 'no significant learnings'", () => {
|
|
524
|
+
const variants = [
|
|
525
|
+
"No Significant Learnings.",
|
|
526
|
+
"NO SIGNIFICANT LEARNINGS",
|
|
527
|
+
"no significant learnings",
|
|
528
|
+
" No significant learnings. ",
|
|
529
|
+
];
|
|
530
|
+
|
|
531
|
+
for (const summary of variants) {
|
|
532
|
+
const shouldIndex =
|
|
533
|
+
summary &&
|
|
534
|
+
summary.length > 20 &&
|
|
535
|
+
!summary.trim().toLowerCase().includes("no significant learnings");
|
|
536
|
+
|
|
537
|
+
expect(shouldIndex).toBe(false);
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
});
|
|
541
|
+
});
|