@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vellumai/assistant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-staging.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"@agentclientprotocol/sdk": "0.25.0",
|
|
37
37
|
"@anthropic-ai/sdk": "0.78.0",
|
|
38
38
|
"@google/genai": "1.45.0",
|
|
39
|
+
"@jitl/quickjs-singlefile-mjs-release-asyncify": "0.32.0",
|
|
39
40
|
"@modelcontextprotocol/sdk": "1.27.1",
|
|
40
41
|
"@qdrant/js-client-rest": "1.17.0",
|
|
41
42
|
"@resvg/resvg-js": "2.6.2",
|
|
@@ -60,16 +61,18 @@
|
|
|
60
61
|
"openai": "6.29.0",
|
|
61
62
|
"pino": "9.14.0",
|
|
62
63
|
"pino-pretty": "13.1.3",
|
|
63
|
-
"semver": "7.8.0",
|
|
64
64
|
"playwright": "1.58.2",
|
|
65
65
|
"postgres": "3.4.8",
|
|
66
|
+
"quickjs-emscripten": "0.32.0",
|
|
66
67
|
"rrule": "2.8.1",
|
|
68
|
+
"semver": "7.8.0",
|
|
67
69
|
"stemmer": "2.0.1",
|
|
68
70
|
"tar-stream": "3.1.7",
|
|
69
71
|
"tldts": "7.0.25",
|
|
70
72
|
"uuid": "11.1.0",
|
|
71
73
|
"yaml": "2.8.2",
|
|
72
|
-
"zod": "4.3.6"
|
|
74
|
+
"zod": "4.3.6",
|
|
75
|
+
"zod-openapi": "5.4.6"
|
|
73
76
|
},
|
|
74
77
|
"engines": {
|
|
75
78
|
"node": ">=20.12.0"
|
|
@@ -100,7 +103,8 @@
|
|
|
100
103
|
"@types/node": "25.5.0",
|
|
101
104
|
"@types/semver": "7.5.8",
|
|
102
105
|
"@types/uuid": "10.0.0",
|
|
103
|
-
"
|
|
106
|
+
"ajv": "8.18.0",
|
|
107
|
+
"drizzle-kit": "0.31.10",
|
|
104
108
|
"eslint": "10.0.3",
|
|
105
109
|
"eslint-plugin-simple-import-sort": "12.1.1",
|
|
106
110
|
"fast-check": "4.6.0",
|
|
@@ -19,10 +19,16 @@
|
|
|
19
19
|
import { readFileSync } from "node:fs";
|
|
20
20
|
import { readdir, readFile, writeFile } from "node:fs/promises";
|
|
21
21
|
import { join, resolve } from "node:path";
|
|
22
|
-
import { Readable } from "node:stream";
|
|
23
22
|
|
|
24
23
|
import { stringify } from "yaml";
|
|
25
24
|
import { z } from "zod";
|
|
25
|
+
import type {
|
|
26
|
+
oas31,
|
|
27
|
+
ZodOpenApiOperationObject,
|
|
28
|
+
ZodOpenApiPathsObject,
|
|
29
|
+
ZodOpenApiResponseObject,
|
|
30
|
+
} from "zod-openapi";
|
|
31
|
+
import { createDocument } from "zod-openapi";
|
|
26
32
|
|
|
27
33
|
const ROOT = resolve(import.meta.dir, "..");
|
|
28
34
|
const ROUTES_DIR = join(ROOT, "src/runtime/routes");
|
|
@@ -46,13 +52,13 @@ const RouteQueryParamSchema = z.object({
|
|
|
46
52
|
* JSON-Schema-style object for backward compatibility with inline routes.
|
|
47
53
|
*/
|
|
48
54
|
const RouteBodySchemaSchema = z.any().refine(
|
|
49
|
-
(v) =>
|
|
55
|
+
(v): v is z.ZodType | oas31.SchemaObject =>
|
|
50
56
|
v != null &&
|
|
51
57
|
typeof v === "object" &&
|
|
52
58
|
// Zod schema instance (Zod 4 uses _zod branded property)
|
|
53
59
|
("_zod" in v ||
|
|
54
60
|
// Plain JSON Schema fallback
|
|
55
|
-
|
|
61
|
+
"type" in v),
|
|
56
62
|
{ message: "Expected a Zod schema or a plain JSON Schema object" },
|
|
57
63
|
);
|
|
58
64
|
|
|
@@ -111,67 +117,29 @@ const RouteEntrySchema = z.object({
|
|
|
111
117
|
|
|
112
118
|
type RouteEntry = z.infer<typeof RouteEntrySchema>;
|
|
113
119
|
|
|
114
|
-
|
|
115
|
-
interface JSONSchemaObject {
|
|
116
|
-
type?: string;
|
|
117
|
-
properties?: Record<string, unknown>;
|
|
118
|
-
required?: string[];
|
|
119
|
-
description?: string;
|
|
120
|
-
additionalProperties?: boolean;
|
|
121
|
-
[key: string]: unknown;
|
|
122
|
-
}
|
|
120
|
+
type ContentSchema = z.ZodType | oas31.SchemaObject;
|
|
123
121
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
* omits the field — generated clients should not be forced to send it.
|
|
130
|
-
*/
|
|
131
|
-
function dropDefaultedFromRequired(node: unknown): void {
|
|
132
|
-
if (node == null || typeof node !== "object") return;
|
|
133
|
-
if (Array.isArray(node)) {
|
|
134
|
-
for (const item of node) dropDefaultedFromRequired(item);
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
const obj = node as Record<string, unknown>;
|
|
138
|
-
const props = obj.properties;
|
|
139
|
-
const required = obj.required;
|
|
140
|
-
if (Array.isArray(required) && props != null && typeof props === "object") {
|
|
141
|
-
const propsRecord = props as Record<string, unknown>;
|
|
142
|
-
const filtered = required.filter((name) => {
|
|
143
|
-
if (typeof name !== "string") return true;
|
|
144
|
-
const prop = propsRecord[name];
|
|
145
|
-
return !(
|
|
146
|
-
prop != null &&
|
|
147
|
-
typeof prop === "object" &&
|
|
148
|
-
"default" in (prop as Record<string, unknown>)
|
|
149
|
-
);
|
|
150
|
-
});
|
|
151
|
-
if (filtered.length > 0) obj.required = filtered;
|
|
152
|
-
else delete obj.required;
|
|
122
|
+
type HttpStatusCode = `${1 | 2 | 3 | 4 | 5}${string}`;
|
|
123
|
+
|
|
124
|
+
function toHttpStatus(status: string): HttpStatusCode {
|
|
125
|
+
if (!/^[1-5]\d{2}$/.test(status)) {
|
|
126
|
+
throw new Error(`Invalid HTTP status code: ${status}`);
|
|
153
127
|
}
|
|
154
|
-
|
|
128
|
+
return status as HttpStatusCode;
|
|
155
129
|
}
|
|
156
130
|
|
|
157
|
-
/**
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
});
|
|
168
|
-
// z.toJSONSchema may add $schema — strip it for inline embedding
|
|
169
|
-
const { $schema: _, ...rest } = converted as Record<string, unknown>;
|
|
170
|
-
if (options.stripRequiredDefaults) dropDefaultedFromRequired(rest);
|
|
171
|
-
return rest as JSONSchemaObject;
|
|
131
|
+
/**
|
|
132
|
+
* Resolve a schema source to a value suitable for zod-openapi's
|
|
133
|
+
* `schema` field. If it's a Zod schema, pass it through directly (so
|
|
134
|
+
* createDocument can extract components and produce $ref pointers).
|
|
135
|
+
* For plain JSON Schema objects (backward compat), pass as-is —
|
|
136
|
+
* createDocument accepts SchemaObject too.
|
|
137
|
+
*/
|
|
138
|
+
function resolveSchemaForDocument(schemaSource: unknown): ContentSchema {
|
|
139
|
+
if (schemaSource == null || typeof schemaSource !== "object") {
|
|
140
|
+
return { type: "object" } satisfies oas31.SchemaObject;
|
|
172
141
|
}
|
|
173
|
-
|
|
174
|
-
return schema as JSONSchemaObject;
|
|
142
|
+
return schemaSource as ContentSchema;
|
|
175
143
|
}
|
|
176
144
|
|
|
177
145
|
// ---------------------------------------------------------------------------
|
|
@@ -302,46 +270,26 @@ interface OpenApiParameter {
|
|
|
302
270
|
description?: string;
|
|
303
271
|
}
|
|
304
272
|
|
|
305
|
-
interface OpenApiResponse {
|
|
306
|
-
description: string;
|
|
307
|
-
content?: Record<string, { schema: JSONSchemaObject }>;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
interface OpenApiOperation {
|
|
311
|
-
operationId: string;
|
|
312
|
-
summary?: string;
|
|
313
|
-
description?: string;
|
|
314
|
-
tags?: string[];
|
|
315
|
-
parameters?: OpenApiParameter[];
|
|
316
|
-
requestBody?: {
|
|
317
|
-
required: boolean;
|
|
318
|
-
content: Record<string, { schema: JSONSchemaObject }>;
|
|
319
|
-
};
|
|
320
|
-
responses: Record<string, OpenApiResponse>;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
273
|
/**
|
|
324
274
|
* Resolve a body declaration (request or success response) into its media type
|
|
325
275
|
* and the schema source to convert. A bare Zod/JSON schema is advertised as
|
|
326
276
|
* `application/json`; the explicit `{ contentType, schema }` form carries its
|
|
327
277
|
* own media type (e.g. `application/octet-stream` for binary bodies).
|
|
328
278
|
*/
|
|
279
|
+
function hasContentType(
|
|
280
|
+
body: unknown,
|
|
281
|
+
): body is { contentType: string; schema: unknown } {
|
|
282
|
+
return typeof body === "object" && body !== null && "contentType" in body;
|
|
283
|
+
}
|
|
284
|
+
|
|
329
285
|
function resolveBodyContent(body: unknown): {
|
|
330
286
|
contentType: string;
|
|
331
287
|
schemaSource: unknown;
|
|
332
288
|
} {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
? (body as { contentType: string }).contentType
|
|
338
|
-
: "application/json",
|
|
339
|
-
schemaSource: hasContentType ? (body as { schema: unknown }).schema : body,
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
interface OpenApiPathItem {
|
|
344
|
-
[method: string]: OpenApiOperation;
|
|
289
|
+
if (hasContentType(body)) {
|
|
290
|
+
return { contentType: body.contentType, schemaSource: body.schema };
|
|
291
|
+
}
|
|
292
|
+
return { contentType: "application/json", schemaSource: body };
|
|
345
293
|
}
|
|
346
294
|
|
|
347
295
|
/** Derive a tag name from a route module filename (e.g. "secret-routes.ts" → "secrets"). */
|
|
@@ -401,14 +349,22 @@ function buildSpec(
|
|
|
401
349
|
return a.method.localeCompare(b.method);
|
|
402
350
|
});
|
|
403
351
|
|
|
404
|
-
// Build paths object
|
|
405
|
-
const paths:
|
|
352
|
+
// Build paths object for zod-openapi's createDocument
|
|
353
|
+
const paths: ZodOpenApiPathsObject = {};
|
|
406
354
|
for (const route of uniqueRoutes) {
|
|
407
355
|
if (!paths[route.path]) {
|
|
408
356
|
paths[route.path] = {};
|
|
409
357
|
}
|
|
410
358
|
|
|
411
|
-
const methodLower = route.method.toLowerCase()
|
|
359
|
+
const methodLower = route.method.toLowerCase() as
|
|
360
|
+
| "get"
|
|
361
|
+
| "post"
|
|
362
|
+
| "put"
|
|
363
|
+
| "patch"
|
|
364
|
+
| "delete"
|
|
365
|
+
| "options"
|
|
366
|
+
| "head"
|
|
367
|
+
| "trace";
|
|
412
368
|
const operationId = route.path.startsWith("/v1/")
|
|
413
369
|
? toOperationId(route.endpoint, route.method)
|
|
414
370
|
: route.path.replace(/^\//, "").replace(/[/{}\-]/g, "_") +
|
|
@@ -448,8 +404,8 @@ function buildSpec(
|
|
|
448
404
|
// Build the operation. Default success status is 200; async endpoints
|
|
449
405
|
// that enqueue a job and return immediately set responseStatus: "202"
|
|
450
406
|
// so the generated spec matches the handler's actual response code.
|
|
451
|
-
const successStatus = entry.responseStatus ?? "200";
|
|
452
|
-
let successResponse:
|
|
407
|
+
const successStatus = toHttpStatus(entry.responseStatus ?? "200");
|
|
408
|
+
let successResponse: ZodOpenApiResponseObject = {
|
|
453
409
|
description: "Successful response",
|
|
454
410
|
};
|
|
455
411
|
if (entry.responseBody) {
|
|
@@ -459,11 +415,13 @@ function buildSpec(
|
|
|
459
415
|
successResponse = {
|
|
460
416
|
description: "Successful response",
|
|
461
417
|
content: {
|
|
462
|
-
[contentType]: {
|
|
418
|
+
[contentType]: {
|
|
419
|
+
schema: resolveSchemaForDocument(schemaSource),
|
|
420
|
+
},
|
|
463
421
|
},
|
|
464
422
|
};
|
|
465
423
|
}
|
|
466
|
-
const operation:
|
|
424
|
+
const operation: ZodOpenApiOperationObject = {
|
|
467
425
|
operationId,
|
|
468
426
|
...(entry.summary ? { summary: entry.summary } : {}),
|
|
469
427
|
...(entry.description ? { description: entry.description } : {}),
|
|
@@ -477,10 +435,6 @@ function buildSpec(
|
|
|
477
435
|
operation.parameters = parameters;
|
|
478
436
|
}
|
|
479
437
|
|
|
480
|
-
// A bare Zod/JSON schema is advertised as `application/json`; the
|
|
481
|
-
// explicit `{ contentType, schema }` form lets a route declare a non-JSON
|
|
482
|
-
// body (e.g. a raw `application/octet-stream` upload) so the generated SDK
|
|
483
|
-
// describes a real body type instead of `never`.
|
|
484
438
|
if (entry.requestBody) {
|
|
485
439
|
const { contentType, schemaSource } = resolveBodyContent(
|
|
486
440
|
entry.requestBody,
|
|
@@ -489,9 +443,7 @@ function buildSpec(
|
|
|
489
443
|
required: true,
|
|
490
444
|
content: {
|
|
491
445
|
[contentType]: {
|
|
492
|
-
schema:
|
|
493
|
-
stripRequiredDefaults: true,
|
|
494
|
-
}),
|
|
446
|
+
schema: resolveSchemaForDocument(schemaSource),
|
|
495
447
|
},
|
|
496
448
|
},
|
|
497
449
|
};
|
|
@@ -500,13 +452,13 @@ function buildSpec(
|
|
|
500
452
|
// Extra documented response variants (e.g. 502 fetch_failed).
|
|
501
453
|
if (entry.additionalResponses) {
|
|
502
454
|
for (const [status, resp] of Object.entries(entry.additionalResponses)) {
|
|
503
|
-
operation.responses[status] = {
|
|
455
|
+
operation.responses[toHttpStatus(status)] = {
|
|
504
456
|
description: resp.description,
|
|
505
457
|
...(resp.schema
|
|
506
458
|
? {
|
|
507
459
|
content: {
|
|
508
460
|
"application/json": {
|
|
509
|
-
schema:
|
|
461
|
+
schema: resolveSchemaForDocument(resp.schema),
|
|
510
462
|
},
|
|
511
463
|
},
|
|
512
464
|
}
|
|
@@ -518,7 +470,7 @@ function buildSpec(
|
|
|
518
470
|
paths[route.path][methodLower] = operation;
|
|
519
471
|
}
|
|
520
472
|
|
|
521
|
-
return {
|
|
473
|
+
return createDocument({
|
|
522
474
|
openapi: "3.1.0",
|
|
523
475
|
info: {
|
|
524
476
|
title: "Vellum Assistant API",
|
|
@@ -533,7 +485,7 @@ function buildSpec(
|
|
|
533
485
|
},
|
|
534
486
|
],
|
|
535
487
|
paths,
|
|
536
|
-
};
|
|
488
|
+
});
|
|
537
489
|
}
|
|
538
490
|
|
|
539
491
|
// ---------------------------------------------------------------------------
|
|
@@ -563,10 +515,8 @@ async function main() {
|
|
|
563
515
|
stringify(spec, { lineWidth: 120 });
|
|
564
516
|
|
|
565
517
|
// Format with prettier so the output matches what the pre-commit hook produces.
|
|
566
|
-
// Use a Node.js Readable stream for stdin — Bun.spawn with Blob stdin produces
|
|
567
|
-
// empty output on some platforms (Bun 1.3.x Linux sandbox).
|
|
568
518
|
const prettierProc = Bun.spawn(["bunx", "prettier", "--parser", "yaml"], {
|
|
569
|
-
stdin:
|
|
519
|
+
stdin: new Blob([rawYaml]),
|
|
570
520
|
stdout: "pipe",
|
|
571
521
|
stderr: "pipe",
|
|
572
522
|
});
|
|
@@ -661,10 +611,12 @@ async function main() {
|
|
|
661
611
|
await writeFile(OUTPUT_PATH, yamlOutput);
|
|
662
612
|
|
|
663
613
|
// Count stats
|
|
664
|
-
const
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
|
|
614
|
+
const paths = spec.paths ?? {};
|
|
615
|
+
const pathCount = Object.keys(paths).length;
|
|
616
|
+
const operationCount = Object.values(paths).reduce(
|
|
617
|
+
(n, methods) => n + Object.keys(methods ?? {}).length,
|
|
618
|
+
0,
|
|
619
|
+
);
|
|
668
620
|
|
|
669
621
|
console.log(`Generated ${OUTPUT_PATH}`);
|
|
670
622
|
console.log(` ${pathCount} paths, ${operationCount} operations`);
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
buildAccessRequestSeedContentBlocks,
|
|
5
|
+
parseAccessRequestPayload,
|
|
6
|
+
} from "../notifications/access-request-copy.js";
|
|
7
|
+
|
|
8
|
+
describe("buildAccessRequestSeedContentBlocks", () => {
|
|
9
|
+
const basePayload: Record<string, unknown> = {
|
|
10
|
+
requestId: "req-123",
|
|
11
|
+
requestCode: "ABC123",
|
|
12
|
+
sourceChannel: "slack",
|
|
13
|
+
conversationExternalId: "C01ABC",
|
|
14
|
+
actorExternalId: "U999",
|
|
15
|
+
actorDisplayName: "Alice",
|
|
16
|
+
actorUsername: "alice",
|
|
17
|
+
senderIdentifier: "U999",
|
|
18
|
+
messagePreview: "Hello, I need help with something",
|
|
19
|
+
messageTs: "1700000000.000100",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
test("produces a ui_surface block and a text fallback block", () => {
|
|
23
|
+
const blocks = buildAccessRequestSeedContentBlocks(basePayload);
|
|
24
|
+
expect(blocks).toHaveLength(2);
|
|
25
|
+
expect((blocks[0] as Record<string, unknown>).type).toBe("ui_surface");
|
|
26
|
+
expect((blocks[1] as Record<string, unknown>).type).toBe("text");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("card surface has correct surfaceType and surfaceId", () => {
|
|
30
|
+
const blocks = buildAccessRequestSeedContentBlocks(basePayload);
|
|
31
|
+
const surface = blocks[0] as Record<string, unknown>;
|
|
32
|
+
expect(surface.surfaceType).toBe("card");
|
|
33
|
+
expect(surface.surfaceId).toBe("access-request-req-123");
|
|
34
|
+
expect(surface.title).toBe("Access Request");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("card data uses actorDisplayName as title", () => {
|
|
38
|
+
const blocks = buildAccessRequestSeedContentBlocks(basePayload);
|
|
39
|
+
const surface = blocks[0] as Record<string, unknown>;
|
|
40
|
+
const data = surface.data as Record<string, unknown>;
|
|
41
|
+
expect(data.title).toBe("Alice");
|
|
42
|
+
expect(data.subtitle).toBe("Requesting access to the assistant");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("card data falls back to senderIdentifier when no displayName", () => {
|
|
46
|
+
const payload = { ...basePayload, actorDisplayName: undefined };
|
|
47
|
+
const blocks = buildAccessRequestSeedContentBlocks(payload);
|
|
48
|
+
const data = (blocks[0] as Record<string, unknown>).data as Record<
|
|
49
|
+
string,
|
|
50
|
+
unknown
|
|
51
|
+
>;
|
|
52
|
+
expect(data.title).toBe("U999");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("card data falls back to 'Someone' when no identity", () => {
|
|
56
|
+
const payload = {
|
|
57
|
+
...basePayload,
|
|
58
|
+
actorDisplayName: undefined,
|
|
59
|
+
senderIdentifier: undefined,
|
|
60
|
+
};
|
|
61
|
+
const blocks = buildAccessRequestSeedContentBlocks(payload);
|
|
62
|
+
const data = (blocks[0] as Record<string, unknown>).data as Record<
|
|
63
|
+
string,
|
|
64
|
+
unknown
|
|
65
|
+
>;
|
|
66
|
+
expect(data.title).toBe("Someone");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("includes username and source in metadata", () => {
|
|
70
|
+
const blocks = buildAccessRequestSeedContentBlocks(basePayload);
|
|
71
|
+
const data = (blocks[0] as Record<string, unknown>).data as Record<
|
|
72
|
+
string,
|
|
73
|
+
unknown
|
|
74
|
+
>;
|
|
75
|
+
const metadata = data.metadata as Array<{ label: string; value: string }>;
|
|
76
|
+
expect(metadata).toContainEqual({
|
|
77
|
+
label: "Username",
|
|
78
|
+
value: "@alice",
|
|
79
|
+
});
|
|
80
|
+
expect(metadata).toContainEqual({
|
|
81
|
+
label: "Source",
|
|
82
|
+
value: "Slack — #C01ABC",
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("DM channel renders as Direct message", () => {
|
|
87
|
+
const payload = { ...basePayload, conversationExternalId: "D01XYZ" };
|
|
88
|
+
const blocks = buildAccessRequestSeedContentBlocks(payload);
|
|
89
|
+
const data = (blocks[0] as Record<string, unknown>).data as Record<
|
|
90
|
+
string,
|
|
91
|
+
unknown
|
|
92
|
+
>;
|
|
93
|
+
const metadata = data.metadata as Array<{ label: string; value: string }>;
|
|
94
|
+
expect(metadata).toContainEqual({
|
|
95
|
+
label: "Source",
|
|
96
|
+
value: "Slack — Direct message",
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("body includes message preview when present", () => {
|
|
101
|
+
const blocks = buildAccessRequestSeedContentBlocks(basePayload);
|
|
102
|
+
const data = (blocks[0] as Record<string, unknown>).data as Record<
|
|
103
|
+
string,
|
|
104
|
+
unknown
|
|
105
|
+
>;
|
|
106
|
+
expect(data.body).toContain("Hello, I need help with something");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("body includes trust signal warnings", () => {
|
|
110
|
+
const payload = {
|
|
111
|
+
...basePayload,
|
|
112
|
+
isStranger: true,
|
|
113
|
+
isRestricted: true,
|
|
114
|
+
previousMemberStatus: "revoked",
|
|
115
|
+
};
|
|
116
|
+
const blocks = buildAccessRequestSeedContentBlocks(payload);
|
|
117
|
+
const data = (blocks[0] as Record<string, unknown>).data as Record<
|
|
118
|
+
string,
|
|
119
|
+
unknown
|
|
120
|
+
>;
|
|
121
|
+
const body = data.body as string;
|
|
122
|
+
expect(body).toContain("External Slack user");
|
|
123
|
+
expect(body).toContain("Guest / restricted account");
|
|
124
|
+
expect(body).toContain("previously revoked");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("body includes Slack message permalink", () => {
|
|
128
|
+
const blocks = buildAccessRequestSeedContentBlocks(basePayload);
|
|
129
|
+
const data = (blocks[0] as Record<string, unknown>).data as Record<
|
|
130
|
+
string,
|
|
131
|
+
unknown
|
|
132
|
+
>;
|
|
133
|
+
const body = data.body as string;
|
|
134
|
+
expect(body).toContain("View message");
|
|
135
|
+
expect(body).toContain(
|
|
136
|
+
"https://slack.com/archives/C01ABC/p1700000000000100",
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("text fallback block contains contract text", () => {
|
|
141
|
+
const blocks = buildAccessRequestSeedContentBlocks(basePayload);
|
|
142
|
+
const textBlock = blocks[1] as Record<string, unknown>;
|
|
143
|
+
expect(textBlock.type).toBe("text");
|
|
144
|
+
const text = textBlock.text as string;
|
|
145
|
+
expect(text).toContain("requesting access to the assistant");
|
|
146
|
+
expect(text).toContain("ABC123");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("body shows fallback when no preview/warnings/permalink", () => {
|
|
150
|
+
const payload = {
|
|
151
|
+
requestId: "req-456",
|
|
152
|
+
requestCode: "XYZ",
|
|
153
|
+
senderIdentifier: "someone",
|
|
154
|
+
};
|
|
155
|
+
const blocks = buildAccessRequestSeedContentBlocks(payload);
|
|
156
|
+
const data = (blocks[0] as Record<string, unknown>).data as Record<
|
|
157
|
+
string,
|
|
158
|
+
unknown
|
|
159
|
+
>;
|
|
160
|
+
expect(data.body).toBe("No additional context available.");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("surface block includes approve/reject actions when requestId present", () => {
|
|
164
|
+
const blocks = buildAccessRequestSeedContentBlocks(basePayload);
|
|
165
|
+
const surface = blocks[0] as Record<string, unknown>;
|
|
166
|
+
const actions = surface.actions as Array<{
|
|
167
|
+
id: string;
|
|
168
|
+
label: string;
|
|
169
|
+
style: string;
|
|
170
|
+
}>;
|
|
171
|
+
expect(actions).toHaveLength(2);
|
|
172
|
+
expect(actions[0]).toEqual({
|
|
173
|
+
id: "apr:req-123:approve_once",
|
|
174
|
+
label: "Approve",
|
|
175
|
+
style: "primary",
|
|
176
|
+
});
|
|
177
|
+
expect(actions[1]).toEqual({
|
|
178
|
+
id: "apr:req-123:reject",
|
|
179
|
+
label: "Reject",
|
|
180
|
+
style: "destructive",
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("surface block omits actions when requestId is missing", () => {
|
|
185
|
+
const payload = {
|
|
186
|
+
...basePayload,
|
|
187
|
+
requestId: undefined,
|
|
188
|
+
};
|
|
189
|
+
const blocks = buildAccessRequestSeedContentBlocks(payload);
|
|
190
|
+
const surface = blocks[0] as Record<string, unknown>;
|
|
191
|
+
expect(surface.actions).toBeUndefined();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("parseAccessRequestPayload extracts typed fields", () => {
|
|
195
|
+
const p = parseAccessRequestPayload(basePayload);
|
|
196
|
+
expect(p.requestId).toBe("req-123");
|
|
197
|
+
expect(p.actorDisplayName).toBe("Alice");
|
|
198
|
+
expect(p.actorUsername).toBe("alice");
|
|
199
|
+
expect(p.sourceChannel).toBe("slack");
|
|
200
|
+
expect(p.isStranger).toBeUndefined();
|
|
201
|
+
expect(p.isRestricted).toBeUndefined();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("parseAccessRequestPayload handles boolean trust signals", () => {
|
|
205
|
+
const p = parseAccessRequestPayload({
|
|
206
|
+
...basePayload,
|
|
207
|
+
isStranger: true,
|
|
208
|
+
isRestricted: true,
|
|
209
|
+
});
|
|
210
|
+
expect(p.isStranger).toBe(true);
|
|
211
|
+
expect(p.isRestricted).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
@@ -11,6 +11,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
|
11
11
|
|
|
12
12
|
import { repairAdaptiveThinkingOnManagedProfiles } from "../workspace/adaptive-thinking-repair.js";
|
|
13
13
|
import { enableAdaptiveThinkingManagedProfilesMigration } from "../workspace/migrations/097-enable-adaptive-thinking-managed-profiles.js";
|
|
14
|
+
import { recheckAdaptiveThinkingModelImpliedAnthropicMigration } from "../workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.js";
|
|
14
15
|
|
|
15
16
|
const ADAPTIVE = { enabled: true, streamThinking: true };
|
|
16
17
|
|
|
@@ -48,15 +49,19 @@ function profile(name: string): Record<string, unknown> {
|
|
|
48
49
|
return profiles[name] as Record<string, unknown>;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
// The startup repair and migration
|
|
52
|
-
// (migration modules must stay self-contained). Run every
|
|
53
|
-
//
|
|
52
|
+
// The startup repair, migration 097, and migration 104 keep frozen copies of
|
|
53
|
+
// the same logic (migration modules must stay self-contained). Run every
|
|
54
|
+
// scenario against all of them so the copies can't drift.
|
|
54
55
|
const implementations: Array<[string, (dir: string) => void]> = [
|
|
55
56
|
["startup repair", repairAdaptiveThinkingOnManagedProfiles],
|
|
56
57
|
[
|
|
57
58
|
"migration 097",
|
|
58
59
|
(dir) => enableAdaptiveThinkingManagedProfilesMigration.run(dir),
|
|
59
60
|
],
|
|
61
|
+
[
|
|
62
|
+
"migration 104",
|
|
63
|
+
(dir) => recheckAdaptiveThinkingModelImpliedAnthropicMigration.run(dir),
|
|
64
|
+
],
|
|
60
65
|
];
|
|
61
66
|
|
|
62
67
|
describe.each(implementations)("%s", (_label, run) => {
|
|
@@ -131,6 +136,30 @@ describe.each(implementations)("%s", (_label, run) => {
|
|
|
131
136
|
expect(profile("balanced").thinking).toEqual(ADAPTIVE);
|
|
132
137
|
});
|
|
133
138
|
|
|
139
|
+
test("patches source-less profiles pinning a known Claude model under a non-Anthropic default", () => {
|
|
140
|
+
// A managed/source-less profile that omits `provider` but pins a known
|
|
141
|
+
// Claude model is Anthropic via the resolver's model-implied provider, even
|
|
142
|
+
// when llm.default.provider is non-Anthropic. It must still get adaptive
|
|
143
|
+
// thinking rather than being skipped.
|
|
144
|
+
writeConfig({
|
|
145
|
+
llm: {
|
|
146
|
+
default: { provider: "gemini", model: "gemini-2.5-pro" },
|
|
147
|
+
profiles: {
|
|
148
|
+
balanced: { model: "claude-sonnet-4-6" },
|
|
149
|
+
"quality-optimized": {
|
|
150
|
+
source: "managed",
|
|
151
|
+
model: "claude-opus-4-8",
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
run(workspaceDir);
|
|
158
|
+
|
|
159
|
+
expect(profile("balanced").thinking).toEqual(ADAPTIVE);
|
|
160
|
+
expect(profile("quality-optimized").thinking).toEqual(ADAPTIVE);
|
|
161
|
+
});
|
|
162
|
+
|
|
134
163
|
test("skips profiles with an explicit non-Anthropic provider", () => {
|
|
135
164
|
writeConfig({
|
|
136
165
|
llm: {
|