@vellumai/assistant 0.11.3 → 0.11.4-dev.202608190019.b94dbf2
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/AGENTS.md +9 -3
- package/ARCHITECTURE.md +32 -10
- package/docs/architecture/memory.md +43 -5
- package/docs/architecture/security.md +96 -152
- package/docs/architecture/turn-actor.md +70 -0
- package/docs/browser-use-architecture-phase2.md +128 -56
- package/docs/flux-turn-detection-spike.md +248 -0
- package/docs/guardian-request-flow.md +35 -0
- package/docs/stt-provider-onboarding.md +3 -1
- package/knip.json +3 -0
- 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__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -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__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
- package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/openapi.yaml +289 -113
- package/package.json +1 -1
- package/scripts/voice-ttft-spike.ts +3 -3
- package/scripts/write-plugin-api-shim.ts +10 -0
- package/src/__tests__/app-compiler.test.ts +38 -3
- package/src/__tests__/app-control-flow.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +2 -2
- package/src/__tests__/assistant-feature-flag-guard.test.ts +25 -3
- package/src/__tests__/attachments-store.test.ts +21 -12
- package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
- package/src/__tests__/call-site-routing-provider.test.ts +1 -1
- package/src/__tests__/channel-availability-routes.test.ts +14 -1
- package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
- package/src/__tests__/channel-delivery-store.test.ts +14 -14
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
- package/src/__tests__/channel-setup-panel-ack.test.ts +1 -1
- package/src/__tests__/checker.test.ts +20 -314
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
- package/src/__tests__/compaction-events.test.ts +8 -10
- package/src/__tests__/config-loader-backfill.test.ts +3 -3
- package/src/__tests__/config-schema.test.ts +25 -10
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop.test.ts +32 -21
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-attention-store.test.ts +63 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +112 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
- package/src/__tests__/conversation-fork-crud.test.ts +69 -0
- package/src/__tests__/conversation-fork-referential.test.ts +67 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +209 -0
- package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
- package/src/__tests__/conversation-queue.test.ts +154 -4
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +9 -9
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +187 -102
- package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
- package/src/__tests__/conversation-slash-queue.test.ts +3 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-app-open.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +21 -14
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-state-update.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
- package/src/__tests__/credential-prompt-route.test.ts +7 -10
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +1 -0
- package/src/__tests__/custom-profile-ensure.test.ts +5 -1
- package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
- package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
- package/src/__tests__/document-append-idempotency.test.ts +233 -0
- package/src/__tests__/document-sync-tags.test.ts +0 -75
- package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
- package/src/__tests__/edit-propagation.test.ts +107 -11
- package/src/__tests__/file-ops-service.test.ts +163 -30
- package/src/__tests__/filesystem-tools.test.ts +23 -24
- package/src/__tests__/gateway-only-guard.test.ts +2 -5
- package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
- package/src/__tests__/helpers/mock-actor-context.ts +49 -0
- package/src/__tests__/helpers/mock-conversation.ts +13 -1
- package/src/__tests__/host-file-read-tool.test.ts +16 -19
- package/src/__tests__/http-user-message-parity.test.ts +1 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +49 -0
- package/src/__tests__/injector-chain.test.ts +63 -41
- package/src/__tests__/injector-disk-pressure.test.ts +11 -23
- package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
- package/src/__tests__/llm-context-resolution.test.ts +73 -1
- package/src/__tests__/llm-schema.test.ts +5 -2
- package/src/__tests__/managed-skill-lifecycle.test.ts +7 -0
- package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
- package/src/__tests__/media-generate-image.test.ts +131 -21
- package/src/__tests__/memory-retrieval-hook.test.ts +100 -7
- package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
- package/src/__tests__/mtime-cache.test.ts +3 -1
- package/src/__tests__/non-member-access-request.test.ts +0 -20
- package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
- package/src/__tests__/plugin-api-store-credential.test.ts +261 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +10 -7
- package/src/__tests__/plugin-disabled-state.test.ts +2 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
- package/src/__tests__/plugin-execution-context.test.ts +73 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +7 -4
- package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
- package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
- package/src/__tests__/proxy-approval-callback.test.ts +1 -0
- package/src/__tests__/qdrant-manager.test.ts +14 -1
- package/src/__tests__/reaction-persistence.test.ts +200 -7
- package/src/__tests__/require-fresh-approval.test.ts +0 -4
- package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +460 -105
- package/src/__tests__/run-due-schedules.test.ts +21 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +187 -18
- package/src/__tests__/schedule-routes.test.ts +23 -0
- package/src/__tests__/schedule-store.test.ts +17 -0
- package/src/__tests__/scoped-approval-grants.test.ts +11 -6
- package/src/__tests__/secret-ingress-channel.test.ts +0 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +3 -3
- package/src/__tests__/skills.test.ts +32 -0
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
- package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
- package/src/__tests__/subagent-spawn-and-await.test.ts +18 -17
- package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
- package/src/__tests__/subagent-tools.test.ts +81 -101
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +1 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
- package/src/__tests__/tool-executor.test.ts +68 -39
- package/src/__tests__/turn-events-store.test.ts +43 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
- package/src/__tests__/ui-shape-teaching.test.ts +33 -0
- package/src/__tests__/ui-visual-surface.test.ts +1 -1
- package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
- package/src/__tests__/ui-work-result-surface.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +3 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/visible-app-context.test.ts +16 -9
- package/src/__tests__/voice-config-update.test.ts +40 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +5 -3
- package/src/__tests__/voice-session-bridge.test.ts +85 -29
- package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
- package/src/__tests__/worker-plugin-surface.test.ts +77 -0
- package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
- package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
- package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
- package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
- package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
- package/src/acp/__tests__/auth-required.test.ts +161 -0
- package/src/acp/acp-claude-oauth.ts +19 -2
- package/src/acp/agent-process.test.ts +100 -0
- package/src/acp/agent-process.ts +29 -26
- package/src/acp/auth-required.ts +102 -0
- package/src/acp/session-manager.test.ts +119 -0
- package/src/acp/session-manager.ts +76 -3
- package/src/api/events/acp-auth-required.ts +55 -0
- package/src/api/events/host-file.ts +2 -2
- package/src/api/index.ts +7 -0
- package/src/api/surfaces.ts +12 -3
- package/src/apps/app-store.ts +3 -0
- package/src/bundler/package-resolver.ts +2 -30
- package/src/calls/__tests__/voice-session-bridge.test.ts +194 -11
- package/src/calls/__tests__/voice-triage-escalate.test.ts +102 -0
- package/src/calls/call-controller.ts +19 -3
- package/src/calls/call-setup-flow.ts +0 -1
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/calls/voice-session-bridge.ts +115 -41
- package/src/calls/voice-triage-escalate.ts +105 -2
- package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
- package/src/channels/config.ts +13 -0
- package/src/channels/plugin-channel-declarations.ts +108 -0
- package/src/channels/types.ts +30 -0
- package/src/cli/AGENTS.md +5 -2
- package/src/cli/bundled-modules.ts +29 -0
- package/src/cli/commands/credentials.help.ts +2 -2
- package/src/cli/commands/db/repair.ts +4 -8
- package/src/cli/commands/domain.ts +6 -3
- package/src/cli/commands/email.ts +6 -3
- package/src/cli/commands/inference-providers.ts +1 -1
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.help.ts +13 -4
- package/src/cli/commands/mcp.ts +9 -0
- package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
- package/src/cli/commands/memory/index.help.ts +84 -28
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/memory-v2.ts +58 -54
- package/src/cli/commands/memory/memory-v3.ts +64 -0
- package/src/cli/commands/memory/memory-validate.ts +18 -0
- package/src/cli/commands/plugins.ts +85 -36
- package/src/cli/commands/schedules.ts +35 -1
- package/src/cli/commands/stt.help.ts +27 -2
- package/src/cli/commands/trust.ts +3 -14
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
- package/src/cli/lib/bundled-marketplace.json +14 -1
- package/src/cli/lib/upgrade-plugin.ts +42 -0
- package/src/config/__tests__/balanced-model-experiment.test.ts +278 -0
- package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
- package/src/config/__tests__/default-provider.test.ts +6 -1
- package/src/config/__tests__/profile-materialization.test.ts +75 -19
- package/src/config/assistant-feature-flags.ts +36 -15
- package/src/config/balanced-model-experiment.ts +35 -0
- package/src/config/bundled-skills/acp/SKILL.md +6 -7
- package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
- package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/SKILL.md +5 -4
- package/src/config/bundled-skills/image-studio/TOOLS.json +1 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +101 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
- package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +9 -3
- package/src/config/bundled-skills/subagent/SKILL.md +17 -12
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -4
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
- package/src/config/call-site-defaults.ts +11 -5
- package/src/config/default-profile-catalog.ts +179 -16
- package/src/config/default-profile-names.ts +4 -1
- package/src/config/default-provider-resolution.ts +4 -0
- package/src/config/feature-flag-registry.json +12 -12
- package/src/config/llm-context-resolution.ts +11 -3
- package/src/config/llm-resolver.ts +28 -1
- package/src/config/profile-materialization.ts +70 -22
- package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
- package/src/config/schemas/call-site-catalog.ts +4 -4
- package/src/config/schemas/live-voice.ts +57 -23
- package/src/config/schemas/llm.ts +59 -32
- package/src/config/schemas/mcp.ts +23 -0
- package/src/config/schemas/plugin-updates.ts +6 -2
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/skills.ts +9 -2
- package/src/context/outbound-sanitize.ts +96 -1
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
- package/src/daemon/conversation-agent-loop.ts +31 -19
- package/src/daemon/conversation-messaging.ts +5 -1
- package/src/daemon/conversation-notifiers.ts +20 -10
- package/src/daemon/conversation-process.ts +20 -6
- package/src/daemon/conversation-runtime-assembly.ts +12 -6
- package/src/daemon/conversation-store.ts +14 -4
- package/src/daemon/conversation-surfaces.ts +75 -26
- package/src/daemon/conversation-tool-setup.ts +3 -6
- package/src/daemon/conversation.ts +154 -51
- package/src/daemon/doordash-steps.ts +2 -2
- package/src/daemon/lifecycle.ts +14 -1
- package/src/daemon/mcp-reload-service.ts +36 -6
- package/src/daemon/process-message.ts +13 -26
- package/src/daemon/providers-setup.ts +6 -3
- package/src/daemon/trust-context-types.ts +29 -0
- package/src/daemon/trust-context.ts +12 -7
- package/src/daemon/wake-conversation-ops.ts +3 -2
- package/src/daemon/windows-compiled-entry.ts +4 -0
- package/src/documents/document-store.ts +143 -240
- package/src/hooks/hook-loader.ts +3 -3
- package/src/hooks/registry.ts +103 -45
- package/src/hooks/types.ts +5 -0
- package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
- package/src/inbound/oauth-callback-url.ts +61 -0
- package/src/ipc/gateway-client.test.ts +1 -1
- package/src/ipc/gateway-client.ts +14 -21
- package/src/ipc/gateway-flag-listener.ts +17 -3
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
- package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +1050 -0
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
- package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +60 -194
- package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
- package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
- package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
- package/src/live-voice/live-voice-archive.ts +2 -0
- package/src/live-voice/live-voice-manager.ts +16 -3
- package/src/live-voice/live-voice-metrics.ts +57 -32
- package/src/live-voice/live-voice-photo.ts +1 -2
- package/src/live-voice/live-voice-session.ts +598 -323
- package/src/live-voice/progress-narration.ts +277 -0
- package/src/live-voice/protocol.ts +21 -1
- package/src/live-voice/windows-compiled-live-voice.ts +4 -0
- package/src/mcp/__tests__/effective-config.test.ts +238 -0
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
- package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
- package/src/mcp/client.ts +16 -11
- package/src/mcp/effective-config.ts +113 -0
- package/src/mcp/manager.ts +11 -6
- package/src/mcp/mcp-auth-orchestrator.ts +13 -22
- package/src/mcp/mcp-oauth-provider.ts +205 -240
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
- package/src/monitoring/control.ts +1 -0
- package/src/monitoring/db-integrity-sample.ts +4 -5
- package/src/monitoring/plugin-auto-update.ts +128 -24
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/approval-card-data.ts +33 -0
- package/src/notifications/signal.ts +1 -0
- package/src/permissions/AGENTS.md +16 -0
- package/src/permissions/checker.test.ts +75 -122
- package/src/permissions/checker.ts +44 -560
- package/src/permissions/confirmation-guardian-request.test.ts +15 -11
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/prompter.ts +1 -5
- package/src/permissions/question-guardian-request.test.ts +14 -6
- package/src/permissions/question-guardian-request.ts +1 -2
- package/src/persistence/attachments-store.ts +8 -1
- package/src/persistence/bookmark-crud.ts +3 -7
- package/src/persistence/conversation-attention-store.ts +16 -45
- package/src/persistence/conversation-crud.ts +33 -4
- package/src/persistence/conversation-lineage.ts +9 -0
- package/src/persistence/conversation-queries.ts +182 -52
- package/src/persistence/delivery-crud.ts +150 -36
- package/src/persistence/embeddings/qdrant-manager.ts +84 -49
- package/src/persistence/external-conversation-store.ts +32 -4
- package/src/persistence/llm-request-log-store.ts +4 -10
- package/src/persistence/llm-usage-store.ts +8 -3
- package/src/persistence/message-reads.test.ts +197 -0
- package/src/persistence/message-reads.ts +211 -0
- package/src/persistence/migrations/360-add-document-workspace-path.ts +5 -14
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
- package/src/persistence/real-user-turn-filter.ts +27 -3
- package/src/persistence/schema/documents.ts +4 -4
- package/src/persistence/steps.ts +9 -0
- package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
- package/src/plugin-api/constants.ts +8 -0
- package/src/plugin-api/conversation-turn.ts +195 -5
- package/src/plugin-api/index.ts +38 -6
- package/src/plugin-api/resolve-credential.ts +3 -2
- package/src/plugin-api/store-credential.ts +146 -0
- package/src/plugin-api/vision-support.test.ts +1 -1
- package/src/plugin-api/webhook-url.ts +13 -11
- package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
- package/src/plugins/defaults/main.ts +21 -7
- package/src/plugins/defaults/memory/AGENTS.md +15 -3
- package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
- package/src/plugins/defaults/memory/buffer-format.ts +165 -0
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +77 -0
- package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +24 -6
- package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +17 -24
- package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +53 -5
- package/src/plugins/defaults/memory/indexer.ts +3 -1
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -4
- package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
- package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +147 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
- package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
- package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
- package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
- package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
- package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +195 -58
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +93 -24
- package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
- package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
- package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
- package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
- package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
- package/src/plugins/defaults/memory/substrate/static-context.ts +160 -33
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +18 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +66 -1
- package/src/plugins/defaults/memory/v3/card.ts +9 -9
- package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
- package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
- package/src/plugins/defaults/memory/v3/edge.ts +13 -57
- package/src/plugins/defaults/memory/v3/injector.ts +8 -0
- package/src/plugins/defaults/memory/v3/prune.ts +2 -0
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +23 -9
- package/src/plugins/defaults/memory/worker-control.ts +1 -0
- package/src/plugins/defaults/memory/worker.ts +6 -3
- package/src/plugins/defaults/worker-entrypoints.ts +3 -0
- package/src/plugins/external-plugin-loader.ts +47 -0
- package/src/plugins/mcp-servers.ts +361 -0
- package/src/plugins/mtime-cache.ts +37 -46
- package/src/plugins/pipeline.ts +14 -7
- package/src/plugins/plugin-execution-context.ts +35 -11
- package/src/plugins/worker-plugin-surface.ts +33 -0
- package/src/prompts/templates/system-sections.ts +0 -7
- package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
- package/src/providers/__tests__/context-overflow-error.test.ts +24 -0
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
- package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
- package/src/providers/__tests__/retry-callsite.test.ts +25 -2
- package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
- package/src/providers/anthropic/client.ts +332 -241
- package/src/providers/call-site-routing.ts +30 -3
- package/src/providers/connection-resolution.ts +194 -11
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +4 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/inference/auth.ts +6 -0
- package/src/providers/inference/connection-availability.ts +24 -2
- package/src/providers/inference/connections.ts +2 -0
- package/src/providers/model-catalog.ts +3 -3
- package/src/providers/model-intents.ts +28 -8
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +163 -40
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
- package/src/providers/openai/chat-completions-provider.ts +133 -36
- package/src/providers/openai/codex-models.ts +2 -1
- package/src/providers/provider-send-message.ts +32 -3
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +625 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +679 -0
- package/src/providers/speech-to-text/provider-catalog.ts +99 -8
- package/src/providers/speech-to-text/resolve.ts +25 -2
- package/src/routes/control.ts +1 -0
- package/src/routes/route-host-client.ts +1 -0
- package/src/routes/route-host-protocol.ts +7 -0
- package/src/routes/worker.ts +48 -15
- package/src/runtime/AGENTS.md +16 -17
- package/src/runtime/access-request-helper.ts +9 -12
- package/src/runtime/agent-wake.ts +18 -15
- package/src/runtime/effective-capabilities.test.ts +43 -0
- package/src/runtime/effective-capabilities.ts +27 -0
- package/src/runtime/guardian-reply-router.ts +6 -2
- package/src/runtime/pre-first-message-gate.ts +4 -0
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +522 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +132 -35
- package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +215 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +133 -1
- package/src/runtime/routes/channel-availability-routes.ts +32 -14
- package/src/runtime/routes/channel-route-shared.ts +0 -6
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
- package/src/runtime/routes/conversation-list-routes.ts +181 -23
- package/src/runtime/routes/conversation-management-routes.ts +17 -12
- package/src/runtime/routes/conversation-query-routes.ts +40 -27
- package/src/runtime/routes/conversation-routes.ts +43 -29
- package/src/runtime/routes/credential-prompt-routes.ts +4 -7
- package/src/runtime/routes/credential-routes.ts +26 -82
- package/src/runtime/routes/default-provider-routes.ts +15 -0
- package/src/runtime/routes/documents-routes.ts +3 -222
- package/src/runtime/routes/inbound-message-handler.ts +21 -45
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
- package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -79
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -7
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -8
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -79
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
- package/src/runtime/routes/inference-profiles-routes.ts +20 -11
- package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/mcp-auth-routes.ts +148 -57
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +2 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +3 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -2
- package/src/runtime/routes/playground/reset-circuit.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +38 -8
- package/src/runtime/routes/schedule-routes.ts +94 -7
- package/src/runtime/routes/settings-routes.ts +6 -6
- package/src/runtime/routes/stt-routes.ts +31 -25
- package/src/runtime/routes/surface-action-routes.ts +20 -19
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
- package/src/runtime/routes/user-route-dispatcher.ts +69 -15
- package/src/runtime/routes/user-route-import.ts +108 -0
- package/src/runtime/routes/user-route-resolution.ts +18 -1
- package/src/runtime/routes/workspace-routes.ts +0 -9
- package/src/runtime/routes/workspace-utils.ts +3 -13
- package/src/runtime/services/conversation-serializer.ts +7 -2
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +68 -5
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +81 -0
- package/src/schedule/plugin-schedule-availability.ts +58 -0
- package/src/schedule/plugin-schedule-declarations.ts +23 -27
- package/src/schedule/plugin-schedule-reconciler.ts +12 -3
- package/src/schedule/schedule-store.ts +5 -1
- package/src/schedule/scheduler.ts +9 -4
- package/src/schedule/worker-control.ts +1 -0
- package/src/schedule/worker.ts +6 -0
- package/src/security/oauth2.ts +6 -22
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
- package/src/stt/__tests__/types.test.ts +94 -0
- package/src/stt/daemon-batch-transcriber.ts +10 -0
- package/src/stt/stt-stream-session.ts +8 -4
- package/src/stt/types.ts +103 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +26 -15
- package/src/subagent/consult-context.ts +11 -11
- package/src/subagent/consult-prompt.ts +26 -35
- package/src/subagent/manager.ts +21 -40
- package/src/subagent/notify.ts +7 -1
- package/src/subagent/types.ts +15 -12
- package/src/tools/__tests__/tool-input-schemas.test.ts +7 -7
- package/src/tools/acp/spawn.test.ts +97 -0
- package/src/tools/acp/spawn.ts +38 -4
- package/src/tools/credentials/ref-parse.ts +35 -0
- package/src/tools/credentials/resolve.ts +4 -10
- package/src/tools/credentials/store.ts +168 -0
- package/src/tools/document/document-tool.ts +12 -3
- package/src/tools/executor.ts +53 -15
- package/src/tools/filesystem/read.ts +27 -10
- package/src/tools/host-filesystem/read.ts +27 -15
- package/src/tools/network/url-safety.ts +9 -16
- package/src/tools/permission-checker.ts +43 -52
- package/src/tools/registry.ts +2 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +63 -35
- package/src/tools/shared/filesystem/legacy-read-args.ts +22 -0
- package/src/tools/shared/filesystem/types.ts +5 -5
- package/src/tools/skills/scaffold-managed.ts +25 -7
- package/src/tools/subagent/spawn.ts +28 -88
- package/src/tools/tool-types.ts +26 -13
- package/src/tools/types.ts +6 -6
- package/src/tools/ui-surface/surface-shape-docs.ts +12 -1
- package/src/tools/workflows/run-workflow.ts +1 -2
- package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
- package/src/tts/reasoning-tag-filter.ts +89 -0
- package/src/util/__tests__/worker-process-command.test.ts +37 -0
- package/src/util/logger.ts +16 -0
- package/src/util/think-tag-stream.ts +95 -0
- package/src/util/worker-process.ts +37 -4
- package/src/windows-compiled-cli.ts +32 -0
- package/src/windows-compiled-entry.ts +4 -0
- package/src/windows-compiled-logger.ts +6 -0
- package/src/windows-compiled-worker-entry.ts +29 -0
- package/src/workspace/byok-default-profile-ensure.ts +76 -24
- package/src/workspace/custom-profile-ensure.ts +4 -24
- package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
- package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
- package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
- package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
- package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/provider-commit-message-generator.ts +7 -5
- package/src/__tests__/document-workspace-file.test.ts +0 -467
- package/src/live-voice/__tests__/front-decision.test.ts +0 -645
- package/src/live-voice/front-decision.ts +0 -476
- package/src/permissions/ipc-risk-types.ts +0 -143
- package/src/permissions/risk-types.ts +0 -76
- package/src/subagent/__tests__/consult-transcript.test.ts +0 -184
- package/src/subagent/consult-transcript.ts +0 -90
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* script's `full` variants and the live session's `llmFirstDeltaMs`).
|
|
9
9
|
*
|
|
10
10
|
* Variants:
|
|
11
|
-
* slim-
|
|
11
|
+
* slim-front voiceFrontDoor call site, slim prompt
|
|
12
12
|
* slim-flash cost-optimized profile, same slim prompt
|
|
13
13
|
* full-notools cost-optimized, real buildSystemPrompt(), no tools
|
|
14
14
|
* full-flash cost-optimized, real buildSystemPrompt() + full tool defs
|
|
@@ -170,8 +170,8 @@ async function main(): Promise<void> {
|
|
|
170
170
|
|
|
171
171
|
const variants: VariantSpec[] = [
|
|
172
172
|
{
|
|
173
|
-
name: "slim-
|
|
174
|
-
callSite: "
|
|
173
|
+
name: "slim-front",
|
|
174
|
+
callSite: "voiceFrontDoor",
|
|
175
175
|
systemPrompt: () => SLIM_SYSTEM_PROMPT,
|
|
176
176
|
},
|
|
177
177
|
{
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import { ensurePluginApiShim } from "../src/plugins/ensure-plugin-api-shim.js";
|
|
4
|
+
|
|
5
|
+
const outputDir = Bun.argv[2];
|
|
6
|
+
if (!outputDir || !path.isAbsolute(outputDir)) {
|
|
7
|
+
throw new Error("An absolute plugin API shim output directory is required.");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
await ensurePluginApiShim({ workspaceDir: outputDir });
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
packageName,
|
|
21
21
|
resolvePackage,
|
|
22
22
|
} from "../bundler/package-resolver.js";
|
|
23
|
+
import { ensureBun } from "../util/bun-runtime.js";
|
|
23
24
|
|
|
24
25
|
// ---------------------------------------------------------------------------
|
|
25
26
|
// Shared temp directory
|
|
@@ -56,6 +57,29 @@ async function scaffold(
|
|
|
56
57
|
return appDir;
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Download `pkg` into bun's global module cache via a throwaway install.
|
|
62
|
+
*
|
|
63
|
+
* `resolvePackage` bounds its own install at INSTALL_TIMEOUT_MS (10s), which a
|
|
64
|
+
* cold global cache can exceed for a large package on a slow network. Priming
|
|
65
|
+
* first is unbounded, so the install the test measures resolves from cache and
|
|
66
|
+
* stays well inside that bound.
|
|
67
|
+
*/
|
|
68
|
+
async function primeBunCache(pkg: string): Promise<void> {
|
|
69
|
+
const primeDir = join(tempDir, `prime-${pkg.replaceAll(/[^a-z0-9]/gi, "-")}`);
|
|
70
|
+
await mkdir(primeDir, { recursive: true });
|
|
71
|
+
await writeFile(
|
|
72
|
+
join(primeDir, "package.json"),
|
|
73
|
+
JSON.stringify({ name: "prime-cache", private: true }),
|
|
74
|
+
);
|
|
75
|
+
const proc = Bun.spawn([await ensureBun(), "install", "--no-save", pkg], {
|
|
76
|
+
cwd: primeDir,
|
|
77
|
+
stdout: "ignore",
|
|
78
|
+
stderr: "ignore",
|
|
79
|
+
});
|
|
80
|
+
await proc.exited;
|
|
81
|
+
}
|
|
82
|
+
|
|
59
83
|
const MINIMAL_HTML = `<!DOCTYPE html>
|
|
60
84
|
<html>
|
|
61
85
|
<head><title>Test</title></head>
|
|
@@ -466,10 +490,21 @@ describe("package-resolver", () => {
|
|
|
466
490
|
expect(ALLOWED_PACKAGES).toContain("clsx");
|
|
467
491
|
});
|
|
468
492
|
|
|
469
|
-
// `lucide` (the vanilla package)
|
|
470
|
-
//
|
|
471
|
-
// exports icon data arrays, not Preact components. Apps use inline SVG.
|
|
493
|
+
// `lucide` (the vanilla package) exports icon data arrays, not Preact
|
|
494
|
+
// components, and unpacks to ~29 MB for no benefit. Apps use inline SVG.
|
|
472
495
|
test("ALLOWED_PACKAGES excludes lucide", () => {
|
|
473
496
|
expect(ALLOWED_PACKAGES).not.toContain("lucide");
|
|
474
497
|
});
|
|
498
|
+
|
|
499
|
+
// `chart.js` is a large allowlisted package: it must install into the shared
|
|
500
|
+
// cache and resolve so apps importing it can compile.
|
|
501
|
+
test("resolvePackage installs a large allowlisted package", async () => {
|
|
502
|
+
await primeBunCache("chart.js");
|
|
503
|
+
|
|
504
|
+
const result = await resolvePackage("chart.js");
|
|
505
|
+
expect(result).not.toBeNull();
|
|
506
|
+
expect(existsSync(join(getCacheDir(), "node_modules", "chart.js"))).toBe(
|
|
507
|
+
true,
|
|
508
|
+
);
|
|
509
|
+
}, 60_000);
|
|
475
510
|
});
|
|
@@ -113,7 +113,7 @@ function makeIdleSession(opts?: {
|
|
|
113
113
|
ensureActorScopedHistory: async () => {},
|
|
114
114
|
getMessages: () => [],
|
|
115
115
|
usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
|
|
116
|
-
|
|
116
|
+
replayActivityState: () => {},
|
|
117
117
|
setHostBrowserProxy: () => {},
|
|
118
118
|
setHostCuProxy: () => {},
|
|
119
119
|
setHostAppControlProxy: () => {},
|
|
@@ -176,7 +176,7 @@ function makeConfirmationEmittingSession(opts?: {
|
|
|
176
176
|
ensureActorScopedHistory: async () => {},
|
|
177
177
|
getMessages: () => [],
|
|
178
178
|
usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
|
|
179
|
-
|
|
179
|
+
replayActivityState: () => {},
|
|
180
180
|
setHostBrowserProxy: () => {},
|
|
181
181
|
setHostCuProxy: () => {},
|
|
182
182
|
setHostAppControlProxy: () => {},
|
|
@@ -40,7 +40,10 @@ interface RegistryFlag {
|
|
|
40
40
|
key: string;
|
|
41
41
|
label: string;
|
|
42
42
|
description: string;
|
|
43
|
-
|
|
43
|
+
/** Boolean for a gate; the winning variation's name for a multivariate flag. */
|
|
44
|
+
defaultEnabled: boolean | string;
|
|
45
|
+
/** Declared variations. Present only on multivariate flags. */
|
|
46
|
+
values?: string[];
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
interface Registry {
|
|
@@ -179,8 +182,27 @@ describe("assistant feature flag guard", () => {
|
|
|
179
182
|
const violations: string[] = [];
|
|
180
183
|
|
|
181
184
|
for (const flag of assistantFlags) {
|
|
182
|
-
|
|
183
|
-
|
|
185
|
+
// A gate declares a boolean default. A multivariate flag declares its
|
|
186
|
+
// variations in `values` and names the winning one in `defaultEnabled`,
|
|
187
|
+
// which the resolver serves verbatim to string consumers.
|
|
188
|
+
if (flag.values === undefined) {
|
|
189
|
+
if (typeof flag.defaultEnabled !== "boolean") {
|
|
190
|
+
violations.push(
|
|
191
|
+
`${flag.key}: missing or non-boolean 'defaultEnabled'`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
} else if (
|
|
195
|
+
!Array.isArray(flag.values) ||
|
|
196
|
+
flag.values.length < 2 ||
|
|
197
|
+
flag.values.some((value) => typeof value !== "string")
|
|
198
|
+
) {
|
|
199
|
+
violations.push(
|
|
200
|
+
`${flag.key}: 'values' must list at least two string variations`,
|
|
201
|
+
);
|
|
202
|
+
} else if (!flag.values.includes(flag.defaultEnabled as string)) {
|
|
203
|
+
violations.push(
|
|
204
|
+
`${flag.key}: 'defaultEnabled' must name one of the declared 'values'`,
|
|
205
|
+
);
|
|
184
206
|
}
|
|
185
207
|
if (
|
|
186
208
|
typeof flag.description !== "string" ||
|
|
@@ -722,12 +722,6 @@ describe("validateAttachmentUpload", () => {
|
|
|
722
722
|
expect(exeResult.error).toContain(".exe");
|
|
723
723
|
}
|
|
724
724
|
|
|
725
|
-
const shResult = validateAttachmentUpload("script.sh", "text/plain");
|
|
726
|
-
expect(shResult.ok).toBe(false);
|
|
727
|
-
if (!shResult.ok) {
|
|
728
|
-
expect(shResult.error).toContain(".sh");
|
|
729
|
-
}
|
|
730
|
-
|
|
731
725
|
const isoResult = validateAttachmentUpload(
|
|
732
726
|
"disk.iso",
|
|
733
727
|
"application/octet-stream",
|
|
@@ -738,6 +732,24 @@ describe("validateAttachmentUpload", () => {
|
|
|
738
732
|
}
|
|
739
733
|
});
|
|
740
734
|
|
|
735
|
+
test("accepts shell scripts as text attachments", () => {
|
|
736
|
+
expect(validateAttachmentUpload("script.sh", "text/plain").ok).toBe(true);
|
|
737
|
+
expect(validateAttachmentUpload("script.SH", "text/plain").ok).toBe(true);
|
|
738
|
+
expect(
|
|
739
|
+
validateAttachmentUpload("setup.sh", "application/x-sh").ok,
|
|
740
|
+
).toBe(true);
|
|
741
|
+
expect(
|
|
742
|
+
validateAttachmentUpload("run.sh", "application/x-shellscript").ok,
|
|
743
|
+
).toBe(true);
|
|
744
|
+
expect(validateAttachmentUpload("run.sh", "text/x-sh").ok).toBe(true);
|
|
745
|
+
expect(validateAttachmentUpload("run.sh", "text/x-shellscript").ok).toBe(
|
|
746
|
+
true,
|
|
747
|
+
);
|
|
748
|
+
expect(
|
|
749
|
+
validateAttachmentUpload("run.sh", "application/octet-stream").ok,
|
|
750
|
+
).toBe(true);
|
|
751
|
+
});
|
|
752
|
+
|
|
741
753
|
test("rejects dangerous extensions regardless of claimed MIME type", () => {
|
|
742
754
|
// .exe disguised as image/png
|
|
743
755
|
const result = validateAttachmentUpload("payload.exe", "image/png");
|
|
@@ -748,7 +760,9 @@ describe("validateAttachmentUpload", () => {
|
|
|
748
760
|
expect(
|
|
749
761
|
validateAttachmentUpload("PROGRAM.EXE", "application/octet-stream").ok,
|
|
750
762
|
).toBe(false);
|
|
751
|
-
expect(validateAttachmentUpload("
|
|
763
|
+
expect(validateAttachmentUpload("INSTALL.DMG", "application/octet-stream").ok).toBe(
|
|
764
|
+
false,
|
|
765
|
+
);
|
|
752
766
|
});
|
|
753
767
|
|
|
754
768
|
test("rejects unsupported MIME types", () => {
|
|
@@ -815,11 +829,6 @@ describe("validateAttachmentUpload", () => {
|
|
|
815
829
|
trustedSource: true,
|
|
816
830
|
}).ok,
|
|
817
831
|
).toBe(true);
|
|
818
|
-
expect(
|
|
819
|
-
validateAttachmentUpload("build.sh", "text/plain", {
|
|
820
|
-
trustedSource: true,
|
|
821
|
-
}).ok,
|
|
822
|
-
).toBe(true);
|
|
823
832
|
});
|
|
824
833
|
|
|
825
834
|
test("trustedSource: false keeps strict validation", () => {
|
|
@@ -278,13 +278,30 @@ describe("ensureByokDefaultProfiles", () => {
|
|
|
278
278
|
["openrouter", "quality-optimized", "anthropic/claude-opus-4.8"],
|
|
279
279
|
["gemini", "cost-optimized", "gemini-3.1-flash-lite-preview"],
|
|
280
280
|
["openai", "cost-optimized", "gpt-5.4-nano"],
|
|
281
|
+
["openai", "balanced", "gpt-5.4-mini"],
|
|
282
|
+
["openai", "quality-optimized", "gpt-5.4"],
|
|
281
283
|
["fireworks", "balanced", "accounts/fireworks/models/kimi-k2p5"],
|
|
282
284
|
["fireworks", "balanced", "accounts/fireworks/models/kimi-k2p6"],
|
|
285
|
+
[
|
|
286
|
+
"fireworks",
|
|
287
|
+
"balanced",
|
|
288
|
+
"accounts/fireworks/models/deepseek-v4-flash-0731",
|
|
289
|
+
],
|
|
283
290
|
[
|
|
284
291
|
"fireworks",
|
|
285
292
|
"quality-optimized",
|
|
286
293
|
"accounts/fireworks/models/deepseek-v4-flash",
|
|
287
294
|
],
|
|
295
|
+
[
|
|
296
|
+
"fireworks",
|
|
297
|
+
"quality-optimized",
|
|
298
|
+
"accounts/fireworks/models/deepseek-v4-flash-0731",
|
|
299
|
+
],
|
|
300
|
+
[
|
|
301
|
+
"fireworks",
|
|
302
|
+
"cost-optimized",
|
|
303
|
+
"accounts/fireworks/models/deepseek-v4-flash",
|
|
304
|
+
],
|
|
288
305
|
] as const)(
|
|
289
306
|
"a historical intent-era copy converts (%s %s pinned to %s)",
|
|
290
307
|
(provider, key, model) => {
|
|
@@ -360,7 +360,6 @@ describe("CallSetupFlow name capture", () => {
|
|
|
360
360
|
).toEqual({ from: PHONE_NUMBER, callerName: CALLER_NAME });
|
|
361
361
|
expect(f.notifyCalls).toEqual([
|
|
362
362
|
{
|
|
363
|
-
canonicalAssistantId: "self",
|
|
364
363
|
sourceChannel: "phone",
|
|
365
364
|
conversationExternalId: PHONE_NUMBER,
|
|
366
365
|
actorExternalId: PHONE_NUMBER,
|
|
@@ -67,7 +67,7 @@ function makeConnectionHook(
|
|
|
67
67
|
byConnection: Record<string, Provider>,
|
|
68
68
|
): (
|
|
69
69
|
connectionName: string,
|
|
70
|
-
expectedProvider: string,
|
|
70
|
+
expectedProvider: string | undefined,
|
|
71
71
|
) => Promise<Provider | null> {
|
|
72
72
|
return async (connectionName, _expectedProvider) =>
|
|
73
73
|
byConnection[connectionName] ?? null;
|
|
@@ -57,6 +57,8 @@ const handler = ROUTES[0]!.handler;
|
|
|
57
57
|
|
|
58
58
|
interface ChannelEntry {
|
|
59
59
|
id: string;
|
|
60
|
+
/** `default` here, `plugin:<name>` for a channel a plugin brings. */
|
|
61
|
+
source: string;
|
|
60
62
|
label: string;
|
|
61
63
|
subtitle: string;
|
|
62
64
|
icon: string;
|
|
@@ -173,10 +175,21 @@ describe("channels/available", () => {
|
|
|
173
175
|
for (const channel of result.channels) {
|
|
174
176
|
const expected = (CHANNEL_METADATA as any)[channel.id];
|
|
175
177
|
expect(expected).toBeDefined();
|
|
176
|
-
|
|
178
|
+
// Plus `source`, which the metadata does not carry: it says who
|
|
179
|
+
// contributes the row, and every row here comes from the assistant.
|
|
180
|
+
expect(channel).toEqual({ ...expected, source: "default" });
|
|
177
181
|
}
|
|
178
182
|
});
|
|
179
183
|
|
|
184
|
+
test("marks every channel the assistant ships as its own", async () => {
|
|
185
|
+
// The base list is what a client compares a plugin-contributed row
|
|
186
|
+
// against, so the marker has to be present rather than implied by an
|
|
187
|
+
// absent field.
|
|
188
|
+
const result = (await handler({})) as HandlerResult;
|
|
189
|
+
|
|
190
|
+
expect(result.channels.every((c) => c.source === "default")).toBe(true);
|
|
191
|
+
});
|
|
192
|
+
|
|
180
193
|
test("email metadata: not verification-capable, mail icon", async () => {
|
|
181
194
|
mockEmailAddressesResponse = {
|
|
182
195
|
ok: true,
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<channel_capabilities>` must not accumulate one copy per turn, and
|
|
3
|
+
* deduplicating it must not disturb the cross-turn byte-identity that prompt
|
|
4
|
+
* caching depends on (see `prompt-cache-cross-turn-stability.test.ts`, which
|
|
5
|
+
* owns that invariant end to end).
|
|
6
|
+
*/
|
|
7
|
+
import { describe, expect, test } from "bun:test";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
dedupeChannelCapabilityBlocks,
|
|
11
|
+
preModelCallSanitize,
|
|
12
|
+
} from "../context/outbound-sanitize.js";
|
|
13
|
+
import type { Message } from "../providers/types.js";
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Fixtures, shaped like what runtime injection actually produces: the block is
|
|
17
|
+
// its OWN text content block, prepended to the turn-starting user message by
|
|
18
|
+
// `injectChannelCapabilityContext`, and then frozen into history.
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
const slackCapabilities = (dynamicUi = false): string =>
|
|
22
|
+
[
|
|
23
|
+
"<channel_capabilities>",
|
|
24
|
+
"channel: slack",
|
|
25
|
+
"dashboard_capable: false",
|
|
26
|
+
`supports_dynamic_ui: ${dynamicUi}`,
|
|
27
|
+
"supports_voice_input: false",
|
|
28
|
+
"",
|
|
29
|
+
"CHANNEL CONSTRAINTS:",
|
|
30
|
+
"- Do NOT reference the dashboard UI, settings panels, or visual preference pickers.",
|
|
31
|
+
'- Do NOT use app_create. Only use ui_show/ui_update for card surfaces with template: "task_progress"; present all other information as text.',
|
|
32
|
+
"- Present information as well-formatted text instead of dynamic UI.",
|
|
33
|
+
"</channel_capabilities>",
|
|
34
|
+
].join("\n");
|
|
35
|
+
|
|
36
|
+
const CAPS = slackCapabilities();
|
|
37
|
+
|
|
38
|
+
const turnContextBlock = (turn: number): string =>
|
|
39
|
+
[
|
|
40
|
+
"<turn_context>",
|
|
41
|
+
`current_time: 2026-05-21 (Thursday) 10:${String(turn).padStart(2, "0")}:00 -05:00 (America/Chicago)`,
|
|
42
|
+
"interface: slack",
|
|
43
|
+
"trust_class: guardian",
|
|
44
|
+
"</turn_context>",
|
|
45
|
+
].join("\n");
|
|
46
|
+
|
|
47
|
+
const userTurn = (turn: number, caps: string = CAPS): Message => ({
|
|
48
|
+
role: "user",
|
|
49
|
+
content: [
|
|
50
|
+
{ type: "text", text: turnContextBlock(turn) },
|
|
51
|
+
{ type: "text", text: caps },
|
|
52
|
+
{ type: "text", text: `User message ${turn}.` },
|
|
53
|
+
],
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const assistantTurn = (turn: number): Message => ({
|
|
57
|
+
role: "assistant",
|
|
58
|
+
content: [{ type: "text", text: `Reply ${turn}.` }],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/** An N-turn conversation, every user row carrying its own injected copy. */
|
|
62
|
+
const conversation = (turns: number): Message[] => {
|
|
63
|
+
const messages: Message[] = [];
|
|
64
|
+
for (let turn = 1; turn <= turns; turn++) {
|
|
65
|
+
messages.push(userTurn(turn));
|
|
66
|
+
if (turn < turns) {
|
|
67
|
+
messages.push(assistantTurn(turn));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return messages;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const allText = (messages: Message[]): string =>
|
|
74
|
+
messages
|
|
75
|
+
.flatMap((m) =>
|
|
76
|
+
m.content.filter((b) => b.type === "text").map((b) => b.text),
|
|
77
|
+
)
|
|
78
|
+
.join("\n");
|
|
79
|
+
|
|
80
|
+
const countOccurrences = (haystack: string, needle: string): number =>
|
|
81
|
+
haystack.split(needle).length - 1;
|
|
82
|
+
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
describe("<channel_capabilities> does not accumulate across a conversation", () => {
|
|
86
|
+
test("a 50-turn conversation carries exactly one copy", () => {
|
|
87
|
+
const raw = conversation(50);
|
|
88
|
+
expect(countOccurrences(allText(raw), "<channel_capabilities>")).toBe(50);
|
|
89
|
+
|
|
90
|
+
const text = allText(preModelCallSanitize(raw));
|
|
91
|
+
expect(countOccurrences(text, "<channel_capabilities>")).toBe(1);
|
|
92
|
+
expect(countOccurrences(text, "CHANNEL CONSTRAINTS:")).toBe(1);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("the surviving copy is the first one, unmodified", () => {
|
|
96
|
+
const sanitized = preModelCallSanitize(conversation(6));
|
|
97
|
+
expect(sanitized[0].content).toEqual(conversation(6)[0].content);
|
|
98
|
+
expect(allText([sanitized[2]])).not.toContain("<channel_capabilities>");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("outbound size stops growing with the repeated block", () => {
|
|
102
|
+
const rawGrowth =
|
|
103
|
+
allText(conversation(45)).length - allText(conversation(5)).length;
|
|
104
|
+
const sanitizedGrowth =
|
|
105
|
+
allText(preModelCallSanitize(conversation(45))).length -
|
|
106
|
+
allText(preModelCallSanitize(conversation(5))).length;
|
|
107
|
+
|
|
108
|
+
// Every extra raw turn pays for a full copy of the block; the deduplicated
|
|
109
|
+
// projection pays nothing for it.
|
|
110
|
+
expect((rawGrowth - sanitizedGrowth) / 40).toBeGreaterThanOrEqual(
|
|
111
|
+
CAPS.length,
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("everything else on the row is untouched", () => {
|
|
116
|
+
const sanitized = preModelCallSanitize(conversation(4));
|
|
117
|
+
// `<turn_context>` is deliberately left alone: it carries a fresh
|
|
118
|
+
// timestamp each turn and historical copies are read back by the
|
|
119
|
+
// compactor's tail resolution.
|
|
120
|
+
expect(countOccurrences(allText(sanitized), "<turn_context>")).toBe(4);
|
|
121
|
+
// The dropped block is the only thing that goes: the row keeps its
|
|
122
|
+
// `<turn_context>` and the user's own text, in order.
|
|
123
|
+
expect(sanitized[6].content).toEqual([
|
|
124
|
+
{ type: "text", text: turnContextBlock(4) },
|
|
125
|
+
{ type: "text", text: "User message 4." },
|
|
126
|
+
]);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe("cross-turn byte stability", () => {
|
|
131
|
+
test("a message renders identically no matter how many turns follow it", () => {
|
|
132
|
+
// The prompt cache is only readable when turn N's messages recur
|
|
133
|
+
// byte-identically at the same index in turn N+1. Deduplication must
|
|
134
|
+
// therefore depend only on what sits ABOVE a message, never on how far it
|
|
135
|
+
// is from the end.
|
|
136
|
+
const turn2 = preModelCallSanitize(conversation(2));
|
|
137
|
+
const turn20 = preModelCallSanitize(conversation(20));
|
|
138
|
+
|
|
139
|
+
turn2.forEach((message, index) => {
|
|
140
|
+
expect(JSON.stringify(turn20[index])).toBe(JSON.stringify(message));
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("the turn-starting message is not treated specially", () => {
|
|
145
|
+
const sanitized = preModelCallSanitize(conversation(3));
|
|
146
|
+
const turnStart = sanitized[sanitized.length - 1];
|
|
147
|
+
// Turn 3 opened this turn and still drops its duplicate copy, which is
|
|
148
|
+
// exactly what keeps it stable once turn 4 arrives.
|
|
149
|
+
expect(allText([turnStart])).not.toContain("<channel_capabilities>");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("is idempotent", () => {
|
|
153
|
+
const once = preModelCallSanitize(conversation(6));
|
|
154
|
+
expect(preModelCallSanitize(once)).toEqual(once);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe("changes and safety", () => {
|
|
159
|
+
test("capabilities that actually change mid-conversation are kept", () => {
|
|
160
|
+
const changed = slackCapabilities(true);
|
|
161
|
+
const history: Message[] = [
|
|
162
|
+
userTurn(1),
|
|
163
|
+
assistantTurn(1),
|
|
164
|
+
userTurn(2),
|
|
165
|
+
assistantTurn(2),
|
|
166
|
+
userTurn(3, changed),
|
|
167
|
+
assistantTurn(3),
|
|
168
|
+
userTurn(4, changed),
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
const sanitized = dedupeChannelCapabilityBlocks(history);
|
|
172
|
+
const text = allText(sanitized);
|
|
173
|
+
expect(countOccurrences(text, "<channel_capabilities>")).toBe(2);
|
|
174
|
+
expect(text).toContain("supports_dynamic_ui: false");
|
|
175
|
+
expect(text).toContain("supports_dynamic_ui: true");
|
|
176
|
+
// Turn 2 and turn 4 are the repeats and are the ones that go.
|
|
177
|
+
expect(allText([sanitized[2]])).not.toContain("<channel_capabilities>");
|
|
178
|
+
expect(allText([sanitized[6]])).not.toContain("<channel_capabilities>");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("a conversation with a single copy is returned untouched", () => {
|
|
182
|
+
const history = conversation(1);
|
|
183
|
+
expect(dedupeChannelCapabilityBlocks(history)).toBe(history);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test("user-authored text that merely mentions the tag is left alone", () => {
|
|
187
|
+
const authored =
|
|
188
|
+
"why does <channel_capabilities> say dashboard_capable: false?";
|
|
189
|
+
const history: Message[] = [
|
|
190
|
+
{ role: "user", content: [{ type: "text", text: authored }] },
|
|
191
|
+
assistantTurn(1),
|
|
192
|
+
{ role: "user", content: [{ type: "text", text: authored }] },
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
expect(dedupeChannelCapabilityBlocks(history)).toBe(history);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test("a user row made only of the block is never emptied or dropped", () => {
|
|
199
|
+
const history: Message[] = [
|
|
200
|
+
userTurn(1),
|
|
201
|
+
assistantTurn(1),
|
|
202
|
+
{ role: "user", content: [{ type: "text", text: CAPS }] },
|
|
203
|
+
assistantTurn(2),
|
|
204
|
+
userTurn(3),
|
|
205
|
+
];
|
|
206
|
+
|
|
207
|
+
const sanitized = dedupeChannelCapabilityBlocks(history);
|
|
208
|
+
expect(sanitized).toHaveLength(5);
|
|
209
|
+
expect(sanitized[2].content).toEqual(history[2].content);
|
|
210
|
+
// The all-block row is retained, so it becomes the baseline the later
|
|
211
|
+
// duplicate is measured against and turn 3 still drops.
|
|
212
|
+
expect(allText([sanitized[4]])).not.toContain("<channel_capabilities>");
|
|
213
|
+
});
|
|
214
|
+
});
|
|
@@ -504,23 +504,23 @@ describe("channel-delivery-store", () => {
|
|
|
504
504
|
expect(r1.conversationId).not.toBe(r2.conversationId);
|
|
505
505
|
});
|
|
506
506
|
|
|
507
|
-
test("same chat
|
|
508
|
-
const r1 = recordInbound("telegram", "chat-1", "msg-1"
|
|
509
|
-
|
|
510
|
-
});
|
|
511
|
-
const r2 = recordInbound("telegram", "chat-1", "msg-2", {
|
|
512
|
-
assistantId: "asst-B",
|
|
513
|
-
});
|
|
507
|
+
test("the same chat keeps the same conversation", () => {
|
|
508
|
+
const r1 = recordInbound("telegram", "chat-1", "msg-1");
|
|
509
|
+
const r2 = recordInbound("telegram", "chat-1", "msg-2");
|
|
514
510
|
|
|
515
|
-
expect(r1.conversationId).
|
|
511
|
+
expect(r1.conversationId).toBe(r2.conversationId);
|
|
516
512
|
});
|
|
517
513
|
|
|
518
|
-
test("
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
514
|
+
test("binds under the self-scoped key", () => {
|
|
515
|
+
// The prefix is a stored format, not an internal detail. It reads like a
|
|
516
|
+
// leftover of the assistant id that used to be interpolated into it, so
|
|
517
|
+
// pin it: rows already written under `asst:self:` stop resolving if a
|
|
518
|
+
// later tidy-up drops it.
|
|
519
|
+
const { conversationId } = recordInbound("telegram", "chat-1", "msg-1");
|
|
520
|
+
|
|
521
|
+
expect(
|
|
522
|
+
getConversationByKey("asst:self:telegram:chat-1")?.conversationId,
|
|
523
|
+
).toBe(conversationId);
|
|
524
524
|
});
|
|
525
525
|
|
|
526
526
|
test("external bindings allow multiple Slack thread anchors per channel", () => {
|
|
@@ -250,7 +250,7 @@ describe("channel inbound disk pressure gate", () => {
|
|
|
250
250
|
|
|
251
251
|
expect(body).toMatchObject({
|
|
252
252
|
accepted: true,
|
|
253
|
-
|
|
253
|
+
reaction: "dropped_disk_pressure",
|
|
254
254
|
diskPressure: "blocked",
|
|
255
255
|
reason: "trusted-contact",
|
|
256
256
|
});
|
|
@@ -268,9 +268,9 @@ describe("channel inbound disk pressure gate", () => {
|
|
|
268
268
|
eq(channelInboundEvents.externalMessageId, "slack-reaction-blocked"),
|
|
269
269
|
)
|
|
270
270
|
.get();
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
expect(event
|
|
271
|
+
// A blocked reaction writes nothing at all: it is dropped before the
|
|
272
|
+
// reacted message is resolved, so no event row is opened either.
|
|
273
|
+
expect(event).toBeUndefined();
|
|
274
274
|
expect(db.select().from(messages).all()).toHaveLength(0);
|
|
275
275
|
});
|
|
276
276
|
|
|
@@ -28,7 +28,7 @@ function makeContext(
|
|
|
28
28
|
): Conversation {
|
|
29
29
|
return asConversation({
|
|
30
30
|
conversationId: "session-1",
|
|
31
|
-
|
|
31
|
+
emit: (msg) => sent.push(msg),
|
|
32
32
|
pendingSurfaceActions: new Map<string, { surfaceType: SurfaceType }>(),
|
|
33
33
|
lastSurfaceAction: new Map<
|
|
34
34
|
string,
|