@vellumai/assistant 0.8.4 → 0.8.6
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/AGENTS.md +33 -1
- package/ARCHITECTURE.md +3 -3
- package/bunfig.toml +6 -1
- package/docs/browser-use-architecture-phase2.md +1 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +4 -3
- package/knip.json +2 -1
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
- package/openapi.yaml +2748 -216
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +3 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
- package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/annotate-risk-options.test.ts +1 -0
- package/src/__tests__/anthropic-provider.test.ts +34 -37
- package/src/__tests__/approval-cascade.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +9 -13
- package/src/__tests__/assert-not-live-db.ts +79 -0
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +12 -28
- package/src/__tests__/audit-log-rotation.test.ts +72 -18
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/background-workers-disk-pressure.test.ts +8 -11
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +5 -5
- package/src/__tests__/call-controller.test.ts +3 -3
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +3 -2
- package/src/__tests__/channel-guardian.test.ts +6 -5
- package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
- package/src/__tests__/channel-reply-delivery.test.ts +35 -0
- package/src/__tests__/channel-retry-sweep.test.ts +320 -3
- package/src/__tests__/checker.test.ts +18 -27
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/compaction-trail-store.test.ts +264 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +215 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -16
- package/src/__tests__/computer-use-tools.test.ts +14 -18
- package/src/__tests__/config-loader-backfill.test.ts +13 -28
- package/src/__tests__/config-loader-corrupt.test.ts +5 -5
- package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
- package/src/__tests__/config-schema.test.ts +10 -10
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/connection-model-compat.test.ts +83 -0
- package/src/__tests__/contacts-tools.test.ts +3 -2
- package/src/__tests__/context-token-estimator.test.ts +22 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -1
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +231 -2
- package/src/__tests__/conversation-agent-loop.test.ts +581 -54
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
- package/src/__tests__/conversation-app-control-instantiation.test.ts +31 -24
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-attention-store.test.ts +101 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
- package/src/__tests__/conversation-clear-safety.test.ts +25 -25
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
- 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 +61 -0
- package/src/__tests__/conversation-fork-crud.test.ts +239 -15
- package/src/__tests__/conversation-fork-route.test.ts +3 -2
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
- package/src/__tests__/conversation-lifecycle.test.ts +53 -11
- package/src/__tests__/conversation-list-source.test.ts +3 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
- package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +14 -13
- package/src/__tests__/conversation-pairing.test.ts +53 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
- package/src/__tests__/conversation-process-callsite.test.ts +1 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-queue.test.ts +333 -291
- package/src/__tests__/conversation-routes-disk-view.test.ts +112 -18
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
- package/src/__tests__/conversation-routes-slash-commands.test.ts +68 -2
- package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
- package/src/__tests__/conversation-skill-tools.test.ts +40 -147
- package/src/__tests__/conversation-slash-queue.test.ts +84 -32
- package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
- package/src/__tests__/conversation-speed-override.test.ts +1 -0
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
- package/src/__tests__/conversation-sync-tags.test.ts +218 -35
- package/src/__tests__/conversation-title-service.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
- package/src/__tests__/conversation-usage.test.ts +1 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -1
- package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
- package/src/__tests__/credential-broker-server-use.test.ts +5 -5
- package/src/__tests__/credential-execution-client.test.ts +72 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +19 -19
- package/src/__tests__/credential-execution-tools.test.ts +6 -6
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +6 -5
- package/src/__tests__/credential-vault-unit.test.ts +21 -21
- package/src/__tests__/credential-vault.test.ts +5 -5
- package/src/__tests__/cross-provider-web-search.test.ts +56 -2
- package/src/__tests__/db-connection-isolation.test.ts +7 -6
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
- package/src/__tests__/db-test-helpers.ts +58 -0
- package/src/__tests__/disk-pressure-guard.test.ts +58 -41
- package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
- package/src/__tests__/disk-pressure-routes.test.ts +0 -33
- package/src/__tests__/disk-pressure-tools.test.ts +0 -4
- package/src/__tests__/dm-persistence.test.ts +26 -40
- package/src/__tests__/document-create-dedupe.test.ts +189 -0
- package/src/__tests__/document-find-replace.test.ts +3 -2
- package/src/__tests__/document-tool-security.test.ts +81 -2
- package/src/__tests__/dynamic-page-surface.test.ts +2 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
- package/src/__tests__/encrypted-store.test.ts +11 -9
- package/src/__tests__/feature-flag-test-helpers.ts +53 -0
- package/src/__tests__/filing-service.test.ts +1 -0
- package/src/__tests__/first-greeting.test.ts +62 -12
- package/src/__tests__/gateway-flag-listener.test.ts +236 -0
- package/src/__tests__/gemini-provider.test.ts +104 -0
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +10 -7
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +5 -0
- package/src/__tests__/heartbeat-service.test.ts +5 -0
- package/src/__tests__/helpers/mock-logger.ts +26 -0
- package/src/__tests__/host-bash-routes.test.ts +1 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-shell-tool.test.ts +6 -5
- package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +29 -7
- package/src/__tests__/identity-intro-cache.test.ts +133 -22
- package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
- package/src/__tests__/inference-profile-reaper.test.ts +3 -2
- package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
- package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
- package/src/__tests__/injector-disk-pressure.test.ts +3 -17
- package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
- package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
- package/src/__tests__/llm-context-normalization.test.ts +42 -0
- 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 +408 -9
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- package/src/__tests__/logger.test.ts +89 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +16 -2
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- package/src/__tests__/media-generate-image.test.ts +31 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
- package/src/__tests__/messaging-send-tool.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +18 -2
- package/src/__tests__/model-intents.test.ts +4 -6
- package/src/__tests__/native-web-search.test.ts +30 -2
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/oauth-commands-routes.test.ts +37 -0
- package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
- package/src/__tests__/oauth-store.test.ts +3 -2
- package/src/__tests__/onboarding-template-contract.test.ts +4 -3
- package/src/__tests__/openai-provider.test.ts +54 -9
- package/src/__tests__/openai-responses-provider.test.ts +176 -14
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
- package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
- package/src/__tests__/persistence-pipeline.test.ts +139 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
- 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 +11 -13
- package/src/__tests__/plugin-tool-contribution.test.ts +50 -40
- 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__/process-message-background-slack.test.ts +21 -16
- package/src/__tests__/process-message-display-content.test.ts +19 -22
- package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
- package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
- package/src/__tests__/provider-registry-ollama.test.ts +45 -22
- package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
- package/src/__tests__/recording-handler.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +84 -84
- package/src/__tests__/relay-server.test.ts +10 -10
- package/src/__tests__/require-fresh-approval.test.ts +2 -2
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
- package/src/__tests__/schedule-store.test.ts +16 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
- package/src/__tests__/secret-ingress-http.test.ts +5 -1
- package/src/__tests__/secure-keys.test.ts +3 -3
- package/src/__tests__/send-endpoint-busy.test.ts +81 -42
- package/src/__tests__/server-history-render.test.ts +4 -1
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
- package/src/__tests__/skill-feature-flags.test.ts +16 -18
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
- package/src/__tests__/skill-projection-feature-flag.test.ts +48 -37
- package/src/__tests__/skill-projection.benchmark.test.ts +7 -13
- package/src/__tests__/skill-tool-factory.test.ts +97 -96
- package/src/__tests__/slack-channel-config.test.ts +3 -3
- package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
- package/src/__tests__/subagent-disposal.test.ts +27 -8
- package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
- package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
- package/src/__tests__/subagent-manager-notify.test.ts +20 -8
- package/src/__tests__/subagent-notify-parent.test.ts +6 -5
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
- package/src/__tests__/subagent-tools.test.ts +2 -1
- package/src/__tests__/suggestion-routes.test.ts +2 -0
- package/src/__tests__/sync-message-contract.test.ts +59 -0
- package/src/__tests__/system-prompt.test.ts +183 -131
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- 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 +35 -12
- package/src/__tests__/tool-executor.test.ts +64 -72
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- 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__/twilio-routes.test.ts +3 -2
- package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
- package/src/__tests__/usage-routes.test.ts +3 -0
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +3 -2
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
- package/src/__tests__/voice-session-bridge.test.ts +37 -28
- 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/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
- package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -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 +6 -7
- package/src/agent/loop.ts +88 -0
- package/src/api/README.md +127 -0
- package/src/api/constants/call-sites.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +51 -0
- package/src/api/events/assistant-text-delta.ts +32 -0
- package/src/api/events/assistant-turn-start.ts +33 -0
- package/src/api/events/document-comment-created.ts +48 -0
- package/src/api/events/document-comment-deleted.ts +24 -0
- package/src/api/events/document-comment-reopened.ts +25 -0
- package/src/api/events/document-comment-resolved.ts +27 -0
- package/src/api/events/generation-cancelled.ts +24 -0
- package/src/api/events/generation-handoff.ts +41 -0
- package/src/api/events/message-complete.ts +42 -0
- package/src/api/events/open-url.ts +30 -0
- package/src/api/events/relationship-state-updated.ts +25 -0
- package/src/api/events/tool-use-start.ts +32 -0
- package/src/api/index.ts +129 -0
- package/src/api/package.json +10 -0
- package/src/api/responses/llm-context-response.ts +39 -0
- package/src/api/responses/llm-request-log-entry.ts +93 -0
- package/src/api/responses/memory-recall-log.ts +65 -0
- package/src/api/responses/memory-v2-activation-log.ts +78 -0
- package/src/background-wake/background-wake-routes.test.ts +868 -0
- package/src/background-wake/platform-client.test.ts +308 -0
- package/src/background-wake/platform-client.ts +167 -0
- package/src/background-wake/publisher.ts +91 -0
- package/src/background-wake/runtime-registry.ts +24 -0
- package/src/background-wake/wake-intent-hooks.test.ts +282 -0
- package/src/calls/guardian-dispatch.ts +1 -0
- package/src/calls/voice-session-bridge.ts +4 -4
- package/src/cli/commands/__tests__/browser.test.ts +23 -5
- package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
- 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/__tests__/notifications.test.ts +184 -40
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -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 +491 -0
- package/src/cli/commands/memory-v3.ts +567 -0
- package/src/cli/commands/notifications.ts +365 -55
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +4 -0
- package/src/config/assistant-feature-flags.ts +39 -46
- package/src/config/bundled-skills/document-editor/SKILL.md +16 -3
- 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-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/call-site-defaults.ts +8 -7
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +33 -17
- package/src/config/llm-context-resolution.ts +10 -1
- package/src/config/llm-resolver.ts +121 -15
- package/src/config/loader.ts +4 -5
- package/src/config/schemas/__tests__/memory-v2.test.ts +228 -1
- package/src/config/schemas/call-site-catalog.ts +21 -7
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +102 -2
- package/src/config/schemas/memory-v2.ts +272 -0
- package/src/config/schemas/memory.ts +2 -1
- package/src/config/schemas/services.ts +6 -2
- package/src/config/seed-inference-profiles.ts +36 -16
- package/src/context/compactor.ts +52 -0
- package/src/context/token-estimator.ts +10 -5
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- package/src/credential-execution/executable-discovery.ts +40 -0
- package/src/credential-execution/process-manager.ts +6 -2
- package/src/credential-health/credential-health-service.ts +125 -40
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +2 -3
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +390 -80
- package/src/daemon/conversation-agent-loop.ts +244 -90
- package/src/daemon/conversation-error.ts +64 -6
- package/src/daemon/conversation-lifecycle.ts +27 -22
- package/src/daemon/conversation-messaging.ts +84 -43
- package/src/daemon/conversation-process.ts +74 -37
- package/src/daemon/conversation-runtime-assembly.ts +38 -17
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-surfaces.ts +69 -34
- package/src/daemon/conversation-tool-setup.ts +77 -32
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +40 -75
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +9 -2
- package/src/daemon/disk-pressure-guard.ts +39 -29
- package/src/daemon/first-greeting.ts +31 -13
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +11 -3
- package/src/daemon/handlers/shared.ts +6 -1
- 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 +29 -26
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +11 -24
- package/src/daemon/message-types/conversations.ts +22 -27
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/home.ts +2 -14
- package/src/daemon/message-types/integrations.ts +2 -7
- package/src/daemon/message-types/messages.ts +25 -48
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/message-types/sync.ts +14 -0
- package/src/daemon/process-message.ts +9 -9
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +16 -0
- package/src/daemon/shutdown-handlers.ts +24 -5
- package/src/daemon/switch-inference-profile-tool.ts +62 -0
- package/src/daemon/tool-setup-types.ts +7 -0
- package/src/daemon/wake-target-adapter.ts +10 -0
- package/src/documents/document-store.ts +38 -0
- package/src/export/__tests__/transcript-formatter.test.ts +1 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +30 -1
- package/src/heartbeat/heartbeat-service.ts +63 -0
- package/src/home/__tests__/feed-writer.test.ts +161 -0
- package/src/home/__tests__/post-connect-feed.test.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +55 -59
- package/src/home/feed-writer.ts +146 -7
- package/src/home/home-greeting.ts +0 -9
- package/src/home/suggested-prompts.ts +27 -154
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/gateway-client.test.ts +4 -1
- package/src/ipc/gateway-flag-listener.ts +123 -0
- package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
- package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
- package/src/ipc/skill-routes/memory.ts +4 -3
- package/src/ipc/skill-routes/registries.ts +35 -40
- 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 +242 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
- package/src/memory/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +423 -182
- 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-connection.ts +29 -19
- package/src/memory/db-init.ts +14 -0
- package/src/memory/db-maintenance.ts +30 -21
- package/src/memory/db-singleton.ts +77 -0
- package/src/memory/delivery-channels.ts +82 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
- 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/graph/retriever.test.ts +3 -3
- 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/job-handlers/embedding.test.ts +3 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
- package/src/memory/jobs/embed-pkb-file.ts +6 -1
- package/src/memory/jobs-store.ts +14 -0
- package/src/memory/jobs-worker.ts +66 -22
- package/src/memory/llm-request-log-source-clickhouse.ts +122 -2
- package/src/memory/llm-request-log-source-local.ts +31 -0
- package/src/memory/llm-request-log-source.ts +40 -2
- package/src/memory/llm-request-log-store.ts +228 -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 +110 -7
- 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/265-drop-provider-connection-status.ts +26 -0
- package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
- package/src/memory/migrations/index.ts +19 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/schema/conversations.ts +10 -2
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/schema/infrastructure.ts +21 -0
- package/src/memory/tool-usage-store.ts +36 -8
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- 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 +83 -0
- package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +230 -0
- package/src/memory/v2/__tests__/harness-runner.test.ts +135 -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/__tests__/sweep-job.test.ts +6 -3
- package/src/memory/v2/harness/compare.ts +57 -0
- package/src/memory/v2/harness/metrics.ts +128 -0
- package/src/memory/v2/harness/oracle.ts +145 -0
- package/src/memory/v2/harness/replay-input.ts +240 -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 +112 -0
- package/src/memory/v2/harness/trace.ts +64 -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 +466 -0
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
- package/src/memory/v3/__tests__/edges.test.ts +706 -0
- package/src/memory/v3/__tests__/filter.test.ts +560 -0
- package/src/memory/v3/__tests__/gate.test.ts +637 -0
- package/src/memory/v3/__tests__/index-composition.test.ts +291 -0
- package/src/memory/v3/__tests__/loop.test.ts +775 -0
- package/src/memory/v3/__tests__/retriever.test.ts +226 -0
- package/src/memory/v3/__tests__/scouts.test.ts +489 -0
- package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +398 -0
- package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
- package/src/memory/v3/__tests__/traversal.test.ts +508 -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 +784 -0
- package/src/memory/v3/__tests__/validate.test.ts +277 -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/coretrieval-seed.ts +240 -0
- package/src/memory/v3/edge-learning-job.ts +160 -0
- package/src/memory/v3/edges.ts +286 -0
- package/src/memory/v3/filter.ts +286 -0
- package/src/memory/v3/gate.ts +349 -0
- package/src/memory/v3/index-composition.ts +126 -0
- package/src/memory/v3/llm-capture.ts +46 -0
- package/src/memory/v3/loop.ts +430 -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 +431 -0
- package/src/memory/v3/shadow-diff.ts +287 -0
- package/src/memory/v3/shadow-middleware.ts +347 -0
- package/src/memory/v3/traversal.ts +211 -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 +356 -0
- package/src/memory/v3/types.ts +65 -0
- package/src/memory/v3/validate.ts +323 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
- package/src/notifications/adapters/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- package/src/notifications/adapters/slack.ts +45 -11
- package/src/notifications/broadcaster.ts +114 -63
- package/src/notifications/conversation-pairing.ts +23 -3
- package/src/notifications/decision-engine.ts +1 -4
- package/src/notifications/decisions-store.ts +32 -1
- package/src/notifications/deliveries-store.ts +45 -0
- package/src/notifications/edit-notification.ts +201 -0
- package/src/notifications/emit-signal.ts +40 -50
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +37 -0
- package/src/oauth/byo-connection.test.ts +67 -3
- package/src/oauth/byo-connection.ts +32 -5
- package/src/oauth/connect-orchestrator.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +76 -0
- package/src/oauth/connection-resolver.ts +49 -10
- package/src/oauth/manual-token-connection.ts +51 -3
- package/src/oauth/seed-providers.ts +3 -0
- package/src/permissions/approval-policy.test.ts +19 -5
- package/src/permissions/approval-policy.ts +14 -3
- package/src/permissions/checker.ts +21 -8
- 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/platform/client.test.ts +24 -1
- package/src/platform/client.ts +8 -0
- package/src/platform/feature-gate.ts +15 -0
- 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 +20 -19
- package/src/plugins/defaults/persistence.ts +25 -6
- package/src/plugins/external-plugin-loader.ts +5 -68
- package/src/plugins/types.ts +68 -29
- package/src/proactive-artifact/aux-message-injector.ts +17 -4
- package/src/proactive-artifact/job.test.ts +1 -0
- package/src/prompts/__tests__/system-prompt.test.ts +4 -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 +84 -221
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP.md +9 -13
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/prompts/templates/system-sections.ts +230 -8
- package/src/providers/__tests__/connection-model-compat.test.ts +233 -0
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -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 +42 -6
- package/src/providers/connection-model-compat.ts +61 -0
- package/src/providers/connection-resolution.ts +47 -14
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +70 -6
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
- package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
- package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/inference/auth.ts +0 -8
- package/src/providers/inference/connections.ts +3 -66
- package/src/providers/inference/resolve-auth.ts +2 -3
- package/src/providers/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +78 -1
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
- package/src/providers/openai/chat-completions-provider.ts +116 -15
- package/src/providers/openai/codex-models.ts +20 -0
- package/src/providers/openai/responses-provider.ts +87 -30
- package/src/providers/openrouter/client.ts +13 -8
- package/src/providers/provider-send-message.ts +20 -5
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +50 -7
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/thinking-config.ts +26 -1
- package/src/providers/types.ts +9 -0
- package/src/providers/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/__tests__/agent-wake.test.ts +1 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
- package/src/runtime/access-request-helper.ts +1 -0
- package/src/runtime/agent-wake.ts +1 -0
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +46 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- package/src/runtime/channel-readiness-service.ts +68 -0
- package/src/runtime/channel-reply-delivery.ts +23 -0
- package/src/runtime/channel-retry-sweep.ts +47 -14
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +12 -4
- package/src/runtime/pending-interactions.ts +0 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +204 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +76 -9
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
- package/src/runtime/routes/acp-routes-list.test.ts +3 -0
- package/src/runtime/routes/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -1
- package/src/runtime/routes/app-management-routes.ts +111 -4
- package/src/runtime/routes/avatar-routes.ts +10 -10
- package/src/runtime/routes/background-wake-routes.ts +356 -0
- package/src/runtime/routes/browser-tabs-routes.ts +200 -0
- package/src/runtime/routes/btw-routes.ts +4 -10
- package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
- package/src/runtime/routes/conversation-list-routes.ts +159 -4
- package/src/runtime/routes/conversation-management-routes.ts +108 -26
- package/src/runtime/routes/conversation-query-routes.ts +200 -44
- package/src/runtime/routes/conversation-routes.ts +409 -521
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/conversations-import-routes.ts +19 -6
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- package/src/runtime/routes/documents-routes.ts +10 -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 +35 -8
- package/src/runtime/routes/home-feed-routes.ts +129 -0
- package/src/runtime/routes/host-browser-routes.ts +10 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- package/src/runtime/routes/identity-intro-cache.ts +61 -16
- package/src/runtime/routes/identity-routes.ts +30 -9
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
- package/src/runtime/routes/index.ts +10 -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/inference-provider-connection-routes.ts +5 -26
- package/src/runtime/routes/integrations/vercel.ts +15 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
- package/src/runtime/routes/llm-context-normalization.ts +7 -2
- 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 +474 -0
- package/src/runtime/routes/migration-routes.ts +32 -28
- package/src/runtime/routes/notification-routes.ts +63 -1
- package/src/runtime/routes/oauth-commands-routes.ts +6 -1
- 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/surface-action-routes.ts +1 -38
- package/src/runtime/routes/surface-content-routes.ts +12 -5
- package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
- package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
- package/src/runtime/routes/workspace-routes.ts +25 -10
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
- package/src/runtime/slack-dm-text-delivery.ts +177 -0
- 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/tool-grant-request-helper.ts +1 -0
- package/src/runtime/verification-outbound-actions.ts +73 -1
- package/src/schedule/schedule-store.ts +8 -1
- package/src/schedule/scheduler.ts +111 -15
- package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
- package/src/security/encrypted-store.ts +7 -16
- package/src/security/store-path-override.ts +61 -0
- package/src/signals/user-message.ts +5 -8
- package/src/skills/validate-input.ts +177 -0
- package/src/subagent/manager.ts +13 -13
- package/src/subagent/types.ts +6 -0
- package/src/tasks/tool-sanitizer.ts +2 -2
- 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 +36 -28
- 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__/browser-execution-acquire.test.ts +2 -8
- 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 +282 -336
- 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 +189 -7
- package/src/tools/execution-target.ts +18 -23
- package/src/tools/executor.ts +24 -56
- 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.test.ts +1 -0
- package/src/tools/host-filesystem/edit.ts +3 -9
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/read.ts +3 -9
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/transfer.ts +3 -9
- package/src/tools/host-filesystem/write.test.ts +1 -0
- 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 -10
- package/src/tools/memory/register.test.ts +1 -1
- package/src/tools/memory/register.ts +4 -9
- package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
- package/src/tools/network/__tests__/web-search.test.ts +211 -3
- package/src/tools/network/managed-search-proxy.ts +183 -0
- package/src/tools/network/web-fetch.ts +3 -9
- package/src/tools/network/web-search.ts +224 -76
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +150 -123
- package/src/tools/schedule/create.ts +1 -1
- 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 +18 -44
- package/src/tools/subagent/notify-parent.ts +3 -9
- package/src/tools/subagent/spawn.ts +3 -0
- package/src/tools/system/request-permission.ts +3 -9
- package/src/tools/terminal/shell.ts +3 -9
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +32 -101
- package/src/tools/ui-surface/definitions.ts +104 -108
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/browser.ts +7 -2
- 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/090-memory-router-cost-optimized-profile.ts +109 -0
- package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
- package/src/workspace/migrations/registry.ts +6 -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
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { v4 as uuid } from "uuid";
|
|
13
13
|
|
|
14
|
+
import { getConversation } from "../memory/conversation-crud.js";
|
|
14
15
|
import { getLogger } from "../util/logger.js";
|
|
15
16
|
import { isGuardianSensitiveEvent } from "./adapters/macos.js";
|
|
16
17
|
import { pairDeliveryWithConversation } from "./conversation-pairing.js";
|
|
@@ -72,6 +73,11 @@ export class NotificationBroadcaster {
|
|
|
72
73
|
this.onConversationCreated = fn;
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
/** Return the registered adapter for a channel, if any. */
|
|
77
|
+
getAdapter(channel: NotificationChannel): ChannelAdapter | undefined {
|
|
78
|
+
return this.adapters.get(channel);
|
|
79
|
+
}
|
|
80
|
+
|
|
75
81
|
/**
|
|
76
82
|
* Broadcast a notification decision to all selected channels.
|
|
77
83
|
*
|
|
@@ -231,78 +237,93 @@ export class NotificationBroadcaster {
|
|
|
231
237
|
);
|
|
232
238
|
|
|
233
239
|
// For the vellum channel, merge the conversationId into deep-link metadata
|
|
234
|
-
// so the macOS client can navigate directly to the
|
|
240
|
+
// so the macOS client can navigate directly to the conversation. Prefer
|
|
241
|
+
// the paired conversation (interactive opt-in flows); otherwise fall back
|
|
242
|
+
// to the originating conversation referenced by `sourceContextId` when it
|
|
243
|
+
// resolves to a real row. Sentinel context ids (job IDs, call session IDs,
|
|
244
|
+
// access-req-* strings) leave the deep link without a conversation, and
|
|
245
|
+
// the macOS handler opens the app to its default landing.
|
|
235
246
|
let deepLinkTarget = decision.deepLinkTarget;
|
|
236
|
-
if (channel === "vellum"
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
? destination.metadata.guardianPrincipalId
|
|
251
|
-
: undefined;
|
|
252
|
-
const targetGuardianPrincipalId =
|
|
253
|
-
guardianPrincipalId &&
|
|
254
|
-
isGuardianSensitiveEvent(signal.sourceEventName)
|
|
255
|
-
? guardianPrincipalId
|
|
256
|
-
: undefined;
|
|
257
|
-
|
|
258
|
-
const conversationTitle =
|
|
259
|
-
copy.conversationTitle ?? copy.title ?? signal.sourceEventName;
|
|
260
|
-
const conversationSilent =
|
|
261
|
-
signal.attentionHints.urgency !== "high" &&
|
|
262
|
-
signal.attentionHints.urgency !== "critical";
|
|
263
|
-
const info: ConversationCreatedInfo = {
|
|
264
|
-
conversationId: pairing.conversationId,
|
|
265
|
-
title: conversationTitle,
|
|
266
|
-
sourceEventName: signal.sourceEventName,
|
|
267
|
-
targetGuardianPrincipalId,
|
|
268
|
-
groupId: signal.conversationMetadata?.groupId,
|
|
269
|
-
source: signal.conversationMetadata?.source,
|
|
270
|
-
silent: conversationSilent,
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
// The per-dispatch onConversationCreated callback fires whenever a vellum
|
|
274
|
-
// conversation is paired (new or reused) because callers like
|
|
275
|
-
// dispatchGuardianQuestion rely on it to create delivery bookkeeping
|
|
276
|
-
// rows before emitNotificationSignal() returns.
|
|
277
|
-
if (options?.onConversationCreated) {
|
|
278
|
-
try {
|
|
279
|
-
options.onConversationCreated(info);
|
|
280
|
-
} catch (err) {
|
|
281
|
-
log.error(
|
|
282
|
-
{ err, signalId: signal.signalId },
|
|
283
|
-
"per-dispatch onConversationCreated callback failed — continuing broadcast",
|
|
284
|
-
);
|
|
247
|
+
if (channel === "vellum") {
|
|
248
|
+
const deepLinkConversationId =
|
|
249
|
+
pairing.conversationId ??
|
|
250
|
+
resolveSourceConversationId(signal.sourceContextId);
|
|
251
|
+
if (deepLinkConversationId) {
|
|
252
|
+
deepLinkTarget = {
|
|
253
|
+
...deepLinkTarget,
|
|
254
|
+
conversationId: deepLinkConversationId,
|
|
255
|
+
};
|
|
256
|
+
if (pairing.messageId) {
|
|
257
|
+
deepLinkTarget = {
|
|
258
|
+
...deepLinkTarget,
|
|
259
|
+
messageId: pairing.messageId,
|
|
260
|
+
};
|
|
285
261
|
}
|
|
286
262
|
}
|
|
287
263
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
264
|
+
if (pairing.conversationId) {
|
|
265
|
+
// Resolve guardian scoping for conversation-created events so clients
|
|
266
|
+
// can filter guardian-sensitive conversations the same way they filter
|
|
267
|
+
// guardian-sensitive notification intents.
|
|
268
|
+
const guardianPrincipalId =
|
|
269
|
+
typeof destination.metadata?.guardianPrincipalId === "string"
|
|
270
|
+
? destination.metadata.guardianPrincipalId
|
|
271
|
+
: undefined;
|
|
272
|
+
const targetGuardianPrincipalId =
|
|
273
|
+
guardianPrincipalId &&
|
|
274
|
+
isGuardianSensitiveEvent(signal.sourceEventName)
|
|
275
|
+
? guardianPrincipalId
|
|
276
|
+
: undefined;
|
|
277
|
+
|
|
278
|
+
const conversationTitle =
|
|
279
|
+
copy.conversationTitle ?? copy.title ?? signal.sourceEventName;
|
|
280
|
+
const conversationSilent =
|
|
281
|
+
signal.attentionHints.urgency !== "high" &&
|
|
282
|
+
signal.attentionHints.urgency !== "critical";
|
|
283
|
+
const info: ConversationCreatedInfo = {
|
|
284
|
+
conversationId: pairing.conversationId,
|
|
285
|
+
title: conversationTitle,
|
|
286
|
+
sourceEventName: signal.sourceEventName,
|
|
287
|
+
targetGuardianPrincipalId,
|
|
288
|
+
groupId: signal.conversationMetadata?.groupId,
|
|
289
|
+
source: signal.conversationMetadata?.source,
|
|
290
|
+
silent: conversationSilent,
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// The per-dispatch onConversationCreated callback fires whenever a vellum
|
|
294
|
+
// conversation is paired (new or reused) because callers like
|
|
295
|
+
// dispatchGuardianQuestion rely on it to create delivery bookkeeping
|
|
296
|
+
// rows before emitNotificationSignal() returns.
|
|
297
|
+
if (options?.onConversationCreated) {
|
|
297
298
|
try {
|
|
298
|
-
|
|
299
|
+
options.onConversationCreated(info);
|
|
299
300
|
} catch (err) {
|
|
300
301
|
log.error(
|
|
301
302
|
{ err, signalId: signal.signalId },
|
|
302
|
-
"onConversationCreated callback failed — continuing broadcast",
|
|
303
|
+
"per-dispatch onConversationCreated callback failed — continuing broadcast",
|
|
303
304
|
);
|
|
304
305
|
}
|
|
305
306
|
}
|
|
307
|
+
|
|
308
|
+
// Emit notification_conversation_created event only when a NEW
|
|
309
|
+
// conversation was actually created. Reusing an existing conversation
|
|
310
|
+
// should not fire the event — the client already knows about the
|
|
311
|
+
// conversation.
|
|
312
|
+
if (
|
|
313
|
+
pairing.createdNewConversation &&
|
|
314
|
+
pairing.strategy === "start_new_conversation"
|
|
315
|
+
) {
|
|
316
|
+
if (this.onConversationCreated) {
|
|
317
|
+
try {
|
|
318
|
+
this.onConversationCreated(info);
|
|
319
|
+
} catch (err) {
|
|
320
|
+
log.error(
|
|
321
|
+
{ err, signalId: signal.signalId },
|
|
322
|
+
"onConversationCreated callback failed — continuing broadcast",
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
306
327
|
}
|
|
307
328
|
}
|
|
308
329
|
|
|
@@ -354,8 +375,21 @@ export class NotificationBroadcaster {
|
|
|
354
375
|
const adapterResult = await adapter.send(payload, destination);
|
|
355
376
|
|
|
356
377
|
if (adapterResult.success) {
|
|
378
|
+
// Prefer the channel-native id the adapter just captured (e.g.
|
|
379
|
+
// Slack `ts`) so later edits can target the same message; fall
|
|
380
|
+
// back to the pairing-supplied id for channels that surface it
|
|
381
|
+
// through conversation pairing instead.
|
|
382
|
+
const resolvedMessageId =
|
|
383
|
+
adapterResult.messageId ?? pairing.messageId ?? undefined;
|
|
357
384
|
if (hasPersistedDecision) {
|
|
358
|
-
updateDeliveryStatus(
|
|
385
|
+
updateDeliveryStatus(
|
|
386
|
+
deliveryId,
|
|
387
|
+
"sent",
|
|
388
|
+
undefined,
|
|
389
|
+
adapterResult.messageId
|
|
390
|
+
? { messageId: adapterResult.messageId }
|
|
391
|
+
: undefined,
|
|
392
|
+
);
|
|
359
393
|
}
|
|
360
394
|
results.push({
|
|
361
395
|
channel,
|
|
@@ -363,7 +397,7 @@ export class NotificationBroadcaster {
|
|
|
363
397
|
status: "sent",
|
|
364
398
|
sentAt: Date.now(),
|
|
365
399
|
conversationId: pairing.conversationId ?? undefined,
|
|
366
|
-
messageId:
|
|
400
|
+
messageId: resolvedMessageId,
|
|
367
401
|
conversationStrategy: pairing.strategy,
|
|
368
402
|
});
|
|
369
403
|
} else {
|
|
@@ -414,3 +448,20 @@ export class NotificationBroadcaster {
|
|
|
414
448
|
return results;
|
|
415
449
|
}
|
|
416
450
|
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Resolve a signal's `sourceContextId` to a conversation id if it points at a
|
|
454
|
+
* real row. Producers may pass sentinels (job IDs, call session IDs,
|
|
455
|
+
* `access-req-*` strings) here; those simply return undefined so the deep
|
|
456
|
+
* link omits the conversation target.
|
|
457
|
+
*/
|
|
458
|
+
function resolveSourceConversationId(
|
|
459
|
+
sourceContextId: string | undefined,
|
|
460
|
+
): string | undefined {
|
|
461
|
+
if (!sourceContextId) return undefined;
|
|
462
|
+
try {
|
|
463
|
+
return getConversation(sourceContextId) ? sourceContextId : undefined;
|
|
464
|
+
} catch {
|
|
465
|
+
return undefined;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
@@ -113,6 +113,29 @@ export async function pairDeliveryWithConversation(
|
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
const conversationAction = options?.conversationAction;
|
|
117
|
+
const bindingContext = options?.bindingContext;
|
|
118
|
+
|
|
119
|
+
// Passive vellum notifications surface via the home feed alone and link
|
|
120
|
+
// back to the originating conversation via `signal.sourceContextId`.
|
|
121
|
+
// Materializing a fresh per-notification conversation just to host the
|
|
122
|
+
// seed message leaves a graveyard entry in the sidebar; skip it unless
|
|
123
|
+
// the producer opted in via `requiresConversation` or the decision engine
|
|
124
|
+
// requested explicit reuse of a target conversation.
|
|
125
|
+
if (
|
|
126
|
+
strategy === "start_new_conversation" &&
|
|
127
|
+
!signal.requiresConversation &&
|
|
128
|
+
conversationAction?.action !== "reuse_existing"
|
|
129
|
+
) {
|
|
130
|
+
return {
|
|
131
|
+
conversationId: null,
|
|
132
|
+
messageId: null,
|
|
133
|
+
strategy,
|
|
134
|
+
createdNewConversation: false,
|
|
135
|
+
conversationFallbackUsed: false,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
116
139
|
const title =
|
|
117
140
|
copy.conversationTitle ?? copy.title ?? signal.sourceEventName;
|
|
118
141
|
|
|
@@ -130,9 +153,6 @@ export async function pairDeliveryWithConversation(
|
|
|
130
153
|
? copy.conversationSeedMessage
|
|
131
154
|
: composeConversationSeed(signal, channel, copy);
|
|
132
155
|
|
|
133
|
-
const conversationAction = options?.conversationAction;
|
|
134
|
-
const bindingContext = options?.bindingContext;
|
|
135
|
-
|
|
136
156
|
// Attempt to reuse an existing conversation when the model requests it
|
|
137
157
|
if (conversationAction?.action === "reuse_existing") {
|
|
138
158
|
const targetId = conversationAction.conversationId;
|
|
@@ -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;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* were routed.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { eq } from "drizzle-orm";
|
|
10
|
+
import { desc, eq } from "drizzle-orm";
|
|
11
11
|
|
|
12
12
|
import { getDb } from "../memory/db-connection.js";
|
|
13
13
|
import { notificationDecisions } from "../memory/schema.js";
|
|
@@ -94,3 +94,34 @@ export function updateDecision(id: string, params: UpdateDecisionParams): void {
|
|
|
94
94
|
.where(eq(notificationDecisions.id, id))
|
|
95
95
|
.run();
|
|
96
96
|
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Return the most recent decision for a given notification event, or
|
|
100
|
+
* `undefined` if none exists. The decision engine writes exactly one
|
|
101
|
+
* decision per event today, but ordering by createdAt DESC keeps this
|
|
102
|
+
* stable if that ever changes (e.g. re-decisions on retry).
|
|
103
|
+
*/
|
|
104
|
+
export function findLatestDecisionByEventId(
|
|
105
|
+
eventId: string,
|
|
106
|
+
): NotificationDecisionRow | undefined {
|
|
107
|
+
const db = getDb();
|
|
108
|
+
const row = db
|
|
109
|
+
.select()
|
|
110
|
+
.from(notificationDecisions)
|
|
111
|
+
.where(eq(notificationDecisions.notificationEventId, eventId))
|
|
112
|
+
.orderBy(desc(notificationDecisions.createdAt))
|
|
113
|
+
.get();
|
|
114
|
+
if (!row) return undefined;
|
|
115
|
+
return {
|
|
116
|
+
id: row.id,
|
|
117
|
+
notificationEventId: row.notificationEventId,
|
|
118
|
+
shouldNotify: row.shouldNotify === 1,
|
|
119
|
+
selectedChannels: row.selectedChannels,
|
|
120
|
+
reasoningSummary: row.reasoningSummary,
|
|
121
|
+
confidence: row.confidence,
|
|
122
|
+
fallbackUsed: row.fallbackUsed === 1,
|
|
123
|
+
promptVersion: row.promptVersion,
|
|
124
|
+
validationResults: row.validationResults,
|
|
125
|
+
createdAt: row.createdAt,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
@@ -137,6 +137,7 @@ export function updateDeliveryStatus(
|
|
|
137
137
|
id: string,
|
|
138
138
|
status: NotificationDeliveryStatus,
|
|
139
139
|
error?: { code?: string; message?: string },
|
|
140
|
+
patch?: { messageId?: string },
|
|
140
141
|
): boolean {
|
|
141
142
|
const db = getDb();
|
|
142
143
|
const now = Date.now();
|
|
@@ -151,6 +152,9 @@ export function updateDeliveryStatus(
|
|
|
151
152
|
if (error?.message) {
|
|
152
153
|
updates.errorMessage = error.message;
|
|
153
154
|
}
|
|
155
|
+
if (patch?.messageId !== undefined) {
|
|
156
|
+
updates.messageId = patch.messageId;
|
|
157
|
+
}
|
|
154
158
|
|
|
155
159
|
db.update(notificationDeliveries)
|
|
156
160
|
.set(updates)
|
|
@@ -160,6 +164,34 @@ export function updateDeliveryStatus(
|
|
|
160
164
|
return rawChanges() > 0;
|
|
161
165
|
}
|
|
162
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Update the rendered copy on an existing delivery row.
|
|
169
|
+
*
|
|
170
|
+
* Used by the edit pipeline so the delivery audit reflects the latest
|
|
171
|
+
* title/body shown to the user, not just the original send.
|
|
172
|
+
*/
|
|
173
|
+
export function updateDeliveryRenderedCopy(
|
|
174
|
+
id: string,
|
|
175
|
+
patch: { renderedTitle?: string; renderedBody?: string },
|
|
176
|
+
): boolean {
|
|
177
|
+
const updates: Record<string, unknown> = { updatedAt: Date.now() };
|
|
178
|
+
if (patch.renderedTitle !== undefined) {
|
|
179
|
+
updates.renderedTitle = patch.renderedTitle;
|
|
180
|
+
}
|
|
181
|
+
if (patch.renderedBody !== undefined) {
|
|
182
|
+
updates.renderedBody = patch.renderedBody;
|
|
183
|
+
}
|
|
184
|
+
if (Object.keys(updates).length === 1) return false;
|
|
185
|
+
|
|
186
|
+
getDb()
|
|
187
|
+
.update(notificationDeliveries)
|
|
188
|
+
.set(updates)
|
|
189
|
+
.where(eq(notificationDeliveries.id, id))
|
|
190
|
+
.run();
|
|
191
|
+
|
|
192
|
+
return rawChanges() > 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
163
195
|
/** Check whether a delivery already exists for a given decision+channel pair. */
|
|
164
196
|
export function findDeliveryByDecisionAndChannel(
|
|
165
197
|
decisionId: string,
|
|
@@ -178,3 +210,16 @@ export function findDeliveryByDecisionAndChannel(
|
|
|
178
210
|
.get();
|
|
179
211
|
return row ? rowToDelivery(row) : undefined;
|
|
180
212
|
}
|
|
213
|
+
|
|
214
|
+
/** Return every delivery row for a given decision. */
|
|
215
|
+
export function findDeliveriesByDecisionId(
|
|
216
|
+
decisionId: string,
|
|
217
|
+
): NotificationDeliveryRow[] {
|
|
218
|
+
const db = getDb();
|
|
219
|
+
const rows = db
|
|
220
|
+
.select()
|
|
221
|
+
.from(notificationDeliveries)
|
|
222
|
+
.where(eq(notificationDeliveries.notificationDecisionId, decisionId))
|
|
223
|
+
.all();
|
|
224
|
+
return rows.map(rowToDelivery);
|
|
225
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edit an already-sent notification.
|
|
3
|
+
*
|
|
4
|
+
* Patches the home-feed entry the user actually sees, then attempts a
|
|
5
|
+
* best-effort update of any per-channel deliveries that support
|
|
6
|
+
* in-place edits (Slack via chat.update today). Feed-only fields
|
|
7
|
+
* (`urgency`, `status`) skip the channel hop — channel messages don't
|
|
8
|
+
* carry that metadata, only body/title.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
type FeedItem,
|
|
13
|
+
type FeedItemStatus,
|
|
14
|
+
type FeedItemUrgency,
|
|
15
|
+
} from "../home/feed-types.js";
|
|
16
|
+
import { patchFeedItemContent } from "../home/feed-writer.js";
|
|
17
|
+
import { getLogger } from "../util/logger.js";
|
|
18
|
+
import { findLatestDecisionByEventId } from "./decisions-store.js";
|
|
19
|
+
import {
|
|
20
|
+
findDeliveriesByDecisionId,
|
|
21
|
+
type NotificationDeliveryRow,
|
|
22
|
+
updateDeliveryRenderedCopy,
|
|
23
|
+
} from "./deliveries-store.js";
|
|
24
|
+
import { getBroadcaster } from "./emit-signal.js";
|
|
25
|
+
import type { NotificationChannel } from "./types.js";
|
|
26
|
+
|
|
27
|
+
const log = getLogger("edit-notification");
|
|
28
|
+
|
|
29
|
+
/** Prefix used by `home-feed-side-effect` when minting feed item ids. */
|
|
30
|
+
export const FEED_ITEM_ID_PREFIX = "notif:";
|
|
31
|
+
|
|
32
|
+
export interface EditNotificationParams {
|
|
33
|
+
/** Feed item id (`notif:<uuid>`) or bare signal uuid. */
|
|
34
|
+
id: string;
|
|
35
|
+
title?: string;
|
|
36
|
+
body?: string;
|
|
37
|
+
urgency?: FeedItemUrgency;
|
|
38
|
+
status?: FeedItemStatus;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type ChannelEditOutcome =
|
|
42
|
+
| "updated"
|
|
43
|
+
| "unsupported"
|
|
44
|
+
| "skipped"
|
|
45
|
+
| "failed";
|
|
46
|
+
|
|
47
|
+
export interface ChannelEditResult {
|
|
48
|
+
channel: NotificationChannel;
|
|
49
|
+
deliveryId: string;
|
|
50
|
+
outcome: ChannelEditOutcome;
|
|
51
|
+
/** Reason for skip/failure when `outcome` is not `"updated"`. */
|
|
52
|
+
reason?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface EditNotificationResult {
|
|
56
|
+
feedItem: FeedItem;
|
|
57
|
+
channels: ChannelEditResult[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Normalize a user-supplied id into the canonical feed-item form
|
|
62
|
+
* (`notif:<uuid>`). Accepts either the full prefixed id or a bare uuid.
|
|
63
|
+
*/
|
|
64
|
+
export function normalizeFeedItemId(id: string): string {
|
|
65
|
+
const trimmed = id.trim();
|
|
66
|
+
if (trimmed.startsWith(FEED_ITEM_ID_PREFIX)) return trimmed;
|
|
67
|
+
return `${FEED_ITEM_ID_PREFIX}${trimmed}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Strip the `notif:` prefix to recover the original signal/event id. */
|
|
71
|
+
export function feedItemIdToSignalId(feedItemId: string): string {
|
|
72
|
+
return feedItemId.startsWith(FEED_ITEM_ID_PREFIX)
|
|
73
|
+
? feedItemId.slice(FEED_ITEM_ID_PREFIX.length)
|
|
74
|
+
: feedItemId;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Apply an edit to a previously-sent notification.
|
|
79
|
+
*
|
|
80
|
+
* Returns the updated feed item plus per-channel update outcomes.
|
|
81
|
+
* Resolves to `null` when the feed item id isn't on disk so callers
|
|
82
|
+
* can surface a clear "not found" to the user.
|
|
83
|
+
*/
|
|
84
|
+
export async function editNotification(
|
|
85
|
+
params: EditNotificationParams,
|
|
86
|
+
): Promise<EditNotificationResult | null> {
|
|
87
|
+
const feedItemId = normalizeFeedItemId(params.id);
|
|
88
|
+
|
|
89
|
+
const feedItem = await patchFeedItemContent(feedItemId, {
|
|
90
|
+
title: params.title,
|
|
91
|
+
summary: params.body,
|
|
92
|
+
urgency: params.urgency,
|
|
93
|
+
status: params.status,
|
|
94
|
+
});
|
|
95
|
+
if (!feedItem) {
|
|
96
|
+
log.warn({ feedItemId }, "Edit requested for unknown feed item");
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Only edit channel messages when the user-visible text changed.
|
|
101
|
+
// Urgency/status are feed-only — pushing a channel update for those
|
|
102
|
+
// alone would re-deliver the same body and confuse the recipient.
|
|
103
|
+
const shouldUpdateChannels =
|
|
104
|
+
params.title !== undefined || params.body !== undefined;
|
|
105
|
+
if (!shouldUpdateChannels) {
|
|
106
|
+
return { feedItem, channels: [] };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const signalId = feedItemIdToSignalId(feedItemId);
|
|
110
|
+
const decision = findLatestDecisionByEventId(signalId);
|
|
111
|
+
if (!decision) {
|
|
112
|
+
log.info(
|
|
113
|
+
{ feedItemId, signalId },
|
|
114
|
+
"Feed item has no persisted decision — skipping channel updates",
|
|
115
|
+
);
|
|
116
|
+
return { feedItem, channels: [] };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const deliveries = findDeliveriesByDecisionId(decision.id);
|
|
120
|
+
const channels = await updateChannelDeliveries(deliveries, {
|
|
121
|
+
title: params.title,
|
|
122
|
+
body: params.body,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return { feedItem, channels };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function updateChannelDeliveries(
|
|
129
|
+
deliveries: NotificationDeliveryRow[],
|
|
130
|
+
patch: { title?: string; body?: string },
|
|
131
|
+
): Promise<ChannelEditResult[]> {
|
|
132
|
+
const broadcaster = getBroadcaster();
|
|
133
|
+
const results: ChannelEditResult[] = [];
|
|
134
|
+
|
|
135
|
+
for (const delivery of deliveries) {
|
|
136
|
+
const channel = delivery.channel as NotificationChannel;
|
|
137
|
+
if (delivery.status !== "sent") {
|
|
138
|
+
results.push({
|
|
139
|
+
channel,
|
|
140
|
+
deliveryId: delivery.id,
|
|
141
|
+
outcome: "skipped",
|
|
142
|
+
reason: `delivery status is ${delivery.status}`,
|
|
143
|
+
});
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const adapter = broadcaster.getAdapter(channel);
|
|
148
|
+
if (!adapter?.update) {
|
|
149
|
+
results.push({
|
|
150
|
+
channel,
|
|
151
|
+
deliveryId: delivery.id,
|
|
152
|
+
outcome: "unsupported",
|
|
153
|
+
reason: `${channel} adapter does not support in-place edits`,
|
|
154
|
+
});
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
const result = await adapter.update(
|
|
160
|
+
{
|
|
161
|
+
deliveryId: delivery.id,
|
|
162
|
+
destination: delivery.destination,
|
|
163
|
+
messageId: delivery.messageId,
|
|
164
|
+
},
|
|
165
|
+
patch,
|
|
166
|
+
);
|
|
167
|
+
if (!result.success) {
|
|
168
|
+
results.push({
|
|
169
|
+
channel,
|
|
170
|
+
deliveryId: delivery.id,
|
|
171
|
+
outcome: "failed",
|
|
172
|
+
reason: result.error ?? "unknown error",
|
|
173
|
+
});
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
updateDeliveryRenderedCopy(delivery.id, {
|
|
177
|
+
renderedTitle: patch.title,
|
|
178
|
+
renderedBody: patch.body,
|
|
179
|
+
});
|
|
180
|
+
results.push({
|
|
181
|
+
channel,
|
|
182
|
+
deliveryId: delivery.id,
|
|
183
|
+
outcome: "updated",
|
|
184
|
+
});
|
|
185
|
+
} catch (err) {
|
|
186
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
187
|
+
log.error(
|
|
188
|
+
{ err, channel, deliveryId: delivery.id },
|
|
189
|
+
"Channel adapter update threw",
|
|
190
|
+
);
|
|
191
|
+
results.push({
|
|
192
|
+
channel,
|
|
193
|
+
deliveryId: delivery.id,
|
|
194
|
+
outcome: "failed",
|
|
195
|
+
reason: message,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return results;
|
|
201
|
+
}
|