@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
package/src/usage/attribution.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { getEffectiveProfiles } from "../config/default-profile-catalog.js";
|
|
2
1
|
import {
|
|
3
|
-
isOverrideOrDefaultResolutionEnabled,
|
|
4
2
|
resolveCallSiteConfig,
|
|
5
3
|
selectWinningProfile,
|
|
6
4
|
} from "../config/llm-resolver.js";
|
|
@@ -87,11 +85,17 @@ export function toAttributionColumns(
|
|
|
87
85
|
* values are capped so later forwarding cannot create unbounded headers.
|
|
88
86
|
*/
|
|
89
87
|
export function sanitizeUsageMetadataValue(value: unknown): string | null {
|
|
90
|
-
if (typeof value !== "string")
|
|
88
|
+
if (typeof value !== "string") {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
91
|
|
|
92
92
|
const trimmed = value.trim();
|
|
93
|
-
if (trimmed.length === 0)
|
|
94
|
-
|
|
93
|
+
if (trimmed.length === 0) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
if (containsControlCharacter(trimmed)) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
95
99
|
|
|
96
100
|
return safeStringSlice(trimmed, 0, MAX_METADATA_VALUE_LENGTH);
|
|
97
101
|
}
|
|
@@ -140,19 +144,15 @@ export function resolveUsageAttribution(
|
|
|
140
144
|
const callSiteProfile = normalizeProfileId(
|
|
141
145
|
llm.callSites?.[callSite]?.profile,
|
|
142
146
|
);
|
|
143
|
-
//
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
const profile =
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
overrideProfile,
|
|
153
|
-
forceOverrideProfile: input.forceOverrideProfile === true,
|
|
154
|
-
callSiteProfile,
|
|
155
|
-
});
|
|
147
|
+
// The resolver's own winner selection is the single source of truth for which
|
|
148
|
+
// profile applied — attribution must never re-derive precedence and drift
|
|
149
|
+
// from dispatch.
|
|
150
|
+
const profile = appliedProfileFromWinnerSelection(
|
|
151
|
+
callSite,
|
|
152
|
+
llm,
|
|
153
|
+
overrideProfile,
|
|
154
|
+
input,
|
|
155
|
+
);
|
|
156
156
|
|
|
157
157
|
return {
|
|
158
158
|
callSite,
|
|
@@ -194,100 +194,6 @@ function appliedProfileFromWinnerSelection(
|
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
function resolveAppliedProfile(input: {
|
|
198
|
-
callSite: LLMCallSite;
|
|
199
|
-
profiles: Record<string, unknown>;
|
|
200
|
-
activeProfile: string | null;
|
|
201
|
-
overrideProfile: string | null;
|
|
202
|
-
forceOverrideProfile: boolean;
|
|
203
|
-
callSiteProfile: string | null;
|
|
204
|
-
}): Pick<UsageAttributionSnapshot, "appliedProfile" | "profileSource"> {
|
|
205
|
-
if (input.callSite === "mainAgent") {
|
|
206
|
-
if (
|
|
207
|
-
input.overrideProfile != null &&
|
|
208
|
-
input.profiles[input.overrideProfile] != null
|
|
209
|
-
) {
|
|
210
|
-
return {
|
|
211
|
-
appliedProfile: input.overrideProfile,
|
|
212
|
-
profileSource: "conversation",
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (
|
|
217
|
-
input.activeProfile != null &&
|
|
218
|
-
input.profiles[input.activeProfile] != null
|
|
219
|
-
) {
|
|
220
|
-
return {
|
|
221
|
-
appliedProfile: input.activeProfile,
|
|
222
|
-
profileSource: "active",
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (
|
|
227
|
-
input.callSiteProfile != null &&
|
|
228
|
-
input.profiles[input.callSiteProfile] != null
|
|
229
|
-
) {
|
|
230
|
-
return {
|
|
231
|
-
appliedProfile: input.callSiteProfile,
|
|
232
|
-
profileSource: "call_site",
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return {
|
|
237
|
-
appliedProfile: null,
|
|
238
|
-
profileSource: "default",
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Forced override floats above the call-site profile (the resolver's
|
|
243
|
-
// `forceOverrideProfile` escape hatch), so it wins attribution too.
|
|
244
|
-
if (
|
|
245
|
-
input.forceOverrideProfile &&
|
|
246
|
-
input.overrideProfile != null &&
|
|
247
|
-
input.profiles[input.overrideProfile] != null
|
|
248
|
-
) {
|
|
249
|
-
return {
|
|
250
|
-
appliedProfile: input.overrideProfile,
|
|
251
|
-
profileSource: "conversation",
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (
|
|
256
|
-
input.callSiteProfile != null &&
|
|
257
|
-
input.profiles[input.callSiteProfile] != null
|
|
258
|
-
) {
|
|
259
|
-
return {
|
|
260
|
-
appliedProfile: input.callSiteProfile,
|
|
261
|
-
profileSource: "call_site",
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if (
|
|
266
|
-
input.overrideProfile != null &&
|
|
267
|
-
input.profiles[input.overrideProfile] != null
|
|
268
|
-
) {
|
|
269
|
-
return {
|
|
270
|
-
appliedProfile: input.overrideProfile,
|
|
271
|
-
profileSource: "conversation",
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
if (
|
|
276
|
-
input.activeProfile != null &&
|
|
277
|
-
input.profiles[input.activeProfile] != null
|
|
278
|
-
) {
|
|
279
|
-
return {
|
|
280
|
-
appliedProfile: input.activeProfile,
|
|
281
|
-
profileSource: "active",
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return {
|
|
286
|
-
appliedProfile: null,
|
|
287
|
-
profileSource: "default",
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
|
|
291
197
|
function normalizeProfileId(value: string | null | undefined): string | null {
|
|
292
198
|
return value ?? null;
|
|
293
199
|
}
|
package/src/{config/bundled-skills/messaging/tools/gmail-mime-helpers.ts → util/mime-type.ts}
RENAMED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Best-effort MIME type inference from a file path's extension.
|
|
3
|
+
*
|
|
4
|
+
* Used to label outbound attachments (Gmail/Outlook multipart parts, native
|
|
5
|
+
* email attachments) when the source is a local file with no declared type.
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
8
|
import { extname } from "node:path";
|
|
@@ -14,8 +14,14 @@ export const VISION_NOT_SUPPORTED_PATTERNS = [
|
|
|
14
14
|
/multi-?modal.*not.*support/i,
|
|
15
15
|
];
|
|
16
16
|
|
|
17
|
-
// Vendor-neutral (OpenRouter/Anthropic-style) credit-exhaustion prose.
|
|
17
|
+
// Vendor-neutral (OpenRouter/Anthropic-style) credit-exhaustion prose. Also
|
|
18
|
+
// covers per-key spend caps: OpenRouter returns 403 "Key limit exceeded" when a
|
|
19
|
+
// key's configured credit limit is reached — a billing/budget condition that
|
|
20
|
+
// routes to the billing classification alongside other credit exhaustion. The
|
|
21
|
+
// phrase is anchored on the contiguous "key limit" so it cannot swallow
|
|
22
|
+
// rate-limit prose ("rate limit exceeded") or generic invalid-key text.
|
|
18
23
|
export const INSUFFICIENT_CREDITS_PATTERNS = [
|
|
19
24
|
/credit balance is too low/i,
|
|
20
25
|
/insufficient.*credits?/i,
|
|
26
|
+
/key limit (?:has been )?(?:exceeded|reached)/i,
|
|
21
27
|
];
|
|
@@ -273,3 +273,108 @@ export function stopWorkerProcess(pidPath: string): WorkerProcessStatus {
|
|
|
273
273
|
}
|
|
274
274
|
return current;
|
|
275
275
|
}
|
|
276
|
+
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
278
|
+
// Liveness supervisor
|
|
279
|
+
// ---------------------------------------------------------------------------
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* A liveness supervisor that probes a worker process and respawns it when it
|
|
283
|
+
* has died, subject to exponential backoff and a suppression hook. Detects
|
|
284
|
+
* process *death* (via the PID-file probe) — not a worker that is alive but
|
|
285
|
+
* wedged.
|
|
286
|
+
*/
|
|
287
|
+
export interface WorkerSupervisor {
|
|
288
|
+
/** Probe liveness; respawn if dead (subject to backoff/suppression). Never throws. */
|
|
289
|
+
ensureAlive(now?: number): Promise<void>;
|
|
290
|
+
/**
|
|
291
|
+
* Stop supervising: no further respawns, and a respawn already in flight is
|
|
292
|
+
* killed via {@link WorkerSupervisorOptions.killChild} when it resolves.
|
|
293
|
+
*/
|
|
294
|
+
dispose(): void;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export interface WorkerSupervisorOptions {
|
|
298
|
+
label: string;
|
|
299
|
+
probe: () => WorkerProcessStatus;
|
|
300
|
+
respawn: () => Promise<{ pid: number; alreadyRunning: boolean }>;
|
|
301
|
+
/**
|
|
302
|
+
* Kill a child respawned after {@link WorkerSupervisor.dispose} was called
|
|
303
|
+
* (closes the shutdown race where a respawn was already in flight).
|
|
304
|
+
*/
|
|
305
|
+
killChild?: (pid: number) => void;
|
|
306
|
+
/**
|
|
307
|
+
* When it returns true, `ensureAlive` skips respawning — e.g. an operator
|
|
308
|
+
* administratively stopped the worker and the watchdog must not undo that.
|
|
309
|
+
*/
|
|
310
|
+
isSuppressed?: () => boolean;
|
|
311
|
+
/** Fired after a respawn actually started a new process (not `alreadyRunning`). */
|
|
312
|
+
onRespawn?: (pid: number) => void;
|
|
313
|
+
/** Fires once when consecutiveFailures first reaches the threshold. */
|
|
314
|
+
onPersistentFailure?: (consecutiveFailures: number, err: unknown) => void;
|
|
315
|
+
minBackoffMs?: number; // default 15_000 (one tick)
|
|
316
|
+
maxBackoffMs?: number; // default 300_000 (5 min)
|
|
317
|
+
persistentFailureThreshold?: number; // default 3
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export function createWorkerSupervisor(
|
|
321
|
+
opts: WorkerSupervisorOptions,
|
|
322
|
+
): WorkerSupervisor {
|
|
323
|
+
let consecutiveFailures = 0;
|
|
324
|
+
let nextAttemptAt = 0;
|
|
325
|
+
let inFlight = false;
|
|
326
|
+
let stopping = false;
|
|
327
|
+
const minBackoff = opts.minBackoffMs ?? 15_000;
|
|
328
|
+
const maxBackoff = opts.maxBackoffMs ?? 300_000;
|
|
329
|
+
const threshold = opts.persistentFailureThreshold ?? 3;
|
|
330
|
+
|
|
331
|
+
return {
|
|
332
|
+
async ensureAlive(now = Date.now()): Promise<void> {
|
|
333
|
+
if (stopping || inFlight) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
// Operator stop wins over the watchdog — never respawn while suppressed.
|
|
337
|
+
if (opts.isSuppressed?.()) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (opts.probe().status === "running") {
|
|
341
|
+
consecutiveFailures = 0;
|
|
342
|
+
nextAttemptAt = 0;
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
if (now < nextAttemptAt) {
|
|
346
|
+
return; // in a backoff window after a failed respawn
|
|
347
|
+
}
|
|
348
|
+
inFlight = true;
|
|
349
|
+
try {
|
|
350
|
+
const { pid, alreadyRunning } = await opts.respawn();
|
|
351
|
+
consecutiveFailures = 0;
|
|
352
|
+
nextAttemptAt = 0;
|
|
353
|
+
if (stopping) {
|
|
354
|
+
// Disposed mid-respawn: kill the child we just created so it is not
|
|
355
|
+
// orphaned past shutdown.
|
|
356
|
+
opts.killChild?.(pid);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (!alreadyRunning) {
|
|
360
|
+
opts.onRespawn?.(pid);
|
|
361
|
+
}
|
|
362
|
+
} catch (err) {
|
|
363
|
+
consecutiveFailures += 1;
|
|
364
|
+
const backoff = Math.min(
|
|
365
|
+
maxBackoff,
|
|
366
|
+
minBackoff * 2 ** (consecutiveFailures - 1),
|
|
367
|
+
);
|
|
368
|
+
nextAttemptAt = now + backoff;
|
|
369
|
+
if (consecutiveFailures === threshold) {
|
|
370
|
+
opts.onPersistentFailure?.(consecutiveFailures, err);
|
|
371
|
+
}
|
|
372
|
+
} finally {
|
|
373
|
+
inFlight = false;
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
dispose(): void {
|
|
377
|
+
stopping = true;
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
10
10
|
|
|
11
11
|
import type { LifecycleEvent } from "../../persistence/lifecycle-events-store.js";
|
|
12
|
+
import type { ConsentState } from "../../platform/consent-cache.js";
|
|
12
13
|
|
|
13
14
|
const checkpoints = new Map<string, string>();
|
|
14
15
|
const recordedEvents: string[] = [];
|
|
15
16
|
let fakeEnabledWatchers: Array<{ providerId: string }> = [];
|
|
16
|
-
let shareAnalytics = true;
|
|
17
|
+
let shareAnalytics: ConsentState = true;
|
|
17
18
|
const recordAndReturnEvent = (name: string): LifecycleEvent => {
|
|
18
19
|
recordedEvents.push(name);
|
|
19
20
|
return { id: "evt-1", eventName: name, createdAt: 0 };
|
|
@@ -32,7 +33,7 @@ mock.module("../../persistence/lifecycle-events-store.js", () => ({
|
|
|
32
33
|
}));
|
|
33
34
|
|
|
34
35
|
mock.module("../../platform/consent-cache.js", () => ({
|
|
35
|
-
|
|
36
|
+
getRawShareAnalytics: () => shareAnalytics,
|
|
36
37
|
}));
|
|
37
38
|
|
|
38
39
|
mock.module("../watcher-store.js", () => ({
|
|
@@ -135,10 +136,10 @@ describe("recordWatcherInventoryIfDue", () => {
|
|
|
135
136
|
expect(checkpoints.get(INVENTORY_KEY)).toBe(String(BASE + 3));
|
|
136
137
|
});
|
|
137
138
|
|
|
138
|
-
test("advances the checkpoint when consent is
|
|
139
|
+
test("advances the checkpoint when consent is a confirmed opt-out", () => {
|
|
139
140
|
fakeEnabledWatchers = [{ providerId: "gmail" }];
|
|
140
141
|
shareAnalytics = false;
|
|
141
|
-
//
|
|
142
|
+
// Confirmed-opt-out skip: the store records nothing and returns null.
|
|
142
143
|
recordImpl = () => null;
|
|
143
144
|
|
|
144
145
|
recordWatcherInventoryIfDue(BASE + 4);
|
|
@@ -146,6 +147,18 @@ describe("recordWatcherInventoryIfDue", () => {
|
|
|
146
147
|
expect(recordedEvents).toEqual([]);
|
|
147
148
|
expect(checkpoints.get(INVENTORY_KEY)).toBe(String(BASE + 4));
|
|
148
149
|
});
|
|
150
|
+
|
|
151
|
+
test("leaves the checkpoint for retry when the store returns null while consent is unknown", () => {
|
|
152
|
+
fakeEnabledWatchers = [{ providerId: "gmail" }];
|
|
153
|
+
shareAnalytics = "unknown";
|
|
154
|
+
// Unknown consent never drops at record time, so a null here means the
|
|
155
|
+
// telemetry DB is unavailable — retry, don't skip a day.
|
|
156
|
+
recordImpl = () => null;
|
|
157
|
+
|
|
158
|
+
recordWatcherInventoryIfDue(BASE + 4);
|
|
159
|
+
|
|
160
|
+
expect(checkpoints.get(INVENTORY_KEY)).toBeUndefined();
|
|
161
|
+
});
|
|
149
162
|
});
|
|
150
163
|
|
|
151
164
|
describe("recordWatcherLlmProcessed", () => {
|
package/src/watcher/telemetry.ts
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
setMemoryCheckpoint,
|
|
25
25
|
} from "../persistence/checkpoints.js";
|
|
26
26
|
import { recordLifecycleEvent } from "../persistence/lifecycle-events-store.js";
|
|
27
|
-
import {
|
|
27
|
+
import { getRawShareAnalytics } from "../platform/consent-cache.js";
|
|
28
28
|
import { getLogger } from "../util/logger.js";
|
|
29
29
|
import { listWatchers } from "./watcher-store.js";
|
|
30
30
|
|
|
@@ -39,9 +39,9 @@ let warnedInventoryDbUnavailable = false;
|
|
|
39
39
|
* Record one `watcher_enabled:<providerId>` lifecycle event per enabled
|
|
40
40
|
* watcher, at most once per 24h. Called from every watcher tick; the
|
|
41
41
|
* checkpoint advances only after the events are recorded, so a transient
|
|
42
|
-
* storage failure (a throw, or a degraded-mode `null` while
|
|
43
|
-
*
|
|
44
|
-
* A
|
|
42
|
+
* storage failure (a throw, or a degraded-mode `null` while consent is not
|
|
43
|
+
* a confirmed opt-out) retries on the next tick instead of skipping a day.
|
|
44
|
+
* A confirmed-opt-out `null` is a deliberate skip and still advances. Retries
|
|
45
45
|
* can duplicate events for watchers recorded before the failure point —
|
|
46
46
|
* an acceptable overcount for best-effort telemetry, where losing a full
|
|
47
47
|
* day's inventory would not be.
|
|
@@ -54,7 +54,7 @@ export function recordWatcherInventoryIfDue(now: number): void {
|
|
|
54
54
|
const recorded = recordLifecycleEvent(
|
|
55
55
|
`watcher_enabled:${watcher.providerId}`,
|
|
56
56
|
);
|
|
57
|
-
if (recorded === null &&
|
|
57
|
+
if (recorded === null && getRawShareAnalytics() !== false) {
|
|
58
58
|
if (!warnedInventoryDbUnavailable) {
|
|
59
59
|
warnedInventoryDbUnavailable = true;
|
|
60
60
|
log.warn(
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Strip the now-removed `services.web-fetch.mode` field from existing
|
|
8
|
+
* `config.json` files. Web fetch has no managed proxy, so the field never
|
|
9
|
+
* governed anything — provider is the only axis — and the schema no longer
|
|
10
|
+
* recognizes it.
|
|
11
|
+
*
|
|
12
|
+
* Purely tidying: the schema strips unknown keys, so a lingering `mode` is
|
|
13
|
+
* inert at runtime. This exists so upgraded configs on disk match the schema
|
|
14
|
+
* rather than carrying a dead key indefinitely.
|
|
15
|
+
*
|
|
16
|
+
* Idempotent: re-running when `mode` is already absent is a no-op.
|
|
17
|
+
*/
|
|
18
|
+
export const dropWebFetchModeMigration: WorkspaceMigration = {
|
|
19
|
+
id: "131-drop-web-fetch-mode",
|
|
20
|
+
description:
|
|
21
|
+
"Strip services.web-fetch.mode from config.json (mode field removed from schema)",
|
|
22
|
+
run(workspaceDir: string): void {
|
|
23
|
+
const configPath = join(workspaceDir, "config.json");
|
|
24
|
+
if (!existsSync(configPath)) return;
|
|
25
|
+
|
|
26
|
+
let config: Record<string, unknown>;
|
|
27
|
+
try {
|
|
28
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
29
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
30
|
+
config = raw as Record<string, unknown>;
|
|
31
|
+
} catch {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const services = config.services;
|
|
36
|
+
if (
|
|
37
|
+
services === null ||
|
|
38
|
+
typeof services !== "object" ||
|
|
39
|
+
Array.isArray(services)
|
|
40
|
+
)
|
|
41
|
+
return;
|
|
42
|
+
|
|
43
|
+
const webFetch = (services as Record<string, unknown>)["web-fetch"];
|
|
44
|
+
if (
|
|
45
|
+
webFetch === null ||
|
|
46
|
+
typeof webFetch !== "object" ||
|
|
47
|
+
Array.isArray(webFetch)
|
|
48
|
+
)
|
|
49
|
+
return;
|
|
50
|
+
|
|
51
|
+
const webFetchObj = webFetch as Record<string, unknown>;
|
|
52
|
+
if (!("mode" in webFetchObj)) return;
|
|
53
|
+
|
|
54
|
+
delete webFetchObj.mode;
|
|
55
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
56
|
+
},
|
|
57
|
+
down(_workspaceDir: string): void {
|
|
58
|
+
// Forward-only: re-adding mode would reintroduce a field the schema no
|
|
59
|
+
// longer recognizes.
|
|
60
|
+
},
|
|
61
|
+
};
|
|
@@ -127,6 +127,7 @@ import { stripManagedProfileBodiesMigration } from "./126-strip-managed-profile-
|
|
|
127
127
|
import { backfillDefaultProviderMigration } from "./127-backfill-default-provider.js";
|
|
128
128
|
import { repairStaleOpenrouterGrokModelIdsMigration } from "./128-repair-stale-openrouter-grok-model-ids.js";
|
|
129
129
|
import { removeAnalyzeConversationConfigMigration } from "./129-remove-analyze-conversation-config.js";
|
|
130
|
+
import { dropWebFetchModeMigration } from "./131-drop-web-fetch-mode.js";
|
|
130
131
|
import { migrateToWorkspaceVolumeMigration } from "./migrate-to-workspace-volume.js";
|
|
131
132
|
import type { WorkspaceMigration } from "./types.js";
|
|
132
133
|
|
|
@@ -265,4 +266,5 @@ export const WORKSPACE_MIGRATIONS: WorkspaceMigration[] = [
|
|
|
265
266
|
backfillDefaultProviderMigration,
|
|
266
267
|
repairStaleOpenrouterGrokModelIdsMigration,
|
|
267
268
|
removeAnalyzeConversationConfigMigration,
|
|
269
|
+
dropWebFetchModeMigration,
|
|
268
270
|
];
|
|
@@ -67,7 +67,9 @@ class ProviderCommitMessageGenerator {
|
|
|
67
67
|
private isBreakerOpen(): boolean {
|
|
68
68
|
const config = getConfig();
|
|
69
69
|
const { openAfterFailures } = config.workspaceGit.commitMessageLLM.breaker;
|
|
70
|
-
if (this.consecutiveFailures < openAfterFailures)
|
|
70
|
+
if (this.consecutiveFailures < openAfterFailures) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
71
73
|
return Date.now() < this.nextAllowedAttemptMs;
|
|
72
74
|
}
|
|
73
75
|
|
|
@@ -122,7 +124,7 @@ class ProviderCommitMessageGenerator {
|
|
|
122
124
|
|
|
123
125
|
// Step 2: Resolve configured provider via the commit-message call site,
|
|
124
126
|
// so model + maxTokens + temperature come from `llm.callSites.commitMessage`
|
|
125
|
-
// (with
|
|
127
|
+
// (with the shipped call-site default as the fallback). Operational fields (`enabled`,
|
|
126
128
|
// `timeoutMs`, `breaker`, `maxFilesInPrompt`, `maxDiffBytes`,
|
|
127
129
|
// `minRemainingTurnBudgetMs`) remain on `workspaceGit.commitMessageLLM`
|
|
128
130
|
// and are read above. If nothing is resolvable, differentiate likely
|
|
@@ -241,8 +243,8 @@ class ProviderCommitMessageGenerator {
|
|
|
241
243
|
signal: ac.signal,
|
|
242
244
|
config: {
|
|
243
245
|
// `callSite` lets the provider resolve model, max_tokens, and
|
|
244
|
-
// temperature from `llm.callSites.commitMessage` (with
|
|
245
|
-
//
|
|
246
|
+
// temperature from `llm.callSites.commitMessage` (with the
|
|
247
|
+
// shipped call-site default as the fallback). Operational fields
|
|
246
248
|
// (`enabled`, `timeoutMs`, `breaker`, `maxFilesInPrompt`,
|
|
247
249
|
// `maxDiffBytes`, `minRemainingTurnBudgetMs`) remain on
|
|
248
250
|
// `workspaceGit.commitMessageLLM` and are read above.
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
|
|
3
|
-
import type { ProxyResolver } from "../tools/apps/executors.js";
|
|
4
|
-
import { openAppViaSurface } from "../tools/apps/open-proxy.js";
|
|
5
|
-
|
|
6
|
-
describe("openAppViaSurface", () => {
|
|
7
|
-
test("returns proxy result content on success", async () => {
|
|
8
|
-
const resolver: ProxyResolver = async (_name, _input) => ({
|
|
9
|
-
content: "opened-surface-123",
|
|
10
|
-
isError: false,
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
const result = await openAppViaSurface("app-1", resolver);
|
|
14
|
-
expect(result).toBe("opened-surface-123");
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test("passes app_id and extraInput to the resolver", async () => {
|
|
18
|
-
let capturedName: string | undefined;
|
|
19
|
-
let capturedInput: Record<string, unknown> | undefined;
|
|
20
|
-
|
|
21
|
-
const resolver: ProxyResolver = async (name, input) => {
|
|
22
|
-
capturedName = name;
|
|
23
|
-
capturedInput = input;
|
|
24
|
-
return { content: "ok", isError: false };
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
await openAppViaSurface("my-app", resolver, {
|
|
28
|
-
preview: { title: "Hello" },
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
expect(capturedName).toBe("app_open");
|
|
32
|
-
expect(capturedInput).toEqual({
|
|
33
|
-
app_id: "my-app",
|
|
34
|
-
preview: { title: "Hello" },
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test("returns informational message when resolver is undefined", async () => {
|
|
39
|
-
const result = await openAppViaSurface("app-1", undefined);
|
|
40
|
-
expect(result).toBe(
|
|
41
|
-
"App created but could not be opened (no connected client). Use app_open to open it manually.",
|
|
42
|
-
);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test("returns fallback text when resolver throws", async () => {
|
|
46
|
-
const resolver: ProxyResolver = async () => {
|
|
47
|
-
throw new Error("connection lost");
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const result = await openAppViaSurface("app-1", resolver);
|
|
51
|
-
expect(result).toBe(
|
|
52
|
-
"Failed to auto-open app. Use app_open to open it manually.",
|
|
53
|
-
);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test("omits extraInput fields when not provided", async () => {
|
|
57
|
-
let capturedInput: Record<string, unknown> | undefined;
|
|
58
|
-
|
|
59
|
-
const resolver: ProxyResolver = async (_name, input) => {
|
|
60
|
-
capturedInput = input;
|
|
61
|
-
return { content: "ok", isError: false };
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
await openAppViaSurface("app-2", resolver);
|
|
65
|
-
expect(capturedInput).toEqual({ app_id: "app-2" });
|
|
66
|
-
});
|
|
67
|
-
});
|