@vellumai/assistant 0.8.4 → 0.8.5
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 +2 -2
- package/docs/browser-use-architecture-phase2.md +1 -1
- package/knip.json +2 -1
- package/openapi.yaml +809 -11
- package/package.json +1 -1
- package/src/__tests__/anthropic-provider.test.ts +34 -37
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
- package/src/__tests__/audit-log-rotation.test.ts +70 -16
- package/src/__tests__/background-workers-disk-pressure.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +2 -3
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/channel-guardian.test.ts +3 -3
- package/src/__tests__/checker.test.ts +6 -15
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
- package/src/__tests__/computer-use-tools.test.ts +2 -4
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +197 -2
- package/src/__tests__/conversation-agent-loop.test.ts +163 -122
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
- package/src/__tests__/conversation-clear-safety.test.ts +25 -25
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-fork-crud.test.ts +178 -15
- package/src/__tests__/conversation-lifecycle.test.ts +52 -11
- package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +13 -13
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
- package/src/__tests__/conversation-skill-tools.test.ts +2 -5
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-sync-tags.test.ts +99 -32
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
- package/src/__tests__/credential-execution-tools.test.ts +6 -6
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +2 -2
- package/src/__tests__/dynamic-page-surface.test.ts +2 -2
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- package/src/__tests__/gateway-flag-listener.test.ts +237 -0
- package/src/__tests__/gemini-provider.test.ts +78 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +7 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +4 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
- package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
- package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
- package/src/__tests__/llm-resolver.test.ts +77 -9
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- package/src/__tests__/logger.test.ts +89 -0
- package/src/__tests__/mcp-abort-signal.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +31 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
- package/src/__tests__/model-intents.test.ts +2 -4
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/onboarding-template-contract.test.ts +1 -1
- package/src/__tests__/openai-provider.test.ts +46 -0
- package/src/__tests__/openai-responses-provider.test.ts +114 -12
- package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
- package/src/__tests__/platform.test.ts +2 -2
- package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
- package/src/__tests__/plugin-bootstrap.test.ts +2 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
- package/src/__tests__/plugin-types.test.ts +3 -2
- package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
- package/src/__tests__/pricing.test.ts +12 -0
- package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
- package/src/__tests__/registry.test.ts +2 -8
- package/src/__tests__/require-fresh-approval.test.ts +2 -2
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
- package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
- package/src/__tests__/skill-tool-factory.test.ts +1 -1
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/sync-message-contract.test.ts +59 -0
- package/src/__tests__/system-prompt.test.ts +145 -131
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/tool-approval-handler.test.ts +1 -5
- package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
- package/src/__tests__/tool-executor.test.ts +9 -62
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
- package/src/__tests__/usage-routes.test.ts +3 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +6 -5
- package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
- package/src/acp/prepare-agent-env.ts +78 -0
- package/src/acp/session-manager.ts +1 -1
- package/src/agent/loop.ts +8 -0
- package/src/api/README.md +5 -0
- package/src/api/index.ts +4 -0
- package/src/api/package.json +10 -0
- package/src/background-wake/background-wake-routes.test.ts +233 -0
- package/src/background-wake/runtime-registry.ts +24 -0
- package/src/cli/commands/__tests__/browser.test.ts +23 -5
- package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
- package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
- package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +1 -0
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/domain.ts +91 -41
- package/src/cli/commands/inference.ts +93 -40
- package/src/cli/commands/memory-v2-compare-render.ts +115 -0
- package/src/cli/commands/memory-v2.ts +176 -1
- package/src/cli/commands/memory-v3-render.ts +344 -0
- package/src/cli/commands/memory-v3.ts +316 -0
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +21 -9
- package/src/config/bundled-skills/document-editor/SKILL.md +11 -2
- package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
- package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/call-site-defaults.ts +7 -6
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +213 -1
- package/src/config/schemas/call-site-catalog.ts +21 -7
- package/src/config/schemas/llm.ts +12 -1
- package/src/config/schemas/memory-v2.ts +246 -0
- package/src/config/schemas/memory.ts +2 -1
- package/src/context/compactor.ts +52 -0
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -13
- package/src/daemon/conversation-agent-loop.ts +126 -76
- package/src/daemon/conversation-error.ts +31 -1
- package/src/daemon/conversation-lifecycle.ts +27 -22
- package/src/daemon/conversation-runtime-assembly.ts +10 -9
- package/src/daemon/conversation-tool-setup.ts +63 -3
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +14 -29
- package/src/daemon/disk-pressure-guard.ts +14 -2
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +11 -3
- package/src/daemon/host-browser-proxy.ts +5 -5
- package/src/daemon/host-cu-proxy.ts +4 -4
- package/src/daemon/host-file-proxy.ts +4 -4
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/host-transfer-proxy.ts +10 -10
- package/src/daemon/lifecycle.ts +23 -20
- package/src/daemon/meet-manifest-loader.ts +1 -7
- package/src/daemon/message-types/conversations.ts +6 -9
- package/src/daemon/message-types/home.ts +1 -13
- package/src/daemon/message-types/messages.ts +6 -14
- package/src/daemon/message-types/sync.ts +14 -0
- package/src/daemon/shutdown-handlers.ts +24 -5
- package/src/daemon/switch-inference-profile-tool.ts +52 -0
- package/src/daemon/tool-setup-types.ts +13 -0
- package/src/events/relationship-state-updated.ts +25 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
- package/src/home/home-greeting.ts +0 -9
- package/src/home/suggested-prompts.ts +0 -9
- package/src/ipc/gateway-flag-listener.ts +123 -0
- package/src/ipc/skill-routes/registries.ts +8 -12
- package/src/memory/__tests__/db-async-query.test.ts +165 -0
- package/src/memory/__tests__/db-maintenance.test.ts +115 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
- package/src/memory/__tests__/memory-retrospective-job.test.ts +7 -0
- package/src/memory/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-crud.ts +71 -70
- package/src/memory/conversation-starters-cadence.ts +3 -1
- package/src/memory/conversation-title-service.ts +19 -3
- package/src/memory/db-async-query.ts +214 -0
- package/src/memory/db-init.ts +10 -0
- package/src/memory/db-maintenance.ts +30 -21
- package/src/memory/graph/bootstrap.ts +8 -1
- package/src/memory/graph/capability-seed.ts +7 -3
- package/src/memory/graph/conversation-graph-memory.ts +100 -17
- package/src/memory/graph/extraction.ts +1 -5
- package/src/memory/graph/graph-search.ts +7 -1
- package/src/memory/indexer.ts +28 -18
- package/src/memory/job-handlers/cleanup.ts +76 -18
- package/src/memory/job-handlers/conversation-starters.ts +1 -4
- package/src/memory/jobs/embed-pkb-file.ts +6 -1
- package/src/memory/jobs-store.ts +14 -0
- package/src/memory/jobs-worker.ts +55 -22
- package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
- package/src/memory/llm-request-log-source-local.ts +7 -0
- package/src/memory/llm-request-log-source.ts +9 -2
- package/src/memory/llm-request-log-store.ts +43 -1
- package/src/memory/llm-usage-store.ts +24 -0
- package/src/memory/memory-retrospective-enqueue.ts +8 -1
- package/src/memory/memory-retrospective-job.ts +5 -0
- package/src/memory/memory-v2-activation-log-store.ts +15 -6
- package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
- package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
- package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
- package/src/memory/migrations/index.ts +17 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/schema/conversations.ts +1 -1
- package/src/memory/schema/infrastructure.ts +21 -0
- package/src/memory/tool-usage-store.ts +36 -8
- package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
- package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
- package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
- package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
- package/src/memory/v2/__tests__/injection.test.ts +127 -98
- package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
- package/src/memory/v2/__tests__/router.test.ts +171 -3
- package/src/memory/v2/harness/compare.ts +57 -0
- package/src/memory/v2/harness/metrics.ts +124 -0
- package/src/memory/v2/harness/oracle.ts +145 -0
- package/src/memory/v2/harness/replay-input.ts +224 -0
- package/src/memory/v2/harness/retriever.ts +74 -0
- package/src/memory/v2/harness/router-retriever.ts +43 -0
- package/src/memory/v2/harness/runner.ts +106 -0
- package/src/memory/v2/harness/trace.ts +58 -0
- package/src/memory/v2/injection.ts +21 -15
- package/src/memory/v2/prompts/router.ts +26 -1
- package/src/memory/v2/qdrant.ts +14 -2
- package/src/memory/v2/router.ts +171 -18
- package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
- package/src/memory/v3/__tests__/edges.test.ts +563 -0
- package/src/memory/v3/__tests__/filter.test.ts +512 -0
- package/src/memory/v3/__tests__/gate.test.ts +574 -0
- package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
- package/src/memory/v3/__tests__/loop.test.ts +530 -0
- package/src/memory/v3/__tests__/retriever.test.ts +226 -0
- package/src/memory/v3/__tests__/scouts.test.ts +440 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
- package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
- package/src/memory/v3/__tests__/traversal.test.ts +469 -0
- package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
- package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
- package/src/memory/v3/__tests__/validate.test.ts +245 -0
- package/src/memory/v3/auto-edges.ts +223 -0
- package/src/memory/v3/coactivation-store.ts +124 -0
- package/src/memory/v3/consolidation-job.ts +323 -0
- package/src/memory/v3/edge-learning-job.ts +160 -0
- package/src/memory/v3/edges.ts +249 -0
- package/src/memory/v3/filter.ts +281 -0
- package/src/memory/v3/gate.ts +334 -0
- package/src/memory/v3/index-composition.ts +113 -0
- package/src/memory/v3/llm-capture.ts +46 -0
- package/src/memory/v3/loop.ts +382 -0
- package/src/memory/v3/maintenance.ts +144 -0
- package/src/memory/v3/prompt-context.ts +33 -0
- package/src/memory/v3/prompts/consolidation.ts +458 -0
- package/src/memory/v3/prompts/system-prompts.ts +196 -0
- package/src/memory/v3/retriever.ts +33 -0
- package/src/memory/v3/scouts.ts +420 -0
- package/src/memory/v3/shadow-middleware.ts +305 -0
- package/src/memory/v3/traversal.ts +206 -0
- package/src/memory/v3/tree-index.ts +237 -0
- package/src/memory/v3/tree-store.ts +394 -0
- package/src/memory/v3/tree-walk.ts +351 -0
- package/src/memory/v3/types.ts +65 -0
- package/src/memory/v3/validate.ts +300 -0
- package/src/notifications/adapters/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- package/src/notifications/decision-engine.ts +1 -4
- package/src/notifications/emit-signal.ts +29 -49
- package/src/permissions/prompter.ts +3 -3
- package/src/permissions/question-prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +2 -2
- package/src/plugin-api/index.ts +4 -0
- package/src/plugin-api/types.ts +7 -33
- package/src/plugins/defaults/index.ts +6 -0
- package/src/plugins/defaults/injectors.ts +18 -11
- package/src/plugins/external-plugin-loader.ts +5 -68
- package/src/plugins/types.ts +11 -16
- package/src/proactive-artifact/aux-message-injector.ts +17 -4
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
- package/src/prompts/persona-resolver.ts +36 -21
- package/src/prompts/sections.ts +39 -7
- package/src/prompts/system-prompt.ts +50 -185
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +230 -8
- package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
- package/src/providers/__tests__/retry-callsite.test.ts +85 -5
- package/src/providers/anthropic/client.ts +32 -66
- package/src/providers/call-site-routing.ts +14 -2
- package/src/providers/connection-model-compat.ts +38 -0
- package/src/providers/connection-resolution.ts +16 -2
- package/src/providers/gemini/client.ts +49 -6
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +43 -0
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openai/chat-completions-provider.ts +6 -3
- package/src/providers/openai/codex-models.ts +18 -0
- package/src/providers/openai/responses-provider.ts +78 -21
- package/src/providers/provider-send-message.ts +7 -1
- package/src/providers/retry.ts +34 -3
- package/src/providers/thinking-config.ts +26 -1
- package/src/providers/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/agent-wake.ts +1 -0
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +36 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +10 -3
- package/src/runtime/pending-interactions.ts +0 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +106 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +25 -6
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
- package/src/runtime/routes/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -1
- package/src/runtime/routes/avatar-routes.ts +10 -10
- package/src/runtime/routes/background-wake-routes.ts +188 -0
- package/src/runtime/routes/browser-tabs-routes.ts +200 -0
- package/src/runtime/routes/btw-routes.ts +0 -6
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +12 -4
- package/src/runtime/routes/conversation-management-routes.ts +77 -20
- package/src/runtime/routes/conversation-query-routes.ts +142 -36
- package/src/runtime/routes/conversation-routes.ts +252 -410
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- package/src/runtime/routes/domain-routes.ts +60 -10
- package/src/runtime/routes/email-routes.ts +5 -2
- package/src/runtime/routes/events-routes.ts +54 -10
- package/src/runtime/routes/group-routes.ts +24 -8
- package/src/runtime/routes/host-browser-routes.ts +10 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
- package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
- package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
- package/src/runtime/routes/memory-item-routes.ts +8 -3
- package/src/runtime/routes/memory-v2-routes.ts +215 -5
- package/src/runtime/routes/memory-v3-routes.ts +316 -0
- package/src/runtime/routes/migration-routes.ts +21 -24
- package/src/runtime/routes/plugins-routes.ts +337 -0
- package/src/runtime/routes/rename-conversation-routes.ts +6 -2
- package/src/runtime/routes/secret-routes.ts +25 -5
- package/src/runtime/routes/settings-routes.ts +12 -11
- package/src/runtime/routes/slack-channel-routes.ts +5 -4
- package/src/runtime/routes/workspace-routes.ts +25 -10
- package/src/runtime/sync/resource-sync-events.ts +106 -38
- package/src/runtime/sync/sync-publisher.test.ts +49 -0
- package/src/runtime/sync/sync-publisher.ts +2 -1
- package/src/runtime/verification-outbound-actions.ts +73 -1
- package/src/telemetry/types.ts +12 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/acp/spawn.test.ts +119 -0
- package/src/tools/acp/spawn.ts +15 -2
- package/src/tools/apps/definitions.ts +2 -8
- package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
- package/src/tools/ask-question/ask-question-tool.ts +38 -45
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
- package/src/tools/browser/browser-execution.ts +16 -3
- package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
- package/src/tools/browser/cdp-client/factory.ts +100 -17
- package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
- package/src/tools/browser/cdp-client/types.ts +65 -0
- package/src/tools/browser/pinned-tabs.ts +96 -40
- package/src/tools/computer-use/definitions.ts +22 -78
- package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
- package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
- package/src/tools/credentials/vault.ts +3 -9
- package/src/tools/document/document-tool.ts +59 -0
- package/src/tools/execution-target.ts +21 -23
- package/src/tools/executor.ts +6 -1
- package/src/tools/filesystem/edit.ts +3 -9
- package/src/tools/filesystem/list.ts +3 -9
- package/src/tools/filesystem/read.ts +3 -9
- package/src/tools/filesystem/write.ts +3 -9
- package/src/tools/host-filesystem/edit.ts +3 -9
- package/src/tools/host-filesystem/read.ts +3 -9
- package/src/tools/host-filesystem/transfer.ts +3 -9
- package/src/tools/host-filesystem/write.ts +3 -9
- package/src/tools/host-terminal/host-shell.ts +3 -9
- package/src/tools/mcp/mcp-tool-factory.ts +1 -8
- package/src/tools/memory/register.test.ts +1 -1
- package/src/tools/memory/register.ts +4 -9
- package/src/tools/network/web-fetch.ts +3 -9
- package/src/tools/network/web-search.ts +25 -32
- package/src/tools/registry.ts +7 -23
- package/src/tools/schema-transforms.ts +1 -1
- package/src/tools/skills/execute.ts +3 -9
- package/src/tools/skills/load.ts +3 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -8
- package/src/tools/subagent/notify-parent.ts +3 -9
- package/src/tools/system/request-permission.ts +3 -9
- package/src/tools/terminal/shell.ts +3 -9
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/types.ts +27 -98
- package/src/tools/ui-surface/definitions.ts +6 -22
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/logger.ts +16 -7
- package/src/util/platform.ts +7 -2
- package/src/util/sqlite3-runtime.ts +65 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
- package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
- package/src/__tests__/message-complete-display-id.test.ts +0 -175
- package/src/daemon/query-complexity-router.ts +0 -75
- package/src/prompts/cache-boundary.ts +0 -8
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory v3 — Tree structure validator.
|
|
3
|
+
*
|
|
4
|
+
* The v3 tree is hand-authored by a data-migration during the v2 → v3 rollout
|
|
5
|
+
* (nodes reference pages and sub-nodes by `page:`/`node:` refs). Because the
|
|
6
|
+
* structure is authored, not derived, it can drift: a ref can dangle, a page
|
|
7
|
+
* can be left unwired, two nodes can reference each other into a cycle, a
|
|
8
|
+
* parent node's compositional summary can fall behind a freshly-edited child,
|
|
9
|
+
* or a page `edges:` entry can point at a slug with no page.
|
|
10
|
+
*
|
|
11
|
+
* `validateTree` is the read-only report the migration (and any later
|
|
12
|
+
* structure-health probe) runs to surface those defects. It is deliberately
|
|
13
|
+
* **non-throwing**: the migration is in progress, so an incomplete tree is
|
|
14
|
+
* expected — the report is informational, and the caller decides what (if
|
|
15
|
+
* anything) is fatal. It builds the three indices it needs (tree, page, edge),
|
|
16
|
+
* walks the DAG, and returns counts plus the offending ids for each category.
|
|
17
|
+
*
|
|
18
|
+
* Categories:
|
|
19
|
+
* - `danglingChildRefs` — a node `children` entry (`node:`/`page:`) whose
|
|
20
|
+
* target node/page does not exist on disk.
|
|
21
|
+
* - `orphanPages` — concept pages present in the page index but not reachable
|
|
22
|
+
* from the tree root by descending every `node:` child. Informational while
|
|
23
|
+
* the migration is mid-flight (not every page is wired in yet). Synthetic
|
|
24
|
+
* page-index entries (skills, CLI commands) are excluded — they are never
|
|
25
|
+
* tree members.
|
|
26
|
+
* - `cycles` — back-edges found during a full DFS over `node:` adjacency
|
|
27
|
+
* (A → B → A). A cycle would make a naive descent loop forever.
|
|
28
|
+
* - `staleIndex` — a node whose own file mtime predates one of its `node:`
|
|
29
|
+
* children's mtime, hinting its compositional index/summary may be out of
|
|
30
|
+
* date relative to the child it composes.
|
|
31
|
+
* - `unknownEdgeTargets` — page `edges:` targets with no corresponding page
|
|
32
|
+
* index slug, reusing v2's `validateEdgeTargets`.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { CLI_COMMAND_SLUG_PREFIX } from "../v2/cli-command-store.js";
|
|
36
|
+
import { getEdgeIndex, validateEdgeTargets } from "../v2/edge-index.js";
|
|
37
|
+
import { getPageIndex } from "../v2/page-index.js";
|
|
38
|
+
import { SKILL_SLUG_PREFIX } from "../v2/skill-store.js";
|
|
39
|
+
import { getTreeIndex, type TreeIndex } from "./tree-index.js";
|
|
40
|
+
import { getNodeMtimeMs } from "./tree-store.js";
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A `node:` child whose mtime is newer than the parent node that composes it.
|
|
44
|
+
* `node` is the parent, `child` the fresher child, and the two `*MtimeMs`
|
|
45
|
+
* fields are their epoch-ms mtimes (parent < child triggers the report).
|
|
46
|
+
*/
|
|
47
|
+
export interface StaleIndexEntry {
|
|
48
|
+
node: string;
|
|
49
|
+
child: string;
|
|
50
|
+
nodeMtimeMs: number;
|
|
51
|
+
childMtimeMs: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Read-only health report over the v3 tree + its referenced pages/edges.
|
|
56
|
+
* Every list is sorted for deterministic output; `*Count` fields mirror the
|
|
57
|
+
* corresponding list length so callers can summarize without re-counting.
|
|
58
|
+
*/
|
|
59
|
+
export interface TreeValidationReport {
|
|
60
|
+
/** `node:`/`page:` children whose target does not exist. */
|
|
61
|
+
danglingChildRefs: Array<{
|
|
62
|
+
node: string;
|
|
63
|
+
ref: string;
|
|
64
|
+
kind: "node" | "page";
|
|
65
|
+
}>;
|
|
66
|
+
danglingChildRefCount: number;
|
|
67
|
+
/** Concept pages not reachable from the root by descending all node children. */
|
|
68
|
+
orphanPages: string[];
|
|
69
|
+
orphanPageCount: number;
|
|
70
|
+
/** Back-edges (`from → to`) closing a cycle during the full DFS descent. */
|
|
71
|
+
cycles: Array<{ from: string; to: string }>;
|
|
72
|
+
cycleCount: number;
|
|
73
|
+
/** Nodes whose mtime predates a child node's mtime. */
|
|
74
|
+
staleIndex: StaleIndexEntry[];
|
|
75
|
+
staleIndexCount: number;
|
|
76
|
+
/** Page `edges:` targets with no corresponding page-index slug. */
|
|
77
|
+
unknownEdgeTargets: Array<{ from: string; to: string }>;
|
|
78
|
+
unknownEdgeTargetCount: number;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** True when a page-index slug is a synthetic (non-concept-page) entry. */
|
|
82
|
+
function isSyntheticSlug(slug: string): boolean {
|
|
83
|
+
return (
|
|
84
|
+
slug.startsWith(SKILL_SLUG_PREFIX) ||
|
|
85
|
+
slug.startsWith(CLI_COMMAND_SLUG_PREFIX)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Collect dangling `node:`/`page:` child refs: every node child whose target
|
|
91
|
+
* node id is absent from `tree.nodes`, and every page child whose slug is
|
|
92
|
+
* absent from `knownPageSlugs`. Sorted by `(node, kind, ref)`.
|
|
93
|
+
*/
|
|
94
|
+
function collectDanglingChildRefs(
|
|
95
|
+
tree: TreeIndex,
|
|
96
|
+
knownPageSlugs: ReadonlySet<string>,
|
|
97
|
+
): Array<{ node: string; ref: string; kind: "node" | "page" }> {
|
|
98
|
+
const dangling: Array<{ node: string; ref: string; kind: "node" | "page" }> =
|
|
99
|
+
[];
|
|
100
|
+
for (const [nodeId, children] of tree.childrenByNode) {
|
|
101
|
+
for (const child of children) {
|
|
102
|
+
const exists =
|
|
103
|
+
child.kind === "node"
|
|
104
|
+
? tree.nodes.has(child.ref)
|
|
105
|
+
: knownPageSlugs.has(child.ref);
|
|
106
|
+
if (!exists) {
|
|
107
|
+
dangling.push({ node: nodeId, ref: child.ref, kind: child.kind });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
dangling.sort(
|
|
112
|
+
(a, b) =>
|
|
113
|
+
a.node.localeCompare(b.node) ||
|
|
114
|
+
a.kind.localeCompare(b.kind) ||
|
|
115
|
+
a.ref.localeCompare(b.ref),
|
|
116
|
+
);
|
|
117
|
+
return dangling;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Resolve the existing `node:` children of `nodeId`, in `children` order. Refs
|
|
122
|
+
* to absent nodes are skipped (those are reported separately as dangling) so
|
|
123
|
+
* the descent never recurses into a node that isn't on disk.
|
|
124
|
+
*/
|
|
125
|
+
function nodeChildrenOf(tree: TreeIndex, nodeId: string): string[] {
|
|
126
|
+
const children = tree.childrenByNode.get(nodeId) ?? [];
|
|
127
|
+
const out: string[] = [];
|
|
128
|
+
for (const child of children) {
|
|
129
|
+
if (child.kind === "node" && tree.nodes.has(child.ref)) {
|
|
130
|
+
out.push(child.ref);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Full DFS over `node:` adjacency from `tree.root`. Returns the set of
|
|
138
|
+
* reachable node ids (for orphan-page reachability) and the back-edges that
|
|
139
|
+
* close a cycle. A back-edge is an edge into a node still on the active
|
|
140
|
+
* recursion stack (classic gray-node cycle detection); `visited` (black)
|
|
141
|
+
* prevents re-walking shared DAG sub-nodes.
|
|
142
|
+
*/
|
|
143
|
+
function descend(tree: TreeIndex): {
|
|
144
|
+
reachableNodes: Set<string>;
|
|
145
|
+
cycles: Array<{ from: string; to: string }>;
|
|
146
|
+
} {
|
|
147
|
+
const reachableNodes = new Set<string>();
|
|
148
|
+
const onStack = new Set<string>();
|
|
149
|
+
const cycles: Array<{ from: string; to: string }> = [];
|
|
150
|
+
|
|
151
|
+
// Iterative DFS with an explicit stack so deep trees don't blow the call
|
|
152
|
+
// stack. Each frame tracks its child cursor; we push a child frame, and on
|
|
153
|
+
// exhaustion pop the parent off the recursion stack (`onStack`).
|
|
154
|
+
type Frame = { node: string; children: string[]; cursor: number };
|
|
155
|
+
const stack: Frame[] = [];
|
|
156
|
+
|
|
157
|
+
function enter(nodeId: string): void {
|
|
158
|
+
reachableNodes.add(nodeId);
|
|
159
|
+
onStack.add(nodeId);
|
|
160
|
+
stack.push({
|
|
161
|
+
node: nodeId,
|
|
162
|
+
children: nodeChildrenOf(tree, nodeId),
|
|
163
|
+
cursor: 0,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (tree.nodes.has(tree.root)) {
|
|
168
|
+
enter(tree.root);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
while (stack.length > 0) {
|
|
172
|
+
const frame = stack[stack.length - 1];
|
|
173
|
+
if (frame.cursor >= frame.children.length) {
|
|
174
|
+
onStack.delete(frame.node);
|
|
175
|
+
stack.pop();
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const child = frame.children[frame.cursor++];
|
|
179
|
+
if (onStack.has(child)) {
|
|
180
|
+
// Edge into an ancestor still on the stack → cycle-closing back-edge.
|
|
181
|
+
cycles.push({ from: frame.node, to: child });
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (reachableNodes.has(child)) {
|
|
185
|
+
// Already fully explored via another parent (shared DAG sub-node).
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
enter(child);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
cycles.sort(
|
|
192
|
+
(a, b) => a.from.localeCompare(b.from) || a.to.localeCompare(b.to),
|
|
193
|
+
);
|
|
194
|
+
return { reachableNodes, cycles };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Concept pages reachable from the tree: every `page:` child of a reachable
|
|
199
|
+
* node. Pages hanging off unreachable nodes are *not* counted reachable — they
|
|
200
|
+
* only become reachable once their parent chain links back to the root.
|
|
201
|
+
*/
|
|
202
|
+
function reachablePages(
|
|
203
|
+
tree: TreeIndex,
|
|
204
|
+
reachableNodes: ReadonlySet<string>,
|
|
205
|
+
): Set<string> {
|
|
206
|
+
const pages = new Set<string>();
|
|
207
|
+
for (const nodeId of reachableNodes) {
|
|
208
|
+
for (const child of tree.childrenByNode.get(nodeId) ?? []) {
|
|
209
|
+
if (child.kind === "page") pages.add(child.ref);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return pages;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Nodes whose own mtime predates one of their `node:` children's mtime. A
|
|
217
|
+
* missing node file reads as mtime 0 (oldest), so the check never flags a
|
|
218
|
+
* parent against an absent child. Sorted by `(node, child)`.
|
|
219
|
+
*/
|
|
220
|
+
async function collectStaleIndex(
|
|
221
|
+
workspaceDir: string,
|
|
222
|
+
tree: TreeIndex,
|
|
223
|
+
): Promise<StaleIndexEntry[]> {
|
|
224
|
+
const ids = [...tree.nodes.keys()];
|
|
225
|
+
const mtimes = new Map<string, number>();
|
|
226
|
+
await Promise.all(
|
|
227
|
+
ids.map(async (id) => {
|
|
228
|
+
mtimes.set(id, await getNodeMtimeMs(workspaceDir, id));
|
|
229
|
+
}),
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
const stale: StaleIndexEntry[] = [];
|
|
233
|
+
for (const node of ids) {
|
|
234
|
+
const nodeMtimeMs = mtimes.get(node) ?? 0;
|
|
235
|
+
for (const child of nodeChildrenOf(tree, node)) {
|
|
236
|
+
const childMtimeMs = mtimes.get(child) ?? 0;
|
|
237
|
+
if (nodeMtimeMs < childMtimeMs) {
|
|
238
|
+
stale.push({ node, child, nodeMtimeMs, childMtimeMs });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
stale.sort(
|
|
243
|
+
(a, b) => a.node.localeCompare(b.node) || a.child.localeCompare(b.child),
|
|
244
|
+
);
|
|
245
|
+
return stale;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Validate the hand-authored v3 tree structure for `workspaceDir` and return a
|
|
250
|
+
* {@link TreeValidationReport}. Builds the tree, page, and edge indices, walks
|
|
251
|
+
* the DAG from the root, and reports the five defect categories. Never throws —
|
|
252
|
+
* it is a report, not an assertion.
|
|
253
|
+
*/
|
|
254
|
+
export async function validateTree(
|
|
255
|
+
workspaceDir: string,
|
|
256
|
+
): Promise<TreeValidationReport> {
|
|
257
|
+
const [tree, pageIndex, edgeIndex] = await Promise.all([
|
|
258
|
+
getTreeIndex(workspaceDir),
|
|
259
|
+
getPageIndex(workspaceDir),
|
|
260
|
+
getEdgeIndex(workspaceDir),
|
|
261
|
+
]);
|
|
262
|
+
|
|
263
|
+
const knownPageSlugs = new Set(pageIndex.bySlug.keys());
|
|
264
|
+
|
|
265
|
+
// Kick off the stale-index mtime stats up front — it only depends on the
|
|
266
|
+
// tree, not on the DAG walk below — so its filesystem reads overlap the
|
|
267
|
+
// (synchronous) descent rather than running strictly after it.
|
|
268
|
+
const staleIndexPromise = collectStaleIndex(workspaceDir, tree);
|
|
269
|
+
|
|
270
|
+
const danglingChildRefs = collectDanglingChildRefs(tree, knownPageSlugs);
|
|
271
|
+
|
|
272
|
+
const { reachableNodes, cycles } = descend(tree);
|
|
273
|
+
|
|
274
|
+
const reached = reachablePages(tree, reachableNodes);
|
|
275
|
+
const orphanPages = [...knownPageSlugs]
|
|
276
|
+
.filter((slug) => !isSyntheticSlug(slug) && !reached.has(slug))
|
|
277
|
+
.sort();
|
|
278
|
+
|
|
279
|
+
const staleIndex = await staleIndexPromise;
|
|
280
|
+
|
|
281
|
+
// Edge graph is page-only; knownSlugs is the full page-index slug set so an
|
|
282
|
+
// edge pointing at a skill/CLI entry is not spuriously flagged unknown.
|
|
283
|
+
const unknownEdgeTargets = validateEdgeTargets(
|
|
284
|
+
edgeIndex,
|
|
285
|
+
knownPageSlugs,
|
|
286
|
+
).missing;
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
danglingChildRefs,
|
|
290
|
+
danglingChildRefCount: danglingChildRefs.length,
|
|
291
|
+
orphanPages,
|
|
292
|
+
orphanPageCount: orphanPages.length,
|
|
293
|
+
cycles,
|
|
294
|
+
cycleCount: cycles.length,
|
|
295
|
+
staleIndex,
|
|
296
|
+
staleIndexCount: staleIndex.length,
|
|
297
|
+
unknownEdgeTargets,
|
|
298
|
+
unknownEdgeTargetCount: unknownEdgeTargets.length,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* does not match their own identity.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
import type { InterfaceId } from "../../channels/types.js";
|
|
21
22
|
import type { ServerMessage } from "../../daemon/message-protocol.js";
|
|
22
23
|
import { getLogger } from "../../util/logger.js";
|
|
23
24
|
import type {
|
|
@@ -30,7 +31,23 @@ import type {
|
|
|
30
31
|
|
|
31
32
|
const log = getLogger("notif-adapter-vellum");
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Optional targeting/filtering applied at the hub when a broadcast is
|
|
36
|
+
* emitted. Mirrors the third argument of
|
|
37
|
+
* `broadcastMessage()` in `runtime/assistant-event-hub.ts`. Callers can
|
|
38
|
+
* use `targetInterfaceId` to scope a legacy message to a single client
|
|
39
|
+
* surface (e.g. macOS) during a migration window.
|
|
40
|
+
*/
|
|
41
|
+
export interface BroadcastFnOptions {
|
|
42
|
+
targetClientId?: string;
|
|
43
|
+
targetInterfaceId?: InterfaceId;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type BroadcastFn = (
|
|
47
|
+
msg: ServerMessage,
|
|
48
|
+
conversationId?: string,
|
|
49
|
+
options?: BroadcastFnOptions,
|
|
50
|
+
) => void;
|
|
34
51
|
|
|
35
52
|
/**
|
|
36
53
|
* Event name prefixes that carry guardian-sensitive content (approval
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* POSTs a `notification_intent` payload to
|
|
6
6
|
* `/v1/assistants/{id}/push/dispatch/`. The platform endpoint fans the
|
|
7
7
|
* notification out to all registered device tokens for the bound user and
|
|
8
|
-
* gates on the `ios-remote-push-enabled`
|
|
8
|
+
* gates on the `ios-remote-push-enabled` feature flag server-side (returning 202
|
|
9
9
|
* with `{ skipped: "flag_off" }` when the flag is OFF — no action needed
|
|
10
10
|
* from the daemon).
|
|
11
11
|
*
|
|
@@ -13,7 +13,6 @@ import { v4 as uuid } from "uuid";
|
|
|
13
13
|
|
|
14
14
|
import { getDeliverableChannels } from "../channels/config.js";
|
|
15
15
|
import { listGuardianChannels } from "../contacts/contact-store.js";
|
|
16
|
-
import { resolveGuardianPersona } from "../prompts/persona-resolver.js";
|
|
17
16
|
import { buildCoreIdentityContext } from "../prompts/system-prompt.js";
|
|
18
17
|
import {
|
|
19
18
|
createTimeout,
|
|
@@ -921,9 +920,7 @@ async function classifyWithLLM(
|
|
|
921
920
|
const candidateContext = candidateSet
|
|
922
921
|
? (serializeCandidatesForPrompt(candidateSet) ?? undefined)
|
|
923
922
|
: undefined;
|
|
924
|
-
const rawIdentityContext = buildCoreIdentityContext(
|
|
925
|
-
userPersona: resolveGuardianPersona(),
|
|
926
|
-
});
|
|
923
|
+
const rawIdentityContext = buildCoreIdentityContext();
|
|
927
924
|
const identityContext = rawIdentityContext
|
|
928
925
|
? truncate(rawIdentityContext, MAX_IDENTITY_CONTEXT_CHARS, "\n…[truncated]")
|
|
929
926
|
: undefined;
|
|
@@ -14,8 +14,9 @@ import { v4 as uuid } from "uuid";
|
|
|
14
14
|
import { getDeliverableChannels } from "../channels/config.js";
|
|
15
15
|
import { findGuardianForChannel } from "../contacts/contact-store.js";
|
|
16
16
|
import type { ConversationCreateType } from "../memory/conversation-crud.js";
|
|
17
|
+
import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
17
18
|
import { getLogger } from "../util/logger.js";
|
|
18
|
-
import {
|
|
19
|
+
import { VellumAdapter } from "./adapters/macos.js";
|
|
19
20
|
import { PlatformPushAdapter } from "./adapters/platform.js";
|
|
20
21
|
import { SlackAdapter } from "./adapters/slack.js";
|
|
21
22
|
import { TelegramAdapter } from "./adapters/telegram.js";
|
|
@@ -49,56 +50,38 @@ const log = getLogger("emit-signal");
|
|
|
49
50
|
// ── Broadcaster singleton ──────────────────────────────────────────────
|
|
50
51
|
|
|
51
52
|
let broadcasterInstance: NotificationBroadcaster | null = null;
|
|
52
|
-
let registeredBroadcastFn: BroadcastFn | null = null;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Register the broadcast function so the vellum adapter can deliver
|
|
56
|
-
* notifications to connected clients. Must be called once during
|
|
57
|
-
* daemon startup (before any signals are emitted).
|
|
58
|
-
*/
|
|
59
|
-
export function registerBroadcastFn(fn: BroadcastFn): void {
|
|
60
|
-
registeredBroadcastFn = fn;
|
|
61
|
-
// Reset the broadcaster so it picks up the new broadcast function
|
|
62
|
-
broadcasterInstance = null;
|
|
63
|
-
}
|
|
64
53
|
|
|
65
54
|
function getBroadcaster(): NotificationBroadcaster {
|
|
66
55
|
if (!broadcasterInstance) {
|
|
67
|
-
|
|
56
|
+
broadcasterInstance = new NotificationBroadcaster([
|
|
57
|
+
new VellumAdapter(broadcastMessage),
|
|
68
58
|
new TelegramAdapter(),
|
|
69
59
|
new SlackAdapter(),
|
|
70
60
|
new PlatformPushAdapter(),
|
|
71
|
-
];
|
|
72
|
-
if (registeredBroadcastFn) {
|
|
73
|
-
adapters.unshift(new VellumAdapter(registeredBroadcastFn));
|
|
74
|
-
}
|
|
75
|
-
broadcasterInstance = new NotificationBroadcaster(adapters);
|
|
61
|
+
]);
|
|
76
62
|
|
|
77
63
|
// Wire the conversation-created callback so the macOS client is notified
|
|
78
64
|
// immediately when a vellum notification conversation is paired — before
|
|
79
65
|
// slower channel deliveries (e.g. Telegram) delay the push.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
source: info.source,
|
|
91
|
-
silent: info.silent,
|
|
92
|
-
});
|
|
93
|
-
log.info(
|
|
94
|
-
{
|
|
95
|
-
conversationId: info.conversationId,
|
|
96
|
-
guardianScoped: info.targetGuardianPrincipalId != null,
|
|
97
|
-
},
|
|
98
|
-
"Emitted notification_conversation_created push event",
|
|
99
|
-
);
|
|
66
|
+
broadcasterInstance.setOnConversationCreated((info) => {
|
|
67
|
+
broadcastMessage({
|
|
68
|
+
type: "notification_conversation_created",
|
|
69
|
+
conversationId: info.conversationId,
|
|
70
|
+
title: info.title,
|
|
71
|
+
sourceEventName: info.sourceEventName,
|
|
72
|
+
targetGuardianPrincipalId: info.targetGuardianPrincipalId,
|
|
73
|
+
groupId: info.groupId,
|
|
74
|
+
source: info.source,
|
|
75
|
+
silent: info.silent,
|
|
100
76
|
});
|
|
101
|
-
|
|
77
|
+
log.info(
|
|
78
|
+
{
|
|
79
|
+
conversationId: info.conversationId,
|
|
80
|
+
guardianScoped: info.targetGuardianPrincipalId != null,
|
|
81
|
+
},
|
|
82
|
+
"Emitted notification_conversation_created push event",
|
|
83
|
+
);
|
|
84
|
+
});
|
|
102
85
|
}
|
|
103
86
|
return broadcasterInstance;
|
|
104
87
|
}
|
|
@@ -115,18 +98,15 @@ function getConnectedChannels(): NotificationChannel[] {
|
|
|
115
98
|
switch (channel) {
|
|
116
99
|
case "vellum":
|
|
117
100
|
// Vellum is always considered connected (the local transport is
|
|
118
|
-
// always available when the
|
|
101
|
+
// always available when the assistant is running).
|
|
119
102
|
channels.push(channel);
|
|
120
103
|
break;
|
|
121
104
|
case "platform":
|
|
122
|
-
// Platform push is connected
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
if (registeredBroadcastFn) {
|
|
128
|
-
channels.push(channel);
|
|
129
|
-
}
|
|
105
|
+
// Platform push is treated as connected at the decision-engine
|
|
106
|
+
// layer; the actual delivery path lazily resolves
|
|
107
|
+
// `VellumPlatformClient.create()` in `PlatformPushAdapter.send()`
|
|
108
|
+
// and reports a delivery failure when credentials are absent.
|
|
109
|
+
channels.push(channel);
|
|
130
110
|
break;
|
|
131
111
|
case "telegram": {
|
|
132
112
|
// A binding-based channel is connected when the guardian has an
|
|
@@ -79,7 +79,7 @@ export class PermissionPrompter {
|
|
|
79
79
|
const timeoutMs = getConfig().timeouts.permissionTimeoutSec * 1000;
|
|
80
80
|
|
|
81
81
|
const timer = setTimeout(() => {
|
|
82
|
-
const interaction = pendingInteractions.resolve(requestId);
|
|
82
|
+
const interaction = pendingInteractions.resolve(requestId, "cancelled");
|
|
83
83
|
this.ownedIds.delete(requestId);
|
|
84
84
|
log.warn(
|
|
85
85
|
{ requestId, toolName },
|
|
@@ -130,7 +130,7 @@ export class PermissionPrompter {
|
|
|
130
130
|
if (signal) {
|
|
131
131
|
const onAbort = () => {
|
|
132
132
|
if (this.ownedIds.has(requestId)) {
|
|
133
|
-
pendingInteractions.resolve(requestId);
|
|
133
|
+
pendingInteractions.resolve(requestId, "cancelled");
|
|
134
134
|
this.ownedIds.delete(requestId);
|
|
135
135
|
resolve({ decision: "deny", wasAbort: true });
|
|
136
136
|
}
|
|
@@ -232,7 +232,7 @@ export class PermissionPrompter {
|
|
|
232
232
|
|
|
233
233
|
dispose(): void {
|
|
234
234
|
for (const requestId of [...this.ownedIds]) {
|
|
235
|
-
const interaction = pendingInteractions.resolve(requestId);
|
|
235
|
+
const interaction = pendingInteractions.resolve(requestId, "cancelled");
|
|
236
236
|
this.ownedIds.delete(requestId);
|
|
237
237
|
interaction?.rpcReject?.(
|
|
238
238
|
new AssistantError("Prompter disposed", ErrorCode.INTERNAL_ERROR),
|
|
@@ -223,8 +223,11 @@ export class QuestionPrompter {
|
|
|
223
223
|
signal.removeEventListener("abort", onAbort);
|
|
224
224
|
}
|
|
225
225
|
// Idempotent: a no-op if the entry was already removed (e.g. by
|
|
226
|
-
// `removeByConversation`) or by an earlier path.
|
|
227
|
-
|
|
226
|
+
// `removeByConversation`) or by an earlier path. The route's
|
|
227
|
+
// success path resolves with "answered" before invoking rpcResolve,
|
|
228
|
+
// so this fallback only fires for timeout / abort / removeByConversation —
|
|
229
|
+
// all cancellation-shaped outcomes.
|
|
230
|
+
pendingInteractions.resolve(requestId, "cancelled");
|
|
228
231
|
fn();
|
|
229
232
|
};
|
|
230
233
|
|
|
@@ -71,7 +71,7 @@ export class SecretPrompter {
|
|
|
71
71
|
const timeoutMs = getConfig().timeouts.permissionTimeoutSec * 1000;
|
|
72
72
|
|
|
73
73
|
const timer = setTimeout(() => {
|
|
74
|
-
pendingInteractions.resolve(requestId);
|
|
74
|
+
pendingInteractions.resolve(requestId, "cancelled");
|
|
75
75
|
this.ownedIds.delete(requestId);
|
|
76
76
|
log.warn({ requestId, service, field }, "Secret prompt timed out");
|
|
77
77
|
resolve({ value: null, delivery: "store" });
|
|
@@ -142,7 +142,7 @@ export class SecretPrompter {
|
|
|
142
142
|
|
|
143
143
|
dispose(): void {
|
|
144
144
|
for (const requestId of [...this.ownedIds]) {
|
|
145
|
-
const interaction = pendingInteractions.resolve(requestId);
|
|
145
|
+
const interaction = pendingInteractions.resolve(requestId, "cancelled");
|
|
146
146
|
this.ownedIds.delete(requestId);
|
|
147
147
|
interaction?.rpcReject?.(
|
|
148
148
|
new AssistantError("Prompter disposed", ErrorCode.INTERNAL_ERROR),
|
package/src/plugin-api/index.ts
CHANGED
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
* - {@link UserPromptSubmitContext} — passed to `user-prompt-submit` hook,
|
|
26
26
|
* fired immediately before the agent loop receives a user's prompt
|
|
27
27
|
* - {@link PluginLogger} — pino-compatible logger shape on the contexts
|
|
28
|
+
* - {@link ToolDefinition} — author-facing tool spec (default-export shape
|
|
29
|
+
* for both plugin tool files and workspace tool files)
|
|
28
30
|
* - {@link ToolContext} — passed to a plugin tool's `execute` method
|
|
29
31
|
* - {@link ToolExecutionResult} — return shape of a plugin tool's `execute`
|
|
30
32
|
*
|
|
@@ -41,6 +43,8 @@ export type {
|
|
|
41
43
|
PluginLogger,
|
|
42
44
|
PluginShutdownContext,
|
|
43
45
|
ToolContext,
|
|
46
|
+
ToolDefinition,
|
|
44
47
|
ToolExecutionResult,
|
|
45
48
|
UserPromptSubmitContext,
|
|
46
49
|
} from "./types.js";
|
|
50
|
+
export { RiskLevel } from "./types.js";
|
package/src/plugin-api/types.ts
CHANGED
|
@@ -1,43 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Public plugin-API types
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* from `@vellumai/plugin-api`. The shapes here are the canonical public
|
|
6
|
-
* contract — anything exported is part of the surface that semver gates.
|
|
7
|
-
*
|
|
8
|
-
* ## Tool-execution types
|
|
9
|
-
*
|
|
10
|
-
* `ToolContext` and `ToolExecutionResult` are re-exports of the narrow,
|
|
11
|
-
* stable bases defined alongside their daemon-internal counterparts in
|
|
12
|
-
* `assistant/src/tools/types.ts`. The daemon-internal `ToolContext` /
|
|
13
|
-
* `ToolExecutionResult` (with CES, trust classification, lifecycle
|
|
14
|
-
* events, sensitive-output bindings, risk metadata, etc.) `extends`
|
|
15
|
-
* the public bases, so the runtime can hand plugins the full value
|
|
16
|
-
* without a manual cast and tsc enforces the structural relationship.
|
|
17
|
-
* Plugin tools see the narrow surface only — they MUST NOT set fields
|
|
18
|
-
* that belong to the daemon-internal extension.
|
|
19
|
-
*
|
|
20
|
-
* ## Hook contexts
|
|
21
|
-
*
|
|
22
|
-
* The init / shutdown hook contexts are owned by this module directly.
|
|
23
|
-
* They have no daemon-internal extension today (the daemon constructs
|
|
24
|
-
* and hands them straight through), so there's nothing to inherit from.
|
|
25
|
-
*
|
|
26
|
-
* ## Compatibility
|
|
27
|
-
*
|
|
28
|
-
* Adding fields to any public shape is non-breaking. Renaming or
|
|
29
|
-
* removing fields is breaking and gated on a major bump of
|
|
30
|
-
* `@vellumai/plugin-api`.
|
|
2
|
+
* Public plugin-API types — the canonical contract for
|
|
3
|
+
* `@vellumai/plugin-api`. Adding fields is non-breaking; renaming /
|
|
4
|
+
* removing is breaking and gated on a major bump.
|
|
31
5
|
*/
|
|
32
6
|
|
|
33
7
|
import type { Message } from "../providers/types.js";
|
|
34
8
|
|
|
35
|
-
// ─── Tool-execution types (re-exported from daemon source-of-truth) ──────────
|
|
36
|
-
|
|
37
9
|
export type {
|
|
38
|
-
|
|
39
|
-
|
|
10
|
+
ToolContext,
|
|
11
|
+
ToolDefinition,
|
|
12
|
+
ToolExecutionResult,
|
|
40
13
|
} from "../tools/types.js";
|
|
14
|
+
export { RiskLevel } from "../tools/types.js";
|
|
41
15
|
|
|
42
16
|
// ─── Logger ──────────────────────────────────────────────────────────────────
|
|
43
17
|
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* chain) does not trip a TDZ.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
+
import { memoryV3ShadowPlugin } from "../../memory/v3/shadow-middleware.js";
|
|
27
28
|
import { registerPlugin, resetPluginRegistryForTests } from "../registry.js";
|
|
28
29
|
import { type Plugin, PluginExecutionError } from "../types.js";
|
|
29
30
|
import { defaultCircuitBreakerPlugin } from "./circuit-breaker.js";
|
|
@@ -60,6 +61,11 @@ function getAllDefaultPlugins(): readonly Plugin[] {
|
|
|
60
61
|
defaultEmptyResponsePlugin,
|
|
61
62
|
defaultToolErrorPlugin,
|
|
62
63
|
defaultMemoryRetrievalPlugin,
|
|
64
|
+
// Live-shadow v3 retrieval. Always registered; inert unless both
|
|
65
|
+
// `memory.v3.enabled` and `memory.v3.shadow` are on (gated inside the
|
|
66
|
+
// middleware). Ordered after the default so the default terminal still
|
|
67
|
+
// produces the injected (v2) `MemoryResult`.
|
|
68
|
+
memoryV3ShadowPlugin,
|
|
63
69
|
defaultInjectorsPlugin,
|
|
64
70
|
defaultTokenEstimatePlugin,
|
|
65
71
|
defaultOverflowReducePlugin,
|