@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
|
@@ -12,6 +12,19 @@ export const VALID_STT_PROVIDERS = [
|
|
|
12
12
|
"vellum",
|
|
13
13
|
] as const;
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Forgiving aliases normalized to a canonical provider id before the enum
|
|
17
|
+
* check, so a natural value like `openai` or `whisper` is accepted rather than
|
|
18
|
+
* silently reset (which cascades into a full `services` section reset).
|
|
19
|
+
*/
|
|
20
|
+
const STT_PROVIDER_ALIASES: Record<
|
|
21
|
+
string,
|
|
22
|
+
(typeof VALID_STT_PROVIDERS)[number]
|
|
23
|
+
> = {
|
|
24
|
+
openai: "openai-whisper",
|
|
25
|
+
whisper: "openai-whisper",
|
|
26
|
+
};
|
|
27
|
+
|
|
15
28
|
/**
|
|
16
29
|
* Sparse provider config map under `services.stt.providers`.
|
|
17
30
|
*
|
|
@@ -33,11 +46,12 @@ export type SttProviders = z.infer<typeof SttProvidersSchema>;
|
|
|
33
46
|
/**
|
|
34
47
|
* Canonical STT service configuration.
|
|
35
48
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
49
|
+
* Managed transcription (through the user's Vellum account, billed to Vellum
|
|
50
|
+
* credits) is selectable two ways: `provider: "vellum"` directly, or
|
|
51
|
+
* `mode: "managed"` alongside a BYOK `provider` — the form the mode toggle
|
|
52
|
+
* writes, which leaves the BYOK choice untouched so switching back to
|
|
53
|
+
* `"your-own"` restores it. Use {@link effectiveSttProvider} to resolve
|
|
54
|
+
* which provider is actually active.
|
|
41
55
|
*/
|
|
42
56
|
export const SttServiceSchema = z
|
|
43
57
|
.object({
|
|
@@ -50,22 +64,21 @@ export const SttServiceSchema = z
|
|
|
50
64
|
'STT service mode -- "your-own" uses the configured provider with your API key; "managed" transcribes through your Vellum account',
|
|
51
65
|
),
|
|
52
66
|
provider: z
|
|
53
|
-
.
|
|
54
|
-
|
|
55
|
-
|
|
67
|
+
.preprocess(
|
|
68
|
+
(v) => {
|
|
69
|
+
if (typeof v !== "string") {
|
|
70
|
+
return v;
|
|
71
|
+
}
|
|
72
|
+
const k = v.trim().toLowerCase();
|
|
73
|
+
return STT_PROVIDER_ALIASES[k] ?? k;
|
|
74
|
+
},
|
|
75
|
+
z.enum(VALID_STT_PROVIDERS, {
|
|
76
|
+
error: `services.stt.provider must be one of: ${VALID_STT_PROVIDERS.join(", ")} (aliases: openai/whisper -> openai-whisper)`,
|
|
77
|
+
}),
|
|
78
|
+
)
|
|
56
79
|
.describe("Active STT provider used for speech-to-text transcription"),
|
|
57
80
|
providers: SttProvidersSchema.default({}),
|
|
58
81
|
})
|
|
59
|
-
.superRefine((service, ctx) => {
|
|
60
|
-
if (service.provider === "vellum" && service.mode !== "managed") {
|
|
61
|
-
ctx.addIssue({
|
|
62
|
-
code: "custom",
|
|
63
|
-
path: ["provider"],
|
|
64
|
-
message:
|
|
65
|
-
'services.stt.provider "vellum" requires services.stt.mode "managed"',
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
82
|
.describe(
|
|
70
83
|
"Speech-to-text service configuration -- provider selection and per-provider settings",
|
|
71
84
|
);
|
|
@@ -75,13 +88,17 @@ export type SttService = z.infer<typeof SttServiceSchema>;
|
|
|
75
88
|
/**
|
|
76
89
|
* Resolve the provider that is actually active for the service config.
|
|
77
90
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* `"your-own"` restores
|
|
91
|
+
* `provider: "vellum"` selects managed transcription directly. Otherwise
|
|
92
|
+
* `mode: "managed"` routes to `vellum` while leaving the user's BYOK
|
|
93
|
+
* `provider` choice untouched, so toggling back to `"your-own"` restores
|
|
94
|
+
* their previous setup.
|
|
81
95
|
*/
|
|
82
96
|
export function effectiveSttProvider(service: {
|
|
83
97
|
mode: SttService["mode"];
|
|
84
98
|
provider: string;
|
|
85
99
|
}): string {
|
|
100
|
+
if (service.provider === "vellum") {
|
|
101
|
+
return "vellum";
|
|
102
|
+
}
|
|
86
103
|
return service.mode === "managed" ? "vellum" : service.provider;
|
|
87
104
|
}
|
|
@@ -273,11 +273,12 @@ for (const id of schemaKeys) {
|
|
|
273
273
|
/**
|
|
274
274
|
* Canonical TTS service configuration.
|
|
275
275
|
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
* `
|
|
279
|
-
*
|
|
280
|
-
*
|
|
276
|
+
* Managed synthesis (through the user's Vellum account, billed to Vellum
|
|
277
|
+
* credits) is selectable two ways: `provider: "vellum"` directly, or
|
|
278
|
+
* `mode: "managed"` alongside a BYOK `provider` — the form the mode toggle
|
|
279
|
+
* writes, which leaves the BYOK choice untouched so switching back to
|
|
280
|
+
* `"your-own"` restores it. Use {@link effectiveTtsProvider} to resolve
|
|
281
|
+
* which provider is actually active.
|
|
281
282
|
*/
|
|
282
283
|
export const TtsServiceSchema = z
|
|
283
284
|
.object({
|
|
@@ -297,16 +298,6 @@ export const TtsServiceSchema = z
|
|
|
297
298
|
.describe("Active TTS provider used for speech synthesis"),
|
|
298
299
|
providers: TtsProvidersSchema.default(TtsProvidersSchema.parse({})),
|
|
299
300
|
})
|
|
300
|
-
.superRefine((service, ctx) => {
|
|
301
|
-
if (service.provider === "vellum" && service.mode !== "managed") {
|
|
302
|
-
ctx.addIssue({
|
|
303
|
-
code: "custom",
|
|
304
|
-
path: ["provider"],
|
|
305
|
-
message:
|
|
306
|
-
'services.tts.provider "vellum" requires services.tts.mode "managed"',
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
})
|
|
310
301
|
.describe(
|
|
311
302
|
"Text-to-speech service configuration — provider selection and per-provider settings",
|
|
312
303
|
);
|
|
@@ -316,14 +307,18 @@ export type TtsService = z.infer<typeof TtsServiceSchema>;
|
|
|
316
307
|
/**
|
|
317
308
|
* Resolve the provider that is actually active for the service config.
|
|
318
309
|
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
* `"your-own"` restores
|
|
310
|
+
* `provider: "vellum"` selects managed synthesis directly. Otherwise
|
|
311
|
+
* `mode: "managed"` routes to `vellum` while leaving the user's BYOK
|
|
312
|
+
* `provider` choice untouched, so toggling back to `"your-own"` restores
|
|
313
|
+
* their previous setup.
|
|
322
314
|
*/
|
|
323
315
|
export function effectiveTtsProvider(service: {
|
|
324
316
|
mode: TtsService["mode"];
|
|
325
317
|
provider?: string;
|
|
326
318
|
}): string {
|
|
319
|
+
if (service.provider === "vellum") {
|
|
320
|
+
return "vellum";
|
|
321
|
+
}
|
|
327
322
|
if (service.mode === "managed") {
|
|
328
323
|
return "vellum";
|
|
329
324
|
}
|
package/src/config/skills.ts
CHANGED
|
@@ -684,25 +684,26 @@ function discoverSkillDirectories(skillsDir: string): string[] {
|
|
|
684
684
|
}
|
|
685
685
|
|
|
686
686
|
/**
|
|
687
|
-
* Whether `pluginDir`
|
|
688
|
-
* parseable `package.json`
|
|
689
|
-
*
|
|
690
|
-
* directory
|
|
687
|
+
* Whether `pluginDir` carries a plugin manifest the runtime can load: a
|
|
688
|
+
* parseable `package.json` with a non-empty string `name`. This mirrors the
|
|
689
|
+
* external plugin loader (`buildPluginFromDir`), which builds a plugin from
|
|
690
|
+
* any such directory and derives the plugin's identity from `package.json`
|
|
691
|
+
* `name` — it imposes no match between that `name` and the directory name.
|
|
692
|
+
*
|
|
693
|
+
* The directory name is the install slug (a marketplace slug or a GitHub path
|
|
694
|
+
* leaf), which routinely differs from the plugin's own `package.json` `name`;
|
|
695
|
+
* requiring the two to match would silently drop the resident skills of every
|
|
696
|
+
* such plugin even though the runtime loads its hooks and tools fine.
|
|
691
697
|
*
|
|
692
698
|
* The caller is responsible for the missing-`package.json` case (it emits a
|
|
693
699
|
* diagnostic warning); this function only judges a manifest that is present.
|
|
694
700
|
*/
|
|
695
|
-
function
|
|
701
|
+
function hasLoadablePluginManifest(pluginDir: string): boolean {
|
|
696
702
|
const manifestPath = join(pluginDir, "package.json");
|
|
697
703
|
if (!existsSync(manifestPath)) return false;
|
|
704
|
+
let parsed: unknown;
|
|
698
705
|
try {
|
|
699
|
-
|
|
700
|
-
return (
|
|
701
|
-
typeof parsed === "object" &&
|
|
702
|
-
parsed !== null &&
|
|
703
|
-
"name" in parsed &&
|
|
704
|
-
(parsed as { name: unknown }).name === dirName
|
|
705
|
-
);
|
|
706
|
+
parsed = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
706
707
|
} catch (err) {
|
|
707
708
|
log.warn(
|
|
708
709
|
{ err, manifestPath },
|
|
@@ -710,12 +711,19 @@ function isRecognizedPluginDir(pluginDir: string, dirName: string): boolean {
|
|
|
710
711
|
);
|
|
711
712
|
return false;
|
|
712
713
|
}
|
|
714
|
+
return (
|
|
715
|
+
typeof parsed === "object" &&
|
|
716
|
+
parsed !== null &&
|
|
717
|
+
"name" in parsed &&
|
|
718
|
+
typeof (parsed as { name: unknown }).name === "string" &&
|
|
719
|
+
(parsed as { name: string }).name.length > 0
|
|
720
|
+
);
|
|
713
721
|
}
|
|
714
722
|
|
|
715
723
|
/**
|
|
716
724
|
* Discover skills shipped on disk inside installed plugins. Each installed
|
|
717
725
|
* plugin — a directory under `<workspaceDir>/plugins/` recognized by
|
|
718
|
-
* {@link
|
|
726
|
+
* {@link hasLoadablePluginManifest} — may ship skills at `skills/<id>/SKILL.md`.
|
|
719
727
|
* Returned summaries are attributed to the owning plugin via their `owner`
|
|
720
728
|
* descriptor (`{ kind: "plugin", id: <plugin dir name> }`).
|
|
721
729
|
*/
|
|
@@ -747,7 +755,7 @@ function discoverPluginResidentSkills(): SkillSummary[] {
|
|
|
747
755
|
if (!existsSync(join(pluginDir, "package.json"))) {
|
|
748
756
|
log.warn(
|
|
749
757
|
{ pluginDir },
|
|
750
|
-
"Plugin directory is missing package.json — skipping; its skills will not be available. Add a package.json
|
|
758
|
+
"Plugin directory is missing package.json — skipping; its skills will not be available. Add a package.json with a `name`.",
|
|
751
759
|
);
|
|
752
760
|
continue;
|
|
753
761
|
}
|
|
@@ -757,13 +765,15 @@ function discoverPluginResidentSkills(): SkillSummary[] {
|
|
|
757
765
|
// tools, so its resident skills must not be loadable either.
|
|
758
766
|
if (existsSync(join(pluginDir, ".disabled"))) continue;
|
|
759
767
|
|
|
760
|
-
// Mirror the plugin loader
|
|
761
|
-
//
|
|
762
|
-
//
|
|
763
|
-
//
|
|
764
|
-
//
|
|
765
|
-
//
|
|
766
|
-
|
|
768
|
+
// Mirror the plugin loader: a directory contributes its resident skills
|
|
769
|
+
// when it carries a loadable manifest (parseable `package.json` with a
|
|
770
|
+
// non-empty `name`). The manifest `name` need not equal the directory name
|
|
771
|
+
// — the loader imposes no such match — so a plugin installed under a
|
|
772
|
+
// marketplace slug or GitHub path leaf that differs from its `package.json`
|
|
773
|
+
// `name` still surfaces its skills, matching the hooks and tools the
|
|
774
|
+
// runtime already loads from it. A parseable manifest still rejects staging
|
|
775
|
+
// dirs and malformed clones the loader would itself refuse.
|
|
776
|
+
if (!hasLoadablePluginManifest(pluginDir)) continue;
|
|
767
777
|
|
|
768
778
|
const skillsDir = join(pluginDir, "skills");
|
|
769
779
|
if (!existsSync(skillsDir)) continue;
|
package/src/context/compactor.ts
CHANGED
|
@@ -82,10 +82,13 @@ function recordCompactionRequestLog(
|
|
|
82
82
|
conversationId: string,
|
|
83
83
|
response: ProviderResponse,
|
|
84
84
|
provider: Provider,
|
|
85
|
-
):
|
|
86
|
-
if (!response.rawRequest || !response.rawResponse) return;
|
|
85
|
+
): string | null {
|
|
86
|
+
if (!response.rawRequest || !response.rawResponse) return null;
|
|
87
87
|
try {
|
|
88
|
-
|
|
88
|
+
// Inserted unlinked (no message id) — user-initiated compaction flows
|
|
89
|
+
// (/compact, summarize-up-to) link the row to their result card after
|
|
90
|
+
// it persists, via `linkRequestLogsToMessage`.
|
|
91
|
+
return recordRequestLog(
|
|
89
92
|
conversationId,
|
|
90
93
|
JSON.stringify(response.rawRequest),
|
|
91
94
|
JSON.stringify(response.rawResponse),
|
|
@@ -98,6 +101,7 @@ function recordCompactionRequestLog(
|
|
|
98
101
|
{ err, conversationId },
|
|
99
102
|
"Failed to persist compaction LLM request log (non-fatal)",
|
|
100
103
|
);
|
|
104
|
+
return null;
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
|
|
@@ -280,6 +284,14 @@ export interface CompactionRunArgs {
|
|
|
280
284
|
* `[1, messages.length)` — otherwise the run returns `compacted: false`.
|
|
281
285
|
*/
|
|
282
286
|
fixedTailStartIndex?: number;
|
|
287
|
+
/**
|
|
288
|
+
* Row-space twin of `fixedTailStartIndex`: index into the conversation's
|
|
289
|
+
* persisted rows of the first message kept verbatim. Bounds the image
|
|
290
|
+
* manifest to rows that are actually being summarized away — kept-tail
|
|
291
|
+
* images stay in context verbatim, so offering them for retention would
|
|
292
|
+
* only duplicate them. Only meaningful alongside `fixedTailStartIndex`.
|
|
293
|
+
*/
|
|
294
|
+
fixedBoundaryRowIndex?: number;
|
|
283
295
|
}
|
|
284
296
|
|
|
285
297
|
export interface CompactionRunResult {
|
|
@@ -305,6 +317,14 @@ export interface CompactionRunResult {
|
|
|
305
317
|
summaryCacheCreationInputTokens?: number;
|
|
306
318
|
summaryCacheReadInputTokens?: number;
|
|
307
319
|
summaryRawResponses?: unknown[];
|
|
320
|
+
/**
|
|
321
|
+
* `llm_request_logs.id` of this pass's compaction call, `null` when the
|
|
322
|
+
* row was not written (logging disabled, missing raw payloads, DB error).
|
|
323
|
+
* User-initiated flows (/compact, summarize-up-to) link the row to their
|
|
324
|
+
* persisted result card so the inspector attributes the call to the card
|
|
325
|
+
* instead of the unlinked-row recovery guessing an enclosing turn.
|
|
326
|
+
*/
|
|
327
|
+
summaryRequestLogId?: string | null;
|
|
308
328
|
summaryText: string;
|
|
309
329
|
/** Inline structured pending state from the model's `<key_state>` block. */
|
|
310
330
|
keyState?: string;
|
|
@@ -457,15 +477,23 @@ interface ManifestEntry {
|
|
|
457
477
|
* `loadFromDb` applies when assembling history — so guardian-only images
|
|
458
478
|
* never enter the manifest and therefore can never be retained back into
|
|
459
479
|
* an untrusted actor's view.
|
|
480
|
+
*
|
|
481
|
+
* `endRowIndex` (exclusive, row-space) bounds the walk to rows before a
|
|
482
|
+
* caller-fixed compaction boundary — images in the kept tail survive
|
|
483
|
+
* verbatim and must not be offered for retention. The slice happens before
|
|
484
|
+
* the trust filter because the boundary indexes the full row list.
|
|
460
485
|
*/
|
|
461
486
|
export function collectImageManifest(
|
|
462
487
|
conversationId: string,
|
|
463
488
|
actorTrustClass?: TrustClass,
|
|
489
|
+
endRowIndex?: number,
|
|
464
490
|
): ManifestEntry[] {
|
|
465
491
|
const allRows = getMessages(conversationId);
|
|
492
|
+
const boundedRows =
|
|
493
|
+
endRowIndex != null ? allRows.slice(0, endRowIndex) : allRows;
|
|
466
494
|
const rows = !resolveCapabilities(actorTrustClass).canAccessMemory
|
|
467
|
-
? filterMessagesForUntrustedActor(
|
|
468
|
-
:
|
|
495
|
+
? filterMessagesForUntrustedActor(boundedRows)
|
|
496
|
+
: boundedRows;
|
|
469
497
|
const entries: ManifestEntry[] = [];
|
|
470
498
|
for (const row of rows) {
|
|
471
499
|
const atts = getAttachmentMetadataForMessage(row.id);
|
|
@@ -1096,10 +1124,12 @@ export async function runAssistantDrivenCompaction(
|
|
|
1096
1124
|
// Build image manifest from the DB before invoking the model so the
|
|
1097
1125
|
// instruction message carries a faithful picture of available images.
|
|
1098
1126
|
// Filtered by actor trust so untrusted turns never see guardian-only
|
|
1099
|
-
// attachments
|
|
1127
|
+
// attachments, and bounded to pre-boundary rows on fixed-boundary runs
|
|
1128
|
+
// so kept-tail images are never offered for retention.
|
|
1100
1129
|
const manifest = collectImageManifest(
|
|
1101
1130
|
args.conversationId,
|
|
1102
1131
|
args.actorTrustClass,
|
|
1132
|
+
fixedTailStartIndex != null ? args.fixedBoundaryRowIndex : undefined,
|
|
1103
1133
|
);
|
|
1104
1134
|
const manifestText = renderImageManifest(manifest);
|
|
1105
1135
|
const instruction = buildInstructionMessage(
|
|
@@ -1159,7 +1189,11 @@ export async function runAssistantDrivenCompaction(
|
|
|
1159
1189
|
|
|
1160
1190
|
// Persist the compaction LLM call into `llm_request_logs` with
|
|
1161
1191
|
// `call_site = "compactionAgent"`. Non-fatal on DB error — see helper.
|
|
1162
|
-
recordCompactionRequestLog(
|
|
1192
|
+
const summaryRequestLogId = recordCompactionRequestLog(
|
|
1193
|
+
args.conversationId,
|
|
1194
|
+
response,
|
|
1195
|
+
args.provider,
|
|
1196
|
+
);
|
|
1163
1197
|
|
|
1164
1198
|
const rawText = extractTextFromResponse(response.content);
|
|
1165
1199
|
const parsed = parseCompactionResult(rawText, {
|
|
@@ -1182,6 +1216,7 @@ export async function runAssistantDrivenCompaction(
|
|
|
1182
1216
|
summaryCallSite: COMPACTION_CALL_SITE,
|
|
1183
1217
|
summaryOverrideProfile: args.overrideProfile ?? null,
|
|
1184
1218
|
summaryRawResponses: response.rawResponse ? [response.rawResponse] : [],
|
|
1219
|
+
summaryRequestLogId,
|
|
1185
1220
|
summaryCalls: 1,
|
|
1186
1221
|
};
|
|
1187
1222
|
}
|
|
@@ -1387,6 +1422,7 @@ export async function runAssistantDrivenCompaction(
|
|
|
1387
1422
|
summaryCallSite: COMPACTION_CALL_SITE,
|
|
1388
1423
|
summaryOverrideProfile: args.overrideProfile ?? null,
|
|
1389
1424
|
summaryRawResponses: response.rawResponse ? [response.rawResponse] : [],
|
|
1425
|
+
summaryRequestLogId,
|
|
1390
1426
|
summaryCalls: 1,
|
|
1391
1427
|
};
|
|
1392
1428
|
}
|
|
@@ -1459,6 +1495,7 @@ export async function runAssistantDrivenCompaction(
|
|
|
1459
1495
|
response.usage.cacheCreationInputTokens ?? 0,
|
|
1460
1496
|
summaryCacheReadInputTokens: response.usage.cacheReadInputTokens ?? 0,
|
|
1461
1497
|
summaryRawResponses: response.rawResponse ? [response.rawResponse] : [],
|
|
1498
|
+
summaryRequestLogId,
|
|
1462
1499
|
summaryText: finalSummaryText,
|
|
1463
1500
|
keyState: parsed.keyState,
|
|
1464
1501
|
summaryFailed: false,
|
|
@@ -104,7 +104,9 @@ export function getToolResultFilePath(
|
|
|
104
104
|
/**
|
|
105
105
|
* Build the truncated stub that replaces a large tool result in context.
|
|
106
106
|
* Preserves the first and last halves of TARGET_CHARS, with a middle marker
|
|
107
|
-
* indicating how many tokens were omitted
|
|
107
|
+
* indicating how many tokens were omitted, where to find the full result, and
|
|
108
|
+
* how to page it back in — the marker is the model's only signal that the
|
|
109
|
+
* omitted content is recoverable at all.
|
|
108
110
|
*/
|
|
109
111
|
export function buildTruncatedContent(
|
|
110
112
|
original: string,
|
|
@@ -119,7 +121,7 @@ export function buildTruncatedContent(
|
|
|
119
121
|
);
|
|
120
122
|
const omittedChars = original.length - TARGET_CHARS;
|
|
121
123
|
const estimatedTokens = Math.round(omittedChars / 4);
|
|
122
|
-
return `${prefix}\n\n...(${estimatedTokens} tokens omitted ${TRUNCATION_MARKER} ${filePath})\n\n${suffix}`;
|
|
124
|
+
return `${prefix}\n\n...(${estimatedTokens} tokens omitted ${TRUNCATION_MARKER} ${filePath} — use file_read to view)\n\n${suffix}`;
|
|
123
125
|
}
|
|
124
126
|
|
|
125
127
|
/**
|
|
@@ -18,11 +18,24 @@ import {
|
|
|
18
18
|
*/
|
|
19
19
|
const AX_TREE_TAG = "<ax-tree>";
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Tools whose results are explicit, self-sized reads the model paginates
|
|
23
|
+
* itself: `web_fetch` takes `max_chars`/`start_index` and reports a
|
|
24
|
+
* "Character Window: X-Y of Z", so the model pages by character index against
|
|
25
|
+
* the window it requested. Stubbing such a result at result time hands the
|
|
26
|
+
* model ~a tenth of the window it just sized — and it keeps paging blind
|
|
27
|
+
* against content it never saw. Like the file-read tools, these explicit
|
|
28
|
+
* reads are honored in full for the turn that made them; the post-turn pass
|
|
29
|
+
* still truncates them at turn end, after the model has consumed the content.
|
|
30
|
+
*/
|
|
31
|
+
export const RESULT_TIME_SPOOL_EXEMPT_TOOLS = new Set<string>(["web_fetch"]);
|
|
32
|
+
|
|
21
33
|
/**
|
|
22
34
|
* Whether a tool result is eligible for the result-time spool/stub pass: the
|
|
23
35
|
* post-turn pass's shared rules plus the AX-tree exemption, minus the file-read
|
|
24
|
-
* tools ({@link FILE_READ_TOOL_NAMES})
|
|
25
|
-
*
|
|
36
|
+
* tools ({@link FILE_READ_TOOL_NAMES}) and the explicit self-sized reads
|
|
37
|
+
* ({@link RESULT_TIME_SPOOL_EXEMPT_TOOLS}). The file-read tools are the model's
|
|
38
|
+
* only way to page spooled content back into context: stubbing a read of a
|
|
26
39
|
* `.tool-results/` file would spool a fresh copy and hand back another stub, so
|
|
27
40
|
* oversized content could never be read at all. Explicit reads are therefore
|
|
28
41
|
* honored in full; the post-turn pass still truncates them at turn end, after
|
|
@@ -32,11 +45,19 @@ function isSpoolEligible(
|
|
|
32
45
|
tr: ToolResultContent,
|
|
33
46
|
toolName: string | undefined,
|
|
34
47
|
): boolean {
|
|
35
|
-
if (!isTruncationEligible(tr, toolName))
|
|
36
|
-
|
|
48
|
+
if (!isTruncationEligible(tr, toolName)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
if (
|
|
52
|
+
toolName !== undefined &&
|
|
53
|
+
(FILE_READ_TOOL_NAMES.has(toolName) ||
|
|
54
|
+
RESULT_TIME_SPOOL_EXEMPT_TOOLS.has(toolName))
|
|
55
|
+
) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
if (tr.content.includes(AX_TREE_TAG)) {
|
|
37
59
|
return false;
|
|
38
60
|
}
|
|
39
|
-
if (tr.content.includes(AX_TREE_TAG)) return false;
|
|
40
61
|
return true;
|
|
41
62
|
}
|
|
42
63
|
|
|
@@ -333,3 +333,51 @@ describe("mergeConsecutiveAssistantMessages", () => {
|
|
|
333
333
|
expect(result).toHaveLength(3);
|
|
334
334
|
});
|
|
335
335
|
});
|
|
336
|
+
|
|
337
|
+
describe("system-card boundaries", () => {
|
|
338
|
+
const cardMeta = JSON.stringify({ messageKind: "system_card" });
|
|
339
|
+
|
|
340
|
+
test("a card never merges into the preceding assistant run", () => {
|
|
341
|
+
const { messages } = mergeConsecutiveAssistantMessages([
|
|
342
|
+
makeMsg("assistant", JSON.stringify([{ type: "text", text: "reply" }])),
|
|
343
|
+
makeMsg(
|
|
344
|
+
"assistant",
|
|
345
|
+
JSON.stringify([{ type: "text", text: "**Conversation summarized**" }]),
|
|
346
|
+
{ metadata: cardMeta },
|
|
347
|
+
),
|
|
348
|
+
]);
|
|
349
|
+
expect(messages).toHaveLength(2);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
test("an assistant row never merges into a preceding card", () => {
|
|
353
|
+
const { messages } = mergeConsecutiveAssistantMessages([
|
|
354
|
+
makeMsg(
|
|
355
|
+
"assistant",
|
|
356
|
+
JSON.stringify([{ type: "text", text: "**Context Cleaned**" }]),
|
|
357
|
+
{ metadata: cardMeta },
|
|
358
|
+
),
|
|
359
|
+
makeMsg("assistant", JSON.stringify([{ type: "text", text: "reply" }])),
|
|
360
|
+
]);
|
|
361
|
+
expect(messages).toHaveLength(2);
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
test("findDisplayTurnEndIndex treats a card as a single-row turn", () => {
|
|
365
|
+
const rows = [
|
|
366
|
+
makeMsg("assistant", JSON.stringify([{ type: "text", text: "card" }]), {
|
|
367
|
+
metadata: cardMeta,
|
|
368
|
+
}),
|
|
369
|
+
makeMsg("assistant", JSON.stringify([{ type: "text", text: "reply" }])),
|
|
370
|
+
];
|
|
371
|
+
expect(findDisplayTurnEndIndex(rows, 0)).toBe(0);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
test("findDisplayTurnEndIndex stops an assistant run before a card", () => {
|
|
375
|
+
const rows = [
|
|
376
|
+
makeMsg("assistant", JSON.stringify([{ type: "text", text: "reply" }])),
|
|
377
|
+
makeMsg("assistant", JSON.stringify([{ type: "text", text: "card" }]), {
|
|
378
|
+
metadata: cardMeta,
|
|
379
|
+
}),
|
|
380
|
+
];
|
|
381
|
+
expect(findDisplayTurnEndIndex(rows, 0)).toBe(0);
|
|
382
|
+
});
|
|
383
|
+
});
|
|
@@ -32,11 +32,22 @@
|
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
34
|
import type { MessageRow } from "../persistence/conversation-crud.js";
|
|
35
|
+
import { isSystemCardMessage } from "../persistence/conversation-crud.js";
|
|
35
36
|
import type { ContentBlock } from "../providers/types.js";
|
|
36
37
|
import { getLogger } from "../util/logger.js";
|
|
37
38
|
|
|
38
39
|
const log = getLogger("message-consolidation");
|
|
39
40
|
|
|
41
|
+
/**
|
|
42
|
+
* True when a row is a daemon-authored system card (`messageKind:
|
|
43
|
+
* "system_card"` metadata). Cards are standalone display turns: they never
|
|
44
|
+
* fold into an adjacent assistant run and adjacent assistant rows never
|
|
45
|
+
* fold into them.
|
|
46
|
+
*/
|
|
47
|
+
export function isSystemCardRow(msg: MessageRow): boolean {
|
|
48
|
+
return isSystemCardMessage(msg.role, msg.metadata);
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
// ── Block predicates ────────────────────────────────────────────────
|
|
41
52
|
|
|
42
53
|
function isToolResultType(type: string): boolean {
|
|
@@ -109,6 +120,10 @@ export function findDisplayTurnEndIndex(
|
|
|
109
120
|
if (messages[startIdx]?.role !== "assistant") {
|
|
110
121
|
return startIdx;
|
|
111
122
|
}
|
|
123
|
+
// A system card is a single-row display turn — never spans neighbours.
|
|
124
|
+
if (isSystemCardRow(messages[startIdx]!)) {
|
|
125
|
+
return startIdx;
|
|
126
|
+
}
|
|
112
127
|
|
|
113
128
|
let endIdx = startIdx;
|
|
114
129
|
while (endIdx + 1 < messages.length) {
|
|
@@ -116,7 +131,7 @@ export function findDisplayTurnEndIndex(
|
|
|
116
131
|
if (!next) {
|
|
117
132
|
break;
|
|
118
133
|
}
|
|
119
|
-
if (next.role === "assistant") {
|
|
134
|
+
if (next.role === "assistant" && !isSystemCardRow(next)) {
|
|
120
135
|
endIdx += 1;
|
|
121
136
|
continue;
|
|
122
137
|
}
|
|
@@ -282,10 +297,15 @@ export function mergeConsecutiveAssistantMessages(messages: MessageRow[]): {
|
|
|
282
297
|
|
|
283
298
|
for (const msg of messages) {
|
|
284
299
|
const lastIdx = result.length - 1;
|
|
300
|
+
// System cards stay standalone in both directions: a card never folds
|
|
301
|
+
// into the preceding assistant run, and the following assistant row
|
|
302
|
+
// never folds into a card.
|
|
285
303
|
const isConsecutiveAssistant =
|
|
286
304
|
msg.role === "assistant" &&
|
|
305
|
+
!isSystemCardRow(msg) &&
|
|
287
306
|
lastIdx >= 0 &&
|
|
288
|
-
result[lastIdx].role === "assistant"
|
|
307
|
+
result[lastIdx].role === "assistant" &&
|
|
308
|
+
!isSystemCardRow(result[lastIdx]);
|
|
289
309
|
|
|
290
310
|
if (!isConsecutiveAssistant) {
|
|
291
311
|
result.push(msg);
|
|
@@ -582,19 +582,12 @@ describe("isToolActiveForContext — ask_question macOS gating", () => {
|
|
|
582
582
|
).toBe(false);
|
|
583
583
|
});
|
|
584
584
|
|
|
585
|
-
test("
|
|
585
|
+
test("app_open is skill-owned and not client-capability gated", () => {
|
|
586
|
+
// The app-builder skill provides app_open; its executor degrades
|
|
587
|
+
// gracefully when no client is connected, so the context filter does
|
|
588
|
+
// not hide it even on clientless turns.
|
|
586
589
|
expect(
|
|
587
|
-
isToolActiveForContext(
|
|
588
|
-
"app_open",
|
|
589
|
-
makeCtx({
|
|
590
|
-
hasNoClient: false,
|
|
591
|
-
channelCapabilities: {
|
|
592
|
-
channel: "macos",
|
|
593
|
-
supportsDynamicUi: true,
|
|
594
|
-
clientOS: "macos",
|
|
595
|
-
},
|
|
596
|
-
}),
|
|
597
|
-
),
|
|
590
|
+
isToolActiveForContext("app_open", makeCtx({ hasNoClient: true })),
|
|
598
591
|
).toBe(true);
|
|
599
592
|
});
|
|
600
593
|
});
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
getApp,
|
|
16
16
|
getAppDirPath,
|
|
17
17
|
getAppsDir,
|
|
18
|
-
isMultifileApp,
|
|
19
18
|
resolveAppIdByDirName,
|
|
20
19
|
} from "../apps/app-store.js";
|
|
21
20
|
import { compileApp } from "../bundler/app-compiler.js";
|
|
@@ -159,8 +158,8 @@ export class AppSourceWatcher {
|
|
|
159
158
|
}
|
|
160
159
|
|
|
161
160
|
/**
|
|
162
|
-
* Handle a detected app source file change. Recompiles
|
|
163
|
-
*
|
|
161
|
+
* Handle a detected app source file change. Recompiles the app and refreshes
|
|
162
|
+
* surfaces across ALL conversations.
|
|
164
163
|
*/
|
|
165
164
|
function handleAppSourceChange(appId: string): void {
|
|
166
165
|
const app = getApp(appId);
|
|
@@ -175,26 +174,21 @@ function handleAppSourceChange(appId: string): void {
|
|
|
175
174
|
void updatePublishedAppDeployment(appId);
|
|
176
175
|
};
|
|
177
176
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
});
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
doRefresh();
|
|
177
|
+
const appDir = getAppDirPath(appId);
|
|
178
|
+
void compileApp(appDir)
|
|
179
|
+
.then((result) => {
|
|
180
|
+
if (!result.ok) {
|
|
181
|
+
log.warn(
|
|
182
|
+
{ appId, errors: result.errors },
|
|
183
|
+
"Recompile failed on app source change",
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
doRefresh();
|
|
187
|
+
})
|
|
188
|
+
.catch((err) => {
|
|
189
|
+
log.warn({ appId, err }, "Recompile threw on app source change");
|
|
190
|
+
doRefresh();
|
|
191
|
+
});
|
|
198
192
|
}
|
|
199
193
|
|
|
200
194
|
/** Start watching app source directories for the life of the daemon. */
|