@vellumai/assistant 0.8.2 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +11 -12
- package/docker-entrypoint.sh +13 -2
- package/docker-init-apt-root.sh +79 -6
- package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
- package/openapi.yaml +945 -36
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +271 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- package/src/__tests__/agent-loop.test.ts +88 -3
- package/src/__tests__/anthropic-provider.test.ts +272 -0
- package/src/__tests__/approval-cascade.test.ts +1 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/channel-delivery-store.test.ts +193 -0
- package/src/__tests__/channel-reply-delivery.test.ts +284 -5
- package/src/__tests__/channel-retry-sweep.test.ts +274 -1
- package/src/__tests__/compaction-events.test.ts +1 -1
- package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
- package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/context-token-estimator.test.ts +112 -57
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
- package/src/__tests__/conversation-agent-loop.test.ts +77 -3
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-clean-command.test.ts +137 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +161 -0
- package/src/__tests__/conversation-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-media-retry.test.ts +19 -8
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-process-callsite.test.ts +1 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +290 -85
- package/src/__tests__/conversation-seed-composer.test.ts +66 -4
- package/src/__tests__/conversation-slash-commands.test.ts +36 -8
- package/src/__tests__/conversation-slash-queue.test.ts +1 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
- package/src/__tests__/conversation-speed-override.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +6 -0
- package/src/__tests__/cu-unified-flow.test.ts +10 -1
- package/src/__tests__/date-context.test.ts +45 -0
- package/src/__tests__/dm-backfill.test.ts +64 -0
- package/src/__tests__/dm-persistence.test.ts +33 -0
- package/src/__tests__/document-find-replace.test.ts +501 -0
- package/src/__tests__/external-plugin-loader.test.ts +91 -19
- package/src/__tests__/first-greeting.test.ts +23 -2
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/headless-browser-navigate.test.ts +172 -0
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/host-app-control-proxy.test.ts +241 -0
- package/src/__tests__/host-bash-proxy.test.ts +6 -0
- package/src/__tests__/host-browser-proxy.test.ts +10 -0
- package/src/__tests__/host-cu-proxy.test.ts +8 -1
- package/src/__tests__/host-file-proxy.test.ts +8 -1
- package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
- package/src/__tests__/host-transfer-proxy.test.ts +8 -1
- package/src/__tests__/identity-routes.test.ts +57 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
- package/src/__tests__/injector-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +7 -0
- package/src/__tests__/injector-document-comments.test.ts +378 -0
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -2
- package/src/__tests__/list-messages-attachments.test.ts +21 -17
- package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
- package/src/__tests__/list-messages-page-latest.test.ts +130 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
- package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +3 -0
- package/src/__tests__/llm-context-normalization.test.ts +0 -2
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
- package/src/__tests__/llm-resolver.test.ts +340 -3
- package/src/__tests__/log-export-routes.test.ts +99 -2
- package/src/__tests__/managed-profile-guard.test.ts +10 -0
- package/src/__tests__/message-queue-steer.test.ts +114 -0
- package/src/__tests__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
- package/src/__tests__/openai-provider.test.ts +323 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
- package/src/__tests__/openai-responses-provider.test.ts +4 -4
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
- package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
- package/src/__tests__/platform-proxy-context.test.ts +6 -1
- package/src/__tests__/platform.test.ts +0 -3
- package/src/__tests__/plugin-source-watcher.test.ts +302 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
- package/src/__tests__/plugin-types.test.ts +2 -2
- package/src/__tests__/process-message-background-slack.test.ts +1 -51
- package/src/__tests__/process-message-display-content.test.ts +21 -16
- package/src/__tests__/provider-catalog-visibility.test.ts +16 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +83 -4
- package/src/__tests__/steer-tool-repair.test.ts +249 -0
- package/src/__tests__/system-prompt.test.ts +57 -101
- package/src/__tests__/terminal-tools.test.ts +11 -1
- package/src/__tests__/thinking-block-replay.test.ts +113 -0
- package/src/__tests__/thread-backfill.test.ts +370 -22
- package/src/__tests__/tool-executor.test.ts +90 -1
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/web-fetch.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +88 -5
- package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
- package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
- package/src/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/agent/attachments.ts +1 -0
- package/src/agent/loop.ts +208 -22
- package/src/background-wake/next-wake.test.ts +289 -0
- package/src/background-wake/next-wake.ts +172 -0
- package/src/browser/operations.ts +15 -0
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +14 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +469 -0
- package/src/cli/commands/conversations.ts +128 -1
- package/src/cli/commands/inference-providers.ts +147 -1
- package/src/cli/commands/memory-v2.ts +308 -0
- package/src/cli/commands/notifications.ts +89 -37
- package/src/cli/commands/plugins.ts +67 -0
- package/src/cli/commands/schedules.ts +297 -5
- package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
- package/src/cli/lib/install-from-github.ts +8 -9
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/program.ts +14 -0
- package/src/cli/utils/conversation-id.ts +17 -5
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
- package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
- package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
- package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +8 -0
- package/src/config/bundled-tool-registry.ts +22 -12
- package/src/config/call-site-defaults.ts +124 -0
- package/src/config/feature-flag-registry.json +111 -23
- package/src/config/llm-resolver.ts +66 -1
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +7 -3
- package/src/config/schemas/call-site-catalog.ts +21 -0
- package/src/config/schemas/channels.ts +9 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +14 -0
- package/src/config/schemas/llm.ts +4 -3
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +51 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/context/compactor.ts +80 -13
- package/src/context/token-estimator.ts +72 -31
- package/src/context/window-manager.ts +25 -0
- package/src/credential-health/credential-health-service.ts +34 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +231 -23
- package/src/daemon/conversation-agent-loop.ts +252 -56
- package/src/daemon/conversation-lifecycle.ts +142 -116
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +273 -0
- package/src/daemon/conversation-queue-manager.ts +14 -0
- package/src/daemon/conversation-runtime-assembly.ts +144 -75
- package/src/daemon/conversation-slash.ts +37 -5
- package/src/daemon/conversation-surfaces.ts +45 -2
- package/src/daemon/conversation-tool-setup.ts +7 -0
- package/src/daemon/conversation.ts +42 -12
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/first-greeting.ts +10 -0
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +449 -0
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +80 -0
- package/src/daemon/handlers/shared.ts +92 -29
- package/src/daemon/host-app-control-proxy.ts +69 -18
- package/src/daemon/host-bash-proxy.ts +1 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/host-file-proxy.ts +1 -1
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/host-transfer-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +67 -65
- package/src/daemon/memory-v2-startup.ts +49 -13
- package/src/daemon/message-protocol.ts +4 -0
- package/src/daemon/message-types/conversations.ts +8 -0
- package/src/daemon/message-types/document-comments.ts +50 -0
- package/src/daemon/message-types/messages.ts +68 -1
- package/src/daemon/message-types/notifications.ts +21 -0
- package/src/daemon/message-types/surfaces.ts +3 -1
- package/src/daemon/message-types/web-activity.ts +57 -0
- package/src/daemon/pkb-reminder-builder.test.ts +10 -53
- package/src/daemon/pkb-reminder-builder.ts +4 -19
- package/src/daemon/plugin-source-watcher.ts +135 -3
- package/src/daemon/process-message.ts +72 -12
- package/src/daemon/query-complexity-router.ts +75 -0
- package/src/daemon/skill-memory-refresh.ts +5 -1
- package/src/daemon/trust-context.ts +6 -0
- package/src/daemon/wake-target-adapter.ts +2 -0
- package/src/documents/document-comments-store.test.ts +338 -0
- package/src/documents/document-comments-store.ts +237 -0
- package/src/documents/document-store.ts +202 -0
- package/src/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -1
- package/src/heartbeat/heartbeat-service.ts +35 -191
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/__tests__/suggested-prompts.test.ts +33 -2
- package/src/home/feed-types.ts +20 -3
- package/src/home/home-content-refresh.ts +52 -0
- package/src/home/home-greeting-cache.ts +69 -0
- package/src/home/home-greeting.ts +94 -0
- package/src/home/suggested-prompts.ts +177 -9
- package/src/ipc/cli-client.ts +147 -45
- package/src/memory/__tests__/conversation-queries.test.ts +220 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +407 -10
- package/src/memory/conversation-crud.ts +133 -43
- package/src/memory/conversation-queries.ts +87 -1
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +22 -0
- package/src/memory/delivery-crud.ts +41 -0
- package/src/memory/delivery-status.ts +141 -15
- package/src/memory/external-conversation-store.ts +32 -1
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
- package/src/memory/graph/conversation-graph-memory.ts +18 -6
- package/src/memory/graph/tools.ts +6 -37
- package/src/memory/invite-store.ts +53 -0
- package/src/memory/jobs-worker.ts +21 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/memory-retrospective-constants.ts +28 -0
- package/src/memory/memory-retrospective-enqueue.ts +4 -22
- package/src/memory/memory-retrospective-job.ts +438 -21
- package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
- package/src/memory/memory-v2-activation-log-store.ts +26 -8
- package/src/memory/migrations/100-core-tables.ts +1 -0
- package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
- package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
- package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
- package/src/memory/migrations/253-document-comments.ts +47 -0
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
- package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
- package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
- package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
- package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
- package/src/memory/migrations/index.ts +20 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/onboarding-events-store.ts +7 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +2 -0
- package/src/memory/schema/infrastructure.ts +2 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/memory/v2/__tests__/injection.test.ts +221 -17
- package/src/memory/v2/__tests__/page-index.test.ts +365 -1
- package/src/memory/v2/__tests__/router.test.ts +489 -1
- package/src/memory/v2/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/consolidation-job.ts +14 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection-events.ts +101 -0
- package/src/memory/v2/injection.ts +69 -29
- package/src/memory/v2/page-index.ts +246 -19
- package/src/memory/v2/page-store.ts +18 -0
- package/src/memory/v2/router.ts +209 -55
- package/src/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +18 -3
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
- package/src/messaging/providers/slack/adapter.ts +178 -25
- package/src/messaging/providers/slack/api.test.ts +54 -0
- package/src/messaging/providers/slack/api.ts +119 -3
- package/src/messaging/providers/slack/client.ts +12 -0
- package/src/messaging/providers/slack/deep-link.ts +20 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
- package/src/messaging/providers/slack/message-metadata.ts +156 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
- package/src/messaging/providers/slack/render-transcript.ts +176 -49
- package/src/messaging/providers/slack/send.test.ts +77 -0
- package/src/messaging/providers/slack/send.ts +8 -2
- package/src/messaging/providers/slack/types.ts +14 -0
- package/src/notifications/__tests__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +5 -1
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +521 -36
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/conversation-seed-composer.ts +14 -2
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +111 -44
- package/src/notifications/deferred-emit.ts +135 -0
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +10 -1
- package/src/notifications/home-feed-side-effect.ts +136 -27
- package/src/notifications/signal.ts +0 -4
- package/src/notifications/types.ts +8 -0
- package/src/oauth/connect-orchestrator.ts +3 -0
- package/src/oauth/credential-token-resolver.ts +2 -0
- package/src/oauth/manual-token-connection.ts +19 -0
- package/src/oauth/oauth-store.ts +12 -0
- package/src/oauth/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +13 -4
- package/src/oauth/seed-providers.ts +22 -0
- package/src/permissions/prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +4 -1
- package/src/plugins/defaults/injectors.ts +118 -26
- package/src/plugins/external-plugin-loader.ts +82 -10
- package/src/plugins/types.ts +16 -7
- package/src/prompts/__tests__/system-prompt.test.ts +44 -45
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
- package/src/prompts/normalize-onboarding.ts +40 -0
- package/src/prompts/sections.ts +32 -14
- package/src/prompts/system-prompt.ts +105 -76
- package/src/prompts/template-detection.ts +37 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/VOICE.md +3 -0
- package/src/prompts/templates/system-sections.ts +51 -10
- package/src/providers/__tests__/inference.test.ts +2 -0
- package/src/providers/anthropic/client.ts +132 -5
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +63 -13
- package/src/providers/fireworks/client.ts +20 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
- package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +24 -21
- package/src/providers/inference/auth.ts +15 -3
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/codex-token-refresh.ts +128 -0
- package/src/providers/inference/connections.ts +85 -5
- package/src/providers/inference/resolve-auth.ts +50 -5
- package/src/providers/model-catalog.ts +244 -242
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +215 -25
- package/src/providers/openai/responses-provider.ts +9 -3
- package/src/providers/openrouter/client.ts +46 -4
- package/src/providers/platform-proxy/constants.ts +3 -4
- package/src/providers/provider-catalog-visibility.ts +3 -1
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +30 -1
- package/src/providers/types.ts +25 -0
- package/src/runtime/__tests__/agent-wake.test.ts +214 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
- package/src/runtime/agent-wake.ts +212 -57
- package/src/runtime/auth/route-policy.ts +20 -3
- package/src/runtime/background-job-runner.ts +26 -0
- package/src/runtime/channel-reply-delivery.ts +182 -47
- package/src/runtime/channel-retry-sweep.ts +141 -16
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +7 -51
- package/src/runtime/pending-interactions.ts +51 -8
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +121 -5
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
- package/src/runtime/routes/approval-routes.ts +4 -1
- package/src/runtime/routes/channel-availability-routes.ts +5 -0
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -0
- package/src/runtime/routes/content-source-routes.ts +78 -0
- package/src/runtime/routes/conversation-cli-routes.ts +146 -1
- package/src/runtime/routes/conversation-query-routes.ts +130 -12
- package/src/runtime/routes/conversation-routes.ts +288 -76
- package/src/runtime/routes/document-comments-routes.ts +287 -0
- package/src/runtime/routes/documents-routes.ts +33 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -3
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-browser-routes.ts +8 -1
- package/src/runtime/routes/identity-routes.ts +21 -0
- package/src/runtime/routes/inbound-message-handler.ts +288 -58
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
- package/src/runtime/routes/index.ts +14 -4
- package/src/runtime/routes/inference-provider-connection-routes.ts +192 -3
- package/src/runtime/routes/integrations/a2a.ts +294 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
- package/src/runtime/routes/log-export-routes.ts +39 -0
- package/src/runtime/routes/memory-v2-routes.ts +217 -0
- package/src/runtime/routes/notification-routes.ts +19 -2
- package/src/runtime/routes/question-routes.ts +4 -1
- package/src/runtime/routes/sanity-routes.ts +159 -0
- package/src/runtime/routes/slack-channel-routes.ts +187 -0
- package/src/runtime/routes/subagents-routes.ts +41 -0
- package/src/runtime/services/conversation-serializer.ts +30 -4
- package/src/schedule/integration-status.ts +3 -1
- package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
- package/src/security/oauth2-device-code.ts +307 -0
- package/src/security/oauth2.ts +26 -9
- package/src/security/secure-keys.ts +5 -0
- package/src/skills/catalog-install.ts +6 -2
- package/src/subagent/manager.ts +2 -0
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
- package/src/tools/browser/browser-execution.ts +93 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
- package/src/tools/browser/cdp-client/factory.ts +87 -3
- package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
- package/src/tools/browser/cdp-client/types.ts +36 -0
- package/src/tools/browser/pinned-tabs.ts +90 -0
- package/src/tools/document/document-comment-tool.test.ts +379 -0
- package/src/tools/document/document-comment-tool.ts +156 -0
- package/src/tools/document/document-tool.ts +128 -2
- package/src/tools/memory/register.ts +1 -9
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
- package/src/tools/network/domain-normalize.ts +17 -0
- package/src/tools/network/web-fetch.ts +213 -64
- package/src/tools/network/web-search.ts +191 -66
- package/src/tools/registry.ts +2 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/tool-approval-handler.ts +19 -12
- package/src/tools/types.ts +41 -2
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/types/onboarding-context.ts +4 -0
- package/src/util/__tests__/favicon.test.ts +84 -0
- package/src/util/favicon.ts +40 -0
- package/src/util/platform.ts +0 -5
- package/src/workspace/git-service.ts +75 -4
- package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- package/src/config/bundled-skills/document/SKILL.md +0 -54
- package/src/config/bundled-skills/document/TOOLS.json +0 -106
- package/src/daemon/seed-files.ts +0 -18
- package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
- package/src/runtime/routes/interface-routes.ts +0 -43
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
|
@@ -57,16 +57,17 @@ import {
|
|
|
57
57
|
} from "../daemon/disk-pressure-policy.js";
|
|
58
58
|
import type { TrustContext } from "../daemon/trust-context.js";
|
|
59
59
|
import { getConversationOverrideProfile } from "../memory/conversation-crud.js";
|
|
60
|
-
import {
|
|
60
|
+
import {
|
|
61
|
+
buildProviderErrorResponsePayload,
|
|
62
|
+
recordRequestLog,
|
|
63
|
+
setAgentLoopExitReasonOnLatestLog,
|
|
64
|
+
} from "../memory/llm-request-log-store.js";
|
|
61
65
|
import type { TurnContext } from "../plugins/types.js";
|
|
62
66
|
import type { Message } from "../providers/types.js";
|
|
63
67
|
import { getLogger } from "../util/logger.js";
|
|
64
68
|
|
|
65
69
|
const log = getLogger("agent-wake");
|
|
66
70
|
|
|
67
|
-
/** Number of messages injected for the wake hint (user + assistant + user). */
|
|
68
|
-
const WAKE_HINT_MESSAGE_COUNT = 3;
|
|
69
|
-
|
|
70
71
|
/** Static preamble user message — no dynamic content, injection-safe. */
|
|
71
72
|
const WAKE_PREAMBLE =
|
|
72
73
|
"[system] The following assistant message comes from an external system.";
|
|
@@ -192,6 +193,51 @@ export interface WakeOptions {
|
|
|
192
193
|
* tune the model/profile and observability bucket independently.
|
|
193
194
|
*/
|
|
194
195
|
callSite?: LLMCallSite;
|
|
196
|
+
/**
|
|
197
|
+
* Role to use for the injected hint message. Defaults to `"assistant"` so
|
|
198
|
+
* the hint is sandwiched between two static user bookends — the canonical
|
|
199
|
+
* anti-injection pattern for hints that may carry text from an external
|
|
200
|
+
* source. Trusted internal callers (e.g. fork-based memory retrospectives)
|
|
201
|
+
* can pass `"user"` to inject a single user-role message containing the
|
|
202
|
+
* hint directly, which reads more naturally as an instruction from the
|
|
203
|
+
* user/system rather than a self-directed assistant note.
|
|
204
|
+
*/
|
|
205
|
+
hintRole?: "assistant" | "user";
|
|
206
|
+
/**
|
|
207
|
+
* Documented intent: this wake must not trigger auto-threshold compaction.
|
|
208
|
+
*
|
|
209
|
+
* Today this is automatically satisfied because the wake invokes
|
|
210
|
+
* `target.agentLoop.run()` directly, bypassing the daemon orchestrator
|
|
211
|
+
* (`conversation-agent-loop.ts`) where the compaction pipeline lives. The
|
|
212
|
+
* flag is recorded in the wake's structured log line so operators can
|
|
213
|
+
* verify the contract holds across refactors. If compaction is ever moved
|
|
214
|
+
* into `AgentLoop.run` or invoked from the wake path, callers that pass
|
|
215
|
+
* `true` here MUST be updated to suppress it; callers that pass `false`
|
|
216
|
+
* (or omit it) MUST tolerate compaction firing.
|
|
217
|
+
*
|
|
218
|
+
* Used by fork-based memory retrospectives: the wake operates on a
|
|
219
|
+
* freshly-forked conversation that may already be near (or past) the
|
|
220
|
+
* source's auto-threshold, but the goal is to operate on that exact
|
|
221
|
+
* context — running a compaction LLM call before the wake's own first
|
|
222
|
+
* call would waste tokens and defeat prompt-cache reuse.
|
|
223
|
+
*/
|
|
224
|
+
suppressAutoCompaction?: boolean;
|
|
225
|
+
/**
|
|
226
|
+
* Skip injection of the hint sandwich entirely. Used when the caller has
|
|
227
|
+
* already persisted the instruction as a real message in the conversation
|
|
228
|
+
* (e.g. fork-based memory retrospectives that append a user message to the
|
|
229
|
+
* forked conversation before waking). When `true`, `hint` is ignored.
|
|
230
|
+
*/
|
|
231
|
+
skipHintInjection?: boolean;
|
|
232
|
+
/**
|
|
233
|
+
* Skip injection of the "Conversation Woke" `ui_surface` card into the
|
|
234
|
+
* first assistant tail message and the corresponding live
|
|
235
|
+
* `onWakeProducedOutput` broadcast. Default false (existing behavior).
|
|
236
|
+
* Used by callers whose conversation context already makes it obvious
|
|
237
|
+
* that the agent's output came from a wake (e.g. fork-based memory
|
|
238
|
+
* retrospectives whose conversation title already says "(Retrospective)").
|
|
239
|
+
*/
|
|
240
|
+
suppressWakeSurface?: boolean;
|
|
195
241
|
}
|
|
196
242
|
|
|
197
243
|
/**
|
|
@@ -220,13 +266,18 @@ export interface WakeResult {
|
|
|
220
266
|
*/
|
|
221
267
|
export interface WakeDeps {
|
|
222
268
|
/**
|
|
223
|
-
* Resolve the wake target for a
|
|
269
|
+
* Resolve the wake target for a wake invocation.
|
|
224
270
|
* Returns `null` if the conversation doesn't exist, `"archived"` if it
|
|
225
271
|
* exists but is archived, or a `WakeTarget` to proceed with the wake.
|
|
272
|
+
*
|
|
273
|
+
* Receives the full {@link WakeOptions} so the default resolver can
|
|
274
|
+
* thread `trustContext` into `getOrCreateConversation`. Without that
|
|
275
|
+
* threading, the conversation hydrates with `trustContext === undefined`
|
|
276
|
+
* and `loadFromDb` fail-closes to `trustClass: "unknown"`, which filters
|
|
277
|
+
* out every guardian-provenance message — fatal for fork-based memory
|
|
278
|
+
* retrospectives.
|
|
226
279
|
*/
|
|
227
|
-
resolveTarget: (
|
|
228
|
-
conversationId: string,
|
|
229
|
-
) => Promise<WakeTarget | null | "archived">;
|
|
280
|
+
resolveTarget: (opts: WakeOptions) => Promise<WakeTarget | null | "archived">;
|
|
230
281
|
/** Timestamp source (for deterministic tests). */
|
|
231
282
|
now?: () => number;
|
|
232
283
|
}
|
|
@@ -238,8 +289,9 @@ export interface WakeDeps {
|
|
|
238
289
|
// `getOrCreateConversation`, and `conversationToWakeTarget`.
|
|
239
290
|
|
|
240
291
|
async function defaultResolveTarget(
|
|
241
|
-
|
|
292
|
+
opts: WakeOptions,
|
|
242
293
|
): Promise<WakeTarget | null | "archived"> {
|
|
294
|
+
const { conversationId } = opts;
|
|
243
295
|
// Lazy-import daemon modules to avoid pulling heavyweight transitive
|
|
244
296
|
// deps (conversation store → config/loader → provider catalogs) at
|
|
245
297
|
// module-evaluation time. Callers that only import agent-wake for
|
|
@@ -260,7 +312,15 @@ async function defaultResolveTarget(
|
|
|
260
312
|
);
|
|
261
313
|
return "archived";
|
|
262
314
|
}
|
|
263
|
-
|
|
315
|
+
// Thread trustContext through to getOrCreateConversation so the
|
|
316
|
+
// hydration path applies setTrustContext + ensureActorScopedHistory
|
|
317
|
+
// (conversation-store.ts:281-289) BEFORE the agent loop's per-turn
|
|
318
|
+
// snapshot reads. Without this, fork-based memory retrospectives see
|
|
319
|
+
// an empty history because loadFromDb ran with trustClass="unknown"
|
|
320
|
+
// and filtered out every guardian-provenance message.
|
|
321
|
+
const conversation = await getOrCreateConversation(conversationId, {
|
|
322
|
+
trustContext: opts.trustContext,
|
|
323
|
+
});
|
|
264
324
|
return conversationToWakeTarget(conversation);
|
|
265
325
|
} catch (err) {
|
|
266
326
|
log.warn(
|
|
@@ -372,6 +432,7 @@ function buildWakeTurnContext(
|
|
|
372
432
|
*/
|
|
373
433
|
function inspectWakeOutput(
|
|
374
434
|
baselineLength: number,
|
|
435
|
+
hintMessageCount: number,
|
|
375
436
|
updatedHistory: Message[],
|
|
376
437
|
): {
|
|
377
438
|
tailMessages: Message[];
|
|
@@ -379,10 +440,10 @@ function inspectWakeOutput(
|
|
|
379
440
|
toolUseNames: string[];
|
|
380
441
|
} {
|
|
381
442
|
// The agent loop appends messages onto the history it was given. We
|
|
382
|
-
// injected
|
|
383
|
-
//
|
|
384
|
-
// the run.
|
|
385
|
-
const firstAssistantIndex = baselineLength +
|
|
443
|
+
// injected `hintMessageCount` hint messages (0, 1, or 3 depending on
|
|
444
|
+
// hint mode), so anything at index >= baselineLength + hintMessageCount
|
|
445
|
+
// came from the run.
|
|
446
|
+
const firstAssistantIndex = baselineLength + hintMessageCount;
|
|
386
447
|
if (updatedHistory.length <= firstAssistantIndex) {
|
|
387
448
|
return { tailMessages: [], hasVisibleText: false, toolUseNames: [] };
|
|
388
449
|
}
|
|
@@ -432,7 +493,7 @@ export async function wakeAgentForOpportunity(
|
|
|
432
493
|
const startedAt = nowFn();
|
|
433
494
|
|
|
434
495
|
return runSingleFlight(conversationId, async () => {
|
|
435
|
-
const resolved = await resolveTarget(
|
|
496
|
+
const resolved = await resolveTarget(opts);
|
|
436
497
|
if (resolved === "archived") {
|
|
437
498
|
log.info(
|
|
438
499
|
{ conversationId, source },
|
|
@@ -501,28 +562,45 @@ export async function wakeAgentForOpportunity(
|
|
|
501
562
|
// tail-slice math would skip every message.
|
|
502
563
|
const baselineLength = baseline.length;
|
|
503
564
|
const wakeTurnContext = buildWakeTurnContext(opts, diskPressureDecision);
|
|
504
|
-
|
|
505
|
-
//
|
|
506
|
-
//
|
|
507
|
-
//
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
//
|
|
511
|
-
//
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
565
|
+
// Build the hint injection. Three modes:
|
|
566
|
+
// - `skipHintInjection`: caller has already persisted an instruction
|
|
567
|
+
// message into the conversation history (typical for fork-based
|
|
568
|
+
// memory retrospectives that append a user message before waking).
|
|
569
|
+
// - `hintRole === "user"`: single user-role message containing the
|
|
570
|
+
// hint directly. Used by trusted internal callers where the hint
|
|
571
|
+
// reads naturally as an instruction.
|
|
572
|
+
// - default (`hintRole === "assistant"`): sandwich the hint as an
|
|
573
|
+
// assistant message between two hardcoded user bookends. The
|
|
574
|
+
// assistant role defangs prompt injection (LLMs don't follow
|
|
575
|
+
// instructions in their own prior output) and the trailing user
|
|
576
|
+
// message satisfies providers that reject assistant prefill.
|
|
577
|
+
const hintRole = opts.hintRole ?? "assistant";
|
|
578
|
+
const wakeMessages: Message[] = opts.skipHintInjection
|
|
579
|
+
? []
|
|
580
|
+
: hintRole === "user"
|
|
581
|
+
? [
|
|
582
|
+
{
|
|
583
|
+
role: "user",
|
|
584
|
+
content: [{ type: "text", text: hint }],
|
|
585
|
+
},
|
|
586
|
+
]
|
|
587
|
+
: [
|
|
588
|
+
{
|
|
589
|
+
role: "user",
|
|
590
|
+
content: [{ type: "text", text: WAKE_PREAMBLE }],
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
role: "assistant",
|
|
594
|
+
content: [
|
|
595
|
+
{ type: "text", text: `[opportunity:${source}] ${hint}` },
|
|
596
|
+
],
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
role: "user",
|
|
600
|
+
content: [{ type: "text", text: WAKE_POSTAMBLE }],
|
|
601
|
+
},
|
|
602
|
+
];
|
|
603
|
+
const wakeHintMessageCount = wakeMessages.length;
|
|
526
604
|
const runInput: Message[] = [...baseline, ...wakeMessages];
|
|
527
605
|
|
|
528
606
|
// Event handling runs in two modes. While `mode === "buffering"`,
|
|
@@ -548,6 +626,12 @@ export async function wakeAgentForOpportunity(
|
|
|
548
626
|
provider?: string;
|
|
549
627
|
};
|
|
550
628
|
const pendingLogs: PendingLog[] = [];
|
|
629
|
+
// Exit reason deferred alongside pendingLogs. Same drop-on-silent-
|
|
630
|
+
// wake guarantee: if the wake never goes live, this stays null and
|
|
631
|
+
// no DB row is touched. Applied after pendingLogs flush in goLive
|
|
632
|
+
// so the latest-row lookup in `setAgentLoopExitReasonOnLatestLog`
|
|
633
|
+
// can see the freshly-persisted final usage row.
|
|
634
|
+
let pendingExitReason: string | null = null;
|
|
551
635
|
const persistLog = (record: PendingLog): void => {
|
|
552
636
|
try {
|
|
553
637
|
recordRequestLog(
|
|
@@ -564,6 +648,16 @@ export async function wakeAgentForOpportunity(
|
|
|
564
648
|
);
|
|
565
649
|
}
|
|
566
650
|
};
|
|
651
|
+
const persistExitReason = (reason: string): void => {
|
|
652
|
+
try {
|
|
653
|
+
setAgentLoopExitReasonOnLatestLog(conversationId, reason);
|
|
654
|
+
} catch (err) {
|
|
655
|
+
log.warn(
|
|
656
|
+
{ err, conversationId, source, reason },
|
|
657
|
+
"agent-wake: failed to persist agent_loop_exit_reason (non-fatal)",
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
};
|
|
567
661
|
const safeEmit = (event: AgentEvent): void => {
|
|
568
662
|
try {
|
|
569
663
|
target.emitAgentEvent(event);
|
|
@@ -590,6 +684,38 @@ export async function wakeAgentForOpportunity(
|
|
|
590
684
|
persistLog(record);
|
|
591
685
|
}
|
|
592
686
|
}
|
|
687
|
+
// Mirror the same recording side-effect for provider-rejected calls.
|
|
688
|
+
// `handleProviderError` in the daemon dispatcher persists these on the
|
|
689
|
+
// normal turn path; the wake path owns its own onEvent and bypasses
|
|
690
|
+
// that dispatcher entirely, so we replicate here. Buffering rules
|
|
691
|
+
// match the success path: if the wake never goes live (silent no-op),
|
|
692
|
+
// the rows are dropped so a stale `messageId IS NULL` row doesn't get
|
|
693
|
+
// mis-backfilled onto an unrelated future assistant message.
|
|
694
|
+
if (event.type === "provider_error") {
|
|
695
|
+
const record: PendingLog = {
|
|
696
|
+
rawRequest: event.rawRequest,
|
|
697
|
+
rawResponse: buildProviderErrorResponsePayload(event.error),
|
|
698
|
+
provider: event.actualProvider,
|
|
699
|
+
};
|
|
700
|
+
if (mode === "buffering") {
|
|
701
|
+
pendingLogs.push(record);
|
|
702
|
+
} else {
|
|
703
|
+
persistLog(record);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
// Replicates the setAgentLoopExitReasonOnLatestLog side-effect that
|
|
707
|
+
// `dispatchAgentEvent` does for the normal path. In live mode the
|
|
708
|
+
// final usage event of the run has already landed its row, so the
|
|
709
|
+
// latest-row lookup hits the right target. In buffering mode the
|
|
710
|
+
// reason is stashed and applied in `goLive` after pendingLogs are
|
|
711
|
+
// persisted, preserving the same ordering guarantee.
|
|
712
|
+
if (event.type === "agent_loop_exit") {
|
|
713
|
+
if (mode === "buffering") {
|
|
714
|
+
pendingExitReason = event.reason;
|
|
715
|
+
} else {
|
|
716
|
+
persistExitReason(event.reason);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
593
719
|
if (mode === "buffering") {
|
|
594
720
|
buffered.push(event);
|
|
595
721
|
return;
|
|
@@ -611,26 +737,28 @@ export async function wakeAgentForOpportunity(
|
|
|
611
737
|
const goLive = (currentHistory: Message[]): void => {
|
|
612
738
|
if (mode === "live") return;
|
|
613
739
|
if (!surfaceInjected) {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
firstAssistant.content
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
data: {
|
|
740
|
+
if (!opts.suppressWakeSurface) {
|
|
741
|
+
const tailStart = baselineLength + wakeHintMessageCount;
|
|
742
|
+
const tail = currentHistory.slice(tailStart);
|
|
743
|
+
const firstAssistant = tail.find((m) => m.role === "assistant");
|
|
744
|
+
if (firstAssistant && Array.isArray(firstAssistant.content)) {
|
|
745
|
+
firstAssistant.content.unshift({
|
|
746
|
+
type: "ui_surface",
|
|
747
|
+
surfaceId: wakeSurfaceId,
|
|
748
|
+
surfaceType: "card",
|
|
624
749
|
title: "Conversation Woke",
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
750
|
+
data: {
|
|
751
|
+
title: "Conversation Woke",
|
|
752
|
+
body: hint,
|
|
753
|
+
metadata: [{ label: "Source", value: source }],
|
|
754
|
+
},
|
|
755
|
+
display: "inline",
|
|
756
|
+
} as never);
|
|
757
|
+
}
|
|
630
758
|
}
|
|
631
759
|
surfaceInjected = true;
|
|
632
760
|
}
|
|
633
|
-
if (target.onWakeProducedOutput) {
|
|
761
|
+
if (!opts.suppressWakeSurface && target.onWakeProducedOutput) {
|
|
634
762
|
try {
|
|
635
763
|
target.onWakeProducedOutput(source, hint, wakeSurfaceId);
|
|
636
764
|
} catch (err) {
|
|
@@ -648,6 +776,14 @@ export async function wakeAgentForOpportunity(
|
|
|
648
776
|
persistLog(record);
|
|
649
777
|
}
|
|
650
778
|
pendingLogs.length = 0;
|
|
779
|
+
// Apply the deferred exit reason after pendingLogs are persisted —
|
|
780
|
+
// the latest-row lookup in `setAgentLoopExitReasonOnLatestLog`
|
|
781
|
+
// needs the final usage row to already exist. Cleared after use so
|
|
782
|
+
// an extremely unlikely double-goLive can't double-stamp.
|
|
783
|
+
if (pendingExitReason !== null) {
|
|
784
|
+
persistExitReason(pendingExitReason);
|
|
785
|
+
pendingExitReason = null;
|
|
786
|
+
}
|
|
651
787
|
mode = "live";
|
|
652
788
|
};
|
|
653
789
|
|
|
@@ -661,8 +797,7 @@ export async function wakeAgentForOpportunity(
|
|
|
661
797
|
const flushPendingTail = async (
|
|
662
798
|
currentHistory: Message[],
|
|
663
799
|
): Promise<void> => {
|
|
664
|
-
const start =
|
|
665
|
-
baselineLength + WAKE_HINT_MESSAGE_COUNT + persistedTailIndex;
|
|
800
|
+
const start = baselineLength + wakeHintMessageCount + persistedTailIndex;
|
|
666
801
|
if (start >= currentHistory.length) return;
|
|
667
802
|
const newMessages = currentHistory.slice(start);
|
|
668
803
|
for (const msg of newMessages) {
|
|
@@ -765,7 +900,11 @@ export async function wakeAgentForOpportunity(
|
|
|
765
900
|
tailMessages,
|
|
766
901
|
hasVisibleText,
|
|
767
902
|
toolUseNames: names,
|
|
768
|
-
} = inspectWakeOutput(
|
|
903
|
+
} = inspectWakeOutput(
|
|
904
|
+
baselineLength,
|
|
905
|
+
wakeHintMessageCount,
|
|
906
|
+
updatedHistory,
|
|
907
|
+
);
|
|
769
908
|
toolUseNames = names;
|
|
770
909
|
producedToolCalls = names.length > 0;
|
|
771
910
|
const producedOutput = producedToolCalls || hasVisibleText;
|
|
@@ -844,9 +983,19 @@ export async function wakeAgentForOpportunity(
|
|
|
844
983
|
}
|
|
845
984
|
|
|
846
985
|
const durationMs = nowFn() - startedAt;
|
|
986
|
+
const suppressAutoCompaction = opts.suppressAutoCompaction === true;
|
|
987
|
+
const suppressWakeSurface = opts.suppressWakeSurface === true;
|
|
847
988
|
if (runError) {
|
|
848
989
|
log.error(
|
|
849
|
-
{
|
|
990
|
+
{
|
|
991
|
+
conversationId,
|
|
992
|
+
source,
|
|
993
|
+
durationMs,
|
|
994
|
+
suppressAutoCompaction,
|
|
995
|
+
suppressWakeSurface,
|
|
996
|
+
hintRole,
|
|
997
|
+
err: runError,
|
|
998
|
+
},
|
|
850
999
|
"agent-wake: agent loop threw; treating as no-op",
|
|
851
1000
|
);
|
|
852
1001
|
} else if (tailMessageCount === 0) {
|
|
@@ -855,6 +1004,9 @@ export async function wakeAgentForOpportunity(
|
|
|
855
1004
|
source,
|
|
856
1005
|
conversationId,
|
|
857
1006
|
durationMs,
|
|
1007
|
+
suppressAutoCompaction,
|
|
1008
|
+
suppressWakeSurface,
|
|
1009
|
+
hintRole,
|
|
858
1010
|
producedToolCalls: false,
|
|
859
1011
|
toolNamesCalled: [],
|
|
860
1012
|
},
|
|
@@ -866,6 +1018,9 @@ export async function wakeAgentForOpportunity(
|
|
|
866
1018
|
source,
|
|
867
1019
|
conversationId,
|
|
868
1020
|
durationMs,
|
|
1021
|
+
suppressAutoCompaction,
|
|
1022
|
+
suppressWakeSurface,
|
|
1023
|
+
hintRole,
|
|
869
1024
|
producedToolCalls,
|
|
870
1025
|
toolNamesCalled: toolUseNames,
|
|
871
1026
|
tailMessageCount,
|
|
@@ -153,6 +153,7 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
153
153
|
{ endpoint: "conversations/undo", scopes: ["chat.write"] },
|
|
154
154
|
{ endpoint: "conversations/regenerate", scopes: ["chat.write"] },
|
|
155
155
|
{ endpoint: "conversations/attention", scopes: ["chat.read"] },
|
|
156
|
+
{ endpoint: "conversations/slack-channel/resolve", scopes: ["chat.read"] },
|
|
156
157
|
{ endpoint: "conversations/seen", scopes: ["chat.write"] },
|
|
157
158
|
{ endpoint: "conversations/unread", scopes: ["chat.write"] },
|
|
158
159
|
{ endpoint: "conversations/import", scopes: ["chat.write"] },
|
|
@@ -243,6 +244,7 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
243
244
|
endpoint: "integrations/slack/channel/config:DELETE",
|
|
244
245
|
scopes: ["settings.write"],
|
|
245
246
|
},
|
|
247
|
+
{ endpoint: "integrations/a2a/invite", scopes: ["settings.write"] },
|
|
246
248
|
{ endpoint: "channel-verification-sessions", scopes: ["settings.write"] },
|
|
247
249
|
{
|
|
248
250
|
endpoint: "channel-verification-sessions:DELETE",
|
|
@@ -450,9 +452,6 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
450
452
|
{ endpoint: "bookmarks:POST", scopes: ["chat.write"] },
|
|
451
453
|
{ endpoint: "bookmarks/by-message:DELETE", scopes: ["chat.write"] },
|
|
452
454
|
|
|
453
|
-
// Interfaces
|
|
454
|
-
{ endpoint: "interfaces", scopes: ["settings.read"] },
|
|
455
|
-
|
|
456
455
|
// Skills
|
|
457
456
|
{ endpoint: "skills:GET", scopes: ["settings.read"] },
|
|
458
457
|
{ endpoint: "skills:POST", scopes: ["settings.write"] },
|
|
@@ -470,6 +469,8 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
470
469
|
{ endpoint: "memory/v2/list-concept-pages:POST", scopes: ["settings.read"] },
|
|
471
470
|
{ endpoint: "memory/v2/reembed-skills:POST", scopes: ["settings.write"] },
|
|
472
471
|
{ endpoint: "memory/v2/concept-frequency:POST", scopes: ["settings.read"] },
|
|
472
|
+
{ endpoint: "memory/v2/ema-scores:POST", scopes: ["settings.read"] },
|
|
473
|
+
{ endpoint: "memory/v2/simulate-router:POST", scopes: ["settings.read"] },
|
|
473
474
|
|
|
474
475
|
// Trust rule listing
|
|
475
476
|
{ endpoint: "trust-rules/manage:GET", scopes: ["settings.read"] },
|
|
@@ -686,6 +687,18 @@ for (const endpoint of INTERNAL_ENDPOINTS) {
|
|
|
686
687
|
});
|
|
687
688
|
}
|
|
688
689
|
|
|
690
|
+
// A2A invite completion: gateway-only (platform-orchestrated)
|
|
691
|
+
registerPolicy("integrations/a2a/invite/complete", {
|
|
692
|
+
requiredScopes: ["internal.write"],
|
|
693
|
+
allowedPrincipalTypes: ["svc_gateway"],
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
// A2A invite redemption: gateway-only (platform-orchestrated)
|
|
697
|
+
registerPolicy("integrations/a2a/invite/redeem", {
|
|
698
|
+
requiredScopes: ["internal.write"],
|
|
699
|
+
allowedPrincipalTypes: ["svc_gateway"],
|
|
700
|
+
});
|
|
701
|
+
|
|
689
702
|
// Admin control-plane endpoints: gateway-only
|
|
690
703
|
registerPolicy("admin/upgrade-broadcast", {
|
|
691
704
|
requiredScopes: ["internal.write"],
|
|
@@ -979,6 +992,10 @@ registerPolicy("conversations/cli/export", {
|
|
|
979
992
|
requiredScopes: ["settings.read"],
|
|
980
993
|
allowedPrincipalTypes: ["local"],
|
|
981
994
|
});
|
|
995
|
+
registerPolicy("conversations/cli/slack/detach", {
|
|
996
|
+
requiredScopes: ["settings.write"],
|
|
997
|
+
allowedPrincipalTypes: ["local"],
|
|
998
|
+
});
|
|
982
999
|
// `conversations/cli/clear` wipes every conversation + message + vector
|
|
983
1000
|
// collection. Elevated to settings.write and locked to local callers,
|
|
984
1001
|
// mirroring the `conversations/clear-all` and `conversations/wipe` gates.
|
|
@@ -24,6 +24,11 @@ import type { TrustContext } from "../daemon/trust-context.js";
|
|
|
24
24
|
import { bootstrapConversation } from "../memory/conversation-bootstrap.js";
|
|
25
25
|
import { addMessage } from "../memory/conversation-crud.js";
|
|
26
26
|
import type { TitleOrigin } from "../memory/conversation-title-service.js";
|
|
27
|
+
import {
|
|
28
|
+
commitDeferredConversation,
|
|
29
|
+
discardDeferredConversation,
|
|
30
|
+
registerDeferredConversation,
|
|
31
|
+
} from "../notifications/deferred-emit.js";
|
|
27
32
|
import { emitNotificationSignal } from "../notifications/emit-signal.js";
|
|
28
33
|
import type { AttentionHints } from "../notifications/signal.js";
|
|
29
34
|
import { getLogger } from "../util/logger.js";
|
|
@@ -121,6 +126,11 @@ export interface RunBackgroundJobOptions {
|
|
|
121
126
|
* the `assistant` role and cannot override the action prompt.
|
|
122
127
|
*/
|
|
123
128
|
assistantSandwich?: { preamble: string; content: string; postamble: string };
|
|
129
|
+
/**
|
|
130
|
+
* Buffer in-band `notifications send` calls and only flush them after the
|
|
131
|
+
* run completes successfully. See `notifications/deferred-emit.ts`.
|
|
132
|
+
*/
|
|
133
|
+
deferNotifications?: boolean;
|
|
124
134
|
}
|
|
125
135
|
|
|
126
136
|
export interface RunBackgroundJobResult {
|
|
@@ -205,6 +215,10 @@ export async function runBackgroundJob(
|
|
|
205
215
|
...(opts.scheduleJobId ? { scheduleJobId: opts.scheduleJobId } : {}),
|
|
206
216
|
});
|
|
207
217
|
|
|
218
|
+
if (opts.deferNotifications) {
|
|
219
|
+
registerDeferredConversation(conversation.id);
|
|
220
|
+
}
|
|
221
|
+
|
|
208
222
|
// Fire the sidebar-creation callback synchronously after bootstrap so
|
|
209
223
|
// connected clients (macOS sidebar, etc.) see the conversation appear
|
|
210
224
|
// immediately rather than after `processMessage` returns. Wrapped so a
|
|
@@ -273,6 +287,14 @@ export async function runBackgroundJob(
|
|
|
273
287
|
});
|
|
274
288
|
|
|
275
289
|
await Promise.race([work, timeout]);
|
|
290
|
+
// Symmetric with the `work.catch` above: once `work` has won the race,
|
|
291
|
+
// the orphan timeout promise can still reject during the await below
|
|
292
|
+
// (commitDeferredConversation). Swallow so it doesn't surface as an
|
|
293
|
+
// unhandled rejection that Bun can use to terminate the process.
|
|
294
|
+
timeout.catch(() => {});
|
|
295
|
+
if (opts.deferNotifications) {
|
|
296
|
+
await commitDeferredConversation(conversation.id);
|
|
297
|
+
}
|
|
276
298
|
return { conversationId: conversation.id, ok: true };
|
|
277
299
|
} catch (err) {
|
|
278
300
|
const errorKind = classifyError(err);
|
|
@@ -281,6 +303,10 @@ export async function runBackgroundJob(
|
|
|
281
303
|
// so the structured failure result still flows to the caller.
|
|
282
304
|
const conversationId = conversation?.id ?? "";
|
|
283
305
|
|
|
306
|
+
if (opts.deferNotifications && conversationId) {
|
|
307
|
+
discardDeferredConversation(conversationId);
|
|
308
|
+
}
|
|
309
|
+
|
|
284
310
|
log.error(
|
|
285
311
|
{
|
|
286
312
|
err: error.message,
|