@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
|
@@ -34,6 +34,7 @@ import { routeGuardianReply } from "../runtime/guardian-reply-router.js";
|
|
|
34
34
|
import { publishConversationMessagesChanged } from "../runtime/sync/resource-sync-events.js";
|
|
35
35
|
import { getLogger } from "../util/logger.js";
|
|
36
36
|
import type { CleanResult } from "./conversation.js";
|
|
37
|
+
import type { PersistMessageOptions } from "./conversation-messaging.js";
|
|
37
38
|
import {
|
|
38
39
|
persistQueuedMessageBody,
|
|
39
40
|
serializePersistedUserMessageContent,
|
|
@@ -158,12 +159,8 @@ export interface ProcessConversationContext {
|
|
|
158
159
|
currentTurnChannelCapabilities?: ChannelCapabilities;
|
|
159
160
|
ensureActorScopedHistory(): Promise<void>;
|
|
160
161
|
persistUserMessage(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
requestId?: string,
|
|
164
|
-
metadata?: Record<string, unknown>,
|
|
165
|
-
displayContent?: string,
|
|
166
|
-
): Promise<string>;
|
|
162
|
+
options: PersistMessageOptions,
|
|
163
|
+
): Promise<{ id: string; deduplicated: boolean }>;
|
|
167
164
|
runAgentLoop(
|
|
168
165
|
content: string,
|
|
169
166
|
userMessageId: string,
|
|
@@ -921,15 +918,16 @@ async function drainSingleMessage(
|
|
|
921
918
|
// succeeds, runAgentLoop is called and its finally block will drain
|
|
922
919
|
// the next message. If persistUserMessage fails, processMessage
|
|
923
920
|
// resolves early (no runAgentLoop call), so we must continue draining.
|
|
924
|
-
let
|
|
921
|
+
let persistResult: { id: string; deduplicated: boolean };
|
|
925
922
|
try {
|
|
926
|
-
|
|
927
|
-
resolvedContent,
|
|
928
|
-
next.attachments,
|
|
929
|
-
next.requestId,
|
|
930
|
-
{ ...next.metadata, sentAt: next.sentAt },
|
|
931
|
-
next.displayContent,
|
|
932
|
-
|
|
923
|
+
persistResult = await conversation.persistUserMessage({
|
|
924
|
+
content: resolvedContent,
|
|
925
|
+
attachments: next.attachments,
|
|
926
|
+
requestId: next.requestId,
|
|
927
|
+
metadata: { ...next.metadata, sentAt: next.sentAt },
|
|
928
|
+
displayContent: next.displayContent,
|
|
929
|
+
clientMessageId: next.clientMessageId,
|
|
930
|
+
});
|
|
933
931
|
} catch (err) {
|
|
934
932
|
const message = err instanceof Error ? err.message : String(err);
|
|
935
933
|
log.error(
|
|
@@ -961,6 +959,18 @@ async function drainSingleMessage(
|
|
|
961
959
|
return;
|
|
962
960
|
}
|
|
963
961
|
|
|
962
|
+
const userMessageId = persistResult.id;
|
|
963
|
+
|
|
964
|
+
if (persistResult.deduplicated) {
|
|
965
|
+
log.info(
|
|
966
|
+
{ conversationId: conversation.conversationId, userMessageId },
|
|
967
|
+
"Skipping agent loop for deduplicated queued message",
|
|
968
|
+
);
|
|
969
|
+
conversation.preactivatedSkillIds = undefined;
|
|
970
|
+
await drainQueue(conversation);
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
|
|
964
974
|
// Broadcast the user message to all hub subscribers so passive devices
|
|
965
975
|
// see the user turn before the assistant reply starts streaming.
|
|
966
976
|
next.onEvent({
|
|
@@ -1217,24 +1227,43 @@ async function drainBatch(
|
|
|
1217
1227
|
const qmContent = qmSlash.content;
|
|
1218
1228
|
|
|
1219
1229
|
try {
|
|
1230
|
+
let batchPersistResult: { id: string; deduplicated: boolean };
|
|
1231
|
+
const persistOptions = {
|
|
1232
|
+
content: qmContent,
|
|
1233
|
+
attachments: qm.attachments,
|
|
1234
|
+
requestId: qm.requestId,
|
|
1235
|
+
metadata: { ...qm.metadata, sentAt: qm.sentAt },
|
|
1236
|
+
displayContent: qm.displayContent,
|
|
1237
|
+
clientMessageId: qm.clientMessageId,
|
|
1238
|
+
};
|
|
1220
1239
|
if (i === 0) {
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
qm.attachments,
|
|
1224
|
-
qm.requestId,
|
|
1225
|
-
{ ...qm.metadata, sentAt: qm.sentAt },
|
|
1226
|
-
qm.displayContent,
|
|
1227
|
-
);
|
|
1240
|
+
batchPersistResult =
|
|
1241
|
+
await conversation.persistUserMessage(persistOptions);
|
|
1228
1242
|
} else {
|
|
1229
|
-
|
|
1243
|
+
batchPersistResult = await persistQueuedMessageBody(
|
|
1230
1244
|
conversation,
|
|
1231
|
-
|
|
1232
|
-
qm.attachments,
|
|
1233
|
-
qm.requestId,
|
|
1234
|
-
{ ...qm.metadata, sentAt: qm.sentAt },
|
|
1235
|
-
qm.displayContent,
|
|
1245
|
+
persistOptions,
|
|
1236
1246
|
);
|
|
1237
1247
|
}
|
|
1248
|
+
if (batchPersistResult.deduplicated) {
|
|
1249
|
+
if (i === 0) {
|
|
1250
|
+
// Head was deduplicated — persistUserMessage cleared the
|
|
1251
|
+
// processing flag. Recursively drain remaining items so the
|
|
1252
|
+
// first non-duplicate becomes the new batch head and sets
|
|
1253
|
+
// processing via persistUserMessage.
|
|
1254
|
+
const remaining = batch.slice(1);
|
|
1255
|
+
if (remaining.length >= 2) {
|
|
1256
|
+
await drainBatch(conversation, remaining, reason);
|
|
1257
|
+
} else if (remaining.length === 1) {
|
|
1258
|
+
await drainSingleMessage(conversation, remaining[0], reason);
|
|
1259
|
+
} else {
|
|
1260
|
+
await drainQueue(conversation);
|
|
1261
|
+
}
|
|
1262
|
+
return;
|
|
1263
|
+
}
|
|
1264
|
+
continue;
|
|
1265
|
+
}
|
|
1266
|
+
lastUserMessageId = batchPersistResult.id;
|
|
1238
1267
|
} catch (err) {
|
|
1239
1268
|
const message = err instanceof Error ? err.message : String(err);
|
|
1240
1269
|
log.error(
|
|
@@ -1377,12 +1406,19 @@ async function drainBatch(
|
|
|
1377
1406
|
conversation.currentActiveSurfaceId = lastSuccessfulActiveSurfaceId;
|
|
1378
1407
|
conversation.currentPage = lastSuccessfulCurrentPage;
|
|
1379
1408
|
|
|
1380
|
-
// Broadcast agent-loop events only to
|
|
1381
|
-
//
|
|
1382
|
-
//
|
|
1383
|
-
//
|
|
1409
|
+
// Broadcast agent-loop events only to unique sinks whose persist succeeded.
|
|
1410
|
+
// Multiple web-queued messages share the same broadcastMessage callback; if
|
|
1411
|
+
// we call it once per queued message, every text delta is published N times
|
|
1412
|
+
// to the same SSE stream and the client renders duplicated text.
|
|
1413
|
+
//
|
|
1414
|
+
// Members whose persist failed already received an error event in the catch
|
|
1415
|
+
// block above; sending them the assistant's streaming response would surface
|
|
1416
|
+
// a reply for a user message that isn't in their DB.
|
|
1417
|
+
const successfulEventSinks = Array.from(
|
|
1418
|
+
new Set(successfulBatch.map((qm) => qm.onEvent)),
|
|
1419
|
+
);
|
|
1384
1420
|
const fanOutOnEvent = (msg: ServerMessage) => {
|
|
1385
|
-
for (const
|
|
1421
|
+
for (const onEvent of successfulEventSinks) onEvent(msg);
|
|
1386
1422
|
};
|
|
1387
1423
|
|
|
1388
1424
|
const drainLoopOptions: {
|
|
@@ -1857,15 +1893,14 @@ export async function processMessage(
|
|
|
1857
1893
|
}
|
|
1858
1894
|
}
|
|
1859
1895
|
|
|
1860
|
-
let
|
|
1896
|
+
let pmResult: { id: string; deduplicated: boolean };
|
|
1861
1897
|
try {
|
|
1862
|
-
|
|
1863
|
-
resolvedContent,
|
|
1898
|
+
pmResult = await conversation.persistUserMessage({
|
|
1899
|
+
content: resolvedContent,
|
|
1864
1900
|
attachments,
|
|
1865
1901
|
requestId,
|
|
1866
|
-
undefined,
|
|
1867
1902
|
displayContent,
|
|
1868
|
-
);
|
|
1903
|
+
});
|
|
1869
1904
|
publishConversationMessagesChanged(conversation.conversationId);
|
|
1870
1905
|
} catch (err) {
|
|
1871
1906
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -1879,6 +1914,8 @@ export async function processMessage(
|
|
|
1879
1914
|
return "";
|
|
1880
1915
|
}
|
|
1881
1916
|
|
|
1917
|
+
const userMessageId = pmResult.id;
|
|
1918
|
+
|
|
1882
1919
|
// Fire-and-forget: detect notification preferences in the user message
|
|
1883
1920
|
// and persist any that are found. Runs in the background so it doesn't
|
|
1884
1921
|
// block the main conversation flow.
|
|
@@ -997,23 +997,38 @@ export function buildUnifiedTurnContextBlock(
|
|
|
997
997
|
// ---------------------------------------------------------------------------
|
|
998
998
|
|
|
999
999
|
/**
|
|
1000
|
-
*
|
|
1001
|
-
*
|
|
1002
|
-
* the
|
|
1000
|
+
* A matcher for an injected text block. A plain string matches by prefix
|
|
1001
|
+
* (`startsWith`). A `{ prefix, suffix }` wrapper requires BOTH the opening
|
|
1002
|
+
* prefix and the closing suffix, so user-authored content that merely begins
|
|
1003
|
+
* with an injection-like opening tag (e.g. a message discussing `<info>`
|
|
1004
|
+
* markup) is not mistaken for an injected block and dropped. This mirrors
|
|
1005
|
+
* `countMemoryPrefixBlocks`, which only treats `<memory>…</memory>` /
|
|
1006
|
+
* `<info>…</info>` blocks as injected when the full wrapper is present.
|
|
1007
|
+
*/
|
|
1008
|
+
type InjectionMatcher = string | { prefix: string; suffix: string };
|
|
1009
|
+
|
|
1010
|
+
/**
|
|
1011
|
+
* Remove text blocks from user messages that match any of the given matchers.
|
|
1012
|
+
* If stripping removes all content blocks from a message, the message itself
|
|
1013
|
+
* is dropped.
|
|
1003
1014
|
*
|
|
1004
1015
|
* This is the shared primitive behind the individual strip* functions and
|
|
1005
1016
|
* the `stripInjectionsForCompaction` pipeline.
|
|
1006
1017
|
*/
|
|
1007
1018
|
function stripUserTextBlocksByPrefix(
|
|
1008
1019
|
messages: Message[],
|
|
1009
|
-
|
|
1020
|
+
matchers: InjectionMatcher[],
|
|
1010
1021
|
): Message[] {
|
|
1011
1022
|
return messages
|
|
1012
1023
|
.map((message) => {
|
|
1013
1024
|
if (message.role !== "user") return message;
|
|
1014
1025
|
const nextContent = message.content.filter((block) => {
|
|
1015
1026
|
if (block.type !== "text") return true;
|
|
1016
|
-
return !
|
|
1027
|
+
return !matchers.some((m) =>
|
|
1028
|
+
typeof m === "string"
|
|
1029
|
+
? block.text.startsWith(m)
|
|
1030
|
+
: block.text.startsWith(m.prefix) && block.text.endsWith(m.suffix),
|
|
1031
|
+
);
|
|
1017
1032
|
});
|
|
1018
1033
|
if (nextContent.length === message.content.length) return message;
|
|
1019
1034
|
if (nextContent.length === 0) return null;
|
|
@@ -1720,8 +1735,8 @@ export function loadSlackActiveThreadFocusBlock(
|
|
|
1720
1735
|
return assembleSlackActiveThreadFocusBlock(rows, capabilities);
|
|
1721
1736
|
}
|
|
1722
1737
|
|
|
1723
|
-
/**
|
|
1724
|
-
const RUNTIME_INJECTION_PREFIXES = [
|
|
1738
|
+
/** Matchers stripped by the pipeline (order doesn't matter — single pass). */
|
|
1739
|
+
const RUNTIME_INJECTION_PREFIXES: InjectionMatcher[] = [
|
|
1725
1740
|
"<channel_capabilities>",
|
|
1726
1741
|
"<channel_command_context>",
|
|
1727
1742
|
"<disk_pressure_warning>",
|
|
@@ -1742,8 +1757,13 @@ const RUNTIME_INJECTION_PREFIXES = [
|
|
|
1742
1757
|
// cadence. The activation pipeline dedupes via `everInjected`, and
|
|
1743
1758
|
// compaction handles aggregate growth, so accumulation does not cause
|
|
1744
1759
|
// unbounded context growth. Both wrappers may appear in persisted rows.
|
|
1745
|
-
|
|
1746
|
-
|
|
1760
|
+
//
|
|
1761
|
+
// These two use the full `{ prefix, suffix }` wrapper shape (not a bare
|
|
1762
|
+
// prefix) so that user-authored text merely starting with `<memory>\n` or
|
|
1763
|
+
// `<info>\n` is never silently dropped during compaction/`/clean`. This
|
|
1764
|
+
// matches the full-wrapper requirement in `countMemoryPrefixBlocks`.
|
|
1765
|
+
{ prefix: "<memory>\n", suffix: "\n</memory>" },
|
|
1766
|
+
{ prefix: "<info>\n", suffix: "\n</info>" },
|
|
1747
1767
|
"<voice_call_control>",
|
|
1748
1768
|
"<workspace_top_level>", // backward-compat: strip legacy workspace blocks
|
|
1749
1769
|
// NOTE: <workspace> is intentionally NOT stripped — workspace context
|
|
@@ -23,6 +23,7 @@ import { parseToolManifestFile } from "../skills/tool-manifest.js";
|
|
|
23
23
|
import { computeSkillVersionHash } from "../skills/version-hash.js";
|
|
24
24
|
import {
|
|
25
25
|
getTool,
|
|
26
|
+
getToolOwner,
|
|
26
27
|
registerSkillTools,
|
|
27
28
|
unregisterSkillTools,
|
|
28
29
|
} from "../tools/registry.js";
|
|
@@ -313,7 +314,6 @@ export function projectSkillTools(
|
|
|
313
314
|
// Create runtime Tool objects
|
|
314
315
|
const tools = createSkillToolsFromManifest(
|
|
315
316
|
manifest.tools,
|
|
316
|
-
skillId,
|
|
317
317
|
skill.directoryPath,
|
|
318
318
|
currentHash,
|
|
319
319
|
skill.bundled,
|
|
@@ -324,7 +324,7 @@ export function projectSkillTools(
|
|
|
324
324
|
const prevHash = prevActive.get(skillId);
|
|
325
325
|
if (prevHash === undefined) {
|
|
326
326
|
// Newly active skill — register for the first time
|
|
327
|
-
accepted = registerSkillTools(tools);
|
|
327
|
+
accepted = registerSkillTools(skillId, tools);
|
|
328
328
|
} else if (prevHash !== currentHash) {
|
|
329
329
|
// Hash changed — unregister stale tools, then re-register with new definitions
|
|
330
330
|
log.info(
|
|
@@ -334,7 +334,7 @@ export function projectSkillTools(
|
|
|
334
334
|
unregisterSkillTools(skillId);
|
|
335
335
|
alreadyUnregistered.add(skillId);
|
|
336
336
|
try {
|
|
337
|
-
accepted = registerSkillTools(tools);
|
|
337
|
+
accepted = registerSkillTools(skillId, tools);
|
|
338
338
|
} catch (err) {
|
|
339
339
|
log.error(
|
|
340
340
|
{ err, skillId },
|
|
@@ -344,33 +344,17 @@ export function projectSkillTools(
|
|
|
344
344
|
continue;
|
|
345
345
|
}
|
|
346
346
|
} else {
|
|
347
|
-
// Hash unchanged —
|
|
348
|
-
//
|
|
349
|
-
//
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
);
|
|
359
|
-
unregisterSkillTools(skillId);
|
|
360
|
-
accepted = registerSkillTools(tools);
|
|
361
|
-
} else {
|
|
362
|
-
// Filter to only tools that are actually registered for this skill.
|
|
363
|
-
// Some tools may have been skipped during initial registration due
|
|
364
|
-
// to core-name collisions — don't let them leak back in.
|
|
365
|
-
accepted = tools.filter((t) => {
|
|
366
|
-
const reg = getTool(t.name);
|
|
367
|
-
return (
|
|
368
|
-
reg !== undefined &&
|
|
369
|
-
reg.origin === "skill" &&
|
|
370
|
-
reg.ownerSkillId === skillId
|
|
371
|
-
);
|
|
372
|
-
});
|
|
373
|
-
}
|
|
347
|
+
// Hash unchanged — filter to only tools that are actually registered
|
|
348
|
+
// for this skill. Some tools may have been skipped during initial
|
|
349
|
+
// registration due to core-name collisions — don't let them leak
|
|
350
|
+
// back in. Bundled-status drift no longer requires re-registration
|
|
351
|
+
// because the permission checker derives bundled state from the
|
|
352
|
+
// live catalog instead of a stamped tool field.
|
|
353
|
+
accepted = tools.filter((t) => {
|
|
354
|
+
if (getTool(t.name) === undefined) return false;
|
|
355
|
+
const owner = getToolOwner(t.name);
|
|
356
|
+
return owner?.kind === "skill" && owner.id === skillId;
|
|
357
|
+
});
|
|
374
358
|
}
|
|
375
359
|
|
|
376
360
|
successfulEntries.set(skillId, currentHash);
|
|
@@ -28,6 +28,7 @@ import { getLogger } from "../util/logger.js";
|
|
|
28
28
|
import { isPlainObject } from "../util/object.js";
|
|
29
29
|
import { buildConversationErrorMessage } from "./conversation-error.js";
|
|
30
30
|
import { launchConversation } from "./conversation-launch.js";
|
|
31
|
+
import type { EnqueueMessageOptions } from "./conversation-messaging.js";
|
|
31
32
|
import type { HostAppControlProxy } from "./host-app-control-proxy.js";
|
|
32
33
|
import type { HostCuProxy } from "./host-cu-proxy.js";
|
|
33
34
|
import type {
|
|
@@ -45,7 +46,6 @@ import type {
|
|
|
45
46
|
UiSurfaceShow,
|
|
46
47
|
} from "./message-protocol.js";
|
|
47
48
|
import { INTERACTIVE_SURFACE_TYPES } from "./message-protocol.js";
|
|
48
|
-
import type { ConversationTransportMetadata } from "./message-types/conversations.js";
|
|
49
49
|
import type { HostAppControlInput } from "./message-types/host-app-control.js";
|
|
50
50
|
import type { UserMessageAttachment } from "./message-types/shared.js";
|
|
51
51
|
import type { TrustContext } from "./trust-context.js";
|
|
@@ -518,18 +518,11 @@ export interface SurfaceConversationContext {
|
|
|
518
518
|
/** True when no interactive client is connected (headless / channel-only). */
|
|
519
519
|
readonly hasNoClient?: boolean;
|
|
520
520
|
isProcessing(): boolean;
|
|
521
|
-
enqueueMessage(
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
activeSurfaceId?: string,
|
|
527
|
-
currentPage?: string,
|
|
528
|
-
metadata?: Record<string, unknown>,
|
|
529
|
-
options?: { isInteractive?: boolean },
|
|
530
|
-
displayContent?: string,
|
|
531
|
-
transport?: ConversationTransportMetadata,
|
|
532
|
-
): { queued: boolean; requestId: string; rejected?: boolean };
|
|
521
|
+
enqueueMessage(options: EnqueueMessageOptions): {
|
|
522
|
+
queued: boolean;
|
|
523
|
+
requestId: string;
|
|
524
|
+
rejected?: boolean;
|
|
525
|
+
};
|
|
533
526
|
getQueueDepth(): number;
|
|
534
527
|
processMessage(
|
|
535
528
|
content: string,
|
|
@@ -1142,6 +1135,34 @@ export type SurfaceActionResult =
|
|
|
1142
1135
|
| { accepted: false; error: string }
|
|
1143
1136
|
| void;
|
|
1144
1137
|
|
|
1138
|
+
const SURFACE_COMPLETE_FLAG = "_completeSurface";
|
|
1139
|
+
const SURFACE_COMPLETION_SUMMARY_FIELD = "_completionSummary";
|
|
1140
|
+
|
|
1141
|
+
function getRequestedSurfaceCompletionSummary(
|
|
1142
|
+
data?: Record<string, unknown>,
|
|
1143
|
+
): string | null {
|
|
1144
|
+
if (data?.[SURFACE_COMPLETE_FLAG] !== true) return null;
|
|
1145
|
+
const summary =
|
|
1146
|
+
typeof data[SURFACE_COMPLETION_SUMMARY_FIELD] === "string"
|
|
1147
|
+
? data[SURFACE_COMPLETION_SUMMARY_FIELD].trim()
|
|
1148
|
+
: "";
|
|
1149
|
+
return summary || "Completed";
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
function completeSurfaceFromAction(
|
|
1153
|
+
ctx: SurfaceConversationContext,
|
|
1154
|
+
surfaceId: string,
|
|
1155
|
+
summary: string,
|
|
1156
|
+
): void {
|
|
1157
|
+
broadcastMessage({
|
|
1158
|
+
type: "ui_surface_complete",
|
|
1159
|
+
conversationId: ctx.conversationId,
|
|
1160
|
+
surfaceId,
|
|
1161
|
+
summary,
|
|
1162
|
+
});
|
|
1163
|
+
markSurfaceCompleted(ctx, surfaceId, summary);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1145
1166
|
export async function handleSurfaceAction(
|
|
1146
1167
|
ctx: SurfaceConversationContext,
|
|
1147
1168
|
surfaceId: string,
|
|
@@ -1318,9 +1339,16 @@ export async function handleSurfaceAction(
|
|
|
1318
1339
|
}
|
|
1319
1340
|
|
|
1320
1341
|
// Determine message content from the action.
|
|
1342
|
+
const stored = ctx.surfaceState.get(surfaceId);
|
|
1343
|
+
const actionDef = stored?.actions?.find((a) => a.id === actionId);
|
|
1344
|
+
const mergedData: Record<string, unknown> | undefined =
|
|
1345
|
+
actionDef?.data || data ? { ...actionDef?.data, ...data } : undefined;
|
|
1346
|
+
|
|
1321
1347
|
const isRelay = actionId === "relay_prompt" || actionId === "agent_prompt";
|
|
1322
1348
|
const prompt =
|
|
1323
|
-
isRelay && typeof
|
|
1349
|
+
isRelay && typeof mergedData?.prompt === "string"
|
|
1350
|
+
? mergedData.prompt.trim()
|
|
1351
|
+
: "";
|
|
1324
1352
|
|
|
1325
1353
|
// Read accumulated state once — used by both relay and custom action paths.
|
|
1326
1354
|
const accState = ctx.accumulatedSurfaceState.get(surfaceId);
|
|
@@ -1329,9 +1357,9 @@ export async function handleSurfaceAction(
|
|
|
1329
1357
|
// Extract file attachments from action data so they are sent as proper
|
|
1330
1358
|
// image/file content blocks instead of dumping base64 into the text.
|
|
1331
1359
|
let attachments: UserMessageAttachment[] = [];
|
|
1332
|
-
let actionDataForText =
|
|
1333
|
-
if (
|
|
1334
|
-
const files =
|
|
1360
|
+
let actionDataForText = mergedData;
|
|
1361
|
+
if (mergedData && Array.isArray(mergedData.files)) {
|
|
1362
|
+
const files = mergedData.files as Array<Record<string, unknown>>;
|
|
1335
1363
|
attachments = files
|
|
1336
1364
|
.filter(
|
|
1337
1365
|
(f) =>
|
|
@@ -1351,7 +1379,7 @@ export async function handleSurfaceAction(
|
|
|
1351
1379
|
// attachments — otherwise preserve the original data so the model still
|
|
1352
1380
|
// sees the files field (e.g. IDs/paths from dynamic app actions).
|
|
1353
1381
|
if (attachments.length > 0) {
|
|
1354
|
-
const { files: _files, ...rest } =
|
|
1382
|
+
const { files: _files, ...rest } = mergedData;
|
|
1355
1383
|
actionDataForText = Object.keys(rest).length > 0 ? rest : undefined;
|
|
1356
1384
|
}
|
|
1357
1385
|
}
|
|
@@ -1414,23 +1442,26 @@ export async function handleSurfaceAction(
|
|
|
1414
1442
|
attributes: { source: "surface_action", surfaceId, actionId },
|
|
1415
1443
|
});
|
|
1416
1444
|
|
|
1417
|
-
const result = ctx.enqueueMessage(
|
|
1445
|
+
const result = ctx.enqueueMessage({
|
|
1418
1446
|
content,
|
|
1419
1447
|
attachments,
|
|
1420
1448
|
onEvent,
|
|
1421
1449
|
requestId,
|
|
1422
|
-
surfaceId,
|
|
1423
|
-
undefined,
|
|
1424
|
-
undefined,
|
|
1425
|
-
undefined,
|
|
1450
|
+
activeSurfaceId: surfaceId,
|
|
1426
1451
|
displayContent,
|
|
1427
|
-
);
|
|
1452
|
+
});
|
|
1428
1453
|
|
|
1429
1454
|
if (result.rejected) {
|
|
1430
1455
|
ctx.surfaceActionRequestIds.delete(requestId);
|
|
1431
1456
|
return;
|
|
1432
1457
|
}
|
|
1433
1458
|
|
|
1459
|
+
const requestedCompletionSummary =
|
|
1460
|
+
getRequestedSurfaceCompletionSummary(mergedData);
|
|
1461
|
+
if (requestedCompletionSummary) {
|
|
1462
|
+
completeSurfaceFromAction(ctx, surfaceId, requestedCompletionSummary);
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1434
1465
|
// One-shot: clear accumulated state now that the message has been accepted.
|
|
1435
1466
|
// Deferred until after rejection check so state is preserved for retry on rejection.
|
|
1436
1467
|
if (hasAccState) {
|
|
@@ -1653,22 +1684,22 @@ export async function handleSurfaceAction(
|
|
|
1653
1684
|
"Surface action follow-up: preparing to send message to model",
|
|
1654
1685
|
);
|
|
1655
1686
|
|
|
1656
|
-
const result = ctx.enqueueMessage(
|
|
1687
|
+
const result = ctx.enqueueMessage({
|
|
1657
1688
|
content,
|
|
1658
|
-
pendingAttachments,
|
|
1689
|
+
attachments: pendingAttachments,
|
|
1659
1690
|
onEvent,
|
|
1660
1691
|
requestId,
|
|
1661
|
-
surfaceId,
|
|
1662
|
-
undefined,
|
|
1663
|
-
undefined,
|
|
1664
|
-
undefined,
|
|
1692
|
+
activeSurfaceId: surfaceId,
|
|
1665
1693
|
displayContent,
|
|
1666
|
-
);
|
|
1694
|
+
});
|
|
1667
1695
|
if (result.rejected) {
|
|
1668
1696
|
ctx.surfaceActionRequestIds.delete(requestId);
|
|
1669
1697
|
return;
|
|
1670
1698
|
}
|
|
1671
1699
|
|
|
1700
|
+
const requestedCompletionSummary =
|
|
1701
|
+
getRequestedSurfaceCompletionSummary(mergedData);
|
|
1702
|
+
|
|
1672
1703
|
// One-shot interactive surfaces — auto-complete now that the message has
|
|
1673
1704
|
// been accepted. Deferred until after rejection check so the surface stays
|
|
1674
1705
|
// active and retryable if the queue was full.
|
|
@@ -1678,15 +1709,19 @@ export async function handleSurfaceAction(
|
|
|
1678
1709
|
"file_upload",
|
|
1679
1710
|
"task_preferences",
|
|
1680
1711
|
];
|
|
1681
|
-
if (
|
|
1712
|
+
if (
|
|
1713
|
+
requestedCompletionSummary ||
|
|
1714
|
+
ONE_SHOT_SURFACE_TYPES.includes(pending.surfaceType)
|
|
1715
|
+
) {
|
|
1716
|
+
const completionSummary = requestedCompletionSummary ?? summary;
|
|
1682
1717
|
broadcastMessage({
|
|
1683
1718
|
type: "ui_surface_complete",
|
|
1684
1719
|
conversationId: ctx.conversationId,
|
|
1685
1720
|
surfaceId,
|
|
1686
|
-
summary,
|
|
1721
|
+
summary: completionSummary,
|
|
1687
1722
|
submittedData: mergedDataForText,
|
|
1688
1723
|
});
|
|
1689
|
-
markSurfaceCompleted(ctx, surfaceId,
|
|
1724
|
+
markSurfaceCompleted(ctx, surfaceId, completionSummary);
|
|
1690
1725
|
}
|
|
1691
1726
|
|
|
1692
1727
|
// One-shot: clear accumulated state now that the message has been accepted.
|