@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
|
@@ -26,6 +26,7 @@ model (section-grain lanes cached as live shadow state). Each subgroup exposes
|
|
|
26
26
|
operator-facing maintenance verbs — reindexing, backfills, validation, and evals.
|
|
27
27
|
|
|
28
28
|
Examples:
|
|
29
|
+
$ assistant memory nodes stats
|
|
29
30
|
$ assistant memory nodes list --search "coffee"
|
|
30
31
|
$ assistant memory nodes delete "User prefers TypeScript"
|
|
31
32
|
$ assistant memory nodes update "User prefers TypeScript" "User prefers TypeScript and Bun"
|
|
@@ -48,11 +49,33 @@ a remembered fact without first looking up its ID.
|
|
|
48
49
|
All subcommands require memory v2 to be enabled and the assistant to be running.
|
|
49
50
|
|
|
50
51
|
Examples:
|
|
52
|
+
$ assistant memory nodes stats
|
|
51
53
|
$ assistant memory nodes list
|
|
52
54
|
$ assistant memory nodes list --search "TypeScript" --limit 20
|
|
53
55
|
$ assistant memory nodes delete "User prefers TypeScript"
|
|
54
56
|
$ assistant memory nodes update "User prefers TypeScript" "User prefers TypeScript and Bun"`,
|
|
55
57
|
subcommands: [
|
|
58
|
+
{
|
|
59
|
+
name: "stats",
|
|
60
|
+
description: "Show a health overview of the memory v2 graph",
|
|
61
|
+
options: [
|
|
62
|
+
{
|
|
63
|
+
flags: "--json",
|
|
64
|
+
description: "Machine-readable compact JSON output",
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
helpText: `
|
|
68
|
+
Behavior:
|
|
69
|
+
Scans all active memory graph nodes in a single pass and reports:
|
|
70
|
+
total count, breakdown by type and fidelity (with an ASCII bar chart),
|
|
71
|
+
nodes at risk of decay (significance < 15%), average significance,
|
|
72
|
+
oldest/newest node timestamps, last reinforcement, and the top 5 nodes
|
|
73
|
+
by significance. Does not require the daemon to be running.
|
|
74
|
+
|
|
75
|
+
Examples:
|
|
76
|
+
$ assistant memory nodes stats
|
|
77
|
+
$ assistant memory nodes stats --json`,
|
|
78
|
+
},
|
|
56
79
|
{
|
|
57
80
|
name: "list",
|
|
58
81
|
description: "List active memory graph nodes",
|
|
@@ -203,4 +203,150 @@ export function registerMemoryNodesCommand(memory: Command): void {
|
|
|
203
203
|
log.info(result.message);
|
|
204
204
|
},
|
|
205
205
|
);
|
|
206
|
+
|
|
207
|
+
// ── stats ─────────────────────────────────────────────────────────────
|
|
208
|
+
|
|
209
|
+
subcommand(nodes, "stats").action(
|
|
210
|
+
async (opts: { json?: boolean }, cmd: Command) => {
|
|
211
|
+
// Deferred: loads config and the graph stats handler in-process.
|
|
212
|
+
// No daemon needed — reads directly from the workspace SQLite DB.
|
|
213
|
+
const [{ handleStatsMemory }, { getConfig }] = await Promise.all([
|
|
214
|
+
import("../../../plugins/defaults/memory/graph/tool-handlers.js") as Promise<
|
|
215
|
+
typeof import("../../../plugins/defaults/memory/graph/tool-handlers.js")
|
|
216
|
+
>,
|
|
217
|
+
import("../../../config/loader.js") as Promise<
|
|
218
|
+
typeof import("../../../config/loader.js")
|
|
219
|
+
>,
|
|
220
|
+
]);
|
|
221
|
+
|
|
222
|
+
const result = handleStatsMemory(getConfig());
|
|
223
|
+
|
|
224
|
+
if (!result.success) {
|
|
225
|
+
log.error(result.message);
|
|
226
|
+
process.exitCode = 1;
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (opts.json) {
|
|
231
|
+
writeOutput(cmd, result.stats);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
printStats(result.stats!);
|
|
236
|
+
},
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const MEMORY_TYPES = [
|
|
241
|
+
"episodic",
|
|
242
|
+
"semantic",
|
|
243
|
+
"procedural",
|
|
244
|
+
"emotional",
|
|
245
|
+
"prospective",
|
|
246
|
+
"behavioral",
|
|
247
|
+
"narrative",
|
|
248
|
+
"shared",
|
|
249
|
+
] as const;
|
|
250
|
+
|
|
251
|
+
interface StatsData {
|
|
252
|
+
total: number;
|
|
253
|
+
byType: { [key: string]: number | undefined };
|
|
254
|
+
byFidelity: { vivid: number; clear: number; faded: number; gist: number };
|
|
255
|
+
atRisk: number;
|
|
256
|
+
edgeCount: number;
|
|
257
|
+
oldestCreated: number | null;
|
|
258
|
+
newestCreated: number | null;
|
|
259
|
+
lastReinforced: number | null;
|
|
260
|
+
avgSignificance: number;
|
|
261
|
+
topNodes: ReadonlyArray<{ content: string; significance: number }>;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function printStats(s: StatsData): void {
|
|
265
|
+
const n = s.total;
|
|
266
|
+
const e = s.edgeCount;
|
|
267
|
+
|
|
268
|
+
console.log(
|
|
269
|
+
`\nMemory graph ${n} node${n === 1 ? "" : "s"} · ${e} edge${e === 1 ? "" : "s"}\n`,
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
if (n === 0) {
|
|
273
|
+
console.log(" The memory graph is empty.");
|
|
274
|
+
console.log("");
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ── by type ─────────────────────────────────────────────────────────────
|
|
279
|
+
|
|
280
|
+
console.log("BY TYPE");
|
|
281
|
+
for (const t of MEMORY_TYPES) {
|
|
282
|
+
const count = s.byType[t] ?? 0;
|
|
283
|
+
if (count > 0) {
|
|
284
|
+
console.log(` ${t.padEnd(12)} ${count}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// ── by fidelity (with ASCII bar) ─────────────────────────────────────────
|
|
289
|
+
|
|
290
|
+
console.log("\nBY FIDELITY");
|
|
291
|
+
const fidelities = ["vivid", "clear", "faded", "gist"] as const;
|
|
292
|
+
for (const f of fidelities) {
|
|
293
|
+
const count = s.byFidelity[f];
|
|
294
|
+
const barLen = n > 0 ? Math.round((count / n) * 20) : 0;
|
|
295
|
+
const bar = "█".repeat(barLen);
|
|
296
|
+
console.log(` ${f.padEnd(6)} ${String(count).padStart(4)} ${bar}`);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ── significance ─────────────────────────────────────────────────────────
|
|
300
|
+
|
|
301
|
+
console.log("\nSIGNIFICANCE");
|
|
302
|
+
console.log(` average ${(s.avgSignificance * 100).toFixed(1)}%`);
|
|
303
|
+
if (s.atRisk > 0) {
|
|
304
|
+
console.log(
|
|
305
|
+
` at risk ${s.atRisk} node${s.atRisk === 1 ? "" : "s"} fading (significance < 15%)`,
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ── timeline ─────────────────────────────────────────────────────────────
|
|
310
|
+
|
|
311
|
+
console.log("\nTIMELINE");
|
|
312
|
+
const dateOpts: Intl.DateTimeFormatOptions = {
|
|
313
|
+
month: "short",
|
|
314
|
+
day: "numeric",
|
|
315
|
+
year: "numeric",
|
|
316
|
+
};
|
|
317
|
+
if (s.oldestCreated) {
|
|
318
|
+
console.log(
|
|
319
|
+
` oldest ${new Date(s.oldestCreated).toLocaleString("en-US", dateOpts)}`,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
if (s.newestCreated) {
|
|
323
|
+
console.log(
|
|
324
|
+
` newest ${new Date(s.newestCreated).toLocaleString("en-US", dateOpts)}`,
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
if (s.lastReinforced) {
|
|
328
|
+
console.log(
|
|
329
|
+
` reinforced ${new Date(s.lastReinforced).toLocaleString("en-US", {
|
|
330
|
+
...dateOpts,
|
|
331
|
+
hour: "numeric",
|
|
332
|
+
minute: "2-digit",
|
|
333
|
+
})}`,
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ── top nodes ────────────────────────────────────────────────────────────
|
|
338
|
+
|
|
339
|
+
if (s.topNodes.length > 0) {
|
|
340
|
+
console.log("\nTOP NODES BY SIGNIFICANCE");
|
|
341
|
+
const WIDTH = 60;
|
|
342
|
+
const trunc = (str: string) =>
|
|
343
|
+
str.length > WIDTH ? str.slice(0, WIDTH - 1) + "…" : str;
|
|
344
|
+
for (const node of s.topNodes) {
|
|
345
|
+
console.log(
|
|
346
|
+
` ${(node.significance * 100).toFixed(0).padStart(3)}% ${trunc(node.content)}`,
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
console.log("");
|
|
206
352
|
}
|
|
@@ -48,9 +48,9 @@ source channel, event name, and attention hints. The decision engine evaluates
|
|
|
48
48
|
whether and where to deliver the notification based on connected channels,
|
|
49
49
|
urgency, and user preferences.
|
|
50
50
|
|
|
51
|
-
Minimal usage: only --message is required. Add --urgent for a push +
|
|
52
|
-
flag in the
|
|
53
|
-
assistant.share when omitted.
|
|
51
|
+
Minimal usage: only --message is required. Add --urgent for a push +
|
|
52
|
+
visual flag in the Vellum Home feed. Source channel/event name fall back
|
|
53
|
+
to assistant_tool / assistant.share when omitted.
|
|
54
54
|
|
|
55
55
|
Examples:
|
|
56
56
|
$ assistant notifications send --message "Build finished"
|
|
@@ -71,7 +71,7 @@ Examples:
|
|
|
71
71
|
{
|
|
72
72
|
flags: "--urgent",
|
|
73
73
|
description:
|
|
74
|
-
"Mark this notification as urgent (fires push + visual flag in
|
|
74
|
+
"Mark this notification as urgent (fires push + visual flag in Vellum Home)",
|
|
75
75
|
defaultValue: false,
|
|
76
76
|
},
|
|
77
77
|
{
|
|
@@ -176,7 +176,7 @@ Examples:
|
|
|
176
176
|
{
|
|
177
177
|
name: "list",
|
|
178
178
|
description:
|
|
179
|
-
"List
|
|
179
|
+
"List Vellum Home feed notifications surfaced by the assistant. Excludes dismissed items by default.",
|
|
180
180
|
options: [
|
|
181
181
|
{
|
|
182
182
|
flags: "--all",
|
|
@@ -231,11 +231,11 @@ Examples:
|
|
|
231
231
|
},
|
|
232
232
|
],
|
|
233
233
|
helpText: `
|
|
234
|
-
Reads
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
234
|
+
Reads Vellum's Home feed at $VELLUM_WORKSPACE_DIR/data/home-feed.json.
|
|
235
|
+
Items are ordered by priority then recency, matching what the user sees
|
|
236
|
+
in the macOS Home page. This is only the assistant's Vellum notification
|
|
237
|
+
feed; it does not read email inboxes, Gmail, Outlook, or other external
|
|
238
|
+
message providers. Use OAuth/provider-specific commands for external mail.
|
|
239
239
|
|
|
240
240
|
Examples:
|
|
241
241
|
$ assistant notifications list
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
buildOAuthConnectSurfaceRedirect,
|
|
5
|
+
isModelSpawnedConversationShell,
|
|
6
|
+
oauthConnectSurfaceHint,
|
|
7
|
+
} from "./connect-surface-guidance.js";
|
|
8
|
+
|
|
9
|
+
describe("OAuth connect surface guidance", () => {
|
|
10
|
+
test("builds the oauth_connect next action payload", () => {
|
|
11
|
+
expect(buildOAuthConnectSurfaceRedirect("google")).toEqual({
|
|
12
|
+
ok: false,
|
|
13
|
+
code: "use_oauth_connect_surface",
|
|
14
|
+
provider: "google",
|
|
15
|
+
hint: oauthConnectSurfaceHint("google"),
|
|
16
|
+
nextAction: {
|
|
17
|
+
type: "ui_show",
|
|
18
|
+
surfaceType: "oauth_connect",
|
|
19
|
+
data: { providerKey: "google" },
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("detects model-spawned conversation shells", () => {
|
|
25
|
+
expect(
|
|
26
|
+
isModelSpawnedConversationShell({ __CONVERSATION_ID: "conv-123" }),
|
|
27
|
+
).toBe(true);
|
|
28
|
+
expect(isModelSpawnedConversationShell({ __CONVERSATION_ID: " " })).toBe(
|
|
29
|
+
false,
|
|
30
|
+
);
|
|
31
|
+
expect(isModelSpawnedConversationShell({})).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("hint tells the model not to paste OAuth URLs", () => {
|
|
35
|
+
const hint = oauthConnectSurfaceHint("google");
|
|
36
|
+
expect(hint).toContain('surface_type "oauth_connect"');
|
|
37
|
+
expect(hint).toContain('data.providerKey "google"');
|
|
38
|
+
expect(hint).toContain("paste an OAuth URL");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface OAuthConnectSurfaceNextAction {
|
|
2
|
+
type: "ui_show";
|
|
3
|
+
surfaceType: "oauth_connect";
|
|
4
|
+
data: { providerKey: string };
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface OAuthConnectSurfaceRedirect {
|
|
8
|
+
ok: false;
|
|
9
|
+
code: "use_oauth_connect_surface";
|
|
10
|
+
provider: string;
|
|
11
|
+
hint: string;
|
|
12
|
+
nextAction: OAuthConnectSurfaceNextAction;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function oauthConnectSurfaceHint(provider: string): string {
|
|
16
|
+
return (
|
|
17
|
+
`To let the user connect, render the connect button: call ` +
|
|
18
|
+
`\`ui_show\` with surface_type "oauth_connect" and ` +
|
|
19
|
+
`data.providerKey "${provider}". That surface is always available — do ` +
|
|
20
|
+
`not run further \`oauth\`/\`channels\` commands, paste an OAuth URL, or ` +
|
|
21
|
+
`load a setup skill just to display it.`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function buildOAuthConnectSurfaceNextAction(
|
|
26
|
+
provider: string,
|
|
27
|
+
): OAuthConnectSurfaceNextAction {
|
|
28
|
+
return {
|
|
29
|
+
type: "ui_show",
|
|
30
|
+
surfaceType: "oauth_connect",
|
|
31
|
+
data: { providerKey: provider },
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function buildOAuthConnectSurfaceRedirect(
|
|
36
|
+
provider: string,
|
|
37
|
+
): OAuthConnectSurfaceRedirect {
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
code: "use_oauth_connect_surface",
|
|
41
|
+
provider,
|
|
42
|
+
hint: oauthConnectSurfaceHint(provider),
|
|
43
|
+
nextAction: buildOAuthConnectSurfaceNextAction(provider),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isModelSpawnedConversationShell(
|
|
48
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
49
|
+
): boolean {
|
|
50
|
+
return (
|
|
51
|
+
typeof env.__CONVERSATION_ID === "string" &&
|
|
52
|
+
env.__CONVERSATION_ID.trim().length > 0
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
const ipcCalls: Array<{ method: string; params?: Record<string, unknown> }> =
|
|
4
|
+
[];
|
|
5
|
+
const openedUrls: string[] = [];
|
|
6
|
+
|
|
7
|
+
mock.module("../../../ipc/cli-client.js", () => ({
|
|
8
|
+
cliIpcCall: async (method: string, params?: Record<string, unknown>) => {
|
|
9
|
+
ipcCalls.push({ method, params });
|
|
10
|
+
if (method === "oauth_providers_by_providerKey_get") {
|
|
11
|
+
return {
|
|
12
|
+
ok: true,
|
|
13
|
+
result: {
|
|
14
|
+
provider: { authUrl: "https://accounts.example.com/oauth" },
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (method === "oauth_mode_get") {
|
|
19
|
+
return { ok: true, result: { ok: true, mode: "managed" } };
|
|
20
|
+
}
|
|
21
|
+
if (method === "oauth_managed_connect_start") {
|
|
22
|
+
return {
|
|
23
|
+
ok: true,
|
|
24
|
+
result: { ok: true, connect_url: "https://connect.example.com" },
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return { ok: false, error: `Unexpected IPC method ${method}` };
|
|
28
|
+
},
|
|
29
|
+
exitFromIpcResult: (r: { error?: string }) => {
|
|
30
|
+
throw new Error(r.error ?? "IPC error");
|
|
31
|
+
},
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
mock.module("../../lib/open-browser.js", () => ({
|
|
35
|
+
openInHostBrowser: (url: string) => {
|
|
36
|
+
openedUrls.push(url);
|
|
37
|
+
},
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
mock.module("../../logger.js", () => ({
|
|
41
|
+
getCliLogger: () => ({
|
|
42
|
+
info: () => {},
|
|
43
|
+
warn: () => {},
|
|
44
|
+
error: () => {},
|
|
45
|
+
debug: () => {},
|
|
46
|
+
}),
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
import { Command } from "commander";
|
|
50
|
+
|
|
51
|
+
import { applyCommandHelp } from "../../lib/cli-command-help.js";
|
|
52
|
+
import { registerConnectCommand } from "./connect.js";
|
|
53
|
+
import { oauthHelp } from "./index.help.js";
|
|
54
|
+
|
|
55
|
+
const originalConversationId = process.env.__CONVERSATION_ID;
|
|
56
|
+
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
ipcCalls.length = 0;
|
|
59
|
+
openedUrls.length = 0;
|
|
60
|
+
process.exitCode = 0;
|
|
61
|
+
process.env.__CONVERSATION_ID = "conv-123";
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
afterEach(() => {
|
|
65
|
+
if (originalConversationId === undefined) {
|
|
66
|
+
delete process.env.__CONVERSATION_ID;
|
|
67
|
+
} else {
|
|
68
|
+
process.env.__CONVERSATION_ID = originalConversationId;
|
|
69
|
+
}
|
|
70
|
+
process.exitCode = 0;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
async function runConnectCommand(): Promise<{
|
|
74
|
+
stdout: string;
|
|
75
|
+
exitCode: number;
|
|
76
|
+
}> {
|
|
77
|
+
const chunks: string[] = [];
|
|
78
|
+
const originalWrite = process.stdout.write;
|
|
79
|
+
process.stdout.write = ((chunk: string | Buffer) => {
|
|
80
|
+
chunks.push(typeof chunk === "string" ? chunk : chunk.toString());
|
|
81
|
+
return true;
|
|
82
|
+
}) as typeof process.stdout.write;
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const program = new Command();
|
|
86
|
+
program.exitOverride();
|
|
87
|
+
const oauth = program.command("oauth").description(oauthHelp.description);
|
|
88
|
+
applyCommandHelp(oauth, oauthHelp);
|
|
89
|
+
registerConnectCommand(oauth);
|
|
90
|
+
await program.parseAsync([
|
|
91
|
+
"node",
|
|
92
|
+
"test",
|
|
93
|
+
"oauth",
|
|
94
|
+
"--json",
|
|
95
|
+
"connect",
|
|
96
|
+
"google",
|
|
97
|
+
]);
|
|
98
|
+
} catch {
|
|
99
|
+
// Commander may throw under exitOverride for parse errors; the assertions
|
|
100
|
+
// below verify the command behavior we care about.
|
|
101
|
+
} finally {
|
|
102
|
+
process.stdout.write = originalWrite;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { stdout: chunks.join(""), exitCode: Number(process.exitCode ?? 0) };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
describe("oauth connect", () => {
|
|
109
|
+
test("managed provider in a conversation shell returns oauth_connect guidance without opening a browser", async () => {
|
|
110
|
+
const { stdout, exitCode } = await runConnectCommand();
|
|
111
|
+
|
|
112
|
+
expect(exitCode).toBe(1);
|
|
113
|
+
const parsed = JSON.parse(stdout) as Record<string, unknown>;
|
|
114
|
+
expect(parsed.code).toBe("use_oauth_connect_surface");
|
|
115
|
+
expect(parsed.nextAction).toEqual({
|
|
116
|
+
type: "ui_show",
|
|
117
|
+
surfaceType: "oauth_connect",
|
|
118
|
+
data: { providerKey: "google" },
|
|
119
|
+
});
|
|
120
|
+
expect(openedUrls).toEqual([]);
|
|
121
|
+
expect(ipcCalls.map((call) => call.method)).toEqual([
|
|
122
|
+
"oauth_providers_by_providerKey_get",
|
|
123
|
+
"oauth_mode_get",
|
|
124
|
+
]);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -5,6 +5,10 @@ import { subcommand } from "../../lib/cli-command-help.js";
|
|
|
5
5
|
import { openInHostBrowser } from "../../lib/open-browser.js";
|
|
6
6
|
import { getCliLogger } from "../../logger.js";
|
|
7
7
|
import { shouldOutputJson, writeOutput } from "../../output.js";
|
|
8
|
+
import {
|
|
9
|
+
buildOAuthConnectSurfaceRedirect,
|
|
10
|
+
isModelSpawnedConversationShell,
|
|
11
|
+
} from "./connect-surface-guidance.js";
|
|
8
12
|
|
|
9
13
|
const log = getCliLogger("cli");
|
|
10
14
|
|
|
@@ -125,7 +129,9 @@ export function registerConnectCommand(oauth: Command): void {
|
|
|
125
129
|
queryParams: { provider },
|
|
126
130
|
});
|
|
127
131
|
|
|
128
|
-
if (!modeResult.ok)
|
|
132
|
+
if (!modeResult.ok) {
|
|
133
|
+
return exitFromIpcResult(modeResult);
|
|
134
|
+
}
|
|
129
135
|
|
|
130
136
|
const managed = modeResult.result?.mode === "managed";
|
|
131
137
|
|
|
@@ -134,6 +140,13 @@ export function registerConnectCommand(oauth: Command): void {
|
|
|
134
140
|
// MANAGED PATH
|
|
135
141
|
// =============================================================
|
|
136
142
|
|
|
143
|
+
if (isModelSpawnedConversationShell()) {
|
|
144
|
+
const redirect = buildOAuthConnectSurfaceRedirect(provider);
|
|
145
|
+
writeOutput(cmd, redirect);
|
|
146
|
+
process.exitCode = 1;
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
137
150
|
if (opts.clientId) {
|
|
138
151
|
log.info(
|
|
139
152
|
`Warning: --client-id is ignored for platform-managed providers. The platform manages OAuth apps for "${provider}".`,
|
|
@@ -152,7 +165,9 @@ export function registerConnectCommand(oauth: Command): void {
|
|
|
152
165
|
body: startBody,
|
|
153
166
|
});
|
|
154
167
|
|
|
155
|
-
if (!startResult.ok)
|
|
168
|
+
if (!startResult.ok) {
|
|
169
|
+
return exitFromIpcResult(startResult);
|
|
170
|
+
}
|
|
156
171
|
|
|
157
172
|
const connectUrl = startResult.result!.connect_url;
|
|
158
173
|
|
|
@@ -169,7 +184,9 @@ export function registerConnectCommand(oauth: Command): void {
|
|
|
169
184
|
queryParams: { provider },
|
|
170
185
|
});
|
|
171
186
|
|
|
172
|
-
if (!snapshotResult.ok)
|
|
187
|
+
if (!snapshotResult.ok) {
|
|
188
|
+
return exitFromIpcResult(snapshotResult);
|
|
189
|
+
}
|
|
173
190
|
|
|
174
191
|
const snapshotIds = new Set(
|
|
175
192
|
(snapshotResult.result?.connections ?? []).map((e) => e.id),
|
|
@@ -207,7 +224,9 @@ export function registerConnectCommand(oauth: Command): void {
|
|
|
207
224
|
queryParams: { provider },
|
|
208
225
|
});
|
|
209
226
|
|
|
210
|
-
if (!currentResult.ok || !currentResult.result)
|
|
227
|
+
if (!currentResult.ok || !currentResult.result) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
211
230
|
|
|
212
231
|
const found = currentResult.result.connections.find(
|
|
213
232
|
(e) => !snapshotIds.has(e.id),
|
|
@@ -282,8 +301,12 @@ export function registerConnectCommand(oauth: Command): void {
|
|
|
282
301
|
service: provider,
|
|
283
302
|
callbackTransport: opts.callbackTransport,
|
|
284
303
|
};
|
|
285
|
-
if (opts.clientId)
|
|
286
|
-
|
|
304
|
+
if (opts.clientId) {
|
|
305
|
+
startBody.clientId = opts.clientId;
|
|
306
|
+
}
|
|
307
|
+
if (opts.scopes) {
|
|
308
|
+
startBody.requestedScopes = opts.scopes;
|
|
309
|
+
}
|
|
287
310
|
|
|
288
311
|
const startResult = await cliIpcCall<{
|
|
289
312
|
auth_url: string;
|
|
@@ -655,7 +655,7 @@ Examples:
|
|
|
655
655
|
name: "connect",
|
|
656
656
|
args: "<provider>",
|
|
657
657
|
description:
|
|
658
|
-
"Initiate
|
|
658
|
+
"Initiate a terminal/headless OAuth authorization flow for a specified provider",
|
|
659
659
|
options: [
|
|
660
660
|
{
|
|
661
661
|
flags: "--scopes <scopes...>",
|
|
@@ -687,6 +687,12 @@ By default, the browser opens automatically and the command waits for
|
|
|
687
687
|
completion. Use --no-browser to print the URL instead (useful for headless
|
|
688
688
|
or SSH sessions).
|
|
689
689
|
|
|
690
|
+
Important for chat/UI turns: do not run this command just to let the user
|
|
691
|
+
connect a managed provider. Render the first-class connect surface instead:
|
|
692
|
+
call \`ui_show\` with surface_type "oauth_connect" and data.providerKey set to
|
|
693
|
+
the provider (for example, "google"). That surface starts the managed OAuth UI
|
|
694
|
+
and avoids pasting raw authorization links into the conversation.
|
|
695
|
+
|
|
690
696
|
Examples:
|
|
691
697
|
$ assistant oauth connect google
|
|
692
698
|
$ assistant oauth connect google --no-browser
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { oauthHelp } from "./index.help.js";
|
|
4
|
+
import { decorateStatusJsonForModel, noConnectionsMessage } from "./status.js";
|
|
4
5
|
|
|
5
6
|
const original = process.env.__RESOLVED_MODEL;
|
|
6
7
|
|
|
7
8
|
afterEach(() => {
|
|
8
|
-
if (original === undefined)
|
|
9
|
-
|
|
9
|
+
if (original === undefined) {
|
|
10
|
+
delete process.env.__RESOLVED_MODEL;
|
|
11
|
+
} else {
|
|
12
|
+
process.env.__RESOLVED_MODEL = original;
|
|
13
|
+
}
|
|
10
14
|
});
|
|
11
15
|
|
|
12
16
|
describe("noConnectionsMessage", () => {
|
|
@@ -31,6 +35,68 @@ describe("noConnectionsMessage", () => {
|
|
|
31
35
|
const msg = await noConnectionsMessage("google");
|
|
32
36
|
expect(msg).toContain('surface_type "oauth_connect"');
|
|
33
37
|
expect(msg).toContain('data.providerKey "google"');
|
|
38
|
+
expect(msg).toContain("paste an OAuth URL");
|
|
34
39
|
expect(msg).not.toContain("assistant oauth connect google");
|
|
35
40
|
});
|
|
41
|
+
|
|
42
|
+
test("weak open models are not steered to oauth_connect for BYO mode", async () => {
|
|
43
|
+
process.env.__RESOLVED_MODEL = "accounts/fireworks/models/minimax-m3";
|
|
44
|
+
const msg = await noConnectionsMessage("google", "byo");
|
|
45
|
+
expect(msg).not.toContain('surface_type "oauth_connect"');
|
|
46
|
+
expect(msg).toContain("assistant oauth connect google");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("weak open model JSON status includes oauth_connect next action", async () => {
|
|
50
|
+
process.env.__RESOLVED_MODEL = "accounts/fireworks/models/glm-5p2";
|
|
51
|
+
const result = await decorateStatusJsonForModel({
|
|
52
|
+
ok: true,
|
|
53
|
+
provider: "google",
|
|
54
|
+
mode: "managed",
|
|
55
|
+
connections: [],
|
|
56
|
+
});
|
|
57
|
+
expect(result.hint).toContain('surface_type "oauth_connect"');
|
|
58
|
+
expect(result.hint).toContain("paste an OAuth URL");
|
|
59
|
+
expect(result.nextAction).toEqual({
|
|
60
|
+
type: "ui_show",
|
|
61
|
+
surfaceType: "oauth_connect",
|
|
62
|
+
data: { providerKey: "google" },
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("weak open model JSON status stays compact for BYO mode", async () => {
|
|
67
|
+
process.env.__RESOLVED_MODEL = "accounts/fireworks/models/glm-5p2";
|
|
68
|
+
const result = await decorateStatusJsonForModel({
|
|
69
|
+
ok: true,
|
|
70
|
+
provider: "google",
|
|
71
|
+
mode: "byo",
|
|
72
|
+
connections: [],
|
|
73
|
+
});
|
|
74
|
+
expect(result.hint).toBeUndefined();
|
|
75
|
+
expect(result.nextAction).toBeUndefined();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("capable model JSON status stays compact", async () => {
|
|
79
|
+
process.env.__RESOLVED_MODEL = "claude-opus-4-8";
|
|
80
|
+
const result = await decorateStatusJsonForModel({
|
|
81
|
+
ok: true,
|
|
82
|
+
provider: "google",
|
|
83
|
+
mode: "managed",
|
|
84
|
+
connections: [],
|
|
85
|
+
});
|
|
86
|
+
expect(result.hint).toBeUndefined();
|
|
87
|
+
expect(result.nextAction).toBeUndefined();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("oauth connect help", () => {
|
|
92
|
+
test("steers chat turns to the oauth_connect surface", () => {
|
|
93
|
+
const connectHelp = oauthHelp.subcommands?.find(
|
|
94
|
+
(command) => command.name === "connect",
|
|
95
|
+
);
|
|
96
|
+
expect(connectHelp?.description).toContain("terminal/headless");
|
|
97
|
+
expect(connectHelp?.helpText).toContain('surface_type "oauth_connect"');
|
|
98
|
+
expect(connectHelp?.helpText).toContain(
|
|
99
|
+
"avoids pasting raw authorization links",
|
|
100
|
+
);
|
|
101
|
+
});
|
|
36
102
|
});
|