@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,723 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
date: 2026-03-20
|
|
3
|
-
topic: "Workflow: Structured Output, Validation Fixes, Workspace Scoping"
|
|
4
|
-
status: verified
|
|
5
|
-
author: taras+claude
|
|
6
|
-
autonomy: critical
|
|
7
|
-
commit-per-phase: true
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# Workflow: Structured Output, Validation Fixes, Workspace Scoping
|
|
11
|
-
|
|
12
|
-
## Overview
|
|
13
|
-
|
|
14
|
-
Four features to close gaps in the workflow engine: workspace scoping for agent-tasks, a validation retry bug fix, structured output extraction from agent-tasks, and validation executor adapter normalization. These are ordered by complexity (lowest first) to deliver value incrementally.
|
|
15
|
-
|
|
16
|
-
**Cross-node validation nodes** (backward edges, cycle detection, step invalidation) are explicitly deferred to a separate plan.
|
|
17
|
-
|
|
18
|
-
## Current State Analysis
|
|
19
|
-
|
|
20
|
-
**Workspace scoping**: `AgentTaskConfigSchema` (agent-task.ts:8-14) only exposes `template`, `agentId`, `tags`, `priority`, `offerMode`. The DB layer's `CreateTaskOptions` (db.ts:1707-1740) already supports `dir`, `vcsRepo`, `model`, `parentTaskId`. The runner already resolves cwd from `task.dir` > `vcsRepo clonePath` > `process.cwd()` (runner.ts:2150-2172). The gap is simply that the workflow executor doesn't forward these fields.
|
|
21
|
-
|
|
22
|
-
**Validation bug**: The retry poller (retry-poller.ts:77-128) re-runs executors after a validation-triggered retry but never calls `runStepValidation()` on the result. Validation only runs in `executeStep()` (engine.ts:447-475). This means a retried step's output is never re-validated.
|
|
23
|
-
|
|
24
|
-
**Structured output**: Task output is always `z.string().optional()` (types.ts:98). `store-progress` (store-progress.ts:124) stores raw strings. There's no way to extract structured data from agent output. The `raw-llm` executor already uses `generateObject()` with AI SDK (raw-llm.ts:47-53), so the extraction pattern exists.
|
|
25
|
-
|
|
26
|
-
**Validation executor adapters**: The pass/fail contract is hardcoded at validation.ts:53-56 (`result.output.pass === true`). Only the `validate` executor produces `{ pass: boolean }`. Other executors (`script`, `property-match`, `raw-llm`) have different output shapes and always "fail" the check.
|
|
27
|
-
|
|
28
|
-
### Key Discoveries:
|
|
29
|
-
- Runner cwd resolution is robust: validates `existsSync()` + `statSync()`, falls back gracefully (runner.ts:2154-2167)
|
|
30
|
-
- `deepInterpolate()` already handles `{{token}}` replacement in all config fields (engine.ts:356), so new fields like `dir: "{{repo_path}}"` work automatically
|
|
31
|
-
- Retry poller uses `setTimeout` chaining (not `setInterval`) to prevent overlap (retry-poller.ts:135)
|
|
32
|
-
- `store-progress` runs memory indexing AFTER task completion (store-progress.ts:178-232) — structured output should be validated BEFORE `completeTask()` call
|
|
33
|
-
- The `validate` executor already uses AI SDK's `generateObject()` with OpenRouter (validate.ts:114-141)
|
|
34
|
-
|
|
35
|
-
## Desired End State
|
|
36
|
-
|
|
37
|
-
1. **Workspace scoping**: Workflow `agent-task` nodes can set `dir`, `vcsRepo`, `model`, `parentTaskId` in their config. These flow through to the created task and the runner resolves the working directory accordingly.
|
|
38
|
-
|
|
39
|
-
2. **Validation bug fixed**: After a validation-triggered retry succeeds, the retry poller re-runs `runStepValidation()` before checkpointing success.
|
|
40
|
-
|
|
41
|
-
3. **Structured output**: Tasks can declare an `outputSchema` (JSON Schema). When set:
|
|
42
|
-
- The agent's prompt includes the schema so it knows what structure to produce
|
|
43
|
-
- `store-progress` validates output against the schema; invalid output fails the tool call (not the task), giving the agent a chance to retry
|
|
44
|
-
- Claude adapter: if session ends without structured output, a fallback extraction call (`claude -p --json-schema`) produces structured data
|
|
45
|
-
- Pi-mono adapter: no fallback — task fails if no valid structured output
|
|
46
|
-
- Workflow `agent-task` nodes can set `outputSchema` in config, forwarded to the task
|
|
47
|
-
|
|
48
|
-
4. **Validation executor adapters**: Any executor can be used as a validator. The validation system normalizes output to `{ pass }` using an adapter layer: `script.exitCode === 0 → pass`, `property-match.passed → pass`, etc.
|
|
49
|
-
|
|
50
|
-
## Quick Verification Reference
|
|
51
|
-
|
|
52
|
-
Common commands:
|
|
53
|
-
- `bun run tsc:check` — TypeScript type check
|
|
54
|
-
- `bun run lint:fix` — Biome lint + format
|
|
55
|
-
- `bun test` — All unit tests
|
|
56
|
-
- `bun test src/tests/<file>.test.ts` — Specific test
|
|
57
|
-
|
|
58
|
-
Key files:
|
|
59
|
-
- `src/workflows/executors/agent-task.ts` — Agent-task executor (config schema + task creation)
|
|
60
|
-
- `src/workflows/validation.ts` — Validation orchestrator (pass/fail contract)
|
|
61
|
-
- `src/workflows/retry-poller.ts` — Retry loop
|
|
62
|
-
- `src/tools/store-progress.ts` — MCP tool for task completion
|
|
63
|
-
- `src/types.ts` — All Zod schemas
|
|
64
|
-
- `src/commands/runner.ts` — Task runner (prompt building, cwd resolution)
|
|
65
|
-
|
|
66
|
-
## What We're NOT Doing
|
|
67
|
-
|
|
68
|
-
- **Cross-node validation nodes**: No backward edges, cycle detection, or step invalidation. Deferred to a separate plan.
|
|
69
|
-
- **UI changes**: No dashboard changes for structured output display or validation status.
|
|
70
|
-
- **New dependencies**: AI SDK is already present. No new packages.
|
|
71
|
-
- **Full JSON Schema support**: The existing `validateJsonSchema()` is a minimal validator (supports `type`, `required`, `properties` only). We will extend it to also support `enum` and `const`, but advanced features like `pattern`, `anyOf`/`oneOf`, `$ref`, `additionalProperties` are out of scope for this plan.
|
|
72
|
-
|
|
73
|
-
## Implementation Approach
|
|
74
|
-
|
|
75
|
-
Ordered by complexity (lowest first). Each phase is independently testable and committable.
|
|
76
|
-
|
|
77
|
-
1. **Workspace scoping** — Pure config passthrough, no new logic
|
|
78
|
-
2. **Validation bug fix** — Small, targeted fix in retry poller
|
|
79
|
-
3. **Structured output** — Largest feature, builds on existing AI SDK patterns
|
|
80
|
-
4. **Validation executor adapters** — Normalize pass/fail contract
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## Phase 1: Workspace Scoping for Agent-Tasks
|
|
85
|
-
|
|
86
|
-
### Overview
|
|
87
|
-
Extend `AgentTaskConfigSchema` to expose `dir`, `vcsRepo`, `model`, and `parentTaskId` fields, and forward them to `createTaskExtended()`. The runner and DB layer already handle these fields — the workflow executor just doesn't pass them through.
|
|
88
|
-
|
|
89
|
-
### Changes Required:
|
|
90
|
-
|
|
91
|
-
#### 1. Extend AgentTaskConfigSchema
|
|
92
|
-
**File**: `src/workflows/executors/agent-task.ts`
|
|
93
|
-
**Changes**:
|
|
94
|
-
- Add optional fields to `AgentTaskConfigSchema` (after line 14):
|
|
95
|
-
```typescript
|
|
96
|
-
dir: z.string().min(1).optional(),
|
|
97
|
-
vcsRepo: z.string().min(1).optional(),
|
|
98
|
-
model: z.string().min(1).optional(),
|
|
99
|
-
parentTaskId: z.string().uuid().optional(),
|
|
100
|
-
```
|
|
101
|
-
- Note: `dir` does NOT enforce `.startsWith("/")` here because the value may come from interpolation (e.g., `"{{repo_path}}"`) and the runner already validates the path at runtime (runner.ts:2154-2167).
|
|
102
|
-
|
|
103
|
-
#### 2. Forward fields to createTaskExtended
|
|
104
|
-
**File**: `src/workflows/executors/agent-task.ts`
|
|
105
|
-
**Changes**:
|
|
106
|
-
- In the `execute()` method's `createTaskExtended()` call (lines 64-72), add the new fields:
|
|
107
|
-
```typescript
|
|
108
|
-
dir: config.dir,
|
|
109
|
-
vcsRepo: config.vcsRepo,
|
|
110
|
-
model: config.model,
|
|
111
|
-
parentTaskId: config.parentTaskId,
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
#### 3. Unit test
|
|
115
|
-
**File**: `src/tests/workflow-agent-task.test.ts` (new file)
|
|
116
|
-
**Changes**:
|
|
117
|
-
- Test that `AgentTaskConfigSchema` parses configs with new fields
|
|
118
|
-
- Test that `execute()` creates tasks with `dir`, `vcsRepo`, `model`, `parentTaskId` set
|
|
119
|
-
- Use isolated SQLite DB (pattern from existing tests)
|
|
120
|
-
|
|
121
|
-
### Success Criteria:
|
|
122
|
-
|
|
123
|
-
#### Automated Verification:
|
|
124
|
-
- [x] Types pass: `bun run tsc:check` ✓
|
|
125
|
-
- [x] Lint passes: `bun run lint:fix` ✓
|
|
126
|
-
- [x] New test passes: `bun test src/tests/workflow-agent-task.test.ts` (6/6) ✓
|
|
127
|
-
- [x] All tests pass: `bun test` (1657/1657) ✓
|
|
128
|
-
|
|
129
|
-
#### Manual Verification:
|
|
130
|
-
- [x] Create a workflow with `agent-task` node that includes `dir: "/workspace/repos/agent-swarm"` and verify the created task has `dir` set via `GET /api/tasks` ✓ (task created with `dir: "/workspace/repos/agent-swarm"`, `source: "workflow"`)
|
|
131
|
-
- [x] Create a workflow with interpolated `dir: "{{trigger.repo_path}}"` and trigger with `{ "repo_path": "/workspace/repos/test" }` — verify interpolation works ✓ (task created with `dir: "/workspace/repos/test"`, `task: "List files in /workspace/repos/test"`)
|
|
132
|
-
|
|
133
|
-
**Note**: Interpolation path must use `{{trigger.repo_path}}` (not `{{repo_path}}`) since trigger data is stored under `ctx.trigger`.
|
|
134
|
-
|
|
135
|
-
**Committed**: `405d679` — `feat(workflow): add workspace scoping to agent-task executor`
|
|
136
|
-
|
|
137
|
-
---
|
|
138
|
-
|
|
139
|
-
## Phase 2: Validation Retry Bug Fix
|
|
140
|
-
|
|
141
|
-
### Overview
|
|
142
|
-
Fix the retry poller to re-run `runStepValidation()` after successfully re-executing a step that was retried due to validation failure. Currently, the poller bypasses validation on retry, meaning a step's output is only validated on its first execution.
|
|
143
|
-
|
|
144
|
-
### Changes Required:
|
|
145
|
-
|
|
146
|
-
#### 1. Add validation re-check in retry poller
|
|
147
|
-
**File**: `src/workflows/retry-poller.ts`
|
|
148
|
-
**Changes**:
|
|
149
|
-
- After the executor succeeds (around line 96), before calling `checkpointStep()`:
|
|
150
|
-
1. Check if the node has a `validation` config
|
|
151
|
-
2. If yes, call `runStepValidation()` with the result output
|
|
152
|
-
3. If validation returns `"retry"`: call `checkpointStepFailure()` again (same as lines 84-95) to schedule another retry, and `continue` to the next step
|
|
153
|
-
4. If validation returns `"halt"`: mark step and run as failed
|
|
154
|
-
5. If validation returns `"pass"`: proceed to `checkpointStep()` as before
|
|
155
|
-
- Import `runStepValidation` from `./validation`
|
|
156
|
-
|
|
157
|
-
#### 2. Unit test
|
|
158
|
-
**File**: `src/tests/workflow-retry-validation.test.ts` (new file)
|
|
159
|
-
**Changes**:
|
|
160
|
-
- Test: step with validation + retry → first execution fails validation → retry poller re-executes → poller re-validates the result
|
|
161
|
-
- Test: retry succeeds but validation still fails → another retry is scheduled (not infinite — respects maxRetries)
|
|
162
|
-
- Test: retry succeeds and validation passes → step checkpointed, graph continues
|
|
163
|
-
|
|
164
|
-
### Success Criteria:
|
|
165
|
-
|
|
166
|
-
#### Automated Verification:
|
|
167
|
-
- [x] Types pass: `bun run tsc:check` ✓
|
|
168
|
-
- [x] Lint passes: `bun run lint:fix` ✓
|
|
169
|
-
- [x] New test passes: `bun test src/tests/workflow-retry-validation.test.ts` (3/3) ✓
|
|
170
|
-
- [x] All tests pass: `bun test` (1660/1660) ✓
|
|
171
|
-
|
|
172
|
-
#### Manual Verification:
|
|
173
|
-
- [x] Create a workflow with `raw-llm` node + LLM-based validation (`mustPass: true`, `retry: { maxRetries: 3 }`). Validation required number > 95 (5% pass rate). ✓ Verified: LLM generated numbers ≤ 95 on all attempts → validation failed on each retry → retryCount incremented to 3 → run correctly marked `"failed"`. Also found and fixed a pre-existing bug: `checkpointStepFailure` wasn't clearing `nextRetryAt` on terminal failure, causing infinite retry loops (commit `ccc5162`).
|
|
174
|
-
|
|
175
|
-
**Committed**: `2e91344` — `fix(workflow): re-run validation after retry poller re-executes a step`
|
|
176
|
-
**Bonus fix**: `ccc5162` — `fix(workflow): clear nextRetryAt when retries are exhausted`
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## Phase 3: Structured Output Extraction for Agent-Tasks
|
|
181
|
-
|
|
182
|
-
### Overview
|
|
183
|
-
Add `outputSchema` support to tasks. When set, the agent is prompted to produce structured output, `store-progress` validates it inline (failing the tool call, not the task, on mismatch), and the Claude adapter provides a fallback extraction if the session ends without valid structured output.
|
|
184
|
-
|
|
185
|
-
### Changes Required:
|
|
186
|
-
|
|
187
|
-
#### 1. Add outputSchema to AgentTaskSchema
|
|
188
|
-
**File**: `src/types.ts`
|
|
189
|
-
**Changes**:
|
|
190
|
-
- Add to `AgentTaskSchema` (near line 98):
|
|
191
|
-
```typescript
|
|
192
|
-
outputSchema: z.record(z.string(), z.unknown()).optional(),
|
|
193
|
-
```
|
|
194
|
-
- This represents a JSON Schema object that the task output must conform to.
|
|
195
|
-
|
|
196
|
-
#### 2. Store outputSchema in DB
|
|
197
|
-
**File**: `src/be/db.ts`
|
|
198
|
-
**Changes**:
|
|
199
|
-
- Add `outputSchema` to `CreateTaskOptions` interface (near line 1733):
|
|
200
|
-
```typescript
|
|
201
|
-
outputSchema?: Record<string, unknown>;
|
|
202
|
-
```
|
|
203
|
-
- In `createTaskExtended()` SQL INSERT (lines 1822-1871): store `outputSchema` as a JSON-stringified column. If the column doesn't exist yet, add a migration.
|
|
204
|
-
- Check: does `agent_tasks` table already have an `outputSchema` column? If not, create migration `NNN_add_output_schema.sql`:
|
|
205
|
-
```sql
|
|
206
|
-
ALTER TABLE agent_tasks ADD COLUMN outputSchema TEXT;
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
#### 3. Validate structured output in store-progress
|
|
210
|
-
**File**: `src/tools/store-progress.ts`
|
|
211
|
-
**Changes**:
|
|
212
|
-
- After the terminal state guard (line 106) and before `completeTask()` call (line 124):
|
|
213
|
-
1. Load the task's `outputSchema` (already have the task object from line 95)
|
|
214
|
-
2. If `outputSchema` is set and `status === "completed"` and `output` is provided:
|
|
215
|
-
a. Try `JSON.parse(output)`
|
|
216
|
-
b. If not valid JSON: return a tool error (NOT task failure) with message explaining the output must be valid JSON matching the schema. Include the schema in the error.
|
|
217
|
-
c. If valid JSON: validate against `outputSchema` using `validateJsonSchema()` (from `src/workflows/json-schema-validator.ts`)
|
|
218
|
-
d. If validation fails: return a tool error with the validation errors, asking the agent to retry
|
|
219
|
-
e. If validation passes: proceed to `completeTask()` as normal
|
|
220
|
-
- This gives the agent multiple chances to produce correct output within the same session.
|
|
221
|
-
- **Validator limitation**: `validateJsonSchema()` currently only supports `type`, `required`, `properties`. Before using it here, extend it to also support `enum` and `const` (common in task output schemas). Add these checks in `json-schema-validator.ts` alongside the existing `type`/`required`/`properties` handling. Other advanced JSON Schema features (`pattern`, `anyOf`, `$ref`, etc.) are out of scope.
|
|
222
|
-
|
|
223
|
-
#### 4. Prompt injection for outputSchema
|
|
224
|
-
**File**: `src/commands/runner.ts`
|
|
225
|
-
**Changes**:
|
|
226
|
-
- In `buildPromptForTrigger()` (around line 892-903), after building the task_assigned prompt:
|
|
227
|
-
1. Check if `trigger.task.outputSchema` exists
|
|
228
|
-
2. If yes, append a section to the prompt:
|
|
229
|
-
```
|
|
230
|
-
**Required Output Format**: When completing this task, you MUST call store-progress with output that is valid JSON conforming to this schema:
|
|
231
|
-
```json
|
|
232
|
-
<JSON.stringify(outputSchema, null, 2)>
|
|
233
|
-
```
|
|
234
|
-
Call store-progress with status "completed" and your JSON output. If your output doesn't match the schema, the tool call will fail and you should fix and retry.
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
#### 5. Structured output fallback in runner completion path
|
|
238
|
-
**File**: `src/commands/runner.ts`
|
|
239
|
-
**Changes**:
|
|
240
|
-
|
|
241
|
-
The existing `ensureTaskFinished()` is a simple safety net (POST status based on exit code). Rather than expanding it, extract the structured output logic into a new helper function:
|
|
242
|
-
|
|
243
|
-
- Add `async function handleStructuredOutputFallback(config: ApiConfig, taskId: string, adapterType: "claude" | "pi-mono"): Promise<string | null>`:
|
|
244
|
-
1. Fetch the task via `GET /api/tasks/${taskId}` (returns task + logs)
|
|
245
|
-
2. If no `outputSchema` on the task: return `null` (no-op)
|
|
246
|
-
3. If the task already has `output` stored (agent called `store-progress` successfully): return `null` (already handled)
|
|
247
|
-
4. **Adapter branching**:
|
|
248
|
-
- **Claude adapter**: Build an extraction prompt and run fallback:
|
|
249
|
-
- Build prompt from task description + progress history (filter `task.logs` for `eventType === "task_progress"`, sort chronologically, format as numbered entries) + output schema
|
|
250
|
-
- The prompt structure:
|
|
251
|
-
```
|
|
252
|
-
Extract structured data from this task's execution history.
|
|
253
|
-
|
|
254
|
-
## Task Description
|
|
255
|
-
${task.description}
|
|
256
|
-
|
|
257
|
-
## Progress Updates (chronological)
|
|
258
|
-
${progressEntries.map((log, i) => `${i+1}. [${log.createdAt}] ${log.newValue}`).join("\n")}
|
|
259
|
-
|
|
260
|
-
## Required Output Schema
|
|
261
|
-
${JSON.stringify(task.outputSchema, null, 2)}
|
|
262
|
-
|
|
263
|
-
Extract the structured data from the progress updates above. Return ONLY valid JSON matching the schema.
|
|
264
|
-
```
|
|
265
|
-
- Run extraction:
|
|
266
|
-
```typescript
|
|
267
|
-
const result = await Bun.$`claude -p ${extractionPrompt} --json-schema ${JSON.stringify(schema)} --output-format json --model sonnet`.json();
|
|
268
|
-
```
|
|
269
|
-
- Return `result.structured_output` as stringified JSON, or `null` on failure
|
|
270
|
-
- **Pi-mono adapter**: Return a special sentinel (e.g., throw or return error string) that signals "fail the task" with reason: `"Structured output required by outputSchema but not provided via store-progress"`
|
|
271
|
-
|
|
272
|
-
- Modify `ensureTaskFinished()` to call the helper before POST:
|
|
273
|
-
1. If `exitCode === 0`: call `handleStructuredOutputFallback(config, taskId, adapterType)`
|
|
274
|
-
2. If it returns structured output: use it as the `output` in the finish POST
|
|
275
|
-
3. If it signals failure (Pi-mono): change status to `"failed"` with the structured output failure reason
|
|
276
|
-
4. If it returns `null`: proceed with existing behavior (raw fallback output)
|
|
277
|
-
|
|
278
|
-
- The `adapterType` is available in the runner's process state (`state.activeTasks` tracks which adapter spawned each process). Pass it to `ensureTaskFinished()` as a new parameter.
|
|
279
|
-
|
|
280
|
-
#### 6. JSON-parse structured output in workflow resume
|
|
281
|
-
**File**: `src/workflows/resume.ts`
|
|
282
|
-
**Changes**:
|
|
283
|
-
- In `resumeFromTaskCompletion()` (line 77), where `stepOutput` is built:
|
|
284
|
-
```typescript
|
|
285
|
-
// Before:
|
|
286
|
-
const stepOutput = { taskId: event.taskId, taskOutput: event.output };
|
|
287
|
-
// After:
|
|
288
|
-
let taskOutput: unknown = event.output;
|
|
289
|
-
if (event.output) {
|
|
290
|
-
try {
|
|
291
|
-
const parsed = JSON.parse(event.output);
|
|
292
|
-
if (typeof parsed === "object" && parsed !== null) {
|
|
293
|
-
taskOutput = parsed;
|
|
294
|
-
}
|
|
295
|
-
} catch {
|
|
296
|
-
// Not JSON — keep as string (non-structured output tasks)
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
const stepOutput = { taskId: event.taskId, taskOutput };
|
|
300
|
-
```
|
|
301
|
-
- This ensures that when a task with `outputSchema` completes, the structured JSON is stored as a parsed object in the workflow context. Downstream nodes can then access nested fields via `{{task1.taskOutput.fileCount}}` through the `interpolate()` dot-path walker (template.ts:18-24).
|
|
302
|
-
- For non-structured tasks that produce plain text, the `JSON.parse()` will either fail (caught, keeps string) or parse to a non-object (keeps string). No behavioral change for existing workflows.
|
|
303
|
-
|
|
304
|
-
#### 8. Forward outputSchema from workflow config
|
|
305
|
-
**File**: `src/workflows/executors/agent-task.ts`
|
|
306
|
-
**Changes**:
|
|
307
|
-
- Add to `AgentTaskConfigSchema`:
|
|
308
|
-
```typescript
|
|
309
|
-
outputSchema: z.record(z.string(), z.unknown()).optional(),
|
|
310
|
-
```
|
|
311
|
-
- Forward in `createTaskExtended()` call:
|
|
312
|
-
```typescript
|
|
313
|
-
outputSchema: config.outputSchema,
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
#### 9. Unit tests
|
|
317
|
-
**File**: `src/tests/structured-output.test.ts` (new file)
|
|
318
|
-
**Changes**:
|
|
319
|
-
- Test: store-progress with valid JSON matching schema → task completes successfully
|
|
320
|
-
- Test: store-progress with invalid JSON → tool call fails with error message, task stays in_progress
|
|
321
|
-
- Test: store-progress with valid JSON not matching schema → tool call fails with validation errors
|
|
322
|
-
- Test: store-progress without outputSchema → no validation, behaves as before
|
|
323
|
-
- Test: AgentTaskConfigSchema parses outputSchema
|
|
324
|
-
- Test: createTaskExtended stores outputSchema
|
|
325
|
-
- Test: resume.ts JSON-parses structured output → downstream context has parsed object
|
|
326
|
-
- Test: resume.ts non-JSON output → downstream context keeps string (backward compat)
|
|
327
|
-
- Test: `validateJsonSchema()` handles `enum` and `const` constraints correctly
|
|
328
|
-
|
|
329
|
-
### Success Criteria:
|
|
330
|
-
|
|
331
|
-
#### Automated Verification:
|
|
332
|
-
- [x] Types pass: `bun run tsc:check` ✓
|
|
333
|
-
- [x] Lint passes: `bun run lint:fix` ✓
|
|
334
|
-
- [x] New test passes: `bun test src/tests/structured-output.test.ts` (18/18) ✓
|
|
335
|
-
- [x] All tests pass: `bun test` (1678/1678) ✓
|
|
336
|
-
- [x] Migration applies cleanly on fresh DB ✓ (outputSchema stored and retrieved correctly)
|
|
337
|
-
|
|
338
|
-
#### Manual Verification:
|
|
339
|
-
- [x] Create a task with `outputSchema` via API ✓ (POST /api/tasks returns outputSchema in response, stored correctly)
|
|
340
|
-
- [x] Assign to a worker, verify the agent sees the schema in its prompt ✓ (Docker worker picked up task, produced `{"greeting":"Hello!","agentName":"worker-5cd53523"}` matching schema — agent clearly saw and followed the schema instructions)
|
|
341
|
-
- [x] Verify store-progress rejects malformed output ✓ (non-JSON rejected, schema mismatch rejected with "missing required property")
|
|
342
|
-
- [x] Verify store-progress accepts valid structured output ✓ (worker's store-progress call with valid JSON succeeded, task completed)
|
|
343
|
-
- [x] Verify downstream node receives structured data (not raw string) ✓ (JSON-parsed to object, `{{t1.taskOutput.fileCount}}` interpolation works)
|
|
344
|
-
- [ ] Verify Claude adapter fallback: kill agent session before it calls store-progress (skipped — agent completed too fast for manual kill; fallback path is unit-tested)
|
|
345
|
-
|
|
346
|
-
**Committed**: `9107205` — `feat(workflow): add structured output support for agent-tasks`
|
|
347
|
-
|
|
348
|
-
---
|
|
349
|
-
|
|
350
|
-
## Phase 4: Validation Executor Adapters
|
|
351
|
-
|
|
352
|
-
### Overview
|
|
353
|
-
Normalize the pass/fail contract so any executor type can be used as a validator. Add an adapter layer in the validation system that maps each executor's output shape to `{ pass: boolean }`.
|
|
354
|
-
|
|
355
|
-
### Changes Required:
|
|
356
|
-
|
|
357
|
-
#### 1. Add pass/fail adapter mapping
|
|
358
|
-
**File**: `src/workflows/validation.ts`
|
|
359
|
-
**Changes**:
|
|
360
|
-
- Add a function `extractPassResult(executorType: string, output: unknown): boolean` that normalizes executor outputs:
|
|
361
|
-
```typescript
|
|
362
|
-
function extractPassResult(executorType: string, output: unknown): boolean {
|
|
363
|
-
if (!output || typeof output !== "object") return false;
|
|
364
|
-
const o = output as Record<string, unknown>;
|
|
365
|
-
|
|
366
|
-
switch (executorType) {
|
|
367
|
-
case "validate":
|
|
368
|
-
return o.pass === true;
|
|
369
|
-
case "script":
|
|
370
|
-
return o.exitCode === 0;
|
|
371
|
-
case "property-match":
|
|
372
|
-
return o.passed === true;
|
|
373
|
-
case "raw-llm":
|
|
374
|
-
// For raw-llm used as validator, check if the LLM output
|
|
375
|
-
// contains a structured pass result
|
|
376
|
-
if (typeof o.result === "object" && o.result !== null) {
|
|
377
|
-
return (o.result as Record<string, unknown>).pass === true;
|
|
378
|
-
}
|
|
379
|
-
return false;
|
|
380
|
-
default:
|
|
381
|
-
// Generic fallback: check for common pass indicators
|
|
382
|
-
return o.pass === true || o.passed === true || o.exitCode === 0;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
```
|
|
386
|
-
- Replace the hardcoded check at line 53-56:
|
|
387
|
-
```typescript
|
|
388
|
-
// Before:
|
|
389
|
-
const passed = result.output && (result.output as { pass?: boolean }).pass === true;
|
|
390
|
-
// After:
|
|
391
|
-
const passed = extractPassResult(executorType, result.output);
|
|
392
|
-
```
|
|
393
|
-
Where `executorType` is the resolved executor type from `validation.executor` (already available at line 30).
|
|
394
|
-
|
|
395
|
-
#### 2. Unit tests
|
|
396
|
-
**File**: `src/tests/validation-adapters.test.ts` (new file)
|
|
397
|
-
**Changes**:
|
|
398
|
-
- Test: `validate` executor output `{ pass: true }` → passes
|
|
399
|
-
- Test: `validate` executor output `{ pass: false }` → fails
|
|
400
|
-
- Test: `script` executor output `{ exitCode: 0 }` → passes
|
|
401
|
-
- Test: `script` executor output `{ exitCode: 1 }` → fails
|
|
402
|
-
- Test: `property-match` executor output `{ passed: true }` → passes
|
|
403
|
-
- Test: `property-match` executor output `{ passed: false }` → fails
|
|
404
|
-
- Test: unknown executor with `{ pass: true }` → passes (generic fallback)
|
|
405
|
-
- Test: null/undefined output → fails
|
|
406
|
-
|
|
407
|
-
### Success Criteria:
|
|
408
|
-
|
|
409
|
-
#### Automated Verification:
|
|
410
|
-
- [x] Types pass: `bun run tsc:check` ✓
|
|
411
|
-
- [x] Lint passes: `bun run lint:fix` ✓
|
|
412
|
-
- [x] New test passes: `bun test src/tests/validation-adapters.test.ts` (19/19) ✓
|
|
413
|
-
- [x] All tests pass: `bun test` (1697/1697) ✓
|
|
414
|
-
|
|
415
|
-
#### Manual Verification:
|
|
416
|
-
- [x] Script executor adapter: `exitCode: 0 → pass`, `exitCode: 1 → fail` ✓ (tested via `extractPassResult()` with real output shapes)
|
|
417
|
-
- [x] Property-match adapter: `passed: true → pass`, `passed: false → fail` ✓
|
|
418
|
-
- [x] Backward compat: validate executor `.pass` still works ✓
|
|
419
|
-
- [x] Raw-LLM adapter: `.result.pass` mapping works ✓
|
|
420
|
-
- [x] Edge cases: null/undefined → fail, generic fallback → checks common indicators ✓
|
|
421
|
-
|
|
422
|
-
**Committed**: `39bebf3` — `feat(workflow): normalize validation pass/fail across all executor types`
|
|
423
|
-
|
|
424
|
-
---
|
|
425
|
-
|
|
426
|
-
## Testing Strategy
|
|
427
|
-
|
|
428
|
-
**Unit tests**: Each phase adds its own test file. Tests use isolated SQLite DBs with `initDb()`/`closeDb()` lifecycle.
|
|
429
|
-
|
|
430
|
-
**Integration tests**: Manual E2E via API + Docker workers (see research doc's E2E scenarios). Not automated in CI — these require Docker workers.
|
|
431
|
-
|
|
432
|
-
**Regression**: `bun test` runs all existing tests to catch regressions.
|
|
433
|
-
|
|
434
|
-
## Manual E2E Verification
|
|
435
|
-
|
|
436
|
-
After all phases are complete, run the full E2E scenario from the research doc:
|
|
437
|
-
|
|
438
|
-
```bash
|
|
439
|
-
# Setup
|
|
440
|
-
rm -f agent-swarm-db.sqlite*
|
|
441
|
-
bun run start:http &
|
|
442
|
-
bun run docker:build:worker
|
|
443
|
-
|
|
444
|
-
docker run --rm -d --name e2e-lead \
|
|
445
|
-
--env-file .env.docker-lead -e AGENT_ROLE=lead \
|
|
446
|
-
-e MAX_CONCURRENT_TASKS=1 -p 3201:3000 agent-swarm-worker:latest
|
|
447
|
-
|
|
448
|
-
docker run --rm -d --name e2e-worker \
|
|
449
|
-
--env-file .env.docker \
|
|
450
|
-
-e MAX_CONCURRENT_TASKS=1 -p 3203:3000 agent-swarm-worker:latest
|
|
451
|
-
|
|
452
|
-
sleep 15
|
|
453
|
-
|
|
454
|
-
# 1. Workspace scoping: task with dir
|
|
455
|
-
curl -s -X POST http://localhost:3013/api/workflows \
|
|
456
|
-
-H "Authorization: Bearer 123123" -H "Content-Type: application/json" \
|
|
457
|
-
-d '{
|
|
458
|
-
"name": "e2e-workspace-test",
|
|
459
|
-
"nodes": [{"id": "t1", "type": "agent-task", "config": {"template": "List files in current dir", "dir": "/workspace/repos/agent-swarm"}}],
|
|
460
|
-
"trigger": {"type": "manual"}
|
|
461
|
-
}'
|
|
462
|
-
# Trigger and verify task.dir is set
|
|
463
|
-
|
|
464
|
-
# 2. Structured output: task with outputSchema
|
|
465
|
-
curl -s -X POST http://localhost:3013/api/tasks \
|
|
466
|
-
-H "Authorization: Bearer 123123" -H "Content-Type: application/json" \
|
|
467
|
-
-d '{
|
|
468
|
-
"description": "Count files in /tmp. Report as JSON.",
|
|
469
|
-
"outputSchema": {"type": "object", "properties": {"fileCount": {"type": "number"}}, "required": ["fileCount"]}
|
|
470
|
-
}'
|
|
471
|
-
# Verify agent sees schema in prompt, output is structured JSON
|
|
472
|
-
|
|
473
|
-
# 3. Validation retry: node with mustPass + retry
|
|
474
|
-
curl -s -X POST http://localhost:3013/api/workflows \
|
|
475
|
-
-H "Authorization: Bearer 123123" -H "Content-Type: application/json" \
|
|
476
|
-
-d '{
|
|
477
|
-
"name": "e2e-validation-retry",
|
|
478
|
-
"nodes": [{"id": "llm1", "type": "raw-llm", "config": {"prompt": "Generate a random number 1-100", "model": "google/gemini-3-flash-preview"}, "validation": {"executor": "validate", "config": {"prompt": "Is the number > 50?"}, "mustPass": true, "retry": {"maxRetries": 3, "strategy": "static", "baseDelayMs": 1000}}}],
|
|
479
|
-
"trigger": {"type": "manual"}
|
|
480
|
-
}'
|
|
481
|
-
# Verify validation runs on each retry
|
|
482
|
-
|
|
483
|
-
# Cleanup
|
|
484
|
-
docker stop e2e-lead e2e-worker
|
|
485
|
-
kill $(lsof -ti :3013)
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
## References
|
|
489
|
-
|
|
490
|
-
- Research: `thoughts/taras/research/2026-03-19-workflow-structured-output-validation-workspace.md`
|
|
491
|
-
- Prior research: `thoughts/taras/research/2026-03-19-workflow-node-io-schemas-and-bugs.md`
|
|
492
|
-
- Prior plan: `thoughts/taras/plans/2026-03-18-workflow-redesign.md`
|
|
493
|
-
- Prior plan: `thoughts/taras/plans/2026-03-19-workflow-io-schemas-and-bugs.md`
|
|
494
|
-
|
|
495
|
-
---
|
|
496
|
-
|
|
497
|
-
## Review Errata
|
|
498
|
-
|
|
499
|
-
_Reviewed: 2026-03-20 by claude_
|
|
500
|
-
|
|
501
|
-
All findings have been addressed in the plan above.
|
|
502
|
-
|
|
503
|
-
### Resolved
|
|
504
|
-
|
|
505
|
-
- [x] **Contradiction about migration** — Removed incorrect "no migration needed" claim from "What We're NOT Doing". Phase 3 step 2 correctly adds migration.
|
|
506
|
-
- [x] **Structured output flows as string in workflow context** — Added Phase 3 step 6: JSON-parse structured output in `resume.ts` before storing in workflow context. Ensures `{{task1.taskOutput.fileCount}}` interpolation works.
|
|
507
|
-
- [x] **`validateJsonSchema()` is minimal** — Added note to "What We're NOT Doing" about scope. Phase 3 step 3 now includes extending the validator to support `enum` and `const`. Added unit test for validator extensions.
|
|
508
|
-
- [x] **Pi-mono adapter failure path unspecified** — Phase 3 step 5 now specifies adapter branching: Claude runs fallback extraction, Pi-mono fails with descriptive reason.
|
|
509
|
-
- [x] **`ensureTaskFinished()` refactoring scope** — Restructured Phase 3 step 5 to extract logic into `handleStructuredOutputFallback()` helper, keeping `ensureTaskFinished()` simple with a single call to the helper.
|
|
510
|
-
- [x] **Phase 4 script executor test example** — Replaced misleading `echo` command with `test` command that uses actual process exit code.
|
|
511
|
-
|
|
512
|
-
---
|
|
513
|
-
|
|
514
|
-
## Appendix: E2E Test Outcomes
|
|
515
|
-
|
|
516
|
-
_Tested: 2026-03-20_
|
|
517
|
-
|
|
518
|
-
### Phase 1: Workspace Scoping
|
|
519
|
-
|
|
520
|
-
**E2E-1: Task with `dir`** — PASS
|
|
521
|
-
```
|
|
522
|
-
POST /api/workflows → workflow created
|
|
523
|
-
POST /api/workflows/:id/trigger → run started
|
|
524
|
-
GET /api/tasks?source=workflow →
|
|
525
|
-
{ task: "List files", dir: "/workspace/repos/agent-swarm", source: "workflow" }
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
**E2E-2: Interpolated `dir`** — PASS
|
|
529
|
-
```
|
|
530
|
-
Workflow config: dir: "{{trigger.repo_path}}"
|
|
531
|
-
Trigger data: { "repo_path": "/workspace/repos/test" }
|
|
532
|
-
Created task: { task: "List files in /workspace/repos/test", dir: "/workspace/repos/test" }
|
|
533
|
-
```
|
|
534
|
-
Note: interpolation path must use `{{trigger.repo_path}}` since trigger data is stored at `ctx.trigger`.
|
|
535
|
-
|
|
536
|
-
### Phase 2: Validation Retry
|
|
537
|
-
|
|
538
|
-
**E2E-3: Validation retry with raw-llm + LLM validation** — PASS
|
|
539
|
-
```
|
|
540
|
-
Workflow: raw-llm generates random number 1-100
|
|
541
|
-
Validation: LLM checks if number > 95 (mustPass: true, maxRetries: 3)
|
|
542
|
-
Server logs:
|
|
543
|
-
[workflows] Retrying step llm1 (attempt 1)
|
|
544
|
-
[workflows] Retrying step llm1 (attempt 2)
|
|
545
|
-
[workflows] Retrying step llm1 (attempt 3)
|
|
546
|
-
Final state:
|
|
547
|
-
step: { status: "failed", retryCount: 3, nextRetryAt: null, finishedAt: "2026-03-20T20:03:51Z" }
|
|
548
|
-
run: { status: "failed", error: "Step failed: Validation failed, retrying" }
|
|
549
|
-
```
|
|
550
|
-
Bonus discovery: found and fixed pre-existing bug where `checkpointStepFailure` didn't clear `nextRetryAt` on terminal failure, causing infinite retry loops (commit `ccc5162`).
|
|
551
|
-
|
|
552
|
-
### Phase 3: Structured Output
|
|
553
|
-
|
|
554
|
-
**E2E-4: Agent sees outputSchema in prompt** — PASS (Docker worker)
|
|
555
|
-
```
|
|
556
|
-
Task: "Say hello and report your name as JSON"
|
|
557
|
-
outputSchema: { type: "object", properties: { greeting: { type: "string" }, agentName: { type: "string" } }, required: [...] }
|
|
558
|
-
Worker output: {"greeting": "Hello!", "agentName": "worker-5cd53523"}
|
|
559
|
-
```
|
|
560
|
-
Agent clearly saw and followed the schema instructions, produced valid JSON via store-progress.
|
|
561
|
-
|
|
562
|
-
**E2E-5: store-progress validation** — PASS
|
|
563
|
-
```
|
|
564
|
-
Non-JSON input: → rejected ("Task output must be valid JSON")
|
|
565
|
-
Schema mismatch: → rejected ("missing required property 'count'")
|
|
566
|
-
Valid JSON output: → accepted, task completed
|
|
567
|
-
```
|
|
568
|
-
|
|
569
|
-
**E2E-6: Downstream receives parsed structured data** — PASS
|
|
570
|
-
```
|
|
571
|
-
JSON output stored as string in DB: '{"fileCount":42,"path":"/tmp"}'
|
|
572
|
-
resume.ts JSON-parses → object in workflow context
|
|
573
|
-
Interpolation {{t1.taskOutput.fileCount}} → 42
|
|
574
|
-
Plain text output stays as string (backward compat)
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
**E2E-7: Validation adapters** — PASS
|
|
578
|
-
```
|
|
579
|
-
extractPassResult("script", { exitCode: 0 }) → true
|
|
580
|
-
extractPassResult("script", { exitCode: 1 }) → false
|
|
581
|
-
extractPassResult("property-match", { passed: true }) → true
|
|
582
|
-
extractPassResult("property-match", { passed: false }) → false
|
|
583
|
-
extractPassResult("validate", { pass: true }) → true
|
|
584
|
-
extractPassResult("raw-llm", { result: { pass: true } }) → true
|
|
585
|
-
extractPassResult("custom", { pass: true }) → true (generic fallback)
|
|
586
|
-
extractPassResult("validate", null) → false (edge case)
|
|
587
|
-
```
|
|
588
|
-
|
|
589
|
-
### DB Record: Structured Output Task (Docker Worker)
|
|
590
|
-
|
|
591
|
-
```json
|
|
592
|
-
{
|
|
593
|
-
"id": "ae75f674",
|
|
594
|
-
"task": "Say hello and report your name as JSON. This is a trivial test task.",
|
|
595
|
-
"status": "completed",
|
|
596
|
-
"source": "api",
|
|
597
|
-
"output": {
|
|
598
|
-
"greeting": "Hello!",
|
|
599
|
-
"agentName": "worker-5cd53523"
|
|
600
|
-
},
|
|
601
|
-
"outputSchema": {
|
|
602
|
-
"type": "object",
|
|
603
|
-
"properties": {
|
|
604
|
-
"greeting": { "type": "string" },
|
|
605
|
-
"agentName": { "type": "string" }
|
|
606
|
-
},
|
|
607
|
-
"required": ["greeting", "agentName"]
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
---
|
|
613
|
-
|
|
614
|
-
## Post-Implementation Verification
|
|
615
|
-
|
|
616
|
-
_Verified: 2026-03-20 by claude_
|
|
617
|
-
|
|
618
|
-
**Verdict: PASS** — All 4 phases correctly implemented, no discrepancies.
|
|
619
|
-
|
|
620
|
-
### Automated Checks
|
|
621
|
-
|
|
622
|
-
| Check | Result |
|
|
623
|
-
|-------|--------|
|
|
624
|
-
| `bun run tsc:check` | Pass (no errors) |
|
|
625
|
-
| `bun run lint:fix` | Pass (warnings only) |
|
|
626
|
-
| `bun test` | 1697/1697 pass, 0 fail |
|
|
627
|
-
|
|
628
|
-
### Phase-by-Phase Code Verification
|
|
629
|
-
|
|
630
|
-
- **Phase 1 (Workspace Scoping)**: `AgentTaskConfigSchema` has all 4 new fields, `execute()` forwards them, 6 unit tests pass. Commit `405d679`.
|
|
631
|
-
- **Phase 2 (Validation Retry)**: `retry-poller.ts` calls `runStepValidation()` after retry, handles halt/retry/pass. `checkpoint.ts` clears `nextRetryAt` on exhaustion. 3 unit tests pass. Commits `2e91344`, `ccc5162`.
|
|
632
|
-
- **Phase 3 (Structured Output)**: All 10 sub-checks verified — types, DB, migration, store-progress validation, prompt injection, fallback extraction, resume JSON-parsing, agent-task forwarding, json-schema-validator enum/const, 18 unit tests. Commit `9107205`.
|
|
633
|
-
- **Phase 4 (Validation Adapters)**: `extractPassResult()` with 5 executor adapters + generic fallback. Hardcoded check replaced. 19 unit tests pass. Commit `39bebf3`.
|
|
634
|
-
|
|
635
|
-
### Open Items
|
|
636
|
-
|
|
637
|
-
- Claude adapter fallback E2E (Phase 3): Skipped — agent completed too fast for manual kill. Fallback path is unit-tested. Acceptable trade-off.
|
|
638
|
-
|
|
639
|
-
---
|
|
640
|
-
|
|
641
|
-
## E2E Verification: Structured I/O with Docker Worker
|
|
642
|
-
|
|
643
|
-
_Verified: 2026-03-20 by taras+claude_
|
|
644
|
-
|
|
645
|
-
**Verdict: PASS** — Full workflow with structured input/output, context propagation, and two sequential agent-task nodes completed successfully with a single Docker worker.
|
|
646
|
-
|
|
647
|
-
### What was tested
|
|
648
|
-
|
|
649
|
-
A 2-node sequential workflow exercising the structured I/O pipeline end-to-end:
|
|
650
|
-
|
|
651
|
-
1. **Node `generate-city`** (agent-task): Asks agent to produce a JSON object with `city`, `country`, `population`. Has `config.outputSchema` for schema validation.
|
|
652
|
-
2. **Node `summarize-city`** (agent-task): Uses `inputs` mapping to pull step 1's output into interpolation context. Template references `{{cityData.taskOutput.city}}` etc. Also has `config.outputSchema`.
|
|
653
|
-
|
|
654
|
-
### Verification checklist
|
|
655
|
-
|
|
656
|
-
| Check | Result |
|
|
657
|
-
|-------|--------|
|
|
658
|
-
| `config.outputSchema` flows from workflow node → task creation | ✅ Task has `outputSchema` field set |
|
|
659
|
-
| Agent produces structured JSON validated against schema | ✅ `{"city":"Lisbon","country":"Portugal","population":545000}` |
|
|
660
|
-
| `resume.ts` JSON-parses task output into run context | ✅ Context has parsed object, not string |
|
|
661
|
-
| `inputs` mapping scopes upstream data for interpolation | ✅ `"cityData": "generate-city"` resolved correctly |
|
|
662
|
-
| Template interpolation resolves nested paths | ✅ `{{cityData.taskOutput.city}}` → `"Lisbon"` |
|
|
663
|
-
| Second node receives interpolated values | ✅ Task prompt: "The city is Lisbon in Portugal with population 545000" |
|
|
664
|
-
| Second node produces its own structured output | ✅ `{"summary":"Lisbon is a city in Portugal with a population of 545000"}` |
|
|
665
|
-
| Workflow completes with both outputs in final context | ✅ Both steps in `run.context` |
|
|
666
|
-
|
|
667
|
-
### Workflow definition (copy-paste to recreate)
|
|
668
|
-
|
|
669
|
-
```json
|
|
670
|
-
{
|
|
671
|
-
"name": "structured-io-e2e",
|
|
672
|
-
"definition": {
|
|
673
|
-
"nodes": [
|
|
674
|
-
{
|
|
675
|
-
"id": "generate-city",
|
|
676
|
-
"type": "agent-task",
|
|
677
|
-
"label": "Generate city data",
|
|
678
|
-
"config": {
|
|
679
|
-
"template": "Respond with ONLY a valid JSON object (no markdown, no explanation, no code fences) describing a real city. Use exactly this format: {\"city\": \"Tokyo\", \"country\": \"Japan\", \"population\": 14000000}. Pick any real city you like. Output ONLY the JSON object, nothing else.",
|
|
680
|
-
"outputSchema": {
|
|
681
|
-
"type": "object",
|
|
682
|
-
"required": ["city", "country", "population"],
|
|
683
|
-
"properties": {
|
|
684
|
-
"city": { "type": "string" },
|
|
685
|
-
"country": { "type": "string" },
|
|
686
|
-
"population": { "type": "number" }
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
},
|
|
690
|
-
"next": "summarize-city"
|
|
691
|
-
},
|
|
692
|
-
{
|
|
693
|
-
"id": "summarize-city",
|
|
694
|
-
"type": "agent-task",
|
|
695
|
-
"label": "Summarize city data",
|
|
696
|
-
"inputs": { "cityData": "generate-city" },
|
|
697
|
-
"config": {
|
|
698
|
-
"template": "You received city data from a previous step. The city is {{cityData.taskOutput.city}} in {{cityData.taskOutput.country}} with population {{cityData.taskOutput.population}}. Respond with ONLY a valid JSON object (no markdown, no explanation, no code fences) in this exact format: {\"summary\": \"<city> is a city in <country> with a population of <population>\"}. Output ONLY the JSON object, nothing else.",
|
|
699
|
-
"outputSchema": {
|
|
700
|
-
"type": "object",
|
|
701
|
-
"required": ["summary"],
|
|
702
|
-
"properties": { "summary": { "type": "string" } }
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
]
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
```
|
|
710
|
-
|
|
711
|
-
### Learnings & roadblocks
|
|
712
|
-
|
|
713
|
-
1. **`inputs` mapping is REQUIRED for cross-node data access** (gotcha): Without an explicit `inputs` mapping on a node, the interpolation context only includes `trigger` and `input` (workflow-level inputs) — upstream step outputs are NOT available. This is by design (engine.ts:316-340) for encapsulation, but it's a non-obvious foot-gun for workflow authors. The first test run failed with `unresolvedTokens` diagnostics until `"inputs": {"cityData": "generate-city"}` was added. This should be prominently documented in workflow authoring guides.
|
|
714
|
-
|
|
715
|
-
2. **`outputSchema` placement matters**: Node-level `outputSchema` (on the WorkflowNode) validates the executor's return value (e.g. `{taskId, taskOutput}`). The `config.outputSchema` on agent-task nodes is what gets forwarded to the created task and validates the agent's raw output. These are different schemas at different layers. For structured agent output, the schema goes in `config.outputSchema`.
|
|
716
|
-
|
|
717
|
-
3. **Stale `in_progress` tasks block worker pickup**: When a worker's Claude session claims a task but exits before completing it, the task remains `in_progress` with `assignedTo=none`. The worker polls for `unassigned` tasks only, so it never sees the stranded task. Restarting the worker doesn't help — the task is permanently stuck. This happened during testing when the first session claimed the second task within the same session but exited after completing only the first. A stale-task recovery mechanism (timeout → reset to `unassigned`) would prevent this.
|
|
718
|
-
|
|
719
|
-
4. **Lead vs worker for workflow tasks**: The lead agent's polling mechanism didn't pick up workflow-created tasks during testing (it polled but never triggered). The worker agent did. For workflow E2E testing, use a worker container, not a lead.
|
|
720
|
-
|
|
721
|
-
5. **Clean DB between test runs is critical**: Old stale tasks (`in_progress` from previous runs) persist across API restarts and block subsequent runs. Always `rm -f agent-swarm-db.sqlite*` before a clean E2E test, and ensure the API server is fully stopped before deleting (WAL replay can resurrect data).
|
|
722
|
-
|
|
723
|
-
6. **Docker env files need port adjustment per worktree**: `.env.docker` and `.env.docker-lead` hardcode `MCP_BASE_URL=http://host.docker.internal:3013`. Worktrees on alternate ports (e.g. 3014) need manual update.
|