@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
|
@@ -663,19 +663,22 @@ export class HostTransferProxy {
|
|
|
663
663
|
const transferId = interaction.metadata?.transferId as string | undefined;
|
|
664
664
|
if (transferId) this.transfers.delete(transferId);
|
|
665
665
|
pendingInteractions.resolve(requestId, "cancelled");
|
|
666
|
+
const { conversationId } = interaction;
|
|
666
667
|
try {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
668
|
+
if (conversationId !== undefined) {
|
|
669
|
+
broadcastMessage(
|
|
670
|
+
{
|
|
671
|
+
type: "host_transfer_cancel",
|
|
672
|
+
requestId,
|
|
673
|
+
conversationId,
|
|
674
|
+
...(interaction.targetClientId != null
|
|
675
|
+
? { targetClientId: interaction.targetClientId }
|
|
676
|
+
: {}),
|
|
677
|
+
},
|
|
678
|
+
conversationId,
|
|
679
|
+
{ targetClientId: interaction.targetClientId },
|
|
680
|
+
);
|
|
681
|
+
}
|
|
679
682
|
} catch {
|
|
680
683
|
// Best-effort cancel notification
|
|
681
684
|
}
|
|
@@ -719,19 +722,22 @@ export class HostTransferProxy {
|
|
|
719
722
|
const transferId = entry.metadata?.transferId as string | undefined;
|
|
720
723
|
if (transferId) this.transfers.delete(transferId);
|
|
721
724
|
pendingInteractions.resolve(entry.requestId, "cancelled");
|
|
725
|
+
const { conversationId } = entry;
|
|
722
726
|
try {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
727
|
+
if (conversationId !== undefined) {
|
|
728
|
+
broadcastMessage(
|
|
729
|
+
{
|
|
730
|
+
type: "host_transfer_cancel",
|
|
731
|
+
requestId: entry.requestId,
|
|
732
|
+
conversationId,
|
|
733
|
+
...(entry.targetClientId != null
|
|
734
|
+
? { targetClientId: entry.targetClientId }
|
|
735
|
+
: {}),
|
|
736
|
+
},
|
|
737
|
+
conversationId,
|
|
738
|
+
{ targetClientId: entry.targetClientId },
|
|
739
|
+
);
|
|
740
|
+
}
|
|
735
741
|
} catch {
|
|
736
742
|
// Best-effort cancel notification
|
|
737
743
|
}
|
package/src/daemon/lifecycle.ts
CHANGED
|
@@ -84,6 +84,7 @@ import {
|
|
|
84
84
|
setUsageTelemetryReporter,
|
|
85
85
|
UsageTelemetryReporter,
|
|
86
86
|
} from "../telemetry/usage-telemetry-reporter.js";
|
|
87
|
+
import { syncFlagGatedTools } from "../tools/registry.js";
|
|
87
88
|
import { registerBuiltinTtsProviders } from "../tts/providers/register-builtins.js";
|
|
88
89
|
import { getDeviceId } from "../util/device-id.js";
|
|
89
90
|
import { getLogger, initLogger } from "../util/logger.js";
|
|
@@ -97,6 +98,7 @@ import {
|
|
|
97
98
|
listWorkItems,
|
|
98
99
|
updateWorkItem,
|
|
99
100
|
} from "../work-items/work-item-store.js";
|
|
101
|
+
import { getWorkflowRunManager } from "../workflows/run-manager.js";
|
|
100
102
|
import { repairAdaptiveThinkingOnManagedProfiles } from "../workspace/adaptive-thinking-repair.js";
|
|
101
103
|
import { WorkspaceHeartbeatService } from "../workspace/heartbeat-service.js";
|
|
102
104
|
import { WORKSPACE_MIGRATIONS } from "../workspace/migrations/registry.js";
|
|
@@ -358,9 +360,14 @@ export async function runDaemon(): Promise<void> {
|
|
|
358
360
|
// so a slow or unreachable gateway doesn't delay daemon startup (the
|
|
359
361
|
// IPC call has a 3s connect + 5s call timeout that would otherwise
|
|
360
362
|
// stall the critical path).
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
363
|
+
// After the async fetch resolves, (re)register any flag-gated tools
|
|
364
|
+
// (`workflows`, `ces-tools`): `initializeTools()` runs during startup before
|
|
365
|
+
// this fetch completes, so without this follow-up sync a flag-enabled
|
|
366
|
+
// assistant would not expose the gated tools until a restart (which can lose
|
|
367
|
+
// the same race). Enable-direction only; chained so it sees the fresh cache.
|
|
368
|
+
void initFeatureFlagOverrides()
|
|
369
|
+
.then(() => syncFlagGatedTools())
|
|
370
|
+
.catch((err) => log.warn({ err }, "Background feature flag init failed"));
|
|
364
371
|
|
|
365
372
|
startGatewayFlagListener();
|
|
366
373
|
|
|
@@ -951,6 +958,26 @@ export async function runDaemon(): Promise<void> {
|
|
|
951
958
|
log.error({ err }, "Schedule recovery failed — continuing startup");
|
|
952
959
|
}
|
|
953
960
|
|
|
961
|
+
// Reconcile workflow runs orphaned by a crash: any row still `running` was
|
|
962
|
+
// in flight when the process died (the engine always finishes its row on
|
|
963
|
+
// exit), so flip it to `interrupted` to make it eligible for an explicit
|
|
964
|
+
// resume. Status only — accounting counters are preserved. Never blocks
|
|
965
|
+
// startup on failure.
|
|
966
|
+
try {
|
|
967
|
+
const reconciled = getWorkflowRunManager().reconcileOrphanedRuns();
|
|
968
|
+
if (reconciled > 0) {
|
|
969
|
+
log.info(
|
|
970
|
+
{ reconciled },
|
|
971
|
+
"Reconciled orphaned workflow runs to interrupted",
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
} catch (err) {
|
|
975
|
+
log.error(
|
|
976
|
+
{ err },
|
|
977
|
+
"Workflow run reconciliation failed — continuing startup",
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
|
|
954
981
|
const scheduler = startScheduler(
|
|
955
982
|
async (conversationId, message, options) => {
|
|
956
983
|
await processMessage(
|
|
@@ -967,6 +994,9 @@ export async function runDaemon(): Promise<void> {
|
|
|
967
994
|
}
|
|
968
995
|
: {}),
|
|
969
996
|
...(options.taskRunId ? { taskRunId: options.taskRunId } : {}),
|
|
997
|
+
...(options.overrideProfile
|
|
998
|
+
? { overrideProfile: options.overrideProfile }
|
|
999
|
+
: {}),
|
|
970
1000
|
}
|
|
971
1001
|
: undefined,
|
|
972
1002
|
);
|
|
@@ -1251,6 +1281,13 @@ export async function runDaemon(): Promise<void> {
|
|
|
1251
1281
|
log.warn({ err }, "Assistant symlink installation failed — continuing");
|
|
1252
1282
|
}
|
|
1253
1283
|
|
|
1284
|
+
// Seed preloaded apps (personal landing page) in background (non-blocking).
|
|
1285
|
+
void import("../memory/preloaded-apps.js")
|
|
1286
|
+
.then(({ seedPreloadedApps }) => seedPreloadedApps(config))
|
|
1287
|
+
.catch((err) =>
|
|
1288
|
+
log.warn({ err }, "Preloaded app seeding failed — continuing"),
|
|
1289
|
+
);
|
|
1290
|
+
|
|
1254
1291
|
// Download embedding runtime in background (non-blocking).
|
|
1255
1292
|
// If download fails, local embeddings gracefully fall back to cloud backends.
|
|
1256
1293
|
void (async () => {
|
|
@@ -46,6 +46,7 @@ export * from "./message-types/sync.js";
|
|
|
46
46
|
export * from "./message-types/upgrades.js";
|
|
47
47
|
export * from "./message-types/web-activity.js";
|
|
48
48
|
export * from "./message-types/work-items.js";
|
|
49
|
+
export * from "./message-types/workflows.js";
|
|
49
50
|
export * from "./message-types/workspace.js";
|
|
50
51
|
|
|
51
52
|
// Import domain-level union aliases for composition
|
|
@@ -135,6 +136,7 @@ import type {
|
|
|
135
136
|
_WorkItemsClientMessages,
|
|
136
137
|
_WorkItemsServerMessages,
|
|
137
138
|
} from "./message-types/work-items.js";
|
|
139
|
+
import type { _WorkflowsServerMessages } from "./message-types/workflows.js";
|
|
138
140
|
import type {
|
|
139
141
|
_WorkspaceClientMessages,
|
|
140
142
|
_WorkspaceServerMessages,
|
|
@@ -208,6 +210,7 @@ export type ServerMessage =
|
|
|
208
210
|
| _UpgradesServerMessages
|
|
209
211
|
| _AcpServerMessages
|
|
210
212
|
| _BookmarksServerMessages
|
|
213
|
+
| _WorkflowsServerMessages
|
|
211
214
|
| DiskPressureStatusChangedEvent
|
|
212
215
|
| SubagentEvent;
|
|
213
216
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import type { AssistantActivityStateEvent } from "../../api/events/assistant-activity-state.js";
|
|
4
4
|
import type { AssistantTextDeltaEvent } from "../../api/events/assistant-text-delta.js";
|
|
5
|
+
import type { AssistantThinkingDeltaEvent } from "../../api/events/assistant-thinking-delta.js";
|
|
5
6
|
import type { AssistantTurnStartEvent } from "../../api/events/assistant-turn-start.js";
|
|
6
7
|
import type { ConfirmationRequestEvent } from "../../api/events/confirmation-request.js";
|
|
7
8
|
import type { ErrorEvent } from "../../api/events/error.js";
|
|
@@ -76,15 +77,6 @@ export interface SuggestionRequest {
|
|
|
76
77
|
|
|
77
78
|
// === Server → Client ===
|
|
78
79
|
|
|
79
|
-
export interface AssistantThinkingDelta {
|
|
80
|
-
type: "assistant_thinking_delta";
|
|
81
|
-
thinking: string;
|
|
82
|
-
conversationId?: string;
|
|
83
|
-
/** Database ID of the assistant message this thinking delta belongs to.
|
|
84
|
-
* Same semantics as `AssistantTextDeltaEvent.messageId`. */
|
|
85
|
-
messageId?: string;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
80
|
export interface ToolInputDelta {
|
|
89
81
|
type: "tool_input_delta";
|
|
90
82
|
toolName: string;
|
|
@@ -160,7 +152,7 @@ export type _MessagesServerMessages =
|
|
|
160
152
|
| UserMessageEchoEvent
|
|
161
153
|
| AssistantTurnStartEvent
|
|
162
154
|
| AssistantTextDeltaEvent
|
|
163
|
-
|
|
|
155
|
+
| AssistantThinkingDeltaEvent
|
|
164
156
|
| ToolUseStartEvent
|
|
165
157
|
| ToolUsePreviewStartEvent
|
|
166
158
|
| ToolOutputChunkEvent
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Workflow orchestration run lifecycle events.
|
|
2
|
+
//
|
|
3
|
+
// Emitted by the `WorkflowRunManager` (run-manager.ts) as a workflow run
|
|
4
|
+
// progresses and completes. These are server → client push events only — the
|
|
5
|
+
// run is launched via the workflow tool / scheduler / routes (later PRs), not
|
|
6
|
+
// via a client message in this union.
|
|
7
|
+
|
|
8
|
+
import type { WorkflowRunStatus } from "../../workflows/journal-store.js";
|
|
9
|
+
|
|
10
|
+
// === Server → Client ===
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Progress push for an in-flight workflow run. Maps the engine's
|
|
14
|
+
* `onProgress` (`phase`/`log`) callback plus the current usage snapshot into a
|
|
15
|
+
* single wire event. `phase` carries the latest `phase(title)`; `message`
|
|
16
|
+
* carries the latest `log(msg)`; only one is set per emission.
|
|
17
|
+
*/
|
|
18
|
+
export interface WorkflowProgress {
|
|
19
|
+
type: "workflow_progress";
|
|
20
|
+
runId: string;
|
|
21
|
+
/** Latest phase title, when this emission came from a `phase(...)` call. */
|
|
22
|
+
phase?: string;
|
|
23
|
+
/** Run label (the workflow's `meta.name`), for client display. */
|
|
24
|
+
label?: string;
|
|
25
|
+
/** Live agent count at emission time. */
|
|
26
|
+
agentsSpawned: number;
|
|
27
|
+
/** Latest log line, when this emission came from a `log(...)` call. */
|
|
28
|
+
message?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Terminal push for a workflow run. Carries the final status, counts, token
|
|
33
|
+
* usage, and a human-readable result/error summary the originating
|
|
34
|
+
* conversation also receives via an agent wake.
|
|
35
|
+
*/
|
|
36
|
+
export interface WorkflowCompleted {
|
|
37
|
+
type: "workflow_completed";
|
|
38
|
+
runId: string;
|
|
39
|
+
status: WorkflowRunStatus;
|
|
40
|
+
agentsSpawned: number;
|
|
41
|
+
inputTokens: number;
|
|
42
|
+
outputTokens: number;
|
|
43
|
+
/** Human-readable result-or-error summary. */
|
|
44
|
+
summary?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// --- Domain-level union aliases (consumed by the barrel file) ---
|
|
48
|
+
|
|
49
|
+
export type _WorkflowsServerMessages = WorkflowProgress | WorkflowCompleted;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
3
|
import { ContextOverflowError } from "../providers/types.js";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
looksLikeContextOverflowError,
|
|
6
|
+
parseActualTokensFromError,
|
|
7
|
+
} from "./parse-actual-tokens-from-error.js";
|
|
5
8
|
|
|
6
9
|
describe("parseActualTokensFromError", () => {
|
|
7
10
|
test("returns null for null input", () => {
|
|
@@ -125,3 +128,61 @@ describe("parseActualTokensFromError", () => {
|
|
|
125
128
|
expect(parseActualTokensFromError(err)).toBe(242201);
|
|
126
129
|
});
|
|
127
130
|
});
|
|
131
|
+
|
|
132
|
+
describe("looksLikeContextOverflowError", () => {
|
|
133
|
+
test("matches the typed ContextOverflowError even without a parseable message", () => {
|
|
134
|
+
const err = new ContextOverflowError("context window exceeded", "openai");
|
|
135
|
+
expect(looksLikeContextOverflowError(err)).toBe(true);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("matches a REWRAPPED plain Error carrying an Anthropic-style message", () => {
|
|
139
|
+
// Managed-proxy/adapter paths rewrap overflow rejections into untyped
|
|
140
|
+
// errors — the heuristic must still recognize them.
|
|
141
|
+
const err = new Error(
|
|
142
|
+
"Provider API error (400): prompt is too long: 250000 tokens > 200000 maximum",
|
|
143
|
+
);
|
|
144
|
+
expect(looksLikeContextOverflowError(err)).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("matches a rewrapped OpenAI-style message", () => {
|
|
148
|
+
expect(
|
|
149
|
+
looksLikeContextOverflowError(
|
|
150
|
+
new Error("too many input tokens: 150000 > 128000"),
|
|
151
|
+
),
|
|
152
|
+
).toBe(true);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("matches context_length_exceeded / maximum-context-length phrasings", () => {
|
|
156
|
+
expect(
|
|
157
|
+
looksLikeContextOverflowError(new Error("context_length_exceeded")),
|
|
158
|
+
).toBe(true);
|
|
159
|
+
expect(
|
|
160
|
+
looksLikeContextOverflowError(
|
|
161
|
+
new Error("This model's maximum context length is 128000 tokens"),
|
|
162
|
+
),
|
|
163
|
+
).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("accepts a raw string message", () => {
|
|
167
|
+
expect(
|
|
168
|
+
looksLikeContextOverflowError(
|
|
169
|
+
"prompt is too long: 242201 tokens > 200000 maximum",
|
|
170
|
+
),
|
|
171
|
+
).toBe(true);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("rejects unrelated errors, strings, and nullish input", () => {
|
|
175
|
+
expect(looksLikeContextOverflowError(new Error("socket hang up"))).toBe(
|
|
176
|
+
false,
|
|
177
|
+
);
|
|
178
|
+
expect(looksLikeContextOverflowError("something went wrong")).toBe(false);
|
|
179
|
+
expect(looksLikeContextOverflowError(null)).toBe(false);
|
|
180
|
+
expect(looksLikeContextOverflowError(undefined)).toBe(false);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("does not misread arbitrary numeric comparisons as overflow", () => {
|
|
184
|
+
expect(
|
|
185
|
+
looksLikeContextOverflowError(new Error("retry budget: 5 > 3 attempts")),
|
|
186
|
+
).toBe(false);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
@@ -30,13 +30,52 @@ export function parseActualTokensFromError(
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// Untyped path — accept either an Error or a string.
|
|
33
|
+
return parseFromMessage(extractMessage(errorOrMessage));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Message patterns that identify a provider context-overflow rejection.
|
|
38
|
+
* Covers the typed wrapper's source patterns plus common provider phrasings
|
|
39
|
+
* that adapter paths (e.g. managed-proxy rewrappers) surface as untyped
|
|
40
|
+
* errors:
|
|
41
|
+
* "prompt is too long: 242201 tokens > 200000 maximum" (Anthropic)
|
|
42
|
+
* "too many input tokens: 242201 > 200000" (OpenAI)
|
|
43
|
+
* "context_length_exceeded" / "maximum context length" (OpenAI-compat)
|
|
44
|
+
*/
|
|
45
|
+
const OVERFLOW_MESSAGE_PATTERNS: readonly RegExp[] = [
|
|
46
|
+
/prompt is too long/i,
|
|
47
|
+
/too many (?:input )?tokens/i,
|
|
48
|
+
/context[_\s-]?length[_\s-]?exceeded/i,
|
|
49
|
+
/maximum context length/i,
|
|
50
|
+
/\d[\d,]*\s*tokens?\s*[>≥]\s*\d/i,
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Heuristic context-overflow check that also catches REWRAPPED provider
|
|
55
|
+
* errors. `isContextOverflowError` only matches the typed
|
|
56
|
+
* `ContextOverflowError` wrapper; adapter layers (managed-proxy rewrappers,
|
|
57
|
+
* retry shims) can re-throw the same rejection as a plain `Error`, hiding the
|
|
58
|
+
* typed signal. Callers that must not misread an overflow as a clean
|
|
59
|
+
* no-output stop (e.g. the suppressed-compaction agent-wake path) should use
|
|
60
|
+
* this instead of the bare typed check.
|
|
61
|
+
*
|
|
62
|
+
* Accepts the same inputs as {@link parseActualTokensFromError}: a typed
|
|
63
|
+
* error, a plain `Error`/object with a `message`, or a raw string.
|
|
64
|
+
*/
|
|
65
|
+
export function looksLikeContextOverflowError(err: unknown): boolean {
|
|
66
|
+
if (isContextOverflowError(err)) return true;
|
|
67
|
+
const message = extractMessage(err);
|
|
68
|
+
if (message === null) return false;
|
|
69
|
+
return OVERFLOW_MESSAGE_PATTERNS.some((pattern) => pattern.test(message));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Pull a message string out of an untyped error-ish value, if possible. */
|
|
73
|
+
function extractMessage(errorOrMessage: unknown): string | null {
|
|
33
74
|
if (errorOrMessage == null) return null;
|
|
34
|
-
if (typeof errorOrMessage === "string")
|
|
35
|
-
return parseFromMessage(errorOrMessage);
|
|
36
|
-
}
|
|
75
|
+
if (typeof errorOrMessage === "string") return errorOrMessage;
|
|
37
76
|
if (typeof errorOrMessage === "object" && "message" in errorOrMessage) {
|
|
38
77
|
const msg = (errorOrMessage as { message?: unknown }).message;
|
|
39
|
-
if (typeof msg === "string") return
|
|
78
|
+
if (typeof msg === "string") return msg;
|
|
40
79
|
}
|
|
41
80
|
return null;
|
|
42
81
|
}
|
|
@@ -534,6 +534,9 @@ export async function processMessage(
|
|
|
534
534
|
isInteractive: options?.isInteractive ?? false,
|
|
535
535
|
isUserMessage: true,
|
|
536
536
|
...(options?.callSite ? { callSite: options.callSite } : {}),
|
|
537
|
+
...(options?.overrideProfile
|
|
538
|
+
? { overrideProfile: options.overrideProfile }
|
|
539
|
+
: {}),
|
|
537
540
|
});
|
|
538
541
|
} finally {
|
|
539
542
|
if (
|
|
@@ -591,6 +594,9 @@ export async function processMessageInBackground(
|
|
|
591
594
|
isInteractive: options?.isInteractive ?? false,
|
|
592
595
|
isUserMessage: true,
|
|
593
596
|
...(options?.callSite ? { callSite: options.callSite } : {}),
|
|
597
|
+
...(options?.overrideProfile
|
|
598
|
+
? { overrideProfile: options.overrideProfile }
|
|
599
|
+
: {}),
|
|
594
600
|
})
|
|
595
601
|
.finally(() => {
|
|
596
602
|
if (
|
|
@@ -8,6 +8,54 @@ import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
|
8
8
|
import type { SurfaceConversationContext } from "./conversation-surfaces.js";
|
|
9
9
|
import type { TrustContext } from "./trust-context.js";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* How a subagent/wake tool allowlist is enforced.
|
|
13
|
+
*
|
|
14
|
+
* - `"wire"` (default): filter the tool definitions sent to the provider so
|
|
15
|
+
* the model never sees non-allowlisted tools. Smaller request, but the
|
|
16
|
+
* tool array no longer byte-matches the conversation's normal turns, so
|
|
17
|
+
* the provider prompt-cache prefix (`tools → system → messages`) cannot
|
|
18
|
+
* be reused.
|
|
19
|
+
* - `"execution"`: keep the conversation's full tool surface on the wire
|
|
20
|
+
* (preserving cache parity with the source conversation's turns) and
|
|
21
|
+
* enforce the allowlist at execution time — a call to a non-allowlisted
|
|
22
|
+
* tool returns an error tool_result without ever invoking the tool's
|
|
23
|
+
* executor.
|
|
24
|
+
*/
|
|
25
|
+
export type SubagentToolGateMode = "wire" | "execution";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Client-context inputs frozen for tool-DEFINITION resolution during a wake
|
|
29
|
+
* that runs with `subagentToolGateMode: "execution"`.
|
|
30
|
+
*
|
|
31
|
+
* Execution gate mode exists to keep the wire tool array byte-identical to
|
|
32
|
+
* the source conversation's live turns (see {@link SubagentToolGateMode}),
|
|
33
|
+
* but the definitions themselves are resolved from the live context: a
|
|
34
|
+
* fork-retrospective wake hydrates clientless (`hasNoClient = true`, no
|
|
35
|
+
* transport interface, no channel capabilities), which drops client-gated
|
|
36
|
+
* tools (`host_*`, `ui_*`, `app_open`, `request_system_permission`) from
|
|
37
|
+
* the wire definitions and breaks the cache prefix anyway. When this pin is
|
|
38
|
+
* set on the conversation, `isToolActiveForContext` reads `hasNoClient` and
|
|
39
|
+
* `transportInterface` exclusively from the pin and treats channel
|
|
40
|
+
* capabilities as unset — an absent optional field pins the value to
|
|
41
|
+
* `undefined`; there is no fall-through to the live conversation state.
|
|
42
|
+
* (Interactive-interface turns never set channel capabilities, so unset IS
|
|
43
|
+
* parity for desktop/web sources; channel-routed sources resolve every tool
|
|
44
|
+
* gate identically under `hasNoClient: true` with or without them.)
|
|
45
|
+
*
|
|
46
|
+
* Tool-definition resolution ONLY. The executor callback and host-proxy
|
|
47
|
+
* attachment paths never read the pin, so it cannot make a host tool
|
|
48
|
+
* runnable: in execution gate mode every non-allowlisted call is rejected
|
|
49
|
+
* before its executor runs, so a pinned-in tool can appear on the wire but
|
|
50
|
+
* can never execute.
|
|
51
|
+
*/
|
|
52
|
+
export interface WakeToolContextPin {
|
|
53
|
+
/** The source conversation's live-turn `hasNoClient` value. */
|
|
54
|
+
hasNoClient: boolean;
|
|
55
|
+
/** The interface the source's live turns ran on (e.g. `"macos"`). */
|
|
56
|
+
transportInterface?: InterfaceId;
|
|
57
|
+
}
|
|
58
|
+
|
|
11
59
|
/**
|
|
12
60
|
* Subset of Conversation state that the tool executor callback reads at
|
|
13
61
|
* call time (not construction time). These are captured by the
|
|
@@ -21,6 +69,15 @@ export interface ToolSetupContext extends SurfaceConversationContext {
|
|
|
21
69
|
abortController: AbortController | null;
|
|
22
70
|
/** When set, only tools in this set may execute during the current turn. */
|
|
23
71
|
allowedToolNames?: Set<string>;
|
|
72
|
+
/** When set, the subagent/wake tool allowlist (see {@link subagentToolGateMode}). */
|
|
73
|
+
subagentAllowedTools?: Set<string>;
|
|
74
|
+
/**
|
|
75
|
+
* How {@link subagentAllowedTools} is enforced. Absent or `"wire"` keeps
|
|
76
|
+
* the historical behavior (definitions filtered before the provider
|
|
77
|
+
* request); `"execution"` keeps the full tool surface on the wire and
|
|
78
|
+
* rejects non-allowlisted calls in the executor callback instead.
|
|
79
|
+
*/
|
|
80
|
+
subagentToolGateMode?: SubagentToolGateMode;
|
|
24
81
|
/** Turn-scoped disk-pressure cleanup mode flag. */
|
|
25
82
|
diskPressureCleanupModeActive?: boolean;
|
|
26
83
|
/** True when the conversation has no connected client (HTTP-only path). */
|
|
@@ -25,6 +25,10 @@ import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
|
25
25
|
import { getLogger } from "../util/logger.js";
|
|
26
26
|
import type { Conversation } from "./conversation.js";
|
|
27
27
|
import type { ServerMessage } from "./message-protocol.js";
|
|
28
|
+
import type {
|
|
29
|
+
SubagentToolGateMode,
|
|
30
|
+
WakeToolContextPin,
|
|
31
|
+
} from "./tool-setup-types.js";
|
|
28
32
|
|
|
29
33
|
const log = getLogger("wake-conversation-ops");
|
|
30
34
|
|
|
@@ -256,14 +260,28 @@ export async function persistWakeTailMessage(
|
|
|
256
260
|
* reusing the conversation's subagent allowlist slot. Returns a restore
|
|
257
261
|
* callback that reinstates the previous allowlist so the wake can release
|
|
258
262
|
* the scope before any queued user turn is drained.
|
|
263
|
+
*
|
|
264
|
+
* `gateMode` controls how the allowlist is enforced — see
|
|
265
|
+
* {@link SubagentToolGateMode}. `toolContextPin`, when provided
|
|
266
|
+
* (execution-gate-mode cache-parity wakes), freezes the client-context
|
|
267
|
+
* inputs for tool-definition resolution — see {@link WakeToolContextPin}.
|
|
268
|
+
* Both are set and restored alongside the allowlist.
|
|
259
269
|
*/
|
|
260
270
|
export function scopeWakeAllowedTools(
|
|
261
271
|
conversation: Conversation,
|
|
262
272
|
tools: ReadonlySet<string>,
|
|
273
|
+
gateMode: SubagentToolGateMode = "wire",
|
|
274
|
+
toolContextPin?: WakeToolContextPin,
|
|
263
275
|
): () => void {
|
|
264
276
|
const previous = conversation.subagentAllowedTools;
|
|
277
|
+
const previousGateMode = conversation.subagentToolGateMode;
|
|
278
|
+
const previousToolContextPin = conversation.toolContextPin;
|
|
265
279
|
conversation.setSubagentAllowedTools(new Set(tools));
|
|
280
|
+
conversation.subagentToolGateMode = gateMode;
|
|
281
|
+
conversation.toolContextPin = toolContextPin;
|
|
266
282
|
return () => {
|
|
267
283
|
conversation.setSubagentAllowedTools(previous);
|
|
284
|
+
conversation.subagentToolGateMode = previousGateMode;
|
|
285
|
+
conversation.toolContextPin = previousToolContextPin;
|
|
268
286
|
};
|
|
269
287
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { desc, eq, sql } from "drizzle-orm";
|
|
1
|
+
import { desc, eq, lt, sql } from "drizzle-orm";
|
|
2
2
|
import { v4 as uuid } from "uuid";
|
|
3
3
|
|
|
4
4
|
import { getDb } from "../memory/db-connection.js";
|
|
@@ -272,12 +272,18 @@ export function countRecentConsecutiveRuns(maxToCheck: number): number {
|
|
|
272
272
|
|
|
273
273
|
/**
|
|
274
274
|
* List heartbeat runs ordered by `scheduledFor` descending.
|
|
275
|
+
* When `before` is set, only runs with `scheduledFor` strictly older than it
|
|
276
|
+
* are returned (cursor for paginating into history).
|
|
275
277
|
*/
|
|
276
|
-
export function listHeartbeatRuns(
|
|
278
|
+
export function listHeartbeatRuns(
|
|
279
|
+
limit = 20,
|
|
280
|
+
before?: number,
|
|
281
|
+
): HeartbeatRunRecord[] {
|
|
277
282
|
const db = getDb();
|
|
278
283
|
const rows = db
|
|
279
284
|
.select()
|
|
280
285
|
.from(heartbeatRuns)
|
|
286
|
+
.where(before != null ? lt(heartbeatRuns.scheduledFor, before) : undefined)
|
|
281
287
|
.orderBy(desc(heartbeatRuns.scheduledFor))
|
|
282
288
|
.limit(limit)
|
|
283
289
|
.all();
|
package/src/home/feed-types.ts
CHANGED
|
@@ -43,7 +43,7 @@ export {
|
|
|
43
43
|
} from "../api/responses/home.js";
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* On-disk file format for
|
|
46
|
+
* On-disk file format for `$VELLUM_WORKSPACE_DIR/data/home-feed.json`.
|
|
47
47
|
*
|
|
48
48
|
* Written by the feed writer, read by the HTTP route and `parseFeedFile`
|
|
49
49
|
* below. `version` is pinned to `2` (collapsed schema); pre-v2 files are
|
|
@@ -3,11 +3,35 @@ import { connect, type Socket } from "node:net";
|
|
|
3
3
|
import { refreshOverridesFromGateway } from "../config/assistant-feature-flags.js";
|
|
4
4
|
import { SYNC_TAGS } from "../daemon/message-types/sync.js";
|
|
5
5
|
import { publishSyncInvalidation } from "../runtime/sync/sync-publisher.js";
|
|
6
|
+
import { syncFlagGatedTools } from "../tools/registry.js";
|
|
6
7
|
import { getLogger } from "../util/logger.js";
|
|
7
8
|
import { resolveIpcSocketPath } from "./socket-path.js";
|
|
8
9
|
|
|
9
10
|
const log = getLogger("gateway-flag-listener");
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Refresh the flag-overrides cache from the gateway, then register any
|
|
14
|
+
* registry-gated tools whose flag gate has since opened. Both the
|
|
15
|
+
* `feature_flags_changed` event and a reconnect only refresh the cache;
|
|
16
|
+
* `syncFlagGatedTools` registers the CES tools whose flag is enabled so that
|
|
17
|
+
* enabling a CES-gating flag at runtime surfaces them without a daemon restart.
|
|
18
|
+
* Workflow tools (`run_workflow` / `manage_workflows`) are not registry-gated:
|
|
19
|
+
* they live in a flag-gated bundled skill surfaced via `skill_load` against the
|
|
20
|
+
* live flag cache, so they need no registry sync here. `syncFlagGatedTools` is
|
|
21
|
+
* idempotent and enable-only, so re-running it on every refresh is safe; it also
|
|
22
|
+
* never throws (it logs internally).
|
|
23
|
+
*/
|
|
24
|
+
function refreshFlagsAndSyncTools(context: string): void {
|
|
25
|
+
refreshOverridesFromGateway()
|
|
26
|
+
.then(() => syncFlagGatedTools())
|
|
27
|
+
.catch((err) => {
|
|
28
|
+
log.warn(
|
|
29
|
+
{ err },
|
|
30
|
+
`Failed to refresh feature flag overrides (${context})`,
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
11
35
|
const MAX_BACKOFF_MS = 30_000;
|
|
12
36
|
const INITIAL_BACKOFF_MS = 1_000;
|
|
13
37
|
|
|
@@ -29,9 +53,7 @@ function handleData(chunk: Buffer): void {
|
|
|
29
53
|
const msg = JSON.parse(trimmed) as { event?: string };
|
|
30
54
|
if (msg.event === "feature_flags_changed") {
|
|
31
55
|
log.info("Received feature_flags_changed event — refreshing overrides");
|
|
32
|
-
|
|
33
|
-
log.warn({ err }, "Failed to refresh feature flag overrides");
|
|
34
|
-
});
|
|
56
|
+
refreshFlagsAndSyncTools("flags-changed event");
|
|
35
57
|
// Fan out to every connected web client so React Query caches
|
|
36
58
|
// for `/v1/feature-flags/client-flag-values/` and
|
|
37
59
|
// `/v1/assistants/:id/feature-flags` invalidate immediately
|
|
@@ -72,9 +94,9 @@ function connectToGateway(): void {
|
|
|
72
94
|
log.info("Connected to gateway IPC for flag events");
|
|
73
95
|
currentBackoffMs = INITIAL_BACKOFF_MS;
|
|
74
96
|
socket = conn;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
97
|
+
// A reconnect may have missed a flag flip while disconnected, so sync the
|
|
98
|
+
// gated tools too — not just the cache.
|
|
99
|
+
refreshFlagsAndSyncTools("reconnect");
|
|
78
100
|
});
|
|
79
101
|
|
|
80
102
|
let buffer = "";
|
|
@@ -96,38 +96,26 @@ export function setMcpAuthError(
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
-
* Get the current state of an OAuth flow, or null if none exists.
|
|
99
|
+
* Get the current state of an OAuth flow, or null if none exists. Sweeps
|
|
100
|
+
* expired entries on every read so a long-polling CLI can never observe
|
|
101
|
+
* a stale flow past its TTL.
|
|
100
102
|
*/
|
|
101
103
|
export function getMcpAuthState(serverId: string): McpAuthState | null {
|
|
102
|
-
clearExpiredMcpAuthStates();
|
|
103
|
-
return activeMcpAuthFlows.get(serverId) ?? null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Remove expired entries from the auth flow map.
|
|
108
|
-
*/
|
|
109
|
-
export function clearExpiredMcpAuthStates(): void {
|
|
110
104
|
const now = Date.now();
|
|
111
|
-
for (const [
|
|
105
|
+
for (const [id, state] of activeMcpAuthFlows) {
|
|
112
106
|
if (state.status === "pending" && now > state.expiresAt) {
|
|
113
|
-
activeMcpAuthFlows.delete(
|
|
107
|
+
activeMcpAuthFlows.delete(id);
|
|
114
108
|
} else if (
|
|
115
109
|
state.status === "complete" &&
|
|
116
110
|
now > state.completedAt + COMPLETION_GRACE_MS
|
|
117
111
|
) {
|
|
118
|
-
activeMcpAuthFlows.delete(
|
|
112
|
+
activeMcpAuthFlows.delete(id);
|
|
119
113
|
} else if (
|
|
120
114
|
state.status === "error" &&
|
|
121
115
|
now > state.failedAt + COMPLETION_GRACE_MS
|
|
122
116
|
) {
|
|
123
|
-
activeMcpAuthFlows.delete(
|
|
117
|
+
activeMcpAuthFlows.delete(id);
|
|
124
118
|
}
|
|
125
119
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Test-only helper — clears all auth flow state for test isolation.
|
|
130
|
-
*/
|
|
131
|
-
export function _clearAllMcpAuthStates(): void {
|
|
132
|
-
activeMcpAuthFlows.clear();
|
|
120
|
+
return activeMcpAuthFlows.get(serverId) ?? null;
|
|
133
121
|
}
|