@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
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-run capability manifest and scoped tool resolution for the workflow
|
|
3
|
+
* orchestration engine.
|
|
4
|
+
*
|
|
5
|
+
* A workflow script declares — once, at the run level — which tools, host
|
|
6
|
+
* functions, and persona access its leaf agents may use. That declaration is
|
|
7
|
+
* the **single consent point** for the entire run: there are no per-leaf or
|
|
8
|
+
* per-call permission prompts inside a workflow run. The engine/leaf runner
|
|
9
|
+
* calls {@link resolveCapabilities} once and then **hard-denies**
|
|
10
|
+
* any tool invocation that falls outside the resolved set.
|
|
11
|
+
*
|
|
12
|
+
* Resolution policy:
|
|
13
|
+
*
|
|
14
|
+
* - Leaves always get a curated read-only baseline ({@link WORKFLOW_READONLY_BASELINE})
|
|
15
|
+
* without having to declare it — low-risk file reads, listing, search, and
|
|
16
|
+
* memory recall.
|
|
17
|
+
* - Side-effecting tools (writes, sends, shell, etc.) are NOT in the baseline;
|
|
18
|
+
* a run must declare them explicitly in its manifest to grant them.
|
|
19
|
+
* - A small set of tools is {@link WORKFLOW_FORBIDDEN_TOOLS forbidden} and can
|
|
20
|
+
* never be granted to a leaf regardless of declaration (recursion vectors,
|
|
21
|
+
* the workflow-management tools themselves, and CES bundle management).
|
|
22
|
+
* - Host-proxy tools (resolved `executionTarget === "host"` — e.g. `host_bash`,
|
|
23
|
+
* `host_file_*`, computer-use) are rejected too: a leaf builds a synthetic,
|
|
24
|
+
* anonymous `ToolContext` that carries none of the originating turn's
|
|
25
|
+
* `transportInterface` / `sourceActorPrincipalId` / proxy-resolver fields, so
|
|
26
|
+
* a host tool would either fall back to in-container execution or proxy to the
|
|
27
|
+
* user's machine WITHOUT the authenticated-identity binding those tools rely
|
|
28
|
+
* on. Unattended, fanned-out leaves must not perform host side effects in v1.
|
|
29
|
+
* (If host execution is ever wanted, the deliberate path is to thread the
|
|
30
|
+
* originating tool context through the engine — not to relax this gate.)
|
|
31
|
+
*
|
|
32
|
+
* This module is pure logic: it performs no feature-flag checks and no I/O
|
|
33
|
+
* beyond the synchronous tool-registry lookup. The `workflows` flag gates the
|
|
34
|
+
* callers, not this code.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import { z } from "zod";
|
|
38
|
+
|
|
39
|
+
import type { TrustClass } from "../runtime/actor-trust-resolver.js";
|
|
40
|
+
import { resolveExecutionTarget } from "../tools/execution-target.js";
|
|
41
|
+
import {
|
|
42
|
+
getCoreToolOverride,
|
|
43
|
+
getTool,
|
|
44
|
+
getToolOwner,
|
|
45
|
+
} from "../tools/registry.js";
|
|
46
|
+
import { isSideEffectTool } from "../tools/side-effects.js";
|
|
47
|
+
import type { Tool } from "../tools/types.js";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Curated read-only baseline available to every workflow leaf without
|
|
51
|
+
* declaration. Each entry is an existing core tool that only reads, lists, or
|
|
52
|
+
* searches — never writes, sends, executes arbitrary code, or otherwise
|
|
53
|
+
* mutates state. Mutating low-risk tools (e.g. `file_write`, `file_edit`,
|
|
54
|
+
* `remember`) and arbitrary-execution tools (`bash`, `skill_execute`) are
|
|
55
|
+
* deliberately excluded even though some carry a low risk band; the baseline
|
|
56
|
+
* is gated on read-only behavior, not on the risk level alone.
|
|
57
|
+
*
|
|
58
|
+
* `web_fetch` is deliberately NOT here: it is classified as a side-effect tool
|
|
59
|
+
* (an outbound request can trigger external actions or exfiltrate read data via
|
|
60
|
+
* the URL — see {@link isSideEffectTool}). The baseline is auto-granted with NO
|
|
61
|
+
* launch approval, so it must carry no side effects; a run that needs
|
|
62
|
+
* `web_fetch` must DECLARE it in its manifest, which forces the launch approval
|
|
63
|
+
* gate ({@link manifestGrantsSideEffects}). {@link resolveCapabilities} also
|
|
64
|
+
* filters the baseline through `isSideEffectTool` as defense in depth.
|
|
65
|
+
*/
|
|
66
|
+
export const WORKFLOW_READONLY_BASELINE: readonly string[] = [
|
|
67
|
+
"file_read",
|
|
68
|
+
"file_list",
|
|
69
|
+
"recall",
|
|
70
|
+
"web_search",
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Tools that may never be granted to a workflow leaf, regardless of what a
|
|
75
|
+
* manifest declares. Declaring one is a hard error in
|
|
76
|
+
* {@link resolveCapabilities}.
|
|
77
|
+
*
|
|
78
|
+
* - `subagent_spawn` — leaves must not spawn nested agents; the workflow
|
|
79
|
+
* engine owns fan-out.
|
|
80
|
+
* - `run_workflow` / `manage_workflows` — the workflow tools themselves;
|
|
81
|
+
* granting either to a leaf would let it recurse into or reconfigure the
|
|
82
|
+
* engine.
|
|
83
|
+
* - `manage_secure_command_tool` — CES secure-bundle management is a
|
|
84
|
+
* human-in-the-loop install path and is never delegated to an unattended
|
|
85
|
+
* leaf.
|
|
86
|
+
* - `run_authenticated_command` / `make_authenticated_request` — these CES
|
|
87
|
+
* tools can return `cesApprovalRequired`, which `ToolExecutor` handles by
|
|
88
|
+
* bridging an interactive approval and RETRYING the call with the grant. A
|
|
89
|
+
* leaf invokes `tool.execute()` directly (the manifest is the run's single
|
|
90
|
+
* consent point, so leaves bypass the executor's permission/approval path),
|
|
91
|
+
* so it would see the raw `cesApprovalRequired` result as a plain error
|
|
92
|
+
* instead of the approve-and-retry flow — silently degrading. Forbid them
|
|
93
|
+
* until leaf invocations run the executor's post-processing (the deliberate
|
|
94
|
+
* future path); declaring one then fails loudly at the consent point rather
|
|
95
|
+
* than confusingly at run time.
|
|
96
|
+
*/
|
|
97
|
+
export const WORKFLOW_FORBIDDEN_TOOLS: readonly string[] = [
|
|
98
|
+
"subagent_spawn",
|
|
99
|
+
"run_workflow",
|
|
100
|
+
"manage_workflows",
|
|
101
|
+
"manage_secure_command_tool",
|
|
102
|
+
"run_authenticated_command",
|
|
103
|
+
"make_authenticated_request",
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Per-run capability declaration. The single consent surface for a workflow
|
|
108
|
+
* run — `tools` and `hostFunctions` are explicit grants on top of the
|
|
109
|
+
* read-only baseline; `persona` opts the run into persona access.
|
|
110
|
+
*/
|
|
111
|
+
export const CapabilityManifestSchema = z.object({
|
|
112
|
+
/** Tool names granted to leaves on top of the read-only baseline. */
|
|
113
|
+
tools: z.array(z.string()).default([]),
|
|
114
|
+
/** Host-function names the run is permitted to invoke. */
|
|
115
|
+
hostFunctions: z.array(z.string()).default([]),
|
|
116
|
+
/** Whether leaves may access persona context. */
|
|
117
|
+
persona: z.boolean().default(false),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
export type CapabilityManifest = z.infer<typeof CapabilityManifestSchema>;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Normalize a stored/raw capability blob into a {@link CapabilityManifest},
|
|
124
|
+
* tolerating BOTH shapes a run row can hold:
|
|
125
|
+
*
|
|
126
|
+
* - the canonical declared shape — `tools`/`hostFunctions` as string names; and
|
|
127
|
+
* - the older RESOLVED shape some interrupted runs persisted — `tools` as
|
|
128
|
+
* resolved Tool objects (`[{ name: "bash" }, …]`).
|
|
129
|
+
*
|
|
130
|
+
* Tool entries are reduced to their string name (string entries kept as-is,
|
|
131
|
+
* object entries via `.name`); non-string host functions are dropped; `persona`
|
|
132
|
+
* is coerced to a boolean. Total and never-throwing: a malformed/absent blob
|
|
133
|
+
* yields empty arrays.
|
|
134
|
+
*
|
|
135
|
+
* This is THE single normalization both the resume path
|
|
136
|
+
* ({@link WorkflowRunManager.resume}, which re-grants the recovered tools) and
|
|
137
|
+
* the consent gate ({@link manifestGrantsSideEffects}) must share, so the gate
|
|
138
|
+
* cannot decide "no side effects" on a blob that `resume()` would in fact grant
|
|
139
|
+
* side-effecting tools from.
|
|
140
|
+
*/
|
|
141
|
+
export function normalizeCapabilityManifest(
|
|
142
|
+
stored: unknown,
|
|
143
|
+
): CapabilityManifest {
|
|
144
|
+
const obj =
|
|
145
|
+
stored && typeof stored === "object"
|
|
146
|
+
? (stored as Record<string, unknown>)
|
|
147
|
+
: {};
|
|
148
|
+
const tools = Array.isArray(obj.tools)
|
|
149
|
+
? obj.tools
|
|
150
|
+
.map((t) =>
|
|
151
|
+
typeof t === "string"
|
|
152
|
+
? t
|
|
153
|
+
: t && typeof t === "object"
|
|
154
|
+
? ((t as Record<string, unknown>).name as string | undefined)
|
|
155
|
+
: undefined,
|
|
156
|
+
)
|
|
157
|
+
.filter((n): n is string => typeof n === "string")
|
|
158
|
+
: [];
|
|
159
|
+
const hostFunctions = Array.isArray(obj.hostFunctions)
|
|
160
|
+
? obj.hostFunctions.filter((n): n is string => typeof n === "string")
|
|
161
|
+
: [];
|
|
162
|
+
return { tools, hostFunctions, persona: obj.persona === true };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* True if a capability manifest grants any side-effecting capability beyond the
|
|
167
|
+
* read-only baseline — i.e. it declares one or more `tools` or `hostFunctions`.
|
|
168
|
+
*
|
|
169
|
+
* The tool executor uses this to force an interactive approval at LAUNCH for
|
|
170
|
+
* such runs (and on RESUME of a stored run). The manifest is the single consent
|
|
171
|
+
* point, but it is authored and declared BY THE MODEL, and a workflow's leaves
|
|
172
|
+
* execute granted tools directly (no per-call permission check) — so without a
|
|
173
|
+
* launch/resume-time gate the model could self-grant `bash`/sends/writes and
|
|
174
|
+
* have leaves run them with no user consent, bypassing the gate those tools hit
|
|
175
|
+
* when the main agent calls them. A read-only run (no declared
|
|
176
|
+
* `tools`/`hostFunctions`) needs no prompt.
|
|
177
|
+
*
|
|
178
|
+
* Runs the SAME {@link normalizeCapabilityManifest} the resume path uses, so it
|
|
179
|
+
* detects grants in BOTH the declared (string names) and older resolved
|
|
180
|
+
* (Tool-object) stored shapes — a strict parse would reject the resolved shape
|
|
181
|
+
* and wrongly report "no grant", letting `resume()` restart side-effecting
|
|
182
|
+
* leaves without approval. Total and never-throwing (the risk-gating path must
|
|
183
|
+
* not throw); a malformed/absent manifest yields "no grant" (false). `persona`
|
|
184
|
+
* is deliberately NOT treated as side-effecting: it grants identity/memory
|
|
185
|
+
* context, not world-mutating tools.
|
|
186
|
+
*/
|
|
187
|
+
export function manifestGrantsSideEffects(rawCapabilities: unknown): boolean {
|
|
188
|
+
const m = normalizeCapabilityManifest(rawCapabilities);
|
|
189
|
+
return m.tools.length > 0 || m.hostFunctions.length > 0;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Whether `caller` may see and control a workflow run. A guardian (the trusted
|
|
194
|
+
* user) owns every run; any other actor owns only runs ORIGINATED by their own
|
|
195
|
+
* conversation (`run.conversationId` is the launching conversation `run_workflow`
|
|
196
|
+
* records). THE single authorization scope shared by the `manage_workflows` tool
|
|
197
|
+
* and the executor's resume-approval gate, so the gate never prompts for — and
|
|
198
|
+
* thereby leaks the existence of — a run the tool would hide as not-found.
|
|
199
|
+
*/
|
|
200
|
+
export function callerOwnsWorkflowRun(
|
|
201
|
+
run: { conversationId: string | null },
|
|
202
|
+
caller: { trustClass: TrustClass; conversationId: string },
|
|
203
|
+
): boolean {
|
|
204
|
+
return (
|
|
205
|
+
caller.trustClass === "guardian" ||
|
|
206
|
+
run.conversationId === caller.conversationId
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Error thrown when a manifest declares a tool that cannot be resolved — either
|
|
212
|
+
* because it does not exist in the tool registry or because it is forbidden.
|
|
213
|
+
*/
|
|
214
|
+
export class CapabilityResolutionError extends Error {
|
|
215
|
+
constructor(
|
|
216
|
+
message: string,
|
|
217
|
+
readonly reason: "unknown_tool" | "forbidden_tool" | "host_tool",
|
|
218
|
+
readonly toolName: string,
|
|
219
|
+
) {
|
|
220
|
+
super(message);
|
|
221
|
+
this.name = "CapabilityResolutionError";
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Result of {@link resolveCapabilities}: the concrete set of tools a leaf may
|
|
227
|
+
* invoke (baseline ∪ declared, minus forbidden), plus the run's host-function
|
|
228
|
+
* and persona grants. The engine/leaf runner hard-denies any invocation whose
|
|
229
|
+
* tool is not in `tools`.
|
|
230
|
+
*/
|
|
231
|
+
export interface ResolvedCapabilities {
|
|
232
|
+
/**
|
|
233
|
+
* Resolved tool objects from the registry — the exhaustive allow-set for
|
|
234
|
+
* the run. Reuses the registry's {@link Tool} type so the leaf runner can
|
|
235
|
+
* pass these straight through to the agent loop.
|
|
236
|
+
*/
|
|
237
|
+
tools: Tool[];
|
|
238
|
+
/** Host functions the run may invoke. */
|
|
239
|
+
hostFunctions: string[];
|
|
240
|
+
/** Whether the run has persona access. */
|
|
241
|
+
persona: boolean;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const FORBIDDEN_SET: ReadonlySet<string> = new Set(WORKFLOW_FORBIDDEN_TOOLS);
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Resolve a read-only baseline name to its TRUSTED CORE implementation — never a
|
|
248
|
+
* workspace (or other non-core) override.
|
|
249
|
+
*
|
|
250
|
+
* The baseline is granted to every workflow leaf WITHOUT a manifest declaration,
|
|
251
|
+
* and {@link manifestGrantsSideEffects} only forces the launch approval for
|
|
252
|
+
* DECLARED tools/host functions. A workspace tool may register under a core name
|
|
253
|
+
* such as `file_read`: the registry stashes the original core tool and installs
|
|
254
|
+
* the workspace replacement under that name. A plain {@link getTool} lookup would
|
|
255
|
+
* then hand that replacement — with arbitrary side-effecting behavior — to every
|
|
256
|
+
* empty-manifest run, with no consent.
|
|
257
|
+
*
|
|
258
|
+
* Core tools have no owner ({@link getToolOwner} returns `undefined`). If any
|
|
259
|
+
* owner holds this name, the live entry is an override, so resolve the stashed
|
|
260
|
+
* original core tool ({@link getCoreToolOverride}) instead — and never the
|
|
261
|
+
* replacement. Returns `undefined` (skipped, not failed) when no trusted core
|
|
262
|
+
* entry exists, matching the baseline's convenience-grant semantics.
|
|
263
|
+
*/
|
|
264
|
+
function resolveBaselineTool(name: string): Tool | undefined {
|
|
265
|
+
if (getToolOwner(name)) return getCoreToolOverride(name);
|
|
266
|
+
return getTool(name);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Resolve a {@link CapabilityManifest} into the concrete capability set a
|
|
271
|
+
* workflow run's leaves are allowed to use.
|
|
272
|
+
*
|
|
273
|
+
* The resolved tool set is the read-only baseline unioned with the manifest's
|
|
274
|
+
* declared tools, with forbidden tools rejected (never silently dropped):
|
|
275
|
+
*
|
|
276
|
+
* - Every declared tool name must exist in the tool registry, else a
|
|
277
|
+
* `CapabilityResolutionError("unknown_tool")` is thrown.
|
|
278
|
+
* - Any declared tool in {@link WORKFLOW_FORBIDDEN_TOOLS} throws a
|
|
279
|
+
* `CapabilityResolutionError("forbidden_tool")`.
|
|
280
|
+
* - The baseline is intersected against the registry too, so a baseline entry
|
|
281
|
+
* that is somehow unregistered is skipped rather than dangling.
|
|
282
|
+
*
|
|
283
|
+
* Because the manifest is the single consent point, the returned `tools` array
|
|
284
|
+
* is the exhaustive allow-set: the leaf runner hard-denies anything outside it
|
|
285
|
+
* and performs no per-call permission prompts inside the run.
|
|
286
|
+
*/
|
|
287
|
+
export function resolveCapabilities(
|
|
288
|
+
manifest: CapabilityManifest,
|
|
289
|
+
): ResolvedCapabilities {
|
|
290
|
+
// Reject forbidden declarations up front — even though forbidden tools are
|
|
291
|
+
// stripped from the final union, an explicit declaration is a manifest
|
|
292
|
+
// authoring error and must surface loudly rather than be silently ignored.
|
|
293
|
+
for (const name of manifest.tools) {
|
|
294
|
+
if (FORBIDDEN_SET.has(name)) {
|
|
295
|
+
throw new CapabilityResolutionError(
|
|
296
|
+
`Tool "${name}" is forbidden in workflow runs and cannot be declared.`,
|
|
297
|
+
"forbidden_tool",
|
|
298
|
+
name,
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const resolved = new Map<string, Tool>();
|
|
304
|
+
|
|
305
|
+
// Baseline first, resolved from the TRUSTED CORE implementation only (a
|
|
306
|
+
// workspace override of a core name must NOT be auto-granted without consent —
|
|
307
|
+
// see resolveBaselineTool). A baseline name with no trusted core entry
|
|
308
|
+
// (unexpected, but possible if a core tool is renamed or a workspace tool
|
|
309
|
+
// shadows it with no stashed original) is skipped — the baseline is a
|
|
310
|
+
// convenience grant, not a declaration, so a missing entry should not fail
|
|
311
|
+
// the run. Forbidden filtering still applies for defense in depth.
|
|
312
|
+
for (const name of WORKFLOW_READONLY_BASELINE) {
|
|
313
|
+
if (FORBIDDEN_SET.has(name)) continue;
|
|
314
|
+
// Defense in depth: the baseline is auto-granted with NO launch approval, so
|
|
315
|
+
// it must never carry a side-effecting tool (e.g. web_fetch, whose URL can
|
|
316
|
+
// exfiltrate read data or trigger external actions). isSideEffectTool is the
|
|
317
|
+
// single source of truth; skip any baseline entry it flags so the no-consent
|
|
318
|
+
// grant can never include a side effect, even if the list above drifts. A
|
|
319
|
+
// run that needs such a tool must DECLARE it (forcing the launch approval).
|
|
320
|
+
if (isSideEffectTool(name)) continue;
|
|
321
|
+
const tool = resolveBaselineTool(name);
|
|
322
|
+
if (tool) resolved.set(name, tool);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Declared tools must exist — a missing one is an authoring error.
|
|
326
|
+
for (const name of manifest.tools) {
|
|
327
|
+
const tool = getTool(name);
|
|
328
|
+
if (!tool) {
|
|
329
|
+
throw new CapabilityResolutionError(
|
|
330
|
+
`Tool "${name}" declared in the workflow manifest does not exist in the tool registry.`,
|
|
331
|
+
"unknown_tool",
|
|
332
|
+
name,
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
// Host-proxy tools run on the user's machine (or fall back to in-container
|
|
336
|
+
// execution) and depend on originating-turn context — `transportInterface`,
|
|
337
|
+
// `sourceActorPrincipalId`, the proxy resolver — that a leaf's synthetic,
|
|
338
|
+
// anonymous ToolContext does not carry. Granting one to an unattended,
|
|
339
|
+
// fanned-out leaf would perform host side effects in the wrong environment
|
|
340
|
+
// or without the authenticated-identity binding the proxy requires. Reject
|
|
341
|
+
// loudly at the consent point rather than silently mis-route at run time.
|
|
342
|
+
if (resolveExecutionTarget(tool) === "host") {
|
|
343
|
+
throw new CapabilityResolutionError(
|
|
344
|
+
`Tool "${name}" runs on the host (executionTarget "host") and cannot ` +
|
|
345
|
+
`be granted to a workflow leaf, which runs unattended without the ` +
|
|
346
|
+
`originating turn's host-routing context.`,
|
|
347
|
+
"host_tool",
|
|
348
|
+
name,
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
resolved.set(name, tool);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return {
|
|
355
|
+
tools: Array.from(resolved.values()),
|
|
356
|
+
hostFunctions: [...manifest.hostFunctions],
|
|
357
|
+
persona: manifest.persona,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic JSON stringify with recursively sorted object keys.
|
|
3
|
+
*
|
|
4
|
+
* Used by the workflow engine and sandbox so marshalled values that feed the
|
|
5
|
+
* resume hash (`call_hash = sha256(deterministicStringify({ prompt, opts }))`)
|
|
6
|
+
* and host-call results are stable regardless of insertion order. `undefined`
|
|
7
|
+
* round-trips to the string `"null"` (top-level `JSON.stringify(undefined)` is
|
|
8
|
+
* itself `undefined`, which the `?? "null"` fallback maps to `"null"`); JSON
|
|
9
|
+
* has no `undefined`.
|
|
10
|
+
*
|
|
11
|
+
* The byte-for-byte output of this function is load-bearing: it feeds the
|
|
12
|
+
* resume hash, so any change to its serialization would silently invalidate
|
|
13
|
+
* every existing journal's cached prefix. Do not "improve" it.
|
|
14
|
+
*/
|
|
15
|
+
export function deterministicStringify(value: unknown): string {
|
|
16
|
+
return JSON.stringify(sortValue(value)) ?? "null";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function sortValue(value: unknown): unknown {
|
|
20
|
+
if (value === null || typeof value !== "object") return value;
|
|
21
|
+
if (Array.isArray(value)) return value.map(sortValue);
|
|
22
|
+
const out: Record<string, unknown> = {};
|
|
23
|
+
for (const key of Object.keys(value as Record<string, unknown>).sort()) {
|
|
24
|
+
out[key] = sortValue((value as Record<string, unknown>)[key]);
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|