@vellumai/assistant 0.10.9 → 0.10.10-dev.202607162206.d08e98e
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/ARCHITECTURE.md +1 -1
- package/Dockerfile +8 -0
- package/docs/activation-funnel-telemetry.md +13 -7
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/openapi.yaml +530 -107
- package/package.json +1 -1
- package/scripts/generate-openapi.ts +8 -0
- package/src/__tests__/activation-early-marking.test.ts +6 -5
- package/src/__tests__/agent-loop-override-profile.test.ts +22 -25
- package/src/__tests__/agent-wake-override-profile.test.ts +21 -48
- package/src/__tests__/app-builder-tool-scripts.test.ts +0 -1
- package/src/__tests__/app-bundler.test.ts +4 -12
- package/src/__tests__/app-executors.test.ts +2 -49
- package/src/__tests__/app-routes-csp.test.ts +114 -146
- package/src/__tests__/auth-fallback-events-store.test.ts +8 -1
- package/src/__tests__/build-persisted-content.test.ts +96 -0
- package/src/__tests__/bundle-scanner.test.ts +27 -1
- package/src/__tests__/call-controller.test.ts +291 -0
- package/src/__tests__/call-site-routing-connection-auto-resolve.test.ts +165 -0
- package/src/__tests__/chat-credential-redaction.test.ts +1395 -0
- package/src/__tests__/chat-reveal-guard-priming.test.ts +791 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -1
- package/src/__tests__/compactor-image-manifest-trust.test.ts +50 -0
- package/src/__tests__/config-loader-backfill.test.ts +9 -4
- package/src/__tests__/config-schema-cmd.test.ts +10 -11
- package/src/__tests__/config-schema.test.ts +190 -257
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +208 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +5 -19
- package/src/__tests__/conversation-agent-loop.test.ts +22 -9
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +110 -0
- package/src/__tests__/conversation-process-callsite.test.ts +12 -19
- package/src/__tests__/conversation-routes-slash-commands.test.ts +7 -21
- package/src/__tests__/conversation-summarize-route.test.ts +36 -44
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +7 -7
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +0 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -1
- package/src/__tests__/conversation-usage.test.ts +4 -12
- package/src/__tests__/credential-routes.test.ts +250 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/db-migration-rollback.test.ts +22 -0
- package/src/__tests__/empty-response-hook.test.ts +186 -1
- package/src/__tests__/external-plugin-loader.test.ts +11 -5
- package/src/__tests__/heartbeat-service.test.ts +0 -28
- package/src/__tests__/host-shell-tool.test.ts +2 -0
- package/src/__tests__/inactive-tool-error-messages.test.ts +2 -2
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +52 -8
- package/src/__tests__/internal-telemetry-routes.test.ts +23 -4
- package/src/__tests__/invite-routes-http.test.ts +12 -16
- package/src/__tests__/list-all-apps.test.ts +0 -4
- package/src/__tests__/llm-context-resolution.test.ts +32 -56
- package/src/__tests__/llm-request-log-turn-query.test.ts +109 -0
- package/src/__tests__/llm-resolver-override-or-default.test.ts +3 -52
- package/src/__tests__/llm-resolver.test.ts +342 -602
- package/src/__tests__/llm-schema.test.ts +79 -37
- package/src/__tests__/max-tokens-continue-hook.test.ts +19 -0
- package/src/__tests__/media-stream-output.test.ts +259 -3
- package/src/__tests__/media-stream-server-integration.test.ts +22 -1
- package/src/__tests__/media-stream-stt-session.test.ts +47 -0
- package/src/__tests__/memory-jobs-worker-cleanup-cadence.test.ts +33 -0
- package/src/__tests__/memory-recall-log-store.test.ts +47 -13
- package/src/__tests__/mock-gateway-ipc.ts +46 -1
- package/src/__tests__/mtime-cache.test.ts +61 -0
- package/src/__tests__/navigate-settings-tab.test.ts +2 -0
- package/src/__tests__/normalize-onboarding.test.ts +33 -0
- package/src/__tests__/onboarding-persona-write.test.ts +26 -0
- package/src/__tests__/plugin-api-resolve-credential.test.ts +140 -0
- package/src/__tests__/plugin-app-serve-routes.test.ts +166 -14
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +2 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +38 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +27 -20
- package/src/__tests__/provider-connections-backfill.test.ts +138 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +10 -31
- package/src/__tests__/provider-registry-ollama.test.ts +8 -18
- package/src/__tests__/provider-send-message-override-profile.test.ts +23 -23
- package/src/__tests__/provider-usage-tracking.test.ts +9 -19
- package/src/__tests__/prune-old-conversations-job.test.ts +12 -0
- package/src/__tests__/published-app-updater.test.ts +22 -16
- package/src/__tests__/registry.test.ts +5 -16
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +22 -23
- package/src/__tests__/retry-thinking-adaptive-only.test.ts +43 -48
- package/src/__tests__/retry-thinking-tool-choice.test.ts +57 -66
- package/src/__tests__/retry-verbosity-normalization.test.ts +24 -23
- package/src/__tests__/reveal-success-registry.test.ts +123 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +130 -0
- package/src/__tests__/secret-fixtures.ts +9 -0
- package/src/__tests__/server-history-render.test.ts +28 -0
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/slack-share-routes.test.ts +0 -1
- package/src/__tests__/stt-stream-session.test.ts +6 -5
- package/src/__tests__/subagent-call-site-routing.test.ts +69 -95
- package/src/__tests__/subagent-disposal.test.ts +2 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +2 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +2 -0
- package/src/__tests__/subagent-manager-notify.test.ts +2 -0
- package/src/__tests__/subagent-role-registry.test.ts +37 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
- package/src/__tests__/subagent-terminal-message.test.ts +50 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -5
- package/src/__tests__/surface-completion-nudge-hook.test.ts +19 -0
- package/src/__tests__/telemetry-routes.test.ts +99 -19
- package/src/__tests__/tool-audit.test.ts +34 -4
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-profiler.test.ts +72 -1
- package/src/__tests__/tool-result-spool.test.ts +49 -4
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -1
- package/src/__tests__/ui-channel-variants.test.ts +108 -0
- package/src/__tests__/ui-shape-teaching.test.ts +255 -0
- package/src/__tests__/usage-attribution.test.ts +18 -41
- package/src/__tests__/user-plugin-loader.test.ts +4 -4
- package/src/__tests__/voice-config-update.test.ts +46 -0
- package/src/__tests__/voice-session-bridge.test.ts +216 -84
- package/src/__tests__/workspace-migration-131-drop-web-fetch-mode.test.ts +120 -0
- package/src/agent/loop.ts +4 -3
- package/src/api/events/open-conversation.test.ts +64 -0
- package/src/api/events/open-conversation.ts +33 -0
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +25 -35
- package/src/bundler/app-bundler.ts +34 -48
- package/src/bundler/app-compiler.ts +39 -4
- package/src/bundler/bundle-scanner.ts +13 -0
- package/src/bundler/manifest.ts +1 -1
- package/src/calls/__tests__/voice-session-bridge.test.ts +47 -0
- package/src/calls/call-constants.ts +5 -0
- package/src/calls/call-controller.ts +100 -32
- package/src/calls/call-transport.ts +9 -0
- package/src/calls/media-stream-output.ts +107 -4
- package/src/calls/media-stream-server.ts +29 -9
- package/src/calls/media-stream-stt-session.ts +7 -1
- package/src/calls/media-turn-detector.ts +11 -1
- package/src/calls/voice-session-bridge.ts +84 -63
- package/src/cli/commands/__tests__/inference-providers.test.ts +270 -33
- package/src/cli/commands/__tests__/notifications.test.ts +24 -3
- package/src/cli/commands/config.help.ts +6 -6
- package/src/cli/commands/credentials.help.ts +13 -0
- package/src/cli/commands/credentials.ts +6 -1
- package/src/cli/commands/email.help.ts +7 -0
- package/src/cli/commands/email.ts +35 -1
- package/src/cli/commands/inference-providers.ts +168 -107
- package/src/cli/commands/inference.help.ts +118 -46
- package/src/cli/commands/memory/index.help.ts +23 -0
- package/src/cli/commands/memory/nodes.ts +146 -0
- package/src/cli/commands/notifications.help.ts +10 -10
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +40 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +54 -0
- package/src/cli/commands/oauth/connect.test.ts +126 -0
- package/src/cli/commands/oauth/connect.ts +29 -6
- package/src/cli/commands/oauth/index.help.ts +7 -1
- package/src/cli/commands/oauth/status.test.ts +69 -3
- package/src/cli/commands/oauth/status.ts +50 -12
- package/src/cli/commands/plugins.help.ts +13 -2
- package/src/cli/commands/plugins.ts +61 -7
- package/src/cli/commands/telemetry.help.ts +13 -0
- package/src/cli/commands/telemetry.ts +45 -5
- package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +8 -2
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +213 -9
- package/src/cli/lib/bundled-marketplace.json +93 -36
- package/src/cli/lib/inspect-plugin.ts +5 -1
- package/src/cli/lib/install-from-github.ts +68 -4
- package/src/cli/lib/plugin-catalog-local.ts +6 -2
- package/src/cli/lib/plugin-fingerprint.ts +3 -3
- package/src/cli/lib/upgrade-plugin.ts +236 -35
- package/src/config/__tests__/default-profile-catalog.test.ts +8 -12
- package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +137 -0
- package/src/config/__tests__/profile-materialization.test.ts +1 -88
- package/src/config/bundled-skills/AGENTS.md +3 -30
- package/src/config/bundled-skills/app-builder/SKILL.md +5 -3
- package/src/config/bundled-skills/app-builder/TOOLS.json +23 -0
- package/src/config/bundled-skills/app-builder/tools/app-open.ts +32 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +7 -7
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +3 -1
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +2 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +18 -10
- package/src/config/bundled-skills/subagent/SKILL.md +2 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
- package/src/config/call-site-defaults.ts +3 -3
- package/src/config/feature-flag-registry.json +24 -39
- package/src/config/llm-resolver.ts +88 -475
- package/src/config/profile-materialization.ts +11 -11
- package/src/config/schema.ts +93 -127
- package/src/config/schemas/__tests__/live-voice.test.ts +24 -6
- package/src/config/schemas/__tests__/stt.test.ts +31 -3
- package/src/config/schemas/live-voice.ts +10 -4
- package/src/config/schemas/llm.ts +52 -15
- package/src/config/schemas/memory-lifecycle.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +8 -0
- package/src/config/schemas/memory-v2.ts +2 -2
- package/src/config/schemas/memory-v3.ts +1 -1
- package/src/config/schemas/services.ts +6 -3
- package/src/config/schemas/stt.ts +38 -21
- package/src/config/schemas/tts.ts +13 -18
- package/src/config/skills.ts +31 -21
- package/src/context/compactor.ts +44 -7
- package/src/context/post-turn-tool-result-truncation.ts +4 -2
- package/src/context/tool-result-spool.ts +26 -5
- package/src/conversations/__tests__/message-consolidation.test.ts +48 -0
- package/src/conversations/message-consolidation.ts +22 -2
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +5 -12
- package/src/daemon/app-source-watcher.ts +17 -23
- package/src/daemon/chat-credential-redaction.ts +1365 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +627 -34
- package/src/daemon/conversation-agent-loop.ts +71 -31
- package/src/daemon/conversation-error.ts +36 -14
- package/src/daemon/conversation-process.ts +22 -0
- package/src/daemon/conversation-store.ts +35 -0
- package/src/daemon/conversation-surfaces.ts +25 -25
- package/src/daemon/conversation-tool-setup.ts +33 -7
- package/src/daemon/conversation.ts +55 -5
- package/src/daemon/handlers/shared.ts +33 -2
- package/src/daemon/lifecycle.ts +4 -4
- package/src/daemon/message-types/conversations.ts +6 -17
- package/src/daemon/providers-setup.ts +8 -0
- package/src/daemon/tool-setup-types.ts +7 -1
- package/src/daemon/wake-conversation-ops.ts +10 -1
- package/src/hooks/types.ts +9 -0
- package/src/ipc/__tests__/email-ipc.test.ts +90 -0
- package/src/ipc/gateway-client.test.ts +59 -0
- package/src/ipc/gateway-client.ts +70 -27
- package/src/live-voice/__tests__/live-voice-events.test.ts +14 -2
- package/src/live-voice/__tests__/live-voice-integration.test.ts +116 -2
- package/src/live-voice/__tests__/live-voice-vad.test.ts +804 -13
- package/src/live-voice/__tests__/protocol.test.ts +122 -0
- package/src/live-voice/live-voice-session.ts +443 -40
- package/src/live-voice/protocol.ts +143 -1
- package/src/monitoring/__tests__/plugin-source-watch.test.ts +3 -1
- package/src/monitoring/plugin-source-watch.ts +3 -62
- package/src/notifications/README.md +1 -1
- package/src/permissions/checker.ts +8 -4
- package/src/persistence/__tests__/db-init-migrations-ok.test.ts +26 -0
- package/src/persistence/conversation-crud.ts +104 -2
- package/src/persistence/db-init.ts +14 -3
- package/src/persistence/job-handlers/cleanup.ts +15 -7
- package/src/persistence/llm-request-log-store.ts +88 -52
- package/src/persistence/migrations/298-move-memory-jobs-to-memory-db.ts +7 -31
- package/src/persistence/migrations/305-drop-contact-acl-columns.ts +3 -2
- package/src/persistence/migrations/326-move-injection-events-to-memory-db.ts +8 -34
- package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +90 -0
- package/src/persistence/migrations/337-move-memory-recall-logs-to-memory-db.ts +114 -0
- package/src/persistence/migrations/338-move-memory-v3-selections-to-memory-db.ts +84 -0
- package/src/persistence/migrations/339-move-activation-sessions-to-memory-db.ts +52 -0
- package/src/persistence/migrations/__tests__/run-migrations.test.ts +155 -0
- package/src/persistence/migrations/helpers/relocation.ts +44 -1
- package/src/persistence/migrations/run-migrations.ts +25 -1
- package/src/persistence/schema/infrastructure.ts +9 -0
- package/src/persistence/schema/memory-core.ts +3 -0
- package/src/persistence/schema/memory-injection.ts +2 -0
- package/src/persistence/steps.ts +36 -0
- package/src/platform/client.test.ts +1 -44
- package/src/platform/client.ts +10 -20
- package/src/platform/consent-cache.test.ts +89 -23
- package/src/platform/consent-cache.ts +71 -33
- package/src/plugin-api/constants.ts +12 -0
- package/src/plugin-api/conversation-turn.ts +37 -14
- package/src/plugin-api/index.ts +11 -1
- package/src/plugin-api/resolve-credential.ts +75 -0
- package/src/plugin-api/vision-support.test.ts +8 -19
- package/src/plugin-api/vision-support.ts +26 -17
- package/src/plugins/collect-source-versions.ts +77 -0
- package/src/plugins/defaults/compaction/compact.ts +6 -0
- package/src/plugins/defaults/compaction/window-manager.ts +9 -0
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +18 -24
- package/src/plugins/defaults/empty-response/hooks/user-prompt-submit.ts +38 -0
- package/src/plugins/defaults/empty-response/refusal-quarantine.ts +99 -0
- package/src/plugins/defaults/image-fallback/__tests__/caption-cache-persistence.test.ts +7 -3
- package/src/plugins/defaults/index.ts +8 -1
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +48 -6
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +28 -22
- package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +148 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +80 -8
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +202 -0
- package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +64 -25
- package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +24 -11
- package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +70 -6
- package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +278 -0
- package/src/plugins/defaults/memory/activation-session-store.ts +27 -20
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -9
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +1 -8
- package/src/plugins/defaults/memory/graph/retriever.test.ts +6 -6
- package/src/plugins/defaults/memory/graph/store.ts +114 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +36 -1
- package/src/plugins/defaults/memory/graph/tools.ts +47 -13
- package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +16 -35
- package/src/plugins/defaults/memory/jobs-worker.ts +10 -1
- package/src/plugins/defaults/memory/memory-db.ts +3 -2
- package/src/plugins/defaults/memory/memory-recall-log-store.ts +129 -66
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +8 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +11 -122
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +216 -0
- package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +84 -46
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +42 -32
- package/src/plugins/defaults/memory/path-containment.ts +21 -0
- package/src/plugins/defaults/memory/prompt-override.ts +51 -13
- package/src/plugins/defaults/memory/tools.test.ts +34 -0
- package/src/plugins/defaults/memory/tools.ts +12 -2
- package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +19 -15
- package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +24 -19
- package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +19 -15
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +22 -2
- package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +5 -3
- package/src/plugins/defaults/memory/v2/harness/oracle.ts +59 -41
- package/src/plugins/defaults/memory/v2/harness/replay-input.ts +29 -25
- package/src/plugins/defaults/memory/v2/migration.ts +46 -16
- package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +4 -0
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +17 -15
- package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +24 -22
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +9 -5
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +277 -10
- package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +57 -5
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +9 -7
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +38 -7
- package/src/plugins/defaults/memory/v3/hot-set.test.ts +36 -18
- package/src/plugins/defaults/memory/v3/hot-set.ts +12 -14
- package/src/plugins/defaults/memory/v3/learned-edges.test.ts +47 -27
- package/src/plugins/defaults/memory/v3/learned-edges.ts +12 -14
- package/src/plugins/defaults/memory/v3/orchestrate.ts +139 -22
- package/src/plugins/defaults/memory/v3/prune.test.ts +10 -3
- package/src/plugins/defaults/memory/v3/prune.ts +17 -11
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +23 -11
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +70 -53
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +9 -6
- package/src/plugins/external-plugin-loader.ts +15 -15
- package/src/plugins/mtime-cache.ts +47 -0
- package/src/plugins/pipeline.ts +9 -1
- package/src/plugins/plugin-execution-context.ts +44 -0
- package/src/plugins/plugin-tree-walk.ts +31 -24
- package/src/plugins/source-fingerprint.ts +3 -4
- package/src/prompts/normalize-onboarding.ts +12 -0
- package/src/prompts/persona-resolver.ts +8 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +1 -1
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +6 -9
- package/src/providers/__tests__/registry-native-web-search.test.ts +4 -10
- package/src/providers/__tests__/retry-callsite.test.ts +235 -215
- package/src/providers/__tests__/satellite-connection-routing.test.ts +8 -16
- package/src/providers/atlascloud/client.ts +10 -49
- package/src/providers/baseten/client.ts +43 -0
- package/src/providers/call-site-routing.ts +26 -13
- package/src/providers/connection-resolution.ts +9 -11
- package/src/providers/fetch-provider-catalog.ts +4 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +29 -4
- package/src/providers/inference/__tests__/connection-availability-keyless.test.ts +78 -0
- package/src/providers/inference/adapter-factory.ts +27 -6
- package/src/providers/inference/auth.ts +29 -1
- package/src/providers/inference/backfill.ts +61 -10
- package/src/providers/inference/connection-availability.ts +3 -2
- package/src/providers/inference/resolve-auth.ts +9 -1
- package/src/providers/model-catalog.ts +37 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +24 -2
- package/src/providers/openai/api-key-validation.ts +70 -0
- package/src/providers/retry.ts +2 -0
- package/src/providers/types.ts +11 -4
- package/src/providers/vellum-model-routing.test.ts +26 -0
- package/src/providers/vellum-model-routing.ts +30 -0
- package/src/providers/voice-error-copy.ts +47 -0
- package/src/runtime/agent-wake.ts +40 -24
- package/src/runtime/for-chat-mint-registry.ts +118 -0
- package/src/runtime/reveal-nonce.ts +49 -0
- package/src/runtime/reveal-success-registry.ts +306 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +88 -3
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +161 -30
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +7 -0
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +15 -0
- package/src/runtime/routes/app-management-routes.ts +152 -45
- package/src/runtime/routes/app-routes.ts +16 -77
- package/src/runtime/routes/canned-message-complete.ts +16 -16
- package/src/runtime/routes/conversation-management-routes.ts +17 -14
- package/src/runtime/routes/conversation-query-routes.ts +54 -6
- package/src/runtime/routes/conversation-routes.ts +48 -2
- package/src/runtime/routes/credential-routes.ts +116 -3
- package/src/runtime/routes/email-routes.ts +17 -1
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +33 -5
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +6 -5
- package/src/runtime/routes/inference-provider-connection-routes.ts +77 -28
- package/src/runtime/routes/inference-send-routes.ts +1 -1
- package/src/runtime/routes/internal-telemetry-routes.ts +7 -6
- package/src/runtime/routes/plugins-routes.ts +37 -6
- package/src/runtime/routes/publish-routes.ts +15 -18
- package/src/runtime/routes/schedule-worker-routes.ts +9 -0
- package/src/runtime/routes/secret-routes.ts +10 -0
- package/src/runtime/routes/telemetry-routes.ts +149 -45
- package/src/schedule/__tests__/schedule-timezone.test.ts +101 -0
- package/src/schedule/__tests__/worker-watchdog.test.ts +209 -0
- package/src/schedule/schedule-store.ts +12 -1
- package/src/schedule/schedule-timezone.ts +63 -0
- package/src/schedule/scheduler.ts +100 -6
- package/src/schedule/worker-control.ts +19 -0
- package/src/security/auth-fallback-events-store.ts +7 -6
- package/src/security/secret-scanner.ts +26 -1
- package/src/services/published-app-updater.ts +6 -11
- package/src/stt/stt-stream-session.ts +36 -16
- package/src/subagent/manager.ts +34 -8
- package/src/telemetry/AGENTS.md +30 -1
- package/src/telemetry/__tests__/config-setting-snapshot.test.ts +18 -0
- package/src/telemetry/__tests__/outbox-test-harness.ts +5 -3
- package/src/telemetry/config-setting-snapshot.ts +44 -10
- package/src/telemetry/telemetry-event-sources.test.ts +124 -30
- package/src/telemetry/telemetry-event-sources.ts +137 -83
- package/src/telemetry/telemetry-events-outbox.test.ts +46 -1
- package/src/telemetry/telemetry-events-outbox.ts +60 -9
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire-validation.ts +39 -2
- package/src/telemetry/telemetry-wire.generated.ts +8 -0
- package/src/telemetry/tool-audit.ts +15 -9
- package/src/telemetry/tool-executed-events-store.test.ts +1 -1
- package/src/telemetry/turn-events-store.ts +20 -0
- package/src/telemetry/types.ts +45 -12
- package/src/telemetry/usage-telemetry-reporter.test.ts +294 -25
- package/src/telemetry/usage-telemetry-reporter.ts +117 -18
- package/src/telemetry/watchdog-direct-emit.test.ts +11 -3
- package/src/telemetry/watchdog-direct-emit.ts +11 -6
- package/src/tools/apps/executors.ts +11 -36
- package/src/tools/executor.ts +14 -1
- package/src/tools/host-terminal/host-shell.ts +6 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +1 -1
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +25 -0
- package/src/tools/network/web-fetch.ts +6 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/subagent/spawn.ts +7 -11
- package/src/tools/terminal/shell.ts +5 -2
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/tool-profiler.ts +37 -6
- package/src/tools/ui-surface/channel-variants.ts +101 -0
- package/src/tools/ui-surface/definitions.ts +23 -67
- package/src/tools/ui-surface/surface-shape-docs.ts +229 -0
- package/src/tts/__tests__/provider-adapters.test.ts +18 -0
- package/src/tts/provider-catalog.ts +2 -4
- package/src/tts/providers/deepgram-provider.ts +10 -1
- package/src/types/onboarding-context.ts +8 -0
- package/src/usage/attribution.ts +18 -112
- package/src/{config/bundled-skills/messaging/tools/gmail-mime-helpers.ts → util/mime-type.ts} +4 -1
- package/src/util/provider-error-patterns.ts +7 -1
- package/src/util/worker-process.ts +105 -0
- package/src/watcher/__tests__/telemetry.test.ts +17 -4
- package/src/watcher/telemetry.ts +5 -5
- package/src/workspace/migrations/131-drop-web-fetch-mode.ts +61 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/workspace/provider-commit-message-generator.ts +6 -4
- package/src/__tests__/app-open-proxy.test.ts +0 -67
- package/src/onboarding/onboarding-research-events-store.test.ts +0 -230
- package/src/onboarding/onboarding-research-events-store.ts +0 -104
- package/src/runtime/routes/assets/vellum-design-system.css +0 -2236
- package/src/tools/apps/definitions.ts +0 -73
- package/src/tools/apps/open-proxy.ts +0 -43
|
@@ -27,9 +27,7 @@ import {
|
|
|
27
27
|
resolveEffectiveContextWindow,
|
|
28
28
|
} from "../config/llm-context-resolution.js";
|
|
29
29
|
import {
|
|
30
|
-
isOverrideOrDefaultResolutionEnabled,
|
|
31
30
|
resolveCallSiteConfig,
|
|
32
|
-
resolveDefaultProfileKey,
|
|
33
31
|
resolveEffectiveProfileKey,
|
|
34
32
|
resolveProfilelessModelKey,
|
|
35
33
|
selectWinningProfile,
|
|
@@ -256,6 +254,16 @@ async function withAbortWatchdog<T>(
|
|
|
256
254
|
|
|
257
255
|
// ── runAgentLoop ─────────────────────────────────────────────────────
|
|
258
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Steering block appended to the tail user message on turns whose
|
|
259
|
+
* triggering message carries `messageSource: "nav_redirect"` — a UI
|
|
260
|
+
* shortcut sent the message on the user's behalf while the user was
|
|
261
|
+
* exploring the interface. Without it the model treats the canned prompt
|
|
262
|
+
* as a hand-typed question and answers with a capability tour.
|
|
263
|
+
*/
|
|
264
|
+
const NAV_REDIRECT_STEERING_BLOCK =
|
|
265
|
+
"<system_reminder>\nThis message was sent by a UI shortcut while the user explored the interface, not typed by hand. Reply in a few sentences at most and end with one concrete, specific next step or question — do not enumerate capabilities or give a tour.\n</system_reminder>";
|
|
266
|
+
|
|
259
267
|
export async function runAgentLoopImpl(
|
|
260
268
|
ctx: Conversation,
|
|
261
269
|
content: string,
|
|
@@ -272,6 +280,15 @@ export async function runAgentLoopImpl(
|
|
|
272
280
|
* the turn.
|
|
273
281
|
*/
|
|
274
282
|
isHiddenPrompt?: boolean;
|
|
283
|
+
/**
|
|
284
|
+
* How the triggering message was initiated when it was sent on the
|
|
285
|
+
* user's behalf by the UI rather than typed by hand (`body.source` on
|
|
286
|
+
* `POST /v1/messages`, persisted as `metadata.userMessageSource`).
|
|
287
|
+
* Current value: `"nav_redirect"`, which steers the turn toward a
|
|
288
|
+
* brief, concrete reply. Forwarded onto the user-prompt-submit hook
|
|
289
|
+
* context. Unset for hand-typed messages.
|
|
290
|
+
*/
|
|
291
|
+
messageSource?: string;
|
|
275
292
|
/**
|
|
276
293
|
* LLM call-site identifier threaded into the per-call provider config.
|
|
277
294
|
* Adapter callers (heartbeat, filing, scheduler, etc.) pass their own
|
|
@@ -367,7 +384,7 @@ export async function runAgentLoopImpl(
|
|
|
367
384
|
// contexts (heartbeat, filing, analyze, etc.) pass their own `callSite`. The
|
|
368
385
|
// provider layer resolves provider/model/maxTokens via `resolveCallSiteConfig`,
|
|
369
386
|
// picking up any user overrides under `llm.callSites.<id>` (falling back to
|
|
370
|
-
//
|
|
387
|
+
// the shipped call-site defaults when absent). `resolveTurnCallSite` keeps subagent
|
|
371
388
|
// conversations on `subagentSpawn` when no call site is supplied.
|
|
372
389
|
const turnCallSite = resolveTurnCallSite(options?.callSite, ctx);
|
|
373
390
|
// Expose the turn's call site on the live conversation so the runtime
|
|
@@ -931,21 +948,16 @@ export async function runAgentLoopImpl(
|
|
|
931
948
|
// `modelProfileKey` is the actual profile used for this turn. The
|
|
932
949
|
// notice key is narrower: it only marks turns where runtime context should
|
|
933
950
|
// remind the model that the profile changed.
|
|
934
|
-
//
|
|
935
|
-
//
|
|
936
|
-
//
|
|
937
|
-
// non-mainAgent turn).
|
|
951
|
+
// The reported key must come from the same winner selection dispatch used —
|
|
952
|
+
// a hand-rolled chain would credit profiles the resolver never consulted
|
|
953
|
+
// (e.g. activeProfile on a non-mainAgent turn).
|
|
938
954
|
const effectiveProfileKey =
|
|
939
|
-
(
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
}).profileName
|
|
946
|
-
: (turnOverrideProfile ??
|
|
947
|
-
config.llm.activeProfile ??
|
|
948
|
-
resolveDefaultProfileKey("mainAgent", config.llm))) ??
|
|
955
|
+
selectWinningProfile(turnCallSite, config.llm, {
|
|
956
|
+
...(turnOverrideProfile != null
|
|
957
|
+
? { overrideProfile: turnOverrideProfile }
|
|
958
|
+
: {}),
|
|
959
|
+
selectionSeed: ctx.conversationId,
|
|
960
|
+
}).profileName ??
|
|
949
961
|
resolveProfilelessModelKey(turnCallSite, config.llm, {
|
|
950
962
|
...(turnOverrideProfile != null
|
|
951
963
|
? { overrideProfile: turnOverrideProfile }
|
|
@@ -988,6 +1000,9 @@ export async function runAgentLoopImpl(
|
|
|
988
1000
|
requestId: reqId,
|
|
989
1001
|
prompt: options?.titleText ?? content,
|
|
990
1002
|
isHiddenPrompt: options?.isHiddenPrompt === true,
|
|
1003
|
+
...(options?.messageSource
|
|
1004
|
+
? { messageSource: options.messageSource }
|
|
1005
|
+
: {}),
|
|
991
1006
|
originalMessages: Object.freeze([...ctx.messages]),
|
|
992
1007
|
latestMessages: ctx.messages,
|
|
993
1008
|
modelProfileKey,
|
|
@@ -999,7 +1014,29 @@ export async function runAgentLoopImpl(
|
|
|
999
1014
|
userPromptCtx,
|
|
1000
1015
|
);
|
|
1001
1016
|
latencyTracker.mark("prompt_hook_end");
|
|
1002
|
-
|
|
1017
|
+
let runMessages = finalUserPromptCtx.latestMessages;
|
|
1018
|
+
|
|
1019
|
+
// UI-shortcut steering: appended after the hook chain so it lands below
|
|
1020
|
+
// the assembled runtime injections on the tail user message, mirroring
|
|
1021
|
+
// the non-interactive block's placement in `applyRuntimeInjections`.
|
|
1022
|
+
// Turn-scoped nudge, deliberately not persisted for byte-exact reload
|
|
1023
|
+
// rehydration — losing it on reload costs one prefix-cache anchor, not
|
|
1024
|
+
// context correctness.
|
|
1025
|
+
if (options?.messageSource === "nav_redirect") {
|
|
1026
|
+
const userTail = runMessages[runMessages.length - 1];
|
|
1027
|
+
if (userTail && userTail.role === "user") {
|
|
1028
|
+
runMessages = [
|
|
1029
|
+
...runMessages.slice(0, -1),
|
|
1030
|
+
{
|
|
1031
|
+
...userTail,
|
|
1032
|
+
content: [
|
|
1033
|
+
...userTail.content,
|
|
1034
|
+
{ type: "text" as const, text: NAV_REDIRECT_STEERING_BLOCK },
|
|
1035
|
+
],
|
|
1036
|
+
},
|
|
1037
|
+
];
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1003
1040
|
|
|
1004
1041
|
// Reset the manager's turn-scoped overflow-recovery ladder at the turn
|
|
1005
1042
|
// boundary so a new turn starts the ladder fresh from the emergency rung.
|
|
@@ -1590,6 +1627,21 @@ export async function runAgentLoopImpl(
|
|
|
1590
1627
|
publishLoopMessagesChanged();
|
|
1591
1628
|
}
|
|
1592
1629
|
} finally {
|
|
1630
|
+
// Clear the processing flag first. It is the release that frees the
|
|
1631
|
+
// conversation for its next turn, so nothing that can throw (the
|
|
1632
|
+
// turn-boundary commit, profiling) is allowed to run ahead of it and leave
|
|
1633
|
+
// the row latched "mid-turn". Stamp the turn's abnormal outcome first
|
|
1634
|
+
// because the telemetry reporter's settled-turn barrier only releases this
|
|
1635
|
+
// turn once processing stops; null `abortController` first so a concurrent
|
|
1636
|
+
// abort takes the force-clear branch rather than signalling a dead one.
|
|
1637
|
+
if (abnormalOutcome) {
|
|
1638
|
+
stampTurnOutcome(userMessageId, abnormalOutcome.outcome, {
|
|
1639
|
+
failureCode: abnormalOutcome.failureCode,
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
ctx.abortController = null;
|
|
1643
|
+
ctx.setProcessing(false);
|
|
1644
|
+
|
|
1593
1645
|
if (turnStarted) {
|
|
1594
1646
|
ctx.turnCount++;
|
|
1595
1647
|
const config = getConfig();
|
|
@@ -1625,24 +1677,12 @@ export async function runAgentLoopImpl(
|
|
|
1625
1677
|
|
|
1626
1678
|
emitToolProfilingSummary(ctx.conversationId, reqId);
|
|
1627
1679
|
|
|
1628
|
-
// Tear down
|
|
1680
|
+
// Tear down the remaining per-turn state. Abort reliably drives the loop to
|
|
1629
1681
|
// this `finally` within a bounded time — cooperative signal propagation
|
|
1630
1682
|
// (provider fetch + tool race) backed by the abort watchdog — so a
|
|
1631
1683
|
// cancelled turn always unwinds before any resend can start a new one.
|
|
1632
1684
|
// There is therefore only ever one turn alive, and clearing the shared
|
|
1633
1685
|
// state below cannot clobber a concurrent turn.
|
|
1634
|
-
// Stamp the turn's abnormal outcome (failed / cancelled) onto its
|
|
1635
|
-
// user-message row BEFORE processing clears: the telemetry reporter's
|
|
1636
|
-
// settled-turn barrier only releases this turn once the conversation
|
|
1637
|
-
// stops processing, so ordering the stamp first guarantees the turn
|
|
1638
|
-
// event ships with the outcome. A normally-replied turn stamps nothing.
|
|
1639
|
-
if (abnormalOutcome) {
|
|
1640
|
-
stampTurnOutcome(userMessageId, abnormalOutcome.outcome, {
|
|
1641
|
-
failureCode: abnormalOutcome.failureCode,
|
|
1642
|
-
});
|
|
1643
|
-
}
|
|
1644
|
-
ctx.abortController = null;
|
|
1645
|
-
ctx.setProcessing(false);
|
|
1646
1686
|
ctx.onConfirmationOutcome = undefined;
|
|
1647
1687
|
ctx.surfaceActionRequestIds.delete(ctx.currentRequestId ?? "");
|
|
1648
1688
|
ctx.approvedViaPromptThisTurn = false;
|
|
@@ -198,13 +198,21 @@ export interface ErrorContext {
|
|
|
198
198
|
* recognized as cancellation too.
|
|
199
199
|
*/
|
|
200
200
|
export function isUserCancellation(error: unknown, ctx: ErrorContext): boolean {
|
|
201
|
-
if (!ctx.aborted)
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
if (!ctx.aborted) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
204
210
|
if (error instanceof ProviderError && isAbortReason(error.abortReason)) {
|
|
205
211
|
return true;
|
|
206
212
|
}
|
|
207
|
-
if (isAbortReason(error))
|
|
213
|
+
if (isAbortReason(error)) {
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
208
216
|
return false;
|
|
209
217
|
}
|
|
210
218
|
|
|
@@ -215,7 +223,9 @@ const MAX_DEBUG_DETAIL_LENGTH = 4000;
|
|
|
215
223
|
* Truncate debug details to a reasonable size for transport.
|
|
216
224
|
*/
|
|
217
225
|
function truncateDebugDetails(details: string): string {
|
|
218
|
-
if (details.length <= MAX_DEBUG_DETAIL_LENGTH)
|
|
226
|
+
if (details.length <= MAX_DEBUG_DETAIL_LENGTH) {
|
|
227
|
+
return details;
|
|
228
|
+
}
|
|
219
229
|
return details.slice(0, MAX_DEBUG_DETAIL_LENGTH) + "\n… (truncated)";
|
|
220
230
|
}
|
|
221
231
|
|
|
@@ -287,7 +297,7 @@ export function classifyConversationError(
|
|
|
287
297
|
}
|
|
288
298
|
|
|
289
299
|
/**
|
|
290
|
-
* Internal throw sites use sentinel pseudo-names (`<
|
|
300
|
+
* Internal throw sites use sentinel pseudo-names (`<default>`,
|
|
291
301
|
* `<resolved-callsite>`) when no real connection row is involved; those must
|
|
292
302
|
* not render as literal connection names.
|
|
293
303
|
*/
|
|
@@ -351,7 +361,9 @@ function classifyCore(
|
|
|
351
361
|
attribution,
|
|
352
362
|
message,
|
|
353
363
|
});
|
|
354
|
-
if (c)
|
|
364
|
+
if (c) {
|
|
365
|
+
return c;
|
|
366
|
+
}
|
|
355
367
|
}
|
|
356
368
|
|
|
357
369
|
// Reason-less (or bad_request/unknown) ProviderError with a status — the
|
|
@@ -493,9 +505,13 @@ function extractProviderDetail(message: string): string | undefined {
|
|
|
493
505
|
detail = detail.replace(/\s*\[[^\]]*\]\s*$/, "").trim();
|
|
494
506
|
if (!detail || detail === message.trim()) {
|
|
495
507
|
// No recognizable prefix — only surface prose that isn't the whole raw line.
|
|
496
|
-
if (/API error \(\d+\)/i.test(message))
|
|
508
|
+
if (/API error \(\d+\)/i.test(message)) {
|
|
509
|
+
return undefined;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (!detail) {
|
|
513
|
+
return undefined;
|
|
497
514
|
}
|
|
498
|
-
if (!detail) return undefined;
|
|
499
515
|
return detail.length > 200 ? `${detail.slice(0, 200)}…` : detail;
|
|
500
516
|
}
|
|
501
517
|
|
|
@@ -768,19 +784,25 @@ function visionNotSupportedClassification(): Omit<
|
|
|
768
784
|
* Build a user-facing message that names the exact profile / connection
|
|
769
785
|
* to fix when one is known, falling back to a generic phrase otherwise.
|
|
770
786
|
* Profile is preferred because that's the entity the user picks in the
|
|
771
|
-
* chat picker; connection is shown when no profile is in play (e.g.
|
|
772
|
-
*
|
|
787
|
+
* chat picker; connection is shown when no profile is in play (e.g. the
|
|
788
|
+
* profileless anchor dispatch) or as a parenthetical when both differ.
|
|
773
789
|
*/
|
|
774
790
|
function describeAttribution(
|
|
775
791
|
attribution: ConversationErrorAttribution | undefined,
|
|
776
792
|
): string {
|
|
777
|
-
if (!attribution)
|
|
793
|
+
if (!attribution) {
|
|
794
|
+
return "";
|
|
795
|
+
}
|
|
778
796
|
const { profileName, connectionName } = attribution;
|
|
779
797
|
if (profileName && connectionName && profileName !== connectionName) {
|
|
780
798
|
return ` for profile "${profileName}" (connection "${connectionName}")`;
|
|
781
799
|
}
|
|
782
|
-
if (profileName)
|
|
783
|
-
|
|
800
|
+
if (profileName) {
|
|
801
|
+
return ` for profile "${profileName}"`;
|
|
802
|
+
}
|
|
803
|
+
if (connectionName) {
|
|
804
|
+
return ` for connection "${connectionName}"`;
|
|
805
|
+
}
|
|
784
806
|
return "";
|
|
785
807
|
}
|
|
786
808
|
|
|
@@ -23,6 +23,7 @@ import { extractPreferences } from "../notifications/preference-extractor.js";
|
|
|
23
23
|
import { createPreference } from "../notifications/preferences-store.js";
|
|
24
24
|
import {
|
|
25
25
|
addMessage,
|
|
26
|
+
getUserMessageSourceMetadata,
|
|
26
27
|
isHiddenMessageMetadata,
|
|
27
28
|
provenanceFromTrustContext,
|
|
28
29
|
recordConversationPersistedSeq,
|
|
@@ -1049,6 +1050,7 @@ async function drainSingleMessage(
|
|
|
1049
1050
|
isUserMessage?: boolean;
|
|
1050
1051
|
titleText?: string;
|
|
1051
1052
|
isHiddenPrompt?: boolean;
|
|
1053
|
+
messageSource?: string;
|
|
1052
1054
|
} = { isUserMessage: true };
|
|
1053
1055
|
if (next.isInteractive !== undefined) {
|
|
1054
1056
|
drainLoopOptions.isInteractive = next.isInteractive;
|
|
@@ -1059,6 +1061,10 @@ async function drainSingleMessage(
|
|
|
1059
1061
|
if (isHiddenMessageMetadata(next.metadata)) {
|
|
1060
1062
|
drainLoopOptions.isHiddenPrompt = true;
|
|
1061
1063
|
}
|
|
1064
|
+
const queuedMessageSource = getUserMessageSourceMetadata(next.metadata);
|
|
1065
|
+
if (queuedMessageSource !== undefined) {
|
|
1066
|
+
drainLoopOptions.messageSource = queuedMessageSource;
|
|
1067
|
+
}
|
|
1062
1068
|
|
|
1063
1069
|
conversation
|
|
1064
1070
|
.runAgentLoop(agentLoopContent, userMessageId, {
|
|
@@ -1500,6 +1506,7 @@ async function drainBatch(
|
|
|
1500
1506
|
isUserMessage?: boolean;
|
|
1501
1507
|
titleText?: string;
|
|
1502
1508
|
isHiddenPrompt?: boolean;
|
|
1509
|
+
messageSource?: string;
|
|
1503
1510
|
} = { isUserMessage: true };
|
|
1504
1511
|
// Source interactive flag from the last successfully-persisted sibling so
|
|
1505
1512
|
// a trailing failed tail doesn't flip the agent loop's interactivity.
|
|
@@ -1519,6 +1526,21 @@ async function drainBatch(
|
|
|
1519
1526
|
) {
|
|
1520
1527
|
drainLoopOptions.isHiddenPrompt = true;
|
|
1521
1528
|
}
|
|
1529
|
+
// Same all-or-nothing rule for the send-source steering: a batch counts
|
|
1530
|
+
// as UI-initiated only when every message in it carries the same source
|
|
1531
|
+
// tag — one hand-typed message justifies a full answer.
|
|
1532
|
+
const batchMessageSource =
|
|
1533
|
+
successfulBatch.length > 0
|
|
1534
|
+
? getUserMessageSourceMetadata(successfulBatch[0].metadata)
|
|
1535
|
+
: undefined;
|
|
1536
|
+
if (
|
|
1537
|
+
batchMessageSource !== undefined &&
|
|
1538
|
+
successfulBatch.every(
|
|
1539
|
+
(qm) => getUserMessageSourceMetadata(qm.metadata) === batchMessageSource,
|
|
1540
|
+
)
|
|
1541
|
+
) {
|
|
1542
|
+
drainLoopOptions.messageSource = batchMessageSource;
|
|
1543
|
+
}
|
|
1522
1544
|
|
|
1523
1545
|
// Fire-and-forget: runAgentLoop's finally block recursively calls drainQueue
|
|
1524
1546
|
// when this run completes. Mirrors drainSingleMessage.
|
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { getConfig } from "../config/loader.js";
|
|
16
|
+
import {
|
|
17
|
+
ADOPTABLE_CONVERSATION_ID_RE,
|
|
18
|
+
createConversation,
|
|
19
|
+
ensureConversationExists,
|
|
20
|
+
getConversation,
|
|
21
|
+
} from "../persistence/conversation-crud.js";
|
|
16
22
|
import { wrapWithCallSiteRouting } from "../providers/call-site-routing.js";
|
|
17
23
|
import {
|
|
18
24
|
mainAgentResolutionError,
|
|
@@ -157,6 +163,35 @@ export async function getOrCreateConversation(
|
|
|
157
163
|
},
|
|
158
164
|
);
|
|
159
165
|
newConversation.updateClient(sendToClient, true);
|
|
166
|
+
|
|
167
|
+
// Ensure the conversations row exists before hydrating from DB.
|
|
168
|
+
// `getOrCreateConversation` builds the in-memory Conversation, but
|
|
169
|
+
// the persisted row is what `loadFromDb` reads for conversationType,
|
|
170
|
+
// source, and other metadata. If the row doesn't exist yet (brand-new
|
|
171
|
+
// conversation), create it now so hydration caches the right fields.
|
|
172
|
+
//
|
|
173
|
+
// When `conversationType` is provided (e.g. "background" for
|
|
174
|
+
// plugin-driven conversations), create the row with that type so it
|
|
175
|
+
// is hidden from the sidebar. The ID is validated against the same
|
|
176
|
+
// pattern as `ensureConversationExists` to prevent path traversal.
|
|
177
|
+
// Otherwise use `ensureConversationExists` directly, which validates
|
|
178
|
+
// and creates a standard row.
|
|
179
|
+
if (!getConversation(conversationId)) {
|
|
180
|
+
if (storedOptions?.conversationType) {
|
|
181
|
+
if (!ADOPTABLE_CONVERSATION_ID_RE.test(conversationId)) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`Refusing to adopt unsafe conversation id: ${JSON.stringify(conversationId)}`,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
createConversation({
|
|
187
|
+
id: conversationId,
|
|
188
|
+
conversationType: storedOptions.conversationType,
|
|
189
|
+
});
|
|
190
|
+
} else {
|
|
191
|
+
ensureConversationExists(conversationId);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
160
195
|
await newConversation.loadFromDb();
|
|
161
196
|
if (storedOptions?.assistantId) {
|
|
162
197
|
newConversation.setAssistantId(storedOptions.assistantId);
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
getApp,
|
|
12
12
|
getAppDirPath,
|
|
13
13
|
getAppPreview,
|
|
14
|
-
isMultifileApp,
|
|
15
14
|
listAppsByConversation,
|
|
16
15
|
resolveAppDir,
|
|
17
16
|
resolveEffectiveAppHtml,
|
|
@@ -1825,6 +1824,17 @@ function completeSurfaceFromAction(
|
|
|
1825
1824
|
markSurfaceCompleted(ctx, surfaceId, summary);
|
|
1826
1825
|
}
|
|
1827
1826
|
|
|
1827
|
+
// One-shot interactive surfaces auto-complete once their action message is
|
|
1828
|
+
// accepted (they never accept further actions).
|
|
1829
|
+
const ONE_SHOT_SURFACE_TYPES = [
|
|
1830
|
+
"choice",
|
|
1831
|
+
"oauth_connect",
|
|
1832
|
+
"form",
|
|
1833
|
+
"confirmation",
|
|
1834
|
+
"file_upload",
|
|
1835
|
+
"task_preferences",
|
|
1836
|
+
];
|
|
1837
|
+
|
|
1828
1838
|
export async function handleSurfaceAction(
|
|
1829
1839
|
ctx: SurfaceConversationContext,
|
|
1830
1840
|
surfaceId: string,
|
|
@@ -2395,14 +2405,6 @@ export async function handleSurfaceAction(
|
|
|
2395
2405
|
// One-shot interactive surfaces — auto-complete now that the message has
|
|
2396
2406
|
// been accepted. Deferred until after rejection check so the surface stays
|
|
2397
2407
|
// active and retryable if the queue was full.
|
|
2398
|
-
const ONE_SHOT_SURFACE_TYPES = [
|
|
2399
|
-
"choice",
|
|
2400
|
-
"oauth_connect",
|
|
2401
|
-
"form",
|
|
2402
|
-
"confirmation",
|
|
2403
|
-
"file_upload",
|
|
2404
|
-
"task_preferences",
|
|
2405
|
-
];
|
|
2406
2408
|
if (
|
|
2407
2409
|
requestedCompletionSummary ||
|
|
2408
2410
|
ONE_SHOT_SURFACE_TYPES.includes(pending.surfaceType)
|
|
@@ -3459,22 +3461,20 @@ export async function surfaceProxyResolver(
|
|
|
3459
3461
|
const storedPreview = getAppPreview(app.id);
|
|
3460
3462
|
const { dirName } = resolveAppDir(app.id);
|
|
3461
3463
|
|
|
3462
|
-
//
|
|
3463
|
-
//
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
);
|
|
3477
|
-
}
|
|
3464
|
+
// Auto-compile if dist is missing, then resolve HTML from compiled
|
|
3465
|
+
// dist/index.html with inlined assets.
|
|
3466
|
+
const { existsSync } = await import("node:fs");
|
|
3467
|
+
const { join } = await import("node:path");
|
|
3468
|
+
const appDir = getAppDirPath(app.id);
|
|
3469
|
+
const distIndex = join(appDir, "dist", "index.html");
|
|
3470
|
+
if (!existsSync(distIndex)) {
|
|
3471
|
+
const { compileApp } = await import("../bundler/app-compiler.js");
|
|
3472
|
+
const result = await compileApp(appDir);
|
|
3473
|
+
if (!result.ok) {
|
|
3474
|
+
log.warn(
|
|
3475
|
+
{ appId, errors: result.errors },
|
|
3476
|
+
"Auto-compile failed on app_open",
|
|
3477
|
+
);
|
|
3478
3478
|
}
|
|
3479
3479
|
}
|
|
3480
3480
|
const html = resolveEffectiveAppHtml(app);
|
|
@@ -16,6 +16,7 @@ import type { PermissionPrompter } from "../permissions/prompter.js";
|
|
|
16
16
|
import type { SecretPrompter } from "../permissions/secret-prompter.js";
|
|
17
17
|
import { getBindingByConversation } from "../persistence/external-conversation-store.js";
|
|
18
18
|
import { getAllDefaultPluginNames } from "../plugins/defaults/main.js";
|
|
19
|
+
import { isActivationSession } from "../plugins/defaults/memory/activation-session-store.js";
|
|
19
20
|
import { isPluginDisabled } from "../plugins/disabled-state.js";
|
|
20
21
|
import type { Message, ToolDefinition } from "../providers/types.js";
|
|
21
22
|
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
@@ -50,6 +51,10 @@ import {
|
|
|
50
51
|
type ToolContext,
|
|
51
52
|
type ToolExecutionResult,
|
|
52
53
|
} from "../tools/types.js";
|
|
54
|
+
import {
|
|
55
|
+
injectActivationMomentParam,
|
|
56
|
+
projectUiToolsForChannel,
|
|
57
|
+
} from "../tools/ui-surface/channel-variants.js";
|
|
53
58
|
import { loadWorkspaceTools } from "../tools/workspace-tools/loader.js";
|
|
54
59
|
import {
|
|
55
60
|
resolveUsageAttribution,
|
|
@@ -194,10 +199,16 @@ export function createToolExecutor(
|
|
|
194
199
|
const rejectNonAllowlistedTool = (
|
|
195
200
|
toolName: string,
|
|
196
201
|
): ToolExecutionResult | null => {
|
|
202
|
+
const allowlist = ctx.subagentAllowedTools;
|
|
203
|
+
// Record any attempt at a tool outside the subagent's role allowlist — in
|
|
204
|
+
// both wire and execution gate modes — so the parent can be told what the
|
|
205
|
+
// subagent needed but lacked. Pure observation; the gating is below.
|
|
206
|
+
if (allowlist !== undefined && !allowlist.has(toolName)) {
|
|
207
|
+
ctx.subagentDeniedToolNames?.add(toolName);
|
|
208
|
+
}
|
|
197
209
|
if (ctx.subagentToolGateMode !== "execution") {
|
|
198
210
|
return null;
|
|
199
211
|
}
|
|
200
|
-
const allowlist = ctx.subagentAllowedTools;
|
|
201
212
|
if (!allowlist || allowlist.has(toolName)) {
|
|
202
213
|
return null;
|
|
203
214
|
}
|
|
@@ -539,7 +550,7 @@ const CROSS_CLIENT_EXPOSED_CAPABILITIES = new Set<HostProxyCapability>([
|
|
|
539
550
|
"host_browser",
|
|
540
551
|
]);
|
|
541
552
|
// Tools that require a connected client but no specific host proxy capability.
|
|
542
|
-
const CLIENT_CAPABILITY_TOOL_NAMES = new Set(["
|
|
553
|
+
const CLIENT_CAPABILITY_TOOL_NAMES = new Set(["ask_question"]);
|
|
543
554
|
const PLATFORM_TOOL_NAMES = new Set(["request_system_permission"]);
|
|
544
555
|
|
|
545
556
|
/**
|
|
@@ -822,11 +833,26 @@ export function createResolveToolsCallback(
|
|
|
822
833
|
? currentWorkspaceDefs.filter((d) => wireAllowlist.has(d.name))
|
|
823
834
|
: currentWorkspaceDefs;
|
|
824
835
|
const excluded = new Set(getConfig().tools.exclude);
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
836
|
+
// Swap UI surface tools for channel-appropriate variants (e.g. Slack's
|
|
837
|
+
// task_progress-only ui_show). Mirrors the pin handling in
|
|
838
|
+
// `isToolActiveForContext`: execution-gate-mode wakes pin channel
|
|
839
|
+
// capabilities to undefined, which resolves to the unprojected defs.
|
|
840
|
+
const channelForUiTools = ctx.toolContextPin
|
|
841
|
+
? undefined
|
|
842
|
+
: ctx.channelCapabilities?.channel;
|
|
843
|
+
let allBaseDefs = projectUiToolsForChannel(
|
|
844
|
+
[...scopedCoreDefs, ...scopedWorkspaceDefs, ...scopedMcpDefs].filter(
|
|
845
|
+
(d) => !excluded.has(d.name),
|
|
846
|
+
),
|
|
847
|
+
channelForUiTools,
|
|
848
|
+
);
|
|
849
|
+
// Activation-rail conversations carry the optional `activation_moment`
|
|
850
|
+
// telemetry param on ui_show. The marker is written before the first
|
|
851
|
+
// tool resolution (see `applyBootstrapTemplate` in system-prompt.ts), so
|
|
852
|
+
// the projected schema is stable for the conversation's lifetime.
|
|
853
|
+
if (isActivationSession(ctx.conversationId)) {
|
|
854
|
+
allBaseDefs = injectActivationMomentParam(allBaseDefs);
|
|
855
|
+
}
|
|
830
856
|
|
|
831
857
|
const effectivePreactivated = [
|
|
832
858
|
...DEFAULT_PREACTIVATED_SKILL_IDS,
|
|
@@ -34,6 +34,10 @@ import {
|
|
|
34
34
|
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
35
35
|
import { getConfig } from "../config/loader.js";
|
|
36
36
|
import type { LLMCallSite, Speed } from "../config/schemas/llm.js";
|
|
37
|
+
import {
|
|
38
|
+
derefToolResultReReads,
|
|
39
|
+
postTurnTruncateToolResults,
|
|
40
|
+
} from "../context/post-turn-tool-result-truncation.js";
|
|
37
41
|
import { PermissionPrompter } from "../permissions/prompter.js";
|
|
38
42
|
import { SecretPrompter } from "../permissions/secret-prompter.js";
|
|
39
43
|
import type { UserDecision } from "../permissions/types.js";
|
|
@@ -315,6 +319,14 @@ export class Conversation {
|
|
|
315
319
|
/** @internal */ toolsDisabledDepth = 0;
|
|
316
320
|
/** @internal */ preactivatedSkillIds?: string[];
|
|
317
321
|
/** @internal */ subagentAllowedTools?: Set<string>;
|
|
322
|
+
/**
|
|
323
|
+
* Tool names a subagent attempted but that its role allowlist
|
|
324
|
+
* ({@link subagentAllowedTools}) denied. Recorded by the tool executor;
|
|
325
|
+
* surfaced to the parent in the terminal notification so it can re-spawn with
|
|
326
|
+
* a role that includes them. Ephemeral, never persisted.
|
|
327
|
+
* @internal
|
|
328
|
+
*/
|
|
329
|
+
subagentDeniedToolNames = new Set<string>();
|
|
318
330
|
/**
|
|
319
331
|
* How {@link subagentAllowedTools} is enforced — see
|
|
320
332
|
* {@link SubagentToolGateMode}. Set and restored alongside the allowlist
|
|
@@ -1258,7 +1270,38 @@ export class Conversation {
|
|
|
1258
1270
|
"Repaired persisted history",
|
|
1259
1271
|
);
|
|
1260
1272
|
}
|
|
1261
|
-
|
|
1273
|
+
|
|
1274
|
+
// Recreate the post-turn tool-result view on the reloaded history. Tools
|
|
1275
|
+
// exempt from the result-time spool (file_read/host_file_read, web_fetch)
|
|
1276
|
+
// persist their full oversized content, while the pre-eviction in-memory
|
|
1277
|
+
// history carried the post-turn stubs — so a reload would otherwise feed
|
|
1278
|
+
// the provider the full content those turns already consumed. Re-running
|
|
1279
|
+
// the deterministic finalize passes (deref, then truncate — same order)
|
|
1280
|
+
// restores that byte-identical view (same stub bytes, same
|
|
1281
|
+
// `.tool-results/` paths), keeping the provider prefix cache matching and
|
|
1282
|
+
// the rebuilt context as lean as it was before eviction/restart.
|
|
1283
|
+
// Best-effort like the finalize pass: a failure degrades to full-content
|
|
1284
|
+
// history, never a failed load.
|
|
1285
|
+
let messagesForHistory = repairedMessages;
|
|
1286
|
+
if (conv) {
|
|
1287
|
+
try {
|
|
1288
|
+
messagesForHistory = postTurnTruncateToolResults(
|
|
1289
|
+
derefToolResultReReads(repairedMessages).messages,
|
|
1290
|
+
{
|
|
1291
|
+
conversationDir: getResolvedConversationDirPath(
|
|
1292
|
+
this.conversationId,
|
|
1293
|
+
conv.createdAt,
|
|
1294
|
+
),
|
|
1295
|
+
},
|
|
1296
|
+
).messages;
|
|
1297
|
+
} catch (err) {
|
|
1298
|
+
log.warn(
|
|
1299
|
+
{ conversationId: this.conversationId, err },
|
|
1300
|
+
"Load-time tool result truncation failed (non-fatal)",
|
|
1301
|
+
);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
this.messages = messagesForHistory;
|
|
1262
1305
|
|
|
1263
1306
|
if (contextSummaryForHistory) {
|
|
1264
1307
|
this.messages.unshift(
|
|
@@ -1465,10 +1508,10 @@ export class Conversation {
|
|
|
1465
1508
|
* Mutate the server-authoritative `processing` flag. Web/Capacitor/CLI
|
|
1466
1509
|
* caches treat this flag as the source of truth for the avatar streaming
|
|
1467
1510
|
* ring and thinking indicator, so the `true → false` clear must announce
|
|
1468
|
-
* itself: the daemon flips it in the agent-loop `finally
|
|
1469
|
-
*
|
|
1470
|
-
*
|
|
1471
|
-
*
|
|
1511
|
+
* itself: the daemon flips it in the agent-loop `finally`, which runs after
|
|
1512
|
+
* the user-visible terminal SSE events, and a racing metadata refetch can
|
|
1513
|
+
* otherwise re-read the not-yet-cleared `true` and clobber the client's
|
|
1514
|
+
* optimistic `false`.
|
|
1472
1515
|
*
|
|
1473
1516
|
* Emitting a metadata invalidation on the clear lets every client GET the
|
|
1474
1517
|
* authoritative `false`, per the multi-client-sync contract in AGENTS.md
|
|
@@ -1976,6 +2019,7 @@ export class Conversation {
|
|
|
1976
2019
|
}
|
|
1977
2020
|
return await this.runCompaction(true, undefined, {
|
|
1978
2021
|
fixedTailStartIndex: tailIndex,
|
|
2022
|
+
fixedBoundaryRowIndex: boundaryRowIndex,
|
|
1979
2023
|
// Slack projections gate on the persisted watermark, not on
|
|
1980
2024
|
// `contextCompactedMessageCount` — without an advance, the summarized
|
|
1981
2025
|
// rows would reappear verbatim in the projection alongside the new
|
|
@@ -2027,6 +2071,8 @@ export class Conversation {
|
|
|
2027
2071
|
* `/compact`); without it the manager no-ops below the threshold.
|
|
2028
2072
|
* `opts.fixedTailStartIndex` pins the kept tail to a caller-chosen history
|
|
2029
2073
|
* index ("summarize up to here") instead of the token-budget cut;
|
|
2074
|
+
* `opts.fixedBoundaryRowIndex` is the same boundary in row space, which
|
|
2075
|
+
* bounds the compactor's image manifest to rows being summarized away;
|
|
2030
2076
|
* `opts.fixedBoundarySlackWatermarkTs` is that path's row-space-derived
|
|
2031
2077
|
* Slack watermark (the auto/forced Slack path derives its own from the
|
|
2032
2078
|
* chronological projection).
|
|
@@ -2036,6 +2082,7 @@ export class Conversation {
|
|
|
2036
2082
|
sizing?: CompactionSizing,
|
|
2037
2083
|
opts?: {
|
|
2038
2084
|
fixedTailStartIndex?: number;
|
|
2085
|
+
fixedBoundaryRowIndex?: number;
|
|
2039
2086
|
fixedBoundarySlackWatermarkTs?: string | null;
|
|
2040
2087
|
},
|
|
2041
2088
|
): Promise<ContextWindowResult> {
|
|
@@ -2097,6 +2144,7 @@ export class Conversation {
|
|
|
2097
2144
|
overrideProfile,
|
|
2098
2145
|
actorTrustClass: this.trustContext?.trustClass,
|
|
2099
2146
|
fixedTailStartIndex: opts?.fixedTailStartIndex,
|
|
2147
|
+
fixedBoundaryRowIndex: opts?.fixedBoundaryRowIndex,
|
|
2100
2148
|
});
|
|
2101
2149
|
// Track circuit-breaker state for every compaction that ran a summary
|
|
2102
2150
|
// call — user-initiated `/compact`, other forced paths, and the wake's
|
|
@@ -2316,6 +2364,8 @@ export class Conversation {
|
|
|
2316
2364
|
titleText?: string;
|
|
2317
2365
|
/** See {@link runAgentLoopImpl} — hidden machine-signal turn marker. */
|
|
2318
2366
|
isHiddenPrompt?: boolean;
|
|
2367
|
+
/** See {@link runAgentLoopImpl} — UI-initiated send-source tag. */
|
|
2368
|
+
messageSource?: string;
|
|
2319
2369
|
callSite?: LLMCallSite;
|
|
2320
2370
|
/**
|
|
2321
2371
|
* Optional ad-hoc inference-profile override applied to every LLM call
|