@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091853.fbaa2ae
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +6 -6
- package/bun.lock +2 -2
- package/docs/activation-funnel-telemetry.md +310 -0
- package/examples/plugins/echo/README.md +61 -60
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +263 -121
- package/package.json +2 -2
- package/src/__tests__/activation-early-marking.test.ts +120 -0
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
- package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
- package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
- package/src/__tests__/agent-loop-thinking.test.ts +36 -20
- package/src/__tests__/agent-loop.test.ts +441 -96
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
- package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
- package/src/__tests__/anthropic-provider.test.ts +23 -8
- package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +132 -0
- package/src/__tests__/approval-cascade.test.ts +6 -5
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +146 -0
- package/src/__tests__/compaction-events.test.ts +7 -7
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
- package/src/__tests__/context-overflow-reducer.test.ts +265 -125
- package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
- package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
- package/src/__tests__/conversation-agent-loop.test.ts +342 -623
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
- package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
- package/src/__tests__/conversation-error.test.ts +15 -1
- package/src/__tests__/conversation-history-web-search.test.ts +6 -1
- package/src/__tests__/conversation-media-retry.test.ts +1 -1
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
- package/src/__tests__/conversation-process-callsite.test.ts +15 -15
- package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
- package/src/__tests__/conversation-queue.test.ts +10 -10
- package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
- package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
- package/src/__tests__/conversation-slash-queue.test.ts +7 -5
- package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
- package/src/__tests__/conversation-speed-override.test.ts +11 -10
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
- package/src/__tests__/conversation-undo.test.ts +2 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
- package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/corrected-target.test.ts +93 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +36 -0
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +1 -1
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +17 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/history-repair-hook.test.ts +5 -1
- package/src/__tests__/host-app-control-proxy.test.ts +45 -0
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/inference-profile-reaper.test.ts +62 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
- package/src/__tests__/injector-background-turn.test.ts +13 -23
- package/src/__tests__/injector-chain.test.ts +268 -44
- package/src/__tests__/injector-disk-pressure.test.ts +210 -52
- package/src/__tests__/injector-document-comments.test.ts +97 -114
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
- package/src/__tests__/injector-v3-suppression.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/llm-resolver.test.ts +73 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
- package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
- package/src/__tests__/notification-decision-strategy.test.ts +3 -3
- package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
- package/src/__tests__/persist-unsendable-image.test.ts +97 -1
- package/src/__tests__/plugin-api-shim.test.ts +6 -9
- package/src/__tests__/plugin-bootstrap.test.ts +91 -81
- package/src/__tests__/plugin-registry.test.ts +3 -49
- package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
- package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
- package/src/__tests__/plugin-types.test.ts +0 -70
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
- package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
- package/src/__tests__/published-app-updater.test.ts +138 -0
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
- package/src/__tests__/steer-tool-repair.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-detail.test.ts +25 -7
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +5 -1
- package/src/__tests__/tool-error-hook.test.ts +1 -1
- package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/__tests__/web-fetch.test.ts +45 -0
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +280 -0
- package/src/acp/auto-install.ts +232 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/prepare-agent-env.ts +80 -27
- package/src/acp/resolve-agent.test.ts +188 -28
- package/src/acp/resolve-agent.ts +119 -42
- package/src/acp/resume-hint.ts +23 -0
- package/src/acp/session-manager.ts +507 -73
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +403 -251
- package/src/api/responses/conversation-message.ts +22 -2
- package/src/api/responses/memory-v3-selection-log.ts +19 -10
- package/src/approvals/guardian-request-resolvers.ts +27 -1
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
- package/src/cli/commands/channel-verification-sessions.ts +6 -6
- package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
- package/src/cli/commands/memory-v3.ts +57 -199
- package/src/cli/commands/plugins.ts +43 -37
- package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
- package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
- package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
- package/src/cli/lib/install-from-github.ts +797 -60
- package/src/cli/lib/plugin-catalog-cache.ts +84 -0
- package/src/cli/lib/plugin-details.ts +416 -0
- package/src/cli/lib/plugin-marketplace.ts +215 -0
- package/src/cli/lib/search-plugins.ts +201 -29
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +9 -3
- package/src/config/acp-schema.ts +1 -7
- package/src/config/bundled-skills/acp/SKILL.md +80 -41
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
- package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +4 -0
- package/src/config/call-site-defaults.ts +0 -3
- package/src/config/feature-flag-registry.json +10 -16
- package/src/config/llm-resolver.ts +39 -7
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
- package/src/config/schemas/call-site-catalog.ts +0 -21
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +17 -3
- package/src/config/schemas/memory-v3.ts +58 -8
- package/src/config/seed-inference-profiles.ts +18 -0
- package/src/context/compactor.ts +22 -4
- package/src/context/post-turn-tool-result-truncation.ts +39 -1
- package/src/context/strip-injections.ts +8 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +18 -36
- package/src/daemon/conversation-agent-loop.ts +308 -1297
- package/src/daemon/conversation-error.ts +31 -4
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +11 -255
- package/src/daemon/conversation-media-retry.ts +19 -6
- package/src/daemon/conversation-messaging.ts +17 -0
- package/src/daemon/conversation-process.ts +22 -141
- package/src/daemon/conversation-queue-manager.ts +8 -0
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +361 -393
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +165 -11
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +444 -62
- package/src/daemon/disk-pressure-policy.ts +0 -1
- package/src/daemon/external-plugins-bootstrap.ts +36 -46
- package/src/daemon/handlers/config-channels.ts +11 -2
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-app-control-proxy.ts +72 -57
- package/src/daemon/host-proxy-preactivation.ts +1 -3
- package/src/daemon/lifecycle.ts +21 -7
- package/src/daemon/persist-unsendable-image.ts +62 -25
- package/src/daemon/process-message.ts +1 -1
- package/src/daemon/server.ts +2 -0
- package/src/daemon/tool-side-effects.ts +15 -0
- package/src/daemon/wake-conversation-ops.ts +269 -0
- package/src/embedded/plugin-api.ts +2 -2
- package/src/export/__tests__/transcript-formatter.test.ts +5 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- package/src/memory/__tests__/activation-session-store.test.ts +41 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
- package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
- package/src/memory/activation-session-store.ts +43 -0
- package/src/memory/conversation-crud.ts +29 -19
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/db-init.ts +6 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
- package/src/memory/jobs-worker.ts +25 -1
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
- package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/onboarding-events-store.ts +66 -18
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +13 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
- package/src/memory/v2/__tests__/page-store.test.ts +22 -0
- package/src/memory/v2/consolidation-job.ts +2 -63
- package/src/memory/v2/types.ts +5 -0
- package/src/messaging/providers/telegram-bot/api.ts +14 -5
- package/src/notifications/__tests__/copy-composer.test.ts +244 -0
- package/src/notifications/access-request-copy.ts +298 -0
- package/src/notifications/adapters/slack.ts +3 -3
- package/src/notifications/adapters/telegram.ts +9 -2
- package/src/notifications/copy-composer.ts +49 -267
- package/src/notifications/decision-engine.ts +16 -35
- package/src/notifications/home-feed-side-effect.ts +1 -6
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +40 -11
- package/src/plugin-api/types.ts +108 -0
- package/src/plugins/defaults/compaction/compact.ts +106 -0
- package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
- package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
- package/src/plugins/defaults/compaction/manager-store.ts +57 -0
- package/src/plugins/defaults/compaction/package.json +1 -2
- package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
- package/src/plugins/defaults/empty-response/package.json +0 -1
- package/src/plugins/defaults/history-repair/package.json +0 -1
- package/src/plugins/defaults/index.ts +156 -26
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
- package/src/plugins/defaults/memory-retrieval/package.json +14 -0
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
- package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
- package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
- package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
- package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
- package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
- package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
- package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
- package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
- package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
- package/src/plugins/defaults/title-generate/package.json +0 -1
- package/src/plugins/defaults/tool-error/package.json +0 -1
- package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
- package/src/plugins/external-api.ts +12 -2
- package/src/plugins/pipeline.ts +6 -293
- package/src/plugins/registry.ts +9 -37
- package/src/plugins/types.ts +76 -381
- package/src/plugins/user-loader.ts +30 -127
- package/src/prompts/__tests__/system-prompt.test.ts +6 -0
- package/src/prompts/system-prompt.ts +61 -10
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
- package/src/providers/anthropic/client.ts +9 -10
- package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
- package/src/providers/inference/logit-bias.ts +55 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -1
- package/src/providers/retry.ts +22 -0
- package/src/providers/types.ts +6 -0
- package/src/runtime/__tests__/agent-wake.test.ts +555 -691
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +108 -209
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
- package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/acp-routes.test.ts +185 -32
- package/src/runtime/routes/acp-routes.ts +328 -30
- package/src/runtime/routes/app-management-routes.ts +3 -0
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/channel-verification-routes.ts +14 -5
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +30 -2
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +18 -3
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
- package/src/runtime/routes/memory-v3-routes.ts +65 -305
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +337 -35
- package/src/runtime/routes/stt-routes.ts +45 -12
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/routes/workspace-routes.ts +50 -15
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/runtime/verification-outbound-actions.ts +147 -2
- package/src/runtime/verification-templates.ts +29 -3
- package/src/services/published-app-updater.ts +30 -8
- package/src/signals/cancel.ts +2 -4
- package/src/subagent/manager.ts +21 -5
- package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
- package/src/telemetry/activation-funnel.ts +167 -0
- package/src/telemetry/types.ts +13 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
- package/src/telemetry/usage-telemetry-reporter.ts +26 -1
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +9 -19
- package/src/tools/acp/list-agents.ts +3 -15
- package/src/tools/acp/spawn.test.ts +173 -202
- package/src/tools/acp/spawn.ts +37 -172
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +166 -50
- package/src/tools/browser/browser-execution.ts +12 -2
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/network/web-fetch.ts +65 -24
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/ui-surface/definitions.ts +32 -5
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
- package/docs/plugins.md +0 -832
- package/examples/plugins/echo/register.ts +0 -143
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
- package/src/__tests__/pipeline-runner.test.ts +0 -554
- package/src/daemon/wake-target-adapter.ts +0 -253
- package/src/memory/v3/__tests__/assign.test.ts +0 -242
- package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
- package/src/memory/v3/__tests__/core.test.ts +0 -39
- package/src/memory/v3/__tests__/health.test.ts +0 -219
- package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
- package/src/memory/v3/__tests__/needle.test.ts +0 -107
- package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
- package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
- package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
- package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
- package/src/memory/v3/__tests__/router.test.ts +0 -332
- package/src/memory/v3/__tests__/selector.test.ts +0 -470
- package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
- package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
- package/src/memory/v3/__tests__/tree.test.ts +0 -192
- package/src/memory/v3/assign.ts +0 -268
- package/src/memory/v3/capabilities.ts +0 -124
- package/src/memory/v3/core.ts +0 -26
- package/src/memory/v3/health.ts +0 -0
- package/src/memory/v3/maintain-job.ts +0 -314
- package/src/memory/v3/needle.ts +0 -115
- package/src/memory/v3/orchestrate.ts +0 -126
- package/src/memory/v3/page-content.ts +0 -34
- package/src/memory/v3/provider-blocks.ts +0 -26
- package/src/memory/v3/reconcile.ts +0 -523
- package/src/memory/v3/router.ts +0 -190
- package/src/memory/v3/selection-log-store.ts +0 -84
- package/src/memory/v3/selector.ts +0 -226
- package/src/memory/v3/shadow-plugin.ts +0 -411
- package/src/memory/v3/snapshot.ts +0 -209
- package/src/memory/v3/tree.ts +0 -174
- package/src/memory/v3/types.ts +0 -59
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/register.ts +0 -35
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/register.ts +0 -23
- package/src/plugins/defaults/history-repair/register.ts +0 -24
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- package/src/plugins/defaults/title-generate/register.ts +0 -35
- package/src/plugins/defaults/tool-error/register.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
- package/src/proactive-artifact/aux-message-injector.ts +0 -97
- package/src/proactive-artifact/decision.test.ts +0 -226
- package/src/proactive-artifact/decision.ts +0 -165
- package/src/proactive-artifact/index.ts +0 -7
- package/src/proactive-artifact/job.test.ts +0 -962
- package/src/proactive-artifact/job.ts +0 -372
- package/src/proactive-artifact/message-copy.ts +0 -58
- package/src/proactive-artifact/trigger-state.test.ts +0 -286
- package/src/proactive-artifact/trigger-state.ts +0 -123
- package/src/util/map-limit.ts +0 -27
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
|
@@ -301,7 +301,14 @@ export type ConversationSlackMessage = z.infer<
|
|
|
301
301
|
*/
|
|
302
302
|
export const ConversationContentBlockSchema = z.discriminatedUnion("type", [
|
|
303
303
|
z.object({ type: z.literal("text"), text: z.string() }),
|
|
304
|
-
z.object({
|
|
304
|
+
z.object({
|
|
305
|
+
type: z.literal("thinking"),
|
|
306
|
+
thinking: z.string(),
|
|
307
|
+
/** Unix ms when the model began emitting this reasoning block. */
|
|
308
|
+
startedAt: z.number().optional(),
|
|
309
|
+
/** Unix ms when this reasoning block completed. */
|
|
310
|
+
completedAt: z.number().optional(),
|
|
311
|
+
}),
|
|
305
312
|
z.object({
|
|
306
313
|
type: z.literal("tool_use"),
|
|
307
314
|
toolCall: ConversationMessageToolCallSchema,
|
|
@@ -335,7 +342,20 @@ export const ConversationMessageSchema = z.object({
|
|
|
335
342
|
* assistant messages were consolidated for history rendering.
|
|
336
343
|
*/
|
|
337
344
|
mergedMessageIds: z.array(z.string()).optional(),
|
|
338
|
-
|
|
345
|
+
/**
|
|
346
|
+
* Client-generated idempotency nonce echoed back on the persisted row.
|
|
347
|
+
* Present only for messages a client sent with one (user sends); lets the
|
|
348
|
+
* client correlate an optimistic row with its confirmed server row by
|
|
349
|
+
* identity instead of matching message text.
|
|
350
|
+
*/
|
|
351
|
+
clientMessageId: z.string().optional(),
|
|
352
|
+
/**
|
|
353
|
+
* Renderable conversation roles only. The messages endpoint emits a
|
|
354
|
+
* UI-facing transcript, so it excludes the `system` rows that the
|
|
355
|
+
* underlying `MessageRole` column also permits — those are agent-context
|
|
356
|
+
* scaffolding, never a displayed turn.
|
|
357
|
+
*/
|
|
358
|
+
role: z.enum(["user", "assistant"]),
|
|
339
359
|
/**
|
|
340
360
|
* Flat plain-text body (joined text segments). Redundant with
|
|
341
361
|
* `textSegments`/`contentOrder` for clients that render from the positional
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Wire contract for the memory v3 selection set surfaced in the inspector's
|
|
3
3
|
* Memory tab. Mirrors the return value of `getMemoryV3SelectionForInspector`
|
|
4
|
-
* in `assistant/src/memory
|
|
4
|
+
* in `assistant/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts`.
|
|
5
5
|
*
|
|
6
6
|
* Canonical wire-contract source. Assistant code imports the types directly
|
|
7
7
|
* from this file via relative paths; external consumers (web client, gateway,
|
|
@@ -12,19 +12,27 @@
|
|
|
12
12
|
* `live` / `shadow` reflect the CURRENT `memory-v3-live` / `memory-v3-shadow`
|
|
13
13
|
* flag state, not the per-turn history (the selection rows don't record which
|
|
14
14
|
* mode was active when they were written). When `live` is true the rendered
|
|
15
|
-
* `injectedText`
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* `injectedText` reflects the live selection; when only `shadow` is true it is
|
|
16
|
+
* the block that WOULD have been injected.
|
|
17
|
+
*
|
|
18
|
+
* `injectedText` is APPROXIMATE, not a verbatim record. It is re-rendered from
|
|
19
|
+
* the persisted selection rows, which store slug/source/pinned but NOT the
|
|
20
|
+
* matched-section identity. A page that live injection sent as a single matched
|
|
21
|
+
* section is re-rendered here as its FULL page (the section ordinal isn't
|
|
22
|
+
* persisted), so the text can differ from what was actually sent to the model.
|
|
23
|
+
* The selected slug set is exact — only the rendered text is full-page
|
|
24
|
+
* approximate. Persisting the per-turn injected section is a documented
|
|
25
|
+
* follow-up.
|
|
19
26
|
*/
|
|
20
27
|
|
|
21
28
|
import { z } from "zod";
|
|
22
29
|
|
|
23
30
|
/**
|
|
24
31
|
* One selected page in the v3 set. `source` is the lane that surfaced it —
|
|
25
|
-
* the daemon emits `
|
|
26
|
-
* schema stays a permissive string so a new lane label
|
|
27
|
-
* on the FE. `pinned` marks a slug carried
|
|
32
|
+
* the daemon emits `needle`, `dense`, `edge`, or `carry-forward` — but the
|
|
33
|
+
* schema stays a permissive string so a new lane label (or a historical
|
|
34
|
+
* pre-lane row) doesn't break parsing on the FE. `pinned` marks a slug carried
|
|
35
|
+
* forward across turns.
|
|
28
36
|
*/
|
|
29
37
|
export const MemoryV3SelectionRowSchema = z.object({
|
|
30
38
|
slug: z.string(),
|
|
@@ -36,8 +44,9 @@ export type MemoryV3SelectionRow = z.infer<typeof MemoryV3SelectionRowSchema>;
|
|
|
36
44
|
|
|
37
45
|
/**
|
|
38
46
|
* Memory v3 selection log shape. `injectedText` is the rendered
|
|
39
|
-
* `<memory>…</memory>` block for the selection
|
|
40
|
-
*
|
|
47
|
+
* `<memory>…</memory>` block for the selection — APPROXIMATE: re-rendered from
|
|
48
|
+
* the persisted rows, with full pages where live injection used a matched
|
|
49
|
+
* section (the section identity isn't persisted). See the file header.
|
|
41
50
|
*/
|
|
42
51
|
export const MemoryV3SelectionLogSchema = z.object({
|
|
43
52
|
turn: z.number(),
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { answerCall } from "../calls/call-domain.js";
|
|
15
15
|
import { findContactChannel } from "../contacts/contact-store.js";
|
|
16
16
|
import { upsertContactChannel } from "../contacts/contacts-write.js";
|
|
17
|
-
import { findConversation } from "../daemon/conversation-
|
|
17
|
+
import { findConversation } from "../daemon/conversation-registry.js";
|
|
18
18
|
import {
|
|
19
19
|
type CanonicalGuardianRequest,
|
|
20
20
|
getCanonicalGuardianRequest,
|
|
@@ -196,6 +196,32 @@ const pendingInteractionResolver: GuardianRequestResolver = {
|
|
|
196
196
|
// resolveConfirmation() owns pendingInteractions deregistration.
|
|
197
197
|
const userDecision: UserDecision =
|
|
198
198
|
decision.action === "reject" ? "deny" : "allow";
|
|
199
|
+
|
|
200
|
+
// Route-owned confirmations (e.g. the ACP spawn/steer approval gate in
|
|
201
|
+
// acp-routes.ts) carry a `directResolve` and are NOT owned by any
|
|
202
|
+
// Conversation.prompter, so handleConfirmationResponse below would no-op
|
|
203
|
+
// and the caller would block until timeout. Resolve them directly, exactly
|
|
204
|
+
// as the POST /v1/confirm route does (see approval-routes.ts).
|
|
205
|
+
if (interaction.directResolve) {
|
|
206
|
+
pendingInteractions.resolve(
|
|
207
|
+
request.id,
|
|
208
|
+
userDecision === "allow" ? "approved" : "rejected",
|
|
209
|
+
);
|
|
210
|
+
interaction.directResolve(userDecision);
|
|
211
|
+
log.info(
|
|
212
|
+
{
|
|
213
|
+
event: "resolver_tool_approval_applied",
|
|
214
|
+
requestId: request.id,
|
|
215
|
+
action: decision.action,
|
|
216
|
+
conversationId: request.conversationId,
|
|
217
|
+
toolName: request.toolName,
|
|
218
|
+
directResolve: true,
|
|
219
|
+
},
|
|
220
|
+
"Tool approval resolver: direct-resolve interaction resolved",
|
|
221
|
+
);
|
|
222
|
+
return { ok: true, applied: true };
|
|
223
|
+
}
|
|
224
|
+
|
|
199
225
|
const conversation = findConversation(interaction.conversationId);
|
|
200
226
|
if (!conversation) {
|
|
201
227
|
return {
|
|
@@ -97,6 +97,7 @@ function getHeartbeatWakeSource(now: number): HeartbeatWakeSource | null {
|
|
|
97
97
|
|
|
98
98
|
const service = HeartbeatService.getInstance();
|
|
99
99
|
if (service?.isConsecutiveRunCapReached) return null;
|
|
100
|
+
if (service?.isDailyCapReached) return null;
|
|
100
101
|
|
|
101
102
|
const serviceNextRunAt = service?.nextRunAt ?? null;
|
|
102
103
|
let nextRunAt = serviceNextRunAt;
|
|
@@ -1,245 +1,226 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tests for the `memory v3` CLI
|
|
2
|
+
* Tests for the `assistant memory v3` CLI subgroup (section-lane model).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* concept page's `leaves:` frontmatter (via the page index) and union it over
|
|
12
|
-
* `assignments.json`, matching the consolidation-injected health block. The
|
|
13
|
-
* fixture below writes concept pages with `leaves:` frontmatter as the
|
|
14
|
-
* authoritative membership and keeps a *stale* `assignments.json` to prove the
|
|
15
|
-
* handlers read the frontmatter, not the stale assignments. The seeded
|
|
16
|
-
* skill/CLI-command catalogs are mocked empty so `allSlugs` (derived from the
|
|
17
|
-
* page index) is deterministic.
|
|
4
|
+
* Validates:
|
|
5
|
+
* - Subcommand registration (rebuild-index, backfill-sections) under
|
|
6
|
+
* `memory v3`.
|
|
7
|
+
* - Each subcommand maps to the right `cliIpcCall` method.
|
|
8
|
+
* - `backfill-sections` passes a long IPC timeout (the one-time full-corpus
|
|
9
|
+
* embed easily outlasts the default 60s), while `rebuild-index` does not.
|
|
10
|
+
* - IPC error paths return a non-zero exit code without throwing.
|
|
18
11
|
*/
|
|
19
12
|
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
13
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
14
|
+
|
|
15
|
+
import { Command } from "commander";
|
|
16
|
+
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Mock state
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
/** The last `cliIpcCall` invocation captured for assertions. */
|
|
22
|
+
let lastIpcCall: {
|
|
23
|
+
method: string;
|
|
24
|
+
|
|
25
|
+
params?: any;
|
|
26
|
+
options?: { timeoutMs?: number; signal?: AbortSignal };
|
|
27
|
+
} | null = null;
|
|
28
|
+
|
|
29
|
+
/** The result that cliIpcCall will return. */
|
|
30
|
+
let mockIpcResult: {
|
|
31
|
+
ok: boolean;
|
|
32
|
+
result?: unknown;
|
|
33
|
+
error?: string;
|
|
34
|
+
} = { ok: true, result: { articles: 3, sections: 12, failures: 0 } };
|
|
35
|
+
|
|
36
|
+
/** Captured log output for assertion. */
|
|
37
|
+
let logOutput: string[] = [];
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Mocks
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
mock.module("../../../ipc/cli-client.js", () => ({
|
|
44
|
+
cliIpcCall: async (
|
|
45
|
+
method: string,
|
|
46
|
+
params?: any,
|
|
47
|
+
options?: { timeoutMs?: number; signal?: AbortSignal },
|
|
48
|
+
) => {
|
|
49
|
+
lastIpcCall = { method, params, options };
|
|
50
|
+
return mockIpcResult;
|
|
51
|
+
},
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
const capture = (...args: unknown[]) => {
|
|
55
|
+
logOutput.push(args.map(String).join(" "));
|
|
56
|
+
};
|
|
57
|
+
const fakeLogger = {
|
|
58
|
+
info: capture,
|
|
59
|
+
warn: capture,
|
|
60
|
+
error: capture,
|
|
61
|
+
debug: () => {},
|
|
62
|
+
};
|
|
63
|
+
mock.module("../../../util/logger.js", () => ({
|
|
64
|
+
getLogger: () => fakeLogger,
|
|
65
|
+
getCliLogger: () => fakeLogger,
|
|
66
|
+
}));
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Import modules under test (after mocks)
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
const { registerMemoryV3Command } = await import("../memory-v3.js");
|
|
73
|
+
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Test helpers
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
function buildProgram(): Command {
|
|
79
|
+
const program = new Command();
|
|
80
|
+
program.exitOverride();
|
|
81
|
+
program.configureOutput({
|
|
82
|
+
writeErr: () => {},
|
|
83
|
+
writeOut: () => {},
|
|
84
|
+
});
|
|
85
|
+
registerMemoryV3Command(program);
|
|
86
|
+
return program;
|
|
60
87
|
}
|
|
61
88
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
89
|
+
async function runCommand(
|
|
90
|
+
args: string[],
|
|
91
|
+
): Promise<{ stdout: string; exitCode: number }> {
|
|
92
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
93
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
94
|
+
const stdoutChunks: string[] = [];
|
|
95
|
+
|
|
96
|
+
process.stdout.write = ((chunk: unknown) => {
|
|
97
|
+
stdoutChunks.push(typeof chunk === "string" ? chunk : String(chunk));
|
|
98
|
+
return true;
|
|
99
|
+
}) as typeof process.stdout.write;
|
|
100
|
+
|
|
101
|
+
process.stderr.write = (() => true) as typeof process.stderr.write;
|
|
102
|
+
|
|
103
|
+
process.exitCode = 0;
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const program = buildProgram();
|
|
107
|
+
await program.parseAsync(["node", "assistant", ...args]);
|
|
108
|
+
} catch {
|
|
109
|
+
if (process.exitCode === 0) process.exitCode = 1;
|
|
110
|
+
} finally {
|
|
111
|
+
process.stdout.write = originalStdoutWrite;
|
|
112
|
+
process.stderr.write = originalStderrWrite;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const exitCode = process.exitCode ?? 0;
|
|
116
|
+
process.exitCode = 0;
|
|
117
|
+
|
|
118
|
+
return { exitCode, stdout: stdoutChunks.join("") };
|
|
76
119
|
}
|
|
77
120
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
await mkdir(dataDir, { recursive: true });
|
|
82
|
-
|
|
83
|
-
// Keep the page index deterministic regardless of the on-disk seeded
|
|
84
|
-
// catalogs, and clear any module-cached index from a prior test.
|
|
85
|
-
spyOn(skillStore, "listSkillEntries").mockReturnValue([]);
|
|
86
|
-
spyOn(cliCommandStore, "listCliCommandEntries").mockReturnValue([]);
|
|
87
|
-
invalidatePageIndex();
|
|
88
|
-
|
|
89
|
-
// A small generic tree: two leaves under domain-a, one under domain-b.
|
|
90
|
-
await writeLeaf("domain-a/topic-x", {
|
|
91
|
-
path: "domain-a/topic-x",
|
|
92
|
-
in_core: true,
|
|
93
|
-
id: "leaf-x",
|
|
94
|
-
});
|
|
95
|
-
await writeLeaf("domain-a/topic-y", {
|
|
96
|
-
path: "domain-a/topic-y",
|
|
97
|
-
in_core: false,
|
|
98
|
-
id: "leaf-y",
|
|
99
|
-
});
|
|
100
|
-
await writeLeaf("domain-b/topic-z", {
|
|
101
|
-
path: "domain-b/topic-z",
|
|
102
|
-
in_core: false,
|
|
103
|
-
id: "leaf-z",
|
|
104
|
-
});
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// Setup
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
105
124
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// when it is non-empty, so for these slugs the frontmatter wins and
|
|
115
|
-
// assignments.json contributes no membership — proving the handlers read the
|
|
116
|
-
// page index, not these stale assignments (the regression Defect A guards
|
|
117
|
-
// against). We deliberately avoid a slug that exists ONLY in assignments.json:
|
|
118
|
-
// such a slug has no frontmatter, falls back to its assignments entry, and
|
|
119
|
-
// would inflate the cost preview below with phantom membership.
|
|
120
|
-
await writeFile(
|
|
121
|
-
join(dataDir, "assignments.json"),
|
|
122
|
-
JSON.stringify({
|
|
123
|
-
"page-1": ["domain-a/bogus-leaf"],
|
|
124
|
-
"page-2": ["domain-b/topic-z"],
|
|
125
|
-
}),
|
|
126
|
-
);
|
|
127
|
-
await writeFile(
|
|
128
|
-
join(dataDir, "core.json"),
|
|
129
|
-
JSON.stringify({ alwaysOn: ["domain-a/topic-x"] }),
|
|
130
|
-
);
|
|
125
|
+
beforeEach(() => {
|
|
126
|
+
lastIpcCall = null;
|
|
127
|
+
mockIpcResult = {
|
|
128
|
+
ok: true,
|
|
129
|
+
result: { articles: 3, sections: 12, failures: 0 },
|
|
130
|
+
};
|
|
131
|
+
logOutput = [];
|
|
132
|
+
process.exitCode = 0;
|
|
131
133
|
});
|
|
132
134
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
// Subcommand registration
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
|
|
139
|
+
describe("subcommand registration", () => {
|
|
140
|
+
test("registers v3 under memory with the expected subcommands", () => {
|
|
141
|
+
const program = buildProgram();
|
|
142
|
+
const memory = program.commands.find((c) => c.name() === "memory");
|
|
143
|
+
expect(memory).toBeDefined();
|
|
144
|
+
const v3 = memory!.commands.find((c) => c.name() === "v3");
|
|
145
|
+
expect(v3).toBeDefined();
|
|
146
|
+
const subcommandNames = v3!.commands.map((c) => c.name()).sort();
|
|
147
|
+
expect(subcommandNames).toEqual(["backfill-sections", "rebuild-index"]);
|
|
148
|
+
});
|
|
136
149
|
});
|
|
137
150
|
|
|
138
151
|
// ---------------------------------------------------------------------------
|
|
139
|
-
//
|
|
152
|
+
// rebuild-index
|
|
140
153
|
// ---------------------------------------------------------------------------
|
|
141
154
|
|
|
142
|
-
describe("
|
|
143
|
-
test("
|
|
144
|
-
|
|
145
|
-
{ add: ["domain-a/does-not-exist"], write: true },
|
|
146
|
-
{ dataDir, workspaceDir },
|
|
147
|
-
);
|
|
148
|
-
await expect(call).rejects.toThrow(/domain-a\/does-not-exist/);
|
|
149
|
-
await expect(
|
|
150
|
-
handleMemoryV3SetCore(
|
|
151
|
-
{ add: ["domain-a/does-not-exist"], write: true },
|
|
152
|
-
{ dataDir, workspaceDir },
|
|
153
|
-
),
|
|
154
|
-
).rejects.toBeInstanceOf(UnknownLeafError);
|
|
155
|
+
describe("memory v3 rebuild-index", () => {
|
|
156
|
+
test("sends memory_v3_rebuild_index with the default (no) timeout", async () => {
|
|
157
|
+
mockIpcResult = { ok: true, result: { invalidated: true } };
|
|
155
158
|
|
|
156
|
-
|
|
157
|
-
const core = JSON.parse(await readFile(join(dataDir, "core.json"), "utf8"));
|
|
158
|
-
expect(core.alwaysOn).toEqual(["domain-a/topic-x"]);
|
|
159
|
-
});
|
|
159
|
+
const { exitCode } = await runCommand(["memory", "v3", "rebuild-index"]);
|
|
160
160
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
// topic-z), topic-x/topic-y would have no members and this would be 0.
|
|
167
|
-
const result = await handleMemoryV3SetCore(
|
|
168
|
-
{ add: ["domain-a/topic-y"] },
|
|
169
|
-
{ dataDir, workspaceDir },
|
|
170
|
-
);
|
|
171
|
-
expect(result.written).toBe(false);
|
|
172
|
-
expect(result.nextCore).toEqual(["domain-a/topic-x", "domain-a/topic-y"]);
|
|
173
|
-
expect(result.alwaysOnPageCount).toBe(2);
|
|
174
|
-
|
|
175
|
-
// No write happened — core.json still holds only the original entry.
|
|
176
|
-
const core = JSON.parse(await readFile(join(dataDir, "core.json"), "utf8"));
|
|
177
|
-
expect(core.alwaysOn).toEqual(["domain-a/topic-x"]);
|
|
161
|
+
expect(exitCode).toBe(0);
|
|
162
|
+
expect(lastIpcCall!.method).toBe("memory_v3_rebuild_index");
|
|
163
|
+
expect(lastIpcCall!.params!.body).toEqual({});
|
|
164
|
+
// rebuild-index is fast; it relies on the default call timeout.
|
|
165
|
+
expect(lastIpcCall!.options).toBeUndefined();
|
|
178
166
|
});
|
|
179
167
|
|
|
180
|
-
test("
|
|
181
|
-
|
|
182
|
-
{ add: ["domain-b/topic-z"], write: true },
|
|
183
|
-
{ dataDir, workspaceDir },
|
|
184
|
-
);
|
|
185
|
-
expect(result.written).toBe(true);
|
|
186
|
-
expect(result.nextCore).toEqual(["domain-a/topic-x", "domain-b/topic-z"]);
|
|
168
|
+
test("exits with code 1 on IPC failure", async () => {
|
|
169
|
+
mockIpcResult = { ok: false, error: "Daemon down" };
|
|
187
170
|
|
|
188
|
-
const
|
|
189
|
-
expect(core.alwaysOn).toEqual(["domain-a/topic-x", "domain-b/topic-z"]);
|
|
190
|
-
});
|
|
171
|
+
const { exitCode } = await runCommand(["memory", "v3", "rebuild-index"]);
|
|
191
172
|
|
|
192
|
-
|
|
193
|
-
const result = await handleMemoryV3SetCore(
|
|
194
|
-
{ remove: ["domain-a/topic-y"], write: true },
|
|
195
|
-
{ dataDir, workspaceDir },
|
|
196
|
-
);
|
|
197
|
-
// topic-y was never in core; result is the original core unchanged.
|
|
198
|
-
expect(result.nextCore).toEqual(["domain-a/topic-x"]);
|
|
173
|
+
expect(exitCode).toBe(1);
|
|
199
174
|
});
|
|
200
175
|
});
|
|
201
176
|
|
|
202
177
|
// ---------------------------------------------------------------------------
|
|
203
|
-
//
|
|
178
|
+
// backfill-sections
|
|
204
179
|
// ---------------------------------------------------------------------------
|
|
205
180
|
|
|
206
|
-
describe("
|
|
207
|
-
test("
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
expect(
|
|
181
|
+
describe("memory v3 backfill-sections", () => {
|
|
182
|
+
test("sends memory_v3_backfill_sections with a long (30-min) IPC timeout", async () => {
|
|
183
|
+
mockIpcResult = {
|
|
184
|
+
ok: true,
|
|
185
|
+
result: { articles: 50, sections: 400, failures: 0 },
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const { exitCode } = await runCommand([
|
|
189
|
+
"memory",
|
|
190
|
+
"v3",
|
|
191
|
+
"backfill-sections",
|
|
192
|
+
]);
|
|
193
|
+
|
|
194
|
+
expect(exitCode).toBe(0);
|
|
195
|
+
expect(lastIpcCall!.method).toBe("memory_v3_backfill_sections");
|
|
196
|
+
expect(lastIpcCall!.params!.body).toEqual({});
|
|
197
|
+
// The one-time full-corpus embed is long-running, so the CLI must override
|
|
198
|
+
// the default 60s timeout with a generous ceiling (30 min).
|
|
199
|
+
expect(lastIpcCall!.options!.timeoutMs).toBe(30 * 60 * 1000);
|
|
220
200
|
});
|
|
221
201
|
|
|
222
|
-
test("
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
202
|
+
test("summarizes embedded sections on success", async () => {
|
|
203
|
+
mockIpcResult = {
|
|
204
|
+
ok: true,
|
|
205
|
+
result: { articles: 7, sections: 42, failures: 0 },
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
await runCommand(["memory", "v3", "backfill-sections"]);
|
|
209
|
+
|
|
210
|
+
expect(
|
|
211
|
+
logOutput.some((line) => line.includes("42") && line.includes("7")),
|
|
212
|
+
).toBe(true);
|
|
227
213
|
});
|
|
228
|
-
});
|
|
229
214
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
215
|
+
test("exits with code 1 on IPC failure", async () => {
|
|
216
|
+
mockIpcResult = { ok: false, error: "Memory v3 not enabled" };
|
|
217
|
+
|
|
218
|
+
const { exitCode } = await runCommand([
|
|
219
|
+
"memory",
|
|
220
|
+
"v3",
|
|
221
|
+
"backfill-sections",
|
|
222
|
+
]);
|
|
233
223
|
|
|
234
|
-
|
|
235
|
-
test("no-op reconcile against an unchanged tree returns empty diffs", async () => {
|
|
236
|
-
// v1: prevLeaves is derived from the current tree, so diffing
|
|
237
|
-
// current-vs-current yields no renames/deletes — reconcile runs as a
|
|
238
|
-
// convergence/prune pass. This still drives the full reconcileTree path
|
|
239
|
-
// (snapshot → apply → validate → invalidate).
|
|
240
|
-
const result = await handleMemoryV3Reconcile({ dataDir, workspaceDir });
|
|
241
|
-
expect(result.renames).toEqual([]);
|
|
242
|
-
expect(result.deleted).toEqual([]);
|
|
243
|
-
expect(result.prunedCore).toEqual([]);
|
|
224
|
+
expect(exitCode).toBe(1);
|
|
244
225
|
});
|
|
245
226
|
});
|
|
@@ -79,7 +79,7 @@ export function registerChannelVerificationSessionsCommand(
|
|
|
79
79
|
"after",
|
|
80
80
|
`
|
|
81
81
|
Verification sessions are used to verify guardian bindings and trusted
|
|
82
|
-
contacts across channels (telegram, phone, slack). Three flows exist:
|
|
82
|
+
contacts across channels (telegram, phone, slack, email). Three flows exist:
|
|
83
83
|
|
|
84
84
|
1. Inbound challenge — the assistant generates a secret code and waits
|
|
85
85
|
for the guardian to send it back on the channel. Used when the
|
|
@@ -107,10 +107,10 @@ Examples:
|
|
|
107
107
|
cvs
|
|
108
108
|
.command("create")
|
|
109
109
|
.description("Create a new verification session")
|
|
110
|
-
.option("--channel <channel>", "Channel type (telegram, phone, slack)")
|
|
110
|
+
.option("--channel <channel>", "Channel type (telegram, phone, slack, email)")
|
|
111
111
|
.option(
|
|
112
112
|
"--destination <destination>",
|
|
113
|
-
"Destination address for outbound verification (handle, phone number, or
|
|
113
|
+
"Destination address for outbound verification (handle, phone number, user ID, or email address)",
|
|
114
114
|
)
|
|
115
115
|
.option("--rebind", "Replace existing guardian binding")
|
|
116
116
|
.option(
|
|
@@ -140,7 +140,7 @@ Routes between three creation modes based on the provided options:
|
|
|
140
140
|
|
|
141
141
|
2. Outbound: --channel <ch> --destination <dest>
|
|
142
142
|
Sends a verification code to the given destination. Supports telegram
|
|
143
|
-
(handle or chat ID), phone (E.164 number),
|
|
143
|
+
(handle or chat ID), phone (E.164 number), slack (user ID), and email.
|
|
144
144
|
Use --rebind to replace an existing guardian binding.
|
|
145
145
|
|
|
146
146
|
3. Inbound: --channel <ch> (no --destination)
|
|
@@ -240,7 +240,7 @@ Examples:
|
|
|
240
240
|
)
|
|
241
241
|
.requiredOption(
|
|
242
242
|
"--channel <channel>",
|
|
243
|
-
"Channel type (telegram, phone, slack)",
|
|
243
|
+
"Channel type (telegram, phone, slack, email)",
|
|
244
244
|
)
|
|
245
245
|
.option(
|
|
246
246
|
"--origin-conversation-id <id>",
|
|
@@ -290,7 +290,7 @@ Examples:
|
|
|
290
290
|
.description("Cancel all active verification sessions for a channel")
|
|
291
291
|
.requiredOption(
|
|
292
292
|
"--channel <channel>",
|
|
293
|
-
"Channel type (telegram, phone, slack)",
|
|
293
|
+
"Channel type (telegram, phone, slack, email)",
|
|
294
294
|
)
|
|
295
295
|
.addHelpText(
|
|
296
296
|
"after",
|
|
@@ -507,7 +507,9 @@ describe("assistant db repair — conversation-backfill step", () => {
|
|
|
507
507
|
expect(parsed.steps[1].result.data.recovered).toBe(0);
|
|
508
508
|
expect(parsed.steps[1].result.data.skipped).toBe(1);
|
|
509
509
|
expect(parsed.steps[1].result.status).toBe("ok");
|
|
510
|
-
|
|
510
|
+
// Two full repair passes (each walks the DB via integrity-check) exceed
|
|
511
|
+
// bun's 5s per-test default, so raise the ceiling to keep CI stable.
|
|
512
|
+
}, 30_000);
|
|
511
513
|
|
|
512
514
|
test("reports nothing-to-backfill on an empty conversations dir", async () => {
|
|
513
515
|
await initSchema();
|