@vellumai/assistant 0.8.12 → 0.9.0-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +0 -14
- package/ARCHITECTURE.md +45 -45
- package/README.md +1 -1
- package/bun.lock +200 -154
- package/docs/architecture/integrations.md +3 -3
- package/docs/architecture/memory.md +2 -2
- package/docs/architecture/security.md +10 -10
- package/docs/runbook-trusted-contacts.md +12 -12
- package/docs/skills.md +6 -6
- package/docs/workflows-testing.md +221 -0
- package/docs/workflows.md +510 -0
- package/examples/plugins/echo/README.md +5 -5
- package/knip.json +2 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +105 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +12 -0
- package/openapi.yaml +7197 -5708
- package/package.json +8 -4
- package/scripts/generate-openapi.ts +66 -114
- package/src/__tests__/access-request-seed-content-blocks.test.ts +213 -0
- package/src/__tests__/adaptive-thinking-repair.test.ts +32 -3
- package/src/__tests__/agent-loop-output-hooks.test.ts +183 -0
- package/src/__tests__/agent-loop-regrowth-guard.test.ts +506 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +77 -0
- package/src/__tests__/app-compiler.test.ts +7 -1
- package/src/__tests__/app-dir-path-guard.test.ts +27 -3
- package/src/__tests__/app-executors.test.ts +43 -0
- package/src/__tests__/approval-cascade.test.ts +0 -5
- package/src/__tests__/approval-routes-http.test.ts +91 -0
- package/src/__tests__/assistant-stream-state.test.ts +107 -0
- package/src/__tests__/browser-fill-credential.test.ts +3 -3
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +1 -1
- package/src/__tests__/compaction-events.test.ts +63 -7
- package/src/__tests__/compaction-trail-store.test.ts +74 -1
- package/src/__tests__/compaction.benchmark.test.ts +63 -41
- package/src/__tests__/compactor-low-watermark-cut.test.ts +349 -0
- package/src/__tests__/context-window-manager-compact-retry.test.ts +64 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -5
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -5
- package/src/__tests__/conversation-history-web-search.test.ts +7 -0
- package/src/__tests__/conversation-process-callsite.test.ts +0 -5
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -5
- package/src/__tests__/conversation-queue.test.ts +0 -5
- package/src/__tests__/conversation-slash-queue.test.ts +0 -5
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -5
- package/src/__tests__/conversation-speed-override.test.ts +0 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +97 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-usage.test.ts +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -5
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -5
- package/src/__tests__/credential-broker-browser-fill.test.ts +2 -2
- package/src/__tests__/credential-broker-server-use.test.ts +2 -2
- package/src/__tests__/credential-broker.test.ts +1 -1
- package/src/__tests__/credential-prompt-route.test.ts +417 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault.test.ts +37 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +24 -0
- package/src/__tests__/dynamic-page-surface.test.ts +219 -0
- package/src/__tests__/empty-state-greeting-cache.test.ts +94 -0
- package/src/__tests__/gateway-flag-listener.test.ts +24 -7
- package/src/__tests__/guardian-action-sweep.test.ts +56 -219
- package/src/__tests__/guardian-routing-invariants.test.ts +138 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +99 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +87 -1
- package/src/__tests__/llm-resolver.test.ts +115 -0
- package/src/__tests__/managed-profile-guard.test.ts +6 -5
- package/src/__tests__/max-tokens-continue-hook.test.ts +184 -0
- package/src/__tests__/media-generate-image.test.ts +20 -9
- package/src/__tests__/mock-gateway-ipc.ts +23 -0
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/normalize-onboarding.test.ts +26 -0
- package/src/__tests__/notification-decision-strategy.test.ts +4 -2
- package/src/__tests__/notification-telegram-adapter.test.ts +21 -3
- package/src/__tests__/pending-interactions-resolved-event.test.ts +62 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +72 -18
- package/src/__tests__/require-fresh-approval.test.ts +425 -1
- package/src/__tests__/resolve-app-id.test.ts +56 -0
- package/src/__tests__/runtime-events-sse-parity.test.ts +2 -0
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +408 -0
- package/src/__tests__/schedule-routes.test.ts +257 -4
- package/src/__tests__/schedule-store.test.ts +60 -0
- package/src/__tests__/schedule-tools.test.ts +247 -2
- package/src/__tests__/skill-execute-input.test.ts +85 -0
- package/src/__tests__/skill-secret-handling-guard.test.ts +21 -20
- package/src/__tests__/skills.test.ts +3 -3
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +1 -1
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +547 -0
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/task-progress-nudge-hook.test.ts +372 -0
- package/src/__tests__/task-scheduler.test.ts +299 -0
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +209 -0
- package/src/__tests__/tool-result-spool.test.ts +3 -1
- package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +181 -0
- package/src/__tests__/workspace-migration-103-upgrade-quality-profile-to-opus-4-8.test.ts +174 -0
- package/src/agent/compaction-circuit.ts +11 -0
- package/src/agent/loop.ts +181 -12
- package/src/api/constants/call-sites.ts +12 -0
- package/src/api/events/assistant-thinking-delta.ts +10 -0
- package/src/api/events/usage-update.ts +7 -0
- package/src/api/index.ts +4 -1
- package/src/api/responses/memory-v3-selection-log.ts +18 -11
- package/src/approvals/approval-primitive.ts +2 -2
- package/src/background-wake/background-wake-routes.test.ts +5 -2
- package/src/bundler/compiler-tools.ts +1 -1
- package/src/bundler/package-resolver.ts +0 -1
- package/src/calls/call-domain.ts +1 -1
- package/src/calls/guardian-action-sweep.ts +16 -93
- package/src/cli/AGENTS.md +4 -0
- package/src/cli/commands/__tests__/schedules.test.ts +430 -1
- package/src/cli/commands/credentials.ts +28 -24
- package/src/cli/commands/image-generation.ts +23 -9
- package/src/cli/commands/notifications.ts +1 -1
- package/src/cli/commands/plugins.ts +89 -46
- package/src/cli/commands/schedules.ts +384 -11
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +69 -5
- package/src/cli/lib/__tests__/install-from-github.test.ts +15 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +81 -4
- package/src/cli/lib/inspect-plugin.ts +62 -1
- package/src/cli/lib/install-from-github.ts +52 -5
- package/src/cli/lib/upgrade-plugin.ts +18 -0
- package/src/config/__tests__/workflows-schema.test.ts +60 -0
- package/src/config/bundled-skills/acp/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +6 -1
- package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +7 -1
- package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +7 -1
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +10 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +66 -19
- package/src/config/bundled-skills/image-studio/TOOLS.json +1 -6
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +22 -3
- package/src/config/bundled-skills/personal-page/SKILL.md +57 -0
- package/src/config/bundled-skills/personal-page/TOOLS.json +27 -0
- package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +17 -0
- package/src/config/bundled-skills/schedule/SKILL.md +7 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +48 -4
- package/src/config/bundled-skills/workflows/SKILL.md +214 -0
- package/src/config/bundled-skills/workflows/TOOLS.json +84 -0
- package/src/config/bundled-skills/workflows/tools/manage-workflows.ts +12 -0
- package/src/config/bundled-skills/workflows/tools/run-workflow.ts +12 -0
- package/src/config/bundled-tool-registry.ts +14 -2
- package/src/config/call-site-defaults.ts +5 -0
- package/src/config/feature-flag-registry.json +12 -4
- package/src/config/llm-context-resolution.ts +8 -0
- package/src/config/llm-resolver.ts +30 -0
- package/src/config/preloaded-apps/personal-page/src/components/About.tsx +22 -0
- package/src/config/preloaded-apps/personal-page/src/components/App.tsx +16 -0
- package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +77 -0
- package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +57 -0
- package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +28 -0
- package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +234 -0
- package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +48 -0
- package/src/config/preloaded-apps/personal-page/src/components/media.ts +16 -0
- package/src/config/preloaded-apps/personal-page/src/index.html +20 -0
- package/src/config/preloaded-apps/personal-page/src/main.tsx +7 -0
- package/src/config/preloaded-apps/personal-page/src/profile-data.ts +82 -0
- package/src/config/preloaded-apps/personal-page/src/styles.css +759 -0
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/heartbeat.ts +4 -1
- package/src/config/schemas/llm.ts +33 -26
- package/src/config/schemas/memory-retrospective.ts +19 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/services.ts +5 -2
- package/src/config/schemas/workflows.ts +42 -0
- package/src/config/skills.ts +3 -3
- package/src/context/compactor.ts +273 -39
- package/src/context/post-turn-tool-result-truncation.ts +23 -6
- package/src/context/tool-result-spool.ts +12 -17
- package/src/credential-execution/executable-discovery.ts +1 -1
- package/src/credential-execution/process-manager.ts +37 -3
- package/src/credential-execution/prompted-credential.ts +205 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +14 -0
- package/src/daemon/conversation-process.ts +11 -2
- package/src/daemon/conversation-surfaces.ts +167 -3
- package/src/daemon/conversation-tool-setup.ts +103 -26
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +115 -11
- package/src/daemon/handlers/shared.ts +26 -14
- package/src/daemon/host-cu-proxy.ts +15 -12
- package/src/daemon/host-file-proxy.ts +15 -12
- package/src/daemon/host-transfer-proxy.ts +30 -24
- package/src/daemon/lifecycle.ts +40 -3
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/messages.ts +2 -10
- package/src/daemon/message-types/workflows.ts +49 -0
- package/src/daemon/parse-actual-tokens-from-error.test.ts +62 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +43 -4
- package/src/daemon/process-message.ts +6 -0
- package/src/daemon/tool-setup-types.ts +57 -0
- package/src/daemon/wake-conversation-ops.ts +18 -0
- package/src/heartbeat/heartbeat-run-store.ts +8 -2
- package/src/home/feed-types.ts +1 -1
- package/src/ipc/gateway-flag-listener.ts +28 -6
- package/src/mcp/mcp-auth-state.ts +8 -20
- package/src/media/__tests__/image-models.test.ts +57 -0
- package/src/media/image-models.ts +66 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +38 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +12 -2
- package/src/memory/__tests__/memory-retrospective-job.test.ts +911 -34
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +227 -5
- package/src/memory/__tests__/memory-retrospective-state.test.ts +195 -0
- package/src/memory/__tests__/preloaded-apps.test.ts +85 -0
- package/src/memory/auto-analysis-enqueue.ts +14 -1
- package/src/memory/compaction-log-store-clickhouse.ts +6 -4
- package/src/memory/conversation-crud.ts +9 -2
- package/src/memory/conversation-disk-view.ts +1 -1
- package/src/memory/conversation-queries.ts +22 -7
- package/src/memory/db-init.ts +20 -0
- package/src/memory/db-maintenance.ts +16 -0
- package/src/memory/embedding-runtime-manager.ts +1 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +112 -14
- package/src/memory/llm-request-log-source-local.ts +19 -1
- package/src/memory/llm-request-log-source.ts +35 -6
- package/src/memory/llm-request-log-store.ts +90 -2
- package/src/memory/memory-retrospective-constants.ts +9 -0
- package/src/memory/memory-retrospective-enqueue.ts +3 -6
- package/src/memory/memory-retrospective-fork-boundary.ts +94 -0
- package/src/memory/memory-retrospective-job.ts +500 -208
- package/src/memory/memory-retrospective-startup-cleanup.ts +97 -19
- package/src/memory/memory-retrospective-state.ts +85 -2
- package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +40 -0
- package/src/memory/migrations/282-schedule-inference-profile.test.ts +77 -0
- package/src/memory/migrations/282-schedule-inference-profile.ts +26 -0
- package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.test.ts +102 -0
- package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.ts +53 -0
- package/src/memory/migrations/284-workflow-runs.ts +51 -0
- package/src/memory/migrations/285-schedule-workflow-mode.ts +26 -0
- package/src/memory/migrations/286-workflow-run-trust.ts +27 -0
- package/src/memory/migrations/287-conversation-origin-channel-index.ts +15 -0
- package/src/memory/migrations/288-backfill-origin-channel-from-bindings.ts +43 -0
- package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +115 -0
- package/src/memory/migrations/290-schedule-capabilities.test.ts +77 -0
- package/src/memory/migrations/290-schedule-capabilities.ts +25 -0
- package/src/memory/migrations/__tests__/281-memory-retrospective-remembered-log.test.ts +96 -0
- package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +571 -0
- package/src/memory/migrations/index.ts +10 -0
- package/src/memory/preloaded-apps.ts +116 -0
- package/src/memory/schema/infrastructure.ts +4 -0
- package/src/memory/schema/memory-core.ts +4 -0
- package/src/memory/v2/__tests__/concept-page-frontmatter-schema.test.ts +45 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +11 -7
- package/src/memory/v2/__tests__/page-store.test.ts +13 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +24 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -6
- package/src/memory/v2/page-store.ts +4 -3
- package/src/memory/v2/qdrant.ts +42 -3
- package/src/memory/v2/types.ts +16 -10
- package/src/messaging/draft-store.ts +1 -1
- package/src/notifications/access-request-copy.ts +200 -113
- package/src/notifications/adapters/slack.ts +250 -111
- package/src/notifications/adapters/telegram.ts +7 -44
- package/src/notifications/approval-card-builder.ts +93 -0
- package/src/notifications/broadcaster.ts +74 -0
- package/src/notifications/conversation-pairing.ts +8 -6
- package/src/notifications/copy-composer.ts +32 -26
- package/src/notifications/decision-engine.ts +59 -7
- package/src/notifications/guardian-question-mode.ts +145 -155
- package/src/notifications/home-feed-side-effect.ts +28 -11
- package/src/notifications/notification-utils.ts +66 -0
- package/src/notifications/signal.ts +6 -0
- package/src/notifications/tool-approval-copy.ts +142 -0
- package/src/notifications/types.ts +19 -0
- package/src/permissions/threshold.ts +11 -0
- package/src/plugin-api/types.ts +16 -4
- package/src/plugins/defaults/compaction/window-manager.ts +44 -0
- package/src/plugins/defaults/index.ts +46 -0
- package/src/plugins/defaults/max-tokens-continue/continue-state-store.ts +53 -0
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +80 -0
- package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +20 -0
- package/src/plugins/defaults/max-tokens-continue/package.json +14 -0
- package/src/plugins/defaults/memory-retrieval/hooks/__tests__/user-prompt-submit.test.ts +37 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +29 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +8 -3
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +4 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +28 -18
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +67 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +122 -22
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +2 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +63 -1
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +61 -18
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +1 -1
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +39 -10
- package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +34 -1
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +112 -47
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +78 -15
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +206 -0
- package/src/plugins/defaults/task-progress-nudge/package.json +15 -0
- package/src/prompts/__tests__/system-prompt.test.ts +100 -1
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +5 -7
- package/src/prompts/normalize-onboarding.ts +2 -0
- package/src/prompts/persona-resolver.ts +3 -0
- package/src/prompts/system-prompt.ts +51 -2
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +3 -1
- package/src/prompts/templates/system-sections.ts +8 -3
- package/src/providers/call-site-routing.ts +6 -3
- package/src/providers/fireworks/client.ts +3 -0
- package/src/providers/inference/auth.ts +52 -46
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/__tests__/coerce-object-args.test.ts +105 -0
- package/src/providers/openai/chat-completions-provider.ts +47 -9
- package/src/providers/openai/coerce-object-args.ts +104 -0
- package/src/providers/retry.ts +8 -5
- package/src/providers/types.ts +10 -0
- package/src/runtime/__tests__/agent-wake.test.ts +629 -7
- package/src/runtime/access-request-helper.ts +16 -9
- package/src/runtime/agent-wake.ts +302 -51
- package/src/runtime/assistant-stream-state.ts +141 -8
- package/src/runtime/background-job-runner.ts +9 -0
- package/src/runtime/channel-approval-types.ts +1 -0
- package/src/runtime/channel-invite-transports/telegram.ts +6 -5
- package/src/runtime/channel-invite-transports/voice.ts +2 -2
- package/src/runtime/channel-invite-types.ts +4 -2
- package/src/runtime/channel-retry-sweep.ts +19 -41
- package/src/runtime/finalize-event-delivery.ts +72 -0
- package/src/runtime/guardian-action-message-composer.ts +0 -54
- package/src/runtime/http-server.ts +6 -14
- package/src/runtime/http-types.ts +0 -1
- package/src/runtime/message-composer-types.ts +0 -9
- package/src/runtime/middleware/__tests__/rate-limiter.test.ts +63 -0
- package/src/runtime/middleware/auth.ts +27 -3
- package/src/runtime/middleware/rate-limiter.ts +28 -1
- package/src/runtime/migrations/vbundle-builder.ts +6 -5
- package/src/runtime/pending-interactions.ts +20 -1
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +232 -173
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +18 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +436 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +11 -0
- package/src/runtime/routes/approval-routes.ts +35 -8
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -1
- package/src/runtime/routes/btw-routes.ts +37 -1
- package/src/runtime/routes/channel-delivery-routes.ts +11 -7
- package/src/runtime/routes/channel-route-definitions.ts +3 -0
- package/src/runtime/routes/channel-route-shared.ts +3 -1
- package/src/runtime/routes/consolidation-routes.ts +17 -13
- package/src/runtime/routes/conversation-compaction-routes.ts +159 -119
- package/src/runtime/routes/conversation-list-routes.ts +41 -4
- package/src/runtime/routes/conversation-query-routes.ts +196 -11
- package/src/runtime/routes/conversation-routes.ts +15 -1
- package/src/runtime/routes/credential-prompt-routes.ts +39 -17
- package/src/runtime/routes/empty-state-greeting-cache.ts +65 -0
- package/src/runtime/routes/heartbeat-routes.ts +18 -13
- package/src/runtime/routes/image-generation-routes.ts +20 -2
- package/src/runtime/routes/inbound-message-handler.ts +13 -12
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +32 -31
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +7 -5
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +7 -21
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +6 -15
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +1 -1
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/log-export/AGENTS.md +1 -1
- package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
- package/src/runtime/routes/migration-routes.ts +5 -9
- package/src/runtime/routes/plugins-routes.ts +26 -0
- package/src/runtime/routes/ps-routes.ts +10 -8
- package/src/runtime/routes/retrospective-routes.ts +235 -0
- package/src/runtime/routes/runs-pagination.ts +75 -0
- package/src/runtime/routes/schedule-routes.ts +367 -59
- package/src/runtime/routes/sounds-config-routes.ts +239 -0
- package/src/runtime/routes/surface-action-routes.ts +84 -4
- package/src/runtime/routes/workflow-routes.test.ts +372 -0
- package/src/runtime/routes/workflow-routes.ts +363 -0
- package/src/runtime/routes/workspace-routes.test.ts +61 -1
- package/src/runtime/routes/workspace-routes.ts +26 -1
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +38 -0
- package/src/runtime/services/analyze-conversation.ts +26 -13
- package/src/schedule/inference-profile.ts +28 -0
- package/src/schedule/schedule-store.ts +152 -4
- package/src/schedule/scheduler-types.ts +6 -0
- package/src/schedule/scheduler.ts +96 -0
- package/src/security/secret-allowlist.ts +1 -1
- package/src/skills/path-classifier.ts +1 -1
- package/src/tools/apps/executors.ts +23 -0
- package/src/tools/apps/resolve-app-id.ts +42 -0
- package/src/tools/browser/browser-execution.ts +9 -11
- package/src/tools/credentials/broker.ts +4 -4
- package/src/tools/credentials/vault.ts +26 -137
- package/src/tools/executor.ts +69 -0
- package/src/tools/flag-gated-tools.test.ts +76 -0
- package/src/tools/permission-checker.ts +8 -1
- package/src/tools/registry.ts +51 -0
- package/src/tools/schedule/create.ts +77 -1
- package/src/tools/schedule/list.ts +1 -0
- package/src/tools/schedule/update.ts +73 -1
- package/src/tools/skills/execute.ts +56 -0
- package/src/tools/terminal/shell.ts +1 -1
- package/src/tools/ui-surface/definitions.ts +91 -2
- package/src/tools/workflows/manage-workflows.ts +183 -0
- package/src/tools/workflows/run-workflow.test.ts +442 -0
- package/src/tools/workflows/run-workflow.ts +88 -0
- package/src/types/onboarding-context.ts +2 -0
- package/src/usage/attribution.ts +24 -0
- package/src/util/canonicalize-identity.ts +12 -3
- package/src/util/platform.ts +17 -17
- package/src/watcher/__tests__/engine.test.ts +24 -0
- package/src/watcher/__tests__/telemetry.test.ts +135 -0
- package/src/watcher/engine.ts +7 -0
- package/src/watcher/telemetry.ts +74 -0
- package/src/workflows/capabilities.test.ts +365 -0
- package/src/workflows/capabilities.ts +359 -0
- package/src/workflows/deterministic-stringify.ts +27 -0
- package/src/workflows/engine-integration.test.ts +656 -0
- package/src/workflows/engine.test.ts +1144 -0
- package/src/workflows/engine.ts +1078 -0
- package/src/workflows/fanout-load.test.ts +168 -0
- package/src/workflows/journal-store.test.ts +369 -0
- package/src/workflows/journal-store.ts +470 -0
- package/src/workflows/leaf-runner.test.ts +704 -0
- package/src/workflows/leaf-runner.ts +589 -0
- package/src/workflows/library.test.ts +134 -0
- package/src/workflows/library.ts +124 -0
- package/src/workflows/run-manager.test.ts +711 -0
- package/src/workflows/run-manager.ts +593 -0
- package/src/workflows/sandbox-escape.test.ts +339 -0
- package/src/workflows/sandbox.test.ts +251 -0
- package/src/workflows/sandbox.ts +447 -0
- package/src/workspace/adaptive-thinking-repair.ts +33 -11
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +1 -1
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +1 -1
- package/src/workspace/migrations/026-backfill-install-meta.ts +1 -1
- package/src/workspace/migrations/030-seed-pkb-autoinject.ts +2 -1
- package/src/workspace/migrations/031-drop-user-md.ts +1 -4
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +1 -1
- package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +5 -2
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +1 -1
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +8 -2
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +41 -14
- package/src/workspace/migrations/102-preserve-heartbeat-enabled-for-existing-workspaces.ts +69 -0
- package/src/workspace/migrations/103-upgrade-quality-profile-to-opus-4-8.ts +83 -0
- package/src/workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.ts +133 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/migrations/runner.ts +1 -1
- package/tsconfig.json +1 -1
- package/src/__tests__/guardian-action-copy-generator.test.ts +0 -200
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -579
- package/src/__tests__/guardian-action-store.test.ts +0 -106
- package/src/daemon/guardian-action-generators.ts +0 -71
- package/src/memory/guardian-action-store.ts +0 -484
- package/src/runtime/guardian-action-grant-minter.ts +0 -150
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
|
|
2
|
+
import { getConfig } from "../../config/loader.js";
|
|
3
|
+
import { validateScheduleInferenceProfile } from "../../schedule/inference-profile.js";
|
|
1
4
|
import { validateRruleSetLines } from "../../schedule/recurrence-engine.js";
|
|
2
5
|
import {
|
|
3
6
|
detectScheduleSyntax,
|
|
@@ -17,7 +20,7 @@ import {
|
|
|
17
20
|
} from "../../schedule/schedule-store.js";
|
|
18
21
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
19
22
|
|
|
20
|
-
const VALID_MODES: ScheduleMode[] = ["notify", "execute", "script"];
|
|
23
|
+
const VALID_MODES: ScheduleMode[] = ["notify", "execute", "script", "workflow"];
|
|
21
24
|
const VALID_ROUTING_INTENTS: RoutingIntent[] = [
|
|
22
25
|
"single_channel",
|
|
23
26
|
"multi_channel",
|
|
@@ -92,6 +95,17 @@ export async function executeScheduleUpdate(
|
|
|
92
95
|
updates.mode = mode;
|
|
93
96
|
}
|
|
94
97
|
|
|
98
|
+
// Workflow fields pass-through (validated against the resulting mode below)
|
|
99
|
+
if (input.workflow_name !== undefined) {
|
|
100
|
+
updates.workflowName =
|
|
101
|
+
typeof input.workflow_name === "string"
|
|
102
|
+
? input.workflow_name.trim()
|
|
103
|
+
: null;
|
|
104
|
+
}
|
|
105
|
+
if (input.workflow_args !== undefined) {
|
|
106
|
+
updates.workflowArgs = input.workflow_args;
|
|
107
|
+
}
|
|
108
|
+
|
|
95
109
|
// Routing intent validation and pass-through
|
|
96
110
|
if (input.routing_intent !== undefined) {
|
|
97
111
|
const routingIntent = input.routing_intent as RoutingIntent;
|
|
@@ -127,6 +141,27 @@ export async function executeScheduleUpdate(
|
|
|
127
141
|
updates.retryBackoffMs = input.retry_backoff_ms;
|
|
128
142
|
}
|
|
129
143
|
|
|
144
|
+
// Inference profile override (null clears it, reverting to the default
|
|
145
|
+
// main-agent model selection)
|
|
146
|
+
if (input.inference_profile !== undefined) {
|
|
147
|
+
if (input.inference_profile === null) {
|
|
148
|
+
updates.inferenceProfile = null;
|
|
149
|
+
} else {
|
|
150
|
+
const inferenceProfile = input.inference_profile;
|
|
151
|
+
if (typeof inferenceProfile !== "string") {
|
|
152
|
+
return {
|
|
153
|
+
content: "Error: inference_profile must be a string or null",
|
|
154
|
+
isError: true,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const profileError = validateScheduleInferenceProfile(inferenceProfile);
|
|
158
|
+
if (profileError) {
|
|
159
|
+
return { content: `Error: ${profileError}`, isError: true };
|
|
160
|
+
}
|
|
161
|
+
updates.inferenceProfile = inferenceProfile;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
130
165
|
// Script execution timeout override (null clears it, reverting to default)
|
|
131
166
|
if (input.timeout_ms !== undefined) {
|
|
132
167
|
if (input.timeout_ms === null) {
|
|
@@ -170,6 +205,39 @@ export async function executeScheduleUpdate(
|
|
|
170
205
|
};
|
|
171
206
|
}
|
|
172
207
|
|
|
208
|
+
// Mirror the HTTP route: a schedule whose RESULTING mode is `workflow` must be
|
|
209
|
+
// flag-enabled and carry a non-empty workflowName. Compute the post-update
|
|
210
|
+
// state (the update's value if present, else the persisted one) so both
|
|
211
|
+
// "switch to workflow without a name" and "clear the name on a workflow
|
|
212
|
+
// schedule" are rejected — otherwise the scheduler hits the `!job.workflowName`
|
|
213
|
+
// skip branch and a one-shot firing job wedges.
|
|
214
|
+
if (updates.mode !== undefined || updates.workflowName !== undefined) {
|
|
215
|
+
const existing = getSchedule(jobId);
|
|
216
|
+
if (existing) {
|
|
217
|
+
const resultingMode =
|
|
218
|
+
updates.mode !== undefined ? (updates.mode as string) : existing.mode;
|
|
219
|
+
if (resultingMode === "workflow") {
|
|
220
|
+
if (!isAssistantFeatureFlagEnabled("workflows", getConfig())) {
|
|
221
|
+
return {
|
|
222
|
+
content: "Error: workflows are not enabled.",
|
|
223
|
+
isError: true,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
const resultingWorkflowName =
|
|
227
|
+
updates.workflowName !== undefined
|
|
228
|
+
? ((updates.workflowName as string | null) ?? "")
|
|
229
|
+
: (existing.workflowName ?? "");
|
|
230
|
+
if (!resultingWorkflowName) {
|
|
231
|
+
return {
|
|
232
|
+
content:
|
|
233
|
+
"Error: workflow_name is required for workflow-mode schedules",
|
|
234
|
+
isError: true,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
173
241
|
// Set-aware pre-validation for RRULE expressions
|
|
174
242
|
const effectiveSyntax = updates.syntax as string | undefined;
|
|
175
243
|
const effectiveExpr =
|
|
@@ -210,6 +278,9 @@ export async function executeScheduleUpdate(
|
|
|
210
278
|
maxRetries?: number;
|
|
211
279
|
retryBackoffMs?: number;
|
|
212
280
|
timeoutMs?: number | null;
|
|
281
|
+
workflowName?: string | null;
|
|
282
|
+
workflowArgs?: unknown;
|
|
283
|
+
inferenceProfile?: string | null;
|
|
213
284
|
},
|
|
214
285
|
);
|
|
215
286
|
|
|
@@ -231,6 +302,7 @@ export async function executeScheduleUpdate(
|
|
|
231
302
|
` Description: ${job.description}`,
|
|
232
303
|
` Syntax: ${job.syntax}`,
|
|
233
304
|
` Mode: ${job.mode}`,
|
|
305
|
+
` Inference profile: ${job.inferenceProfile ?? "default (mainAgent)"}`,
|
|
234
306
|
` Schedule: ${scheduleDescription}${job.timezone ? ` (${job.timezone})` : ""}`,
|
|
235
307
|
` Enabled: ${job.enabled}`,
|
|
236
308
|
` Next run: ${job.enabled ? formatLocalDate(job.nextRunAt) : "n/a (disabled)"}`,
|
|
@@ -6,6 +6,62 @@ import type {
|
|
|
6
6
|
ToolExecutionResult,
|
|
7
7
|
} from "../types.js";
|
|
8
8
|
|
|
9
|
+
/** Envelope keys consumed by `skill_execute` itself, never inner-tool params. */
|
|
10
|
+
const SKILL_EXECUTE_ENVELOPE_KEYS = new Set(["tool", "input", "activity"]);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the inner tool's parameters from a `skill_execute` envelope.
|
|
14
|
+
*
|
|
15
|
+
* The documented contract is `{ tool, input: {...}, activity }` — the inner
|
|
16
|
+
* tool's parameters nested under `input`. A correctly nested, non-empty object
|
|
17
|
+
* is returned unchanged, so well-formed callers are unaffected.
|
|
18
|
+
*
|
|
19
|
+
* Weaker models routinely misplace the parameters. Left unhandled, the inner
|
|
20
|
+
* tool receives `{}`, fails schema validation ("<field> is required"), and the
|
|
21
|
+
* model retries the identical malformed call until it gives up — the empty-
|
|
22
|
+
* input retry loop. Two common misplacements are rescued so the call can
|
|
23
|
+
* succeed instead:
|
|
24
|
+
*
|
|
25
|
+
* 1. `input` passed as a JSON-encoded string instead of an object.
|
|
26
|
+
* 2. Parameters spread as top-level siblings of `tool`/`activity`, with `input`
|
|
27
|
+
* absent or an empty object.
|
|
28
|
+
*/
|
|
29
|
+
export function resolveSkillExecuteInput(
|
|
30
|
+
envelope: Record<string, unknown>,
|
|
31
|
+
): Record<string, unknown> {
|
|
32
|
+
const raw = envelope.input;
|
|
33
|
+
|
|
34
|
+
if (raw != null && typeof raw === "object" && !Array.isArray(raw)) {
|
|
35
|
+
const obj = raw as Record<string, unknown>;
|
|
36
|
+
// A populated object is the well-formed case. An empty object falls
|
|
37
|
+
// through to sibling rescue: the model may have nested nothing yet placed
|
|
38
|
+
// the real parameters at the top level.
|
|
39
|
+
if (Object.keys(obj).length > 0) return obj;
|
|
40
|
+
} else if (typeof raw === "string" && raw.trim()) {
|
|
41
|
+
try {
|
|
42
|
+
const parsed: unknown = JSON.parse(raw);
|
|
43
|
+
if (
|
|
44
|
+
parsed != null &&
|
|
45
|
+
typeof parsed === "object" &&
|
|
46
|
+
!Array.isArray(parsed)
|
|
47
|
+
) {
|
|
48
|
+
return parsed as Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
// Not JSON — fall through to sibling rescue.
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const siblings = Object.fromEntries(
|
|
56
|
+
Object.entries(envelope).filter(
|
|
57
|
+
([key]) => !SKILL_EXECUTE_ENVELOPE_KEYS.has(key),
|
|
58
|
+
),
|
|
59
|
+
);
|
|
60
|
+
if (Object.keys(siblings).length > 0) return siblings;
|
|
61
|
+
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
|
|
9
65
|
export const skillExecuteTool = {
|
|
10
66
|
name: "skill_execute",
|
|
11
67
|
description:
|
|
@@ -200,7 +200,7 @@ export const shellTool = {
|
|
|
200
200
|
return {
|
|
201
201
|
content: `Error: unknown credential reference(s): ${unresolvedRefs.join(
|
|
202
202
|
", ",
|
|
203
|
-
)}. Use
|
|
203
|
+
)}. Use \`assistant credentials list\` to see available credentials.`,
|
|
204
204
|
isError: true,
|
|
205
205
|
};
|
|
206
206
|
}
|
|
@@ -35,6 +35,22 @@ function proxyExecute(toolName: string) {
|
|
|
35
35
|
input: Record<string, unknown>,
|
|
36
36
|
context: ToolContext,
|
|
37
37
|
): Promise<ToolExecutionResult> => {
|
|
38
|
+
if (toolName === "ui_show" && isEmptyDynamicPage(input)) {
|
|
39
|
+
return {
|
|
40
|
+
content:
|
|
41
|
+
"Error: ui_show dynamic_page requires non-empty HTML in `data.html`. The surface was not displayed because no content was provided — the user would see a blank box. Resend ui_show with the full HTML markup in `data.html`.",
|
|
42
|
+
isError: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (toolName === "ui_show" && isEmptyCard(input)) {
|
|
47
|
+
return {
|
|
48
|
+
content:
|
|
49
|
+
"Error: ui_show card requires content — provide `data.body`, a `template` (e.g. task_progress with steps), `data.metadata`, or `actions`. The surface was not displayed because it carried only a title, which renders as a blank box. Resend ui_show with populated card content.",
|
|
50
|
+
isError: true,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
38
54
|
if (toolName === "ui_show" && isDynamicPageAppSubstitute(input)) {
|
|
39
55
|
return {
|
|
40
56
|
content:
|
|
@@ -49,10 +65,83 @@ function proxyExecute(toolName: string) {
|
|
|
49
65
|
isError: true,
|
|
50
66
|
};
|
|
51
67
|
}
|
|
52
|
-
|
|
68
|
+
const result = await context.proxyToolResolver(toolName, input);
|
|
69
|
+
if (
|
|
70
|
+
toolName === "ui_show" &&
|
|
71
|
+
!result.isError &&
|
|
72
|
+
typeof result.content === "string" &&
|
|
73
|
+
isTaskProgressCardShow(input)
|
|
74
|
+
) {
|
|
75
|
+
return {
|
|
76
|
+
...result,
|
|
77
|
+
content: `${result.content}\n\n${TASK_PROGRESS_UPDATE_HINT}`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
53
81
|
};
|
|
54
82
|
}
|
|
55
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Worked ui_update example, appended to a successful task_progress `ui_show`
|
|
86
|
+
* result so the model learns the update pattern at the point of use (with the
|
|
87
|
+
* real surface_id in hand) rather than carrying it in the always-present tool
|
|
88
|
+
* description.
|
|
89
|
+
*/
|
|
90
|
+
const TASK_PROGRESS_UPDATE_HINT =
|
|
91
|
+
'As each step finishes, call ui_update with this surface_id to advance it — e.g. ui_update { surface_id: "<the surface_id above>", data: { templateData: { steps: [{ label: "Scaffold project", status: "completed" }, { label: "Wire up commands", status: "in_progress" }] } } }';
|
|
92
|
+
|
|
93
|
+
function isTaskProgressCardShow(input: Record<string, unknown>): boolean {
|
|
94
|
+
if (input.template === "task_progress") {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
const data = asRecord(input.data);
|
|
98
|
+
return data?.template === "task_progress";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function isEmptyDynamicPage(input: Record<string, unknown>): boolean {
|
|
102
|
+
if (input.surface_type !== "dynamic_page") {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
const data = asRecord(input.data);
|
|
106
|
+
const html = data?.html;
|
|
107
|
+
return typeof html !== "string" || html.trim().length === 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* A `card` ui_show carrying no renderable content — only a title (or nothing)
|
|
112
|
+
* — renders as a blank bordered box. A declared `template` (task_progress,
|
|
113
|
+
* weather_forecast, …) renders its own shell, and `body`/`subtitle`/`metadata`/
|
|
114
|
+
* `actions` are real content; any of those passes. The model places these
|
|
115
|
+
* either nested in `data` or at the top level, so both are checked. Title is
|
|
116
|
+
* intentionally not content: a title-only card is the blank box.
|
|
117
|
+
*/
|
|
118
|
+
function isEmptyCard(input: Record<string, unknown>): boolean {
|
|
119
|
+
if (input.surface_type !== "card") {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
const data = asRecord(input.data) ?? {};
|
|
123
|
+
|
|
124
|
+
const template =
|
|
125
|
+
nonEmptyString(input.template) ?? nonEmptyString(data.template);
|
|
126
|
+
if (template) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const hasBody = !!(nonEmptyString(input.body) ?? nonEmptyString(data.body));
|
|
131
|
+
const hasSubtitle = !!nonEmptyString(data.subtitle);
|
|
132
|
+
const hasMetadata = Array.isArray(data.metadata) && data.metadata.length > 0;
|
|
133
|
+
const actions = input.actions ?? data.actions;
|
|
134
|
+
const hasActions = Array.isArray(actions) && actions.length > 0;
|
|
135
|
+
|
|
136
|
+
return !(hasBody || hasSubtitle || hasMetadata || hasActions);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function nonEmptyString(value: unknown): string | undefined {
|
|
140
|
+
return typeof value === "string" && value.trim().length > 0
|
|
141
|
+
? value
|
|
142
|
+
: undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
56
145
|
function isDynamicPageAppSubstitute(input: Record<string, unknown>): boolean {
|
|
57
146
|
if (input.surface_type !== "dynamic_page") {
|
|
58
147
|
return false;
|
|
@@ -137,7 +226,7 @@ export const uiShowTool = {
|
|
|
137
226
|
"- file_upload: { prompt, acceptedTypes?, maxFiles? }\n" +
|
|
138
227
|
"- task_preferences: {} (no data needed — categories are rendered client-side)\n" +
|
|
139
228
|
'- work_result: { eyebrow?, status?: "completed"|"partial"|"failed"|"in_progress", summary?, metrics?: [{ label, value, detail?, tone?: "neutral"|"positive"|"warning"|"negative" }], sections?: [{ id?, title, description?, type?: "items"|"timeline"|"diff"|"artifacts"|"warnings", items?: [{ id?, title, description?, status?, tone?, metadata?: [{ label, value }], href? }], diffs?: [{ label?, before?, after? }] }] }. Shows a structured receipt after real work: what changed, what was skipped, proof points, and next actions. Keep display-only unless explicit follow-up buttons are needed.\n\n' +
|
|
140
|
-
"
|
|
229
|
+
"For multi-step or long-running turns (web searches, file operations, research), show a task_progress card early and keep its steps updated as work progresses. Coarse steps are fine, and you can add or revise them as the work takes shape — a rough card beats no signal.",
|
|
141
230
|
category: "ui-surface",
|
|
142
231
|
defaultRiskLevel: RiskLevel.Low,
|
|
143
232
|
executionTarget: "host",
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `manage_workflows` core implementation — thin reads/controls over
|
|
3
|
+
* {@link WorkflowRunManager}: check a run's status, abort a run, or list recent
|
|
4
|
+
* runs. All state lives in the run manager / journal; this delegates and
|
|
5
|
+
* compacts the result to JSON.
|
|
6
|
+
*
|
|
7
|
+
* NOTE: this runs in-process and returns a `runId`-keyed, deliberately trimmed
|
|
8
|
+
* projection for the model — a DIFFERENT contract from the HTTP wire shape
|
|
9
|
+
* (`id`-keyed `toWireRun`/`workflowRunSchema` in
|
|
10
|
+
* `runtime/routes/workflow-routes.ts`). The two are intentionally not unified:
|
|
11
|
+
* converging on `toWireRun` here would change this tool's emitted JSON. Both
|
|
12
|
+
* project from the same `WorkflowRun` source type, so field renames are caught
|
|
13
|
+
* by the type checker.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { loadConfig } from "../../config/loader.js";
|
|
17
|
+
import { callerOwnsWorkflowRun } from "../../workflows/capabilities.js";
|
|
18
|
+
import type { WorkflowRun } from "../../workflows/journal-store.js";
|
|
19
|
+
import { getWorkflowRunManager } from "../../workflows/run-manager.js";
|
|
20
|
+
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
21
|
+
|
|
22
|
+
export async function executeManageWorkflows(
|
|
23
|
+
input: Record<string, unknown>,
|
|
24
|
+
context: ToolContext,
|
|
25
|
+
): Promise<ToolExecutionResult> {
|
|
26
|
+
const action = input.action as string | undefined;
|
|
27
|
+
const runId = input.run_id as string | undefined;
|
|
28
|
+
const manager = getWorkflowRunManager();
|
|
29
|
+
|
|
30
|
+
// Authorization scope ({@link callerOwnsWorkflowRun}, shared with the
|
|
31
|
+
// executor's resume-approval gate): a guardian may inspect/control every run,
|
|
32
|
+
// but a non-guardian conversation is limited to runs IT originated. Without
|
|
33
|
+
// this, a contact could enumerate a guardian's workflows (names/statuses) via
|
|
34
|
+
// list_runs and then abort/resume them by id — the tool is low-risk and
|
|
35
|
+
// reachable in non-guardian conversations. A run the caller may not see is
|
|
36
|
+
// treated as not-found so the tool never reveals another conversation's run.
|
|
37
|
+
const ownsRun = (run: WorkflowRun): boolean =>
|
|
38
|
+
callerOwnsWorkflowRun(run, context);
|
|
39
|
+
|
|
40
|
+
switch (action) {
|
|
41
|
+
case "status": {
|
|
42
|
+
if (!runId) {
|
|
43
|
+
return {
|
|
44
|
+
content: '"run_id" is required for action "status".',
|
|
45
|
+
isError: true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const run = manager.status(runId);
|
|
49
|
+
if (!run || !ownsRun(run)) {
|
|
50
|
+
return {
|
|
51
|
+
content: JSON.stringify({ runId, found: false }),
|
|
52
|
+
isError: false,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
content: JSON.stringify({
|
|
57
|
+
runId: run.id,
|
|
58
|
+
name: run.name,
|
|
59
|
+
status: run.status,
|
|
60
|
+
agentsSpawned: run.agentsSpawned,
|
|
61
|
+
inputTokens: run.inputTokens,
|
|
62
|
+
outputTokens: run.outputTokens,
|
|
63
|
+
error: run.error,
|
|
64
|
+
}),
|
|
65
|
+
isError: false,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
case "get_result": {
|
|
69
|
+
if (!runId) {
|
|
70
|
+
return {
|
|
71
|
+
content: '"run_id" is required for action "get_result".',
|
|
72
|
+
isError: true,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// The full result payload rides on the run record (journal getRun);
|
|
76
|
+
// `status` omits it to stay lightweight, so this action returns it in
|
|
77
|
+
// full. The completion-summary wake truncates large results and points
|
|
78
|
+
// the assistant here for the complete value.
|
|
79
|
+
const run = manager.status(runId);
|
|
80
|
+
if (!run || !ownsRun(run)) {
|
|
81
|
+
return {
|
|
82
|
+
content: JSON.stringify({ runId, found: false }),
|
|
83
|
+
isError: false,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
content: JSON.stringify({
|
|
88
|
+
runId: run.id,
|
|
89
|
+
status: run.status,
|
|
90
|
+
result: run.result ?? null,
|
|
91
|
+
error: run.error ?? null,
|
|
92
|
+
}),
|
|
93
|
+
isError: false,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
case "abort": {
|
|
97
|
+
if (!runId) {
|
|
98
|
+
return {
|
|
99
|
+
content: '"run_id" is required for action "abort".',
|
|
100
|
+
isError: true,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// Only signal a run the caller owns. A non-owned (or absent) run is a
|
|
104
|
+
// no-op with the same response shape, so existence is never revealed.
|
|
105
|
+
const run = manager.status(runId);
|
|
106
|
+
if (run && ownsRun(run)) manager.abort(runId);
|
|
107
|
+
return {
|
|
108
|
+
content: JSON.stringify({
|
|
109
|
+
runId,
|
|
110
|
+
message: "Abort signalled (no-op if the run already finished).",
|
|
111
|
+
}),
|
|
112
|
+
isError: false,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
case "resume": {
|
|
116
|
+
if (!runId) {
|
|
117
|
+
return {
|
|
118
|
+
content: '"run_id" is required for action "resume".',
|
|
119
|
+
isError: true,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// Don't resume — or reveal — a run the caller doesn't own; mirror
|
|
123
|
+
// resume()'s own not-found message.
|
|
124
|
+
const run = manager.status(runId);
|
|
125
|
+
if (!run || !ownsRun(run)) {
|
|
126
|
+
return {
|
|
127
|
+
content: `Failed to resume workflow: Workflow run ${runId} not found.`,
|
|
128
|
+
isError: true,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const { runId: resumedId } = manager.resume(runId);
|
|
133
|
+
return {
|
|
134
|
+
content: JSON.stringify({
|
|
135
|
+
runId: resumedId,
|
|
136
|
+
status: "running",
|
|
137
|
+
message:
|
|
138
|
+
"Workflow resumed. The completed prefix is replayed from the journal and the run continues from the first unfinished step. You will be notified in this conversation when it completes — do NOT poll.",
|
|
139
|
+
}),
|
|
140
|
+
isError: false,
|
|
141
|
+
};
|
|
142
|
+
} catch (err) {
|
|
143
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
144
|
+
return { content: `Failed to resume workflow: ${msg}`, isError: true };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
case "list_runs": {
|
|
148
|
+
const runs = manager.list().filter(ownsRun);
|
|
149
|
+
return {
|
|
150
|
+
content: JSON.stringify({
|
|
151
|
+
runs: runs.map((r) => ({
|
|
152
|
+
runId: r.id,
|
|
153
|
+
name: r.name,
|
|
154
|
+
status: r.status,
|
|
155
|
+
agentsSpawned: r.agentsSpawned,
|
|
156
|
+
})),
|
|
157
|
+
}),
|
|
158
|
+
isError: false,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
case "list_profiles": {
|
|
162
|
+
// Mirror the `config/llm/profiles` route: sorted profile names plus the
|
|
163
|
+
// workspace-wide active profile. Read-only — leaves use this to pick a
|
|
164
|
+
// valid `profile` for `run_workflow` (an unknown profile throws).
|
|
165
|
+
const { llm } = loadConfig();
|
|
166
|
+
const profiles = llm?.profiles ?? {};
|
|
167
|
+
return {
|
|
168
|
+
content: JSON.stringify({
|
|
169
|
+
profiles: Object.keys(profiles).sort(),
|
|
170
|
+
activeProfile:
|
|
171
|
+
typeof llm?.activeProfile === "string" ? llm.activeProfile : null,
|
|
172
|
+
}),
|
|
173
|
+
isError: false,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
default:
|
|
177
|
+
return {
|
|
178
|
+
content:
|
|
179
|
+
'Unknown action. Use one of: "status", "get_result", "abort", "resume", "list_runs", "list_profiles".',
|
|
180
|
+
isError: true,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|