@vellumai/assistant 0.8.12 → 0.9.0-staging.1
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/openapi.yaml +6935 -5545
- 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-dir-path-guard.test.ts +27 -3
- 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-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 +125 -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__/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__/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/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/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 +75 -0
- 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 +1 -1
- 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/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-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-stages/acl-enforcement.ts +26 -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 +122 -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/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 +48 -2
- package/src/tools/workflows/manage-workflows.ts +183 -0
- package/src/tools/workflows/run-workflow.test.ts +442 -0
- package/src/tools/workflows/run-workflow.ts +88 -0
- package/src/types/onboarding-context.ts +2 -0
- package/src/usage/attribution.ts +24 -0
- package/src/util/canonicalize-identity.ts +12 -3
- package/src/util/platform.ts +17 -17
- package/src/watcher/__tests__/engine.test.ts +24 -0
- package/src/watcher/__tests__/telemetry.test.ts +135 -0
- package/src/watcher/engine.ts +7 -0
- package/src/watcher/telemetry.ts +74 -0
- package/src/workflows/capabilities.test.ts +365 -0
- package/src/workflows/capabilities.ts +359 -0
- package/src/workflows/deterministic-stringify.ts +27 -0
- package/src/workflows/engine-integration.test.ts +656 -0
- package/src/workflows/engine.test.ts +1144 -0
- package/src/workflows/engine.ts +1078 -0
- package/src/workflows/fanout-load.test.ts +168 -0
- package/src/workflows/journal-store.test.ts +369 -0
- package/src/workflows/journal-store.ts +470 -0
- package/src/workflows/leaf-runner.test.ts +704 -0
- package/src/workflows/leaf-runner.ts +589 -0
- package/src/workflows/library.test.ts +134 -0
- package/src/workflows/library.ts +124 -0
- package/src/workflows/run-manager.test.ts +711 -0
- package/src/workflows/run-manager.ts +593 -0
- package/src/workflows/sandbox-escape.test.ts +339 -0
- package/src/workflows/sandbox.test.ts +251 -0
- package/src/workflows/sandbox.ts +447 -0
- package/src/workspace/adaptive-thinking-repair.ts +33 -11
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +1 -1
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +1 -1
- package/src/workspace/migrations/026-backfill-install-meta.ts +1 -1
- package/src/workspace/migrations/030-seed-pkb-autoinject.ts +2 -1
- package/src/workspace/migrations/031-drop-user-md.ts +1 -4
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +1 -1
- package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +5 -2
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +1 -1
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +8 -2
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +41 -14
- package/src/workspace/migrations/102-preserve-heartbeat-enabled-for-existing-workspaces.ts +69 -0
- package/src/workspace/migrations/103-upgrade-quality-profile-to-opus-4-8.ts +83 -0
- package/src/workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.ts +133 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/migrations/runner.ts +1 -1
- package/tsconfig.json +1 -1
- package/src/__tests__/guardian-action-copy-generator.test.ts +0 -200
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -579
- package/src/__tests__/guardian-action-store.test.ts +0 -106
- package/src/daemon/guardian-action-generators.ts +0 -71
- package/src/memory/guardian-action-store.ts +0 -484
- package/src/runtime/guardian-action-grant-minter.ts +0 -150
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the default `max-tokens-continue` plugin's hooks.
|
|
3
|
+
*
|
|
4
|
+
* Covers:
|
|
5
|
+
* - The `post-model-call` hook's decision for the canonical cases: a
|
|
6
|
+
* main-agent turn truncated at the output token limit → continue, with the
|
|
7
|
+
* truncated turn and the canonical continuation nudge appended to
|
|
8
|
+
* `messages`; any other stop reason → stop; non-main-agent call sites →
|
|
9
|
+
* stop; a provider rejection → stop; an entirely-stripped (empty) truncated
|
|
10
|
+
* turn → stop.
|
|
11
|
+
* - The per-run budget is split across the two hooks: `post-model-call`
|
|
12
|
+
* consumes one unit per continue (up to `MAX_TOKENS_AUTO_CONTINUES`) and
|
|
13
|
+
* the `stop` hook clears the counter on the definitive terminal so the next
|
|
14
|
+
* run starts with a full budget.
|
|
15
|
+
*
|
|
16
|
+
* The loop's actual side-effects (keeping the partial turn, per-run backstop,
|
|
17
|
+
* the continuation card on a terminal stop) live in `agent/loop.ts`. This
|
|
18
|
+
* file isolates the hook.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { beforeEach, describe, expect, test } from "bun:test";
|
|
22
|
+
|
|
23
|
+
import type {
|
|
24
|
+
PluginLogger,
|
|
25
|
+
PostModelCallContext,
|
|
26
|
+
StopContext,
|
|
27
|
+
} from "../plugin-api/types.js";
|
|
28
|
+
import {
|
|
29
|
+
hasMaxTokensContinueBudget,
|
|
30
|
+
MAX_TOKENS_AUTO_CONTINUES,
|
|
31
|
+
resetMaxTokensContinueStoreForTests,
|
|
32
|
+
} from "../plugins/defaults/max-tokens-continue/continue-state-store.js";
|
|
33
|
+
import postModelCall, {
|
|
34
|
+
MAX_TOKENS_CONTINUE_NUDGE_TEXT,
|
|
35
|
+
} from "../plugins/defaults/max-tokens-continue/hooks/post-model-call.js";
|
|
36
|
+
import stop from "../plugins/defaults/max-tokens-continue/hooks/stop.js";
|
|
37
|
+
import type { ContentBlock } from "../providers/types.js";
|
|
38
|
+
|
|
39
|
+
// ─── Fixtures ────────────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
const noopLogger: PluginLogger = {
|
|
42
|
+
info: () => {},
|
|
43
|
+
warn: () => {},
|
|
44
|
+
error: () => {},
|
|
45
|
+
debug: () => {},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const truncatedText: ContentBlock = {
|
|
49
|
+
type: "text",
|
|
50
|
+
text: "Here is the start of a very long answer that got cut o",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
function makeCtx(
|
|
54
|
+
overrides: Partial<PostModelCallContext> = {},
|
|
55
|
+
): PostModelCallContext {
|
|
56
|
+
return {
|
|
57
|
+
conversationId: "conv-mtc",
|
|
58
|
+
callSite: "mainAgent",
|
|
59
|
+
content: [truncatedText],
|
|
60
|
+
messages: [{ role: "user", content: [{ type: "text", text: "build it" }] }],
|
|
61
|
+
stopReason: "max_tokens",
|
|
62
|
+
decision: "stop",
|
|
63
|
+
logger: noopLogger,
|
|
64
|
+
...overrides,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
beforeEach(() => {
|
|
69
|
+
resetMaxTokensContinueStoreForTests();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// ─── Decisions ───────────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
describe("max-tokens-continue post-model-call hook", () => {
|
|
75
|
+
test("truncated main-agent turn → continue with the turn and nudge appended", async () => {
|
|
76
|
+
/**
|
|
77
|
+
* Tests that a max_tokens stop on a main-agent turn auto-continues.
|
|
78
|
+
*/
|
|
79
|
+
// GIVEN a main-agent turn that stopped at the output token limit.
|
|
80
|
+
const ctx = makeCtx();
|
|
81
|
+
const priorLength = ctx.messages.length;
|
|
82
|
+
|
|
83
|
+
// WHEN the hook runs.
|
|
84
|
+
await postModelCall(ctx);
|
|
85
|
+
|
|
86
|
+
// THEN it asks the loop to continue.
|
|
87
|
+
expect(ctx.decision).toBe("continue");
|
|
88
|
+
// AND it appends the truncated assistant turn followed by the nudge.
|
|
89
|
+
expect(ctx.messages).toHaveLength(priorLength + 2);
|
|
90
|
+
expect(ctx.messages[priorLength]).toEqual({
|
|
91
|
+
role: "assistant",
|
|
92
|
+
content: [truncatedText],
|
|
93
|
+
});
|
|
94
|
+
expect(ctx.messages[priorLength + 1]).toEqual({
|
|
95
|
+
role: "user",
|
|
96
|
+
content: [{ type: "text", text: MAX_TOKENS_CONTINUE_NUDGE_TEXT }],
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("non-max-tokens stop reason → stop", async () => {
|
|
101
|
+
/**
|
|
102
|
+
* Tests that ordinary stop reasons are left alone.
|
|
103
|
+
*/
|
|
104
|
+
// GIVEN a turn that ended normally.
|
|
105
|
+
const ctx = makeCtx({ stopReason: "end_turn" });
|
|
106
|
+
|
|
107
|
+
// WHEN the hook runs.
|
|
108
|
+
await postModelCall(ctx);
|
|
109
|
+
|
|
110
|
+
// THEN the decision stays stop and messages are untouched.
|
|
111
|
+
expect(ctx.decision).toBe("stop");
|
|
112
|
+
expect(ctx.messages).toHaveLength(1);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("non-mainAgent call site → stop", async () => {
|
|
116
|
+
/**
|
|
117
|
+
* Tests that background/subagent calls are never auto-continued.
|
|
118
|
+
*/
|
|
119
|
+
// GIVEN a truncated turn on a non-main-agent call site.
|
|
120
|
+
const ctx = makeCtx({ callSite: "recall" });
|
|
121
|
+
|
|
122
|
+
// WHEN the hook runs.
|
|
123
|
+
await postModelCall(ctx);
|
|
124
|
+
|
|
125
|
+
// THEN the decision stays stop.
|
|
126
|
+
expect(ctx.decision).toBe("stop");
|
|
127
|
+
expect(ctx.messages).toHaveLength(1);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("provider rejection → stop", async () => {
|
|
131
|
+
/**
|
|
132
|
+
* Tests that a rejection outcome (no reply content) is ignored.
|
|
133
|
+
*/
|
|
134
|
+
// GIVEN a provider rejection carrying an error.
|
|
135
|
+
const ctx = makeCtx({ error: new Error("boom"), content: [] });
|
|
136
|
+
|
|
137
|
+
// WHEN the hook runs.
|
|
138
|
+
await postModelCall(ctx);
|
|
139
|
+
|
|
140
|
+
// THEN the decision stays stop.
|
|
141
|
+
expect(ctx.decision).toBe("stop");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("empty truncated content → stop", async () => {
|
|
145
|
+
/**
|
|
146
|
+
* Tests that a turn with nothing left after truncation-block stripping
|
|
147
|
+
* ends terminally rather than pushing an empty assistant message.
|
|
148
|
+
*/
|
|
149
|
+
// GIVEN a max_tokens stop whose safe content is empty.
|
|
150
|
+
const ctx = makeCtx({ content: [] });
|
|
151
|
+
|
|
152
|
+
// WHEN the hook runs.
|
|
153
|
+
await postModelCall(ctx);
|
|
154
|
+
|
|
155
|
+
// THEN the decision stays stop and nothing is appended.
|
|
156
|
+
expect(ctx.decision).toBe("stop");
|
|
157
|
+
expect(ctx.messages).toHaveLength(1);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("budget exhausts after MAX_TOKENS_AUTO_CONTINUES and stop hook resets it", async () => {
|
|
161
|
+
/**
|
|
162
|
+
* Tests the per-run continue budget and its reset on the terminal stop.
|
|
163
|
+
*/
|
|
164
|
+
// GIVEN the budget is consumed by repeated truncated turns.
|
|
165
|
+
for (let i = 0; i < MAX_TOKENS_AUTO_CONTINUES; i++) {
|
|
166
|
+
const ctx = makeCtx();
|
|
167
|
+
await postModelCall(ctx);
|
|
168
|
+
expect(ctx.decision).toBe("continue");
|
|
169
|
+
}
|
|
170
|
+
expect(hasMaxTokensContinueBudget("conv-mtc")).toBe(false);
|
|
171
|
+
|
|
172
|
+
// WHEN one more truncated turn arrives.
|
|
173
|
+
const exhausted = makeCtx();
|
|
174
|
+
await postModelCall(exhausted);
|
|
175
|
+
|
|
176
|
+
// THEN the hook lets the turn end.
|
|
177
|
+
expect(exhausted.decision).toBe("stop");
|
|
178
|
+
expect(exhausted.messages).toHaveLength(1);
|
|
179
|
+
|
|
180
|
+
// AND the stop hook clears the budget so the next run continues afresh.
|
|
181
|
+
await stop({ conversationId: "conv-mtc" } as StopContext);
|
|
182
|
+
expect(hasMaxTokensContinueBudget("conv-mtc")).toBe(true);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
@@ -322,7 +322,13 @@ describe("image-studio skill script wrapper", () => {
|
|
|
322
322
|
expect(result.isError).toBe(true);
|
|
323
323
|
expect(result.content).toContain("Mock Gemini error: API failure");
|
|
324
324
|
expect(result.content).toContain(
|
|
325
|
-
"
|
|
325
|
+
"Failed model: gemini-3.1-flash-image-preview",
|
|
326
|
+
);
|
|
327
|
+
expect(result.content).toContain(
|
|
328
|
+
"Do not change service configuration (managed/your-own mode or default provider/model settings)",
|
|
329
|
+
);
|
|
330
|
+
expect(result.content).toContain(
|
|
331
|
+
"Retrying this call once with a different model parameter is allowed",
|
|
326
332
|
);
|
|
327
333
|
});
|
|
328
334
|
|
|
@@ -335,7 +341,10 @@ describe("image-studio skill script wrapper", () => {
|
|
|
335
341
|
expect(result.isError).toBe(true);
|
|
336
342
|
expect(result.content).toContain("Mock OpenAI error: openai failure");
|
|
337
343
|
expect(result.content).toContain(
|
|
338
|
-
"Do not change service configuration (mode
|
|
344
|
+
"Do not change service configuration (managed/your-own mode or default provider/model settings)",
|
|
345
|
+
);
|
|
346
|
+
expect(result.content).toContain(
|
|
347
|
+
"Retrying this call once with a different model parameter is allowed",
|
|
339
348
|
);
|
|
340
349
|
});
|
|
341
350
|
|
|
@@ -346,8 +355,9 @@ describe("image-studio skill script wrapper", () => {
|
|
|
346
355
|
|
|
347
356
|
expect(result.isError).toBe(true);
|
|
348
357
|
expect(result.content).toContain("No Gemini API key");
|
|
358
|
+
expect(result.content).toContain("Report this error to the user as-is");
|
|
349
359
|
expect(result.content).toContain(
|
|
350
|
-
"Do not change service configuration (mode
|
|
360
|
+
"Do not change service configuration (managed/your-own mode or default provider/model settings)",
|
|
351
361
|
);
|
|
352
362
|
});
|
|
353
363
|
|
|
@@ -359,8 +369,9 @@ describe("image-studio skill script wrapper", () => {
|
|
|
359
369
|
|
|
360
370
|
expect(result.isError).toBe(true);
|
|
361
371
|
expect(result.content).toContain("Managed proxy is not available");
|
|
372
|
+
expect(result.content).toContain("Report this error to the user as-is");
|
|
362
373
|
expect(result.content).toContain(
|
|
363
|
-
"Do not change service configuration (mode
|
|
374
|
+
"Do not change service configuration (managed/your-own mode or default provider/model settings)",
|
|
364
375
|
);
|
|
365
376
|
});
|
|
366
377
|
|
|
@@ -463,11 +474,11 @@ describe("image-studio TOOLS.json manifest", () => {
|
|
|
463
474
|
expect(props.mode.enum).toEqual(["generate", "edit"]);
|
|
464
475
|
expect(props.source_paths.type).toBe("array");
|
|
465
476
|
expect(props.attachment_ids).toBeUndefined();
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
477
|
+
// No enum by design: model accepts tier aliases or concrete IDs, and is
|
|
478
|
+
// validated at runtime against the registry so the schema never goes
|
|
479
|
+
// stale when models change.
|
|
480
|
+
expect(props.model.type).toBe("string");
|
|
481
|
+
expect(props.model.enum).toBeUndefined();
|
|
471
482
|
expect(props.variants.type).toBe("number");
|
|
472
483
|
});
|
|
473
484
|
});
|
|
@@ -20,7 +20,7 @@ describe("model intents", () => {
|
|
|
20
20
|
"claude-haiku-4-5-20251001",
|
|
21
21
|
);
|
|
22
22
|
expect(resolveModelIntent("anthropic", "quality-optimized")).toBe(
|
|
23
|
-
"claude-
|
|
23
|
+
"claude-opus-4-8",
|
|
24
24
|
);
|
|
25
25
|
expect(resolveModelIntent("anthropic", "vision-optimized")).toBe(
|
|
26
26
|
"claude-opus-4-6",
|
|
@@ -139,6 +139,32 @@ describe("normalizeOnboardingContext", () => {
|
|
|
139
139
|
expect(result.preferredName).toBeUndefined();
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
+
test("maps occupation through, trimmed", () => {
|
|
143
|
+
const ctx: OnboardingContext = {
|
|
144
|
+
tools: [],
|
|
145
|
+
tasks: [],
|
|
146
|
+
tone: "friendly",
|
|
147
|
+
occupation: " Software Engineer ",
|
|
148
|
+
};
|
|
149
|
+
const result = normalizeOnboardingContext(ctx);
|
|
150
|
+
expect(result.occupation).toBe("Software Engineer");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("absent or blank occupation yields undefined", () => {
|
|
154
|
+
expect(
|
|
155
|
+
normalizeOnboardingContext({ tools: [], tasks: [], tone: "friendly" })
|
|
156
|
+
.occupation,
|
|
157
|
+
).toBeUndefined();
|
|
158
|
+
expect(
|
|
159
|
+
normalizeOnboardingContext({
|
|
160
|
+
tools: [],
|
|
161
|
+
tasks: [],
|
|
162
|
+
tone: "friendly",
|
|
163
|
+
occupation: " ",
|
|
164
|
+
}).occupation,
|
|
165
|
+
).toBeUndefined();
|
|
166
|
+
});
|
|
167
|
+
|
|
142
168
|
test("tone passes through", () => {
|
|
143
169
|
const ctx: OnboardingContext = {
|
|
144
170
|
tools: [],
|
|
@@ -15,8 +15,6 @@ import {
|
|
|
15
15
|
hasAccessRequestInstructions,
|
|
16
16
|
hasInviteFlowDirective,
|
|
17
17
|
normalizeForDirectiveMatching,
|
|
18
|
-
sanitizeIdentityField,
|
|
19
|
-
sanitizeMessagePreview,
|
|
20
18
|
} from "../notifications/access-request-copy.js";
|
|
21
19
|
import type { ConversationCandidateSet } from "../notifications/conversation-candidates.js";
|
|
22
20
|
import { composeFallbackCopy } from "../notifications/copy-composer.js";
|
|
@@ -24,6 +22,10 @@ import {
|
|
|
24
22
|
enforceGuardianCallConversationAffinity,
|
|
25
23
|
validateConversationActions,
|
|
26
24
|
} from "../notifications/decision-engine.js";
|
|
25
|
+
import {
|
|
26
|
+
sanitizeIdentityField,
|
|
27
|
+
sanitizeMessagePreview,
|
|
28
|
+
} from "../notifications/notification-utils.js";
|
|
27
29
|
import type { NotificationSignal } from "../notifications/signal.js";
|
|
28
30
|
import type {
|
|
29
31
|
NotificationChannel,
|
|
@@ -186,9 +186,18 @@ describe("TelegramAdapter", () => {
|
|
|
186
186
|
contextPayload: {
|
|
187
187
|
requestId: "req-abc-123",
|
|
188
188
|
requestCode: "XYZW",
|
|
189
|
-
senderIdentifier: "
|
|
189
|
+
senderIdentifier: "TestUser",
|
|
190
190
|
sourceChannel: "telegram",
|
|
191
191
|
},
|
|
192
|
+
approvalContext: {
|
|
193
|
+
requestId: "req-abc-123",
|
|
194
|
+
actions: [
|
|
195
|
+
{ id: "approve_once", label: "Approve once" },
|
|
196
|
+
{ id: "reject", label: "Reject" },
|
|
197
|
+
],
|
|
198
|
+
plainTextFallback:
|
|
199
|
+
'TestUser is requesting access to the assistant.\nReply "XYZW approve" to grant access or "XYZW reject" to deny.\nReply "open invite flow" to start Trusted Contacts invite flow.',
|
|
200
|
+
},
|
|
192
201
|
});
|
|
193
202
|
|
|
194
203
|
const result = await adapter.send(payload, makeDestination());
|
|
@@ -237,7 +246,7 @@ describe("TelegramAdapter", () => {
|
|
|
237
246
|
body: "Someone is requesting access.",
|
|
238
247
|
},
|
|
239
248
|
contextPayload: {
|
|
240
|
-
senderIdentifier: "
|
|
249
|
+
senderIdentifier: "TestUser",
|
|
241
250
|
sourceChannel: "telegram",
|
|
242
251
|
// no requestId
|
|
243
252
|
},
|
|
@@ -264,9 +273,18 @@ describe("TelegramAdapter", () => {
|
|
|
264
273
|
contextPayload: {
|
|
265
274
|
requestId: "req-abc-123",
|
|
266
275
|
requestCode: "XYZW",
|
|
267
|
-
senderIdentifier: "
|
|
276
|
+
senderIdentifier: "TestUser",
|
|
268
277
|
sourceChannel: "telegram",
|
|
269
278
|
},
|
|
279
|
+
approvalContext: {
|
|
280
|
+
requestId: "req-abc-123",
|
|
281
|
+
actions: [
|
|
282
|
+
{ id: "approve_once", label: "Approve once" },
|
|
283
|
+
{ id: "reject", label: "Reject" },
|
|
284
|
+
],
|
|
285
|
+
plainTextFallback:
|
|
286
|
+
'TestUser is requesting access to the assistant.\nReply "XYZW approve" to grant access or "XYZW reject" to deny.\nReply "open invite flow" to start Trusted Contacts invite flow.',
|
|
287
|
+
},
|
|
270
288
|
});
|
|
271
289
|
|
|
272
290
|
const result = await adapter.send(payload, makeDestination());
|
|
@@ -102,6 +102,28 @@ describe("pendingInteractions.resolve emits interaction_resolved", () => {
|
|
|
102
102
|
expect(publishedMessages).toHaveLength(0);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
+
test("no event is emitted for a conversation-less interaction", () => {
|
|
106
|
+
/**
|
|
107
|
+
* Conversation-less interactions (e.g. the CLI `credentials prompt`
|
|
108
|
+
* command) resolve through their own resolver rather than a conversation.
|
|
109
|
+
* The `interaction_resolved` envelope requires a conversationId, so the
|
|
110
|
+
* tracker skips the broadcast instead of emitting an invalid event.
|
|
111
|
+
*/
|
|
112
|
+
// GIVEN a registered interaction with no owning conversation
|
|
113
|
+
pendingInteractions.register("req-detached", { kind: "secret" });
|
|
114
|
+
|
|
115
|
+
// WHEN it is resolved
|
|
116
|
+
const returned = pendingInteractions.resolve("req-detached", "answered");
|
|
117
|
+
|
|
118
|
+
// THEN the entry is still returned to its caller
|
|
119
|
+
expect(returned).toBeDefined();
|
|
120
|
+
|
|
121
|
+
// AND no interaction_resolved envelope is published
|
|
122
|
+
expect(
|
|
123
|
+
publishedMessages.filter((m) => m.type === "interaction_resolved"),
|
|
124
|
+
).toHaveLength(0);
|
|
125
|
+
});
|
|
126
|
+
|
|
105
127
|
test("a single resolve emits exactly one event", () => {
|
|
106
128
|
pendingInteractions.register("req-once", {
|
|
107
129
|
conversationId: "conv-e",
|
|
@@ -186,4 +208,44 @@ describe("removeByConversation emits interaction_resolved per entry", () => {
|
|
|
186
208
|
.state,
|
|
187
209
|
).toBe("cancelled");
|
|
188
210
|
});
|
|
211
|
+
|
|
212
|
+
test("settles a swept secret prompt's resolver with a cancelled result", () => {
|
|
213
|
+
/**
|
|
214
|
+
* A secret prompt blocks its caller (the CLI `credentials prompt` command
|
|
215
|
+
* or the in-conversation SecretPrompter) on `rpcResolve`. Unlike questions
|
|
216
|
+
* (abort-signal teardown) and confirmations (denyAllPendingConfirmations),
|
|
217
|
+
* nothing else settles a secret when it is superseded, so removing the
|
|
218
|
+
* entry alone would hang the caller until its IPC client times out.
|
|
219
|
+
*/
|
|
220
|
+
// GIVEN a pending secret whose caller is blocked on rpcResolve
|
|
221
|
+
const resolved: unknown[] = [];
|
|
222
|
+
pendingInteractions.register("secret-sweep", {
|
|
223
|
+
conversationId: "conv-sweep",
|
|
224
|
+
kind: "secret",
|
|
225
|
+
rpcResolve: (value) => resolved.push(value),
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// WHEN a new user message supersedes the conversation's interactions
|
|
229
|
+
pendingInteractions.removeByConversation("conv-sweep");
|
|
230
|
+
|
|
231
|
+
// THEN the secret resolver is settled once with a cancelled result
|
|
232
|
+
expect(resolved).toEqual([{ value: null, delivery: "store" }]);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test("does not invoke a swept confirmation's resolver with a secret result", () => {
|
|
236
|
+
// GIVEN a pending confirmation carrying an rpcResolve callback
|
|
237
|
+
const resolved: unknown[] = [];
|
|
238
|
+
pendingInteractions.register("conf-sweep", {
|
|
239
|
+
conversationId: "conv-conf",
|
|
240
|
+
kind: "confirmation",
|
|
241
|
+
rpcResolve: (value) => resolved.push(value),
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// WHEN the conversation is superseded
|
|
245
|
+
pendingInteractions.removeByConversation("conv-conf");
|
|
246
|
+
|
|
247
|
+
// THEN the confirmation resolver is left untouched — only secret prompts
|
|
248
|
+
// are settled with a SecretPromptResult-shaped value here.
|
|
249
|
+
expect(resolved).toHaveLength(0);
|
|
250
|
+
});
|
|
189
251
|
});
|
|
@@ -49,8 +49,10 @@ describe("postTurnTruncateToolResults", () => {
|
|
|
49
49
|
const shortContent = "a".repeat(THRESHOLD_CHARS);
|
|
50
50
|
const messages = makeMessages([makeToolResult(shortContent)]);
|
|
51
51
|
|
|
52
|
-
const { messages: result, truncatedCount } =
|
|
53
|
-
|
|
52
|
+
const { messages: result, truncatedCount } = postTurnTruncateToolResults(
|
|
53
|
+
messages,
|
|
54
|
+
{ conversationDir: convDir },
|
|
55
|
+
);
|
|
54
56
|
|
|
55
57
|
expect(truncatedCount).toBe(0);
|
|
56
58
|
expect(result).toBe(messages); // same reference — no copy
|
|
@@ -62,12 +64,17 @@ describe("postTurnTruncateToolResults", () => {
|
|
|
62
64
|
const toolUseId = "tool_use_abc";
|
|
63
65
|
const messages = makeMessages([makeToolResult(longContent, toolUseId)]);
|
|
64
66
|
|
|
65
|
-
const { messages: result, truncatedCount } =
|
|
66
|
-
|
|
67
|
+
const { messages: result, truncatedCount } = postTurnTruncateToolResults(
|
|
68
|
+
messages,
|
|
69
|
+
{ conversationDir: convDir },
|
|
70
|
+
);
|
|
67
71
|
|
|
68
72
|
expect(truncatedCount).toBe(1);
|
|
69
73
|
|
|
70
|
-
const block = result[0].content[0] as {
|
|
74
|
+
const block = result[0].content[0] as {
|
|
75
|
+
type: "tool_result";
|
|
76
|
+
content: string;
|
|
77
|
+
};
|
|
71
78
|
expect(block.content).toContain(TRUNCATION_MARKER);
|
|
72
79
|
expect(block.content.length).toBeLessThan(longContent.length);
|
|
73
80
|
|
|
@@ -83,8 +90,10 @@ describe("postTurnTruncateToolResults", () => {
|
|
|
83
90
|
makeToolResult(longContent, "tool_err", true),
|
|
84
91
|
]);
|
|
85
92
|
|
|
86
|
-
const { messages: result, truncatedCount } =
|
|
87
|
-
|
|
93
|
+
const { messages: result, truncatedCount } = postTurnTruncateToolResults(
|
|
94
|
+
messages,
|
|
95
|
+
{ conversationDir: convDir },
|
|
96
|
+
);
|
|
88
97
|
|
|
89
98
|
expect(truncatedCount).toBe(0);
|
|
90
99
|
expect(result).toBe(messages);
|
|
@@ -100,8 +109,10 @@ describe("postTurnTruncateToolResults", () => {
|
|
|
100
109
|
makeToolResult(alreadyTruncated, "tool_idempotent"),
|
|
101
110
|
]);
|
|
102
111
|
|
|
103
|
-
const { messages: result, truncatedCount } =
|
|
104
|
-
|
|
112
|
+
const { messages: result, truncatedCount } = postTurnTruncateToolResults(
|
|
113
|
+
messages,
|
|
114
|
+
{ conversationDir: convDir },
|
|
115
|
+
);
|
|
105
116
|
|
|
106
117
|
expect(truncatedCount).toBe(0);
|
|
107
118
|
expect(result).toBe(messages);
|
|
@@ -117,8 +128,10 @@ describe("postTurnTruncateToolResults", () => {
|
|
|
117
128
|
makeToolResult(long2, "tool_long2"),
|
|
118
129
|
]);
|
|
119
130
|
|
|
120
|
-
const { messages: result, truncatedCount } =
|
|
121
|
-
|
|
131
|
+
const { messages: result, truncatedCount } = postTurnTruncateToolResults(
|
|
132
|
+
messages,
|
|
133
|
+
{ conversationDir: convDir },
|
|
134
|
+
);
|
|
122
135
|
|
|
123
136
|
expect(truncatedCount).toBe(2);
|
|
124
137
|
|
|
@@ -174,8 +187,10 @@ describe("postTurnTruncateToolResults", () => {
|
|
|
174
187
|
{ role: "user", content: [makeToolResult(skillBody, toolUseId)] },
|
|
175
188
|
];
|
|
176
189
|
|
|
177
|
-
const { messages: result, truncatedCount } =
|
|
178
|
-
|
|
190
|
+
const { messages: result, truncatedCount } = postTurnTruncateToolResults(
|
|
191
|
+
messages,
|
|
192
|
+
{ conversationDir: convDir },
|
|
193
|
+
);
|
|
179
194
|
|
|
180
195
|
expect(truncatedCount).toBe(0);
|
|
181
196
|
expect(result).toBe(messages); // same reference — no copy
|
|
@@ -209,8 +224,10 @@ describe("postTurnTruncateToolResults", () => {
|
|
|
209
224
|
{ role: "user", content: [makeToolResult(longContent, toolUseId)] },
|
|
210
225
|
];
|
|
211
226
|
|
|
212
|
-
const { messages: result, truncatedCount } =
|
|
213
|
-
|
|
227
|
+
const { messages: result, truncatedCount } = postTurnTruncateToolResults(
|
|
228
|
+
messages,
|
|
229
|
+
{ conversationDir: convDir },
|
|
230
|
+
);
|
|
214
231
|
|
|
215
232
|
expect(truncatedCount).toBe(1);
|
|
216
233
|
const block = result[1].content[0] as {
|
|
@@ -262,7 +279,38 @@ describe("derefToolResultReReads", () => {
|
|
|
262
279
|
derefToolResultReReads(messages);
|
|
263
280
|
|
|
264
281
|
expect(dereferencedCount).toBe(1);
|
|
265
|
-
const block = result[1].content[0] as {
|
|
282
|
+
const block = result[1].content[0] as {
|
|
283
|
+
type: "tool_result";
|
|
284
|
+
content: string;
|
|
285
|
+
};
|
|
286
|
+
expect(block.content).toBe(REREAD_STUB);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test("host_file_read of .tool-results/ path: tool_result content replaced with REREAD_STUB", () => {
|
|
290
|
+
const toolUseId = "tu_host_reread";
|
|
291
|
+
const messages: Message[] = [
|
|
292
|
+
{
|
|
293
|
+
role: "assistant",
|
|
294
|
+
content: [
|
|
295
|
+
makeToolUse(toolUseId, "host_file_read", {
|
|
296
|
+
path: `/home/user/.local/share/vellum/conversations/abc/${TOOL_RESULT_DIR}/abc123.txt`,
|
|
297
|
+
}),
|
|
298
|
+
],
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
role: "user",
|
|
302
|
+
content: [makeToolResult("full host file contents here", toolUseId)],
|
|
303
|
+
},
|
|
304
|
+
];
|
|
305
|
+
|
|
306
|
+
const { messages: result, dereferencedCount } =
|
|
307
|
+
derefToolResultReReads(messages);
|
|
308
|
+
|
|
309
|
+
expect(dereferencedCount).toBe(1);
|
|
310
|
+
const block = result[1].content[0] as {
|
|
311
|
+
type: "tool_result";
|
|
312
|
+
content: string;
|
|
313
|
+
};
|
|
266
314
|
expect(block.content).toBe(REREAD_STUB);
|
|
267
315
|
});
|
|
268
316
|
|
|
@@ -289,7 +337,10 @@ describe("derefToolResultReReads", () => {
|
|
|
289
337
|
|
|
290
338
|
expect(dereferencedCount).toBe(0);
|
|
291
339
|
expect(result).toBe(messages); // same reference — no copy
|
|
292
|
-
const block = result[1].content[0] as {
|
|
340
|
+
const block = result[1].content[0] as {
|
|
341
|
+
type: "tool_result";
|
|
342
|
+
content: string;
|
|
343
|
+
};
|
|
293
344
|
expect(block.content).toBe(originalContent);
|
|
294
345
|
});
|
|
295
346
|
|
|
@@ -316,7 +367,10 @@ describe("derefToolResultReReads", () => {
|
|
|
316
367
|
|
|
317
368
|
expect(dereferencedCount).toBe(0);
|
|
318
369
|
expect(result).toBe(messages);
|
|
319
|
-
const block = result[1].content[0] as {
|
|
370
|
+
const block = result[1].content[0] as {
|
|
371
|
+
type: "tool_result";
|
|
372
|
+
content: string;
|
|
373
|
+
};
|
|
320
374
|
expect(block.content).toBe(outputMentioningDir);
|
|
321
375
|
});
|
|
322
376
|
|