@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,365 @@
|
|
|
1
|
+
import { afterAll, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { RiskLevel } from "../permissions/types.js";
|
|
4
|
+
import {
|
|
5
|
+
__clearRegistryForTesting,
|
|
6
|
+
__resetRegistryForTesting,
|
|
7
|
+
registerTool,
|
|
8
|
+
registerWorkspaceTools,
|
|
9
|
+
} from "../tools/registry.js";
|
|
10
|
+
import { isSideEffectTool } from "../tools/side-effects.js";
|
|
11
|
+
import type {
|
|
12
|
+
ExecutionTarget,
|
|
13
|
+
Tool,
|
|
14
|
+
ToolContext,
|
|
15
|
+
ToolExecutionResult,
|
|
16
|
+
} from "../tools/types.js";
|
|
17
|
+
import {
|
|
18
|
+
CapabilityManifestSchema,
|
|
19
|
+
CapabilityResolutionError,
|
|
20
|
+
manifestGrantsSideEffects,
|
|
21
|
+
normalizeCapabilityManifest,
|
|
22
|
+
resolveCapabilities,
|
|
23
|
+
WORKFLOW_FORBIDDEN_TOOLS,
|
|
24
|
+
WORKFLOW_READONLY_BASELINE,
|
|
25
|
+
} from "./capabilities.js";
|
|
26
|
+
|
|
27
|
+
function makeFakeTool(
|
|
28
|
+
name: string,
|
|
29
|
+
executionTarget: ExecutionTarget = "sandbox",
|
|
30
|
+
): Tool {
|
|
31
|
+
return {
|
|
32
|
+
name,
|
|
33
|
+
description: `Fake ${name}`,
|
|
34
|
+
category: "test",
|
|
35
|
+
defaultRiskLevel: RiskLevel.Low,
|
|
36
|
+
executionTarget,
|
|
37
|
+
input_schema: { type: "object", properties: {}, required: [] },
|
|
38
|
+
async execute(
|
|
39
|
+
_input: Record<string, unknown>,
|
|
40
|
+
_context: ToolContext,
|
|
41
|
+
): Promise<ToolExecutionResult> {
|
|
42
|
+
return { content: "ok", isError: false };
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// A declarable side-effecting tool that is NOT part of the baseline — used to
|
|
48
|
+
// exercise the "baseline ∪ declared" union path.
|
|
49
|
+
const DECLARABLE_TOOL = "file_write";
|
|
50
|
+
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
// Deterministic registry: only the baseline tools plus one declarable tool.
|
|
53
|
+
__clearRegistryForTesting();
|
|
54
|
+
for (const name of WORKFLOW_READONLY_BASELINE) {
|
|
55
|
+
registerTool(makeFakeTool(name));
|
|
56
|
+
}
|
|
57
|
+
registerTool(makeFakeTool(DECLARABLE_TOOL));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
afterAll(() => {
|
|
61
|
+
// Restore the registry to its post-init baseline so other test files in a
|
|
62
|
+
// combined run are not contaminated.
|
|
63
|
+
__resetRegistryForTesting();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("CapabilityManifestSchema", () => {
|
|
67
|
+
test("applies documented defaults for omitted fields", () => {
|
|
68
|
+
const manifest = CapabilityManifestSchema.parse({});
|
|
69
|
+
expect(manifest).toEqual({
|
|
70
|
+
tools: [],
|
|
71
|
+
hostFunctions: [],
|
|
72
|
+
persona: false,
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("preserves declared values", () => {
|
|
77
|
+
const manifest = CapabilityManifestSchema.parse({
|
|
78
|
+
tools: ["file_write"],
|
|
79
|
+
hostFunctions: ["notify"],
|
|
80
|
+
persona: true,
|
|
81
|
+
});
|
|
82
|
+
expect(manifest).toEqual({
|
|
83
|
+
tools: ["file_write"],
|
|
84
|
+
hostFunctions: ["notify"],
|
|
85
|
+
persona: true,
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("resolveCapabilities", () => {
|
|
91
|
+
test("grants the read-only baseline without declaration", () => {
|
|
92
|
+
const resolved = resolveCapabilities(CapabilityManifestSchema.parse({}));
|
|
93
|
+
const names = resolved.tools.map((t) => t.name).sort();
|
|
94
|
+
expect(names).toEqual([...WORKFLOW_READONLY_BASELINE].sort());
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("the read-only baseline contains no side-effect tools", () => {
|
|
98
|
+
// The baseline is auto-granted with NO launch approval, so every entry must
|
|
99
|
+
// be read-only per the single side-effect source of truth. This invariant
|
|
100
|
+
// is what the defense-in-depth filter in resolveCapabilities enforces.
|
|
101
|
+
for (const name of WORKFLOW_READONLY_BASELINE) {
|
|
102
|
+
expect(isSideEffectTool(name)).toBe(false);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("does NOT auto-grant web_fetch, but it can still be declared", () => {
|
|
107
|
+
// web_fetch is a side-effect tool (its URL can exfiltrate read data or
|
|
108
|
+
// trigger external actions), so an empty-manifest (no-approval) run must not
|
|
109
|
+
// get it — even when it is registered as a core tool.
|
|
110
|
+
registerTool(makeFakeTool("web_fetch"));
|
|
111
|
+
const baseline = resolveCapabilities(CapabilityManifestSchema.parse({}));
|
|
112
|
+
expect(baseline.tools.map((t) => t.name)).not.toContain("web_fetch");
|
|
113
|
+
|
|
114
|
+
// A run that DECLARES web_fetch still gets it — and declaring it flips
|
|
115
|
+
// manifestGrantsSideEffects, which forces the launch approval gate.
|
|
116
|
+
const declared = resolveCapabilities(
|
|
117
|
+
CapabilityManifestSchema.parse({ tools: ["web_fetch"] }),
|
|
118
|
+
);
|
|
119
|
+
expect(declared.tools.map((t) => t.name)).toContain("web_fetch");
|
|
120
|
+
expect(manifestGrantsSideEffects({ tools: ["web_fetch"] })).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("unions baseline with declared tools (no duplicates)", () => {
|
|
124
|
+
const manifest = CapabilityManifestSchema.parse({
|
|
125
|
+
// Declare one new tool plus a baseline tool that should not duplicate.
|
|
126
|
+
tools: [DECLARABLE_TOOL, "file_read"],
|
|
127
|
+
});
|
|
128
|
+
const resolved = resolveCapabilities(manifest);
|
|
129
|
+
const names = resolved.tools.map((t) => t.name).sort();
|
|
130
|
+
expect(names).toEqual(
|
|
131
|
+
[...WORKFLOW_READONLY_BASELINE, DECLARABLE_TOOL].sort(),
|
|
132
|
+
);
|
|
133
|
+
// No duplicate entries for the redeclared baseline tool.
|
|
134
|
+
expect(names.filter((n) => n === "file_read")).toHaveLength(1);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("passes through hostFunctions and persona", () => {
|
|
138
|
+
const manifest = CapabilityManifestSchema.parse({
|
|
139
|
+
hostFunctions: ["host_a", "host_b"],
|
|
140
|
+
persona: true,
|
|
141
|
+
});
|
|
142
|
+
const resolved = resolveCapabilities(manifest);
|
|
143
|
+
expect(resolved.hostFunctions).toEqual(["host_a", "host_b"]);
|
|
144
|
+
expect(resolved.persona).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("rejects a declared tool that does not exist in the registry", () => {
|
|
148
|
+
const manifest = CapabilityManifestSchema.parse({
|
|
149
|
+
tools: ["does_not_exist"],
|
|
150
|
+
});
|
|
151
|
+
expect(() => resolveCapabilities(manifest)).toThrow(
|
|
152
|
+
CapabilityResolutionError,
|
|
153
|
+
);
|
|
154
|
+
try {
|
|
155
|
+
resolveCapabilities(manifest);
|
|
156
|
+
} catch (err) {
|
|
157
|
+
expect(err).toBeInstanceOf(CapabilityResolutionError);
|
|
158
|
+
expect((err as CapabilityResolutionError).reason).toBe("unknown_tool");
|
|
159
|
+
expect((err as CapabilityResolutionError).toolName).toBe(
|
|
160
|
+
"does_not_exist",
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("rejects a declared forbidden tool", () => {
|
|
166
|
+
const forbidden = WORKFLOW_FORBIDDEN_TOOLS[0]!;
|
|
167
|
+
// Even if it were registered, declaring a forbidden tool must throw.
|
|
168
|
+
registerTool(makeFakeTool(forbidden));
|
|
169
|
+
const manifest = CapabilityManifestSchema.parse({ tools: [forbidden] });
|
|
170
|
+
try {
|
|
171
|
+
resolveCapabilities(manifest);
|
|
172
|
+
throw new Error("expected resolveCapabilities to throw");
|
|
173
|
+
} catch (err) {
|
|
174
|
+
expect(err).toBeInstanceOf(CapabilityResolutionError);
|
|
175
|
+
expect((err as CapabilityResolutionError).reason).toBe("forbidden_tool");
|
|
176
|
+
expect((err as CapabilityResolutionError).toolName).toBe(forbidden);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("forbids the CES authenticated tools (executor post-processing bypass)", () => {
|
|
181
|
+
// run_authenticated_command / make_authenticated_request can return
|
|
182
|
+
// `cesApprovalRequired`, which only ToolExecutor bridges + retries. A leaf
|
|
183
|
+
// calls tool.execute() directly, so it would see the raw approval-required
|
|
184
|
+
// result as an error — hence these are forbidden until leaf invocations run
|
|
185
|
+
// the executor's post-processing. Declaring either is a hard error.
|
|
186
|
+
for (const name of [
|
|
187
|
+
"run_authenticated_command",
|
|
188
|
+
"make_authenticated_request",
|
|
189
|
+
]) {
|
|
190
|
+
expect(WORKFLOW_FORBIDDEN_TOOLS).toContain(name);
|
|
191
|
+
registerTool(makeFakeTool(name));
|
|
192
|
+
const manifest = CapabilityManifestSchema.parse({ tools: [name] });
|
|
193
|
+
try {
|
|
194
|
+
resolveCapabilities(manifest);
|
|
195
|
+
throw new Error(`expected resolveCapabilities to throw for ${name}`);
|
|
196
|
+
} catch (err) {
|
|
197
|
+
expect(err).toBeInstanceOf(CapabilityResolutionError);
|
|
198
|
+
expect((err as CapabilityResolutionError).reason).toBe(
|
|
199
|
+
"forbidden_tool",
|
|
200
|
+
);
|
|
201
|
+
expect((err as CapabilityResolutionError).toolName).toBe(name);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("rejects a declared host-proxy tool (executionTarget host)", () => {
|
|
207
|
+
// A leaf builds a synthetic, anonymous ToolContext that carries none of the
|
|
208
|
+
// originating turn's host-routing fields (transportInterface,
|
|
209
|
+
// sourceActorPrincipalId, proxy resolver), so a host tool would mis-route
|
|
210
|
+
// at run time. Rejection keys off the resolved executionTarget, NOT the
|
|
211
|
+
// name — `send_to_host` has no `host_` prefix yet must still be rejected.
|
|
212
|
+
// Every real host tool (host_bash, host_file_*, computer-use) declares
|
|
213
|
+
// `executionTarget: "host"`, so this is the path that catches them.
|
|
214
|
+
registerTool(makeFakeTool("send_to_host", "host"));
|
|
215
|
+
const manifest = CapabilityManifestSchema.parse({
|
|
216
|
+
tools: ["send_to_host"],
|
|
217
|
+
});
|
|
218
|
+
try {
|
|
219
|
+
resolveCapabilities(manifest);
|
|
220
|
+
throw new Error("expected resolveCapabilities to throw");
|
|
221
|
+
} catch (err) {
|
|
222
|
+
expect(err).toBeInstanceOf(CapabilityResolutionError);
|
|
223
|
+
expect((err as CapabilityResolutionError).reason).toBe("host_tool");
|
|
224
|
+
expect((err as CapabilityResolutionError).toolName).toBe("send_to_host");
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("baseline resolves the CORE tool, not a workspace override of the name", () => {
|
|
229
|
+
// A workspace tool may register under a core baseline name (file_read). The
|
|
230
|
+
// baseline is granted to every empty-manifest run WITHOUT the launch
|
|
231
|
+
// approval declared tools require, so it must resolve the trusted core
|
|
232
|
+
// implementation — never the workspace replacement, which could run
|
|
233
|
+
// arbitrary side-effecting behavior unconsented.
|
|
234
|
+
registerWorkspaceTools([
|
|
235
|
+
{
|
|
236
|
+
tool: {
|
|
237
|
+
name: "file_read",
|
|
238
|
+
description: "Workspace override of file_read",
|
|
239
|
+
// A distinct category so we can tell which implementation resolved.
|
|
240
|
+
category: "workspace-marker",
|
|
241
|
+
defaultRiskLevel: RiskLevel.Low,
|
|
242
|
+
executionTarget: "sandbox",
|
|
243
|
+
input_schema: { type: "object", properties: {}, required: [] },
|
|
244
|
+
async execute(): Promise<ToolExecutionResult> {
|
|
245
|
+
return { content: "workspace", isError: false };
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
workspacePath: "/ws",
|
|
249
|
+
},
|
|
250
|
+
]);
|
|
251
|
+
|
|
252
|
+
const resolved = resolveCapabilities(CapabilityManifestSchema.parse({}));
|
|
253
|
+
const fileRead = resolved.tools.find((t) => t.name === "file_read");
|
|
254
|
+
expect(fileRead).toBeDefined();
|
|
255
|
+
// The stashed CORE tool (category "test" from makeFakeTool) wins — NOT the
|
|
256
|
+
// workspace override (category "workspace-marker").
|
|
257
|
+
expect(fileRead?.category).toBe("test");
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test("never includes a forbidden tool in the resolved set", () => {
|
|
261
|
+
// Sanity: forbidden tools and baseline tools are disjoint.
|
|
262
|
+
for (const name of WORKFLOW_FORBIDDEN_TOOLS) {
|
|
263
|
+
expect(WORKFLOW_READONLY_BASELINE).not.toContain(name);
|
|
264
|
+
}
|
|
265
|
+
const resolved = resolveCapabilities(CapabilityManifestSchema.parse({}));
|
|
266
|
+
const names = new Set(resolved.tools.map((t) => t.name));
|
|
267
|
+
for (const forbidden of WORKFLOW_FORBIDDEN_TOOLS) {
|
|
268
|
+
expect(names.has(forbidden)).toBe(false);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
describe("manifestGrantsSideEffects", () => {
|
|
274
|
+
// The launch-time consent gate keys off this predicate: a run that grants
|
|
275
|
+
// side-effecting tools/host functions must prompt; a read-only run must not.
|
|
276
|
+
test("false for an absent or empty manifest (read-only baseline only)", () => {
|
|
277
|
+
expect(manifestGrantsSideEffects(undefined)).toBe(false);
|
|
278
|
+
expect(manifestGrantsSideEffects(null)).toBe(false);
|
|
279
|
+
expect(manifestGrantsSideEffects({})).toBe(false);
|
|
280
|
+
expect(manifestGrantsSideEffects({ tools: [], hostFunctions: [] })).toBe(
|
|
281
|
+
false,
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("true when the manifest declares side-effecting tools", () => {
|
|
286
|
+
expect(manifestGrantsSideEffects({ tools: ["file_write"] })).toBe(true);
|
|
287
|
+
expect(manifestGrantsSideEffects({ tools: ["bash", "send_email"] })).toBe(
|
|
288
|
+
true,
|
|
289
|
+
);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test("true when the manifest declares host functions", () => {
|
|
293
|
+
expect(manifestGrantsSideEffects({ hostFunctions: ["notify"] })).toBe(true);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test("persona alone is NOT side-effecting (identity/memory, not tools)", () => {
|
|
297
|
+
expect(manifestGrantsSideEffects({ persona: true })).toBe(false);
|
|
298
|
+
expect(
|
|
299
|
+
manifestGrantsSideEffects({
|
|
300
|
+
tools: [],
|
|
301
|
+
hostFunctions: [],
|
|
302
|
+
persona: true,
|
|
303
|
+
}),
|
|
304
|
+
).toBe(false);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test("false (never throws) for a malformed manifest — execute re-parses and rejects it", () => {
|
|
308
|
+
expect(manifestGrantsSideEffects({ tools: "not-an-array" })).toBe(false);
|
|
309
|
+
expect(manifestGrantsSideEffects(42)).toBe(false);
|
|
310
|
+
expect(manifestGrantsSideEffects("nope")).toBe(false);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test("true for the older RESOLVED stored shape (tools as Tool objects)", () => {
|
|
314
|
+
// Some interrupted runs persisted resolved Tool objects rather than string
|
|
315
|
+
// names. resume() recovers those names and grants the tools, so the consent
|
|
316
|
+
// gate must see them as side-effecting too — a strict parse would reject the
|
|
317
|
+
// object shape and wrongly report a read-only run, letting resume restart
|
|
318
|
+
// side-effecting leaves without approval.
|
|
319
|
+
expect(
|
|
320
|
+
manifestGrantsSideEffects({
|
|
321
|
+
tools: [{ name: "bash" }],
|
|
322
|
+
hostFunctions: [],
|
|
323
|
+
persona: false,
|
|
324
|
+
}),
|
|
325
|
+
).toBe(true);
|
|
326
|
+
expect(
|
|
327
|
+
manifestGrantsSideEffects({
|
|
328
|
+
tools: [{ name: "file_write", category: "fs" }],
|
|
329
|
+
}),
|
|
330
|
+
).toBe(true);
|
|
331
|
+
// An empty resolved-shape run is still read-only.
|
|
332
|
+
expect(manifestGrantsSideEffects({ tools: [] })).toBe(false);
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
describe("normalizeCapabilityManifest", () => {
|
|
337
|
+
test("recovers tool names from BOTH string and Tool-object entries", () => {
|
|
338
|
+
expect(
|
|
339
|
+
normalizeCapabilityManifest({
|
|
340
|
+
tools: ["file_read", { name: "bash" }, { nope: 1 }, 42],
|
|
341
|
+
hostFunctions: ["notify", 7],
|
|
342
|
+
persona: true,
|
|
343
|
+
}),
|
|
344
|
+
).toEqual({
|
|
345
|
+
tools: ["file_read", "bash"],
|
|
346
|
+
hostFunctions: ["notify"],
|
|
347
|
+
persona: true,
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
test("total: a malformed/absent blob yields empty arrays, never throws", () => {
|
|
352
|
+
expect(normalizeCapabilityManifest(undefined)).toEqual({
|
|
353
|
+
tools: [],
|
|
354
|
+
hostFunctions: [],
|
|
355
|
+
persona: false,
|
|
356
|
+
});
|
|
357
|
+
expect(normalizeCapabilityManifest({ tools: "x", persona: "yes" })).toEqual(
|
|
358
|
+
{
|
|
359
|
+
tools: [],
|
|
360
|
+
hostFunctions: [],
|
|
361
|
+
persona: false,
|
|
362
|
+
},
|
|
363
|
+
);
|
|
364
|
+
});
|
|
365
|
+
});
|