@vellumai/assistant 0.8.5 → 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 +1 -1
- package/bunfig.toml +6 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +4 -3
- 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 +1900 -166
- 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__/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-feature-flags-integration.test.ts +9 -25
- package/src/__tests__/audit-log-rotation.test.ts +2 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/background-workers-disk-pressure.test.ts +5 -8
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +3 -2
- package/src/__tests__/call-controller.test.ts +3 -2
- package/src/__tests__/channel-approval-routes.test.ts +3 -2
- package/src/__tests__/channel-guardian.test.ts +3 -2
- 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 +12 -12
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compaction-trail-store.test.ts +264 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
- package/src/__tests__/computer-use-tools.test.ts +12 -14
- 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__/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 +1 -0
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +34 -0
- package/src/__tests__/conversation-agent-loop.test.ts +488 -2
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
- package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
- 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-confirmation-signals.test.ts +1 -0
- package/src/__tests__/conversation-error.test.ts +30 -0
- package/src/__tests__/conversation-fork-crud.test.ts +69 -8
- 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 +1 -0
- 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-history-stripped.test.ts +1 -0
- 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 +5 -0
- package/src/__tests__/conversation-queue.test.ts +333 -291
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -18
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
- package/src/__tests__/conversation-routes-slash-commands.test.ts +33 -2
- package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
- package/src/__tests__/conversation-skill-tools.test.ts +38 -142
- 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-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 +128 -12
- 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 +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -0
- 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 +10 -12
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -5
- package/src/__tests__/credential-vault-unit.test.ts +19 -19
- 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-skill-workflow-prompt.test.ts +5 -4
- 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 +0 -1
- package/src/__tests__/gemini-provider.test.ts +26 -0
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-outbound-http.test.ts +3 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -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 +5 -4
- 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__/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__/llm-context-normalization.test.ts +42 -0
- package/src/__tests__/llm-resolver.test.ts +331 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +14 -0
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- 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 +3 -3
- package/src/__tests__/native-web-search.test.ts +30 -2
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- 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 +3 -2
- package/src/__tests__/openai-provider.test.ts +8 -9
- package/src/__tests__/openai-responses-provider.test.ts +70 -10
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
- package/src/__tests__/persistence-pipeline.test.ts +139 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
- package/src/__tests__/plugin-bootstrap.test.ts +9 -11
- package/src/__tests__/plugin-tool-contribution.test.ts +41 -38
- 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__/recording-handler.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +82 -76
- package/src/__tests__/relay-server.test.ts +10 -10
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- 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__/skill-feature-flags-integration.test.ts +8 -10
- package/src/__tests__/skill-feature-flags.test.ts +14 -16
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
- package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
- package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
- package/src/__tests__/skill-tool-factory.test.ts +96 -95
- 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 +5 -4
- 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 +1 -0
- package/src/__tests__/system-prompt.test.ts +38 -0
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
- package/src/__tests__/tool-executor.test.ts +55 -10
- package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/twilio-routes.test.ts +3 -2
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
- 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-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/session-manager.ts +5 -6
- package/src/agent/loop.ts +80 -0
- package/src/api/README.md +124 -2
- 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/{events → api/events}/relationship-state-updated.ts +3 -3
- package/src/api/events/tool-use-start.ts +32 -0
- package/src/api/index.ts +128 -3
- 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 +687 -52
- 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 +2 -2
- 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__/conversations-slack.test.ts +16 -0
- package/src/cli/commands/__tests__/notifications.test.ts +184 -40
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -0
- package/src/cli/commands/memory-v3-render.ts +147 -0
- package/src/cli/commands/memory-v3.ts +255 -4
- package/src/cli/commands/notifications.ts +365 -55
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +23 -42
- package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
- 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/call-site-defaults.ts +1 -1
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +17 -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 +15 -0
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +90 -1
- package/src/config/schemas/memory-v2.ts +26 -0
- package/src/config/schemas/services.ts +6 -2
- package/src/config/seed-inference-profiles.ts +36 -16
- package/src/context/token-estimator.ts +10 -5
- 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 +1 -2
- 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 +389 -68
- package/src/daemon/conversation-agent-loop.ts +132 -28
- package/src/daemon/conversation-error.ts +33 -5
- package/src/daemon/conversation-messaging.ts +84 -43
- package/src/daemon/conversation-process.ts +74 -37
- package/src/daemon/conversation-runtime-assembly.ts +29 -9
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-surfaces.ts +69 -34
- package/src/daemon/conversation-tool-setup.ts +33 -48
- package/src/daemon/conversation.ts +26 -46
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +9 -2
- package/src/daemon/disk-pressure-guard.ts +27 -29
- package/src/daemon/first-greeting.ts +31 -13
- package/src/daemon/handlers/shared.ts +6 -1
- package/src/daemon/lifecycle.ts +12 -12
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +10 -17
- package/src/daemon/message-types/conversations.ts +20 -22
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/home.ts +2 -2
- package/src/daemon/message-types/integrations.ts +2 -7
- package/src/daemon/message-types/messages.ts +23 -38
- package/src/daemon/message-types/subagents.ts +6 -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/switch-inference-profile-tool.ts +13 -3
- package/src/daemon/tool-setup-types.ts +0 -6
- 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 +29 -0
- 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/suggested-prompts.ts +27 -145
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/gateway-client.test.ts +4 -1
- 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 +28 -29
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
- 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 +1 -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/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +352 -112
- package/src/memory/db-connection.ts +29 -19
- package/src/memory/db-init.ts +4 -0
- 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/retriever.test.ts +3 -3
- 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-worker.ts +12 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +80 -0
- package/src/memory/llm-request-log-source-local.ts +24 -0
- package/src/memory/llm-request-log-source.ts +31 -0
- package/src/memory/llm-request-log-store.ts +188 -3
- package/src/memory/memory-v2-activation-log-store.ts +95 -1
- 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 +2 -0
- package/src/memory/schema/conversations.ts +9 -1
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
- package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
- package/src/memory/v2/harness/metrics.ts +5 -1
- package/src/memory/v2/harness/replay-input.ts +19 -3
- package/src/memory/v2/harness/runner.ts +6 -0
- package/src/memory/v2/harness/trace.ts +6 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +2 -4
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
- package/src/memory/v3/__tests__/edges.test.ts +144 -1
- package/src/memory/v3/__tests__/filter.test.ts +48 -0
- package/src/memory/v3/__tests__/gate.test.ts +96 -33
- package/src/memory/v3/__tests__/index-composition.test.ts +58 -0
- package/src/memory/v3/__tests__/loop.test.ts +250 -5
- package/src/memory/v3/__tests__/scouts.test.ts +49 -0
- package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +88 -2
- package/src/memory/v3/__tests__/traversal.test.ts +39 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +77 -0
- package/src/memory/v3/__tests__/validate.test.ts +32 -0
- package/src/memory/v3/coretrieval-seed.ts +240 -0
- package/src/memory/v3/edges.ts +58 -21
- package/src/memory/v3/filter.ts +27 -22
- package/src/memory/v3/gate.ts +51 -36
- package/src/memory/v3/index-composition.ts +18 -5
- package/src/memory/v3/loop.ts +65 -17
- package/src/memory/v3/scouts.ts +15 -4
- package/src/memory/v3/shadow-diff.ts +287 -0
- package/src/memory/v3/shadow-middleware.ts +44 -2
- package/src/memory/v3/traversal.ts +6 -1
- package/src/memory/v3/tree-walk.ts +6 -1
- package/src/memory/v3/validate.ts +56 -33
- 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/slack.ts +45 -11
- package/src/notifications/broadcaster.ts +114 -63
- package/src/notifications/conversation-pairing.ts +23 -3
- 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 +11 -1
- 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/platform/client.test.ts +24 -1
- package/src/platform/client.ts +8 -0
- package/src/platform/feature-gate.ts +15 -0
- package/src/plugins/defaults/injectors.ts +2 -8
- package/src/plugins/defaults/persistence.ts +25 -6
- package/src/plugins/types.ts +57 -13
- package/src/proactive-artifact/job.test.ts +1 -0
- package/src/prompts/__tests__/system-prompt.test.ts +4 -4
- package/src/prompts/system-prompt.ts +38 -40
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP.md +7 -11
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
- package/src/providers/call-site-routing.ts +33 -9
- package/src/providers/connection-model-compat.ts +23 -0
- package/src/providers/connection-resolution.ts +39 -20
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +24 -3
- 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/auth.ts +0 -8
- package/src/providers/inference/connections.ts +3 -66
- package/src/providers/inference/resolve-auth.ts +2 -3
- package/src/providers/model-catalog.ts +35 -1
- package/src/providers/model-intents.ts +3 -3
- 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 +110 -12
- package/src/providers/openai/codex-models.ts +2 -0
- package/src/providers/openai/responses-provider.ts +53 -53
- package/src/providers/openrouter/client.ts +13 -8
- package/src/providers/provider-send-message.ts +18 -9
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +16 -4
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/types.ts +9 -0
- 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/auth/route-policy.ts +10 -0
- 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/migrations/vbundle-builder.ts +3 -2
- 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 +98 -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 +51 -3
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -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/app-management-routes.ts +111 -4
- package/src/runtime/routes/background-wake-routes.ts +188 -20
- package/src/runtime/routes/btw-routes.ts +4 -4
- package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
- package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
- package/src/runtime/routes/conversation-list-routes.ts +147 -0
- package/src/runtime/routes/conversation-management-routes.ts +39 -14
- package/src/runtime/routes/conversation-query-routes.ts +60 -10
- package/src/runtime/routes/conversation-routes.ts +186 -140
- package/src/runtime/routes/conversations-import-routes.ts +19 -6
- package/src/runtime/routes/documents-routes.ts +10 -1
- package/src/runtime/routes/group-routes.ts +11 -0
- package/src/runtime/routes/home-feed-routes.ts +129 -0
- 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/background-dispatch.test.ts +530 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
- package/src/runtime/routes/index.ts +2 -0
- 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-context-normalization.ts +7 -2
- package/src/runtime/routes/memory-v3-routes.ts +160 -2
- package/src/runtime/routes/migration-routes.ts +20 -13
- package/src/runtime/routes/notification-routes.ts +63 -1
- package/src/runtime/routes/oauth-commands-routes.ts +6 -1
- 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/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 +1 -1
- package/src/runtime/tool-grant-request-helper.ts +1 -0
- 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/tools/apps/definitions.ts +35 -21
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
- package/src/tools/computer-use/definitions.ts +268 -266
- package/src/tools/document/document-tool.ts +131 -8
- package/src/tools/execution-target.ts +2 -5
- package/src/tools/executor.ts +18 -55
- package/src/tools/host-filesystem/edit.test.ts +1 -0
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/write.test.ts +1 -0
- package/src/tools/mcp/mcp-tool-factory.ts +0 -2
- 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-search.ts +199 -44
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +146 -103
- package/src/tools/schedule/create.ts +1 -1
- package/src/tools/skills/skill-tool-factory.ts +17 -36
- package/src/tools/subagent/spawn.ts +3 -0
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +17 -15
- package/src/tools/ui-surface/definitions.ts +98 -86
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/util/browser.ts +7 -2
- 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 +4 -0
|
@@ -8,10 +8,11 @@ import { z } from "zod";
|
|
|
8
8
|
import { getDb } from "../../memory/db-connection.js";
|
|
9
9
|
import { notificationDeliveries } from "../../memory/schema.js";
|
|
10
10
|
import { bufferIfDeferred } from "../../notifications/deferred-emit.js";
|
|
11
|
+
import { editNotification } from "../../notifications/edit-notification.js";
|
|
11
12
|
import { emitNotificationSignal } from "../../notifications/emit-signal.js";
|
|
12
13
|
import { listEvents } from "../../notifications/events-store.js";
|
|
13
14
|
import type { AttentionHints } from "../../notifications/signal.js";
|
|
14
|
-
import { BadRequestError } from "./errors.js";
|
|
15
|
+
import { BadRequestError, NotFoundError } from "./errors.js";
|
|
15
16
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
16
17
|
|
|
17
18
|
function handleNotificationIntentResult({ body = {} }: RouteHandlerArgs) {
|
|
@@ -89,6 +90,26 @@ const ListNotificationEventsParams = z.object({
|
|
|
89
90
|
sourceEventName: z.string().optional(),
|
|
90
91
|
});
|
|
91
92
|
|
|
93
|
+
const EditNotificationParams = z
|
|
94
|
+
.object({
|
|
95
|
+
id: z.string().min(1).describe("Feed item id (notif:<uuid>) or bare uuid"),
|
|
96
|
+
title: z.string().optional(),
|
|
97
|
+
body: z.string().optional(),
|
|
98
|
+
urgency: z.enum(["low", "medium", "high", "critical"]).optional(),
|
|
99
|
+
status: z.enum(["new", "seen", "acted_on", "dismissed"]).optional(),
|
|
100
|
+
})
|
|
101
|
+
.refine(
|
|
102
|
+
(v) =>
|
|
103
|
+
v.title !== undefined ||
|
|
104
|
+
v.body !== undefined ||
|
|
105
|
+
v.urgency !== undefined ||
|
|
106
|
+
v.status !== undefined,
|
|
107
|
+
{
|
|
108
|
+
message:
|
|
109
|
+
"At least one of `title`, `body`, `urgency`, or `status` must be supplied",
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
|
|
92
113
|
// ── Notification pipeline handlers ───────────────────────────────────
|
|
93
114
|
|
|
94
115
|
async function handleEmitSignal({ body = {} }: RouteHandlerArgs) {
|
|
@@ -125,6 +146,19 @@ async function handleEmitSignal({ body = {} }: RouteHandlerArgs) {
|
|
|
125
146
|
};
|
|
126
147
|
}
|
|
127
148
|
|
|
149
|
+
async function handleEditNotification({ body = {} }: RouteHandlerArgs) {
|
|
150
|
+
const validated = EditNotificationParams.parse(body);
|
|
151
|
+
const result = await editNotification(validated);
|
|
152
|
+
if (!result) {
|
|
153
|
+
throw new NotFoundError(`No notification found for id ${validated.id}`);
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
ok: true,
|
|
157
|
+
feedItem: result.feedItem,
|
|
158
|
+
channels: result.channels,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
128
162
|
function handleListEvents({ body = {} }: RouteHandlerArgs) {
|
|
129
163
|
const validated = ListNotificationEventsParams.parse(body);
|
|
130
164
|
const rows = listEvents({
|
|
@@ -175,6 +209,34 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
175
209
|
reason: z.string(),
|
|
176
210
|
}),
|
|
177
211
|
},
|
|
212
|
+
{
|
|
213
|
+
operationId: "edit_notification",
|
|
214
|
+
endpoint: "notifications/edit",
|
|
215
|
+
method: "POST",
|
|
216
|
+
handler: handleEditNotification,
|
|
217
|
+
summary: "Edit an already-sent notification",
|
|
218
|
+
description:
|
|
219
|
+
"Patch the home-feed entry for a notification and, where supported (Slack today), update the delivered message in place.",
|
|
220
|
+
tags: ["notifications"],
|
|
221
|
+
requestBody: EditNotificationParams,
|
|
222
|
+
responseBody: z.object({
|
|
223
|
+
ok: z.boolean(),
|
|
224
|
+
feedItem: z.record(z.string(), z.unknown()),
|
|
225
|
+
channels: z.array(
|
|
226
|
+
z.object({
|
|
227
|
+
channel: z.string(),
|
|
228
|
+
deliveryId: z.string(),
|
|
229
|
+
outcome: z.enum(["updated", "unsupported", "skipped", "failed"]),
|
|
230
|
+
reason: z.string().optional(),
|
|
231
|
+
}),
|
|
232
|
+
),
|
|
233
|
+
}),
|
|
234
|
+
additionalResponses: {
|
|
235
|
+
"404": {
|
|
236
|
+
description: "No notification found for the supplied id",
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
},
|
|
178
240
|
{
|
|
179
241
|
operationId: "list_notification_events",
|
|
180
242
|
endpoint: "notifications/events",
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
resolveOAuthConnection,
|
|
24
24
|
type ResolveOAuthConnectionOptions,
|
|
25
25
|
} from "../../oauth/connection-resolver.js";
|
|
26
|
+
import { syncManualTokenConnection } from "../../oauth/manual-token-connection.js";
|
|
26
27
|
import {
|
|
27
28
|
disconnectOAuthProvider,
|
|
28
29
|
getActiveConnection,
|
|
@@ -516,6 +517,10 @@ async function handleStatus({ queryParams = {} }: RouteHandlerArgs) {
|
|
|
516
517
|
}
|
|
517
518
|
|
|
518
519
|
// BYO path
|
|
520
|
+
if (providerRow.authorizeUrl === "urn:manual-token") {
|
|
521
|
+
await syncManualTokenConnection(provider);
|
|
522
|
+
}
|
|
523
|
+
|
|
519
524
|
const allConnections = listConnections(provider);
|
|
520
525
|
const activeRows = allConnections.filter((r) => r.status === "active");
|
|
521
526
|
|
|
@@ -914,7 +919,7 @@ async function handleManagedConnect({ body = {} }: RouteHandlerArgs) {
|
|
|
914
919
|
reqBody.requested_scopes = b.scopes;
|
|
915
920
|
}
|
|
916
921
|
reqBody.redirect_after_connect =
|
|
917
|
-
b.redirect_after_connect ?? "/account/oauth/
|
|
922
|
+
b.redirect_after_connect ?? "/account/oauth/complete";
|
|
918
923
|
|
|
919
924
|
const response = await client.fetch(startPath, {
|
|
920
925
|
method: "POST",
|
|
@@ -11,13 +11,6 @@ import { z } from "zod";
|
|
|
11
11
|
|
|
12
12
|
import type { ChannelId } from "../../channels/types.js";
|
|
13
13
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
14
|
-
import type { Conversation } from "../../daemon/conversation.js";
|
|
15
|
-
import {
|
|
16
|
-
findConversation,
|
|
17
|
-
findConversationBySurfaceId,
|
|
18
|
-
getOrCreateConversation,
|
|
19
|
-
} from "../../daemon/conversation-store.js";
|
|
20
|
-
import { rawGet } from "../../memory/raw-query.js";
|
|
21
14
|
import { getLogger } from "../../util/logger.js";
|
|
22
15
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
23
16
|
import { healGuardianBindingDrift } from "../guardian-vellum-migration.js";
|
|
@@ -27,6 +20,7 @@ import {
|
|
|
27
20
|
withSourceChannel,
|
|
28
21
|
} from "../trust-context-resolver.js";
|
|
29
22
|
import { BadRequestError, InternalError, NotFoundError, RouteError } from "./errors.js";
|
|
23
|
+
import { resolveSurfaceConversation } from "./surface-conversation-resolver.js";
|
|
30
24
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
31
25
|
|
|
32
26
|
const log = getLogger("surface-action-routes");
|
|
@@ -90,37 +84,6 @@ function applyTrustContext(
|
|
|
90
84
|
}
|
|
91
85
|
}
|
|
92
86
|
|
|
93
|
-
/**
|
|
94
|
-
* Resolve the conversation owning a surface, rehydrating from the DB when
|
|
95
|
-
* the in-memory lookup misses (daemon restart or LRU eviction). The DB scan
|
|
96
|
-
* is also the source of truth that the surface exists — without it,
|
|
97
|
-
* `getOrCreateConversation` would silently create a phantom conversation
|
|
98
|
-
* for any caller-supplied id.
|
|
99
|
-
*/
|
|
100
|
-
async function resolveSurfaceConversation(
|
|
101
|
-
conversationId: string | null | undefined,
|
|
102
|
-
surfaceId: string,
|
|
103
|
-
): Promise<Conversation | undefined> {
|
|
104
|
-
const found = conversationId
|
|
105
|
-
? findConversation(conversationId)
|
|
106
|
-
: findConversationBySurfaceId(surfaceId);
|
|
107
|
-
if (found) return found;
|
|
108
|
-
|
|
109
|
-
// Escape LIKE wildcards so a `surfaceId` like "%" or "_" can't match
|
|
110
|
-
// unrelated rows.
|
|
111
|
-
const escaped = surfaceId.replace(/[\\%_]/g, "\\$&");
|
|
112
|
-
const row = rawGet<{ conversation_id: string }>(
|
|
113
|
-
`SELECT conversation_id FROM messages
|
|
114
|
-
WHERE content LIKE ? ESCAPE '\\'
|
|
115
|
-
ORDER BY created_at DESC
|
|
116
|
-
LIMIT 1`,
|
|
117
|
-
`%"surfaceId":"${escaped}"%`,
|
|
118
|
-
);
|
|
119
|
-
if (!row) return undefined;
|
|
120
|
-
if (conversationId && conversationId !== row.conversation_id) return undefined;
|
|
121
|
-
return await getOrCreateConversation(row.conversation_id);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
87
|
// ---------------------------------------------------------------------------
|
|
125
88
|
// Handlers
|
|
126
89
|
// ---------------------------------------------------------------------------
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
* Route handler for fetching surface content by ID.
|
|
3
3
|
*
|
|
4
4
|
* GET /v1/surfaces/:surfaceId — return the full surface payload from the
|
|
5
|
-
* conversation's in-memory surface state. Used by clients to re-hydrate
|
|
6
|
-
* whose data was stripped during memory compaction
|
|
5
|
+
* conversation's in-memory surface state. Used by clients to re-hydrate
|
|
6
|
+
* surfaces whose data was stripped during memory compaction, or whose
|
|
7
|
+
* owning conversation has been evicted from the daemon's in-memory map
|
|
8
|
+
* (daemon restart, LRU eviction).
|
|
7
9
|
*/
|
|
8
10
|
import { z } from "zod";
|
|
9
11
|
|
|
10
|
-
import { findConversation } from "../../daemon/conversation-store.js";
|
|
11
12
|
import { getLogger } from "../../util/logger.js";
|
|
12
13
|
import { BadRequestError, NotFoundError } from "./errors.js";
|
|
14
|
+
import { resolveSurfaceConversation } from "./surface-conversation-resolver.js";
|
|
13
15
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
14
16
|
|
|
15
17
|
const log = getLogger("surface-content-routes");
|
|
@@ -18,7 +20,7 @@ const log = getLogger("surface-content-routes");
|
|
|
18
20
|
// GET /v1/surfaces/:surfaceId?conversationId=...
|
|
19
21
|
// ---------------------------------------------------------------------------
|
|
20
22
|
|
|
21
|
-
function handleGetSurfaceContent({
|
|
23
|
+
async function handleGetSurfaceContent({
|
|
22
24
|
pathParams = {},
|
|
23
25
|
queryParams = {},
|
|
24
26
|
}: RouteHandlerArgs) {
|
|
@@ -32,7 +34,12 @@ function handleGetSurfaceContent({
|
|
|
32
34
|
throw new BadRequestError("surfaceId path parameter is required");
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
// Resolve via the shared surface→conversation helper: in-memory first,
|
|
38
|
+
// falling back to a DB scan that rehydrates the conversation when the
|
|
39
|
+
// owning Conversation has been evicted or the daemon was restarted. The
|
|
40
|
+
// DB scan uses the surfaceId itself as the existence check so a stale
|
|
41
|
+
// or made-up conversationId can't materialize a phantom conversation.
|
|
42
|
+
const conversation = await resolveSurfaceConversation(conversationId, surfaceId);
|
|
36
43
|
if (!conversation) {
|
|
37
44
|
throw new NotFoundError(
|
|
38
45
|
"No active conversation found for this conversationId",
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helper for resolving the conversation that owns a surface.
|
|
3
|
+
*
|
|
4
|
+
* Used by both `surface-action-routes` (POST /v1/surface-actions) and
|
|
5
|
+
* `surface-content-routes` (GET /v1/surfaces/:surfaceId) so the
|
|
6
|
+
* in-memory-miss → DB-scan → rehydrate flow stays in one place.
|
|
7
|
+
*
|
|
8
|
+
* Why this exists: surfaces live on the in-memory `Conversation` object
|
|
9
|
+
* (`surfaceState` is rebuilt from `ui_surface` blocks in message
|
|
10
|
+
* history by `restoreSurfaceStateFromHistory()` whenever a Conversation
|
|
11
|
+
* is constructed). A bare `findConversation` lookup 404s after daemon
|
|
12
|
+
* restart or LRU eviction even though the surface data is still in the
|
|
13
|
+
* SQLite `messages` table. The DB scan below uses the surfaceId itself
|
|
14
|
+
* as the existence check so `getOrCreateConversation` can't be tricked
|
|
15
|
+
* into materializing a phantom conversation for any caller-supplied id.
|
|
16
|
+
*/
|
|
17
|
+
import type { Conversation } from "../../daemon/conversation.js";
|
|
18
|
+
import {
|
|
19
|
+
findConversation,
|
|
20
|
+
findConversationBySurfaceId,
|
|
21
|
+
getOrCreateConversation,
|
|
22
|
+
} from "../../daemon/conversation-store.js";
|
|
23
|
+
import { rawGet } from "../../memory/raw-query.js";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the {@link Conversation} that owns the given surface.
|
|
27
|
+
*
|
|
28
|
+
* Lookup order:
|
|
29
|
+
* 1. In-memory map keyed by `conversationId` (or by `surfaceId` when no
|
|
30
|
+
* id is supplied).
|
|
31
|
+
* 2. SQLite `messages` table — find the conversation whose history
|
|
32
|
+
* contains a `ui_surface` block with this `surfaceId`. The result is
|
|
33
|
+
* validated against the caller's `conversationId` (when supplied) so
|
|
34
|
+
* a mismatched pair returns `undefined` rather than silently
|
|
35
|
+
* re-routing to a different conversation.
|
|
36
|
+
* 3. `getOrCreateConversation` rehydrates the row, which triggers
|
|
37
|
+
* `restoreSurfaceStateFromHistory()` and repopulates `surfaceState`.
|
|
38
|
+
*
|
|
39
|
+
* Returns `undefined` when neither lookup nor DB scan turns up a
|
|
40
|
+
* matching conversation. Callers are expected to translate that into
|
|
41
|
+
* the route-appropriate 404.
|
|
42
|
+
*/
|
|
43
|
+
export async function resolveSurfaceConversation(
|
|
44
|
+
conversationId: string | null | undefined,
|
|
45
|
+
surfaceId: string,
|
|
46
|
+
): Promise<Conversation | undefined> {
|
|
47
|
+
const found = conversationId
|
|
48
|
+
? findConversation(conversationId)
|
|
49
|
+
: findConversationBySurfaceId(surfaceId);
|
|
50
|
+
if (found) return found;
|
|
51
|
+
|
|
52
|
+
// Escape LIKE wildcards so a `surfaceId` like "%" or "_" can't match
|
|
53
|
+
// unrelated rows.
|
|
54
|
+
const escaped = surfaceId.replace(/[\\%_]/g, "\\$&");
|
|
55
|
+
const row = rawGet<{ conversation_id: string }>(
|
|
56
|
+
`SELECT conversation_id FROM messages
|
|
57
|
+
WHERE content LIKE ? ESCAPE '\\'
|
|
58
|
+
ORDER BY created_at DESC
|
|
59
|
+
LIMIT 1`,
|
|
60
|
+
`%"surfaceId":"${escaped}"%`,
|
|
61
|
+
);
|
|
62
|
+
if (!row) return undefined;
|
|
63
|
+
if (conversationId && conversationId !== row.conversation_id) return undefined;
|
|
64
|
+
return await getOrCreateConversation(row.conversation_id);
|
|
65
|
+
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
|
|
7
7
|
import { destroyActiveConversation } from "../../daemon/conversation-store.js";
|
|
8
|
+
import { stripConversationIds } from "../../home/feed-writer.js";
|
|
8
9
|
import {
|
|
9
10
|
countConversationsByScheduleJobId,
|
|
10
11
|
getConversation,
|
|
@@ -54,6 +55,8 @@ async function handleWipeConversation({ body = {} }: RouteHandlerArgs) {
|
|
|
54
55
|
});
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
void stripConversationIds(conversationId);
|
|
59
|
+
|
|
57
60
|
return {
|
|
58
61
|
wiped: true,
|
|
59
62
|
unsupersededItems: 0,
|
|
@@ -46,6 +46,7 @@ mock.module("../../../memory/conversation-crud.js", () => ({
|
|
|
46
46
|
addMessage: mockAddMessage,
|
|
47
47
|
findAnalysisConversationFor: mockFindAnalysisConversationFor,
|
|
48
48
|
getConversationSource: mockGetConversationSource,
|
|
49
|
+
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
49
50
|
}));
|
|
50
51
|
|
|
51
52
|
mock.module("../../../export/transcript-formatter.js", () => ({
|
|
@@ -80,6 +81,7 @@ const testHub = new AssistantEventHub();
|
|
|
80
81
|
mock.module("../../assistant-event-hub.js", () => ({
|
|
81
82
|
AssistantEventHub,
|
|
82
83
|
assistantEventHub: testHub,
|
|
84
|
+
broadcastMessage: async () => {},
|
|
83
85
|
}));
|
|
84
86
|
|
|
85
87
|
import { analyzeConversation } from "../analyze-conversation.js";
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type { ChannelId } from "../channels/types.js";
|
|
2
|
+
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
3
|
+
import { getLogger } from "../util/logger.js";
|
|
4
|
+
import { deliverChannelReply } from "./gateway-client.js";
|
|
5
|
+
|
|
6
|
+
const log = getLogger("runtime-http");
|
|
7
|
+
|
|
8
|
+
const NO_RESPONSE_INLINE_RE = /<no_response\s*\/?>/gi;
|
|
9
|
+
|
|
10
|
+
export function isSlackDeliveryCallbackUrl(replyCallbackUrl?: string): boolean {
|
|
11
|
+
if (!replyCallbackUrl) return false;
|
|
12
|
+
try {
|
|
13
|
+
return new URL(replyCallbackUrl).pathname.endsWith("/deliver/slack");
|
|
14
|
+
} catch {
|
|
15
|
+
return replyCallbackUrl.endsWith("/deliver/slack");
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function shouldDeliverSlackDmTextResponses(params: {
|
|
20
|
+
sourceChannel: ChannelId;
|
|
21
|
+
chatType?: string;
|
|
22
|
+
replyCallbackUrl?: string;
|
|
23
|
+
}): boolean {
|
|
24
|
+
return (
|
|
25
|
+
params.sourceChannel === "slack" &&
|
|
26
|
+
params.chatType === "im" &&
|
|
27
|
+
isSlackDeliveryCallbackUrl(params.replyCallbackUrl)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type SlackDmTextDeliveryController = {
|
|
32
|
+
observeEvent: (msg: ServerMessage) => void;
|
|
33
|
+
waitForPendingDeliveries: () => Promise<void>;
|
|
34
|
+
getFinalDeliveryResumeOptions: (
|
|
35
|
+
messageId: string | undefined,
|
|
36
|
+
) => { startFromSegment: number; messageTs?: string } | undefined;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export function createSlackDmTextDeliveryController(params: {
|
|
40
|
+
sourceChannel: ChannelId;
|
|
41
|
+
chatType?: string;
|
|
42
|
+
replyCallbackUrl?: string;
|
|
43
|
+
chatId: string;
|
|
44
|
+
assistantId?: string;
|
|
45
|
+
deliveredTextResponseIndexes?: readonly number[];
|
|
46
|
+
onTextResponseDelivered?: (
|
|
47
|
+
responseIndex: number,
|
|
48
|
+
reason: "before_tool" | "message_complete",
|
|
49
|
+
) => void;
|
|
50
|
+
}): SlackDmTextDeliveryController | undefined {
|
|
51
|
+
const { replyCallbackUrl } = params;
|
|
52
|
+
if (!shouldDeliverSlackDmTextResponses(params) || !replyCallbackUrl) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const deliveredTextResponseIndexes = new Set(
|
|
57
|
+
params.deliveredTextResponseIndexes ?? [],
|
|
58
|
+
);
|
|
59
|
+
const messageIdToResponseIndexes = new Map<string, number[]>();
|
|
60
|
+
const responseIndexToMessageTs = new Map<number, string>();
|
|
61
|
+
let textResponseIndex = 0;
|
|
62
|
+
let pendingText = "";
|
|
63
|
+
let currentMessageResponseIndexes: number[] = [];
|
|
64
|
+
let deliveryChain = Promise.resolve();
|
|
65
|
+
|
|
66
|
+
const associateCurrentMessageResponses = (
|
|
67
|
+
messageId: string | undefined,
|
|
68
|
+
): void => {
|
|
69
|
+
if (!messageId || currentMessageResponseIndexes.length === 0) return;
|
|
70
|
+
const responseIndexes = messageIdToResponseIndexes.get(messageId) ?? [];
|
|
71
|
+
for (const responseIndex of currentMessageResponseIndexes) {
|
|
72
|
+
if (!responseIndexes.includes(responseIndex)) {
|
|
73
|
+
responseIndexes.push(responseIndex);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
messageIdToResponseIndexes.set(messageId, responseIndexes);
|
|
77
|
+
currentMessageResponseIndexes = [];
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const flushPendingText = (
|
|
81
|
+
reason: "before_tool" | "message_complete",
|
|
82
|
+
): void => {
|
|
83
|
+
const text = pendingText;
|
|
84
|
+
pendingText = "";
|
|
85
|
+
|
|
86
|
+
const deliverableText = text.replace(NO_RESPONSE_INLINE_RE, "").trim();
|
|
87
|
+
if (deliverableText.length === 0) return;
|
|
88
|
+
|
|
89
|
+
textResponseIndex += 1;
|
|
90
|
+
const currentResponseIndex = textResponseIndex;
|
|
91
|
+
currentMessageResponseIndexes.push(currentResponseIndex);
|
|
92
|
+
if (deliveredTextResponseIndexes.has(currentResponseIndex)) return;
|
|
93
|
+
|
|
94
|
+
deliveryChain = deliveryChain
|
|
95
|
+
.catch(() => undefined)
|
|
96
|
+
.then(async () => {
|
|
97
|
+
let result: Awaited<ReturnType<typeof deliverChannelReply>>;
|
|
98
|
+
try {
|
|
99
|
+
result = await deliverChannelReply(replyCallbackUrl, {
|
|
100
|
+
chatId: params.chatId,
|
|
101
|
+
text: deliverableText,
|
|
102
|
+
assistantId: params.assistantId,
|
|
103
|
+
useBlocks: true,
|
|
104
|
+
});
|
|
105
|
+
} catch (err) {
|
|
106
|
+
log.warn(
|
|
107
|
+
{ err, chatId: params.chatId },
|
|
108
|
+
"Failed to deliver intermediate Slack DM assistant text",
|
|
109
|
+
);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (result.ts) {
|
|
114
|
+
responseIndexToMessageTs.set(currentResponseIndex, result.ts);
|
|
115
|
+
}
|
|
116
|
+
deliveredTextResponseIndexes.add(currentResponseIndex);
|
|
117
|
+
try {
|
|
118
|
+
params.onTextResponseDelivered?.(currentResponseIndex, reason);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
log.warn(
|
|
121
|
+
{ err, chatId: params.chatId, responseIndex: currentResponseIndex },
|
|
122
|
+
"Failed to persist intermediate Slack DM assistant text progress",
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
observeEvent(msg) {
|
|
130
|
+
if (msg.type === "assistant_text_delta") {
|
|
131
|
+
pendingText += msg.text;
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (msg.type === "message_complete") {
|
|
136
|
+
flushPendingText("message_complete");
|
|
137
|
+
if (typeof msg.messageId === "string") {
|
|
138
|
+
associateCurrentMessageResponses(msg.messageId);
|
|
139
|
+
}
|
|
140
|
+
currentMessageResponseIndexes = [];
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (msg.type === "tool_use_start") {
|
|
145
|
+
flushPendingText("before_tool");
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
waitForPendingDeliveries: () => deliveryChain,
|
|
149
|
+
getFinalDeliveryResumeOptions: (messageId) => {
|
|
150
|
+
if (typeof messageId !== "string") {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
const responseIndexes = messageIdToResponseIndexes.get(messageId) ?? [];
|
|
154
|
+
let deliveredPrefixCount = 0;
|
|
155
|
+
for (const responseIndex of responseIndexes) {
|
|
156
|
+
if (!deliveredTextResponseIndexes.has(responseIndex)) break;
|
|
157
|
+
deliveredPrefixCount += 1;
|
|
158
|
+
}
|
|
159
|
+
if (deliveredPrefixCount === 0) return undefined;
|
|
160
|
+
|
|
161
|
+
const firstLiveResponseIndex = responseIndexes[0];
|
|
162
|
+
const allTextResponsesDelivered =
|
|
163
|
+
responseIndexes.length > 0 &&
|
|
164
|
+
responseIndexes.every((responseIndex) =>
|
|
165
|
+
deliveredTextResponseIndexes.has(responseIndex),
|
|
166
|
+
);
|
|
167
|
+
const messageTs =
|
|
168
|
+
allTextResponsesDelivered && firstLiveResponseIndex !== undefined
|
|
169
|
+
? responseIndexToMessageTs.get(firstLiveResponseIndex)
|
|
170
|
+
: undefined;
|
|
171
|
+
return {
|
|
172
|
+
startFromSegment: deliveredPrefixCount,
|
|
173
|
+
...(messageTs ? { messageTs } : {}),
|
|
174
|
+
};
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
@@ -64,7 +64,7 @@ const SHAPE_CHANGING_REASONS: ReadonlySet<ConversationListInvalidatedReason> =
|
|
|
64
64
|
*
|
|
65
65
|
* Web consumes `sync_changed` (`conversationsList` for shape changes,
|
|
66
66
|
* `conversation:<id>:metadata` for content changes) directly and patches
|
|
67
|
-
* the cached list in place — see `
|
|
67
|
+
* the cached list in place — see `useConversationSync` for the consumer
|
|
68
68
|
* side. macOS (`ConversationRestorer.swift`) still listens for the typed
|
|
69
69
|
* broadcast.
|
|
70
70
|
*
|
|
@@ -147,6 +147,7 @@ export function createOrReuseToolGrantRequest(
|
|
|
147
147
|
sourceEventName: "guardian.question",
|
|
148
148
|
sourceChannel: sourceChannel as NotificationSourceChannel,
|
|
149
149
|
sourceContextId: conversationId,
|
|
150
|
+
requiresConversation: true,
|
|
150
151
|
attentionHints: {
|
|
151
152
|
requiresAction: true,
|
|
152
153
|
urgency: "high",
|
|
@@ -17,6 +17,13 @@ const logger = getLogger("schedule-store");
|
|
|
17
17
|
|
|
18
18
|
function notifySchedulesChanged(): void {
|
|
19
19
|
publishSchedulesChanged();
|
|
20
|
+
void import("../background-wake/publisher.js")
|
|
21
|
+
.then(({ refreshBackgroundWakeIntent }) =>
|
|
22
|
+
refreshBackgroundWakeIntent("schedule-changed"),
|
|
23
|
+
)
|
|
24
|
+
.catch((err) =>
|
|
25
|
+
logger.warn({ err }, "Failed to queue background wake refresh"),
|
|
26
|
+
);
|
|
20
27
|
}
|
|
21
28
|
|
|
22
29
|
export type ScheduleMode = "notify" | "execute" | "script" | "wake";
|
|
@@ -124,7 +131,7 @@ export function createSchedule(params: {
|
|
|
124
131
|
const routingIntent = params.routingIntent ?? "all_channels";
|
|
125
132
|
const routingHints = params.routingHints ?? {};
|
|
126
133
|
const quiet = params.quiet ?? false;
|
|
127
|
-
const reuseConversation = params.reuseConversation ??
|
|
134
|
+
const reuseConversation = params.reuseConversation ?? !isOneShot;
|
|
128
135
|
const maxRetries = params.maxRetries ?? 3;
|
|
129
136
|
const retryBackoffMs = params.retryBackoffMs ?? 60000;
|
|
130
137
|
|