@vellumai/assistant 0.7.1 → 0.7.3
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 +48 -50
- package/Dockerfile +1 -0
- package/README.md +1 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
- package/bun.lock +26 -26
- package/docs/architecture/memory.md +5 -2
- package/docs/architecture/security.md +20 -0
- package/docs/plugins.md +7 -9
- package/knip.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +52 -5
- package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
- package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
- package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
- package/node_modules/@vellumai/twilio-client/package.json +18 -0
- package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
- package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
- package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
- package/openapi.yaml +1020 -40
- package/package.json +6 -3
- package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
- package/src/__tests__/app-bundler.test.ts +170 -1
- package/src/__tests__/app-control-flow.test.ts +384 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
- package/src/__tests__/app-executors.test.ts +30 -43
- package/src/__tests__/approval-routes-http.test.ts +23 -6
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
- package/src/__tests__/assistant-event-hub.test.ts +157 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -7
- package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
- package/src/__tests__/background-shell-host-bash.test.ts +14 -15
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
- package/src/__tests__/btw-routes.test.ts +13 -4
- package/src/__tests__/call-controller.test.ts +49 -1
- package/src/__tests__/call-conversation-messages.test.ts +8 -2
- package/src/__tests__/call-domain.test.ts +0 -2
- package/src/__tests__/call-routes-http.test.ts +0 -2
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
- package/src/__tests__/channel-readiness-service.test.ts +62 -2
- package/src/__tests__/checker.test.ts +3 -4
- package/src/__tests__/config-loader-backfill.test.ts +461 -147
- package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -1
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/config-set-platform-guard.test.ts +48 -4
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +20 -11
- package/src/__tests__/config-watcher.test.ts +142 -71
- package/src/__tests__/context-search-agent-runner.test.ts +61 -3
- package/src/__tests__/context-search-conversations-source.test.ts +0 -24
- package/src/__tests__/context-search-fanout.test.ts +0 -1
- package/src/__tests__/context-search-memory-source.test.ts +3 -7
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop.test.ts +454 -5
- package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-lifecycle.test.ts +36 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
- package/src/__tests__/conversation-process-callsite.test.ts +43 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
- package/src/__tests__/conversation-slash-commands.test.ts +0 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-store.test.ts +0 -18
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +328 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
- package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
- package/src/__tests__/credentials-cli.test.ts +12 -12
- package/src/__tests__/cu-unified-flow.test.ts +351 -23
- package/src/__tests__/daemon-credential-client.test.ts +101 -19
- package/src/__tests__/date-context.test.ts +164 -2
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/disk-pressure-guard.test.ts +262 -0
- package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
- package/src/__tests__/disk-pressure-policy.test.ts +241 -0
- package/src/__tests__/disk-pressure-routes.test.ts +379 -0
- package/src/__tests__/disk-pressure-tools.test.ts +277 -0
- package/src/__tests__/disk-usage.test.ts +150 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/events-client-registration.test.ts +52 -0
- package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
- package/src/__tests__/file-write-tool.test.ts +4 -10
- package/src/__tests__/filing-service.test.ts +3 -4
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
- package/src/__tests__/heartbeat-service.test.ts +968 -2
- package/src/__tests__/helpers/call-route-handler.ts +7 -1
- package/src/__tests__/host-app-control-proxy.test.ts +772 -0
- package/src/__tests__/host-app-control-routes.test.ts +263 -0
- package/src/__tests__/host-bash-proxy.test.ts +439 -47
- package/src/__tests__/host-bash-routes.test.ts +459 -0
- package/src/__tests__/host-browser-proxy.test.ts +24 -22
- package/src/__tests__/host-browser-routes.test.ts +39 -13
- package/src/__tests__/host-cu-proxy.test.ts +248 -52
- package/src/__tests__/host-cu-routes-targeted.test.ts +429 -0
- package/src/__tests__/host-file-edit-tool.test.ts +47 -1
- package/src/__tests__/host-file-proxy-targeted.test.ts +378 -0
- package/src/__tests__/host-file-proxy.test.ts +301 -45
- package/src/__tests__/host-file-read-tool.test.ts +17 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +420 -0
- package/src/__tests__/host-file-write-tool.test.ts +42 -1
- package/src/__tests__/host-proxy-base.test.ts +312 -0
- package/src/__tests__/host-shell-tool.test.ts +22 -4
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +932 -0
- package/src/__tests__/host-transfer-proxy.test.ts +121 -22
- package/src/__tests__/host-transfer-routes-targeted.test.ts +662 -0
- package/src/__tests__/http-user-message-parity.test.ts +108 -1
- package/src/__tests__/identity-intro-cache.test.ts +29 -0
- package/src/__tests__/identity-routes.test.ts +103 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
- package/src/__tests__/injector-chain.test.ts +18 -6
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- package/src/__tests__/inline-command-runner.test.ts +0 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
- package/src/__tests__/integration-status.test.ts +85 -5
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
- package/src/__tests__/managed-profile-guard.test.ts +18 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/mcp-abort-signal.test.ts +130 -0
- package/src/__tests__/mcp-auth-routes.test.ts +197 -0
- package/src/__tests__/mcp-cli.test.ts +338 -2
- package/src/__tests__/memory-admin-recall.test.ts +3 -11
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
- package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
- package/src/__tests__/migration-import-commit-http.test.ts +108 -2
- package/src/__tests__/mock-gateway-ipc.ts +1 -0
- package/src/__tests__/normalize-onboarding.test.ts +180 -0
- package/src/__tests__/oauth-cli.test.ts +0 -2
- package/src/__tests__/oauth-connect-routes.test.ts +316 -0
- package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
- package/src/__tests__/onboarding-persona-write.test.ts +308 -0
- package/src/__tests__/openai-provider.test.ts +45 -8
- package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
- package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
- package/src/__tests__/platform-callback-registration.test.ts +21 -4
- package/src/__tests__/platform.test.ts +2 -1
- package/src/__tests__/playbook-execution.test.ts +0 -43
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +214 -25
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
- package/src/__tests__/provider-tool-name.test.ts +23 -0
- package/src/__tests__/public-ingress-urls.test.ts +97 -0
- package/src/__tests__/relay-server.test.ts +15 -4
- package/src/__tests__/require-fresh-approval.test.ts +0 -1
- package/src/__tests__/retry-backoff.test.ts +87 -0
- package/src/__tests__/runtime-events-sse.test.ts +2 -2
- package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
- package/src/__tests__/schedule-retry.test.ts +715 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
- package/src/__tests__/skill-feature-flags.test.ts +43 -41
- package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
- package/src/__tests__/skill-load-inline-command.test.ts +0 -51
- package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
- package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
- package/src/__tests__/slack-channel-config.test.ts +9 -14
- package/src/__tests__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/test-preload.ts +8 -0
- package/src/__tests__/tool-approval-handler.test.ts +3 -4
- package/src/__tests__/tool-audit-listener.test.ts +48 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/twilio-config.test.ts +3 -16
- package/src/__tests__/twilio-routes.test.ts +3 -5
- package/src/__tests__/twilio-validation.test.ts +93 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
- package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
- package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
- package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
- package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
- package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
- package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
- package/src/approvals/guardian-decision-primitive.ts +13 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -17
- package/src/backup/__tests__/paths.test.ts +0 -22
- package/src/backup/__tests__/restore.test.ts +51 -151
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +107 -231
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/app-bundler.ts +51 -3
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-conversation-messages.ts +46 -10
- package/src/calls/relay-server.ts +4 -44
- package/src/calls/twilio-config.ts +2 -17
- package/src/calls/twilio-rest.ts +33 -105
- package/src/calls/twilio-routes.ts +11 -12
- package/src/channels/types.ts +8 -7
- package/src/cli/commands/__tests__/backup.test.ts +6 -277
- package/src/cli/commands/__tests__/gateway.test.ts +288 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -5
- package/src/cli/commands/backup.ts +6 -331
- package/src/cli/commands/bash.ts +35 -108
- package/src/cli/commands/clients.ts +36 -37
- package/src/cli/commands/contacts.ts +137 -25
- package/src/cli/commands/conversations.ts +2 -5
- package/src/cli/commands/credentials.ts +71 -7
- package/src/cli/commands/domain.ts +66 -15
- package/src/cli/commands/gateway.ts +183 -0
- package/src/cli/commands/keys.ts +9 -6
- package/src/cli/commands/mcp.ts +116 -156
- package/src/cli/commands/memory-v2.ts +303 -7
- package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
- package/src/cli/commands/oauth/connect.ts +127 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -4
- package/src/cli/commands/platform/__tests__/connect.test.ts +7 -3
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -3
- package/src/cli/commands/platform/__tests__/status.test.ts +116 -21
- package/src/cli/commands/platform/disconnect.ts +5 -4
- package/src/cli/commands/platform/index.ts +16 -25
- package/src/cli/commands/status.ts +57 -0
- package/src/cli/lib/daemon-credential-client.ts +110 -28
- package/src/cli/program.ts +6 -2
- package/src/config/assistant-feature-flags.ts +79 -12
- package/src/config/bundled-skills/acp/SKILL.md +6 -0
- package/src/config/bundled-skills/acp/TOOLS.json +1 -22
- package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
- package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
- package/src/config/bundled-skills/app-control/SKILL.md +75 -0
- package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
- package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
- package/src/config/bundled-skills/document/TOOLS.json +0 -8
- package/src/config/bundled-skills/followups/TOOLS.json +0 -12
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
- package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
- package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
- package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +25 -4
- package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
- package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
- package/src/config/bundled-skills/settings/SKILL.md +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +0 -12
- package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
- package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
- package/src/config/bundled-skills/subagent/SKILL.md +6 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
- package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
- package/src/config/bundled-tool-registry.ts +21 -0
- package/src/config/env-registry.ts +0 -2
- package/src/config/env.ts +19 -20
- package/src/config/feature-flag-registry.json +47 -135
- package/src/config/loader.ts +197 -104
- package/src/config/sanitize-for-transfer.ts +2 -0
- package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +17 -9
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/calls.ts +0 -9
- package/src/config/schemas/channels.ts +0 -5
- package/src/config/schemas/heartbeat.ts +64 -1
- package/src/config/schemas/ingress.ts +10 -6
- package/src/config/schemas/llm.ts +7 -10
- package/src/config/schemas/memory-lifecycle.ts +90 -24
- package/src/config/schemas/memory-v2.ts +121 -13
- package/src/config/schemas/platform.ts +49 -3
- package/src/config/schemas/services.ts +29 -15
- package/src/config/schemas/skills.ts +0 -6
- package/src/config/seed-inference-profiles.ts +230 -33
- package/src/contacts/contact-store.ts +0 -55
- package/src/contacts/contacts-write.ts +0 -27
- package/src/context/window-manager.ts +1 -2
- package/src/credential-execution/feature-gates.ts +10 -10
- package/src/credential-execution/process-manager.ts +12 -41
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +187 -5
- package/src/daemon/assistant-attachments.ts +4 -4
- package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
- package/src/daemon/config-watcher.ts +89 -60
- package/src/daemon/conversation-agent-loop-handlers.ts +27 -3
- package/src/daemon/conversation-agent-loop.ts +202 -61
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +9 -4
- package/src/daemon/conversation-process.ts +24 -11
- package/src/daemon/conversation-runtime-assembly.ts +28 -2
- package/src/daemon/conversation-store.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +305 -4
- package/src/daemon/conversation-tool-setup.ts +66 -62
- package/src/daemon/conversation.ts +38 -24
- package/src/daemon/date-context.ts +71 -22
- package/src/daemon/disk-pressure-background-gate.ts +73 -0
- package/src/daemon/disk-pressure-guard.ts +343 -0
- package/src/daemon/disk-pressure-policy.ts +163 -0
- package/src/daemon/doordash-steps.ts +1 -1
- package/src/daemon/handlers/shared.ts +4 -2
- package/src/daemon/handlers/skills.ts +3 -4
- package/src/daemon/host-app-control-proxy.ts +389 -0
- package/src/daemon/host-bash-proxy.ts +117 -82
- package/src/daemon/host-browser-proxy.ts +67 -82
- package/src/daemon/host-cu-proxy.ts +127 -86
- package/src/daemon/host-file-proxy.ts +129 -69
- package/src/daemon/host-proxy-base.ts +294 -0
- package/src/daemon/host-proxy-preactivation.ts +82 -0
- package/src/daemon/host-transfer-proxy.ts +338 -129
- package/src/daemon/lifecycle.ts +194 -145
- package/src/daemon/meet-host-supervisor.ts +4 -4
- package/src/daemon/meet-manifest-loader.ts +0 -1
- package/src/daemon/memory-v2-startup.ts +14 -4
- package/src/daemon/message-protocol.ts +6 -8
- package/src/daemon/message-types/contacts.ts +23 -1
- package/src/daemon/message-types/conversations.ts +15 -8
- package/src/daemon/message-types/disk-pressure.ts +9 -0
- package/src/daemon/message-types/host-app-control.ts +150 -0
- package/src/daemon/message-types/host-bash.ts +4 -0
- package/src/daemon/message-types/host-cu.ts +2 -0
- package/src/daemon/message-types/host-file.ts +4 -0
- package/src/daemon/message-types/host-transfer.ts +3 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/message-types/schedules.ts +8 -3
- package/src/daemon/message-types/skills.ts +2 -2
- package/src/daemon/process-message.ts +18 -1
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/shutdown-handlers.ts +0 -3
- package/src/daemon/tool-setup-types.ts +51 -0
- package/src/daemon/tool-side-effects.ts +1 -1
- package/src/documents/document-store.ts +85 -0
- package/src/events/tool-audit-listener.ts +2 -1
- package/src/filing/filing-service.ts +30 -5
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +24 -23
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +252 -0
- package/src/heartbeat/heartbeat-run-store.ts +249 -0
- package/src/heartbeat/heartbeat-service.ts +459 -54
- package/src/home/__tests__/post-connect-feed.test.ts +99 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
- package/src/home/__tests__/suggested-prompts.test.ts +89 -0
- package/src/home/feed-scheduler.ts +18 -0
- package/src/home/post-connect-feed.ts +68 -0
- package/src/home/relationship-state-writer.ts +17 -92
- package/src/home/suggested-prompts.ts +46 -10
- package/src/inbound/platform-callback-registration.ts +8 -15
- package/src/inbound/public-ingress-urls.ts +32 -34
- package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
- package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
- package/src/ipc/assistant-server.ts +70 -3
- package/src/ipc/cli-client.ts +32 -1
- package/src/ipc/gateway-client.ts +37 -3
- package/src/live-voice/live-voice-archive.ts +4 -4
- package/src/live-voice/live-voice-metrics.ts +10 -10
- package/src/live-voice/protocol.ts +5 -7
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
- package/src/mcp/mcp-auth-orchestrator.ts +213 -0
- package/src/mcp/mcp-auth-state.ts +133 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -0
- package/src/media/image-service.ts +1 -7
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
- package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
- package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
- package/src/memory/admin.ts +5 -9
- package/src/memory/anisotropy.test.ts +247 -0
- package/src/memory/anisotropy.ts +443 -0
- package/src/memory/auto-analysis-constants.ts +17 -0
- package/src/memory/auto-analysis-guard.ts +5 -15
- package/src/memory/canonical-guardian-store.ts +7 -7
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
- package/src/memory/context-search/agent-protocol.ts +6 -6
- package/src/memory/context-search/agent-runner.ts +51 -9
- package/src/memory/context-search/sources/conversations.ts +2 -11
- package/src/memory/context-search/sources/memory-v2.ts +22 -9
- package/src/memory/context-search/sources/memory.ts +0 -1
- package/src/memory/context-search/types.ts +0 -1
- package/src/memory/conversation-crud.ts +5 -13
- package/src/memory/conversation-key-store.ts +2 -15
- package/src/memory/db-init.ts +6 -0
- package/src/memory/embedding-backend.ts +9 -21
- package/src/memory/embedding-runtime-manager.ts +119 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +81 -25
- package/src/memory/graph/conversation-graph-memory.ts +43 -78
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +10 -67
- package/src/memory/graph/graph-search.ts +9 -20
- package/src/memory/graph/retriever.test.ts +6 -0
- package/src/memory/graph/retriever.ts +34 -10
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/indexer.ts +54 -45
- package/src/memory/job-handlers/backfill.ts +2 -11
- package/src/memory/job-handlers/cleanup.ts +43 -0
- package/src/memory/job-handlers/embedding.ts +6 -8
- package/src/memory/job-handlers/summarization.ts +2 -7
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
- package/src/memory/jobs/embed-concept-page.ts +28 -2
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
- package/src/memory/jobs-store.ts +114 -22
- package/src/memory/jobs-worker.ts +193 -106
- package/src/memory/memory-v2-activation-log-store.ts +33 -15
- package/src/memory/memory-v2-concept-frequency.ts +169 -0
- package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
- package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
- package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -0
- package/src/memory/pkb/pkb-search.ts +7 -0
- package/src/memory/qdrant-client.ts +49 -32
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/schema/infrastructure.ts +15 -0
- package/src/memory/search/semantic.ts +13 -67
- package/src/memory/sparse-tokenize.ts +49 -0
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +387 -344
- package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
- package/src/memory/v2/__tests__/injection.test.ts +181 -169
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +154 -188
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/memory/v2/__tests__/static-context.test.ts +76 -2
- package/src/memory/v2/activation.ts +213 -239
- package/src/memory/v2/consolidation-job.ts +65 -17
- package/src/memory/v2/constants.ts +7 -0
- package/src/memory/v2/injection.ts +123 -103
- package/src/memory/v2/prompts/consolidation.ts +348 -92
- package/src/memory/v2/qdrant.ts +198 -1
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +113 -77
- package/src/memory/v2/skill-content.ts +4 -3
- package/src/memory/v2/skill-store.ts +91 -53
- package/src/memory/v2/sparse-bm25.ts +245 -0
- package/src/memory/v2/static-context.ts +28 -5
- package/src/memory/v2/types.ts +10 -10
- package/src/messaging/providers/gmail/types.ts +0 -49
- package/src/messaging/providers/slack/adapter.ts +1 -31
- package/src/messaging/providers/slack/types.ts +0 -32
- package/src/notifications/README.md +10 -10
- package/src/notifications/broadcaster.ts +1 -1
- package/src/notifications/copy-composer.ts +13 -0
- package/src/notifications/guardian-question-mode.ts +5 -5
- package/src/notifications/signal.ts +4 -0
- package/src/oauth/AGENTS.md +3 -1
- package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
- package/src/oauth/connect-orchestrator.ts +6 -0
- package/src/oauth/connection-resolver.test.ts +66 -1
- package/src/oauth/connection-resolver.ts +55 -1
- package/src/oauth/credential-token-resolver.ts +1 -3
- package/src/oauth/manual-token-connection.ts +0 -4
- package/src/oauth/oauth-connect-state.ts +77 -0
- package/src/oauth/seed-providers.ts +58 -1
- package/src/outbound-proxy/index.ts +1 -37
- package/src/outbound-proxy/logging.ts +1 -1
- package/src/outbound-proxy/policy.ts +6 -5
- package/src/outbound-proxy/router.ts +2 -1
- package/src/permissions/approval-policy.test.ts +6 -275
- package/src/permissions/approval-policy.ts +0 -51
- package/src/permissions/checker.test.ts +0 -1
- package/src/permissions/checker.ts +3 -17
- package/src/permissions/gateway-threshold-reader.ts +2 -0
- package/src/permissions/prompter.ts +34 -1
- package/src/permissions/secret-prompter.ts +6 -2
- package/src/plugins/defaults/injectors.ts +35 -2
- package/src/plugins/defaults/memory-retrieval.ts +5 -6
- package/src/plugins/types.ts +7 -0
- package/src/proactive-artifact/aux-message-injector.ts +74 -0
- package/src/proactive-artifact/decision.test.ts +226 -0
- package/src/proactive-artifact/decision.ts +165 -0
- package/src/proactive-artifact/index.ts +7 -0
- package/src/proactive-artifact/job.test.ts +867 -0
- package/src/proactive-artifact/job.ts +352 -0
- package/src/proactive-artifact/message-copy.ts +41 -0
- package/src/proactive-artifact/trigger-state.test.ts +277 -0
- package/src/proactive-artifact/trigger-state.ts +119 -0
- package/src/prompts/bootstrap-cleanup.ts +27 -0
- package/src/prompts/normalize-onboarding.ts +80 -0
- package/src/prompts/persona-resolver.ts +101 -9
- package/src/prompts/system-prompt.ts +23 -24
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/providers/__tests__/retry-callsite.test.ts +222 -1
- package/src/providers/model-intents.ts +7 -0
- package/src/providers/openrouter/client.ts +8 -0
- package/src/providers/retry.ts +50 -0
- package/src/providers/speech-to-text/provider-catalog.ts +7 -8
- package/src/providers/types.ts +1 -0
- package/src/runtime/__tests__/agent-wake.test.ts +456 -3
- package/src/runtime/agent-wake.ts +238 -100
- package/src/runtime/assistant-event-hub.ts +151 -99
- package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
- package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
- package/src/runtime/auth/middleware.ts +0 -96
- package/src/runtime/auth/route-policy.ts +32 -0
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/btw-sidechain.ts +2 -3
- package/src/runtime/channel-invite-transport.ts +2 -48
- package/src/runtime/channel-invite-transports/email.ts +1 -1
- package/src/runtime/channel-invite-transports/slack.ts +1 -1
- package/src/runtime/channel-invite-transports/telegram.ts +1 -1
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
- package/src/runtime/channel-invite-types.ts +54 -0
- package/src/runtime/channel-readiness-service.ts +32 -13
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/guardian-reply-router.ts +10 -0
- package/src/runtime/http-server.ts +3 -329
- package/src/runtime/http-types.ts +0 -5
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
- package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
- package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
- package/src/runtime/migrations/migration-transport.ts +7 -7
- package/src/runtime/migrations/vbundle-builder.ts +327 -60
- package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
- package/src/runtime/migrations/vbundle-importer.ts +245 -68
- package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
- package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
- package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
- package/src/runtime/migrations/vbundle-validator.ts +114 -0
- package/src/runtime/pending-interactions.ts +43 -9
- package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
- package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -5
- package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
- package/src/runtime/routes/approval-interception-types.ts +13 -0
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
- package/src/runtime/routes/backup-routes.ts +15 -38
- package/src/runtime/routes/btw-routes.ts +14 -37
- package/src/runtime/routes/client-routes.ts +21 -2
- package/src/runtime/routes/contact-prompt-routes.ts +183 -0
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-query-routes.ts +36 -1
- package/src/runtime/routes/conversation-routes.ts +65 -39
- package/src/runtime/routes/debug-bash-routes.ts +163 -0
- package/src/runtime/routes/disk-pressure-routes.ts +121 -0
- package/src/runtime/routes/document-pdf-renderer.ts +169 -0
- package/src/runtime/routes/documents-routes.ts +32 -75
- package/src/runtime/routes/errors.ts +19 -4
- package/src/runtime/routes/events-routes.ts +38 -0
- package/src/runtime/routes/gateway-log-routes.ts +79 -0
- package/src/runtime/routes/guardian-approval-interception.ts +2 -8
- package/src/runtime/routes/heartbeat-routes.ts +103 -38
- package/src/runtime/routes/host-app-control-routes.ts +134 -0
- package/src/runtime/routes/host-bash-routes.ts +56 -6
- package/src/runtime/routes/host-browser-routes.ts +108 -13
- package/src/runtime/routes/host-cu-routes.ts +66 -9
- package/src/runtime/routes/host-file-routes.ts +54 -5
- package/src/runtime/routes/host-transfer-routes.ts +122 -19
- package/src/runtime/routes/http-adapter.ts +1 -0
- package/src/runtime/routes/identity-intro-cache.ts +30 -0
- package/src/runtime/routes/identity-routes.ts +21 -180
- package/src/runtime/routes/inbound-message-handler.ts +78 -21
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
- package/src/runtime/routes/index.ts +14 -0
- package/src/runtime/routes/mcp-auth-routes.ts +132 -0
- package/src/runtime/routes/memory-item-routes.test.ts +41 -15
- package/src/runtime/routes/memory-item-routes.ts +10 -12
- package/src/runtime/routes/memory-v2-routes.ts +474 -1
- package/src/runtime/routes/migration-routes.ts +96 -0
- package/src/runtime/routes/oauth-connect-routes.ts +153 -0
- package/src/runtime/routes/schedule-routes.ts +7 -0
- package/src/runtime/verification-outbound-actions.ts +4 -4
- package/src/runtime/verification-templates.ts +4 -7
- package/src/schedule/integration-status.ts +66 -2
- package/src/schedule/recurrence-engine.ts +4 -1
- package/src/schedule/retry-backoff.ts +18 -0
- package/src/schedule/retry-policy.ts +82 -0
- package/src/schedule/run-script.ts +37 -5
- package/src/schedule/schedule-recovery.ts +64 -0
- package/src/schedule/schedule-store.ts +106 -2
- package/src/schedule/scheduler-types.ts +25 -0
- package/src/schedule/scheduler.ts +83 -39
- package/src/security/encrypted-store.ts +2 -0
- package/src/security/oauth-callback-registry.ts +8 -0
- package/src/security/secure-keys.ts +55 -0
- package/src/sequence/analytics.ts +5 -5
- package/src/sequence/engine.ts +1 -1
- package/src/skills/catalog-files.ts +2 -8
- package/src/skills/include-graph.ts +5 -5
- package/src/skills/remote-skill-policy.ts +10 -16
- package/src/skills/skill-file-provider.ts +1 -1
- package/src/skills/skill-file-types.ts +13 -0
- package/src/skills/skillssh-audit-types.ts +28 -0
- package/src/skills/skillssh-registry.ts +8 -21
- package/src/subagent/index.ts +1 -7
- package/src/subagent/manager.ts +1 -15
- package/src/tasks/task-runner.ts +0 -1
- package/src/tasks/task-store.ts +0 -3
- package/src/telemetry/types.ts +2 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
- package/src/tools/apps/executors.ts +56 -69
- package/src/tools/background-tool-registry.ts +17 -3
- package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
- package/src/tools/browser/browser-execution.ts +2 -2
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
- package/src/tools/browser/cdp-client/factory.ts +23 -24
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/computer-use/definitions.ts +42 -20
- package/src/tools/executor.ts +2 -0
- package/src/tools/host-filesystem/edit.test.ts +151 -0
- package/src/tools/host-filesystem/edit.ts +68 -0
- package/src/tools/host-filesystem/read.test.ts +129 -0
- package/src/tools/host-filesystem/read.ts +68 -0
- package/src/tools/host-filesystem/transfer.test.ts +127 -2
- package/src/tools/host-filesystem/transfer.ts +78 -3
- package/src/tools/host-filesystem/write.test.ts +134 -0
- package/src/tools/host-filesystem/write.ts +68 -0
- package/src/tools/host-terminal/host-shell.ts +66 -1
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/register.test.ts +12 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/schedule/create.ts +6 -0
- package/src/tools/schedule/list.ts +2 -0
- package/src/tools/schedule/update.ts +10 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
- package/src/tools/shared/filesystem/path-policy.ts +25 -1
- package/src/tools/skills/load.ts +0 -32
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +32 -11
- package/src/tools/types.ts +28 -2
- package/src/tts/provider-catalog.ts +3 -5
- package/src/usage/pricing.ts +1 -1
- package/src/util/disk-usage.ts +138 -0
- package/src/util/platform.ts +21 -11
- package/src/util/process-liveness.ts +26 -0
- package/src/workspace/hatched-date.ts +86 -0
- package/src/workspace/heartbeat-service.ts +19 -0
- package/src/workspace/migrations/003-seed-device-id.ts +1 -1
- package/src/workspace/migrations/006-services-config.ts +8 -5
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
- package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
- package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/utils.ts +21 -0
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
- package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
- package/src/__tests__/twilio-rest.test.ts +0 -34
- package/src/backup/__tests__/backup-key.test.ts +0 -152
- package/src/backup/__tests__/backup-worker.test.ts +0 -782
- package/src/backup/__tests__/offsite-writer.test.ts +0 -641
- package/src/backup/__tests__/stream-crypt.test.ts +0 -228
- package/src/backup/backup-key.ts +0 -137
- package/src/backup/backup-worker.ts +0 -472
- package/src/backup/offsite-writer.ts +0 -222
- package/src/backup/stream-crypt.ts +0 -263
- package/src/daemon/message-types/pairing.ts +0 -58
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
- package/src/memory/v2/skill-qdrant.ts +0 -395
- package/src/outbound-proxy/config.ts +0 -20
- package/src/outbound-proxy/health.ts +0 -18
- package/src/outbound-proxy/types.ts +0 -150
- package/src/runtime/capability-tokens.ts +0 -190
- package/src/signals/bash.ts +0 -198
- package/src/signals/mcp-reload.ts +0 -18
|
@@ -372,26 +372,58 @@ describe("memoryV2ConsolidateJob — concurrent invocations", () => {
|
|
|
372
372
|
writeFileSync(bufferPath(), "- [Apr 27, 9:00 AM] Alice prefers VS Code.\n");
|
|
373
373
|
});
|
|
374
374
|
|
|
375
|
-
test("a
|
|
376
|
-
// Pre-seed a lock file
|
|
377
|
-
//
|
|
378
|
-
//
|
|
375
|
+
test("a live lock holder blocks a second concurrent invocation", async () => {
|
|
376
|
+
// Pre-seed a lock file with the current process's PID so the liveness
|
|
377
|
+
// probe sees a running holder and the second invocation correctly
|
|
378
|
+
// reports `locked` rather than taking over.
|
|
379
379
|
mkdirSync(join(memoryDir(), ".v2-state"), { recursive: true });
|
|
380
|
-
writeFileSync(lockPath(),
|
|
380
|
+
writeFileSync(lockPath(), `${process.pid} 1700000000000\n`);
|
|
381
381
|
|
|
382
382
|
const result = await memoryV2ConsolidateJob(makeJob(), CONFIG);
|
|
383
383
|
|
|
384
384
|
expect(result.kind).toBe("locked");
|
|
385
385
|
if (result.kind === "locked") {
|
|
386
|
-
expect(result.holder).toContain(
|
|
386
|
+
expect(result.holder).toContain(`${process.pid}`);
|
|
387
387
|
}
|
|
388
388
|
expect(bootstrapCalls).toBe(0);
|
|
389
389
|
expect(wakeCalls).toBe(0);
|
|
390
390
|
expect(enqueuedJobs).toHaveLength(0);
|
|
391
|
-
// The
|
|
392
|
-
// owner releases it.
|
|
391
|
+
// The live holder's lock must NOT be removed by a contender.
|
|
393
392
|
expect(existsSync(lockPath())).toBe(true);
|
|
394
393
|
});
|
|
394
|
+
|
|
395
|
+
test("a stale lock from a non-running PID is taken over and consolidation proceeds", async () => {
|
|
396
|
+
// PID 999999 is well outside the typical kernel max_pid range on macOS
|
|
397
|
+
// and Linux, so kill(pid, 0) reliably returns ESRCH. The takeover path
|
|
398
|
+
// must unlink the stale file, retry the wx create, and bootstrap the
|
|
399
|
+
// background conversation as if the lock had been free all along.
|
|
400
|
+
mkdirSync(join(memoryDir(), ".v2-state"), { recursive: true });
|
|
401
|
+
writeFileSync(lockPath(), "999999 1700000000000\n");
|
|
402
|
+
|
|
403
|
+
const result = await memoryV2ConsolidateJob(makeJob(), CONFIG);
|
|
404
|
+
|
|
405
|
+
expect(result.kind).toBe("invoked");
|
|
406
|
+
expect(bootstrapCalls).toBe(1);
|
|
407
|
+
expect(wakeCalls).toBe(1);
|
|
408
|
+
// Lock is released in the finally block after a successful run.
|
|
409
|
+
expect(existsSync(lockPath())).toBe(false);
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test("an empty / corrupted lock file is treated as stale and taken over", async () => {
|
|
413
|
+
// A zero-byte file simulates a prior holder that crashed between the
|
|
414
|
+
// O_EXCL create and the PID write. With only one writer ever, an
|
|
415
|
+
// unparseable payload is unambiguously corruption, not a live
|
|
416
|
+
// mid-write — take it over.
|
|
417
|
+
mkdirSync(join(memoryDir(), ".v2-state"), { recursive: true });
|
|
418
|
+
writeFileSync(lockPath(), "");
|
|
419
|
+
|
|
420
|
+
const result = await memoryV2ConsolidateJob(makeJob(), CONFIG);
|
|
421
|
+
|
|
422
|
+
expect(result.kind).toBe("invoked");
|
|
423
|
+
expect(bootstrapCalls).toBe(1);
|
|
424
|
+
expect(wakeCalls).toBe(1);
|
|
425
|
+
expect(existsSync(lockPath())).toBe(false);
|
|
426
|
+
});
|
|
395
427
|
});
|
|
396
428
|
|
|
397
429
|
describe("CONSOLIDATION_PROMPT", () => {
|
|
@@ -8,18 +8,18 @@
|
|
|
8
8
|
* - A new topic appearing on a later turn injects only the new slug.
|
|
9
9
|
* - `evictCompactedTurns` re-enables a previously-injected slug —
|
|
10
10
|
* after eviction the same slug appears again in `toInject`.
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* - Unified-pool skills: a `skills/<id>` slug ranked into the top-K is
|
|
12
|
+
* rendered under `### Skills You Can Use`, mixed concept-page+skill
|
|
13
|
+
* blocks render concept sections first then the skills suffix, both
|
|
14
|
+
* empty → null block, skills participate in `everInjected` so they
|
|
15
|
+
* deduplicate across turns just like concepts.
|
|
14
16
|
*
|
|
15
17
|
* Hermetic by design: the embedding backend, qdrant client, and `getConfig`
|
|
16
18
|
* are mocked at the module level so the suite never reaches a real backend.
|
|
17
|
-
* The skill
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* Qdrant collection. The activation-store uses an in-memory SQLite database
|
|
22
|
-
* so writes are real but contained.
|
|
19
|
+
* The skill-store cache (`getSkillCapability`, `isSkillSlug`) is mocked so
|
|
20
|
+
* each test can stage skill content without touching the real catalog.
|
|
21
|
+
* The activation-store uses an in-memory SQLite database so writes are
|
|
22
|
+
* real but contained.
|
|
23
23
|
*
|
|
24
24
|
* Tests use a temp workspace (mkdtemp) and never touch `~/.vellum/`. Sample
|
|
25
25
|
* page content uses generic placeholders (Alice, Bob, etc.) per the cross-
|
|
@@ -124,43 +124,32 @@ mock.module("@qdrant/js-client-rest", () => ({
|
|
|
124
124
|
}));
|
|
125
125
|
|
|
126
126
|
// ---------------------------------------------------------------------------
|
|
127
|
-
// Skill
|
|
127
|
+
// Skill-store mock
|
|
128
128
|
// ---------------------------------------------------------------------------
|
|
129
129
|
//
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
//
|
|
130
|
+
// Skills now flow through the unified pipeline under the `skills/<id>` slug
|
|
131
|
+
// prefix — they are scored by `simBatch` against the same Qdrant collection
|
|
132
|
+
// as concept pages, ranked by `selectInjections`, and rendered alongside
|
|
133
|
+
// concept sections. The render path branches on `isSkillSlug(slug)` to fetch
|
|
134
|
+
// content from the in-process cache via `getSkillCapability` instead of
|
|
135
|
+
// reading a page from disk. Tests stage that cache and rely on the regular
|
|
136
|
+
// `stageTurn` plumbing to land skill slugs in the candidate set.
|
|
137
137
|
|
|
138
138
|
const skillState = {
|
|
139
|
-
/**
|
|
140
|
-
topSkillIds: [] as string[],
|
|
141
|
-
/** id → SkillEntry used by `getSkillCapability`. */
|
|
139
|
+
/** id → SkillEntry consulted by `getSkillCapability`. */
|
|
142
140
|
entries: new Map<string, SkillEntry>(),
|
|
143
141
|
};
|
|
144
142
|
|
|
145
|
-
const realActivation = await import("../activation.js");
|
|
146
|
-
mock.module("../activation.js", () => ({
|
|
147
|
-
...realActivation,
|
|
148
|
-
// The injection wiring only consumes `topNow` — the candidate set and
|
|
149
|
-
// activation map are inputs to `selectSkillInjections`, not anything the
|
|
150
|
-
// injection logic introspects. Stub them to empty so the test stays focused
|
|
151
|
-
// on the wiring, not the pipeline internals (covered in activation.test.ts).
|
|
152
|
-
selectSkillCandidates: async () => new Set<string>(),
|
|
153
|
-
computeSkillActivation: async () => ({
|
|
154
|
-
activation: new Map<string, number>(),
|
|
155
|
-
breakdown: new Map(),
|
|
156
|
-
}),
|
|
157
|
-
selectSkillInjections: ({ topK }: { topK: number }) => ({
|
|
158
|
-
topNow: skillState.topSkillIds.slice(0, topK),
|
|
159
|
-
}),
|
|
160
|
-
}));
|
|
161
|
-
|
|
162
143
|
mock.module("../skill-store.js", () => ({
|
|
163
|
-
getSkillCapability: (
|
|
144
|
+
getSkillCapability: (idOrSlug: string) => {
|
|
145
|
+
const id = idOrSlug.startsWith("skills/")
|
|
146
|
+
? idOrSlug.slice("skills/".length)
|
|
147
|
+
: idOrSlug;
|
|
148
|
+
return skillState.entries.get(id) ?? null;
|
|
149
|
+
},
|
|
150
|
+
isSkillSlug: (slug: string) => slug.startsWith("skills/"),
|
|
151
|
+
SKILL_SLUG_PREFIX: "skills/",
|
|
152
|
+
skillSlugFor: (id: string) => `skills/${id}`,
|
|
164
153
|
}));
|
|
165
154
|
|
|
166
155
|
// ---------------------------------------------------------------------------
|
|
@@ -292,7 +281,6 @@ function makeConfig(
|
|
|
292
281
|
k: number;
|
|
293
282
|
hops: number;
|
|
294
283
|
top_k: number;
|
|
295
|
-
top_k_skills: number;
|
|
296
284
|
epsilon: number;
|
|
297
285
|
dense_weight: number;
|
|
298
286
|
sparse_weight: number;
|
|
@@ -307,8 +295,7 @@ function makeConfig(
|
|
|
307
295
|
c_now: 0.2,
|
|
308
296
|
k: 0.5,
|
|
309
297
|
hops: 2,
|
|
310
|
-
top_k:
|
|
311
|
-
top_k_skills: 5,
|
|
298
|
+
top_k: 25,
|
|
312
299
|
epsilon: 0.01,
|
|
313
300
|
dense_weight: 1.0,
|
|
314
301
|
sparse_weight: 0.0,
|
|
@@ -331,6 +318,13 @@ function stageTurn(
|
|
|
331
318
|
hits: Array<{ slug: string; denseScore?: number; sparseScore?: number }>,
|
|
332
319
|
channels = 4,
|
|
333
320
|
): void {
|
|
321
|
+
// Clear any leftovers from a prior turn before staging this one so unused
|
|
322
|
+
// staged responses can't bleed into the next injection. The activation
|
|
323
|
+
// pipeline now skips the embedding round-trip for empty texts (turn 1's
|
|
324
|
+
// assistantMessage), so consumed-channel counts vary per turn — staging
|
|
325
|
+
// exclusively is the only way multi-turn tests stay aligned.
|
|
326
|
+
state.queryResponses.dense.length = 0;
|
|
327
|
+
state.queryResponses.sparse.length = 0;
|
|
334
328
|
for (let i = 0; i < channels; i++) {
|
|
335
329
|
state.queryResponses.dense.push({
|
|
336
330
|
points: hits
|
|
@@ -350,7 +344,6 @@ function resetState(): void {
|
|
|
350
344
|
state.sparseReturn = { indices: [1, 2, 3], values: [0.5, 0.5, 0.5] };
|
|
351
345
|
state.queryResponses.dense.length = 0;
|
|
352
346
|
state.queryResponses.sparse.length = 0;
|
|
353
|
-
skillState.topSkillIds.length = 0;
|
|
354
347
|
skillState.entries.clear();
|
|
355
348
|
telemetryState.recordCalls.length = 0;
|
|
356
349
|
telemetryState.recordShouldThrow = false;
|
|
@@ -360,10 +353,8 @@ function resetState(): void {
|
|
|
360
353
|
_resetMemoryV2QdrantForTests();
|
|
361
354
|
}
|
|
362
355
|
|
|
363
|
-
/** Stage
|
|
364
|
-
function stageSkills(
|
|
365
|
-
skillState.topSkillIds.length = 0;
|
|
366
|
-
skillState.topSkillIds.push(...ids);
|
|
356
|
+
/** Stage skill-store cache entries for the upcoming render. */
|
|
357
|
+
function stageSkills(entries: SkillEntry[]): void {
|
|
367
358
|
for (const entry of entries) {
|
|
368
359
|
skillState.entries.set(entry.id, entry);
|
|
369
360
|
}
|
|
@@ -399,11 +390,13 @@ describe("injectMemoryV2Block", () => {
|
|
|
399
390
|
|
|
400
391
|
expect(result.toInject).toEqual(["alice-vscode"]);
|
|
401
392
|
expect(result.block).not.toBeNull();
|
|
402
|
-
|
|
393
|
+
// `block` is the unwrapped inner content; the caller adds the
|
|
394
|
+
// `<memory>...</memory>` wrapper exactly once at injection time.
|
|
395
|
+
expect(result.block).not.toContain("<memory>");
|
|
396
|
+
expect(result.block).not.toContain("</memory>");
|
|
403
397
|
expect(result.block).not.toContain("## What I Remember Right Now");
|
|
404
398
|
expect(result.block).toContain("### alice-vscode");
|
|
405
399
|
expect(result.block).toContain("VS Code");
|
|
406
|
-
expect(result.block).toContain("</memory>");
|
|
407
400
|
|
|
408
401
|
// State persisted: alice's activation is above epsilon and recorded;
|
|
409
402
|
// everInjected captured the new slug + currentTurn.
|
|
@@ -652,27 +645,36 @@ describe("injectMemoryV2Block", () => {
|
|
|
652
645
|
expect(persisted!.everInjected).toEqual([
|
|
653
646
|
{ slug: "phantom-slug", turn: 1 },
|
|
654
647
|
]);
|
|
648
|
+
|
|
649
|
+
// Activation log marks the slug `page_missing` (not `injected`) so a
|
|
650
|
+
// stale Qdrant / edge-index entry pointing at a vanished page is
|
|
651
|
+
// visible in telemetry instead of masquerading as a successful inject.
|
|
652
|
+
expect(telemetryState.recordCalls.length).toBe(1);
|
|
653
|
+
const row = telemetryState.recordCalls[0] as {
|
|
654
|
+
concepts: Array<{ slug: string; status: string }>;
|
|
655
|
+
};
|
|
656
|
+
const phantom = row.concepts.find((c) => c.slug === "phantom-slug");
|
|
657
|
+
expect(phantom).toBeDefined();
|
|
658
|
+
expect(phantom!.status).toBe("page_missing");
|
|
655
659
|
});
|
|
656
660
|
|
|
657
661
|
// ---------------------------------------------------------------------------
|
|
658
|
-
//
|
|
662
|
+
// Unified pool — skills as `skills/<id>` slugs
|
|
659
663
|
// ---------------------------------------------------------------------------
|
|
660
664
|
|
|
661
|
-
test("renders a skill-only block
|
|
662
|
-
// No concept-page candidates this turn — the
|
|
663
|
-
//
|
|
664
|
-
//
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
],
|
|
675
|
-
);
|
|
665
|
+
test("renders a skill-only block via the skills/ slug prefix", async () => {
|
|
666
|
+
// No concept-page candidates this turn — the only ANN hit is a skill
|
|
667
|
+
// slug. The render path branches on `skills/` prefix: it pulls the
|
|
668
|
+
// entry from the skill-store cache (mocked) and emits the bullet under
|
|
669
|
+
// the `### Skills You Can Use` subsection.
|
|
670
|
+
stageTurn([{ slug: "skills/example-skill-a", denseScore: 0.9 }]);
|
|
671
|
+
stageSkills([
|
|
672
|
+
{
|
|
673
|
+
id: "example-skill-a",
|
|
674
|
+
content:
|
|
675
|
+
'The "Example Skill A" skill (example-skill-a) is available. Helps with examples.',
|
|
676
|
+
},
|
|
677
|
+
]);
|
|
676
678
|
|
|
677
679
|
const result = await injectMemoryV2Block({
|
|
678
680
|
database: db,
|
|
@@ -685,14 +687,11 @@ describe("injectMemoryV2Block", () => {
|
|
|
685
687
|
config: makeConfig(),
|
|
686
688
|
});
|
|
687
689
|
|
|
688
|
-
expect(result.toInject).toEqual([]);
|
|
690
|
+
expect(result.toInject).toEqual(["skills/example-skill-a"]);
|
|
689
691
|
expect(result.block).not.toBeNull();
|
|
690
|
-
|
|
691
|
-
expect(result.block).toContain("
|
|
692
|
+
expect(result.block).not.toContain("<memory>");
|
|
693
|
+
expect(result.block).not.toContain("</memory>");
|
|
692
694
|
expect(result.block).not.toContain("## What I Remember Right Now");
|
|
693
|
-
expect(result.block).toContain("</memory>");
|
|
694
|
-
// No concept-page sections; skills subsection present with the right
|
|
695
|
-
// bullet shape and the unconditional `→ use skill_load to activate` suffix.
|
|
696
695
|
expect(result.block).not.toContain("### alice-vscode");
|
|
697
696
|
expect(result.block).toContain("### Skills You Can Use");
|
|
698
697
|
expect(result.block).toContain(
|
|
@@ -701,19 +700,19 @@ describe("injectMemoryV2Block", () => {
|
|
|
701
700
|
});
|
|
702
701
|
|
|
703
702
|
test("renders concept-page sections before the skills subsection in mixed blocks", async () => {
|
|
704
|
-
// Concept page
|
|
703
|
+
// Concept page hit AND a skill — concept-page sections come first, then
|
|
705
704
|
// the skills subsection.
|
|
706
|
-
stageTurn([
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
);
|
|
705
|
+
stageTurn([
|
|
706
|
+
{ slug: "alice-vscode", denseScore: 0.9 },
|
|
707
|
+
{ slug: "skills/example-skill-a", denseScore: 0.7 },
|
|
708
|
+
]);
|
|
709
|
+
stageSkills([
|
|
710
|
+
{
|
|
711
|
+
id: "example-skill-a",
|
|
712
|
+
content:
|
|
713
|
+
'The "Example Skill A" skill (example-skill-a) is available. Helps with examples.',
|
|
714
|
+
},
|
|
715
|
+
]);
|
|
717
716
|
|
|
718
717
|
const result = await injectMemoryV2Block({
|
|
719
718
|
database: db,
|
|
@@ -726,7 +725,10 @@ describe("injectMemoryV2Block", () => {
|
|
|
726
725
|
config: makeConfig(),
|
|
727
726
|
});
|
|
728
727
|
|
|
729
|
-
|
|
728
|
+
// Both slugs ranked into top-K and got freshly attached.
|
|
729
|
+
expect(new Set(result.toInject)).toEqual(
|
|
730
|
+
new Set(["alice-vscode", "skills/example-skill-a"]),
|
|
731
|
+
);
|
|
730
732
|
expect(result.block).not.toBeNull();
|
|
731
733
|
|
|
732
734
|
const aliceIdx = result.block!.indexOf("### alice-vscode");
|
|
@@ -735,46 +737,20 @@ describe("injectMemoryV2Block", () => {
|
|
|
735
737
|
expect(skillsIdx).toBeGreaterThan(-1);
|
|
736
738
|
expect(aliceIdx).toBeLessThan(skillsIdx);
|
|
737
739
|
|
|
738
|
-
// The activation suffix is always appended for skills.
|
|
739
740
|
expect(result.block).toContain(
|
|
740
741
|
'- The "Example Skill A" skill (example-skill-a) is available. Helps with examples. → use skill_load to activate',
|
|
741
742
|
);
|
|
742
743
|
});
|
|
743
744
|
|
|
744
|
-
test("
|
|
745
|
-
//
|
|
746
|
-
// AND no skill ids.
|
|
747
|
-
stageTurn([]);
|
|
748
|
-
stageSkills([]);
|
|
749
|
-
|
|
750
|
-
const result = await injectMemoryV2Block({
|
|
751
|
-
database: db,
|
|
752
|
-
conversationId: "conv-1",
|
|
753
|
-
currentTurn: 1,
|
|
754
|
-
userMessage: "anything",
|
|
755
|
-
assistantMessage: "",
|
|
756
|
-
nowText: "",
|
|
757
|
-
messageId: "msg-1",
|
|
758
|
-
config: makeConfig(),
|
|
759
|
-
});
|
|
760
|
-
|
|
761
|
-
expect(result.toInject).toEqual([]);
|
|
762
|
-
expect(result.block).toBeNull();
|
|
763
|
-
});
|
|
764
|
-
|
|
765
|
-
test("re-renders the same top-ranked skill on consecutive turns (no dedup)", async () => {
|
|
766
|
-
// Skills are stateless: the same id can appear on back-to-back turns.
|
|
767
|
-
// Stage no concept-page candidates so the block content is purely the
|
|
768
|
-
// skills subsection.
|
|
745
|
+
test("skills participate in everInjected — an attached skill is not re-attached on the next turn", async () => {
|
|
746
|
+
// Turn 1: skill ranks high, gets attached.
|
|
769
747
|
const skillEntry = {
|
|
770
748
|
id: "example-skill-a",
|
|
771
749
|
content:
|
|
772
750
|
'The "Example Skill A" skill (example-skill-a) is available. Helps with examples.',
|
|
773
751
|
};
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
stageTurn([]);
|
|
777
|
-
stageSkills(["example-skill-a"], [skillEntry]);
|
|
752
|
+
stageTurn([{ slug: "skills/example-skill-a", denseScore: 0.9 }]);
|
|
753
|
+
stageSkills([skillEntry]);
|
|
778
754
|
const result1 = await injectMemoryV2Block({
|
|
779
755
|
database: db,
|
|
780
756
|
conversationId: "conv-1",
|
|
@@ -785,15 +761,14 @@ describe("injectMemoryV2Block", () => {
|
|
|
785
761
|
messageId: "msg-1",
|
|
786
762
|
config: makeConfig(),
|
|
787
763
|
});
|
|
788
|
-
expect(result1.
|
|
764
|
+
expect(result1.toInject).toEqual(["skills/example-skill-a"]);
|
|
789
765
|
expect(result1.block).toContain("### Skills You Can Use");
|
|
790
|
-
expect(result1.block).toContain("example-skill-a");
|
|
791
766
|
|
|
792
|
-
// Turn 2
|
|
793
|
-
//
|
|
794
|
-
//
|
|
795
|
-
stageTurn([]);
|
|
796
|
-
stageSkills([
|
|
767
|
+
// Turn 2: same skill ranks top again. It is already in `everInjected`, so
|
|
768
|
+
// `toInject` is empty and the block is null — the attachment from turn 1
|
|
769
|
+
// remains visible to the agent via the cached prior user message.
|
|
770
|
+
stageTurn([{ slug: "skills/example-skill-a", denseScore: 0.9 }]);
|
|
771
|
+
stageSkills([skillEntry]);
|
|
797
772
|
const result2 = await injectMemoryV2Block({
|
|
798
773
|
database: db,
|
|
799
774
|
conversationId: "conv-1",
|
|
@@ -804,21 +779,57 @@ describe("injectMemoryV2Block", () => {
|
|
|
804
779
|
messageId: "msg-2",
|
|
805
780
|
config: makeConfig(),
|
|
806
781
|
});
|
|
807
|
-
expect(result2.
|
|
808
|
-
expect(result2.block).
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
// The skill content line is identical across the two turns — the renderer
|
|
812
|
-
// is deterministic in `id → entry` lookup and the entry is unchanged.
|
|
813
|
-
const skillLine =
|
|
814
|
-
'- The "Example Skill A" skill (example-skill-a) is available. Helps with examples. → use skill_load to activate';
|
|
815
|
-
expect(result1.block).toContain(skillLine);
|
|
816
|
-
expect(result2.block).toContain(skillLine);
|
|
817
|
-
|
|
818
|
-
// `everInjected` is untouched by the skill pipeline — both turns left it
|
|
819
|
-
// empty (no concept pages were injected).
|
|
782
|
+
expect(result2.toInject).toEqual([]);
|
|
783
|
+
expect(result2.block).toBeNull();
|
|
784
|
+
|
|
820
785
|
const persisted = await hydrate(db, "conv-1");
|
|
821
|
-
expect(persisted!.everInjected).toEqual([
|
|
786
|
+
expect(persisted!.everInjected).toEqual([
|
|
787
|
+
{ slug: "skills/example-skill-a", turn: 1 },
|
|
788
|
+
]);
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
test("skill slugs whose entry is missing from the cache are dropped silently", async () => {
|
|
792
|
+
// The skill ranks into top-K but the in-process cache no longer knows
|
|
793
|
+
// its content (skill uninstalled mid-run). The render path drops it
|
|
794
|
+
// without surfacing it as a `missingSlugs` page-missing event — that
|
|
795
|
+
// status is reserved for on-disk concept pages, not catalog-derived
|
|
796
|
+
// skill entries.
|
|
797
|
+
stageTurn([{ slug: "skills/missing-skill", denseScore: 0.9 }]);
|
|
798
|
+
// No `stageSkills` call — cache stays empty.
|
|
799
|
+
|
|
800
|
+
const result = await injectMemoryV2Block({
|
|
801
|
+
database: db,
|
|
802
|
+
conversationId: "conv-1",
|
|
803
|
+
currentTurn: 1,
|
|
804
|
+
userMessage: "anything",
|
|
805
|
+
assistantMessage: "",
|
|
806
|
+
nowText: "Now",
|
|
807
|
+
messageId: "msg-1",
|
|
808
|
+
config: makeConfig(),
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
// `toInject` still records the slug (it ranked into top-K) but the
|
|
812
|
+
// block collapses to null because the only entry was a cache miss.
|
|
813
|
+
expect(result.toInject).toEqual(["skills/missing-skill"]);
|
|
814
|
+
expect(result.block).toBeNull();
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
test("returns null when both concept pages and skills are empty", async () => {
|
|
818
|
+
stageTurn([]);
|
|
819
|
+
|
|
820
|
+
const result = await injectMemoryV2Block({
|
|
821
|
+
database: db,
|
|
822
|
+
conversationId: "conv-1",
|
|
823
|
+
currentTurn: 1,
|
|
824
|
+
userMessage: "anything",
|
|
825
|
+
assistantMessage: "",
|
|
826
|
+
nowText: "",
|
|
827
|
+
messageId: "msg-1",
|
|
828
|
+
config: makeConfig(),
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
expect(result.toInject).toEqual([]);
|
|
832
|
+
expect(result.block).toBeNull();
|
|
822
833
|
});
|
|
823
834
|
|
|
824
835
|
test("context-load mode renders topNow even when every slug was previously injected", async () => {
|
|
@@ -910,39 +921,6 @@ describe("injectMemoryV2Block", () => {
|
|
|
910
921
|
expect(persisted!.everInjected).toHaveLength(3);
|
|
911
922
|
});
|
|
912
923
|
|
|
913
|
-
test("`top_k_skills: 0` short-circuits to no skills subsection", async () => {
|
|
914
|
-
// Even when the underlying mock would surface skills, the cap at 0 must
|
|
915
|
-
// drop them via `selectSkillInjections.topK = 0` → empty `topNow`.
|
|
916
|
-
stageTurn([{ slug: "alice-vscode", denseScore: 0.9 }]);
|
|
917
|
-
stageSkills(
|
|
918
|
-
["example-skill-a"],
|
|
919
|
-
[
|
|
920
|
-
{
|
|
921
|
-
id: "example-skill-a",
|
|
922
|
-
content:
|
|
923
|
-
'The "Example Skill A" skill (example-skill-a) is available.',
|
|
924
|
-
},
|
|
925
|
-
],
|
|
926
|
-
);
|
|
927
|
-
|
|
928
|
-
const result = await injectMemoryV2Block({
|
|
929
|
-
database: db,
|
|
930
|
-
conversationId: "conv-1",
|
|
931
|
-
currentTurn: 1,
|
|
932
|
-
userMessage: "Alice's editor",
|
|
933
|
-
assistantMessage: "",
|
|
934
|
-
nowText: "Now",
|
|
935
|
-
messageId: "msg-1",
|
|
936
|
-
config: makeConfig({ top_k_skills: 0 }),
|
|
937
|
-
});
|
|
938
|
-
|
|
939
|
-
expect(result.toInject).toEqual(["alice-vscode"]);
|
|
940
|
-
expect(result.block).not.toBeNull();
|
|
941
|
-
expect(result.block).toContain("### alice-vscode");
|
|
942
|
-
expect(result.block).not.toContain("### Skills You Can Use");
|
|
943
|
-
expect(result.block).not.toContain("example-skill-a");
|
|
944
|
-
});
|
|
945
|
-
|
|
946
924
|
// ---------------------------------------------------------------------------
|
|
947
925
|
// Activation-log telemetry
|
|
948
926
|
// ---------------------------------------------------------------------------
|
|
@@ -991,13 +969,12 @@ describe("injectMemoryV2Block", () => {
|
|
|
991
969
|
status: string;
|
|
992
970
|
source: string;
|
|
993
971
|
}>;
|
|
994
|
-
skills: unknown[];
|
|
995
972
|
config: { top_k: number };
|
|
996
973
|
};
|
|
997
974
|
expect(row.conversationId).toBe("conv-1");
|
|
998
975
|
expect(row.turn).toBe(2);
|
|
999
976
|
expect(row.mode).toBe("per-turn");
|
|
1000
|
-
expect(row.config.top_k).toBe(
|
|
977
|
+
expect(row.config.top_k).toBe(25);
|
|
1001
978
|
|
|
1002
979
|
// The candidate set is the union of fromPrior (alice) and fromAnn
|
|
1003
980
|
// (alice + carol) → two concept rows.
|
|
@@ -1019,6 +996,41 @@ describe("injectMemoryV2Block", () => {
|
|
|
1019
996
|
expect(byslug.get("carol-jazz")!.status).toBe("injected");
|
|
1020
997
|
});
|
|
1021
998
|
|
|
999
|
+
test("activation-log concepts include skill rows under the skills/ prefix", async () => {
|
|
1000
|
+
// Skills participate in the unified telemetry list — they live in the
|
|
1001
|
+
// same `concepts` array, identifiable by the `skills/` slug prefix.
|
|
1002
|
+
stageTurn([
|
|
1003
|
+
{ slug: "alice-vscode", denseScore: 0.9 },
|
|
1004
|
+
{ slug: "skills/example-skill-a", denseScore: 0.7 },
|
|
1005
|
+
]);
|
|
1006
|
+
stageSkills([
|
|
1007
|
+
{
|
|
1008
|
+
id: "example-skill-a",
|
|
1009
|
+
content: "skill content",
|
|
1010
|
+
},
|
|
1011
|
+
]);
|
|
1012
|
+
|
|
1013
|
+
await injectMemoryV2Block({
|
|
1014
|
+
database: db,
|
|
1015
|
+
conversationId: "conv-1",
|
|
1016
|
+
currentTurn: 1,
|
|
1017
|
+
userMessage: "Alice's editor",
|
|
1018
|
+
assistantMessage: "",
|
|
1019
|
+
nowText: "Now",
|
|
1020
|
+
messageId: "msg-1",
|
|
1021
|
+
config: makeConfig(),
|
|
1022
|
+
});
|
|
1023
|
+
|
|
1024
|
+
expect(telemetryState.recordCalls.length).toBe(1);
|
|
1025
|
+
const row = telemetryState.recordCalls[0] as {
|
|
1026
|
+
concepts: Array<{ slug: string; status: string }>;
|
|
1027
|
+
};
|
|
1028
|
+
const slugs = row.concepts.map((c) => c.slug);
|
|
1029
|
+
expect(new Set(slugs)).toEqual(
|
|
1030
|
+
new Set(["alice-vscode", "skills/example-skill-a"]),
|
|
1031
|
+
);
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1022
1034
|
test("context-load mode marks every rendered slug as `injected`, never `in_context`", async () => {
|
|
1023
1035
|
// Turn 1 (per-turn): seed alice as injected so the next turn's prior
|
|
1024
1036
|
// `everInjected` includes her — the same setup the per-turn telemetry
|
|
@@ -4,7 +4,14 @@
|
|
|
4
4
|
* file-based override and falls back to the bundled prompt when the
|
|
5
5
|
* override is missing/empty/unreadable.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { execFileSync } from "node:child_process";
|
|
8
|
+
import {
|
|
9
|
+
mkdirSync,
|
|
10
|
+
mkdtempSync,
|
|
11
|
+
rmSync,
|
|
12
|
+
symlinkSync,
|
|
13
|
+
writeFileSync,
|
|
14
|
+
} from "node:fs";
|
|
8
15
|
import { homedir, tmpdir } from "node:os";
|
|
9
16
|
import { join } from "node:path";
|
|
10
17
|
import {
|
|
@@ -67,7 +74,14 @@ beforeEach(() => {
|
|
|
67
74
|
});
|
|
68
75
|
|
|
69
76
|
afterEach(() => {
|
|
70
|
-
for (const entry of [
|
|
77
|
+
for (const entry of [
|
|
78
|
+
"custom-prompt.md",
|
|
79
|
+
"empty.md",
|
|
80
|
+
"no-placeholder.md",
|
|
81
|
+
"huge.md",
|
|
82
|
+
"link.md",
|
|
83
|
+
"fifo",
|
|
84
|
+
]) {
|
|
71
85
|
rmSync(join(tmpWorkspace, entry), { force: true });
|
|
72
86
|
}
|
|
73
87
|
});
|
|
@@ -178,4 +192,49 @@ describe("resolveConsolidationPrompt — failure modes", () => {
|
|
|
178
192
|
const data = warnCalls[0].data as Record<string, unknown>;
|
|
179
193
|
expect(data.reason).toBe("empty_override");
|
|
180
194
|
});
|
|
195
|
+
|
|
196
|
+
test("falls back to bundled prompt when the override exceeds the size limit", () => {
|
|
197
|
+
const path = join(tmpWorkspace, "huge.md");
|
|
198
|
+
// 1 MiB + 1 byte — just over the cap so we don't waste test memory.
|
|
199
|
+
writeFileSync(path, Buffer.alloc(1 * 1024 * 1024 + 1, 0x61));
|
|
200
|
+
|
|
201
|
+
const result = resolveConsolidationPrompt(path, CUTOFF);
|
|
202
|
+
|
|
203
|
+
expect(result).toBe(bundledPrompt());
|
|
204
|
+
expect(warnCalls).toHaveLength(1);
|
|
205
|
+
const data = warnCalls[0].data as Record<string, unknown>;
|
|
206
|
+
expect(data.reason).toBe("oversized_override");
|
|
207
|
+
expect(data.size).toBe(1 * 1024 * 1024 + 1);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("falls back to bundled prompt when the override is a symlink", () => {
|
|
211
|
+
const target = join(tmpWorkspace, "custom-prompt.md");
|
|
212
|
+
writeFileSync(target, "real prompt body\n");
|
|
213
|
+
const link = join(tmpWorkspace, "link.md");
|
|
214
|
+
symlinkSync(target, link);
|
|
215
|
+
|
|
216
|
+
const result = resolveConsolidationPrompt(link, CUTOFF);
|
|
217
|
+
|
|
218
|
+
expect(result).toBe(bundledPrompt());
|
|
219
|
+
expect(warnCalls).toHaveLength(1);
|
|
220
|
+
const data = warnCalls[0].data as Record<string, unknown>;
|
|
221
|
+
expect(data.reason).toBe("not_regular_file");
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("falls back to bundled prompt when the override is a FIFO", () => {
|
|
225
|
+
const fifoPath = join(tmpWorkspace, "fifo");
|
|
226
|
+
try {
|
|
227
|
+
execFileSync("mkfifo", [fifoPath]);
|
|
228
|
+
} catch {
|
|
229
|
+
// mkfifo unavailable on this platform — skip without failing.
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const result = resolveConsolidationPrompt(fifoPath, CUTOFF);
|
|
234
|
+
|
|
235
|
+
expect(result).toBe(bundledPrompt());
|
|
236
|
+
expect(warnCalls).toHaveLength(1);
|
|
237
|
+
const data = warnCalls[0].data as Record<string, unknown>;
|
|
238
|
+
expect(data.reason).toBe("not_regular_file");
|
|
239
|
+
});
|
|
181
240
|
});
|