@vellumai/assistant 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +6 -7
- package/Dockerfile +1 -0
- package/README.md +2 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
- package/bun.lock +3 -0
- package/docs/architecture/security.md +18 -16
- package/knip.json +1 -0
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
- package/node_modules/@vellumai/slack-text/bun.lock +24 -0
- package/node_modules/@vellumai/slack-text/package.json +18 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
- package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
- package/openapi.yaml +294 -107
- package/package.json +4 -2
- package/scripts/generate-openapi.ts +16 -111
- package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
- package/src/__tests__/anthropic-provider.test.ts +56 -13
- package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
- package/src/__tests__/app-conversation-ids.test.ts +151 -0
- package/src/__tests__/approval-cascade.test.ts +0 -15
- package/src/__tests__/approval-routes-http.test.ts +6 -17
- package/src/__tests__/assistant-event-hub.test.ts +126 -77
- package/src/__tests__/assistant-event.test.ts +0 -5
- package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
- package/src/__tests__/background-shell-host-bash.test.ts +34 -43
- package/src/__tests__/call-controller.test.ts +1 -1
- package/src/__tests__/call-site-routing-provider.test.ts +193 -0
- package/src/__tests__/channel-approval-routes.test.ts +10 -296
- package/src/__tests__/channel-approvals.test.ts +25 -17
- package/src/__tests__/channel-guardian.test.ts +100 -146
- package/src/__tests__/checker.test.ts +20 -34
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/config-schema.test.ts +6 -48
- package/src/__tests__/config-watcher.test.ts +12 -0
- package/src/__tests__/connection-policy.test.ts +1 -52
- package/src/__tests__/contacts-write.test.ts +2 -64
- package/src/__tests__/context-image-dimensions.test.ts +1 -1
- package/src/__tests__/context-search-memory-source.test.ts +120 -1
- package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
- package/src/__tests__/context-search-pkb-source.test.ts +49 -0
- package/src/__tests__/context-search-workspace-source.test.ts +9 -22
- package/src/__tests__/context-window-manager.test.ts +46 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
- package/src/__tests__/conversation-agent-loop.test.ts +980 -13
- package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
- package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
- package/src/__tests__/conversation-history-web-search.test.ts +4 -3
- package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
- package/src/__tests__/conversation-lifecycle.test.ts +4 -4
- package/src/__tests__/conversation-process-callsite.test.ts +79 -2
- package/src/__tests__/conversation-queue.test.ts +3 -8
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
- package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
- package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
- package/src/__tests__/conversation-slash-commands.test.ts +24 -4
- package/src/__tests__/conversation-slash-queue.test.ts +2 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-starter-routes.test.ts +79 -2
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
- package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
- package/src/__tests__/conversation-usage.test.ts +253 -3
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
- package/src/__tests__/credential-health-service.test.ts +68 -0
- package/src/__tests__/credential-security-e2e.test.ts +4 -3
- package/src/__tests__/credential-security-invariants.test.ts +1 -5
- package/src/__tests__/credential-token-resolver.test.ts +180 -0
- package/src/__tests__/cu-unified-flow.test.ts +33 -16
- package/src/__tests__/daemon-assistant-events.test.ts +34 -21
- package/src/__tests__/daemon-credential-client.test.ts +4 -1
- package/src/__tests__/db-connection-isolation.test.ts +125 -0
- package/src/__tests__/db-migration-rollback.test.ts +101 -0
- package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
- package/src/__tests__/document-conversations.test.ts +332 -0
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
- package/src/__tests__/emit-event-signal.test.ts +4 -6
- package/src/__tests__/events-client-registration.test.ts +193 -49
- package/src/__tests__/filing-service.test.ts +58 -7
- package/src/__tests__/first-greeting.test.ts +156 -150
- package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
- package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -1
- package/src/__tests__/guardian-grant-minting.test.ts +7 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
- package/src/__tests__/guardian-routing-state.test.ts +1 -1
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
- package/src/__tests__/headless-browser-mode.test.ts +4 -9
- package/src/__tests__/headless-browser-navigate.test.ts +21 -20
- package/src/__tests__/heartbeat-service.test.ts +289 -7
- package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
- package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
- package/src/__tests__/host-bash-proxy.test.ts +46 -122
- package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
- package/src/__tests__/host-browser-proxy.test.ts +111 -185
- package/src/__tests__/host-browser-routes.test.ts +45 -75
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
- package/src/__tests__/host-cu-proxy.test.ts +56 -111
- package/src/__tests__/host-file-proxy.test.ts +44 -98
- package/src/__tests__/host-file-read-tool.test.ts +42 -21
- package/src/__tests__/host-shell-tool.test.ts +33 -68
- package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
- package/src/__tests__/host-transfer-proxy.test.ts +43 -53
- package/src/__tests__/http-user-message-parity.test.ts +0 -6
- package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
- package/src/__tests__/injector-chain.test.ts +10 -5
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
- package/src/__tests__/inline-command-runner.test.ts +0 -66
- package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
- package/src/__tests__/install-skill-routing.test.ts +1 -13
- package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
- package/src/__tests__/llm-catalog-parity.test.ts +90 -0
- package/src/__tests__/llm-context-resolution.test.ts +180 -0
- package/src/__tests__/llm-resolver.test.ts +80 -12
- package/src/__tests__/llm-usage-store.test.ts +269 -4
- package/src/__tests__/log-export-routes.test.ts +89 -0
- package/src/__tests__/managed-profile-guard.test.ts +225 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
- package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
- package/src/__tests__/migration-export-http.test.ts +33 -26
- package/src/__tests__/migration-export-streaming.test.ts +18 -10
- package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
- package/src/__tests__/migration-import-commit-http.test.ts +66 -21
- package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
- package/src/__tests__/migration-import-from-url.test.ts +20 -6
- package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
- package/src/__tests__/migration-parity-persistence.test.ts +62 -25
- package/src/__tests__/migration-transport.test.ts +115 -23
- package/src/__tests__/migration-validate-http.test.ts +105 -80
- package/src/__tests__/migration-wizard.test.ts +133 -27
- package/src/__tests__/non-member-access-request.test.ts +1 -1
- package/src/__tests__/notification-guardian-path.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +19 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
- package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
- package/src/__tests__/pricing.test.ts +68 -4
- package/src/__tests__/process-message-background-slack.test.ts +331 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
- package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
- package/src/__tests__/provider-usage-tracking.test.ts +208 -0
- package/src/__tests__/reaction-persistence.test.ts +9 -6
- package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
- package/src/__tests__/recording-handler.test.ts +64 -81
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
- package/src/__tests__/relay-server.test.ts +18 -13
- package/src/__tests__/require-fresh-approval.test.ts +13 -22
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
- package/src/__tests__/runtime-events-sse.test.ts +3 -12
- package/src/__tests__/search-skills-unified.test.ts +9 -15
- package/src/__tests__/secret-ingress-cli.test.ts +2 -5
- package/src/__tests__/secret-ingress-http.test.ts +0 -4
- package/src/__tests__/secret-onetime-send.test.ts +4 -2
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
- package/src/__tests__/secret-response-routing.test.ts +29 -15
- package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
- package/src/__tests__/secret-scanner.test.ts +2 -545
- package/src/__tests__/send-endpoint-busy.test.ts +9 -24
- package/src/__tests__/settings-routes.test.ts +1 -1
- package/src/__tests__/shell-credential-ref.test.ts +0 -8
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
- package/src/__tests__/skill-tool-factory.test.ts +97 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
- package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
- package/src/__tests__/slack-inbound-verification.test.ts +1 -62
- package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
- package/src/__tests__/subagent-manager-notify.test.ts +70 -70
- package/src/__tests__/subagent-notify-parent.test.ts +80 -83
- package/src/__tests__/system-prompt.test.ts +115 -13
- package/src/__tests__/terminal-tools.test.ts +0 -89
- package/src/__tests__/thread-backfill.test.ts +945 -31
- package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
- package/src/__tests__/tool-executor.test.ts +12 -19
- package/src/__tests__/tool-metrics-listener.test.ts +0 -35
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
- package/src/__tests__/tool-trace-listener.test.ts +0 -17
- package/src/__tests__/transfer-progress-screen.test.ts +63 -26
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
- package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
- package/src/__tests__/trusted-contact-verification.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +16 -5
- package/src/__tests__/usage-attribution.test.ts +247 -0
- package/src/__tests__/usage-cli.test.ts +143 -0
- package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
- package/src/__tests__/usage-routes.test.ts +150 -0
- package/src/__tests__/validation-results-screen.test.ts +39 -16
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
- package/src/__tests__/voice-session-bridge.test.ts +5 -5
- package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
- package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
- package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
- package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
- package/src/acp/index.ts +0 -15
- package/src/acp/session-manager.ts +37 -34
- package/src/agent/loop.ts +16 -1
- package/src/approvals/AGENTS.md +4 -0
- package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
- package/src/approvals/guardian-request-resolvers.ts +10 -2
- package/src/backup/__tests__/backup-worker.test.ts +36 -8
- package/src/backup/__tests__/paths.test.ts +2 -2
- package/src/backup/__tests__/restore.test.ts +45 -28
- package/src/backup/backup-worker.ts +36 -2
- package/src/backup/paths.ts +9 -6
- package/src/browser-session/events.ts +0 -9
- package/src/calls/call-store.ts +1 -34
- package/src/calls/guardian-question-copy.ts +0 -108
- package/src/calls/relay-server.ts +0 -24
- package/src/calls/twilio-rest.ts +0 -38
- package/src/calls/twilio-routes.ts +1 -1
- package/src/calls/voice-session-bridge.ts +7 -38
- package/src/channels/types.ts +1 -36
- package/src/cli/commands/__tests__/cache.test.ts +152 -5
- package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
- package/src/cli/commands/__tests__/trust.test.ts +21 -387
- package/src/cli/commands/backup.ts +4 -4
- package/src/cli/commands/cache-fs.ts +8 -0
- package/src/cli/commands/cache.ts +153 -82
- package/src/cli/commands/clients.ts +63 -5
- package/src/cli/commands/completions.ts +3 -3
- package/src/cli/commands/contacts.ts +231 -76
- package/src/cli/commands/keys.ts +4 -1
- package/src/cli/commands/memory-v2.ts +24 -52
- package/src/cli/commands/oauth/shared.ts +2 -29
- package/src/cli/commands/pending.ts +102 -0
- package/src/cli/commands/skills.ts +77 -35
- package/src/cli/commands/trust.ts +70 -430
- package/src/cli/commands/usage.ts +25 -16
- package/src/cli/lib/daemon-credential-client.ts +14 -0
- package/src/cli/program.ts +2 -0
- package/src/cli.ts +0 -21
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
- package/src/config/env-registry.ts +12 -2
- package/src/config/env.ts +3 -14
- package/src/config/feature-flag-registry.json +30 -30
- package/src/config/llm-callsite-catalog.ts +12 -0
- package/src/config/llm-context-resolution.ts +80 -0
- package/src/config/llm-resolver.ts +58 -22
- package/src/config/loader.ts +3 -3
- package/src/config/schema.ts +2 -158
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +271 -0
- package/src/config/schemas/calls.ts +5 -5
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/ingress.ts +1 -1
- package/src/config/schemas/llm.ts +31 -3
- package/src/config/schemas/memory-retrieval.ts +2 -2
- package/src/config/schemas/memory-v2.ts +9 -0
- package/src/config/schemas/security.ts +1 -42
- package/src/config/schemas/services.ts +6 -6
- package/src/config/schemas/skills.ts +5 -5
- package/src/config/schemas/tts.ts +1 -1
- package/src/config/seed-inference-profiles.ts +117 -0
- package/src/config/skills.ts +0 -90
- package/src/config/types.ts +3 -6
- package/src/contacts/contact-store.ts +0 -17
- package/src/contacts/contacts-write.ts +1 -105
- package/src/context/window-manager.ts +44 -5
- package/src/credential-execution/process-manager.ts +34 -10
- package/src/credential-health/credential-health-service.ts +21 -16
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
- package/src/daemon/connection-policy.ts +1 -26
- package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
- package/src/daemon/conversation-agent-loop.ts +277 -36
- package/src/daemon/conversation-history.ts +8 -8
- package/src/daemon/conversation-launch.ts +20 -135
- package/src/daemon/conversation-lifecycle.ts +1 -1
- package/src/daemon/conversation-messaging.ts +1 -0
- package/src/daemon/conversation-process.ts +83 -163
- package/src/daemon/conversation-runtime-assembly.ts +219 -76
- package/src/daemon/conversation-slash.ts +47 -5
- package/src/daemon/conversation-store.ts +7 -31
- package/src/daemon/conversation-surfaces.ts +22 -28
- package/src/daemon/conversation-tool-setup.ts +3 -33
- package/src/daemon/conversation-usage.ts +36 -0
- package/src/daemon/conversation.ts +117 -233
- package/src/daemon/daemon-control.ts +3 -71
- package/src/daemon/daemon-skill-host.ts +8 -11
- package/src/daemon/dictation-profile-store.ts +2 -26
- package/src/daemon/first-greeting.ts +44 -156
- package/src/daemon/handlers/config-channels.ts +12 -12
- package/src/daemon/handlers/config-ingress.ts +4 -165
- package/src/daemon/handlers/config-model.ts +1 -1
- package/src/daemon/handlers/config-voice.ts +0 -42
- package/src/daemon/handlers/conversations.ts +11 -190
- package/src/daemon/handlers/recording.ts +26 -158
- package/src/daemon/handlers/shared.ts +23 -71
- package/src/daemon/handlers/skills.ts +42 -93
- package/src/daemon/host-bash-proxy.ts +67 -45
- package/src/daemon/host-browser-proxy.ts +65 -27
- package/src/daemon/host-cu-proxy.ts +40 -39
- package/src/daemon/host-file-proxy.ts +58 -37
- package/src/daemon/host-transfer-proxy.ts +84 -46
- package/src/daemon/lifecycle.ts +49 -15
- package/src/daemon/message-types/conversations.ts +7 -0
- package/src/daemon/message-types/host-bash.ts +1 -0
- package/src/daemon/message-types/host-cu.ts +1 -0
- package/src/daemon/message-types/host-file.ts +1 -0
- package/src/daemon/message-types/host-transfer.ts +1 -0
- package/src/daemon/message-types/messages.ts +10 -9
- package/src/daemon/message-types/workspace.ts +1 -1
- package/src/daemon/process-message.ts +102 -239
- package/src/daemon/server.ts +13 -462
- package/src/daemon/shutdown-handlers.ts +2 -2
- package/src/daemon/tool-side-effects.ts +125 -107
- package/src/daemon/trust-context.ts +13 -0
- package/src/daemon/wake-target-adapter.ts +4 -9
- package/src/events/domain-events.ts +0 -8
- package/src/events/tool-audit-listener.ts +3 -1
- package/src/events/tool-domain-event-publisher.ts +0 -10
- package/src/events/tool-metrics-listener.ts +0 -17
- package/src/events/tool-trace-listener.ts +0 -14
- package/src/filing/filing-service.ts +13 -1
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
- package/src/heartbeat/heartbeat-service.ts +23 -5
- package/src/home/__tests__/feed-writer.test.ts +0 -4
- package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
- package/src/home/feed-writer.ts +1 -2
- package/src/home/relationship-state-writer.ts +16 -3
- package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
- package/src/ipc/assistant-server.ts +3 -10
- package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
- package/src/ipc/routes/route-adapter.ts +1 -1
- package/src/ipc/routes/trust-rules.test.ts +0 -95
- package/src/ipc/skill-ipc-types.ts +41 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
- package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
- package/src/ipc/skill-routes/events.ts +12 -23
- package/src/ipc/skill-routes/identity.ts +4 -17
- package/src/ipc/skill-routes/index.ts +1 -1
- package/src/ipc/skill-server.ts +6 -39
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
- package/src/live-voice/protocol.ts +4 -13
- package/src/mcp/manager.ts +0 -5
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
- package/src/memory/app-git-service.ts +0 -32
- package/src/memory/app-store.ts +154 -0
- package/src/memory/attachments-store.ts +6 -0
- package/src/memory/context-search/sources/memory-v2.ts +578 -0
- package/src/memory/context-search/sources/memory.ts +5 -0
- package/src/memory/context-search/sources/pkb.ts +10 -1
- package/src/memory/context-search/sources/workspace.ts +3 -2
- package/src/memory/conversation-crud.ts +29 -4
- package/src/memory/conversation-disk-view.ts +1 -5
- package/src/memory/conversation-starter-checkpoints.ts +63 -0
- package/src/memory/db-connection.ts +62 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +3 -21
- package/src/memory/embedding-gemini.ts +0 -2
- package/src/memory/embedding-local.ts +6 -6
- package/src/memory/embedding-ollama.ts +6 -6
- package/src/memory/embedding-openai.ts +6 -6
- package/src/memory/embedding-types.ts +21 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
- package/src/memory/graph/conversation-graph-memory.ts +35 -13
- package/src/memory/graph/injection.test.ts +2 -2
- package/src/memory/graph/injection.ts +1 -1
- package/src/memory/guardian-action-store.ts +0 -83
- package/src/memory/guardian-approvals.ts +0 -48
- package/src/memory/indexer.ts +1 -15
- package/src/memory/job-handlers/conversation-starters.ts +36 -53
- package/src/memory/job-utils.ts +0 -6
- package/src/memory/jobs-store.ts +0 -1
- package/src/memory/jobs-worker.ts +2 -16
- package/src/memory/llm-request-log-store.ts +0 -41
- package/src/memory/llm-usage-store.ts +129 -43
- package/src/memory/memory-v2-activation-log-store.ts +115 -0
- package/src/memory/migrations/233-document-conversations.ts +54 -0
- package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
- package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
- package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
- package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
- package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
- package/src/memory/migrations/index.ts +14 -0
- package/src/memory/migrations/registry.ts +24 -0
- package/src/memory/raw-query.ts +2 -68
- package/src/memory/schema/conversations.ts +7 -0
- package/src/memory/schema/infrastructure.ts +25 -0
- package/src/memory/search/semantic.ts +5 -16
- package/src/memory/tool-usage-store.ts +2 -0
- package/src/memory/usage-buckets.ts +40 -1
- package/src/memory/usage-grouped-buckets.ts +127 -0
- package/src/memory/v2/__tests__/activation.test.ts +289 -90
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
- package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
- package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
- package/src/memory/v2/__tests__/injection.test.ts +384 -15
- package/src/memory/v2/__tests__/migration.test.ts +64 -36
- package/src/memory/v2/__tests__/page-store.test.ts +191 -8
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
- package/src/memory/v2/__tests__/static-context.test.ts +153 -0
- package/src/memory/v2/activation.ts +168 -97
- package/src/memory/v2/backfill-jobs.ts +15 -100
- package/src/memory/v2/consolidation-job.ts +14 -12
- package/src/memory/v2/edge-index.ts +191 -0
- package/src/memory/v2/injection.ts +182 -58
- package/src/memory/v2/migration.ts +57 -64
- package/src/memory/v2/now-text.ts +2 -3
- package/src/memory/v2/page-store.ts +168 -31
- package/src/memory/v2/prompts/consolidation.ts +118 -42
- package/src/memory/v2/prompts/sweep.ts +3 -3
- package/src/memory/v2/skill-store.ts +55 -7
- package/src/memory/v2/static-context.ts +62 -0
- package/src/memory/v2/types.ts +10 -20
- package/src/memory/validation.ts +0 -11
- package/src/messaging/draft-store.ts +0 -6
- package/src/messaging/provider-types.ts +8 -0
- package/src/messaging/provider.ts +7 -0
- package/src/messaging/providers/gmail/client.ts +1 -121
- package/src/messaging/providers/outlook/client.ts +0 -73
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
- package/src/messaging/providers/slack/adapter.ts +122 -21
- package/src/messaging/providers/slack/backfill.test.ts +95 -6
- package/src/messaging/providers/slack/backfill.ts +89 -11
- package/src/messaging/providers/slack/client.ts +10 -124
- package/src/messaging/providers/slack/message-metadata.ts +12 -2
- package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
- package/src/messaging/providers/slack/render-transcript.ts +126 -25
- package/src/messaging/providers/slack/types.ts +1 -0
- package/src/oauth/connection-resolver.test.ts +8 -0
- package/src/oauth/connection-resolver.ts +8 -16
- package/src/oauth/credential-token-resolver.ts +97 -0
- package/src/oauth/manual-token-connection.ts +30 -34
- package/src/oauth/oauth-store.ts +6 -4
- package/src/outbound-proxy/certs.ts +0 -7
- package/src/outbound-proxy/config.ts +0 -74
- package/src/outbound-proxy/health.ts +0 -44
- package/src/outbound-proxy/index.ts +0 -22
- package/src/permissions/approval-provenance.test.ts +184 -0
- package/src/permissions/approval-provenance.ts +70 -0
- package/src/permissions/checker.ts +4 -1
- package/src/permissions/gateway-threshold-reader.ts +4 -1
- package/src/permissions/prompter.ts +9 -2
- package/src/permissions/secret-prompter.ts +21 -48
- package/src/permissions/types.ts +33 -0
- package/src/permissions/workspace-policy.ts +0 -5
- package/src/platform/sync-identity.ts +0 -8
- package/src/plugins/defaults/injectors.ts +69 -2
- package/src/plugins/defaults/overflow-reduce.ts +3 -2
- package/src/plugins/types.ts +8 -0
- package/src/prompts/system-prompt.ts +34 -70
- package/src/prompts/templates/BOOTSTRAP.md +52 -6
- package/src/prompts/update-bulletin-job.ts +2 -0
- package/src/providers/__tests__/retry-callsite.test.ts +138 -1
- package/src/providers/anthropic/client.ts +72 -33
- package/src/providers/call-site-routing.ts +42 -3
- package/src/providers/gemini/client.ts +18 -2
- package/src/providers/managed-proxy/context.ts +0 -5
- package/src/providers/model-catalog.ts +105 -19
- package/src/providers/openai/chat-completions-provider.ts +6 -0
- package/src/providers/openai/responses-provider.ts +7 -1
- package/src/providers/provider-send-message.ts +45 -2
- package/src/providers/ratelimit.ts +7 -2
- package/src/providers/registry.ts +14 -9
- package/src/providers/retry.ts +96 -8
- package/src/providers/types.ts +13 -0
- package/src/providers/usage-tracking.ts +96 -0
- package/src/runtime/AGENTS.md +10 -6
- package/src/runtime/__tests__/agent-wake.test.ts +89 -0
- package/src/runtime/agent-wake.ts +39 -2
- package/src/runtime/assistant-event-hub.ts +541 -45
- package/src/runtime/assistant-event.ts +1 -6
- package/src/runtime/auth/context.ts +0 -9
- package/src/runtime/auth/middleware.ts +1 -1
- package/src/runtime/auth/route-policy.ts +11 -9
- package/src/runtime/auth/token-service.ts +0 -11
- package/src/runtime/channel-approvals.ts +6 -2
- package/src/runtime/channel-verification-service.ts +3 -5
- package/src/runtime/http-errors.ts +0 -34
- package/src/runtime/http-router.ts +6 -3
- package/src/runtime/http-server.ts +22 -82
- package/src/runtime/http-types.ts +5 -0
- package/src/runtime/interactive-ui.ts +0 -1
- package/src/runtime/middleware/auth.ts +0 -20
- package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
- package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
- package/src/runtime/migrations/migration-transport.ts +46 -13
- package/src/runtime/migrations/migration-wizard.ts +2 -2
- package/src/runtime/migrations/origin-mode.ts +40 -0
- package/src/runtime/migrations/vbundle-builder.ts +133 -79
- package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
- package/src/runtime/migrations/vbundle-importer.ts +7 -7
- package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
- package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
- package/src/runtime/migrations/vbundle-validator.ts +214 -41
- package/src/runtime/pending-interactions.ts +13 -4
- package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
- package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
- package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
- package/src/runtime/routes/acp-routes.test.ts +0 -3
- package/src/runtime/routes/acp-routes.ts +3 -7
- package/src/runtime/routes/app-management-routes.ts +18 -9
- package/src/runtime/routes/approval-routes.ts +55 -14
- package/src/runtime/routes/avatar-routes.ts +3 -5
- package/src/runtime/routes/browser-routes.ts +1 -15
- package/src/runtime/routes/channel-guardian-routes.ts +1 -5
- package/src/runtime/routes/channel-readiness-routes.ts +3 -7
- package/src/runtime/routes/channel-route-shared.ts +2 -28
- package/src/runtime/routes/client-routes.ts +45 -12
- package/src/runtime/routes/consolidation-routes.ts +115 -0
- package/src/runtime/routes/conversation-list-routes.ts +12 -29
- package/src/runtime/routes/conversation-management-routes.ts +14 -51
- package/src/runtime/routes/conversation-query-routes.ts +120 -8
- package/src/runtime/routes/conversation-routes.ts +44 -528
- package/src/runtime/routes/conversation-starter-routes.ts +19 -40
- package/src/runtime/routes/documents-routes.ts +53 -18
- package/src/runtime/routes/events-routes.ts +59 -91
- package/src/runtime/routes/filing-routes.ts +18 -1
- package/src/runtime/routes/guardian-action-routes.ts +4 -9
- package/src/runtime/routes/host-bash-routes.ts +3 -2
- package/src/runtime/routes/host-browser-routes.ts +9 -33
- package/src/runtime/routes/host-cu-routes.ts +6 -1
- package/src/runtime/routes/host-file-routes.ts +3 -2
- package/src/runtime/routes/host-transfer-routes.ts +11 -15
- package/src/runtime/routes/identity-routes.ts +78 -6
- package/src/runtime/routes/inbound-message-handler.ts +580 -137
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
- package/src/runtime/routes/index.ts +4 -0
- package/src/runtime/routes/integrations/slack/channel.ts +0 -24
- package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
- package/src/runtime/routes/memory-v2-routes.ts +10 -15
- package/src/runtime/routes/migration-routes.ts +188 -31
- package/src/runtime/routes/playground/guard.ts +1 -1
- package/src/runtime/routes/playground/index.ts +0 -2
- package/src/runtime/routes/recording-routes.ts +4 -24
- package/src/runtime/routes/rename-conversation-routes.ts +2 -6
- package/src/runtime/routes/schedule-routes.ts +3 -6
- package/src/runtime/routes/secret-routes.ts +87 -18
- package/src/runtime/routes/settings-routes.ts +29 -28
- package/src/runtime/routes/skills-routes.ts +12 -31
- package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
- package/src/runtime/routes/task-routes.ts +6 -6
- package/src/runtime/routes/trust-rules-routes.ts +3 -94
- package/src/runtime/routes/types.ts +4 -4
- package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
- package/src/runtime/routes/usage-routes.ts +87 -10
- package/src/runtime/routes/user-routes.ts +17 -31
- package/src/runtime/routes/work-items-routes.ts +1 -4
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
- package/src/runtime/services/analyze-conversation.ts +7 -17
- package/src/runtime/services/conversation-serializer.ts +2 -4
- package/src/runtime/verification-outbound-actions.ts +1 -1
- package/src/runtime/verification-rate-limiter.ts +1 -1
- package/src/schedule/schedule-store.ts +0 -16
- package/src/security/secret-scanner.ts +14 -547
- package/src/security/secure-keys.ts +31 -11
- package/src/security/token-manager.ts +7 -3
- package/src/signals/cancel.ts +16 -25
- package/src/signals/conversation-undo.ts +2 -27
- package/src/signals/emit-event.ts +1 -2
- package/src/signals/user-message.ts +108 -22
- package/src/skills/catalog-install.ts +1 -0
- package/src/skills/clawhub.ts +2 -2
- package/src/skills/inline-command-runner.ts +1 -7
- package/src/subagent/manager.ts +67 -84
- package/src/tasks/task-store.ts +1 -28
- package/src/telemetry/types.ts +6 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
- package/src/telemetry/usage-telemetry-reporter.ts +3 -5
- package/src/tools/acp/spawn.test.ts +1 -2
- package/src/tools/acp/steer.test.ts +1 -2
- package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
- package/src/tools/browser/browser-execution.ts +31 -147
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
- package/src/tools/browser/cdp-client/factory.ts +48 -76
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/executor.ts +44 -31
- package/src/tools/host-filesystem/edit.ts +3 -2
- package/src/tools/host-filesystem/read.ts +3 -2
- package/src/tools/host-filesystem/transfer.test.ts +45 -42
- package/src/tools/host-filesystem/transfer.ts +4 -3
- package/src/tools/host-filesystem/write.ts +3 -2
- package/src/tools/host-terminal/host-shell.ts +4 -3
- package/src/tools/network/script-proxy/index.ts +1 -10
- package/src/tools/permission-checker.ts +66 -1
- package/src/tools/skills/sandbox-runner.ts +1 -6
- package/src/tools/skills/skill-tool-factory.ts +32 -0
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/terminal/shell.ts +2 -78
- package/src/tools/types.ts +12 -39
- package/src/tts/__tests__/provider-catalog.test.ts +2 -2
- package/src/tts/provider-catalog.ts +1 -1
- package/src/usage/actors.ts +2 -1
- package/src/usage/attribution.ts +185 -0
- package/src/usage/pricing.ts +166 -0
- package/src/usage/types.ts +14 -0
- package/src/util/json.ts +13 -0
- package/src/util/logger.ts +3 -3
- package/src/util/pricing.ts +50 -3
- package/src/work-items/work-item-runner.ts +15 -42
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
- package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
- package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
- package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
- package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
- package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/provider-commit-message-generator.ts +3 -3
- package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
- package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
- package/src/__tests__/secret-detection-handler.test.ts +0 -67
- package/src/__tests__/secret-scanner-executor.test.ts +0 -450
- package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
- package/src/__tests__/terminal-sandbox.test.ts +0 -374
- package/src/__tests__/tool-notification-listener.test.ts +0 -65
- package/src/context/__tests__/microcompact.test.ts +0 -805
- package/src/context/microcompact.ts +0 -443
- package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
- package/src/events/tool-notification-listener.ts +0 -17
- package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
- package/src/memory/v2/__tests__/edges.test.ts +0 -435
- package/src/memory/v2/edges.ts +0 -217
- package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
- package/src/runtime/__tests__/client-registry.test.ts +0 -271
- package/src/runtime/chrome-extension-registry.ts +0 -368
- package/src/runtime/client-registry.ts +0 -254
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
- package/src/tools/secret-detection-handler.ts +0 -269
- package/src/tools/terminal/backends/native.ts +0 -327
- package/src/tools/terminal/backends/types.ts +0 -37
- package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
- package/src/tools/terminal/sandbox.ts +0 -40
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Tests for slash command interception in the POST /v1/messages handler.
|
|
3
3
|
*
|
|
4
4
|
* Validates that:
|
|
5
|
-
* - Built-in slash commands (/
|
|
5
|
+
* - Built-in slash commands (/context, /models, /commands) are intercepted and
|
|
6
6
|
* do NOT trigger the agent loop.
|
|
7
7
|
* - Regular messages pass through to the agent loop unchanged.
|
|
8
8
|
*/
|
|
@@ -10,19 +10,13 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
|
10
10
|
|
|
11
11
|
mock.module("../config/env.js", () => ({ isHttpAuthDisabled: () => true }));
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
content: _content,
|
|
19
|
-
}),
|
|
13
|
+
const formatCompactResultMock = mock(
|
|
14
|
+
(result: { maxInputTokens: number }) =>
|
|
15
|
+
`Context Compacted\n\nContext: 10,000 / ${result.maxInputTokens.toLocaleString(
|
|
16
|
+
"en-US",
|
|
17
|
+
)} tokens`,
|
|
20
18
|
);
|
|
21
19
|
|
|
22
|
-
mock.module("../daemon/conversation-slash.js", () => ({
|
|
23
|
-
resolveSlash: resolveSlashMock,
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
20
|
mock.module("../config/loader.js", () => ({
|
|
27
21
|
getConfig: () => ({
|
|
28
22
|
ui: {},
|
|
@@ -56,7 +50,11 @@ mock.module("../config/loader.js", () => ({
|
|
|
56
50
|
},
|
|
57
51
|
},
|
|
58
52
|
},
|
|
59
|
-
profiles: {
|
|
53
|
+
profiles: {
|
|
54
|
+
"short-context": {
|
|
55
|
+
contextWindow: { maxInputTokens: 150000 },
|
|
56
|
+
},
|
|
57
|
+
},
|
|
60
58
|
callSites: {},
|
|
61
59
|
pricingOverrides: [],
|
|
62
60
|
},
|
|
@@ -133,6 +131,7 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
133
131
|
content: string,
|
|
134
132
|
metadata?: Record<string, unknown>,
|
|
135
133
|
) => addMessageMock(conversationId, role, content, metadata),
|
|
134
|
+
getConversationOverrideProfile: () => "short-context",
|
|
136
135
|
getMessages: () => [],
|
|
137
136
|
provenanceFromTrustContext: (ctx: unknown) =>
|
|
138
137
|
ctx
|
|
@@ -152,6 +151,7 @@ mock.module("../daemon/conversation-process.js", () => ({
|
|
|
152
151
|
isModelSlashCommand: (content: string) => {
|
|
153
152
|
return content.trim() === "/models";
|
|
154
153
|
},
|
|
154
|
+
formatCompactResult: formatCompactResultMock,
|
|
155
155
|
}));
|
|
156
156
|
|
|
157
157
|
mock.module("../runtime/local-actor-identity.js", () => ({
|
|
@@ -220,6 +220,21 @@ function makeConversation() {
|
|
|
220
220
|
) => undefined,
|
|
221
221
|
);
|
|
222
222
|
const setPreactivatedSkillIds = mock((_ids: string[] | undefined) => {});
|
|
223
|
+
const forceCompact = mock(async () => ({
|
|
224
|
+
messages: [],
|
|
225
|
+
compacted: true,
|
|
226
|
+
previousEstimatedInputTokens: 12000,
|
|
227
|
+
estimatedInputTokens: 10000,
|
|
228
|
+
maxInputTokens: 150000,
|
|
229
|
+
thresholdTokens: 120000,
|
|
230
|
+
compactedMessages: 2,
|
|
231
|
+
compactedPersistedMessages: 2,
|
|
232
|
+
summaryCalls: 1,
|
|
233
|
+
summaryInputTokens: 500,
|
|
234
|
+
summaryOutputTokens: 100,
|
|
235
|
+
summaryModel: "claude-opus-4-7",
|
|
236
|
+
summaryText: "Summary",
|
|
237
|
+
}));
|
|
223
238
|
const events: unknown[] = [];
|
|
224
239
|
const messages: unknown[] = [];
|
|
225
240
|
const conversation = {
|
|
@@ -236,17 +251,14 @@ function makeConversation() {
|
|
|
236
251
|
enqueueMessage: () => ({ queued: true, requestId: "queued-id" }),
|
|
237
252
|
persistUserMessage,
|
|
238
253
|
runAgentLoop,
|
|
254
|
+
forceCompact,
|
|
239
255
|
setPreactivatedSkillIds,
|
|
240
256
|
drainQueue: async () => {},
|
|
241
257
|
getMessages: () => messages,
|
|
242
258
|
assistantId: "self",
|
|
243
259
|
trustContext: undefined,
|
|
244
260
|
hasPendingConfirmation: () => false,
|
|
245
|
-
setHostBashProxy: () => {},
|
|
246
261
|
setHostBrowserProxy: () => {},
|
|
247
|
-
setHostFileProxy: () => {},
|
|
248
|
-
setHostTransferProxy: () => {},
|
|
249
|
-
getHostTransferProxy: () => undefined,
|
|
250
262
|
setHostCuProxy: () => {},
|
|
251
263
|
addPreactivatedSkillId: () => {},
|
|
252
264
|
usageStats: {
|
|
@@ -262,13 +274,18 @@ function makeConversation() {
|
|
|
262
274
|
setPreactivatedSkillIds,
|
|
263
275
|
events,
|
|
264
276
|
messages,
|
|
277
|
+
forceCompact,
|
|
265
278
|
};
|
|
266
279
|
}
|
|
267
280
|
|
|
268
281
|
function makeRequest(content: string, extras: Record<string, unknown> = {}) {
|
|
269
282
|
return new Request("http://localhost/v1/messages", {
|
|
270
283
|
method: "POST",
|
|
271
|
-
headers: {
|
|
284
|
+
headers: {
|
|
285
|
+
"Content-Type": "application/json",
|
|
286
|
+
"x-vellum-actor-principal-id": "test-user",
|
|
287
|
+
"x-vellum-principal-type": "actor",
|
|
288
|
+
},
|
|
272
289
|
body: JSON.stringify({
|
|
273
290
|
conversationKey: "slash-test-key",
|
|
274
291
|
content,
|
|
@@ -293,22 +310,17 @@ function makeDeps(
|
|
|
293
310
|
|
|
294
311
|
describe("handleSendMessage slash command interception", () => {
|
|
295
312
|
beforeEach(() => {
|
|
296
|
-
|
|
313
|
+
formatCompactResultMock.mockClear();
|
|
297
314
|
addMessageMock.mockClear();
|
|
298
315
|
ipcCallMock.mockClear();
|
|
299
316
|
});
|
|
300
317
|
|
|
301
318
|
test("intercepts built-in slash commands (unknown kind) without calling agent loop", async () => {
|
|
302
|
-
resolveSlashMock.mockReturnValue({
|
|
303
|
-
kind: "unknown",
|
|
304
|
-
message: "Conversation Status\n\nContext: 5%",
|
|
305
|
-
});
|
|
306
|
-
|
|
307
319
|
const { conversation, persistUserMessage, runAgentLoop } =
|
|
308
320
|
makeConversation();
|
|
309
321
|
const res = await callHandler(
|
|
310
322
|
(args) => handleSendMessage(args, makeDeps(conversation)),
|
|
311
|
-
makeRequest("/
|
|
323
|
+
makeRequest("/context"),
|
|
312
324
|
undefined,
|
|
313
325
|
202,
|
|
314
326
|
);
|
|
@@ -321,10 +333,6 @@ describe("handleSendMessage slash command interception", () => {
|
|
|
321
333
|
expect(body.accepted).toBe(true);
|
|
322
334
|
expect(body.messageId).toBe("persisted-user-id");
|
|
323
335
|
|
|
324
|
-
// Slash command was resolved
|
|
325
|
-
expect(resolveSlashMock).toHaveBeenCalledTimes(1);
|
|
326
|
-
expect(resolveSlashMock.mock.calls[0][0]).toBe("/status");
|
|
327
|
-
|
|
328
336
|
// User + assistant messages persisted, but agent loop NOT called
|
|
329
337
|
expect(addMessageMock).toHaveBeenCalledTimes(2);
|
|
330
338
|
const roles = addMessageMock.mock.calls.map((c) => c[1]);
|
|
@@ -333,12 +341,35 @@ describe("handleSendMessage slash command interception", () => {
|
|
|
333
341
|
expect(runAgentLoop).not.toHaveBeenCalled();
|
|
334
342
|
});
|
|
335
343
|
|
|
336
|
-
test("
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
344
|
+
test("handles /compact without calling agent loop and formats the compaction max", async () => {
|
|
345
|
+
const { conversation, persistUserMessage, runAgentLoop, forceCompact } =
|
|
346
|
+
makeConversation();
|
|
347
|
+
const res = await callHandler(
|
|
348
|
+
(args) => handleSendMessage(args, makeDeps(conversation)),
|
|
349
|
+
makeRequest("/compact"),
|
|
350
|
+
undefined,
|
|
351
|
+
202,
|
|
352
|
+
);
|
|
341
353
|
|
|
354
|
+
expect(res.status).toBe(202);
|
|
355
|
+
const body = (await res.json()) as {
|
|
356
|
+
accepted: boolean;
|
|
357
|
+
messageId?: string;
|
|
358
|
+
};
|
|
359
|
+
expect(body.accepted).toBe(true);
|
|
360
|
+
expect(body.messageId).toBe("persisted-user-id");
|
|
361
|
+
|
|
362
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
363
|
+
|
|
364
|
+
expect(forceCompact).toHaveBeenCalledTimes(1);
|
|
365
|
+
expect(formatCompactResultMock).toHaveBeenCalledWith(
|
|
366
|
+
expect.objectContaining({ maxInputTokens: 150000 }),
|
|
367
|
+
);
|
|
368
|
+
expect(persistUserMessage).not.toHaveBeenCalled();
|
|
369
|
+
expect(runAgentLoop).not.toHaveBeenCalled();
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test("passes regular messages through to agent loop unchanged", async () => {
|
|
342
373
|
const {
|
|
343
374
|
conversation,
|
|
344
375
|
persistUserMessage,
|
|
@@ -354,9 +385,6 @@ describe("handleSendMessage slash command interception", () => {
|
|
|
354
385
|
|
|
355
386
|
expect(res.status).toBe(202);
|
|
356
387
|
|
|
357
|
-
// Slash command was resolved but passed through
|
|
358
|
-
expect(resolveSlashMock).toHaveBeenCalledTimes(1);
|
|
359
|
-
|
|
360
388
|
// No skill preactivation
|
|
361
389
|
expect(setPreactivatedSkillIds).not.toHaveBeenCalled();
|
|
362
390
|
|
|
@@ -367,41 +395,26 @@ describe("handleSendMessage slash command interception", () => {
|
|
|
367
395
|
expect(loopContent).toBe("hello there");
|
|
368
396
|
});
|
|
369
397
|
|
|
370
|
-
test("passes SlashContext with
|
|
371
|
-
resolveSlashMock.mockReturnValue({
|
|
372
|
-
kind: "passthrough",
|
|
373
|
-
content: "test",
|
|
374
|
-
});
|
|
375
|
-
|
|
398
|
+
test("passes SlashContext with resolved profile context budget", async () => {
|
|
376
399
|
const { conversation } = makeConversation();
|
|
377
400
|
await callHandler(
|
|
378
401
|
(args) => handleSendMessage(args, makeDeps(conversation)),
|
|
379
|
-
makeRequest("
|
|
402
|
+
makeRequest("/context"),
|
|
380
403
|
undefined,
|
|
381
404
|
202,
|
|
382
405
|
);
|
|
383
406
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
expect(
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
estimatedCost: 0.05,
|
|
393
|
-
model: "claude-opus-4-7",
|
|
394
|
-
provider: "anthropic",
|
|
395
|
-
maxInputTokens: 200000,
|
|
396
|
-
});
|
|
407
|
+
const assistantPersist = addMessageMock.mock.calls.find(
|
|
408
|
+
(call) => call[1] === "assistant",
|
|
409
|
+
);
|
|
410
|
+
expect(assistantPersist).toBeDefined();
|
|
411
|
+
expect(String(assistantPersist?.[2])).toContain("1,000 / 150,000 tokens");
|
|
412
|
+
expect(String(assistantPersist?.[2])).toContain(
|
|
413
|
+
"claude-opus-4-7 (anthropic)",
|
|
414
|
+
);
|
|
397
415
|
});
|
|
398
416
|
|
|
399
417
|
test("applies riskThreshold override when provided", async () => {
|
|
400
|
-
resolveSlashMock.mockReturnValue({
|
|
401
|
-
kind: "passthrough",
|
|
402
|
-
content: "hello there",
|
|
403
|
-
});
|
|
404
|
-
|
|
405
418
|
const { conversation } = makeConversation();
|
|
406
419
|
const res = await callHandler(
|
|
407
420
|
(args) => handleSendMessage(args, makeDeps(conversation)),
|
|
@@ -418,10 +431,6 @@ describe("handleSendMessage slash command interception", () => {
|
|
|
418
431
|
});
|
|
419
432
|
|
|
420
433
|
test("returns 500 when riskThreshold IPC fails", async () => {
|
|
421
|
-
resolveSlashMock.mockReturnValue({
|
|
422
|
-
kind: "passthrough",
|
|
423
|
-
content: "hello there",
|
|
424
|
-
});
|
|
425
434
|
ipcCallMock.mockImplementationOnce(async () => undefined);
|
|
426
435
|
|
|
427
436
|
const { conversation } = makeConversation();
|
|
@@ -28,11 +28,13 @@ import {
|
|
|
28
28
|
buildSubagentStatusBlock,
|
|
29
29
|
buildUnifiedTurnContextBlock,
|
|
30
30
|
findLastInjectedNowContent,
|
|
31
|
+
getSlackCompactionWatermarkForPrefix,
|
|
31
32
|
injectChannelCapabilityContext,
|
|
32
33
|
injectChannelCommandContext,
|
|
33
34
|
isGroupChatType,
|
|
34
35
|
isSlackChannelConversation,
|
|
35
36
|
loadSlackActiveThreadFocusBlock,
|
|
37
|
+
loadSlackChronologicalContext,
|
|
36
38
|
loadSlackChronologicalMessages,
|
|
37
39
|
resolveChannelCapabilities,
|
|
38
40
|
stripChannelCapabilityContext,
|
|
@@ -1159,9 +1161,7 @@ describe("buildUnifiedTurnContextBlock", () => {
|
|
|
1159
1161
|
expect(text).toContain("member_policy: allow");
|
|
1160
1162
|
// Behavioral guidance: conversational confirmation (one-time decision pattern)
|
|
1161
1163
|
expect(text).toContain("trusted contact (non-guardian)");
|
|
1162
|
-
expect(text).toContain(
|
|
1163
|
-
"confirming the guardian's intent conversationally",
|
|
1164
|
-
);
|
|
1164
|
+
expect(text).toContain("confirming the guardian's intent conversationally");
|
|
1165
1165
|
expect(text).not.toContain(
|
|
1166
1166
|
"tool execution layer will automatically deny it and escalate",
|
|
1167
1167
|
);
|
|
@@ -2298,6 +2298,24 @@ describe("Slack channel chronological rendering — multi-thread", () => {
|
|
|
2298
2298
|
});
|
|
2299
2299
|
}
|
|
2300
2300
|
|
|
2301
|
+
test("normalized Slack mention labels stay in assembled model context", async () => {
|
|
2302
|
+
const rows: MessageRow[] = [
|
|
2303
|
+
userRow({
|
|
2304
|
+
id: "m-normalized-mention",
|
|
2305
|
+
createdAt: 1700000000_000,
|
|
2306
|
+
text: "@leo can you check this?",
|
|
2307
|
+
slackMeta: buildSlackMeta({ channelTs: T0, displayName: "alice" }),
|
|
2308
|
+
}),
|
|
2309
|
+
];
|
|
2310
|
+
|
|
2311
|
+
const result = await runSlackChannelAssembly(rows);
|
|
2312
|
+
const renderedContext = texts(result).join("\n");
|
|
2313
|
+
|
|
2314
|
+
expect(renderedContext).toContain("@leo can you check this?");
|
|
2315
|
+
expect(renderedContext).not.toContain("<@U_LEO>");
|
|
2316
|
+
expect(renderedContext).not.toContain("U_LEO");
|
|
2317
|
+
});
|
|
2318
|
+
|
|
2301
2319
|
// ── Scenario 1: reply in mid-thread ──────────────────────────────────
|
|
2302
2320
|
// Alice posts to thread A, Bob replies in thread B (cross-thread). Then
|
|
2303
2321
|
// Alice posts a follow-up reply in thread A. Cross-thread visibility:
|
|
@@ -2825,6 +2843,37 @@ describe("Slack channel chronological rendering — multi-thread", () => {
|
|
|
2825
2843
|
expect(allText).not.toContain("dm context");
|
|
2826
2844
|
});
|
|
2827
2845
|
|
|
2846
|
+
test("slack late-join notice is model-facing and non-persisted", async () => {
|
|
2847
|
+
const slackChannelCaps: ChannelCapabilities = {
|
|
2848
|
+
channel: "slack",
|
|
2849
|
+
dashboardCapable: false,
|
|
2850
|
+
supportsDynamicUi: false,
|
|
2851
|
+
supportsVoiceInput: false,
|
|
2852
|
+
chatType: "channel",
|
|
2853
|
+
};
|
|
2854
|
+
const notice =
|
|
2855
|
+
"Slack context note: this turn joined an existing thread. 3 earlier thread messages were backfilled before the current message.";
|
|
2856
|
+
|
|
2857
|
+
const { messages: result, blocks } = await applyRuntimeInjections(
|
|
2858
|
+
[{ role: "user", content: [{ type: "text", text: "current turn" }] }],
|
|
2859
|
+
{
|
|
2860
|
+
channelCapabilities: slackChannelCaps,
|
|
2861
|
+
slackRuntimeContextNotice: notice,
|
|
2862
|
+
transportHints: [notice],
|
|
2863
|
+
},
|
|
2864
|
+
);
|
|
2865
|
+
|
|
2866
|
+
const allText = result
|
|
2867
|
+
.flatMap((m) => m.content)
|
|
2868
|
+
.filter((b): b is { type: "text"; text: string } => b.type === "text")
|
|
2869
|
+
.map((b) => b.text)
|
|
2870
|
+
.join("\n");
|
|
2871
|
+
expect(allText).toContain("<slack_context_notice>");
|
|
2872
|
+
expect(allText).toContain(notice);
|
|
2873
|
+
expect(allText).not.toContain("<transport_hints>");
|
|
2874
|
+
expect(JSON.stringify(blocks)).not.toContain(notice);
|
|
2875
|
+
});
|
|
2876
|
+
|
|
2828
2877
|
// ── transport_hints kept for non-slack channels ───────────────────────
|
|
2829
2878
|
test("non-slack conversations still receive <transport_hints>", async () => {
|
|
2830
2879
|
const { messages: result } = await applyRuntimeInjections(
|
|
@@ -2894,6 +2943,211 @@ describe("Slack channel chronological rendering — multi-thread", () => {
|
|
|
2894
2943
|
expect(allText).toContain("from untrusted actor");
|
|
2895
2944
|
});
|
|
2896
2945
|
|
|
2946
|
+
test("loadSlackChronologicalContext preserves summary and filters by Slack watermark", () => {
|
|
2947
|
+
const caps: ChannelCapabilities = {
|
|
2948
|
+
channel: "slack",
|
|
2949
|
+
dashboardCapable: false,
|
|
2950
|
+
supportsDynamicUi: false,
|
|
2951
|
+
supportsVoiceInput: false,
|
|
2952
|
+
chatType: "channel",
|
|
2953
|
+
};
|
|
2954
|
+
const rows: MessageRow[] = [
|
|
2955
|
+
userRow({
|
|
2956
|
+
id: "newer-inserted-first",
|
|
2957
|
+
createdAt: 1700000030_000,
|
|
2958
|
+
text: "after watermark",
|
|
2959
|
+
slackMeta: buildSlackMeta({
|
|
2960
|
+
channelTs: T2,
|
|
2961
|
+
displayName: "carol",
|
|
2962
|
+
}),
|
|
2963
|
+
}),
|
|
2964
|
+
userRow({
|
|
2965
|
+
id: "older-backfilled-later",
|
|
2966
|
+
createdAt: 1700000040_000,
|
|
2967
|
+
text: "before watermark even though inserted later",
|
|
2968
|
+
slackMeta: buildSlackMeta({
|
|
2969
|
+
channelTs: T0,
|
|
2970
|
+
displayName: "alice",
|
|
2971
|
+
}),
|
|
2972
|
+
}),
|
|
2973
|
+
userRow({
|
|
2974
|
+
id: "legacy-before-watermark",
|
|
2975
|
+
createdAt: 1700000008_000,
|
|
2976
|
+
text: "legacy row before watermark",
|
|
2977
|
+
}),
|
|
2978
|
+
userRow({
|
|
2979
|
+
id: "at-watermark",
|
|
2980
|
+
createdAt: 1700000045_000,
|
|
2981
|
+
text: "at watermark",
|
|
2982
|
+
slackMeta: buildSlackMeta({
|
|
2983
|
+
channelTs: T1,
|
|
2984
|
+
displayName: "bob",
|
|
2985
|
+
}),
|
|
2986
|
+
}),
|
|
2987
|
+
];
|
|
2988
|
+
|
|
2989
|
+
const result = loadSlackChronologicalContext("conv-1", caps, {
|
|
2990
|
+
loader: () => rows,
|
|
2991
|
+
trustClass: "guardian",
|
|
2992
|
+
contextSummary: "## Summary\n- compacted Slack history",
|
|
2993
|
+
contextCompactedMessageCount: 99,
|
|
2994
|
+
slackContextCompactionWatermarkTs: T1,
|
|
2995
|
+
});
|
|
2996
|
+
|
|
2997
|
+
expect(result).not.toBeNull();
|
|
2998
|
+
const renderedText = result!.messages
|
|
2999
|
+
.flatMap((message) => message.content)
|
|
3000
|
+
.filter((block): block is { type: "text"; text: string } => {
|
|
3001
|
+
return block.type === "text";
|
|
3002
|
+
})
|
|
3003
|
+
.map((block) => block.text)
|
|
3004
|
+
.join("\n");
|
|
3005
|
+
expect(renderedText).toContain("<context_summary>");
|
|
3006
|
+
expect(renderedText).toContain("compacted Slack history");
|
|
3007
|
+
expect(renderedText).toContain("after watermark");
|
|
3008
|
+
expect(renderedText).not.toContain("before watermark");
|
|
3009
|
+
expect(renderedText).not.toContain("legacy row before watermark");
|
|
3010
|
+
expect(renderedText).not.toContain("at watermark");
|
|
3011
|
+
expect(result!.renderedMessages.map((entry) => entry.message)).toEqual(
|
|
3012
|
+
result!.messages,
|
|
3013
|
+
);
|
|
3014
|
+
expect(
|
|
3015
|
+
result!.renderedMessages.map((entry) => entry.sourceChannelTs),
|
|
3016
|
+
).toEqual([null, T2]);
|
|
3017
|
+
expect(getSlackCompactionWatermarkForPrefix(result, 1)).toBe(T2);
|
|
3018
|
+
});
|
|
3019
|
+
|
|
3020
|
+
test("active-thread focus filters pre-watermark and legacy compacted rows", () => {
|
|
3021
|
+
const caps: ChannelCapabilities = {
|
|
3022
|
+
channel: "slack",
|
|
3023
|
+
dashboardCapable: false,
|
|
3024
|
+
supportsDynamicUi: false,
|
|
3025
|
+
supportsVoiceInput: false,
|
|
3026
|
+
chatType: "channel",
|
|
3027
|
+
};
|
|
3028
|
+
const rows: MessageRow[] = [
|
|
3029
|
+
userRow({
|
|
3030
|
+
id: "thread-root",
|
|
3031
|
+
createdAt: 1700000000_000,
|
|
3032
|
+
text: "compacted root",
|
|
3033
|
+
slackMeta: buildSlackMeta({
|
|
3034
|
+
channelTs: T0,
|
|
3035
|
+
threadTs: T0,
|
|
3036
|
+
displayName: "alice",
|
|
3037
|
+
}),
|
|
3038
|
+
}),
|
|
3039
|
+
userRow({
|
|
3040
|
+
id: "legacy-old",
|
|
3041
|
+
createdAt: 1700000005_000,
|
|
3042
|
+
text: "legacy compacted row",
|
|
3043
|
+
}),
|
|
3044
|
+
userRow({
|
|
3045
|
+
id: "reply-before",
|
|
3046
|
+
createdAt: 1700000008_000,
|
|
3047
|
+
text: "compacted reply",
|
|
3048
|
+
slackMeta: buildSlackMeta({
|
|
3049
|
+
channelTs: T0_REPLY1,
|
|
3050
|
+
threadTs: T0,
|
|
3051
|
+
displayName: "bob",
|
|
3052
|
+
}),
|
|
3053
|
+
}),
|
|
3054
|
+
userRow({
|
|
3055
|
+
id: "reply-after",
|
|
3056
|
+
createdAt: 1700000025_000,
|
|
3057
|
+
text: "live reply",
|
|
3058
|
+
slackMeta: buildSlackMeta({
|
|
3059
|
+
channelTs: T0_REPLY2,
|
|
3060
|
+
threadTs: T0,
|
|
3061
|
+
displayName: "carol",
|
|
3062
|
+
}),
|
|
3063
|
+
}),
|
|
3064
|
+
];
|
|
3065
|
+
|
|
3066
|
+
const result = loadSlackActiveThreadFocusBlock("conv-1", caps, {
|
|
3067
|
+
loader: () => rows,
|
|
3068
|
+
trustClass: "guardian",
|
|
3069
|
+
contextCompactedMessageCount: 3,
|
|
3070
|
+
slackContextCompactionWatermarkTs: T1,
|
|
3071
|
+
});
|
|
3072
|
+
|
|
3073
|
+
expect(result).not.toBeNull();
|
|
3074
|
+
expect(result!).toContain("live reply");
|
|
3075
|
+
expect(result!).not.toContain("compacted root");
|
|
3076
|
+
expect(result!).not.toContain("compacted reply");
|
|
3077
|
+
expect(result!).not.toContain("legacy compacted row");
|
|
3078
|
+
});
|
|
3079
|
+
|
|
3080
|
+
test("long Slack thread stays compacted after a later reply", () => {
|
|
3081
|
+
const caps: ChannelCapabilities = {
|
|
3082
|
+
channel: "slack",
|
|
3083
|
+
dashboardCapable: false,
|
|
3084
|
+
supportsDynamicUi: false,
|
|
3085
|
+
supportsVoiceInput: false,
|
|
3086
|
+
chatType: "channel",
|
|
3087
|
+
};
|
|
3088
|
+
const ts = (n: number) => `1700000${String(n).padStart(3, "0")}.000000`;
|
|
3089
|
+
const watermark = ts(80);
|
|
3090
|
+
const rows: MessageRow[] = [
|
|
3091
|
+
...Array.from({ length: 121 }, (_, index) =>
|
|
3092
|
+
userRow({
|
|
3093
|
+
id: `thread-${index}`,
|
|
3094
|
+
createdAt: 1700000000_000 + index,
|
|
3095
|
+
text: index === 0 ? "original root" : `pre-compaction ${index}`,
|
|
3096
|
+
slackMeta: buildSlackMeta({
|
|
3097
|
+
channelTs: ts(index),
|
|
3098
|
+
threadTs: index === 0 ? undefined : ts(0),
|
|
3099
|
+
displayName: index % 2 === 0 ? "alice" : "bob",
|
|
3100
|
+
}),
|
|
3101
|
+
}),
|
|
3102
|
+
),
|
|
3103
|
+
userRow({
|
|
3104
|
+
id: "subsequent-reply",
|
|
3105
|
+
createdAt: 1700000000_500,
|
|
3106
|
+
text: "reply after compaction",
|
|
3107
|
+
slackMeta: buildSlackMeta({
|
|
3108
|
+
channelTs: ts(121),
|
|
3109
|
+
threadTs: ts(0),
|
|
3110
|
+
displayName: "carol",
|
|
3111
|
+
}),
|
|
3112
|
+
}),
|
|
3113
|
+
];
|
|
3114
|
+
|
|
3115
|
+
const result = loadSlackChronologicalContext("conv-1", caps, {
|
|
3116
|
+
loader: () => rows,
|
|
3117
|
+
trustClass: "guardian",
|
|
3118
|
+
contextSummary: "## Summary\n- compacted long Slack thread",
|
|
3119
|
+
contextCompactedMessageCount: 81,
|
|
3120
|
+
slackContextCompactionWatermarkTs: watermark,
|
|
3121
|
+
});
|
|
3122
|
+
|
|
3123
|
+
expect(result).not.toBeNull();
|
|
3124
|
+
const renderedText = result!.messages
|
|
3125
|
+
.flatMap((message) => message.content)
|
|
3126
|
+
.filter((block): block is { type: "text"; text: string } => {
|
|
3127
|
+
return block.type === "text";
|
|
3128
|
+
})
|
|
3129
|
+
.map((block) => block.text)
|
|
3130
|
+
.join("\n");
|
|
3131
|
+
|
|
3132
|
+
expect(renderedText).toContain("compacted long Slack thread");
|
|
3133
|
+
expect(renderedText).toContain("reply after compaction");
|
|
3134
|
+
expect(renderedText).not.toContain("original root");
|
|
3135
|
+
expect(renderedText).not.toContain("pre-compaction 80");
|
|
3136
|
+
const sourceChannelTs = result!.renderedMessages.map(
|
|
3137
|
+
(entry) => entry.sourceChannelTs,
|
|
3138
|
+
);
|
|
3139
|
+
expect(sourceChannelTs[0]).toBeNull();
|
|
3140
|
+
expect(
|
|
3141
|
+
sourceChannelTs
|
|
3142
|
+
.slice(1)
|
|
3143
|
+
.every(
|
|
3144
|
+
(channelTs) =>
|
|
3145
|
+
channelTs !== null &&
|
|
3146
|
+
Number.parseFloat(channelTs) > Number.parseFloat(watermark),
|
|
3147
|
+
),
|
|
3148
|
+
).toBe(true);
|
|
3149
|
+
});
|
|
3150
|
+
|
|
2897
3151
|
// ── loadSlackChronologicalMessages returns null for non-slack channels ─
|
|
2898
3152
|
test("loadSlackChronologicalMessages returns null for non-slack channels", () => {
|
|
2899
3153
|
const result = loadSlackChronologicalMessages(
|
|
@@ -36,6 +36,7 @@ describe("resolveSlash /commands interface-aware help", () => {
|
|
|
36
36
|
expect(lines).toEqual([
|
|
37
37
|
"/commands — List all available commands",
|
|
38
38
|
"/compact — Force context compaction immediately",
|
|
39
|
+
"/context — Show conversation context usage",
|
|
39
40
|
"/models — List all available models",
|
|
40
41
|
"/status — Show conversation status and context usage",
|
|
41
42
|
"/btw — Ask a side question while the assistant is working",
|
|
@@ -51,6 +52,7 @@ describe("resolveSlash /commands interface-aware help", () => {
|
|
|
51
52
|
expect(lines).toEqual([
|
|
52
53
|
"/commands — List all available commands",
|
|
53
54
|
"/compact — Force context compaction immediately",
|
|
55
|
+
"/context — Show conversation context usage",
|
|
54
56
|
"/models — List all available models",
|
|
55
57
|
"/status — Show conversation status and context usage",
|
|
56
58
|
"/btw — Ask a side question while the assistant is working",
|
|
@@ -65,17 +67,19 @@ describe("resolveSlash /commands interface-aware help", () => {
|
|
|
65
67
|
expect(lines).toEqual([
|
|
66
68
|
"/commands — List all available commands",
|
|
67
69
|
"/compact — Force context compaction immediately",
|
|
70
|
+
"/context — Show conversation context usage",
|
|
68
71
|
"/models — List all available models",
|
|
69
72
|
"/status — Show conversation status and context usage",
|
|
70
73
|
"/btw — Ask a side question while the assistant is working",
|
|
71
74
|
]);
|
|
72
75
|
});
|
|
73
76
|
|
|
74
|
-
test("
|
|
77
|
+
test("orders fallback help consistently when no interface is provided", async () => {
|
|
75
78
|
const lines = await resolveCommandsLines(makeSlashContext());
|
|
76
79
|
expect(lines).toEqual([
|
|
77
80
|
"/commands — List all available commands",
|
|
78
81
|
"/compact — Force context compaction immediately",
|
|
82
|
+
"/context — Show conversation context usage",
|
|
79
83
|
"/models — List all available models",
|
|
80
84
|
"/status — Show conversation status and context usage",
|
|
81
85
|
]);
|
|
@@ -92,9 +96,23 @@ describe("resolveSlash /commands interface-aware help", () => {
|
|
|
92
96
|
});
|
|
93
97
|
|
|
94
98
|
describe("resolveSlash command contract", () => {
|
|
99
|
+
test("/context reports the resolved context budget", async () => {
|
|
100
|
+
const result = await resolveSlash(
|
|
101
|
+
"/context",
|
|
102
|
+
makeSlashContext({ inputTokens: 75_000, maxInputTokens: 150_000 }),
|
|
103
|
+
);
|
|
104
|
+
expect(result.kind).toBe("unknown");
|
|
105
|
+
if (result.kind !== "unknown") {
|
|
106
|
+
throw new Error("Expected /context to resolve to kind=unknown");
|
|
107
|
+
}
|
|
108
|
+
expect(result.message).toContain("50%");
|
|
109
|
+
expect(result.message).toContain("75,000 / 150,000 tokens");
|
|
110
|
+
});
|
|
111
|
+
|
|
95
112
|
test("keeps unsupported slash forms as passthrough", async () => {
|
|
96
113
|
const slashForms = [
|
|
97
114
|
"/commands foo",
|
|
115
|
+
"/context foo",
|
|
98
116
|
"/models foo",
|
|
99
117
|
"/status foo",
|
|
100
118
|
"/pair foo",
|
|
@@ -110,17 +128,19 @@ describe("resolveSlash command contract", () => {
|
|
|
110
128
|
expect(result).toEqual({ kind: "passthrough", content: input });
|
|
111
129
|
}
|
|
112
130
|
});
|
|
113
|
-
|
|
114
|
-
|
|
115
131
|
});
|
|
116
132
|
|
|
117
133
|
describe("classifySlash is a pure classifier matching resolveSlash kinds", () => {
|
|
118
134
|
// Lookahead in `buildPassthroughBatch` must not run `resolveSlash`'s side
|
|
119
135
|
// effects. The pure classifier is synchronous, takes no side-effecting
|
|
120
136
|
// dependencies, and must agree with resolveSlash's `kind`.
|
|
121
|
-
const cases: Array<{
|
|
137
|
+
const cases: Array<{
|
|
138
|
+
input: string;
|
|
139
|
+
kind: "passthrough" | "compact" | "unknown";
|
|
140
|
+
}> = [
|
|
122
141
|
{ input: "/pair", kind: "passthrough" },
|
|
123
142
|
{ input: "/models", kind: "unknown" },
|
|
143
|
+
{ input: "/context", kind: "unknown" },
|
|
124
144
|
{ input: "/status", kind: "unknown" },
|
|
125
145
|
{ input: "/commands", kind: "unknown" },
|
|
126
146
|
{ input: "/compact", kind: "compact" },
|
|
@@ -60,6 +60,8 @@ mock.module("../config/loader.js", () => ({
|
|
|
60
60
|
pricingOverrides: [],
|
|
61
61
|
},
|
|
62
62
|
rateLimit: { maxRequestsPerMinute: 0 },
|
|
63
|
+
memory: { v2: { enabled: false } },
|
|
64
|
+
conversations: { skipAutoRetitling: false },
|
|
63
65
|
daemon: {
|
|
64
66
|
startupSocketWaitMs: 5000,
|
|
65
67
|
stopTimeoutMs: 5000,
|
|
@@ -294,7 +294,6 @@ describe("per-conversation speed override", () => {
|
|
|
294
294
|
4096,
|
|
295
295
|
makeSendToClient(),
|
|
296
296
|
"/tmp",
|
|
297
|
-
undefined, // broadcastToAllClients
|
|
298
297
|
undefined, // memoryPolicy
|
|
299
298
|
undefined, // sharedCesClient
|
|
300
299
|
"standard", // speedOverride
|
|
@@ -316,7 +315,6 @@ describe("per-conversation speed override", () => {
|
|
|
316
315
|
4096,
|
|
317
316
|
makeSendToClient(),
|
|
318
317
|
"/tmp",
|
|
319
|
-
undefined, // broadcastToAllClients
|
|
320
318
|
undefined, // memoryPolicy
|
|
321
319
|
undefined, // sharedCesClient
|
|
322
320
|
// no speedOverride — should fall back to global config "fast"
|
|
@@ -337,7 +335,6 @@ describe("per-conversation speed override", () => {
|
|
|
337
335
|
4096,
|
|
338
336
|
makeSendToClient(),
|
|
339
337
|
"/tmp",
|
|
340
|
-
undefined, // broadcastToAllClients
|
|
341
338
|
undefined, // memoryPolicy
|
|
342
339
|
undefined, // sharedCesClient
|
|
343
340
|
"fast", // speedOverride
|