@vellumai/assistant 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +32 -49
- 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/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 +39 -1
- 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/skill-host-contracts/src/assistant-event.ts +9 -0
- 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 +565 -12
- 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 +374 -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 +109 -2
- package/src/__tests__/assistant-event.test.ts +10 -0
- package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -7
- package/src/__tests__/background-shell-host-bash.test.ts +14 -15
- 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-domain.test.ts +0 -2
- package/src/__tests__/call-routes-http.test.ts +0 -2
- package/src/__tests__/channel-readiness-service.test.ts +59 -1
- package/src/__tests__/checker.test.ts +3 -4
- package/src/__tests__/config-loader-backfill.test.ts +90 -155
- 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-set-platform-guard.test.ts +48 -4
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
- package/src/__tests__/config-watcher.test.ts +2 -2
- 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-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-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-slash-commands.test.ts +0 -4
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -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 +5 -12
- package/src/__tests__/cu-unified-flow.test.ts +185 -23
- package/src/__tests__/daemon-credential-client.test.ts +101 -19
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- 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-service.test.ts +718 -1
- package/src/__tests__/helpers/call-route-handler.ts +7 -1
- package/src/__tests__/host-app-control-proxy.test.ts +602 -0
- package/src/__tests__/host-app-control-routes.test.ts +263 -0
- package/src/__tests__/host-bash-proxy.test.ts +246 -47
- package/src/__tests__/host-bash-routes.test.ts +294 -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 +41 -52
- package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
- package/src/__tests__/host-file-edit-tool.test.ts +47 -1
- package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
- package/src/__tests__/host-file-proxy.test.ts +37 -43
- package/src/__tests__/host-file-read-tool.test.ts +17 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +262 -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 +583 -0
- package/src/__tests__/host-transfer-proxy.test.ts +121 -22
- package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- 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__/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-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/mcp-auth-routes.test.ts +197 -0
- package/src/__tests__/mcp-cli.test.ts +338 -2
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
- package/src/__tests__/migration-import-commit-http.test.ts +108 -2
- package/src/__tests__/mock-gateway-ipc.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +0 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
- package/src/__tests__/prechat-onboarding-contract.test.ts +3 -1
- 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__/public-ingress-urls.test.ts +97 -0
- 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 +10 -6
- package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
- package/src/__tests__/schedule-retry.test.ts +715 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- 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__/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-backfill-installation-id.test.ts +1 -5
- package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
- 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/bundler/app-bundler.ts +51 -3
- 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 -1
- package/src/cli/commands/backup.ts +6 -331
- package/src/cli/commands/clients.ts +36 -37
- package/src/cli/commands/contacts.ts +73 -0
- package/src/cli/commands/conversations.ts +2 -5
- package/src/cli/commands/credentials.ts +15 -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 +296 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
- package/src/cli/commands/platform/disconnect.ts +5 -4
- package/src/cli/commands/platform/index.ts +0 -18
- package/src/cli/lib/daemon-credential-client.ts +110 -28
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +67 -10
- 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/phone-calls/TOOLS.json +0 -12
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
- package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
- 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 -12
- package/src/config/feature-flag-registry.json +21 -133
- package/src/config/loader.ts +73 -99
- 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 +7 -4
- package/src/config/schemas/calls.ts +0 -9
- package/src/config/schemas/heartbeat.ts +63 -0
- package/src/config/schemas/ingress.ts +10 -6
- package/src/config/schemas/llm.ts +5 -10
- package/src/config/schemas/memory-lifecycle.ts +77 -24
- package/src/config/schemas/memory-v2.ts +48 -4
- package/src/config/schemas/platform.ts +6 -0
- package/src/config/schemas/services.ts +1 -15
- package/src/config/schemas/skills.ts +0 -6
- package/src/config/seed-inference-profiles.ts +1 -1
- package/src/contacts/contact-store.ts +0 -30
- 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 +126 -5
- package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
- package/src/daemon/config-watcher.ts +4 -3
- package/src/daemon/conversation-agent-loop-handlers.ts +21 -3
- package/src/daemon/conversation-agent-loop.ts +32 -28
- package/src/daemon/conversation-lifecycle.ts +8 -1
- package/src/daemon/conversation-process.ts +16 -11
- package/src/daemon/conversation-runtime-assembly.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +125 -4
- package/src/daemon/conversation-tool-setup.ts +16 -55
- package/src/daemon/conversation.ts +21 -2
- package/src/daemon/doordash-steps.ts +1 -1
- package/src/daemon/handlers/shared.ts +4 -1
- package/src/daemon/host-app-control-proxy.ts +293 -0
- package/src/daemon/host-bash-proxy.ts +84 -74
- package/src/daemon/host-browser-proxy.ts +67 -82
- package/src/daemon/host-cu-proxy.ts +81 -86
- package/src/daemon/host-file-proxy.ts +93 -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 +247 -129
- package/src/daemon/lifecycle.ts +115 -117
- package/src/daemon/message-protocol.ts +3 -8
- package/src/daemon/message-types/contacts.ts +23 -1
- package/src/daemon/message-types/conversations.ts +11 -8
- 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/schedules.ts +8 -3
- package/src/daemon/message-types/skills.ts +2 -2
- package/src/daemon/process-message.ts +18 -1
- 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/events/tool-audit-listener.ts +2 -1
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +15 -7
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
- package/src/heartbeat/heartbeat-run-store.ts +236 -0
- package/src/heartbeat/heartbeat-service.ts +280 -49
- 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/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/public-ingress-urls.ts +32 -34
- package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
- package/src/ipc/assistant-server.ts +14 -1
- package/src/ipc/cli-client.ts +32 -1
- package/src/live-voice/live-voice-metrics.ts +10 -10
- 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/memory/__tests__/jobs-store-job-classes.test.ts +24 -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/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 +32 -7
- package/src/memory/context-search/sources/memory-v2.ts +17 -5
- package/src/memory/conversation-crud.ts +1 -1
- package/src/memory/conversation-key-store.ts +2 -15
- package/src/memory/db-init.ts +4 -0
- package/src/memory/embedding-backend.ts +9 -21
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -4
- package/src/memory/graph/conversation-graph-memory.ts +1 -24
- package/src/memory/graph/graph-search.ts +8 -0
- package/src/memory/graph/retriever.ts +28 -0
- package/src/memory/graph/tools.ts +1 -1
- 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 +66 -22
- package/src/memory/jobs-worker.ts +112 -63
- package/src/memory/memory-v2-activation-log-store.ts +1 -1
- 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/index.ts +5 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-search.ts +7 -0
- package/src/memory/qdrant-client.ts +50 -20
- package/src/memory/schema/infrastructure.ts +15 -0
- package/src/memory/search/semantic.ts +7 -0
- package/src/memory/sparse-tokenize.ts +49 -0
- package/src/memory/v2/__tests__/activation.test.ts +77 -95
- package/src/memory/v2/__tests__/injection.test.ts +43 -21
- package/src/memory/v2/__tests__/sim.test.ts +166 -6
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/memory/v2/__tests__/static-context.test.ts +0 -1
- package/src/memory/v2/activation.ts +69 -88
- package/src/memory/v2/consolidation-job.ts +3 -5
- package/src/memory/v2/constants.ts +7 -0
- package/src/memory/v2/injection.ts +86 -53
- package/src/memory/v2/prompts/consolidation.ts +312 -91
- package/src/memory/v2/qdrant.ts +99 -1
- package/src/memory/v2/sim.ts +126 -16
- package/src/memory/v2/skill-qdrant.ts +12 -3
- package/src/memory/v2/skill-store.ts +16 -1
- package/src/memory/v2/sparse-bm25.ts +245 -0
- package/src/memory/v2/static-context.ts +6 -5
- 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/guardian-question-mode.ts +5 -5
- package/src/oauth/connect-orchestrator.ts +4 -0
- package/src/oauth/credential-token-resolver.ts +1 -3
- package/src/oauth/manual-token-connection.ts +0 -4
- 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/prompts/bootstrap-cleanup.ts +27 -0
- package/src/prompts/system-prompt.ts +3 -18
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/providers/speech-to-text/provider-catalog.ts +7 -8
- package/src/runtime/assistant-event-hub.ts +118 -96
- package/src/runtime/assistant-event.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
- package/src/runtime/auth/middleware.ts +0 -96
- package/src/runtime/auth/route-policy.ts +19 -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/http-server.ts +3 -329
- package/src/runtime/http-types.ts +0 -5
- 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 +35 -9
- package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- 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 +1 -0
- package/src/runtime/routes/contact-prompt-routes.ts +183 -0
- package/src/runtime/routes/conversation-query-routes.ts +36 -1
- package/src/runtime/routes/conversation-routes.ts +30 -13
- package/src/runtime/routes/document-pdf-renderer.ts +165 -0
- package/src/runtime/routes/documents-routes.ts +30 -0
- package/src/runtime/routes/errors.ts +19 -4
- package/src/runtime/routes/events-routes.ts +12 -6
- 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 +36 -6
- package/src/runtime/routes/host-browser-routes.ts +108 -13
- package/src/runtime/routes/host-cu-routes.ts +44 -14
- package/src/runtime/routes/host-file-routes.ts +33 -10
- package/src/runtime/routes/host-transfer-routes.ts +64 -24
- 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 +15 -43
- package/src/runtime/routes/inbound-message-handler.ts +1 -9
- 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/transcribe-audio.test.ts +0 -20
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/mcp-auth-routes.ts +132 -0
- package/src/runtime/routes/memory-item-routes.ts +10 -12
- package/src/runtime/routes/memory-v2-routes.ts +441 -1
- package/src/runtime/routes/migration-routes.ts +96 -0
- package/src/runtime/routes/schedule-routes.ts +7 -0
- 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/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 +63 -38
- package/src/security/oauth-callback-registry.ts +8 -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 +5 -5
- 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/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/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.ts +26 -0
- package/src/tools/host-filesystem/read.ts +26 -0
- package/src/tools/host-filesystem/transfer.ts +31 -1
- package/src/tools/host-filesystem/write.ts +26 -0
- package/src/tools/host-terminal/host-shell.ts +58 -0
- 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/tool-approval-handler.ts +1 -5
- package/src/tools/types.ts +4 -0
- package/src/usage/pricing.ts +1 -1
- package/src/workspace/hatched-date.ts +86 -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/AGENTS.md +1 -1
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
- package/src/workspace/migrations/utils.ts +21 -0
- 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/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/mcp-reload.ts +0 -18
|
@@ -8,6 +8,16 @@ import { z } from "zod";
|
|
|
8
8
|
|
|
9
9
|
import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
|
|
10
10
|
import { loadConfig } from "../../config/loader.js";
|
|
11
|
+
import {
|
|
12
|
+
applyCorrectionIfCalibrated,
|
|
13
|
+
explainedVarianceRatio,
|
|
14
|
+
fitAnisotropyCalibration,
|
|
15
|
+
saveCalibration,
|
|
16
|
+
} from "../../memory/anisotropy.js";
|
|
17
|
+
import {
|
|
18
|
+
embedWithBackend,
|
|
19
|
+
selectEmbeddingBackend,
|
|
20
|
+
} from "../../memory/embedding-backend.js";
|
|
11
21
|
import {
|
|
12
22
|
enqueueMemoryJob,
|
|
13
23
|
type MemoryJobType,
|
|
@@ -17,8 +27,22 @@ import {
|
|
|
17
27
|
totalEdgeCount,
|
|
18
28
|
validateEdgeTargets,
|
|
19
29
|
} from "../../memory/v2/edge-index.js";
|
|
20
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
listPages,
|
|
32
|
+
readPage,
|
|
33
|
+
renderPageContent,
|
|
34
|
+
} from "../../memory/v2/page-store.js";
|
|
35
|
+
import {
|
|
36
|
+
hybridQueryConceptPages,
|
|
37
|
+
sampleConceptPageDenseVectors,
|
|
38
|
+
} from "../../memory/v2/qdrant.js";
|
|
39
|
+
import { effectiveWeights } from "../../memory/v2/sim.js";
|
|
21
40
|
import { seedV2SkillEntries } from "../../memory/v2/skill-store.js";
|
|
41
|
+
import {
|
|
42
|
+
generateBm25QueryEmbedding,
|
|
43
|
+
getConceptPageCorpusStats,
|
|
44
|
+
rebuildConceptPageCorpusStats,
|
|
45
|
+
} from "../../memory/v2/sparse-bm25.js";
|
|
22
46
|
import { getWorkspaceDir } from "../../util/platform.js";
|
|
23
47
|
import { RouteError } from "./errors.js";
|
|
24
48
|
import type { RouteDefinition } from "./types.js";
|
|
@@ -113,6 +137,79 @@ async function handleValidate({
|
|
|
113
137
|
};
|
|
114
138
|
}
|
|
115
139
|
|
|
140
|
+
// ── Get concept page ────────────────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
const MemoryV2GetConceptPageParams = z
|
|
143
|
+
.object({
|
|
144
|
+
slug: z.string().min(1),
|
|
145
|
+
})
|
|
146
|
+
.strict();
|
|
147
|
+
|
|
148
|
+
export type MemoryV2GetConceptPageResult = {
|
|
149
|
+
slug: string;
|
|
150
|
+
/** Frontmatter + body, as produced by `renderPageContent`. */
|
|
151
|
+
rendered: string;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
async function handleGetConceptPage({
|
|
155
|
+
body = {},
|
|
156
|
+
}: RouteHandlerArgs): Promise<MemoryV2GetConceptPageResult> {
|
|
157
|
+
const { slug } = MemoryV2GetConceptPageParams.parse(body);
|
|
158
|
+
const workspaceDir = getWorkspaceDir();
|
|
159
|
+
let page;
|
|
160
|
+
try {
|
|
161
|
+
page = await readPage(workspaceDir, slug);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
throw new RouteError(
|
|
164
|
+
`Failed to read concept page '${slug}': ${err instanceof Error ? err.message : String(err)}`,
|
|
165
|
+
"MEMORY_V2_PAGE_READ_FAILED",
|
|
166
|
+
400,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
if (!page) {
|
|
170
|
+
throw new RouteError(
|
|
171
|
+
`Concept page '${slug}' not found on disk`,
|
|
172
|
+
"MEMORY_V2_PAGE_NOT_FOUND",
|
|
173
|
+
404,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
return { slug, rendered: renderPageContent(page) };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ── Rebuild BM25 corpus stats ───────────────────────────────────────────
|
|
180
|
+
|
|
181
|
+
const MemoryV2RebuildCorpusStatsParams = z.object({}).strict();
|
|
182
|
+
|
|
183
|
+
export interface MemoryV2RebuildCorpusStatsResult {
|
|
184
|
+
totalDocs: number;
|
|
185
|
+
avgDl: number;
|
|
186
|
+
/** Number of distinct hashed-token buckets that received any DF count. */
|
|
187
|
+
vocabularyBuckets: number;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function handleRebuildCorpusStats({
|
|
191
|
+
body = {},
|
|
192
|
+
}: RouteHandlerArgs): Promise<MemoryV2RebuildCorpusStatsResult> {
|
|
193
|
+
MemoryV2RebuildCorpusStatsParams.parse(body);
|
|
194
|
+
const workspaceDir = getWorkspaceDir();
|
|
195
|
+
await rebuildConceptPageCorpusStats(workspaceDir);
|
|
196
|
+
const stats = getConceptPageCorpusStats();
|
|
197
|
+
if (!stats) {
|
|
198
|
+
// The rebuild always swaps in a non-null table on success, so a missing
|
|
199
|
+
// value here means an unexpected reset between rebuild and read.
|
|
200
|
+
throw new RouteError(
|
|
201
|
+
"Corpus stats rebuild completed but no table is loaded",
|
|
202
|
+
"MEMORY_V2_CORPUS_STATS_MISSING",
|
|
203
|
+
500,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
totalDocs: stats.totalDocs,
|
|
208
|
+
avgDl: stats.avgDl,
|
|
209
|
+
vocabularyBuckets: stats.df.size,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
116
213
|
// ── Reembed skills ──────────────────────────────────────────────────────
|
|
117
214
|
|
|
118
215
|
const MemoryV2ReembedSkillsParams = z.object({}).strict();
|
|
@@ -149,6 +246,305 @@ async function handleReembedSkills({
|
|
|
149
246
|
return { success: true };
|
|
150
247
|
}
|
|
151
248
|
|
|
249
|
+
// ── Explain similarity ──────────────────────────────────────────────────
|
|
250
|
+
|
|
251
|
+
const MemoryV2ExplainSimilarityParams = z
|
|
252
|
+
.object({
|
|
253
|
+
userText: z.string().min(1),
|
|
254
|
+
assistantText: z.string().optional(),
|
|
255
|
+
nowText: z.string().optional(),
|
|
256
|
+
top: z.number().int().min(1).default(25),
|
|
257
|
+
})
|
|
258
|
+
.strict();
|
|
259
|
+
|
|
260
|
+
export interface MemoryV2ExplainSimilarityRow {
|
|
261
|
+
slug: string;
|
|
262
|
+
/** Raw dense cosine score, or null when the slug missed the dense channel. */
|
|
263
|
+
denseScore: number | null;
|
|
264
|
+
/** Raw sparse score (Qdrant scale), or null when the slug missed sparse. */
|
|
265
|
+
sparseRaw: number | null;
|
|
266
|
+
/** Sparse score divided by the per-batch max, in [0, 1]. */
|
|
267
|
+
sparseNorm: number | null;
|
|
268
|
+
/** `clamp01(dense_weight·dense + sparse_weight·sparseNorm)` — the simBatch fused value. */
|
|
269
|
+
fused: number;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface MemoryV2ExplainSimilarityStats {
|
|
273
|
+
count: number;
|
|
274
|
+
min: number;
|
|
275
|
+
max: number;
|
|
276
|
+
mean: number;
|
|
277
|
+
stddev: number;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export interface MemoryV2ExplainSimilarityChannel {
|
|
281
|
+
channel: "user" | "assistant" | "now";
|
|
282
|
+
textPreview: string;
|
|
283
|
+
maxSparse: number;
|
|
284
|
+
/**
|
|
285
|
+
* Spread (max - min) of normalized sparse scores across this channel's
|
|
286
|
+
* hits. Drives adaptive sparse weighting — low spread means the sparse
|
|
287
|
+
* channel can't discriminate, so its weight collapses for this query.
|
|
288
|
+
*/
|
|
289
|
+
sparseSpread: number;
|
|
290
|
+
/** Sparse weight after adaptive collapse (≤ the configured base). */
|
|
291
|
+
effectiveSparseWeight: number;
|
|
292
|
+
/** Dense weight after adaptive compensation (≥ the configured base). */
|
|
293
|
+
effectiveDenseWeight: number;
|
|
294
|
+
rows: MemoryV2ExplainSimilarityRow[];
|
|
295
|
+
stats: {
|
|
296
|
+
dense: MemoryV2ExplainSimilarityStats;
|
|
297
|
+
sparseRaw: MemoryV2ExplainSimilarityStats;
|
|
298
|
+
sparseNorm: MemoryV2ExplainSimilarityStats;
|
|
299
|
+
fused: MemoryV2ExplainSimilarityStats;
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export interface MemoryV2ExplainSimilarityResult {
|
|
304
|
+
config: {
|
|
305
|
+
dense_weight: number;
|
|
306
|
+
sparse_weight: number;
|
|
307
|
+
};
|
|
308
|
+
channels: MemoryV2ExplainSimilarityChannel[];
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function summarizeStats(values: number[]): MemoryV2ExplainSimilarityStats {
|
|
312
|
+
if (values.length === 0) {
|
|
313
|
+
return { count: 0, min: 0, max: 0, mean: 0, stddev: 0 };
|
|
314
|
+
}
|
|
315
|
+
let min = Infinity;
|
|
316
|
+
let max = -Infinity;
|
|
317
|
+
let sum = 0;
|
|
318
|
+
for (const v of values) {
|
|
319
|
+
if (v < min) min = v;
|
|
320
|
+
if (v > max) max = v;
|
|
321
|
+
sum += v;
|
|
322
|
+
}
|
|
323
|
+
const mean = sum / values.length;
|
|
324
|
+
let sqDiff = 0;
|
|
325
|
+
for (const v of values) sqDiff += (v - mean) * (v - mean);
|
|
326
|
+
const stddev = Math.sqrt(sqDiff / values.length);
|
|
327
|
+
return { count: values.length, min, max, mean, stddev };
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async function scoreChannel(
|
|
331
|
+
channel: "user" | "assistant" | "now",
|
|
332
|
+
text: string,
|
|
333
|
+
top: number,
|
|
334
|
+
denseWeight: number,
|
|
335
|
+
sparseWeight: number,
|
|
336
|
+
config: ReturnType<typeof loadConfig>,
|
|
337
|
+
): Promise<MemoryV2ExplainSimilarityChannel> {
|
|
338
|
+
const denseResult = await embedWithBackend(config, [text]);
|
|
339
|
+
const denseVec = await applyCorrectionIfCalibrated(
|
|
340
|
+
denseResult.vectors[0],
|
|
341
|
+
denseResult.provider,
|
|
342
|
+
denseResult.model,
|
|
343
|
+
);
|
|
344
|
+
const sparseVec = generateBm25QueryEmbedding(text);
|
|
345
|
+
|
|
346
|
+
const hits = await hybridQueryConceptPages(denseVec, sparseVec, top);
|
|
347
|
+
|
|
348
|
+
let maxSparse = 0;
|
|
349
|
+
for (const hit of hits) {
|
|
350
|
+
if (hit.sparseScore !== undefined && hit.sparseScore > maxSparse) {
|
|
351
|
+
maxSparse = hit.sparseScore;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Mirror simBatch's adaptive weighting so the printed `fused` matches what
|
|
356
|
+
// production retrieval would actually score for this query — otherwise
|
|
357
|
+
// operators staring at the diagnostic would see different numbers than
|
|
358
|
+
// the activation pipeline saw.
|
|
359
|
+
const {
|
|
360
|
+
dense: effDense,
|
|
361
|
+
sparse: effSparse,
|
|
362
|
+
spread: sparseSpread,
|
|
363
|
+
} = effectiveWeights(hits, maxSparse, denseWeight, sparseWeight, config);
|
|
364
|
+
|
|
365
|
+
const rows: MemoryV2ExplainSimilarityRow[] = hits.map((hit) => {
|
|
366
|
+
const dense = hit.denseScore ?? 0;
|
|
367
|
+
const sparseNorm =
|
|
368
|
+
hit.sparseScore !== undefined && maxSparse > 0
|
|
369
|
+
? hit.sparseScore / maxSparse
|
|
370
|
+
: 0;
|
|
371
|
+
const fusedRaw = effDense * dense + effSparse * sparseNorm;
|
|
372
|
+
const fused = Math.max(0, Math.min(1, fusedRaw));
|
|
373
|
+
return {
|
|
374
|
+
slug: hit.slug,
|
|
375
|
+
denseScore: hit.denseScore ?? null,
|
|
376
|
+
sparseRaw: hit.sparseScore ?? null,
|
|
377
|
+
sparseNorm: hit.sparseScore !== undefined ? sparseNorm : null,
|
|
378
|
+
fused,
|
|
379
|
+
};
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
rows.sort((a, b) => b.fused - a.fused);
|
|
383
|
+
|
|
384
|
+
const denseValues: number[] = [];
|
|
385
|
+
const sparseRawValues: number[] = [];
|
|
386
|
+
const sparseNormValues: number[] = [];
|
|
387
|
+
const fusedValues: number[] = [];
|
|
388
|
+
for (const row of rows) {
|
|
389
|
+
if (row.denseScore !== null) denseValues.push(row.denseScore);
|
|
390
|
+
if (row.sparseRaw !== null) sparseRawValues.push(row.sparseRaw);
|
|
391
|
+
if (row.sparseNorm !== null) sparseNormValues.push(row.sparseNorm);
|
|
392
|
+
fusedValues.push(row.fused);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
channel,
|
|
397
|
+
textPreview: text.length > 120 ? `${text.slice(0, 120)}…` : text,
|
|
398
|
+
maxSparse,
|
|
399
|
+
sparseSpread,
|
|
400
|
+
effectiveSparseWeight: effSparse,
|
|
401
|
+
effectiveDenseWeight: effDense,
|
|
402
|
+
rows,
|
|
403
|
+
stats: {
|
|
404
|
+
dense: summarizeStats(denseValues),
|
|
405
|
+
sparseRaw: summarizeStats(sparseRawValues),
|
|
406
|
+
sparseNorm: summarizeStats(sparseNormValues),
|
|
407
|
+
fused: summarizeStats(fusedValues),
|
|
408
|
+
},
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
async function handleExplainSimilarity({
|
|
413
|
+
body = {},
|
|
414
|
+
}: RouteHandlerArgs): Promise<MemoryV2ExplainSimilarityResult> {
|
|
415
|
+
const params = MemoryV2ExplainSimilarityParams.parse(body);
|
|
416
|
+
const config = loadConfig();
|
|
417
|
+
const { dense_weight: denseWeight, sparse_weight: sparseWeight } =
|
|
418
|
+
config.memory.v2;
|
|
419
|
+
|
|
420
|
+
const channels: MemoryV2ExplainSimilarityChannel[] = [];
|
|
421
|
+
channels.push(
|
|
422
|
+
await scoreChannel(
|
|
423
|
+
"user",
|
|
424
|
+
params.userText,
|
|
425
|
+
params.top,
|
|
426
|
+
denseWeight,
|
|
427
|
+
sparseWeight,
|
|
428
|
+
config,
|
|
429
|
+
),
|
|
430
|
+
);
|
|
431
|
+
if (params.assistantText && params.assistantText.length > 0) {
|
|
432
|
+
channels.push(
|
|
433
|
+
await scoreChannel(
|
|
434
|
+
"assistant",
|
|
435
|
+
params.assistantText,
|
|
436
|
+
params.top,
|
|
437
|
+
denseWeight,
|
|
438
|
+
sparseWeight,
|
|
439
|
+
config,
|
|
440
|
+
),
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
if (params.nowText && params.nowText.length > 0) {
|
|
444
|
+
channels.push(
|
|
445
|
+
await scoreChannel(
|
|
446
|
+
"now",
|
|
447
|
+
params.nowText,
|
|
448
|
+
params.top,
|
|
449
|
+
denseWeight,
|
|
450
|
+
sparseWeight,
|
|
451
|
+
config,
|
|
452
|
+
),
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return {
|
|
457
|
+
config: { dense_weight: denseWeight, sparse_weight: sparseWeight },
|
|
458
|
+
channels,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// ── Fit anisotropy calibration ──────────────────────────────────────────
|
|
463
|
+
|
|
464
|
+
const MemoryV2FitAnisotropyParams = z
|
|
465
|
+
.object({
|
|
466
|
+
/**
|
|
467
|
+
* Number of leading principal components to project out at apply time.
|
|
468
|
+
* `1` is the canonical default for transformer embeddings; raise to 2-3
|
|
469
|
+
* only when the variance spectrum shows multiple dominant directions.
|
|
470
|
+
*/
|
|
471
|
+
k: z.number().int().min(1).max(16).default(1),
|
|
472
|
+
/**
|
|
473
|
+
* Maximum number of stored vectors to pull from Qdrant for the fit.
|
|
474
|
+
* 5_000 is plenty for 3072-dim Gemini — power iteration converges fast
|
|
475
|
+
* and pulling the full corpus would just cost wall-clock time.
|
|
476
|
+
*/
|
|
477
|
+
sample: z.number().int().min(1).max(100_000).default(5_000),
|
|
478
|
+
})
|
|
479
|
+
.strict();
|
|
480
|
+
|
|
481
|
+
export interface MemoryV2FitAnisotropyResult {
|
|
482
|
+
provider: string;
|
|
483
|
+
model: string;
|
|
484
|
+
dim: number;
|
|
485
|
+
k: number;
|
|
486
|
+
sampleCount: number;
|
|
487
|
+
totalVariance: number;
|
|
488
|
+
componentVariance: number[];
|
|
489
|
+
/** `componentVariance[i] / totalVariance` for each component. */
|
|
490
|
+
explainedVarianceRatio: number[];
|
|
491
|
+
/** Absolute path the calibration was written to. */
|
|
492
|
+
path: string;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
async function handleFitAnisotropy({
|
|
496
|
+
body = {},
|
|
497
|
+
}: RouteHandlerArgs): Promise<MemoryV2FitAnisotropyResult> {
|
|
498
|
+
const { k, sample } = MemoryV2FitAnisotropyParams.parse(body);
|
|
499
|
+
const config = loadConfig();
|
|
500
|
+
|
|
501
|
+
const selection = await selectEmbeddingBackend(config);
|
|
502
|
+
if (!selection.backend) {
|
|
503
|
+
throw new RouteError(
|
|
504
|
+
`Cannot fit anisotropy calibration: ${selection.reason ?? "no embedding backend configured"}`,
|
|
505
|
+
"MEMORY_V2_NO_EMBEDDING_BACKEND",
|
|
506
|
+
409,
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const vectors = await sampleConceptPageDenseVectors(sample);
|
|
511
|
+
if (vectors.length === 0) {
|
|
512
|
+
throw new RouteError(
|
|
513
|
+
"Cannot fit anisotropy calibration: the v2 concept-page collection is empty. " +
|
|
514
|
+
"Embed some concept pages first (run `assistant memory v2 reembed`), then retry.",
|
|
515
|
+
"MEMORY_V2_NO_VECTORS",
|
|
516
|
+
409,
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
if (vectors.length < k * 4) {
|
|
520
|
+
// PCA on too-few samples is unstable — refuse rather than hand back
|
|
521
|
+
// overfit components. The 4× heuristic is conservative; in practice
|
|
522
|
+
// anisotropy fits stabilise at a few hundred samples per component.
|
|
523
|
+
throw new RouteError(
|
|
524
|
+
`Cannot fit k=${k} components from only ${vectors.length} vectors — need at least ${k * 4}. ` +
|
|
525
|
+
"Embed more concept pages or fit a smaller k.",
|
|
526
|
+
"MEMORY_V2_INSUFFICIENT_VECTORS",
|
|
527
|
+
409,
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const { provider, model } = selection.backend;
|
|
532
|
+
const calib = fitAnisotropyCalibration(vectors, k, { provider, model });
|
|
533
|
+
const path = await saveCalibration(calib);
|
|
534
|
+
|
|
535
|
+
return {
|
|
536
|
+
provider,
|
|
537
|
+
model,
|
|
538
|
+
dim: calib.dim,
|
|
539
|
+
k,
|
|
540
|
+
sampleCount: calib.sampleCount,
|
|
541
|
+
totalVariance: calib.totalVariance,
|
|
542
|
+
componentVariance: calib.componentVariance,
|
|
543
|
+
explainedVarianceRatio: explainedVarianceRatio(calib),
|
|
544
|
+
path,
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
152
548
|
// ── Route definitions ───────────────────────────────────────────────────
|
|
153
549
|
|
|
154
550
|
export const ROUTES: RouteDefinition[] = [
|
|
@@ -174,6 +570,17 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
174
570
|
tags: ["memory"],
|
|
175
571
|
requestBody: MemoryV2ValidateParams,
|
|
176
572
|
},
|
|
573
|
+
{
|
|
574
|
+
operationId: "memory_v2_get_concept_page",
|
|
575
|
+
method: "POST",
|
|
576
|
+
endpoint: "memory/v2/concept-page",
|
|
577
|
+
handler: handleGetConceptPage,
|
|
578
|
+
summary: "Read a single memory v2 concept page",
|
|
579
|
+
description:
|
|
580
|
+
"Returns the rendered (frontmatter + body) markdown for a slug. 404 when the slug has no on-disk page — the activation log inspector uses this to show what got injected.",
|
|
581
|
+
tags: ["memory"],
|
|
582
|
+
requestBody: MemoryV2GetConceptPageParams,
|
|
583
|
+
},
|
|
177
584
|
{
|
|
178
585
|
operationId: "memory_v2_reembed_skills",
|
|
179
586
|
method: "POST",
|
|
@@ -185,4 +592,37 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
185
592
|
tags: ["memory"],
|
|
186
593
|
requestBody: MemoryV2ReembedSkillsParams,
|
|
187
594
|
},
|
|
595
|
+
{
|
|
596
|
+
operationId: "memory_v2_explain_similarity",
|
|
597
|
+
method: "POST",
|
|
598
|
+
endpoint: "memory/v2/explain-similarity",
|
|
599
|
+
handler: handleExplainSimilarity,
|
|
600
|
+
summary: "Diagnose dense vs sparse similarity score distributions",
|
|
601
|
+
description:
|
|
602
|
+
"Read-only diagnostic. Embeds the supplied text(s), runs hybrid dense + sparse queries against the concept-page collection, and returns per-slug raw dense, raw sparse, normalized sparse, and fused scores plus per-channel summary stats. Used to investigate score-compression at the head of the activation distribution.",
|
|
603
|
+
tags: ["memory"],
|
|
604
|
+
requestBody: MemoryV2ExplainSimilarityParams,
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
operationId: "memory_v2_rebuild_corpus_stats",
|
|
608
|
+
method: "POST",
|
|
609
|
+
endpoint: "memory/v2/rebuild-corpus-stats",
|
|
610
|
+
handler: handleRebuildCorpusStats,
|
|
611
|
+
summary: "Rebuild the BM25 corpus statistics for memory v2",
|
|
612
|
+
description:
|
|
613
|
+
"Walks every concept page on disk, recomputes the document-frequency table and average document length used by the BM25 sparse channel, and atomically swaps the in-memory stats. Run after bulk content imports or to recover from a rebuild that errored at startup. Does not reembed individual page sparse vectors — pair with `assistant memory v2 reembed` when document-side weights need refreshing.",
|
|
614
|
+
tags: ["memory"],
|
|
615
|
+
requestBody: MemoryV2RebuildCorpusStatsParams,
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
operationId: "memory_v2_fit_anisotropy",
|
|
619
|
+
method: "POST",
|
|
620
|
+
endpoint: "memory/v2/fit-anisotropy",
|
|
621
|
+
handler: handleFitAnisotropy,
|
|
622
|
+
summary: "Fit the embedding anisotropy correction for memory v2",
|
|
623
|
+
description:
|
|
624
|
+
"Samples stored dense vectors from the concept-page Qdrant collection, fits a corpus mean + top-k principal components (Mu & Viswanath 'all-but-the-top'), and persists the calibration so subsequent embeds and queries apply the correction. Run `assistant memory v2 reembed` after fitting so stored vectors are written under the new calibration — until then, queries (corrected) and stored vectors (uncorrected) live in different spaces.",
|
|
625
|
+
tags: ["memory"],
|
|
626
|
+
requestBody: MemoryV2FitAnisotropyParams,
|
|
627
|
+
},
|
|
188
628
|
];
|
|
@@ -65,6 +65,11 @@ import {
|
|
|
65
65
|
analyzeImport,
|
|
66
66
|
DefaultPathResolver,
|
|
67
67
|
} from "../migrations/vbundle-import-analyzer.js";
|
|
68
|
+
import {
|
|
69
|
+
evaluateRuntimeCompatibility,
|
|
70
|
+
formatRuntimeCompatibilityMessage,
|
|
71
|
+
type RuntimeCompatibility,
|
|
72
|
+
} from "../migrations/vbundle-import-policy.js";
|
|
68
73
|
import {
|
|
69
74
|
commitImport,
|
|
70
75
|
extractCredentialsFromBundle,
|
|
@@ -79,6 +84,7 @@ import {
|
|
|
79
84
|
InternalError,
|
|
80
85
|
NotFoundError,
|
|
81
86
|
RouteError,
|
|
87
|
+
UnprocessableEntityError,
|
|
82
88
|
} from "./errors.js";
|
|
83
89
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
84
90
|
import { RouteResponse } from "./types.js";
|
|
@@ -866,6 +872,23 @@ export async function handleMigrationImport(
|
|
|
866
872
|
};
|
|
867
873
|
}
|
|
868
874
|
|
|
875
|
+
// Pre-check runtime-version compat before the DB close/reopen cycle.
|
|
876
|
+
// commitImport runs the same gate as defense-in-depth for callers that
|
|
877
|
+
// don't pre-check; we run it here too so an incompatible bundle short-
|
|
878
|
+
// circuits before resetDb().
|
|
879
|
+
const compatResult = evaluateRuntimeCompatibility(
|
|
880
|
+
validation.manifest!.compatibility,
|
|
881
|
+
APP_VERSION,
|
|
882
|
+
);
|
|
883
|
+
if (!compatResult.ok) {
|
|
884
|
+
throwImportCommitFailure({
|
|
885
|
+
ok: false,
|
|
886
|
+
reason: "version_incompatible",
|
|
887
|
+
bundle_compat: compatResult.bundle_compat,
|
|
888
|
+
runtime_version: compatResult.runtime_version,
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
|
|
869
892
|
const pathResolver = new DefaultPathResolver(
|
|
870
893
|
getWorkspaceDir(),
|
|
871
894
|
getWorkspaceHooksDir(),
|
|
@@ -918,6 +941,12 @@ export async function handleMigrationImport(
|
|
|
918
941
|
|
|
919
942
|
return importCommitSuccessResult(result.report, credentialsImported);
|
|
920
943
|
} catch (err) {
|
|
944
|
+
// Preserve typed RouteError instances (e.g. UnprocessableEntityError for
|
|
945
|
+
// version_incompatible, BadRequestError for validation_failed) — only
|
|
946
|
+
// wrap genuinely unexpected errors as 500 InternalError.
|
|
947
|
+
if (err instanceof RouteError) {
|
|
948
|
+
throw err;
|
|
949
|
+
}
|
|
921
950
|
log.error({ err }, "Unexpected error during import commit");
|
|
922
951
|
throw new InternalError(
|
|
923
952
|
err instanceof Error ? err.message : "Unexpected import error",
|
|
@@ -1014,12 +1043,18 @@ interface GcsImportErrorInit {
|
|
|
1014
1043
|
| "fetch_failed"
|
|
1015
1044
|
| "validation_failed"
|
|
1016
1045
|
| "extraction_failed"
|
|
1046
|
+
| "version_incompatible"
|
|
1017
1047
|
| "write_failed";
|
|
1018
1048
|
message: string;
|
|
1019
1049
|
upstreamStatus?: number;
|
|
1020
1050
|
reason?: string;
|
|
1021
1051
|
errors?: Array<{ code: string; message: string; path?: string }>;
|
|
1022
1052
|
partial_report?: ImportCommitReport;
|
|
1053
|
+
/** Populated for `version_incompatible` — mirrors the platform's PR #5470
|
|
1054
|
+
* response shape so the URL-body endpoint can return the same body. */
|
|
1055
|
+
bundle_compat?: RuntimeCompatibility;
|
|
1056
|
+
/** Populated for `version_incompatible`. */
|
|
1057
|
+
runtime_version?: string;
|
|
1023
1058
|
}
|
|
1024
1059
|
|
|
1025
1060
|
class GcsImportError extends Error {
|
|
@@ -1028,6 +1063,8 @@ class GcsImportError extends Error {
|
|
|
1028
1063
|
public readonly reason?: string;
|
|
1029
1064
|
public readonly errors?: GcsImportErrorInit["errors"];
|
|
1030
1065
|
public readonly partial_report?: ImportCommitReport;
|
|
1066
|
+
public readonly bundle_compat?: RuntimeCompatibility;
|
|
1067
|
+
public readonly runtime_version?: string;
|
|
1031
1068
|
|
|
1032
1069
|
constructor(init: GcsImportErrorInit) {
|
|
1033
1070
|
super(init.message);
|
|
@@ -1045,6 +1082,12 @@ class GcsImportError extends Error {
|
|
|
1045
1082
|
if (init.partial_report !== undefined) {
|
|
1046
1083
|
this.partial_report = init.partial_report;
|
|
1047
1084
|
}
|
|
1085
|
+
if (init.bundle_compat !== undefined) {
|
|
1086
|
+
this.bundle_compat = init.bundle_compat;
|
|
1087
|
+
}
|
|
1088
|
+
if (init.runtime_version !== undefined) {
|
|
1089
|
+
this.runtime_version = init.runtime_version;
|
|
1090
|
+
}
|
|
1048
1091
|
}
|
|
1049
1092
|
}
|
|
1050
1093
|
|
|
@@ -1343,6 +1386,22 @@ async function runGcsImport(
|
|
|
1343
1386
|
reason: result.reason,
|
|
1344
1387
|
});
|
|
1345
1388
|
}
|
|
1389
|
+
if (result.reason === "version_incompatible") {
|
|
1390
|
+
// Returned by commitImport / streamCommitImport when the runtime falls
|
|
1391
|
+
// outside the bundle's compat range. The platform-side gate is the
|
|
1392
|
+
// primary check; this catches legacy bundles whose ExportJob row
|
|
1393
|
+
// predates PR #5470 (compat columns NULL → platform gate skipped).
|
|
1394
|
+
throw new GcsImportError({
|
|
1395
|
+
code: "version_incompatible",
|
|
1396
|
+
message: formatRuntimeCompatibilityMessage(
|
|
1397
|
+
result.bundle_compat,
|
|
1398
|
+
result.runtime_version,
|
|
1399
|
+
),
|
|
1400
|
+
reason: result.reason,
|
|
1401
|
+
bundle_compat: result.bundle_compat,
|
|
1402
|
+
runtime_version: result.runtime_version,
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1346
1405
|
// write_failed
|
|
1347
1406
|
throw new GcsImportError({
|
|
1348
1407
|
code: "write_failed",
|
|
@@ -1442,6 +1501,20 @@ function throwGcsImportError(err: unknown): never {
|
|
|
1442
1501
|
}),
|
|
1443
1502
|
);
|
|
1444
1503
|
}
|
|
1504
|
+
if (err.code === "version_incompatible") {
|
|
1505
|
+
// 422 (not 500) — the bundle is structurally valid but cannot be
|
|
1506
|
+
// imported on this runtime. Body mirrors the platform's PR #5470
|
|
1507
|
+
// response shape.
|
|
1508
|
+
throw new UnprocessableEntityError(err.message, {
|
|
1509
|
+
reason: "version_incompatible" as const,
|
|
1510
|
+
...(err.bundle_compat !== undefined && {
|
|
1511
|
+
bundle_compat: err.bundle_compat,
|
|
1512
|
+
}),
|
|
1513
|
+
...(err.runtime_version !== undefined && {
|
|
1514
|
+
runtime_version: err.runtime_version,
|
|
1515
|
+
}),
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1445
1518
|
if (err.code === "extraction_failed") {
|
|
1446
1519
|
throw new InternalError(err.message);
|
|
1447
1520
|
}
|
|
@@ -1674,6 +1747,29 @@ function throwImportCommitFailure(
|
|
|
1674
1747
|
throw new InternalError(result.message);
|
|
1675
1748
|
}
|
|
1676
1749
|
|
|
1750
|
+
if (result.reason === "version_incompatible") {
|
|
1751
|
+
// Returned by commitImport / streamCommitImport when the runtime falls
|
|
1752
|
+
// outside the bundle's compat range. The platform-side gate is the
|
|
1753
|
+
// primary check; this catches legacy bundles whose ExportJob row
|
|
1754
|
+
// predates PR #5470 (compat columns NULL → platform gate skipped).
|
|
1755
|
+
//
|
|
1756
|
+
// 422 (not 500) — the bundle is structurally valid but cannot be
|
|
1757
|
+
// imported on this runtime; the caller can act on it (upgrade the
|
|
1758
|
+
// runtime, choose a different bundle). Body mirrors the platform's
|
|
1759
|
+
// PR #5470 response shape.
|
|
1760
|
+
throw new UnprocessableEntityError(
|
|
1761
|
+
formatRuntimeCompatibilityMessage(
|
|
1762
|
+
result.bundle_compat,
|
|
1763
|
+
result.runtime_version,
|
|
1764
|
+
),
|
|
1765
|
+
{
|
|
1766
|
+
reason: "version_incompatible" as const,
|
|
1767
|
+
bundle_compat: result.bundle_compat,
|
|
1768
|
+
runtime_version: result.runtime_version,
|
|
1769
|
+
},
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1677
1773
|
// write_failed
|
|
1678
1774
|
throw new InternalError(result.message);
|
|
1679
1775
|
}
|
|
@@ -54,6 +54,9 @@ function handleListSchedules(queryParams: Record<string, string>) {
|
|
|
54
54
|
nextRunAt: j.nextRunAt,
|
|
55
55
|
lastRunAt: j.lastRunAt,
|
|
56
56
|
lastStatus: j.lastStatus,
|
|
57
|
+
retryCount: j.retryCount,
|
|
58
|
+
maxRetries: j.maxRetries,
|
|
59
|
+
retryBackoffMs: j.retryBackoffMs,
|
|
57
60
|
description:
|
|
58
61
|
j.syntax === "cron"
|
|
59
62
|
? describeCronExpression(j.cronExpression)
|
|
@@ -139,6 +142,8 @@ function handleUpdateSchedule(id: string, body: Record<string, unknown>) {
|
|
|
139
142
|
"quiet",
|
|
140
143
|
"reuseConversation",
|
|
141
144
|
"wakeConversationId",
|
|
145
|
+
"maxRetries",
|
|
146
|
+
"retryBackoffMs",
|
|
142
147
|
] as const) {
|
|
143
148
|
if (key in body) {
|
|
144
149
|
updates[key] = body[key];
|
|
@@ -294,6 +299,8 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
294
299
|
.describe("single_channel, multi_channel, or all_channels"),
|
|
295
300
|
quiet: z.boolean(),
|
|
296
301
|
reuseConversation: z.boolean(),
|
|
302
|
+
maxRetries: z.number().describe("Maximum retry attempts"),
|
|
303
|
+
retryBackoffMs: z.number().describe("Retry backoff in milliseconds"),
|
|
297
304
|
}),
|
|
298
305
|
responseBody: z.object({
|
|
299
306
|
schedules: z.array(z.unknown()).describe("Updated schedule list"),
|