@vellumai/assistant 0.9.1-staging.1 → 0.10.0-staging.2
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/docs/activation-funnel-telemetry.md +24 -18
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +15 -0
- package/openapi.yaml +852 -15
- package/package.json +1 -1
- package/src/__tests__/access-request-card-view.test.ts +98 -0
- package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +59 -7
- package/src/__tests__/agent-loop-compaction-strip.test.ts +17 -16
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
- package/src/__tests__/app-compiler.test.ts +15 -1
- package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
- package/src/__tests__/call-pointer-messages.test.ts +28 -0
- package/src/__tests__/cancel-clears-processing.test.ts +89 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -4
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
- package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
- package/src/__tests__/config-loader-backfill.test.ts +174 -30
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +0 -6
- package/src/__tests__/contacts-tools.test.ts +29 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +58 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-lifecycle.test.ts +7 -9
- package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
- package/src/__tests__/conversation-title-service.test.ts +62 -0
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
- package/src/__tests__/credential-prompt-route.test.ts +1 -0
- package/src/__tests__/credential-security-invariants.test.ts +2 -0
- package/src/__tests__/disk-pressure-policy.test.ts +12 -0
- package/src/__tests__/disk-usage.test.ts +65 -0
- package/src/__tests__/dynamic-page-surface.test.ts +51 -0
- package/src/__tests__/gateway-flag-listener.test.ts +110 -1
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
- package/src/__tests__/guardian-grant-minting.test.ts +3 -35
- package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
- package/src/__tests__/guardian-routing-state.test.ts +0 -1
- package/src/__tests__/headless-browser-mode.test.ts +10 -0
- package/src/__tests__/headless-browser-navigate.test.ts +8 -3
- package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
- package/src/__tests__/host-browser-proxy.test.ts +87 -0
- package/src/__tests__/injector-v3-suppression.test.ts +27 -20
- package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
- package/src/__tests__/invite-redemption-service.test.ts +0 -3
- package/src/__tests__/llm-catalog-parity.test.ts +30 -1
- package/src/__tests__/llm-resolver.test.ts +21 -0
- package/src/__tests__/llm-schema.test.ts +1 -0
- package/src/__tests__/managed-profile-guard.test.ts +163 -4
- package/src/__tests__/mcp-health-check.test.ts +6 -7
- package/src/__tests__/media-stream-server-integration.test.ts +317 -13
- package/src/__tests__/path-policy.test.ts +34 -0
- package/src/__tests__/persona-resolver.test.ts +38 -0
- package/src/__tests__/plugin-api-provider.test.ts +24 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
- package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
- package/src/__tests__/reaction-persistence.test.ts +150 -29
- package/src/__tests__/relay-server.test.ts +285 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
- package/src/__tests__/skill-execute-input.test.ts +5 -0
- package/src/__tests__/skills.test.ts +51 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
- package/src/__tests__/subagent-tools.test.ts +150 -0
- package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +100 -3
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
- package/src/__tests__/tool-audit-listener.test.ts +7 -7
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
- package/src/__tests__/trusted-contact-verification.test.ts +2 -4
- package/src/__tests__/twilio-routes.test.ts +81 -1
- package/src/__tests__/voice-invite-redemption.test.ts +0 -1
- package/src/__tests__/weak-open-model.test.ts +30 -0
- package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
- package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
- package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
- package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
- package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
- package/src/agent/loop.ts +33 -33
- package/src/api/events/tool-result.ts +6 -0
- package/src/api/events/workflow-completed.ts +53 -0
- package/src/api/events/workflow-leaf-finished.ts +38 -0
- package/src/api/events/workflow-leaf-started.ts +35 -0
- package/src/api/events/workflow-progress.ts +32 -0
- package/src/api/events/workflow-started.ts +31 -0
- package/src/api/index.ts +40 -0
- package/src/api/responses/conversation-message.ts +26 -0
- package/src/api/responses/home.ts +26 -0
- package/src/api/responses/workflow-journal.ts +53 -0
- package/src/approvals/guardian-card-withdrawal.ts +145 -0
- package/src/approvals/guardian-decision-primitive.ts +26 -3
- package/src/approvals/guardian-request-resolvers.ts +181 -78
- package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
- package/src/calls/call-pointer-messages.ts +10 -4
- package/src/calls/channel-admission-reader.ts +104 -0
- package/src/calls/guardian-dispatch.ts +17 -45
- package/src/calls/media-stream-server.ts +84 -2
- package/src/calls/relay-server.ts +66 -0
- package/src/calls/relay-setup-router.ts +82 -1
- package/src/calls/twilio-routes.ts +17 -8
- package/src/cli/commands/clients.ts +3 -0
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
- package/src/cli/commands/memory/index.ts +30 -0
- package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
- package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
- package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
- package/src/cli/commands/oauth/status.test.ts +36 -0
- package/src/cli/commands/oauth/status.ts +23 -3
- package/src/cli/commands/plugins.ts +57 -5
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +134 -4
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +53 -11
- package/src/cli/lib/inspect-plugin.ts +12 -1
- package/src/cli/lib/merge-plugin-tree.ts +149 -49
- package/src/cli/lib/plugin-surfaces.ts +104 -0
- package/src/cli/lib/upgrade-plugin.ts +64 -36
- package/src/cli/program.ts +2 -4
- package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
- package/src/config/assistant-feature-flags.ts +22 -7
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
- package/src/config/bundled-skills/messaging/SKILL.md +6 -4
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
- package/src/config/bundled-skills/workflows/SKILL.md +14 -7
- package/src/config/call-site-defaults.ts +3 -0
- package/src/config/feature-flag-registry.json +49 -18
- package/src/config/llm-resolver.ts +3 -0
- package/src/config/memory-v3-gate.ts +11 -0
- package/src/config/schema.ts +8 -6
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/channels.ts +11 -0
- package/src/config/schemas/llm.ts +31 -0
- package/src/config/schemas/memory-lifecycle.ts +3 -7
- package/src/config/schemas/memory-v3.ts +6 -0
- package/src/config/schemas/services.ts +18 -0
- package/src/config/seed-inference-profiles.ts +94 -34
- package/src/config/skills.ts +21 -0
- package/src/config/sync-gated-profiles.ts +220 -0
- package/src/contacts/contact-store.ts +2 -10
- package/src/contacts/contacts-write.ts +1 -2
- package/src/contacts/types.ts +0 -1
- package/src/context/compactor.ts +86 -52
- package/src/context/strip-injections.ts +58 -10
- package/src/context/token-estimator.ts +1 -1
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
- package/src/daemon/conversation-agent-loop.ts +100 -19
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +3 -5
- package/src/daemon/conversation-process.ts +13 -5
- package/src/daemon/conversation-runtime-assembly.ts +13 -15
- package/src/daemon/conversation-surfaces.ts +26 -0
- package/src/daemon/conversation-tool-setup.ts +16 -11
- package/src/daemon/conversation.ts +64 -14
- package/src/daemon/disk-pressure-policy.ts +5 -3
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
- package/src/daemon/handlers/config-a2a.ts +0 -2
- package/src/daemon/handlers/config-channels.ts +5 -10
- package/src/daemon/handlers/config-slack-channel.ts +20 -0
- package/src/daemon/handlers/conversations.ts +107 -0
- package/src/daemon/host-browser-proxy.ts +41 -0
- package/src/daemon/lifecycle.ts +55 -20
- package/src/daemon/message-provenance.ts +2 -0
- package/src/daemon/message-types/contacts.ts +0 -1
- package/src/daemon/message-types/web-activity.ts +7 -1
- package/src/daemon/message-types/workflows.ts +83 -1
- package/src/daemon/tool-setup-types.ts +4 -0
- package/src/daemon/trust-context.ts +1 -1
- package/src/events/tool-audit-listener.ts +2 -2
- package/src/home/feed-source-enrichment.test.ts +151 -0
- package/src/home/feed-source-enrichment.ts +176 -0
- package/src/instrument.ts +18 -6
- package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
- package/src/ipc/assistant-server.ts +37 -4
- package/src/ipc/gateway-flag-listener.ts +18 -2
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
- package/src/memory/__tests__/memory-retrospective-job.test.ts +34 -0
- package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
- package/src/memory/auth-fallback-events-store.ts +2 -2
- package/src/memory/auto-analysis-enqueue.ts +3 -5
- package/src/memory/canonical-guardian-store.ts +39 -1
- package/src/memory/conversation-crud.ts +9 -4
- package/src/memory/conversation-key-store.ts +17 -2
- package/src/memory/conversation-title-service.ts +64 -7
- package/src/memory/db-init.ts +10 -0
- package/src/memory/embedding-backend.ts +15 -1
- package/src/memory/jobs-worker.ts +2 -1
- package/src/memory/lifecycle-events-store.ts +2 -2
- package/src/memory/memory-retrospective-enqueue.ts +31 -6
- package/src/memory/memory-retrospective-job.ts +9 -0
- package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
- package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
- package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
- package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +10 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
- package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
- package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
- package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
- package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
- package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
- package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +30 -0
- package/src/memory/migrations/index.ts +5 -0
- package/src/memory/onboarding-events-store.ts +3 -3
- package/src/memory/schema/contacts.ts +0 -1
- package/src/memory/skill-loaded-events-store.test.ts +7 -15
- package/src/memory/skill-loaded-events-store.ts +2 -2
- package/src/memory/tool-executed-events-store.test.ts +7 -7
- package/src/memory/turn-trace-store.test.ts +736 -0
- package/src/memory/turn-trace-store.ts +364 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
- package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
- package/src/memory/v2/consolidation-job.ts +2 -2
- package/src/memory/v2/skill-content.ts +25 -7
- package/src/memory/v2/skill-store.ts +7 -1
- package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
- package/src/memory/v3-eval/eval-packets.ts +546 -0
- package/src/messaging/providers/slack/api.ts +31 -0
- package/src/messaging/providers/slack/send.test.ts +114 -2
- package/src/messaging/providers/slack/send.ts +30 -7
- package/src/messaging/providers/slack/withdraw.test.ts +200 -0
- package/src/messaging/providers/slack/withdraw.ts +161 -0
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/access-request-copy.ts +72 -59
- package/src/notifications/adapters/slack.ts +55 -73
- package/src/notifications/approval-card-data.ts +333 -0
- package/src/notifications/broadcaster.ts +6 -2
- package/src/notifications/canonical-delivery-recorder.ts +139 -0
- package/src/notifications/copy-composer.ts +3 -3
- package/src/notifications/decision-engine.ts +4 -2
- package/src/notifications/destination-resolver.ts +4 -6
- package/src/notifications/guardian-question-mode.ts +10 -0
- package/src/notifications/home-feed-side-effect.ts +3 -13
- package/src/notifications/notification-utils.ts +2 -1
- package/src/notifications/signal.ts +79 -43
- package/src/notifications/types.ts +98 -128
- package/src/permissions/checker.test.ts +51 -0
- package/src/permissions/checker.ts +185 -26
- package/src/permissions/ipc-risk-types.ts +24 -0
- package/src/permissions/question-prompter.test.ts +27 -0
- package/src/permissions/question-prompter.ts +4 -0
- package/src/platform/client.test.ts +119 -0
- package/src/platform/client.ts +66 -0
- package/src/platform/consent-cache.test.ts +267 -0
- package/src/platform/consent-cache.ts +174 -0
- package/src/plugin-api/index.ts +27 -0
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
- package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
- package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
- package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
- package/src/plugins/defaults/advisor/config.ts +21 -0
- package/src/plugins/defaults/advisor/consult.ts +93 -0
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/advisor/package.json +14 -0
- package/src/plugins/defaults/advisor/steering.ts +67 -0
- package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
- package/src/plugins/defaults/advisor/transcript.ts +76 -0
- package/src/plugins/defaults/index.ts +35 -0
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +75 -7
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +37 -4
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +2 -12
- package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
- package/src/prompts/persona-resolver.ts +12 -2
- package/src/prompts/templates/system-sections.ts +7 -2
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
- package/src/providers/__tests__/retry-callsite.test.ts +176 -0
- package/src/providers/atlascloud/client.ts +85 -0
- package/src/providers/fetch-provider-catalog.ts +85 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/model-catalog.ts +58 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
- package/src/providers/openai/chat-completions-provider.ts +7 -0
- package/src/providers/openai/responses-provider.ts +10 -0
- package/src/providers/provider-send-message.ts +11 -3
- package/src/providers/retry.ts +53 -12
- package/src/providers/search-provider-catalog.ts +10 -0
- package/src/providers/weak-open-model.ts +22 -0
- package/src/runtime/__tests__/agent-wake.test.ts +181 -0
- package/src/runtime/__tests__/client-health.test.ts +44 -0
- package/src/runtime/access-request-helper.ts +21 -53
- package/src/runtime/actor-trust-resolver.ts +49 -21
- package/src/runtime/agent-wake.ts +52 -0
- package/src/runtime/assistant-event-hub.ts +18 -4
- package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
- package/src/runtime/auth/require-bound-guardian.ts +1 -4
- package/src/runtime/capabilities.test.ts +120 -0
- package/src/runtime/capabilities.ts +197 -0
- package/src/runtime/channel-approval-types.ts +5 -1
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/channel-verification-service.ts +1 -2
- package/src/runtime/client-health.ts +26 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
- package/src/runtime/effective-capabilities.test.ts +128 -0
- package/src/runtime/effective-capabilities.ts +84 -0
- package/src/runtime/guardian-reply-router.ts +106 -21
- package/src/runtime/invite-redemption-service.ts +6 -22
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +123 -0
- package/src/runtime/migrations/vbundle-builder.ts +49 -20
- package/src/runtime/pending-interactions.ts +15 -0
- package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +35 -13
- package/src/runtime/routes/browser-tabs-routes.ts +9 -0
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
- package/src/runtime/routes/client-routes.ts +10 -0
- package/src/runtime/routes/contact-routes.ts +31 -8
- package/src/runtime/routes/conversation-management-routes.ts +80 -1
- package/src/runtime/routes/conversation-query-routes.ts +68 -22
- package/src/runtime/routes/conversation-routes.ts +37 -12
- package/src/runtime/routes/events-routes.ts +1 -3
- package/src/runtime/routes/guardian-approval-interception.ts +14 -73
- package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
- package/src/runtime/routes/home-feed-routes.ts +8 -3
- package/src/runtime/routes/inbound-message-handler.ts +214 -228
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +88 -6
- package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
- package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
- package/src/runtime/routes/integrations/slack/channel.ts +36 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
- package/src/runtime/routes/mcp-auth-routes.ts +233 -41
- package/src/runtime/routes/memory-eval-routes.ts +87 -0
- package/src/runtime/routes/notification-routes.ts +122 -133
- package/src/runtime/routes/platform-routes.ts +2 -2
- package/src/runtime/routes/plugins-routes.ts +40 -7
- package/src/runtime/routes/secret-routes.ts +10 -0
- package/src/runtime/routes/surface-action-routes.ts +2 -1
- package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
- package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
- package/src/runtime/routes/workflow-routes.test.ts +225 -1
- package/src/runtime/routes/workflow-routes.ts +131 -1
- package/src/runtime/tool-grant-request-helper.ts +18 -16
- package/src/runtime/trust-context-resolver.ts +8 -5
- package/src/schedule/schedule-store.ts +1 -1
- package/src/schedule/scheduler-types.ts +5 -1
- package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
- package/src/security/secret-patterns.ts +3 -0
- package/src/subagent/manager.ts +11 -4
- package/src/telemetry/trace-collection-policy.test.ts +28 -0
- package/src/telemetry/trace-collection-policy.ts +30 -0
- package/src/telemetry/types.ts +89 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
- package/src/telemetry/usage-telemetry-reporter.ts +148 -41
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
- package/src/tools/browser/browser-execution.ts +29 -18
- package/src/tools/document/document-tool.ts +2 -3
- package/src/tools/executor.ts +5 -3
- package/src/tools/host-terminal/host-shell.ts +5 -4
- package/src/tools/memory/register.ts +2 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
- package/src/tools/network/__tests__/web-search.test.ts +143 -0
- package/src/tools/network/web-fetch.ts +372 -1
- package/src/tools/network/web-search.ts +213 -10
- package/src/tools/permission-checker.ts +3 -2
- package/src/tools/registry.ts +20 -0
- package/src/tools/schedule/create.ts +4 -3
- package/src/tools/schedule/update.ts +2 -1
- package/src/tools/shared/filesystem/path-policy.ts +39 -13
- package/src/tools/skills/execute.ts +1 -2
- package/src/tools/subagent/spawn.ts +37 -13
- package/src/tools/terminal/shell.ts +10 -4
- package/src/tools/tool-approval-handler.ts +17 -10
- package/src/tools/types.ts +9 -0
- package/src/tools/ui-surface/definitions.ts +25 -2
- package/src/tools/verification-control-plane-policy.ts +3 -1
- package/src/tools/workflows/run-workflow.ts +1 -0
- package/src/util/disk-usage.ts +78 -23
- package/src/util/platform.ts +8 -1
- package/src/watcher/telemetry.ts +2 -2
- package/src/workflows/engine.test.ts +175 -1
- package/src/workflows/engine.ts +82 -0
- package/src/workflows/journal-store.test.ts +70 -0
- package/src/workflows/journal-store.ts +18 -3
- package/src/workflows/run-manager.test.ts +171 -3
- package/src/workflows/run-manager.ts +64 -0
- package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
- package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
- package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
- package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/notifications/tool-approval-copy.ts +0 -142
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getLogger } from "../../util/logger.js";
|
|
2
|
+
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
|
|
4
|
+
const log = getLogger("migration-295");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Drops the `approval_prompt_ts_tracker` table.
|
|
8
|
+
*
|
|
9
|
+
* Guardian approval-by-reaction no longer scopes reactions through a bespoke
|
|
10
|
+
* `(channel, chat, ts)` tracker. The canonical guardian delivery record
|
|
11
|
+
* (`canonical_guardian_deliveries.destination_message_id`) is now the single
|
|
12
|
+
* mapping from a delivered approval card to its request, so this table is dead.
|
|
13
|
+
*
|
|
14
|
+
* Idempotent: `DROP TABLE IF EXISTS` is a no-op once the table is gone.
|
|
15
|
+
*/
|
|
16
|
+
export function dropApprovalPromptTsTrackerTable(database: DrizzleDb): void {
|
|
17
|
+
const raw = getSqliteFrom(database);
|
|
18
|
+
raw.run("DROP TABLE IF EXISTS approval_prompt_ts_tracker");
|
|
19
|
+
log.info("Dropped approval_prompt_ts_tracker table");
|
|
20
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { existsSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { Database } from "bun:sqlite";
|
|
3
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
4
|
+
|
|
5
|
+
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
6
|
+
|
|
7
|
+
import { getWorkspaceConfigPath } from "../../util/platform.js";
|
|
8
|
+
import * as schema from "../schema.js";
|
|
9
|
+
import { migrateRewriteBalancedEconomyProfilePins } from "./296-rewrite-balanced-economy-profile-pins.js";
|
|
10
|
+
|
|
11
|
+
function writeWorkspaceConfig(config: Record<string, unknown>): void {
|
|
12
|
+
writeFileSync(getWorkspaceConfigPath(), JSON.stringify(config));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
const path = getWorkspaceConfigPath();
|
|
17
|
+
if (existsSync(path)) rmSync(path);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
function createTestDb(withColumns = true) {
|
|
21
|
+
const sqlite = new Database(":memory:");
|
|
22
|
+
sqlite.exec(/*sql*/ `
|
|
23
|
+
CREATE TABLE conversations (
|
|
24
|
+
id TEXT PRIMARY KEY
|
|
25
|
+
${withColumns ? ", inference_profile TEXT" : ""}
|
|
26
|
+
)
|
|
27
|
+
`);
|
|
28
|
+
sqlite.exec(/*sql*/ `
|
|
29
|
+
CREATE TABLE cron_jobs (
|
|
30
|
+
id TEXT PRIMARY KEY
|
|
31
|
+
${withColumns ? ", inference_profile TEXT" : ""}
|
|
32
|
+
)
|
|
33
|
+
`);
|
|
34
|
+
return { sqlite, db: drizzle(sqlite, { schema }) };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function pin(sqlite: Database, table: string, id: string): string | null {
|
|
38
|
+
return (
|
|
39
|
+
sqlite
|
|
40
|
+
.query(`SELECT inference_profile FROM ${table} WHERE id = ?`)
|
|
41
|
+
.get(id) as { inference_profile: string | null }
|
|
42
|
+
).inference_profile;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe("migration 296: rewrite balanced-economy profile pins", () => {
|
|
46
|
+
test("rewrites balanced-economy pins to balanced on conversations and schedules", () => {
|
|
47
|
+
const { sqlite, db } = createTestDb();
|
|
48
|
+
sqlite.run(
|
|
49
|
+
`INSERT INTO conversations (id, inference_profile) VALUES ('c1', 'balanced-economy'), ('c2', 'quality-optimized'), ('c3', NULL)`,
|
|
50
|
+
);
|
|
51
|
+
sqlite.run(
|
|
52
|
+
`INSERT INTO cron_jobs (id, inference_profile) VALUES ('j1', 'balanced-economy'), ('j2', 'balanced')`,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
migrateRewriteBalancedEconomyProfilePins(db);
|
|
56
|
+
|
|
57
|
+
expect(pin(sqlite, "conversations", "c1")).toBe("balanced");
|
|
58
|
+
// Unrelated pins and NULLs are left untouched.
|
|
59
|
+
expect(pin(sqlite, "conversations", "c2")).toBe("quality-optimized");
|
|
60
|
+
expect(pin(sqlite, "conversations", "c3")).toBeNull();
|
|
61
|
+
expect(pin(sqlite, "cron_jobs", "j1")).toBe("balanced");
|
|
62
|
+
expect(pin(sqlite, "cron_jobs", "j2")).toBe("balanced");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("is idempotent — re-run is a no-op", () => {
|
|
66
|
+
const { sqlite, db } = createTestDb();
|
|
67
|
+
sqlite.run(
|
|
68
|
+
`INSERT INTO conversations (id, inference_profile) VALUES ('c1', 'balanced-economy')`,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
migrateRewriteBalancedEconomyProfilePins(db);
|
|
72
|
+
expect(() => migrateRewriteBalancedEconomyProfilePins(db)).not.toThrow();
|
|
73
|
+
expect(pin(sqlite, "conversations", "c1")).toBe("balanced");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("skips a table that has no inference_profile column", () => {
|
|
77
|
+
const { db } = createTestDb(false);
|
|
78
|
+
expect(() => migrateRewriteBalancedEconomyProfilePins(db)).not.toThrow();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("leaves pins alone when balanced-economy is a user-owned profile", () => {
|
|
82
|
+
// The workspace migration keeps a user-owned profile of this name, so its
|
|
83
|
+
// pins still resolve and must not be switched to balanced.
|
|
84
|
+
writeWorkspaceConfig({
|
|
85
|
+
llm: { profiles: { "balanced-economy": { source: "user" } } },
|
|
86
|
+
});
|
|
87
|
+
const { sqlite, db } = createTestDb();
|
|
88
|
+
sqlite.run(
|
|
89
|
+
`INSERT INTO conversations (id, inference_profile) VALUES ('c1', 'balanced-economy')`,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
migrateRewriteBalancedEconomyProfilePins(db);
|
|
93
|
+
|
|
94
|
+
expect(pin(sqlite, "conversations", "c1")).toBe("balanced-economy");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test("rewrites pins when balanced-economy is the managed profile in config", () => {
|
|
98
|
+
writeWorkspaceConfig({
|
|
99
|
+
llm: { profiles: { "balanced-economy": { source: "managed" } } },
|
|
100
|
+
});
|
|
101
|
+
const { sqlite, db } = createTestDb();
|
|
102
|
+
sqlite.run(
|
|
103
|
+
`INSERT INTO conversations (id, inference_profile) VALUES ('c1', 'balanced-economy')`,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
migrateRewriteBalancedEconomyProfilePins(db);
|
|
107
|
+
|
|
108
|
+
expect(pin(sqlite, "conversations", "c1")).toBe("balanced");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { loadRawConfig } from "../../config/loader.js";
|
|
2
|
+
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
|
|
4
|
+
const OLD_PROFILE = "balanced-economy";
|
|
5
|
+
const NEW_PROFILE = "balanced";
|
|
6
|
+
|
|
7
|
+
// Active inference-profile pin columns: the per-conversation override and the
|
|
8
|
+
// per-schedule override. Audit/telemetry tables (tool_invocations,
|
|
9
|
+
// llm_usage_events, skill_loaded_events) also carry an `inference_profile`, but
|
|
10
|
+
// those record what actually ran and must keep their historical value.
|
|
11
|
+
const PIN_TABLES = ["conversations", "cron_jobs"] as const;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Rewrite persisted `balanced-economy` inference-profile pins to `balanced`.
|
|
15
|
+
*
|
|
16
|
+
* The managed `balanced-economy` profile folds into `balanced` (both resolve to
|
|
17
|
+
* MiniMax M3 on Fireworks). The workspace-config migration removes the profile
|
|
18
|
+
* definition, but a profile key can also be pinned outside config.json — on a
|
|
19
|
+
* conversation (`conversations.inference_profile`) or a schedule
|
|
20
|
+
* (`cron_jobs.inference_profile`). Left unrewritten those pins dangle, and
|
|
21
|
+
* `resolveCallSiteConfig` treats an unresolvable override as a silent
|
|
22
|
+
* fall-through to the active/default profile — dropping the user's intended
|
|
23
|
+
* MiniMax route. `balanced-economy` is a reserved managed-profile key, so every
|
|
24
|
+
* persisted pin refers to the now-folded profile.
|
|
25
|
+
*
|
|
26
|
+
* Ownership guard: the companion workspace migration keeps a `balanced-economy`
|
|
27
|
+
* profile the user owns (`source !== "managed"`) intact, so its pins still
|
|
28
|
+
* resolve and must not be touched. Memory migrations run before workspace
|
|
29
|
+
* migrations on boot, so the profile is still in config here either way; gate on
|
|
30
|
+
* its source rather than its presence. A reserved managed key (or no profile at
|
|
31
|
+
* all) means every pin is stale and safe to rewrite.
|
|
32
|
+
*
|
|
33
|
+
* Idempotent: the WHERE clause matches nothing once rewritten. The PRAGMA guard
|
|
34
|
+
* skips a table an install hasn't created the column on yet.
|
|
35
|
+
*/
|
|
36
|
+
export function migrateRewriteBalancedEconomyProfilePins(
|
|
37
|
+
database: DrizzleDb,
|
|
38
|
+
): void {
|
|
39
|
+
if (isUserOwnedEconomyProfile()) return;
|
|
40
|
+
|
|
41
|
+
const raw = getSqliteFrom(database);
|
|
42
|
+
|
|
43
|
+
for (const table of PIN_TABLES) {
|
|
44
|
+
const cols = raw.prepare(`PRAGMA table_info(${table})`).all() as {
|
|
45
|
+
name: string;
|
|
46
|
+
}[];
|
|
47
|
+
if (!cols.some((c) => c.name === "inference_profile")) continue;
|
|
48
|
+
|
|
49
|
+
raw
|
|
50
|
+
.prepare(
|
|
51
|
+
`UPDATE ${table} SET inference_profile = ? WHERE inference_profile = ?`,
|
|
52
|
+
)
|
|
53
|
+
.run(NEW_PROFILE, OLD_PROFILE);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** True when `balanced-economy` exists in config as a user-owned profile. */
|
|
58
|
+
function isUserOwnedEconomyProfile(): boolean {
|
|
59
|
+
const llm = asObject(loadRawConfig().llm);
|
|
60
|
+
const profile = asObject(asObject(llm?.profiles)?.[OLD_PROFILE]);
|
|
61
|
+
return profile !== null && profile.source !== "managed";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function asObject(value: unknown): Record<string, unknown> | null {
|
|
65
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
66
|
+
? (value as Record<string, unknown>)
|
|
67
|
+
: null;
|
|
68
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { describe, expect, test } from "bun:test";
|
|
3
|
+
|
|
4
|
+
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
5
|
+
|
|
6
|
+
import { getSqliteFrom } from "../../db-connection.js";
|
|
7
|
+
import * as schema from "../../schema.js";
|
|
8
|
+
import { migrateDropLegacyMemberGuardianTables } from "../131-drop-legacy-member-guardian-tables.js";
|
|
9
|
+
|
|
10
|
+
function createTestDb() {
|
|
11
|
+
const sqlite = new Database(":memory:");
|
|
12
|
+
sqlite.exec("PRAGMA journal_mode=WAL");
|
|
13
|
+
return drizzle(sqlite, { schema });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function bootstrap(db: ReturnType<typeof createTestDb>): void {
|
|
17
|
+
const raw = getSqliteFrom(db);
|
|
18
|
+
raw.exec(/*sql*/ `
|
|
19
|
+
CREATE TABLE contacts (
|
|
20
|
+
id TEXT PRIMARY KEY,
|
|
21
|
+
display_name TEXT NOT NULL,
|
|
22
|
+
role TEXT NOT NULL DEFAULT 'contact',
|
|
23
|
+
principal_id TEXT,
|
|
24
|
+
created_at INTEGER NOT NULL,
|
|
25
|
+
updated_at INTEGER NOT NULL
|
|
26
|
+
)
|
|
27
|
+
`);
|
|
28
|
+
raw.exec(/*sql*/ `
|
|
29
|
+
CREATE TABLE contact_channels (
|
|
30
|
+
id TEXT PRIMARY KEY,
|
|
31
|
+
contact_id TEXT NOT NULL,
|
|
32
|
+
type TEXT NOT NULL,
|
|
33
|
+
address TEXT NOT NULL,
|
|
34
|
+
external_user_id TEXT,
|
|
35
|
+
external_chat_id TEXT,
|
|
36
|
+
status TEXT NOT NULL DEFAULT 'unverified',
|
|
37
|
+
policy TEXT NOT NULL DEFAULT 'allow',
|
|
38
|
+
invite_id TEXT,
|
|
39
|
+
revoked_reason TEXT,
|
|
40
|
+
blocked_reason TEXT,
|
|
41
|
+
last_seen_at INTEGER,
|
|
42
|
+
verified_at INTEGER,
|
|
43
|
+
verified_via TEXT,
|
|
44
|
+
created_at INTEGER NOT NULL,
|
|
45
|
+
updated_at INTEGER
|
|
46
|
+
)
|
|
47
|
+
`);
|
|
48
|
+
raw.exec(/*sql*/ `
|
|
49
|
+
CREATE INDEX idx_contact_channels_type_ext_user
|
|
50
|
+
ON contact_channels(type, external_user_id)
|
|
51
|
+
`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function createLegacyTables(raw: Database): void {
|
|
55
|
+
raw.exec(/*sql*/ `
|
|
56
|
+
CREATE TABLE channel_guardian_bindings (
|
|
57
|
+
id TEXT PRIMARY KEY,
|
|
58
|
+
channel TEXT NOT NULL,
|
|
59
|
+
status TEXT NOT NULL,
|
|
60
|
+
guardian_external_user_id TEXT,
|
|
61
|
+
guardian_principal_id TEXT,
|
|
62
|
+
guardian_delivery_chat_id TEXT,
|
|
63
|
+
metadata_json TEXT,
|
|
64
|
+
verified_at INTEGER,
|
|
65
|
+
verified_via TEXT,
|
|
66
|
+
created_at INTEGER NOT NULL
|
|
67
|
+
)
|
|
68
|
+
`);
|
|
69
|
+
raw.exec(/*sql*/ `
|
|
70
|
+
CREATE TABLE assistant_ingress_members (
|
|
71
|
+
id TEXT PRIMARY KEY,
|
|
72
|
+
source_channel TEXT NOT NULL,
|
|
73
|
+
external_user_id TEXT,
|
|
74
|
+
external_chat_id TEXT,
|
|
75
|
+
display_name TEXT,
|
|
76
|
+
username TEXT,
|
|
77
|
+
status TEXT NOT NULL,
|
|
78
|
+
policy TEXT,
|
|
79
|
+
invite_id TEXT,
|
|
80
|
+
revoked_reason TEXT,
|
|
81
|
+
blocked_reason TEXT,
|
|
82
|
+
last_seen_at INTEGER,
|
|
83
|
+
created_at INTEGER NOT NULL,
|
|
84
|
+
updated_at INTEGER
|
|
85
|
+
)
|
|
86
|
+
`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function tableExists(raw: Database, name: string): boolean {
|
|
90
|
+
return !!raw
|
|
91
|
+
.prepare(`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?`)
|
|
92
|
+
.get(name);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function seedLegacyRows(raw: Database): void {
|
|
96
|
+
raw.run(
|
|
97
|
+
`INSERT INTO channel_guardian_bindings
|
|
98
|
+
(id, channel, status, guardian_external_user_id, guardian_principal_id,
|
|
99
|
+
guardian_delivery_chat_id, metadata_json, verified_at, verified_via, created_at)
|
|
100
|
+
VALUES ('g1','telegram','active','U-guardian','prin-1','chat-1',NULL,1000,'telegram',1000)`,
|
|
101
|
+
);
|
|
102
|
+
raw.run(
|
|
103
|
+
`INSERT INTO assistant_ingress_members
|
|
104
|
+
(id, source_channel, external_user_id, external_chat_id, display_name,
|
|
105
|
+
username, status, policy, invite_id, revoked_reason, blocked_reason,
|
|
106
|
+
last_seen_at, created_at, updated_at)
|
|
107
|
+
VALUES ('m1','slack','U-member',NULL,'Member One','member1','active','allow',
|
|
108
|
+
NULL,NULL,NULL,2000,2000,2000)`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
describe("migration 131 — drop legacy member/guardian tables", () => {
|
|
113
|
+
test("syncs stragglers then drops the legacy tables when the column is present", () => {
|
|
114
|
+
const db = createTestDb();
|
|
115
|
+
const raw = getSqliteFrom(db);
|
|
116
|
+
bootstrap(db);
|
|
117
|
+
createLegacyTables(raw);
|
|
118
|
+
seedLegacyRows(raw);
|
|
119
|
+
|
|
120
|
+
migrateDropLegacyMemberGuardianTables(db);
|
|
121
|
+
|
|
122
|
+
// The straggler rows were synced into contact_channels.
|
|
123
|
+
const synced = raw
|
|
124
|
+
.prepare(`SELECT external_user_id FROM contact_channels ORDER BY id`)
|
|
125
|
+
.all() as { external_user_id: string | null }[];
|
|
126
|
+
expect(synced.map((r) => r.external_user_id).sort()).toEqual([
|
|
127
|
+
"U-guardian",
|
|
128
|
+
"U-member",
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
// The legacy tables were removed.
|
|
132
|
+
expect(tableExists(raw, "channel_guardian_bindings")).toBe(false);
|
|
133
|
+
expect(tableExists(raw, "assistant_ingress_members")).toBe(false);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("drops the legacy tables without throwing when external_user_id is absent (re-run after migration 294)", () => {
|
|
137
|
+
const db = createTestDb();
|
|
138
|
+
const raw = getSqliteFrom(db);
|
|
139
|
+
bootstrap(db);
|
|
140
|
+
createLegacyTables(raw);
|
|
141
|
+
seedLegacyRows(raw);
|
|
142
|
+
|
|
143
|
+
// Simulate a later startup where migration 294 has already dropped the
|
|
144
|
+
// index + column. The sync references external_user_id, so 131 must skip it
|
|
145
|
+
// and still drop the tables rather than failing on every boot.
|
|
146
|
+
raw.run("DROP INDEX IF EXISTS idx_contact_channels_type_ext_user");
|
|
147
|
+
raw.run("ALTER TABLE contact_channels DROP COLUMN external_user_id");
|
|
148
|
+
|
|
149
|
+
expect(() => migrateDropLegacyMemberGuardianTables(db)).not.toThrow();
|
|
150
|
+
|
|
151
|
+
expect(tableExists(raw, "channel_guardian_bindings")).toBe(false);
|
|
152
|
+
expect(tableExists(raw, "assistant_ingress_members")).toBe(false);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
@@ -568,4 +568,35 @@ describe("migration 287 — dedup case collisions + drop ext_user indexes", () =
|
|
|
568
568
|
// Original casing preserved
|
|
569
569
|
expect(channels[0]!.address).toBe("U999");
|
|
570
570
|
});
|
|
571
|
+
|
|
572
|
+
test("no-op when external_user_id column is absent (re-run after migration 294)", () => {
|
|
573
|
+
const db = createTestDb();
|
|
574
|
+
const raw = getSqliteFrom(db);
|
|
575
|
+
bootstrap(db);
|
|
576
|
+
|
|
577
|
+
insertContact(raw, "c1");
|
|
578
|
+
insertChannel(raw, {
|
|
579
|
+
id: "ch1",
|
|
580
|
+
contactId: "c1",
|
|
581
|
+
type: "slack",
|
|
582
|
+
address: "U999",
|
|
583
|
+
externalUserId: "U999",
|
|
584
|
+
status: "active",
|
|
585
|
+
updatedAt: 1000,
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
// Simulate a later startup where migration 294 has already dropped the
|
|
589
|
+
// index and column. Migration steps re-run on every startup, so this must
|
|
590
|
+
// tolerate the dropped column rather than throwing "no such column".
|
|
591
|
+
raw.run("DROP INDEX IF EXISTS idx_contact_channels_type_ext_user");
|
|
592
|
+
raw.run("ALTER TABLE contact_channels DROP COLUMN external_user_id");
|
|
593
|
+
|
|
594
|
+
expect(() => migrateContactChannelsUniqueExtUser(db)).not.toThrow();
|
|
595
|
+
|
|
596
|
+
const rows = raw
|
|
597
|
+
.prepare("SELECT id, address FROM contact_channels")
|
|
598
|
+
.all() as { id: string; address: string }[];
|
|
599
|
+
expect(rows).toHaveLength(1);
|
|
600
|
+
expect(rows[0]!.address).toBe("U999");
|
|
601
|
+
});
|
|
571
602
|
});
|
|
@@ -308,4 +308,34 @@ describe("migration 291 — renormalize addresses", () => {
|
|
|
308
308
|
expect(rows).toHaveLength(1);
|
|
309
309
|
expect(rows[0].address).toBe("U12345ABC");
|
|
310
310
|
});
|
|
311
|
+
|
|
312
|
+
test("no-op when external_user_id column is absent (re-run after migration 294)", () => {
|
|
313
|
+
const db = createTestDb();
|
|
314
|
+
bootstrap(db);
|
|
315
|
+
const raw = getSqliteFrom(db);
|
|
316
|
+
|
|
317
|
+
insertContact(raw, "c1");
|
|
318
|
+
insertChannel(raw, {
|
|
319
|
+
id: "ch1",
|
|
320
|
+
contactId: "c1",
|
|
321
|
+
type: "slack",
|
|
322
|
+
address: "u12345abc",
|
|
323
|
+
externalUserId: "U12345ABC",
|
|
324
|
+
status: "active",
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// Simulate a later startup where migration 294 has already dropped the
|
|
328
|
+
// index and column. Migration steps re-run on every startup, so this must
|
|
329
|
+
// tolerate the dropped column rather than throwing "no such column".
|
|
330
|
+
raw.run("DROP INDEX IF EXISTS idx_contact_channels_type_ext_user");
|
|
331
|
+
raw.run("ALTER TABLE contact_channels DROP COLUMN external_user_id");
|
|
332
|
+
|
|
333
|
+
expect(() => migrateContactChannelsRenormalizeAddresses(db)).not.toThrow();
|
|
334
|
+
|
|
335
|
+
const rows = raw
|
|
336
|
+
.prepare("SELECT id, address FROM contact_channels")
|
|
337
|
+
.all() as { id: string; address: string }[];
|
|
338
|
+
expect(rows).toHaveLength(1);
|
|
339
|
+
expect(rows[0].address).toBe("u12345abc");
|
|
340
|
+
});
|
|
311
341
|
});
|
|
@@ -283,6 +283,11 @@ export { migrateBackfillOriginChannelFromBindings } from "./288-backfill-origin-
|
|
|
283
283
|
export { migrateContactChannelsUniqueExtUser } from "./289-contact-channels-unique-ext-user.js";
|
|
284
284
|
export { migrateScheduleCapabilities } from "./290-schedule-capabilities.js";
|
|
285
285
|
export { migrateContactChannelsRenormalizeAddresses } from "./291-contact-channels-renormalize-addresses.js";
|
|
286
|
+
export { migrateScheduleDefaultNoReuseConversation } from "./292-schedule-default-no-reuse-conversation.js";
|
|
287
|
+
export { migrateWorkflowJournalLeafTokens } from "./293-workflow-journal-leaf-tokens.js";
|
|
288
|
+
export { migrateDropExternalUserId } from "./294-drop-external-user-id.js";
|
|
289
|
+
export { dropApprovalPromptTsTrackerTable } from "./295-drop-approval-prompt-ts-tracker.js";
|
|
290
|
+
export { migrateRewriteBalancedEconomyProfilePins } from "./296-rewrite-balanced-economy-profile-pins.js";
|
|
286
291
|
export {
|
|
287
292
|
MIGRATION_REGISTRY,
|
|
288
293
|
type MigrationRegistryEntry,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { and, asc, eq, gt, or } from "drizzle-orm";
|
|
2
2
|
import { v4 as uuid } from "uuid";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { getCachedShareAnalytics } from "../platform/consent-cache.js";
|
|
5
5
|
import {
|
|
6
6
|
ACTIVATION_AB_VARIANT,
|
|
7
7
|
ACTIVATION_FUNNEL_VERSION,
|
|
@@ -58,7 +58,7 @@ function insertOnboardingEvent(event: OnboardingEvent): OnboardingEvent {
|
|
|
58
58
|
export function recordOnboardingEvent(
|
|
59
59
|
params: RecordOnboardingEventParams,
|
|
60
60
|
): OnboardingEvent | null {
|
|
61
|
-
if (!
|
|
61
|
+
if (!getCachedShareAnalytics()) return null;
|
|
62
62
|
return insertOnboardingEvent({
|
|
63
63
|
id: uuid(),
|
|
64
64
|
createdAt: Date.now(),
|
|
@@ -93,7 +93,7 @@ export function recordActivationEvent(params: {
|
|
|
93
93
|
userId?: string | null;
|
|
94
94
|
abVariant?: string;
|
|
95
95
|
}): OnboardingEvent | null {
|
|
96
|
-
if (!
|
|
96
|
+
if (!getCachedShareAnalytics()) return null;
|
|
97
97
|
const createdAt = Date.now();
|
|
98
98
|
return insertOnboardingEvent({
|
|
99
99
|
id: uuid(),
|
|
@@ -26,7 +26,6 @@ export const contactChannels = sqliteTable(
|
|
|
26
26
|
isPrimary: integer("is_primary", { mode: "boolean" })
|
|
27
27
|
.notNull()
|
|
28
28
|
.default(false),
|
|
29
|
-
externalUserId: text("external_user_id"), // channel-native user ID (e.g., Telegram numeric ID, E.164 phone)
|
|
30
29
|
externalChatId: text("external_chat_id"), // delivery/notification routing address (e.g., Telegram chat ID)
|
|
31
30
|
status: text("status").notNull().default("unverified"), // 'active' | 'pending' | 'revoked' | 'blocked' | 'unverified'
|
|
32
31
|
policy: text("policy").notNull().default("allow"), // 'allow' | 'deny' | 'escalate'
|
|
@@ -8,18 +8,10 @@ mock.module("../util/logger.js", () => ({
|
|
|
8
8
|
}),
|
|
9
9
|
}));
|
|
10
10
|
|
|
11
|
-
let
|
|
12
|
-
|
|
13
|
-
mock.module("../
|
|
14
|
-
|
|
15
|
-
ui: {},
|
|
16
|
-
model: "test",
|
|
17
|
-
provider: "test",
|
|
18
|
-
memory: { enabled: false },
|
|
19
|
-
rateLimit: { maxRequestsPerMinute: 0 },
|
|
20
|
-
secretDetection: { enabled: false },
|
|
21
|
-
collectUsageData,
|
|
22
|
-
}),
|
|
11
|
+
let shareAnalytics = true;
|
|
12
|
+
|
|
13
|
+
mock.module("../platform/consent-cache.js", () => ({
|
|
14
|
+
getCachedShareAnalytics: () => shareAnalytics,
|
|
23
15
|
}));
|
|
24
16
|
|
|
25
17
|
import { getDb } from "./db-connection.js";
|
|
@@ -42,12 +34,12 @@ function insertEvent(
|
|
|
42
34
|
|
|
43
35
|
describe("skill-loaded-events-store", () => {
|
|
44
36
|
beforeEach(() => {
|
|
45
|
-
|
|
37
|
+
shareAnalytics = true;
|
|
46
38
|
getDb().delete(skillLoadedEvents).run();
|
|
47
39
|
});
|
|
48
40
|
|
|
49
|
-
test("honors the
|
|
50
|
-
|
|
41
|
+
test("honors the share_analytics opt-out (records nothing)", () => {
|
|
42
|
+
shareAnalytics = false;
|
|
51
43
|
recordSkillLoadedEvent({ skillName: "web-research" });
|
|
52
44
|
expect(queryUnreportedSkillLoadedEvents(0, undefined, 10)).toHaveLength(0);
|
|
53
45
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { and, asc, eq, gt, or } from "drizzle-orm";
|
|
2
2
|
import { v4 as uuid } from "uuid";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { getCachedShareAnalytics } from "../platform/consent-cache.js";
|
|
5
5
|
import type { UsageAttributionColumns } from "../usage/attribution.js";
|
|
6
6
|
import { getDb } from "./db-connection.js";
|
|
7
7
|
import { skillLoadedEvents } from "./schema.js";
|
|
@@ -38,7 +38,7 @@ export interface SkillLoadedEvent {
|
|
|
38
38
|
* opt-out, matching the rest of telemetry).
|
|
39
39
|
*/
|
|
40
40
|
export function recordSkillLoadedEvent(record: SkillLoadedEventRecord): void {
|
|
41
|
-
if (!
|
|
41
|
+
if (!getCachedShareAnalytics()) return;
|
|
42
42
|
const db = getDb();
|
|
43
43
|
db.insert(skillLoadedEvents)
|
|
44
44
|
.values({
|
|
@@ -8,12 +8,12 @@ mock.module("../util/logger.js", () => ({
|
|
|
8
8
|
}),
|
|
9
9
|
}));
|
|
10
10
|
|
|
11
|
-
// Toggle for the
|
|
11
|
+
// Toggle for the share_analytics opt-out gate the audit listener consults
|
|
12
12
|
// when populating the telemetry columns.
|
|
13
|
-
let
|
|
13
|
+
let shareAnalytics = true;
|
|
14
14
|
|
|
15
|
-
mock.module("../
|
|
16
|
-
|
|
15
|
+
mock.module("../platform/consent-cache.js", () => ({
|
|
16
|
+
getCachedShareAnalytics: () => shareAnalytics,
|
|
17
17
|
}));
|
|
18
18
|
|
|
19
19
|
import {
|
|
@@ -43,7 +43,7 @@ function insertInvocation(
|
|
|
43
43
|
|
|
44
44
|
describe("tool-executed-events-store", () => {
|
|
45
45
|
beforeEach(() => {
|
|
46
|
-
|
|
46
|
+
shareAnalytics = true;
|
|
47
47
|
getDb().delete(toolInvocations).run();
|
|
48
48
|
});
|
|
49
49
|
|
|
@@ -136,10 +136,10 @@ describe("tool-executed-events-store", () => {
|
|
|
136
136
|
|
|
137
137
|
listener(executedEvent("t-opted-in-before"));
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
shareAnalytics = false;
|
|
140
140
|
listener(executedEvent("t-opted-out"));
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
shareAnalytics = true;
|
|
143
143
|
listener(executedEvent("t-opted-in-after"));
|
|
144
144
|
|
|
145
145
|
// Mid-session opt-out flip: only rows recorded while opted in project.
|