@desplega.ai/agent-swarm 1.49.0 → 1.52.0
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 +1 -1
- package/openapi.json +2070 -728
- package/package.json +10 -1
- package/src/agentmail/handlers.ts +65 -10
- package/src/agentmail/templates.ts +111 -0
- package/src/be/db.ts +1233 -7
- 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/019_skills.sql +65 -0
- package/src/be/migrations/020_approval_requests.sql +41 -0
- package/src/be/seed.ts +62 -0
- package/src/be/skill-parser.ts +70 -0
- package/src/be/skill-sync.ts +106 -0
- package/src/commands/runner.ts +320 -132
- package/src/commands/templates.ts +172 -0
- package/src/github/handlers.ts +292 -77
- 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/gitlab/handlers.ts +63 -22
- package/src/gitlab/templates.ts +140 -0
- package/src/heartbeat/heartbeat.ts +19 -10
- package/src/heartbeat/templates.ts +30 -0
- package/src/http/active-sessions.ts +27 -0
- package/src/http/approval-requests.ts +247 -0
- package/src/http/config.ts +3 -3
- package/src/http/index.ts +9 -2
- package/src/http/poll.ts +135 -14
- package/src/http/prompt-templates.ts +412 -0
- package/src/http/schedules.ts +35 -0
- package/src/http/skills.ts +479 -0
- package/src/http/workflows.ts +8 -0
- package/src/linear/sync.ts +28 -4
- package/src/linear/templates.ts +47 -0
- package/src/prompts/base-prompt.ts +41 -490
- 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 +15 -2
- package/src/providers/pi-mono-extension.ts +5 -1
- package/src/scheduler/scheduler.ts +125 -91
- package/src/server.ts +44 -0
- package/src/slack/assistant.ts +7 -4
- package/src/slack/channel-activity.ts +177 -0
- package/src/slack/handlers.ts +21 -6
- package/src/slack/templates.ts +55 -0
- package/src/tests/approval-requests.test.ts +735 -0
- package/src/tests/artifact-sdk.test.ts +12 -12
- package/src/tests/base-prompt.test.ts +49 -49
- package/src/tests/channel-activity.test.ts +363 -0
- package/src/tests/heartbeat.test.ts +1 -0
- package/src/tests/linear-webhook.test.ts +7 -3
- package/src/tests/pool-session-logs.test.ts +199 -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/self-improvement.test.ts +8 -7
- package/src/tests/skill-parser.test.ts +178 -0
- package/src/tests/skill-sync.test.ts +171 -0
- package/src/tests/slack-metadata-inheritance.test.ts +1 -1
- package/src/tests/slack-thread-followups.test.ts +1 -1
- package/src/tests/structured-output.test.ts +0 -4
- package/src/tests/tool-annotations.test.ts +2 -1
- package/src/tests/update-profile-agentid.test.ts +248 -0
- package/src/tests/update-profile-auth.test.ts +195 -0
- package/src/tests/workflow-async-v2.test.ts +126 -4
- package/src/tests/workflow-definition-validation.test.ts +76 -0
- package/src/tests/workflow-executors.test.ts +4 -2
- package/src/tests/workflow-retry-v2.test.ts +1 -1
- package/src/tests/workflow-schedule-trigger.test.ts +104 -0
- package/src/tests/workflow-workspace.test.ts +272 -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/request-human-input.ts +106 -0
- package/src/tools/skills/index.ts +11 -0
- package/src/tools/skills/skill-create.ts +105 -0
- package/src/tools/skills/skill-delete.ts +67 -0
- package/src/tools/skills/skill-get.ts +75 -0
- package/src/tools/skills/skill-install-remote.ts +152 -0
- package/src/tools/skills/skill-install.ts +101 -0
- package/src/tools/skills/skill-list.ts +77 -0
- package/src/tools/skills/skill-publish.ts +123 -0
- package/src/tools/skills/skill-search.ts +43 -0
- package/src/tools/skills/skill-sync-remote.ts +128 -0
- package/src/tools/skills/skill-uninstall.ts +60 -0
- package/src/tools/skills/skill-update.ts +128 -0
- package/src/tools/store-progress.ts +22 -4
- package/src/tools/task-action.ts +20 -0
- package/src/tools/templates.ts +53 -0
- package/src/tools/tool-config.ts +23 -0
- package/src/tools/update-profile.ts +106 -34
- package/src/tools/workflows/create-workflow.ts +19 -1
- package/src/tools/workflows/update-workflow.ts +16 -1
- package/src/types.ts +109 -2
- package/src/workflows/definition.ts +30 -12
- package/src/workflows/engine.ts +40 -14
- package/src/workflows/executors/agent-task.ts +14 -3
- package/src/workflows/executors/human-in-the-loop.ts +160 -0
- package/src/workflows/executors/registry.ts +2 -0
- package/src/workflows/index.ts +1 -1
- package/src/workflows/recovery.ts +72 -0
- package/src/workflows/resume.ts +162 -12
- package/src/workflows/triggers.ts +31 -2
- package/src/workflows/version.ts +2 -0
- package/.claude/settings.json +0 -84
- package/.claude/settings.local.json +0 -117
- package/.dockerignore +0 -61
- package/.editorconfig +0 -15
- package/.entire/settings.json +0 -4
- package/.env.docker.example +0 -56
- package/.env.example +0 -78
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -78
- package/.github/ISSUE_TEMPLATE/community-template.yml +0 -77
- package/.github/ISSUE_TEMPLATE/config.yml +0 -8
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -60
- package/.github/PULL_REQUEST_TEMPLATE/community-template.md +0 -29
- package/.github/workflows/ci.yml +0 -52
- package/.github/workflows/docker-and-deploy.yml +0 -132
- package/.github/workflows/merge-gate.yml +0 -233
- package/.opencode/plugins/entire.ts +0 -133
- package/.superset/config.json +0 -6
- package/.wts-config.json +0 -4
- package/.wts-setup.ts +0 -171
- package/CHANGELOG.md +0 -447
- package/CLAUDE.md +0 -521
- package/CONTRIBUTING.md +0 -315
- package/DEPLOYMENT.md +0 -622
- package/Dockerfile +0 -65
- package/Dockerfile.worker +0 -189
- package/MCP.md +0 -841
- package/UI.md +0 -40
- package/api-entrypoint.sh +0 -56
- 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/depot.json +0 -1
- package/docker-compose.example.yml +0 -350
- package/docker-compose.local.yml +0 -119
- package/docker-entrypoint.sh +0 -632
- package/docs-site/app/api/search/route.ts +0 -4
- package/docs-site/app/docs/[[...slug]]/page.tsx +0 -87
- package/docs-site/app/docs/layout.tsx +0 -12
- package/docs-site/app/globals.css +0 -24
- package/docs-site/app/layout.config.tsx +0 -34
- package/docs-site/app/layout.tsx +0 -119
- package/docs-site/app/llms-full.txt/route.ts +0 -11
- package/docs-site/app/llms.mdx/docs/[[...slug]]/route.ts +0 -24
- package/docs-site/app/llms.txt/route.ts +0 -8
- package/docs-site/app/page.tsx +0 -5
- package/docs-site/app/robots.ts +0 -13
- package/docs-site/app/sitemap.ts +0 -37
- package/docs-site/components/api-page.client.tsx +0 -4
- package/docs-site/components/api-page.tsx +0 -7
- package/docs-site/components/mdx/mermaid.tsx +0 -55
- package/docs-site/content/docs/(documentation)/architecture/agents.mdx +0 -117
- package/docs-site/content/docs/(documentation)/architecture/hooks.mdx +0 -77
- package/docs-site/content/docs/(documentation)/architecture/memory.mdx +0 -96
- package/docs-site/content/docs/(documentation)/architecture/meta.json +0 -4
- package/docs-site/content/docs/(documentation)/architecture/overview.mdx +0 -172
- package/docs-site/content/docs/(documentation)/concepts/epics.mdx +0 -98
- package/docs-site/content/docs/(documentation)/concepts/meta.json +0 -4
- package/docs-site/content/docs/(documentation)/concepts/scheduling.mdx +0 -136
- package/docs-site/content/docs/(documentation)/concepts/services.mdx +0 -104
- package/docs-site/content/docs/(documentation)/concepts/task-lifecycle.mdx +0 -148
- package/docs-site/content/docs/(documentation)/concepts/workflows.mdx +0 -209
- package/docs-site/content/docs/(documentation)/contributing.mdx +0 -158
- package/docs-site/content/docs/(documentation)/getting-started.mdx +0 -157
- package/docs-site/content/docs/(documentation)/guides/agentmail-integration.mdx +0 -79
- package/docs-site/content/docs/(documentation)/guides/deployment.mdx +0 -171
- package/docs-site/content/docs/(documentation)/guides/github-integration.mdx +0 -81
- package/docs-site/content/docs/(documentation)/guides/gitlab-integration.mdx +0 -93
- package/docs-site/content/docs/(documentation)/guides/linear-integration.mdx +0 -98
- package/docs-site/content/docs/(documentation)/guides/meta.json +0 -13
- package/docs-site/content/docs/(documentation)/guides/sentry-integration.mdx +0 -52
- package/docs-site/content/docs/(documentation)/guides/slack-integration.mdx +0 -179
- package/docs-site/content/docs/(documentation)/guides/x402-payments.mdx +0 -154
- package/docs-site/content/docs/(documentation)/index.mdx +0 -65
- package/docs-site/content/docs/(documentation)/meta.json +0 -19
- package/docs-site/content/docs/(documentation)/reference/cli.mdx +0 -241
- package/docs-site/content/docs/(documentation)/reference/environment-variables.mdx +0 -205
- package/docs-site/content/docs/(documentation)/reference/mcp-tools.mdx +0 -449
- package/docs-site/content/docs/(documentation)/reference/meta.json +0 -4
- package/docs-site/content/docs/api-reference/active-sessions.mdx +0 -9
- package/docs-site/content/docs/api-reference/agents.mdx +0 -9
- package/docs-site/content/docs/api-reference/channels.mdx +0 -9
- package/docs-site/content/docs/api-reference/config.mdx +0 -9
- package/docs-site/content/docs/api-reference/debug.mdx +0 -9
- package/docs-site/content/docs/api-reference/ecosystem.mdx +0 -9
- package/docs-site/content/docs/api-reference/epics.mdx +0 -9
- package/docs-site/content/docs/api-reference/index.mdx +0 -32
- package/docs-site/content/docs/api-reference/memory.mdx +0 -9
- package/docs-site/content/docs/api-reference/meta.json +0 -25
- package/docs-site/content/docs/api-reference/poll.mdx +0 -9
- package/docs-site/content/docs/api-reference/repos.mdx +0 -9
- package/docs-site/content/docs/api-reference/schedules.mdx +0 -9
- package/docs-site/content/docs/api-reference/session-data.mdx +0 -9
- package/docs-site/content/docs/api-reference/stats.mdx +0 -9
- package/docs-site/content/docs/api-reference/tasks.mdx +0 -9
- package/docs-site/content/docs/api-reference/trackers.mdx +0 -9
- package/docs-site/content/docs/api-reference/webhooks.mdx +0 -9
- package/docs-site/content/docs/api-reference/workflows.mdx +0 -9
- package/docs-site/content/docs/meta.json +0 -3
- package/docs-site/lib/get-llm-text.ts +0 -10
- package/docs-site/lib/openapi.ts +0 -23
- package/docs-site/lib/source.ts +0 -8
- package/docs-site/mdx-components.tsx +0 -13
- package/docs-site/next.config.mjs +0 -29
- package/docs-site/package.json +0 -35
- package/docs-site/pnpm-lock.yaml +0 -5407
- package/docs-site/postcss.config.mjs +0 -8
- package/docs-site/public/logo.png +0 -0
- package/docs-site/scripts/generate-docs.ts +0 -171
- package/docs-site/source.config.ts +0 -17
- package/docs-site/tsconfig.json +0 -46
- package/ecosystem.config.cjs +0 -66
- package/landing/next.config.ts +0 -14
- package/landing/package.json +0 -31
- package/landing/pnpm-lock.yaml +0 -1091
- package/landing/postcss.config.mjs +0 -8
- package/landing/public/apple-touch-icon.png +0 -0
- package/landing/public/favicon.ico +0 -0
- package/landing/public/logo.png +0 -0
- package/landing/public/og-image.png +0 -0
- package/landing/public/omghost-desplega.svg +0 -30
- package/landing/public/omghost-openfort.svg +0 -9
- package/landing/src/app/actions/waitlist.ts +0 -25
- package/landing/src/app/blog/openfort-hackathon/page.tsx +0 -863
- package/landing/src/app/blog/page.tsx +0 -162
- package/landing/src/app/blog/swarm-metrics/page.tsx +0 -685
- package/landing/src/app/examples/page.tsx +0 -174
- package/landing/src/app/examples/x402/page.tsx +0 -456
- package/landing/src/app/globals.css +0 -122
- package/landing/src/app/layout.tsx +0 -134
- package/landing/src/app/page.tsx +0 -27
- package/landing/src/app/robots.ts +0 -13
- package/landing/src/app/sitemap.ts +0 -44
- package/landing/src/components/architecture.tsx +0 -163
- package/landing/src/components/cta.tsx +0 -52
- package/landing/src/components/features.tsx +0 -160
- package/landing/src/components/footer.tsx +0 -100
- package/landing/src/components/hero.tsx +0 -217
- package/landing/src/components/how-it-works.tsx +0 -165
- package/landing/src/components/navbar.tsx +0 -147
- package/landing/src/components/waitlist.tsx +0 -110
- package/landing/src/components/why-choose.tsx +0 -149
- package/landing/src/components/workshops.tsx +0 -328
- package/landing/src/lib/utils.ts +0 -6
- package/landing/tsconfig.json +0 -41
- package/misc/transcripts/2026-03-09-pi-mono-e2e-verification.md +0 -154
- package/new-ui/CLAUDE.md +0 -92
- package/new-ui/README.md +0 -73
- package/new-ui/biome.json +0 -42
- package/new-ui/components.json +0 -21
- package/new-ui/index.html +0 -25
- package/new-ui/package.json +0 -49
- package/new-ui/pnpm-lock.yaml +0 -4845
- package/new-ui/public/logo.png +0 -0
- package/new-ui/src/api/client.ts +0 -814
- package/new-ui/src/api/hooks/index.ts +0 -64
- package/new-ui/src/api/hooks/use-agents.ts +0 -58
- package/new-ui/src/api/hooks/use-channels.ts +0 -115
- package/new-ui/src/api/hooks/use-config-api.ts +0 -46
- package/new-ui/src/api/hooks/use-costs.ts +0 -122
- package/new-ui/src/api/hooks/use-db-query.ts +0 -29
- package/new-ui/src/api/hooks/use-epics.ts +0 -75
- package/new-ui/src/api/hooks/use-repos.ts +0 -61
- package/new-ui/src/api/hooks/use-schedules.ts +0 -81
- package/new-ui/src/api/hooks/use-services.ts +0 -16
- package/new-ui/src/api/hooks/use-stats.ts +0 -27
- package/new-ui/src/api/hooks/use-tasks.ts +0 -89
- package/new-ui/src/api/hooks/use-workflows.ts +0 -109
- package/new-ui/src/api/types.ts +0 -549
- package/new-ui/src/app/App.tsx +0 -13
- package/new-ui/src/app/providers.tsx +0 -32
- package/new-ui/src/app/router.tsx +0 -52
- package/new-ui/src/components/layout/app-header.tsx +0 -47
- package/new-ui/src/components/layout/app-sidebar.tsx +0 -128
- package/new-ui/src/components/layout/breadcrumbs.tsx +0 -57
- package/new-ui/src/components/layout/config-guard.tsx +0 -22
- package/new-ui/src/components/layout/root-layout.tsx +0 -40
- package/new-ui/src/components/layout/swarm-switcher.tsx +0 -85
- package/new-ui/src/components/shared/command-menu.tsx +0 -131
- package/new-ui/src/components/shared/data-grid.tsx +0 -141
- package/new-ui/src/components/shared/empty-state.tsx +0 -24
- package/new-ui/src/components/shared/error-boundary.tsx +0 -72
- package/new-ui/src/components/shared/json-viewer.tsx +0 -47
- package/new-ui/src/components/shared/name-connection-modal.tsx +0 -99
- package/new-ui/src/components/shared/page-skeleton.tsx +0 -16
- package/new-ui/src/components/shared/session-log-viewer.tsx +0 -364
- package/new-ui/src/components/shared/stats-bar.tsx +0 -132
- package/new-ui/src/components/shared/status-badge.tsx +0 -131
- package/new-ui/src/components/shared/usage-summary.tsx +0 -179
- package/new-ui/src/components/ui/alert-dialog.tsx +0 -176
- package/new-ui/src/components/ui/alert.tsx +0 -60
- package/new-ui/src/components/ui/avatar.tsx +0 -96
- package/new-ui/src/components/ui/badge.tsx +0 -46
- package/new-ui/src/components/ui/button.tsx +0 -62
- package/new-ui/src/components/ui/card.tsx +0 -75
- package/new-ui/src/components/ui/command.tsx +0 -160
- package/new-ui/src/components/ui/dialog.tsx +0 -143
- package/new-ui/src/components/ui/dropdown-menu.tsx +0 -226
- package/new-ui/src/components/ui/input.tsx +0 -21
- package/new-ui/src/components/ui/label.tsx +0 -19
- package/new-ui/src/components/ui/progress.tsx +0 -26
- package/new-ui/src/components/ui/scroll-area.tsx +0 -54
- package/new-ui/src/components/ui/select.tsx +0 -175
- package/new-ui/src/components/ui/separator.tsx +0 -28
- package/new-ui/src/components/ui/sheet.tsx +0 -132
- package/new-ui/src/components/ui/sidebar.tsx +0 -691
- package/new-ui/src/components/ui/skeleton.tsx +0 -13
- package/new-ui/src/components/ui/sonner.tsx +0 -35
- package/new-ui/src/components/ui/switch.tsx +0 -33
- package/new-ui/src/components/ui/table.tsx +0 -92
- package/new-ui/src/components/ui/tabs.tsx +0 -79
- package/new-ui/src/components/ui/textarea.tsx +0 -18
- package/new-ui/src/components/ui/tooltip.tsx +0 -51
- package/new-ui/src/components/workflows/action-node.tsx +0 -53
- package/new-ui/src/components/workflows/condition-node.tsx +0 -50
- package/new-ui/src/components/workflows/graph-utils.ts +0 -124
- package/new-ui/src/components/workflows/json-tree.tsx +0 -189
- package/new-ui/src/components/workflows/node-styles.ts +0 -10
- package/new-ui/src/components/workflows/step-detail-sheet.tsx +0 -87
- package/new-ui/src/components/workflows/trigger-node.tsx +0 -41
- package/new-ui/src/components/workflows/workflow-graph.tsx +0 -65
- package/new-ui/src/hooks/use-auto-scroll.ts +0 -82
- package/new-ui/src/hooks/use-config.ts +0 -203
- package/new-ui/src/hooks/use-keyboard-shortcuts.ts +0 -41
- package/new-ui/src/hooks/use-mobile.ts +0 -19
- package/new-ui/src/hooks/use-theme.ts +0 -60
- package/new-ui/src/lib/config.ts +0 -188
- package/new-ui/src/lib/slugs.ts +0 -71
- package/new-ui/src/lib/utils.ts +0 -120
- package/new-ui/src/main.tsx +0 -11
- package/new-ui/src/pages/agents/[id]/page.tsx +0 -492
- package/new-ui/src/pages/agents/page.tsx +0 -134
- package/new-ui/src/pages/chat/page.tsx +0 -674
- package/new-ui/src/pages/config/page.tsx +0 -1109
- package/new-ui/src/pages/dashboard/page.tsx +0 -454
- package/new-ui/src/pages/debug/page.tsx +0 -275
- package/new-ui/src/pages/epics/[id]/page.tsx +0 -809
- package/new-ui/src/pages/epics/page.tsx +0 -321
- package/new-ui/src/pages/not-found/page.tsx +0 -18
- package/new-ui/src/pages/repos/page.tsx +0 -369
- package/new-ui/src/pages/schedules/[id]/page.tsx +0 -664
- package/new-ui/src/pages/schedules/page.tsx +0 -477
- package/new-ui/src/pages/services/page.tsx +0 -128
- package/new-ui/src/pages/tasks/[id]/page.tsx +0 -670
- package/new-ui/src/pages/tasks/page.tsx +0 -592
- package/new-ui/src/pages/usage/page.tsx +0 -195
- package/new-ui/src/pages/workflow-runs/[id]/page.tsx +0 -363
- package/new-ui/src/pages/workflows/[id]/page.tsx +0 -417
- package/new-ui/src/pages/workflows/page.tsx +0 -266
- package/new-ui/src/styles/ag-grid.css +0 -36
- package/new-ui/src/styles/globals.css +0 -213
- package/new-ui/test-results/.last-run.json +0 -4
- package/new-ui/tsconfig.app.json +0 -34
- package/new-ui/tsconfig.json +0 -4
- package/new-ui/tsconfig.node.json +0 -26
- package/new-ui/vercel.json +0 -4
- package/new-ui/vite.config.ts +0 -28
- package/plugin/README.md +0 -1
- package/plugin/build-pi-skills.ts +0 -233
- package/plugin/hooks/hooks.json +0 -71
- package/prek.toml +0 -75
- package/pyproject.toml +0 -9
- package/scripts/check-db-boundary.sh +0 -60
- package/scripts/e2e-docker-provider.ts +0 -820
- package/scripts/e2e-io-schemas-test.ts +0 -807
- package/scripts/e2e-provider-test.ts +0 -220
- package/scripts/e2e-workflow-redesign.sh +0 -229
- package/scripts/e2e-workflow-test.sh +0 -285
- package/scripts/e2e-workflow-test.ts +0 -857
- package/scripts/generate-mcp-docs.ts +0 -415
- package/scripts/generate-openapi.ts +0 -26
- package/scripts/measure-tool-tokens.ts +0 -118
- package/scripts/x402-e2e-test.ts +0 -195
- package/scripts/x402-test-server.ts +0 -236
- package/scripts/x402-testnet-e2e.ts +0 -668
- package/slack-manifest.json +0 -88
- package/templates-ui/README.md +0 -46
- package/templates-ui/components.json +0 -17
- package/templates-ui/eslint.config.mjs +0 -18
- package/templates-ui/next.config.ts +0 -7
- package/templates-ui/package.json +0 -35
- package/templates-ui/pnpm-lock.yaml +0 -4571
- package/templates-ui/postcss.config.mjs +0 -7
- package/templates-ui/public/file.svg +0 -1
- package/templates-ui/public/globe.svg +0 -1
- package/templates-ui/public/logo.png +0 -0
- package/templates-ui/public/next.svg +0 -1
- package/templates-ui/public/vercel.svg +0 -1
- package/templates-ui/public/window.svg +0 -1
- package/templates-ui/src/app/[category]/[name]/page.tsx +0 -89
- package/templates-ui/src/app/api/templates/[...slug]/route.ts +0 -52
- package/templates-ui/src/app/api/templates/route.ts +0 -18
- package/templates-ui/src/app/builder/page.tsx +0 -37
- package/templates-ui/src/app/globals.css +0 -94
- package/templates-ui/src/app/layout.tsx +0 -79
- package/templates-ui/src/app/page.tsx +0 -38
- package/templates-ui/src/app/robots.ts +0 -11
- package/templates-ui/src/app/sitemap.ts +0 -31
- package/templates-ui/src/components/compose-builder.tsx +0 -442
- package/templates-ui/src/components/compose-preview.tsx +0 -117
- package/templates-ui/src/components/file-preview.tsx +0 -77
- package/templates-ui/src/components/footer.tsx +0 -40
- package/templates-ui/src/components/header.tsx +0 -41
- package/templates-ui/src/components/template-card.tsx +0 -87
- package/templates-ui/src/components/template-detail.tsx +0 -125
- package/templates-ui/src/components/template-gallery.tsx +0 -263
- package/templates-ui/src/components/ui/badge.tsx +0 -36
- package/templates-ui/src/components/ui/button.tsx +0 -57
- package/templates-ui/src/components/ui/card.tsx +0 -76
- package/templates-ui/src/components/ui/separator.tsx +0 -31
- package/templates-ui/src/components/ui/tooltip.tsx +0 -32
- package/templates-ui/src/lib/compose-generator.ts +0 -241
- package/templates-ui/src/lib/templates.ts +0 -137
- package/templates-ui/src/lib/utils.ts +0 -6
- package/templates-ui/tsconfig.json +0 -34
- package/thoughts/research/2026-02-28-openfort-viem-x402-research.md +0 -679
- package/thoughts/research/2026-02-28-x402-payments-research.md +0 -686
- package/thoughts/researcher/plans/2026-02-20-agent-self-improvement-plan.md +0 -282
- package/thoughts/researcher/research/2026-02-20-agent-self-improvement.md +0 -492
- package/thoughts/shared/plans/.gitkeep +0 -0
- 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/plans/2026-02-26-mcp-tool-context-reduction.md +0 -282
- package/thoughts/shared/plans/2026-03-02-claude-context-mode-integration.md +0 -328
- package/thoughts/shared/plans/2026-03-02-code-level-heartbeat.md +0 -224
- 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/shared/research/2026-02-26-cliffy-mcp-tools.md +0 -159
- package/thoughts/shared/research/2026-03-03-database-migration-system-refactor.md +0 -337
- package/thoughts/swarm-researcher/plans/2026-02-23-openclaw-improvements-plan.md +0 -778
- package/thoughts/swarm-researcher/plans/2026-02-26-artifacts-localtunnel-plan.md +0 -1269
- package/thoughts/swarm-researcher/research/2026-02-23-openclaw-vs-agent-swarm-comparison.md +0 -411
- package/thoughts/swarm-researcher/research/2026-02-26-artifacts-localtunnel.md +0 -724
- package/thoughts/taras/brainstorms/2026-03-20-prompt-template-registry.md +0 -443
- package/thoughts/taras/brainstorms/2026-03-20-setup-cli-onboarding.md +0 -307
- 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/plans/2026-02-20-auto-improvement.md +0 -803
- package/thoughts/taras/plans/2026-02-20-env-management.md +0 -538
- package/thoughts/taras/plans/2026-02-20-memory-system.md +0 -882
- package/thoughts/taras/plans/2026-02-20-repos-knowledge.md +0 -806
- package/thoughts/taras/plans/2026-02-20-session-attach.md +0 -647
- package/thoughts/taras/plans/2026-02-20-worker-identity.md +0 -820
- package/thoughts/taras/plans/2026-02-25-feat-new-ui-visual-redesign-plan.md +0 -768
- package/thoughts/taras/plans/2026-03-04-fix-buildSystemPrompt-missing-fields.md +0 -77
- package/thoughts/taras/plans/2026-03-04-new-ui-missing-actions.md +0 -543
- package/thoughts/taras/plans/2026-03-06-one-time-scheduled-tasks.md +0 -373
- package/thoughts/taras/plans/2026-03-08-memory-self-improvement-enhancements.md +0 -512
- package/thoughts/taras/plans/2026-03-08-pi-mono-provider-implementation.md +0 -919
- package/thoughts/taras/plans/2026-03-09-templates-registry.md +0 -723
- package/thoughts/taras/plans/2026-03-10-task-working-directory.md +0 -371
- package/thoughts/taras/plans/2026-03-11-archil-per-agent-write-strategy.md +0 -621
- package/thoughts/taras/plans/2026-03-12-eliminate-inbox-route-to-tasks.md +0 -61
- package/thoughts/taras/plans/2026-03-12-slack-thread-followup-additive.md +0 -488
- package/thoughts/taras/plans/2026-03-13-slack-ai-improvements.md +0 -644
- package/thoughts/taras/plans/2026-03-16-route-wrapper-openapi.md +0 -636
- package/thoughts/taras/plans/2026-03-17-multi-api-config.md +0 -444
- package/thoughts/taras/plans/2026-03-18-agent-fs-integration.md +0 -591
- package/thoughts/taras/plans/2026-03-18-debug-db-explorer.md +0 -446
- package/thoughts/taras/plans/2026-03-18-workflow-redesign.md +0 -987
- package/thoughts/taras/plans/2026-03-19-compound-learnings.md +0 -403
- package/thoughts/taras/plans/2026-03-19-ticket-tracker-linear-integration.md +0 -860
- package/thoughts/taras/plans/2026-03-19-workflow-io-schemas-and-bugs.md +0 -899
- package/thoughts/taras/plans/2026-03-20-setup-cli-onboarding.md +0 -874
- package/thoughts/taras/plans/2026-03-20-workflow-structured-output-validation-workspace.md +0 -723
- 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/thoughts/taras/research/2026-02-19-agent-native-swarm-architecture.md +0 -390
- package/thoughts/taras/research/2026-02-19-swarm-gaps-implementation.md +0 -594
- package/thoughts/taras/research/2026-02-25-dashboard-ui-design-best-practices.md +0 -825
- package/thoughts/taras/research/2026-02-26-task-detail-page-redesign.md +0 -393
- package/thoughts/taras/research/2026-03-03-new-ui-missing-actions.md +0 -168
- package/thoughts/taras/research/2026-03-05-pi-mono-provider-research.md +0 -230
- package/thoughts/taras/research/2026-03-06-workflow-engine-design.md +0 -445
- package/thoughts/taras/research/2026-03-08-drive-loop-concept.md +0 -375
- package/thoughts/taras/research/2026-03-08-pi-mono-deep-dive.md +0 -869
- package/thoughts/taras/research/2026-03-09-templates-registry.md +0 -373
- package/thoughts/taras/research/2026-03-10-agent-working-directory.md +0 -223
- package/thoughts/taras/research/2026-03-10-configurable-event-prompts.md +0 -339
- package/thoughts/taras/research/2026-03-11-archil-production-setup.md +0 -181
- package/thoughts/taras/research/2026-03-11-archil-shared-disk-write-strategies.md +0 -437
- package/thoughts/taras/research/2026-03-13-slack-ai-features.md +0 -258
- package/thoughts/taras/research/2026-03-16-openapi-docs-generation.md +0 -335
- package/thoughts/taras/research/2026-03-16-route-wrapper-openapi.md +0 -670
- package/thoughts/taras/research/2026-03-16-slack-thread-followups-e2e.md +0 -54
- package/thoughts/taras/research/2026-03-18-agent-fs-integration.md +0 -558
- package/thoughts/taras/research/2026-03-18-linear-integration-finalization.md +0 -526
- package/thoughts/taras/research/2026-03-18-workflow-redesign.md +0 -797
- package/thoughts/taras/research/2026-03-19-workflow-node-io-schemas-and-bugs.md +0 -563
- package/thoughts/taras/research/2026-03-19-workflow-structured-output-validation-workspace.md +0 -486
- package/thoughts/taras/research/2026-03-20-prompt-template-registry.md +0 -469
- package/tsconfig.json +0 -37
|
@@ -1,882 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
date: 2026-02-20
|
|
3
|
-
planner: Claude
|
|
4
|
-
branch: claw-memory
|
|
5
|
-
repository: agent-swarm
|
|
6
|
-
topic: "Memory System Implementation (Gap 2)"
|
|
7
|
-
tags: [plan, memory, embeddings, vector-search, hooks, mcp-tools]
|
|
8
|
-
status: complete
|
|
9
|
-
autonomy: autopilot
|
|
10
|
-
related_research: thoughts/taras/research/2026-02-19-swarm-gaps-implementation.md
|
|
11
|
-
last_updated: 2026-02-20
|
|
12
|
-
last_updated_by: Claude
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
# Memory System Implementation Plan (Gap 2)
|
|
16
|
-
|
|
17
|
-
## Overview
|
|
18
|
-
|
|
19
|
-
Implement a persistent memory system for agent-swarm that allows agents to accumulate knowledge across sessions. Today, agent data is scattered across 7 storage subsystems (see [research](../research/2026-02-19-swarm-gaps-implementation.md#gap-2-memory-system-fs--sqlite-vec--openai-embeddings)) with zero cross-system search. This plan adds:
|
|
20
|
-
|
|
21
|
-
1. An `agent_memory` table with embedding-based vector search
|
|
22
|
-
2. `memory-search` and `memory-get` MCP tools for agents to query their memories
|
|
23
|
-
3. File-based auto-indexing via PostToolUse hook (writes to `{personal|shared}/memory/` get indexed)
|
|
24
|
-
4. Session summarization at Stop hook (task output/progress → memory)
|
|
25
|
-
5. Task completion memory (completed tasks auto-indexed)
|
|
26
|
-
|
|
27
|
-
## Current State Analysis
|
|
28
|
-
|
|
29
|
-
**What exists:**
|
|
30
|
-
- Agent data scattered across `agents.claudeMd`, `agent_tasks.progress/output`, `agent_log`, `session_logs`, `session_costs`, `/workspace/personal/`, `/workspace/shared/thoughts/` — none searchable cross-system
|
|
31
|
-
- Base prompt (`src/prompts/base-prompt.ts:214-219`) tells agents to create `memory.txt` or `memory.db` locally — no server-side automation
|
|
32
|
-
- No `openai` package in dependencies — embedding API not available
|
|
33
|
-
- No sqlite-vec or FTS5 extensions loaded
|
|
34
|
-
- PostToolUse hook (`src/hooks/hook.ts:620-653`) already intercepts Write/Edit for identity file sync — pattern exists to extend
|
|
35
|
-
|
|
36
|
-
**Key patterns to follow:**
|
|
37
|
-
- DB table creation: `CREATE TABLE IF NOT EXISTS` inside `initSchema` transaction (`src/be/db.ts:329-349` for `swarm_config`)
|
|
38
|
-
- DB migrations: `try { ALTER TABLE ADD COLUMN } catch { /* exists */ }` (`src/be/db.ts:381-539`)
|
|
39
|
-
- Tool registration: `createToolRegistrar(server)` pattern with `inputSchema`/`outputSchema` zod schemas (`src/tools/utils.ts:86-114`)
|
|
40
|
-
- Tool return format: `{ content: [{type: "text", text}], structuredContent: {yourAgentId, success, message, ...} }`
|
|
41
|
-
- Capability gating: `hasCapability("memory")` check in `src/server.ts:62-64`
|
|
42
|
-
- Hook HTTP calls: fire-and-forget to API server (`src/hooks/hook.ts:632-636`)
|
|
43
|
-
- Test pattern: isolated SQLite DB per test file, `node:http` handler, `beforeAll`/`afterAll` cleanup (`src/tests/session-attach.test.ts:1-15`)
|
|
44
|
-
|
|
45
|
-
### Key Discoveries:
|
|
46
|
-
- `src/be/db.ts:329-349` — `swarm_config` table uses `CREATE TABLE IF NOT EXISTS` inside init transaction with separate index statements. Memory table should follow same pattern.
|
|
47
|
-
- `src/hooks/hook.ts:627-637` — PostToolUse already checks `toolName === "Write" || "Edit"` and `editedPath` for identity sync. Memory indexing extends this exact pattern.
|
|
48
|
-
- `src/hooks/hook.ts:666-695` — Stop hook syncs CLAUDE.md and identity files. Session summarization adds a new step here.
|
|
49
|
-
- `src/tools/store-progress.ts:104-112` — Task completion (`status === "completed"`) updates agent status. Memory indexing hooks into this point.
|
|
50
|
-
- `src/server.ts:55-64` — Capability flags system. Adding `"memory"` to `DEFAULT_CAPABILITIES` string at line 57.
|
|
51
|
-
- `src/types.ts:372-386` — `SwarmConfigSchema` is the newest Zod schema. `AgentMemorySchema` follows the same pattern.
|
|
52
|
-
- No OpenAI SDK in `package.json` — needs `bun add openai`.
|
|
53
|
-
|
|
54
|
-
## Desired End State
|
|
55
|
-
|
|
56
|
-
Agents can:
|
|
57
|
-
1. Call `memory-search` with a natural language query and get semantically similar past memories
|
|
58
|
-
2. Call `memory-get` to retrieve full details of a specific memory
|
|
59
|
-
3. Write files to `/workspace/personal/memory/` or `/workspace/shared/memory/` and have them automatically indexed with embeddings
|
|
60
|
-
4. Have their completed task outputs automatically indexed as memories
|
|
61
|
-
5. Have session summaries automatically captured at session end
|
|
62
|
-
|
|
63
|
-
Verified by:
|
|
64
|
-
- Unit tests for DB functions, embedding, cosine similarity
|
|
65
|
-
- Unit tests for MCP tools against isolated DB
|
|
66
|
-
- E2E test: write a file to memory directory → search for it → find it
|
|
67
|
-
|
|
68
|
-
## Quick Verification Reference
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
bun run tsc:check # Type check
|
|
72
|
-
bun run lint:fix # Lint & format
|
|
73
|
-
bun test src/tests/memory.test.ts # Memory unit tests
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
Key files to check:
|
|
77
|
-
- `src/be/db.ts` — `agent_memory` table, CRUD functions, dedup
|
|
78
|
-
- `src/be/embedding.ts` — Embedding utility, cosine similarity
|
|
79
|
-
- `src/be/chunking.ts` — Two-stage markdown-aware text chunker
|
|
80
|
-
- `src/tools/memory-search.ts` — MCP search tool (lead-aware)
|
|
81
|
-
- `src/tools/memory-get.ts` — MCP get tool
|
|
82
|
-
- `src/hooks/hook.ts` — PostToolUse auto-indexing, Stop session summary
|
|
83
|
-
- `src/http.ts` — `POST /api/memory/index` ingestion endpoint (chunking + dedup)
|
|
84
|
-
- `src/server.ts` — Tool registration with "memory" capability
|
|
85
|
-
- `src/types.ts` — `AgentMemorySchema`
|
|
86
|
-
- `src/tests/memory.test.ts` — Unit tests
|
|
87
|
-
|
|
88
|
-
## What We're NOT Doing
|
|
89
|
-
|
|
90
|
-
- **NOT using sqlite-vec**: Using BLOB storage + JS cosine similarity for simplicity. Works identically on macOS and Linux. Good for <10K vectors. sqlite-vec can be added later as optimization.
|
|
91
|
-
- **NOT implementing BM25/hybrid search**: Pure vector search only. Keyword fallback can be added later.
|
|
92
|
-
- **NOT implementing memory garbage collection**: Just `createdAt` index for future cleanup.
|
|
93
|
-
- **NOT implementing cross-agent automatic propagation**: Agents explicitly choose scope (`agent` vs `swarm`) when writing to personal vs shared memory directories.
|
|
94
|
-
- **NOT implementing a `memory-save` MCP tool**: Memory creation happens through file writes (auto-indexed by hook) and automatic task completion indexing. Keeps the agent's workflow natural — write files, not call tools.
|
|
95
|
-
- **NOT implementing memory maintenance/curation**: OpenClaw has agents periodically review and curate their memories. We skip this for now — memories accumulate, agents search what they need.
|
|
96
|
-
|
|
97
|
-
## Implementation Approach
|
|
98
|
-
|
|
99
|
-
**Embedding strategy**: BLOB storage in regular SQLite table + brute-force cosine similarity in JS. At 512 dimensions (Float32Array), each embedding is 2KB. For 10K memories, that's 20MB of embeddings — fits easily in memory for O(n) search.
|
|
100
|
-
|
|
101
|
-
**Async indexing**: Hook calls API endpoint (`POST /api/memory/index`) which returns 202 immediately and processes embedding in background. Hooks stay fast, agent is never blocked.
|
|
102
|
-
|
|
103
|
-
**Scope model**: Memories have `scope: 'agent' | 'swarm'`. Files in `/workspace/personal/memory/` → agent scope. Files in `/workspace/shared/memory/` → swarm scope. **Lead agents see ALL memories (agent + swarm, across all agents)**. Workers see their own agent-scoped + all swarm-scoped memories.
|
|
104
|
-
|
|
105
|
-
**Embedding provider**: OpenAI `text-embedding-3-small` at 512 dimensions ($0.02/1M tokens). Simple, cheap, well-documented.
|
|
106
|
-
|
|
107
|
-
**Chunking strategy**: Two-stage markdown-aware splitter. Stage 1: split by markdown headers (`#`, `##`, `###`) to preserve document structure. Stage 2: if any section exceeds 2,000 chars (~500 tokens), apply recursive character splitting with separators `["\n\n", "\n", ". ", " "]`. Overlap of 100 chars between chunks. Files under 2,000 chars are embedded as a single chunk. Min chunk size 50 chars (skip trivially small chunks).
|
|
108
|
-
|
|
109
|
-
**Deduplication strategy**: When re-indexing a file (same `sourcePath`), use transaction-wrapped delete + re-insert: `DELETE FROM agent_memory WHERE sourcePath = ? AND agentId = ?` followed by batch INSERT of new chunks — all inside `getDb().transaction()`. This follows existing codebase patterns (`deleteServicesByAgentId` + `createSessionLogs`).
|
|
110
|
-
|
|
111
|
-
**OPENAI_API_KEY placement**: Only needed on the **API server** (`.env` on host). Workers never call OpenAI directly — they POST to the API server which handles embedding server-side. Session summarization uses `claude -p` with `CLAUDE_CODE_OAUTH_TOKEN` (already in worker containers).
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
## Phase 1: Database Schema & Embedding Infrastructure
|
|
116
|
-
|
|
117
|
-
### Overview
|
|
118
|
-
Create the `agent_memory` table, add the `openai` package, implement embedding generation and cosine similarity functions, and DB CRUD operations. This phase is pure infrastructure with no user-facing features.
|
|
119
|
-
|
|
120
|
-
### Changes Required:
|
|
121
|
-
|
|
122
|
-
#### 1. Add OpenAI dependency
|
|
123
|
-
**Command**: `bun add openai`
|
|
124
|
-
|
|
125
|
-
#### 2. Create embedding utility
|
|
126
|
-
**File**: `src/be/embedding.ts` (new file)
|
|
127
|
-
**Changes**: Implement `getEmbedding(text: string): Promise<Float32Array>` using OpenAI `text-embedding-3-small` at 512 dimensions. Implement `cosineSimilarity(a: Float32Array, b: Float32Array): number` for vector comparison. Implement `serializeEmbedding(embedding: Float32Array): Buffer` and `deserializeEmbedding(buffer: Buffer): Float32Array` for BLOB storage.
|
|
128
|
-
|
|
129
|
-
Key implementation details:
|
|
130
|
-
- Strip newlines from input text before embedding (`text.replace(/[\n\r]/g, " ")`)
|
|
131
|
-
- Handle API errors gracefully — return null on failure, let caller decide
|
|
132
|
-
- `OPENAI_API_KEY` env var required (skip embedding if not set — graceful degradation)
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
// Pseudo-code structure
|
|
136
|
-
import OpenAI from "openai";
|
|
137
|
-
|
|
138
|
-
let openai: OpenAI | null = null;
|
|
139
|
-
|
|
140
|
-
function getClient(): OpenAI | null {
|
|
141
|
-
if (!process.env.OPENAI_API_KEY) return null;
|
|
142
|
-
if (!openai) openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
|
|
143
|
-
return openai;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export async function getEmbedding(text: string): Promise<Float32Array | null> {
|
|
147
|
-
const client = getClient();
|
|
148
|
-
if (!client) return null;
|
|
149
|
-
// Call API, return Float32Array
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export function cosineSimilarity(a: Float32Array, b: Float32Array): number { ... }
|
|
153
|
-
export function serializeEmbedding(e: Float32Array): Buffer { ... }
|
|
154
|
-
export function deserializeEmbedding(b: Buffer): Float32Array { ... }
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
#### 3. Add `agent_memory` table to database
|
|
158
|
-
**File**: `src/be/db.ts`
|
|
159
|
-
**Changes**: Add `CREATE TABLE IF NOT EXISTS agent_memory` inside the `initSchema` transaction (after `swarm_config` table at line ~349). Add indexes.
|
|
160
|
-
|
|
161
|
-
```sql
|
|
162
|
-
CREATE TABLE IF NOT EXISTS agent_memory (
|
|
163
|
-
id TEXT PRIMARY KEY,
|
|
164
|
-
agentId TEXT,
|
|
165
|
-
scope TEXT NOT NULL CHECK(scope IN ('agent', 'swarm')),
|
|
166
|
-
name TEXT NOT NULL,
|
|
167
|
-
content TEXT NOT NULL,
|
|
168
|
-
summary TEXT,
|
|
169
|
-
embedding BLOB,
|
|
170
|
-
source TEXT NOT NULL CHECK(source IN ('manual', 'file_index', 'session_summary', 'task_completion')),
|
|
171
|
-
sourceTaskId TEXT,
|
|
172
|
-
sourcePath TEXT,
|
|
173
|
-
chunkIndex INTEGER DEFAULT 0,
|
|
174
|
-
totalChunks INTEGER DEFAULT 1,
|
|
175
|
-
tags TEXT DEFAULT '[]',
|
|
176
|
-
createdAt TEXT NOT NULL,
|
|
177
|
-
accessedAt TEXT NOT NULL
|
|
178
|
-
)
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
Indexes:
|
|
182
|
-
- `idx_agent_memory_agent ON agent_memory(agentId)`
|
|
183
|
-
- `idx_agent_memory_scope ON agent_memory(scope)`
|
|
184
|
-
- `idx_agent_memory_source ON agent_memory(source)`
|
|
185
|
-
- `idx_agent_memory_created ON agent_memory(createdAt)`
|
|
186
|
-
- `idx_agent_memory_source_path ON agent_memory(sourcePath)` — needed for deduplication on re-index
|
|
187
|
-
|
|
188
|
-
#### 4. Add DB CRUD functions
|
|
189
|
-
**File**: `src/be/db.ts`
|
|
190
|
-
**Changes**: Add functions following existing patterns (e.g., `createSwarmConfig` at line ~4468):
|
|
191
|
-
|
|
192
|
-
- `createMemory(data: CreateMemoryOptions): AgentMemory` — INSERT with UUID generation
|
|
193
|
-
- `getMemoryById(id: string): AgentMemory | null` — SELECT by ID, update `accessedAt`
|
|
194
|
-
- `searchMemoriesByVector(queryEmbedding: Float32Array, agentId: string, options?: { scope?, limit?, source?, isLead? }): AgentMemory[]` — Load all matching embeddings, compute cosine similarity in JS, return top-K. When `isLead: true`, return ALL memories across all agents (not just own + swarm).
|
|
195
|
-
- `listMemoriesByAgent(agentId: string, options?: { scope?, limit?, offset?, isLead? }): AgentMemory[]` — Paginated list. Lead sees all agents' memories.
|
|
196
|
-
- `deleteMemoriesBySourcePath(sourcePath: string, agentId: string): number` — Delete all chunks for a given source path (used for re-indexing)
|
|
197
|
-
- `deleteMemory(id: string): boolean` — DELETE by ID
|
|
198
|
-
- `getMemoryStats(agentId: string): { total: number, bySource: Record<string, number>, byScope: Record<string, number> }` — Aggregate stats
|
|
199
|
-
|
|
200
|
-
Internal helpers:
|
|
201
|
-
- `rowToAgentMemory(row: AgentMemoryRow): AgentMemory` — Convert DB row to typed object (following `rowToAgent` pattern at `db.ts:731-748`)
|
|
202
|
-
- `AgentMemoryRow` type for the raw DB row
|
|
203
|
-
|
|
204
|
-
#### 5. Add Zod types
|
|
205
|
-
**File**: `src/types.ts`
|
|
206
|
-
**Changes**: Add `AgentMemorySchema` and derived types after `SwarmConfigSchema` (line ~386):
|
|
207
|
-
|
|
208
|
-
```typescript
|
|
209
|
-
export const AgentMemoryScopeSchema = z.enum(["agent", "swarm"]);
|
|
210
|
-
export const AgentMemorySourceSchema = z.enum(["manual", "file_index", "session_summary", "task_completion"]);
|
|
211
|
-
|
|
212
|
-
export const AgentMemorySchema = z.object({
|
|
213
|
-
id: z.string().uuid(),
|
|
214
|
-
agentId: z.string().uuid().nullable(),
|
|
215
|
-
scope: AgentMemoryScopeSchema,
|
|
216
|
-
name: z.string().min(1).max(500),
|
|
217
|
-
content: z.string(),
|
|
218
|
-
summary: z.string().nullable(),
|
|
219
|
-
source: AgentMemorySourceSchema,
|
|
220
|
-
sourceTaskId: z.string().uuid().nullable(),
|
|
221
|
-
sourcePath: z.string().nullable(),
|
|
222
|
-
chunkIndex: z.number().int().min(0).default(0),
|
|
223
|
-
totalChunks: z.number().int().min(1).default(1),
|
|
224
|
-
tags: z.array(z.string()),
|
|
225
|
-
createdAt: z.string(),
|
|
226
|
-
accessedAt: z.string(),
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
export type AgentMemoryScope = z.infer<typeof AgentMemoryScopeSchema>;
|
|
230
|
-
export type AgentMemorySource = z.infer<typeof AgentMemorySourceSchema>;
|
|
231
|
-
export type AgentMemory = z.infer<typeof AgentMemorySchema>;
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Note: `embedding` is NOT in the Zod schema — it's a BLOB that stays server-side, never serialized to JSON.
|
|
235
|
-
|
|
236
|
-
#### 6. Create chunking utility
|
|
237
|
-
**File**: `src/be/chunking.ts` (new file)
|
|
238
|
-
**Changes**: Implement a two-stage markdown-aware chunker.
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
export interface MemoryChunk {
|
|
242
|
-
content: string;
|
|
243
|
-
chunkIndex: number;
|
|
244
|
-
totalChunks: number;
|
|
245
|
-
headings: string[]; // heading hierarchy for context
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const MAX_CHUNK_SIZE = 2000; // ~500 tokens
|
|
249
|
-
const CHUNK_OVERLAP = 100; // chars
|
|
250
|
-
const MIN_CHUNK_SIZE = 50; // skip trivially small chunks
|
|
251
|
-
|
|
252
|
-
export function chunkContent(text: string): MemoryChunk[] { ... }
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
**Stage 1**: Split by markdown headers (`#`, `##`, `###`). Each section under a heading becomes a candidate chunk, preserving heading hierarchy as metadata.
|
|
256
|
-
|
|
257
|
-
**Stage 2**: If any section exceeds `MAX_CHUNK_SIZE`, apply recursive character splitting with separators `["\n\n", "\n", ". ", " "]` and `CHUNK_OVERLAP` overlap.
|
|
258
|
-
|
|
259
|
-
**Small files**: If the entire text is under `MAX_CHUNK_SIZE`, return it as a single chunk (no splitting).
|
|
260
|
-
|
|
261
|
-
Key rules:
|
|
262
|
-
- Strip leading/trailing whitespace from chunks
|
|
263
|
-
- Skip chunks under `MIN_CHUNK_SIZE` (50 chars)
|
|
264
|
-
- Include heading hierarchy in the chunk content as a prefix (e.g., `"## Setup > Prerequisites\n\n..."`) so the embedding captures the section context
|
|
265
|
-
|
|
266
|
-
#### 7. Unit tests
|
|
267
|
-
**File**: `src/tests/memory.test.ts` (new file)
|
|
268
|
-
**Changes**: Test DB CRUD operations, cosine similarity, and chunking:
|
|
269
|
-
|
|
270
|
-
- Test `createMemory` with all fields (including `chunkIndex`, `totalChunks`)
|
|
271
|
-
- Test `getMemoryById` returns correct data
|
|
272
|
-
- Test `searchMemoriesByVector` with mock embeddings (known similarity values)
|
|
273
|
-
- Test `searchMemoriesByVector` with `isLead: true` returns ALL memories across agents
|
|
274
|
-
- Test `searchMemoriesByVector` with `isLead: false` returns only own + swarm
|
|
275
|
-
- Test `listMemoriesByAgent` pagination
|
|
276
|
-
- Test `deleteMemory`
|
|
277
|
-
- Test `deleteMemoriesBySourcePath` deletes all chunks for a path
|
|
278
|
-
- Test `getMemoryStats`
|
|
279
|
-
- Test `cosineSimilarity` with known vectors (orthogonal → 0, identical → 1, opposite → -1)
|
|
280
|
-
- Test `serializeEmbedding` / `deserializeEmbedding` roundtrip
|
|
281
|
-
- Test scope filtering: agent memories not visible to other agents, swarm memories visible to all
|
|
282
|
-
- Test `chunkContent` with small text (no split)
|
|
283
|
-
- Test `chunkContent` with markdown headers (splits on headers)
|
|
284
|
-
- Test `chunkContent` with oversized section (recursive split)
|
|
285
|
-
- Test `chunkContent` skips chunks under 50 chars
|
|
286
|
-
- Test `chunkContent` includes heading hierarchy as prefix
|
|
287
|
-
|
|
288
|
-
Test setup: isolated SQLite DB (`./test-memory.sqlite`), `initDb`/`closeDb` in `beforeAll`/`afterAll`.
|
|
289
|
-
|
|
290
|
-
### Success Criteria:
|
|
291
|
-
|
|
292
|
-
#### Automated Verification:
|
|
293
|
-
- [x] Type check passes: `bun run tsc:check`
|
|
294
|
-
- [x] Lint passes: `bun run lint:fix`
|
|
295
|
-
- [x] Memory tests pass: `bun test src/tests/memory.test.ts`
|
|
296
|
-
- [x] All existing tests still pass: `bun test`
|
|
297
|
-
|
|
298
|
-
#### Manual Verification:
|
|
299
|
-
- [x] `agent_memory` table created when starting server: `bun run start:http` then `sqlite3 agent-swarm-db.sqlite ".tables"` shows `agent_memory`
|
|
300
|
-
- [x] Embedding function works with valid `OPENAI_API_KEY`: confirmed via POST /api/memory/index — embeddings are 2048 bytes (512 float32s)
|
|
301
|
-
- [x] Embedding function returns null when `OPENAI_API_KEY` is not set (graceful degradation) — code path verified via code review (getClient returns null)
|
|
302
|
-
|
|
303
|
-
**Implementation Note**: After completing this phase, pause for manual confirmation.
|
|
304
|
-
|
|
305
|
-
---
|
|
306
|
-
|
|
307
|
-
## Phase 2: MCP Tools (memory-search, memory-get)
|
|
308
|
-
|
|
309
|
-
### Overview
|
|
310
|
-
Create two MCP tools that agents can call to search and retrieve their memories. Register them behind a "memory" capability flag.
|
|
311
|
-
|
|
312
|
-
### Changes Required:
|
|
313
|
-
|
|
314
|
-
#### 1. Create memory-search tool
|
|
315
|
-
**File**: `src/tools/memory-search.ts` (new file)
|
|
316
|
-
**Changes**: Following the tool pattern from `src/tools/get-task-details.ts`:
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
// Input schema:
|
|
320
|
-
z.object({
|
|
321
|
-
query: z.string().min(1).describe("Natural language search query."),
|
|
322
|
-
scope: z.enum(["all", "agent", "swarm"]).default("all")
|
|
323
|
-
.describe("Search scope: 'all' (own + swarm), 'agent' (own only), 'swarm' (shared only)."),
|
|
324
|
-
limit: z.number().int().min(1).max(50).default(10)
|
|
325
|
-
.describe("Max results to return."),
|
|
326
|
-
source: z.enum(["file_index", "session_summary", "task_completion", "manual"]).optional()
|
|
327
|
-
.describe("Filter by memory source type."),
|
|
328
|
-
})
|
|
329
|
-
|
|
330
|
-
// Output schema:
|
|
331
|
-
z.object({
|
|
332
|
-
yourAgentId: z.string().uuid().optional(),
|
|
333
|
-
success: z.boolean(),
|
|
334
|
-
message: z.string(),
|
|
335
|
-
results: z.array(z.object({
|
|
336
|
-
id: z.string().uuid(),
|
|
337
|
-
name: z.string(),
|
|
338
|
-
summary: z.string().nullable(),
|
|
339
|
-
source: AgentMemorySourceSchema,
|
|
340
|
-
scope: AgentMemoryScopeSchema,
|
|
341
|
-
similarity: z.number(),
|
|
342
|
-
createdAt: z.string(),
|
|
343
|
-
})).optional(),
|
|
344
|
-
})
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
Implementation:
|
|
348
|
-
1. Validate `requestInfo.agentId` exists
|
|
349
|
-
2. Look up agent to determine `isLead` status
|
|
350
|
-
3. Call `getEmbedding(query)` for the query
|
|
351
|
-
4. If embedding is null (no API key), fall back to listing recent memories
|
|
352
|
-
5. Call `searchMemoriesByVector(queryEmbedding, agentId, { scope, limit, source, isLead })`
|
|
353
|
-
- Lead agents see ALL memories (agent-scoped from all agents + swarm)
|
|
354
|
-
- Workers see own agent-scoped + all swarm-scoped
|
|
355
|
-
6. Return results with similarity scores, names, summaries (NOT full content — use `memory-get` for that)
|
|
356
|
-
|
|
357
|
-
#### 2. Create memory-get tool
|
|
358
|
-
**File**: `src/tools/memory-get.ts` (new file)
|
|
359
|
-
**Changes**: Simple retrieval tool:
|
|
360
|
-
|
|
361
|
-
```typescript
|
|
362
|
-
// Input schema:
|
|
363
|
-
z.object({
|
|
364
|
-
memoryId: z.uuid().describe("The ID of the memory to retrieve."),
|
|
365
|
-
})
|
|
366
|
-
|
|
367
|
-
// Output schema:
|
|
368
|
-
z.object({
|
|
369
|
-
yourAgentId: z.string().uuid().optional(),
|
|
370
|
-
success: z.boolean(),
|
|
371
|
-
message: z.string(),
|
|
372
|
-
memory: AgentMemorySchema.optional(),
|
|
373
|
-
})
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
Implementation:
|
|
377
|
-
1. Call `getMemoryById(memoryId)` — this also updates `accessedAt`
|
|
378
|
-
2. Return full memory details including content
|
|
379
|
-
|
|
380
|
-
#### 3. Register tools in server.ts
|
|
381
|
-
**File**: `src/server.ts`
|
|
382
|
-
**Changes**:
|
|
383
|
-
- Add imports for `registerMemorySearchTool` and `registerMemoryGetTool`
|
|
384
|
-
- Add `"memory"` to `DEFAULT_CAPABILITIES` string (line 57): `"core,task-pool,messaging,profiles,services,scheduling,epics,memory"`
|
|
385
|
-
- Add capability-gated registration block:
|
|
386
|
-
```typescript
|
|
387
|
-
if (hasCapability("memory")) {
|
|
388
|
-
registerMemorySearchTool(server);
|
|
389
|
-
registerMemoryGetTool(server);
|
|
390
|
-
}
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
#### 4. Unit tests
|
|
394
|
-
**File**: `src/tests/memory.test.ts` (extend)
|
|
395
|
-
**Changes**: Add tests for MCP tool handlers via the HTTP test pattern (following `session-attach.test.ts`):
|
|
396
|
-
|
|
397
|
-
- Test `memory-search` returns results sorted by similarity
|
|
398
|
-
- Test `memory-search` with scope filter (agent-only, swarm-only, all)
|
|
399
|
-
- Test `memory-search` fallback when no OPENAI_API_KEY (returns recent memories)
|
|
400
|
-
- Test `memory-get` returns full content
|
|
401
|
-
- Test `memory-get` with invalid ID returns error
|
|
402
|
-
- Test `memory-search` without agentId returns error
|
|
403
|
-
|
|
404
|
-
### Success Criteria:
|
|
405
|
-
|
|
406
|
-
#### Automated Verification:
|
|
407
|
-
- [x] Type check passes: `bun run tsc:check`
|
|
408
|
-
- [x] Lint passes: `bun run lint:fix`
|
|
409
|
-
- [x] Memory tests pass: `bun test src/tests/memory.test.ts`
|
|
410
|
-
- [x] All existing tests still pass: `bun test`
|
|
411
|
-
|
|
412
|
-
#### Manual Verification:
|
|
413
|
-
- [x] Start server, call `memory-search` via MCP curl session — returns results with similarity scores (0.626 for exact match, 0.280 for related, 0.195 for unrelated)
|
|
414
|
-
- [x] Call `memory-get` with returned ID — returns full content, agentId, scope, source, timestamps
|
|
415
|
-
- [x] Verify "memory" appears in capabilities list — `tools/list` shows `memory-search` and `memory-get`
|
|
416
|
-
|
|
417
|
-
**Implementation Note**: After completing this phase, pause for manual confirmation.
|
|
418
|
-
|
|
419
|
-
---
|
|
420
|
-
|
|
421
|
-
## Phase 3: Memory Ingestion API & Hook Auto-Indexing
|
|
422
|
-
|
|
423
|
-
### Overview
|
|
424
|
-
Add a server-side API endpoint for memory ingestion (async embedding + storage), then extend the PostToolUse hook to detect file writes to memory directories and trigger indexing.
|
|
425
|
-
|
|
426
|
-
### Changes Required:
|
|
427
|
-
|
|
428
|
-
#### 1. Add memory ingestion API endpoint
|
|
429
|
-
**File**: `src/http.ts`
|
|
430
|
-
**Changes**: Add `POST /api/memory/index` endpoint (following the REST pattern used by existing endpoints):
|
|
431
|
-
|
|
432
|
-
Request body:
|
|
433
|
-
```json
|
|
434
|
-
{
|
|
435
|
-
"agentId": "uuid",
|
|
436
|
-
"content": "file content or text to index",
|
|
437
|
-
"name": "human-readable label",
|
|
438
|
-
"scope": "agent" | "swarm",
|
|
439
|
-
"source": "file_index" | "session_summary" | "task_completion" | "manual",
|
|
440
|
-
"sourceTaskId": "uuid (optional)",
|
|
441
|
-
"sourcePath": "/workspace/personal/memory/something.md (optional)",
|
|
442
|
-
"tags": ["optional", "tags"]
|
|
443
|
-
}
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
Response: `202 Accepted` with `{ queued: true, memoryIds: ["uuid1", "uuid2", ...] }`
|
|
447
|
-
|
|
448
|
-
Implementation:
|
|
449
|
-
1. Validate required fields
|
|
450
|
-
2. **Dedup**: If `sourcePath` is provided, delete all existing chunks for `(sourcePath, agentId)` inside a transaction
|
|
451
|
-
3. **Chunk**: Call `chunkContent(content)` to split into chunks (most files will be 1 chunk)
|
|
452
|
-
4. Create memory records in DB for each chunk (without embedding), inside same transaction
|
|
453
|
-
5. Kick off async embedding for each chunk: `processChunkEmbeddings(memoryIds, chunks)` — no `await`
|
|
454
|
-
6. Return 202 with the memory IDs
|
|
455
|
-
|
|
456
|
-
The dedup + insert transaction:
|
|
457
|
-
```typescript
|
|
458
|
-
const memoryIds = getDb().transaction(() => {
|
|
459
|
-
// Delete old chunks if re-indexing same file
|
|
460
|
-
if (sourcePath && agentId) {
|
|
461
|
-
deleteMemoriesBySourcePath(sourcePath, agentId);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
const chunks = chunkContent(content);
|
|
465
|
-
const ids: string[] = [];
|
|
466
|
-
for (const chunk of chunks) {
|
|
467
|
-
const memory = createMemory({
|
|
468
|
-
agentId, content: chunk.content, name,
|
|
469
|
-
scope, source, sourcePath,
|
|
470
|
-
chunkIndex: chunk.chunkIndex,
|
|
471
|
-
totalChunks: chunk.totalChunks,
|
|
472
|
-
tags,
|
|
473
|
-
});
|
|
474
|
-
ids.push(memory.id);
|
|
475
|
-
}
|
|
476
|
-
return ids;
|
|
477
|
-
})();
|
|
478
|
-
```
|
|
479
|
-
|
|
480
|
-
The async embedding function:
|
|
481
|
-
```typescript
|
|
482
|
-
async function processChunkEmbeddings(memoryIds: string[], chunks: MemoryChunk[]): Promise<void> {
|
|
483
|
-
for (let i = 0; i < chunks.length; i++) {
|
|
484
|
-
try {
|
|
485
|
-
const embedding = await getEmbedding(chunks[i].content);
|
|
486
|
-
if (embedding) {
|
|
487
|
-
updateMemoryEmbedding(memoryIds[i], serializeEmbedding(embedding));
|
|
488
|
-
}
|
|
489
|
-
} catch (err) {
|
|
490
|
-
console.error(`[memory] Failed to embed chunk ${memoryIds[i]}:`, (err as Error).message);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
#### 2. Add `updateMemoryEmbedding` DB function
|
|
497
|
-
**File**: `src/be/db.ts`
|
|
498
|
-
**Changes**: Simple UPDATE for the embedding BLOB:
|
|
499
|
-
```typescript
|
|
500
|
-
export function updateMemoryEmbedding(id: string, embedding: Buffer): void {
|
|
501
|
-
getDb().prepare("UPDATE agent_memory SET embedding = ? WHERE id = ?").run(embedding, id);
|
|
502
|
-
}
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
#### 3. Extend PostToolUse hook for memory auto-indexing
|
|
506
|
-
**File**: `src/hooks/hook.ts`
|
|
507
|
-
**Changes**: After the existing identity file sync block (line 637), add memory directory detection:
|
|
508
|
-
|
|
509
|
-
```typescript
|
|
510
|
-
// Auto-index files written to memory directories
|
|
511
|
-
if (
|
|
512
|
-
(toolName === "Write" || toolName === "Edit") &&
|
|
513
|
-
editedPath &&
|
|
514
|
-
(editedPath.startsWith("/workspace/personal/memory/") ||
|
|
515
|
-
editedPath.startsWith("/workspace/shared/memory/"))
|
|
516
|
-
) {
|
|
517
|
-
try {
|
|
518
|
-
const fileContent = await Bun.file(editedPath).text();
|
|
519
|
-
const isShared = editedPath.startsWith("/workspace/shared/");
|
|
520
|
-
const fileName = editedPath.split("/").pop() ?? "unnamed";
|
|
521
|
-
|
|
522
|
-
await fetch(`${apiUrl}/api/memory/index`, {
|
|
523
|
-
method: "POST",
|
|
524
|
-
headers: {
|
|
525
|
-
"Content-Type": "application/json",
|
|
526
|
-
Authorization: `Bearer ${apiKey}`,
|
|
527
|
-
"X-Agent-ID": agentInfo.id,
|
|
528
|
-
},
|
|
529
|
-
body: JSON.stringify({
|
|
530
|
-
agentId: agentInfo.id,
|
|
531
|
-
content: fileContent,
|
|
532
|
-
name: fileName.replace(/\.\w+$/, ""), // strip extension
|
|
533
|
-
scope: isShared ? "swarm" : "agent",
|
|
534
|
-
source: "file_index",
|
|
535
|
-
sourcePath: editedPath,
|
|
536
|
-
}),
|
|
537
|
-
});
|
|
538
|
-
} catch {
|
|
539
|
-
// Non-blocking — don't interrupt the agent's workflow
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
```
|
|
543
|
-
|
|
544
|
-
This means when an agent does `Write("/workspace/personal/memory/auth-fix.md", "...")`, the hook:
|
|
545
|
-
1. Reads the file content
|
|
546
|
-
2. POSTs to the API for async embedding + indexing
|
|
547
|
-
3. The agent is never blocked
|
|
548
|
-
|
|
549
|
-
#### 4. Ensure memory directories exist
|
|
550
|
-
**File**: `docker-entrypoint.sh`
|
|
551
|
-
**Changes**: Add `mkdir -p /workspace/personal/memory /workspace/shared/memory` in the workspace directory creation section (around line ~303-347).
|
|
552
|
-
|
|
553
|
-
#### 5. Unit tests
|
|
554
|
-
**File**: `src/tests/memory.test.ts` (extend)
|
|
555
|
-
**Changes**:
|
|
556
|
-
- Test `POST /api/memory/index` endpoint creates memory records (possibly multiple chunks)
|
|
557
|
-
- Test that memory is created even without OPENAI_API_KEY (just no embedding)
|
|
558
|
-
- Test `updateMemoryEmbedding` correctly stores and retrieves embedding BLOB
|
|
559
|
-
- Test dedup: POST same `sourcePath` twice → old chunks deleted, new chunks created
|
|
560
|
-
- Test chunking: POST large content → creates multiple chunk records with correct `chunkIndex`/`totalChunks`
|
|
561
|
-
- Test that small content (<2000 chars) creates a single chunk
|
|
562
|
-
|
|
563
|
-
### Success Criteria:
|
|
564
|
-
|
|
565
|
-
#### Automated Verification:
|
|
566
|
-
- [x] Type check passes: `bun run tsc:check`
|
|
567
|
-
- [x] Lint passes: `bun run lint:fix`
|
|
568
|
-
- [x] Memory tests pass: `bun test src/tests/memory.test.ts`
|
|
569
|
-
- [x] All existing tests still pass: `bun test`
|
|
570
|
-
|
|
571
|
-
#### Manual Verification:
|
|
572
|
-
- [x] Start server with `OPENAI_API_KEY` set, POST to `/api/memory/index` via curl — returns 202 with memoryIds
|
|
573
|
-
- [x] Verify embedding column is populated after async processing — all 8 test memories have 2048-byte embeddings
|
|
574
|
-
- [x] Dedup verified: re-POST same sourcePath replaces old record (count stays 1, content updated)
|
|
575
|
-
- [x] Large content chunking verified: 5-section markdown → 5 chunks with correct chunkIndex/totalChunks
|
|
576
|
-
- [x] In Docker: write a file to `/workspace/personal/memory/api-patterns.md` — auto-indexed as `file_index` memory with embedding (2048 bytes)
|
|
577
|
-
|
|
578
|
-
**Implementation Note**: After completing this phase, pause for manual confirmation.
|
|
579
|
-
|
|
580
|
-
---
|
|
581
|
-
|
|
582
|
-
## Phase 4: Task Completion & Session Summarization
|
|
583
|
-
|
|
584
|
-
### Overview
|
|
585
|
-
Automatically index completed task outputs as memories and capture session summaries at Stop hook.
|
|
586
|
-
|
|
587
|
-
### Changes Required:
|
|
588
|
-
|
|
589
|
-
#### 1. Extend store-progress for task completion memory
|
|
590
|
-
**File**: `src/tools/store-progress.ts`
|
|
591
|
-
**Changes**: After the task completion block (line 104-112), add async memory indexing:
|
|
592
|
-
|
|
593
|
-
```typescript
|
|
594
|
-
if (status === "completed") {
|
|
595
|
-
const result = completeTask(taskId, output);
|
|
596
|
-
if (result) {
|
|
597
|
-
updatedTask = result;
|
|
598
|
-
if (existingTask.agentId) {
|
|
599
|
-
updateAgentStatusFromCapacity(existingTask.agentId);
|
|
600
|
-
}
|
|
601
|
-
// Index completed task as memory (async, non-blocking)
|
|
602
|
-
indexTaskCompletionMemory(existingTask, output).catch(() => {});
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
```
|
|
606
|
-
|
|
607
|
-
The `indexTaskCompletionMemory` function (can be in `src/be/memory.ts` or inline):
|
|
608
|
-
1. Compose content from task description + output
|
|
609
|
-
2. Create memory with `source: 'task_completion'`, `sourceTaskId: task.id`
|
|
610
|
-
3. Generate embedding async
|
|
611
|
-
|
|
612
|
-
Note: This can also be done as an HTTP call to `/api/memory/index` (keeping the embedding logic centralized), or directly via DB functions since store-progress runs server-side.
|
|
613
|
-
|
|
614
|
-
#### 2. Extend Stop hook for session summarization (via Claude Haiku)
|
|
615
|
-
**File**: `src/hooks/hook.ts`
|
|
616
|
-
**Changes**: In the Stop handler (line 674-683), after syncing CLAUDE.md and identity files, add real session summarization using `claude -p --model haiku`.
|
|
617
|
-
|
|
618
|
-
The hook has access to `msg.transcript_path` (the full session transcript) and optionally `process.env.TASK_FILE` (the current task). This should work in ALL cases — even when there's no task file (e.g., lead agent sessions, ad-hoc sessions).
|
|
619
|
-
|
|
620
|
-
**Flow:**
|
|
621
|
-
1. Read the transcript from `msg.transcript_path` (truncate to last ~20K chars if too large)
|
|
622
|
-
2. Optionally read task context from `TASK_FILE` (if available)
|
|
623
|
-
3. Call `claude -p --model haiku` to generate a structured summary
|
|
624
|
-
4. POST the summary to `/api/memory/index` with `sourceTaskId` as optional
|
|
625
|
-
|
|
626
|
-
```typescript
|
|
627
|
-
// Session summarization via Claude Haiku
|
|
628
|
-
if (agentInfo?.id && msg.transcript_path) {
|
|
629
|
-
try {
|
|
630
|
-
// 1. Read transcript (truncated to last ~20K chars)
|
|
631
|
-
let transcript = "";
|
|
632
|
-
try {
|
|
633
|
-
const fullTranscript = await Bun.file(msg.transcript_path).text();
|
|
634
|
-
transcript = fullTranscript.length > 20000
|
|
635
|
-
? fullTranscript.slice(-20000)
|
|
636
|
-
: fullTranscript;
|
|
637
|
-
} catch { /* no transcript */ }
|
|
638
|
-
|
|
639
|
-
if (transcript.length > 100) { // Skip trivial sessions
|
|
640
|
-
// 2. Optionally read task context
|
|
641
|
-
let taskContext = "";
|
|
642
|
-
let taskId: string | undefined;
|
|
643
|
-
const taskFile = process.env.TASK_FILE;
|
|
644
|
-
if (taskFile) {
|
|
645
|
-
try {
|
|
646
|
-
const taskData = JSON.parse(await Bun.file(taskFile).text());
|
|
647
|
-
taskContext = `Task: ${taskData.task || "Unknown"}`;
|
|
648
|
-
taskId = taskData.id;
|
|
649
|
-
} catch { /* no task file — that's fine */ }
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
// 3. Summarize with Claude Haiku (pipe transcript via stdin)
|
|
653
|
-
const summarizePrompt = [
|
|
654
|
-
"Summarize this agent session transcript concisely. Output ONLY the summary, no preamble.",
|
|
655
|
-
"Format as 3-7 bullet points covering:",
|
|
656
|
-
"- What was accomplished",
|
|
657
|
-
"- Key decisions made",
|
|
658
|
-
"- Problems encountered and solutions found",
|
|
659
|
-
"- Learnings useful for future sessions",
|
|
660
|
-
taskContext ? `\nTask context: ${taskContext}` : "",
|
|
661
|
-
`\nTranscript:\n${transcript}`,
|
|
662
|
-
].filter(Boolean).join("\n");
|
|
663
|
-
|
|
664
|
-
// Write prompt to temp file and pipe to claude (avoids shell arg length issues)
|
|
665
|
-
const tmpFile = `/tmp/session-summary-${Date.now()}.txt`;
|
|
666
|
-
await Bun.write(tmpFile, summarizePrompt);
|
|
667
|
-
const result = await Bun.$`cat ${tmpFile} | claude -p --model haiku --output-format json`
|
|
668
|
-
.quiet()
|
|
669
|
-
.timeout(30000); // 30s timeout
|
|
670
|
-
await Bun.$`rm -f ${tmpFile}`.quiet();
|
|
671
|
-
|
|
672
|
-
const summaryOutput = JSON.parse(result.stdout.toString());
|
|
673
|
-
const summary = summaryOutput.result ?? result.stdout.toString();
|
|
674
|
-
|
|
675
|
-
if (summary && summary.length > 20) {
|
|
676
|
-
// 4. Index as memory (async, non-blocking)
|
|
677
|
-
await fetch(`${apiUrl}/api/memory/index`, {
|
|
678
|
-
method: "POST",
|
|
679
|
-
headers: {
|
|
680
|
-
"Content-Type": "application/json",
|
|
681
|
-
Authorization: `Bearer ${apiKey}`,
|
|
682
|
-
"X-Agent-ID": agentInfo.id,
|
|
683
|
-
},
|
|
684
|
-
body: JSON.stringify({
|
|
685
|
-
agentId: agentInfo.id,
|
|
686
|
-
content: summary,
|
|
687
|
-
name: taskContext
|
|
688
|
-
? `Session: ${taskContext.slice(0, 80)}`
|
|
689
|
-
: `Session: ${new Date().toISOString().slice(0, 16)}`,
|
|
690
|
-
scope: "agent",
|
|
691
|
-
source: "session_summary",
|
|
692
|
-
...(taskId ? { sourceTaskId: taskId } : {}),
|
|
693
|
-
}),
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
} catch {
|
|
698
|
-
// Non-blocking — session summarization failure should never block shutdown
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
```
|
|
702
|
-
|
|
703
|
-
**Key design decisions:**
|
|
704
|
-
- Uses `claude -p --model haiku` — fast (~2-5s), cheap, runs inside the container where Claude CLI is installed
|
|
705
|
-
- Prompt written to temp file and piped via stdin (avoids shell argument length limits with large transcripts)
|
|
706
|
-
- 30s timeout to avoid blocking shutdown indefinitely
|
|
707
|
-
- Works without a task file (for lead sessions, ad-hoc work, etc.)
|
|
708
|
-
- `sourceTaskId` is optional — null for sessions without a task
|
|
709
|
-
- Session memories are **always `scope: 'agent'`** and linked to the specific agent's ID. Lead agents can see all session memories from all agents via the `isLead` search path.
|
|
710
|
-
- Transcript truncated to last 20K chars to stay within haiku's context and keep cost minimal
|
|
711
|
-
- Output format is JSON to reliably extract the result
|
|
712
|
-
- Uses `CLAUDE_CODE_OAUTH_TOKEN` (already in container) — does NOT need `OPENAI_API_KEY` (that's on the API server side for embedding)
|
|
713
|
-
|
|
714
|
-
#### 3. Unit tests
|
|
715
|
-
**File**: `src/tests/memory.test.ts` (extend)
|
|
716
|
-
**Changes**:
|
|
717
|
-
- Test that completing a task via `store-progress` creates a memory with `source: 'task_completion'`
|
|
718
|
-
- Test that trivial task outputs (short content) are not indexed
|
|
719
|
-
- Test the memory ingestion API with optional `sourceTaskId` (null allowed)
|
|
720
|
-
- Test that the session summary content structure is correct (mock the claude call in tests)
|
|
721
|
-
|
|
722
|
-
### Success Criteria:
|
|
723
|
-
|
|
724
|
-
#### Automated Verification:
|
|
725
|
-
- [x] Type check passes: `bun run tsc:check`
|
|
726
|
-
- [x] Lint passes: `bun run lint:fix`
|
|
727
|
-
- [x] Memory tests pass: `bun test src/tests/memory.test.ts`
|
|
728
|
-
- [x] All existing tests still pass: `bun test`
|
|
729
|
-
|
|
730
|
-
#### Manual Verification:
|
|
731
|
-
- [x] Complete a task via `store-progress` MCP tool — `task_completion` memory created with embedding (2048 bytes)
|
|
732
|
-
- [x] Stop a Docker session, verify `session_summary` memory — Haiku generates bullet-point summaries (accomplishments, workflow, blockers)
|
|
733
|
-
- [x] Stop a session without a task file (lead agent) — summarization works, uses date-based name (`Session: 2026-02-20T11:39`), no sourceTaskId
|
|
734
|
-
- [x] Search for session content via `memory-search` — "Redis caching TTL" query returns task completion memory at 0.626 similarity
|
|
735
|
-
- [x] Summarization doesn't significantly delay shutdown — Haiku responds in ~5-10s, 30s timeout as safety net
|
|
736
|
-
- [x] **Bug found & fixed**: Stop hook spawning `claude -p --model haiku` triggered recursive hook invocation (fork bomb). Fixed with `SKIP_SESSION_SUMMARY` env var guard.
|
|
737
|
-
|
|
738
|
-
**Implementation Note**: After completing this phase, pause for manual confirmation.
|
|
739
|
-
|
|
740
|
-
---
|
|
741
|
-
|
|
742
|
-
## Phase 5: Prompt & Template Updates
|
|
743
|
-
|
|
744
|
-
### Overview
|
|
745
|
-
Update the agent prompts and templates to inform agents about the memory system and how to use it.
|
|
746
|
-
|
|
747
|
-
### Changes Required:
|
|
748
|
-
|
|
749
|
-
#### 1. Update base prompt memory section
|
|
750
|
-
**File**: `src/prompts/base-prompt.ts`
|
|
751
|
-
**Changes**: Replace the existing `#### Memory` section (lines 214-219) with updated instructions inspired by [OpenClaw's AGENTS.md](https://github.com/openclaw/openclaw/blob/main/docs/reference/templates/AGENTS.md) "Write It Down" philosophy:
|
|
752
|
-
|
|
753
|
-
```markdown
|
|
754
|
-
#### Memory
|
|
755
|
-
|
|
756
|
-
**Your memory is limited — if you want to remember something, WRITE IT TO A FILE.**
|
|
757
|
-
Mental notes don't survive session restarts. Files do. Text > Brain.
|
|
758
|
-
|
|
759
|
-
**Session boot:** At the start of each session, use `memory-search` to recall relevant context for your current task. Your past learnings are searchable.
|
|
760
|
-
|
|
761
|
-
**Saving memories:** Write important learnings, patterns, decisions, and solutions to files in your memory directories. They are automatically indexed and become searchable via `memory-search`:
|
|
762
|
-
- `/workspace/personal/memory/` — Private to you, searchable only by you
|
|
763
|
-
- `/workspace/shared/memory/` — Shared with all agents, searchable by everyone
|
|
764
|
-
|
|
765
|
-
When you solve a hard problem, fix a tricky bug, or learn something about the codebase — write it down immediately. Don't wait until the end of the session.
|
|
766
|
-
|
|
767
|
-
Example: `Write("/workspace/personal/memory/auth-header-fix.md", "The API requires Bearer prefix on all auth headers. Without it, you get a misleading 403 instead of 401.")`
|
|
768
|
-
|
|
769
|
-
**Memory tools:**
|
|
770
|
-
- `memory-search` — Search your memories with natural language queries. Returns summaries with IDs.
|
|
771
|
-
- `memory-get` — Retrieve full details of a specific memory by ID.
|
|
772
|
-
|
|
773
|
-
**What gets auto-indexed (no action needed from you):**
|
|
774
|
-
- Files written to the memory directories above (via PostToolUse hook)
|
|
775
|
-
- Completed task outputs (when you call store-progress with status: completed)
|
|
776
|
-
- Session summaries (captured automatically when your session ends)
|
|
777
|
-
|
|
778
|
-
**When to write memories:**
|
|
779
|
-
- You solved a problem → write the solution
|
|
780
|
-
- You learned a codebase pattern → write the pattern
|
|
781
|
-
- You made a mistake → write what went wrong and how to avoid it
|
|
782
|
-
- Someone says "remember this" → write it down
|
|
783
|
-
- You discovered an important configuration → write it
|
|
784
|
-
|
|
785
|
-
You also still have `/workspace/personal/` for general file persistence and `sqlite3` for local structured data.
|
|
786
|
-
```
|
|
787
|
-
|
|
788
|
-
#### 2. Update default CLAUDE.md template
|
|
789
|
-
**File**: `src/be/db.ts`
|
|
790
|
-
**Changes**: In `generateDefaultClaudeMd()` (line ~2200), add a memory section to the template. Inspired by OpenClaw's two-tier approach (daily logs + curated memory):
|
|
791
|
-
|
|
792
|
-
```markdown
|
|
793
|
-
### Memory
|
|
794
|
-
- Use `memory-search` to recall past experience before starting new tasks
|
|
795
|
-
- Write important learnings to `/workspace/personal/memory/` files
|
|
796
|
-
- Share useful knowledge to `/workspace/shared/memory/` for the swarm
|
|
797
|
-
```
|
|
798
|
-
|
|
799
|
-
#### 3. Add OPENAI_API_KEY to env documentation
|
|
800
|
-
**File**: `.env.example` (or `.env` if no `.env.example` exists)
|
|
801
|
-
**Changes**: Add `OPENAI_API_KEY=` with a comment:
|
|
802
|
-
```bash
|
|
803
|
-
# Memory system - OpenAI embeddings (API server only, NOT needed in workers)
|
|
804
|
-
# Optional: system works without it but memory search degrades to recency-based
|
|
805
|
-
OPENAI_API_KEY=
|
|
806
|
-
```
|
|
807
|
-
|
|
808
|
-
**Important**: This goes in the **API server's** `.env` only. Do NOT add to `.env.docker` or `.env.docker-lead` — workers don't call OpenAI directly. Workers POST to the API server which handles embedding server-side. Session summarization in workers uses `claude -p` with the existing `CLAUDE_CODE_OAUTH_TOKEN`.
|
|
809
|
-
|
|
810
|
-
### Success Criteria:
|
|
811
|
-
|
|
812
|
-
#### Automated Verification:
|
|
813
|
-
- [x] Type check passes: `bun run tsc:check`
|
|
814
|
-
- [x] Lint passes: `bun run lint:fix`
|
|
815
|
-
- [x] All tests pass: `bun test`
|
|
816
|
-
|
|
817
|
-
#### Manual Verification:
|
|
818
|
-
- [x] Start a fresh agent (join-swarm), verify the default CLAUDE.md includes memory instructions — confirmed: "Memory" section with `memory-search` guidance
|
|
819
|
-
- [x] Check the system prompt includes updated memory tool documentation — confirmed: base-prompt.ts has memory-search, memory-get, auto-indexed docs
|
|
820
|
-
- [x] Verify `.env.example` documents `OPENAI_API_KEY` — confirmed at line 44
|
|
821
|
-
|
|
822
|
-
**Implementation Note**: After completing this phase, pause for manual confirmation.
|
|
823
|
-
|
|
824
|
-
---
|
|
825
|
-
|
|
826
|
-
## Testing Strategy
|
|
827
|
-
|
|
828
|
-
### Unit Tests (`src/tests/memory.test.ts`)
|
|
829
|
-
- Isolated SQLite DB (`./test-memory.sqlite`)
|
|
830
|
-
- Test all DB CRUD functions with known data
|
|
831
|
-
- Test cosine similarity with mathematically verifiable vectors
|
|
832
|
-
- Test embedding serialization/deserialization roundtrip
|
|
833
|
-
- Mock OpenAI API calls for tool tests (or use known pre-computed embeddings)
|
|
834
|
-
- Test scope filtering (agent vs swarm visibility)
|
|
835
|
-
- Test memory ingestion endpoint
|
|
836
|
-
- Test store-progress memory creation
|
|
837
|
-
|
|
838
|
-
### Integration Tests
|
|
839
|
-
- MCP tool tests via HTTP handler (following `session-attach.test.ts` pattern)
|
|
840
|
-
- Memory search with pre-seeded embeddings
|
|
841
|
-
- Memory get with valid/invalid IDs
|
|
842
|
-
|
|
843
|
-
### Manual E2E
|
|
844
|
-
```bash
|
|
845
|
-
# 1. Start API server
|
|
846
|
-
OPENAI_API_KEY=sk-... bun run start:http
|
|
847
|
-
|
|
848
|
-
# 2. Create a memory via API
|
|
849
|
-
curl -X POST http://localhost:3013/api/memory/index \
|
|
850
|
-
-H "Authorization: Bearer 123123" \
|
|
851
|
-
-H "Content-Type: application/json" \
|
|
852
|
-
-H "X-Agent-ID: $(uuidgen)" \
|
|
853
|
-
-d '{"agentId":"<agent-uuid>","content":"The auth header needs Bearer prefix","name":"auth-fix","scope":"agent","source":"manual"}'
|
|
854
|
-
|
|
855
|
-
# 3. Wait 2s for async embedding
|
|
856
|
-
sleep 2
|
|
857
|
-
|
|
858
|
-
# 4. Verify memory exists
|
|
859
|
-
sqlite3 agent-swarm-db.sqlite "SELECT id, name, source, length(embedding) FROM agent_memory"
|
|
860
|
-
|
|
861
|
-
# 5. Search via MCP tool (requires MCP session - see CLAUDE.md "MCP Tool Testing")
|
|
862
|
-
# Initialize session, then:
|
|
863
|
-
curl -s -X POST http://localhost:3013/mcp \
|
|
864
|
-
-H "Authorization: Bearer 123123" \
|
|
865
|
-
-H "Content-Type: application/json" \
|
|
866
|
-
-H "Accept: application/json, text/event-stream" \
|
|
867
|
-
-H "X-Agent-ID: <agent-uuid>" \
|
|
868
|
-
-H "mcp-session-id: $SESSION_ID" \
|
|
869
|
-
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"memory-search","arguments":{"query":"authentication header","limit":5}}}'
|
|
870
|
-
|
|
871
|
-
# 6. Docker E2E (full hook integration)
|
|
872
|
-
# Build worker: docker build -f Dockerfile.worker -t agent-swarm-worker:memory .
|
|
873
|
-
# Start worker, create a task that writes to /workspace/personal/memory/
|
|
874
|
-
# Verify memory appears in DB after task completes
|
|
875
|
-
```
|
|
876
|
-
|
|
877
|
-
## References
|
|
878
|
-
|
|
879
|
-
- **Research document**: [`thoughts/taras/research/2026-02-19-swarm-gaps-implementation.md`](../research/2026-02-19-swarm-gaps-implementation.md) — Gap 2: Memory System section (lines 88-221)
|
|
880
|
-
- **Related research**: [`thoughts/taras/research/2026-02-19-agent-native-swarm-architecture.md`](../research/2026-02-19-agent-native-swarm-architecture.md) — OpenClaw's self-learning loop analysis
|
|
881
|
-
- **Identity implementation (Gap 1)**: [`thoughts/taras/plans/2026-02-20-worker-identity.md`](2026-02-20-worker-identity.md) — Pattern reference for the identity system this builds on
|
|
882
|
-
- **Session attachment (Gap 3)**: [`thoughts/taras/plans/2026-02-20-session-attach.md`](2026-02-20-session-attach.md) — Session continuity that memory enhances
|