@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
|
@@ -92,6 +92,19 @@ export interface HistorySurface {
|
|
|
92
92
|
completionSummary?: string;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Positional reference to a file attachment captured while walking the
|
|
97
|
+
* content array. The index of an entry in `RenderedHistoryContent.attachments`
|
|
98
|
+
* is what `contentOrder` references as `attachment:N`.
|
|
99
|
+
*/
|
|
100
|
+
export interface HistoryAttachmentRef {
|
|
101
|
+
/** Stable DB attachment id when persisted on the file block (`_attachmentId`). */
|
|
102
|
+
attachmentId?: string;
|
|
103
|
+
filename: string;
|
|
104
|
+
mimeType: string;
|
|
105
|
+
sizeBytes: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
95
108
|
export interface RenderedHistoryContent {
|
|
96
109
|
text: string;
|
|
97
110
|
toolCalls: HistoryToolCall[];
|
|
@@ -99,12 +112,18 @@ export interface RenderedHistoryContent {
|
|
|
99
112
|
toolCallsBeforeText: boolean;
|
|
100
113
|
/** Text segments split by tool-call boundaries. */
|
|
101
114
|
textSegments: string[];
|
|
102
|
-
/** Content block ordering using "text:N", "tool:N", "surface:N" encoding. */
|
|
115
|
+
/** Content block ordering using "text:N", "tool:N", "surface:N", "attachment:N" encoding. */
|
|
103
116
|
contentOrder: string[];
|
|
104
117
|
/** UI surfaces (widgets) embedded in the message. */
|
|
105
118
|
surfaces: HistorySurface[];
|
|
106
119
|
/** Thinking segments extracted from thinking blocks. */
|
|
107
120
|
thinkingSegments: string[];
|
|
121
|
+
/**
|
|
122
|
+
* File attachments captured in content order. Index `N` matches an
|
|
123
|
+
* `attachment:N` entry in `contentOrder`. Callers align their DB-sourced
|
|
124
|
+
* attachment metadata to this ordering for inline placement.
|
|
125
|
+
*/
|
|
126
|
+
attachments: HistoryAttachmentRef[];
|
|
108
127
|
}
|
|
109
128
|
|
|
110
129
|
/**
|
|
@@ -115,6 +134,8 @@ export interface RenderedHistoryContent {
|
|
|
115
134
|
export interface SlackInboundMessageMetadata {
|
|
116
135
|
/** Slack channel id (conversation external id) — recorded as `channelId`. */
|
|
117
136
|
channelId: string;
|
|
137
|
+
/** Human-readable Slack channel name, when the gateway supplied it. */
|
|
138
|
+
channelName?: string;
|
|
118
139
|
/** Slack `ts` for this message — required so persistence can record `channelTs`. */
|
|
119
140
|
channelTs: string;
|
|
120
141
|
/** Parent `thread_ts` when the message lives inside a thread; absent for top-level. */
|
|
@@ -123,6 +144,18 @@ export interface SlackInboundMessageMetadata {
|
|
|
123
144
|
displayName?: string;
|
|
124
145
|
/** Canonical Slack external user id for the sender, when available. */
|
|
125
146
|
actorExternalUserId?: string;
|
|
147
|
+
/** Raw Slack profile timezone for the sender, when supplied. */
|
|
148
|
+
actorTimezone?: string;
|
|
149
|
+
/** Compact Slack profile timezone label for the sender, when supplied. */
|
|
150
|
+
actorTimezoneLabel?: string;
|
|
151
|
+
/** Raw Slack profile timezone offset in seconds, when supplied. */
|
|
152
|
+
actorTimezoneOffsetSeconds?: number;
|
|
153
|
+
/** Timezone used to render this message's timestamp. */
|
|
154
|
+
timestampTimezone?: string;
|
|
155
|
+
/** Compact label for the rendered timestamp timezone. */
|
|
156
|
+
timestampTimezoneLabel?: string;
|
|
157
|
+
/** Compact timezone label appended to the rendered speaker name. */
|
|
158
|
+
speakerTimezoneLabel?: string;
|
|
126
159
|
}
|
|
127
160
|
|
|
128
161
|
/**
|
|
@@ -144,8 +177,6 @@ export interface ConversationCreateOptions {
|
|
|
144
177
|
authContext?: AuthContext;
|
|
145
178
|
/** Whether this turn can block on interactive approval prompts. */
|
|
146
179
|
isInteractive?: boolean;
|
|
147
|
-
/** Slack-only non-persisted notice injected into the active model turn. */
|
|
148
|
-
slackRuntimeContextNotice?: string;
|
|
149
180
|
/**
|
|
150
181
|
* Persisted user-facing content. When present, storage/UI use this value
|
|
151
182
|
* while the model-facing turn continues to use `content`.
|
|
@@ -192,22 +223,42 @@ function clampAttachmentText(text: string): string {
|
|
|
192
223
|
return `${text.slice(0, HISTORY_ATTACHMENT_TEXT_LIMIT)}<truncated />`;
|
|
193
224
|
}
|
|
194
225
|
|
|
195
|
-
|
|
226
|
+
interface FileBlockMetadata {
|
|
227
|
+
mediaType: string;
|
|
228
|
+
filename: string;
|
|
229
|
+
sizeBytes: number;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function extractFileBlockMetadata(
|
|
233
|
+
block: Record<string, unknown>,
|
|
234
|
+
): FileBlockMetadata {
|
|
196
235
|
const source = isRecord(block.source) ? block.source : null;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
236
|
+
return {
|
|
237
|
+
mediaType:
|
|
238
|
+
source && typeof source.media_type === "string"
|
|
239
|
+
? source.media_type
|
|
240
|
+
: "application/octet-stream",
|
|
241
|
+
filename:
|
|
242
|
+
source && typeof source.filename === "string"
|
|
243
|
+
? source.filename
|
|
244
|
+
: "attachment",
|
|
245
|
+
sizeBytes:
|
|
246
|
+
source && typeof source.data === "string"
|
|
247
|
+
? estimateBase64Bytes(source.data)
|
|
248
|
+
: 0,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function renderFileBlockForHistory(
|
|
253
|
+
block: Record<string, unknown>,
|
|
254
|
+
meta: FileBlockMetadata,
|
|
255
|
+
): string {
|
|
256
|
+
const summaryParts = [
|
|
257
|
+
`[File attachment] ${meta.filename}`,
|
|
258
|
+
`type=${meta.mediaType}`,
|
|
259
|
+
];
|
|
260
|
+
if (meta.sizeBytes > 0)
|
|
261
|
+
summaryParts.push(`size=${formatBytes(meta.sizeBytes)}`);
|
|
211
262
|
|
|
212
263
|
const extractedText =
|
|
213
264
|
typeof block.extracted_text === "string" ? block.extracted_text.trim() : "";
|
|
@@ -237,11 +288,13 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
|
|
|
237
288
|
contentOrder: text ? ["text:0"] : [],
|
|
238
289
|
surfaces: [],
|
|
239
290
|
thinkingSegments: [],
|
|
291
|
+
attachments: [],
|
|
240
292
|
};
|
|
241
293
|
}
|
|
242
294
|
|
|
243
295
|
const textParts: string[] = [];
|
|
244
296
|
const attachmentParts: string[] = [];
|
|
297
|
+
const attachments: HistoryAttachmentRef[] = [];
|
|
245
298
|
const toolCalls: HistoryToolCall[] = [];
|
|
246
299
|
const surfaces: HistorySurface[] = [];
|
|
247
300
|
const thinkingSegments: string[] = [];
|
|
@@ -351,7 +404,19 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
|
|
|
351
404
|
continue;
|
|
352
405
|
}
|
|
353
406
|
if (block.type === "file") {
|
|
354
|
-
|
|
407
|
+
const meta = extractFileBlockMetadata(block);
|
|
408
|
+
attachmentParts.push(renderFileBlockForHistory(block, meta));
|
|
409
|
+
finalizeSegment();
|
|
410
|
+
const ref: HistoryAttachmentRef = {
|
|
411
|
+
filename: meta.filename,
|
|
412
|
+
mimeType: meta.mediaType,
|
|
413
|
+
sizeBytes: meta.sizeBytes,
|
|
414
|
+
};
|
|
415
|
+
if (typeof block._attachmentId === "string" && block._attachmentId) {
|
|
416
|
+
ref.attachmentId = block._attachmentId;
|
|
417
|
+
}
|
|
418
|
+
attachments.push(ref);
|
|
419
|
+
contentOrder.push(`attachment:${attachments.length - 1}`);
|
|
355
420
|
continue;
|
|
356
421
|
}
|
|
357
422
|
if (block.type === "image") {
|
|
@@ -495,17 +560,14 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
|
|
|
495
560
|
matched.imageData = imageDataList[0];
|
|
496
561
|
matched.imageDataList = imageDataList;
|
|
497
562
|
}
|
|
498
|
-
} else {
|
|
499
|
-
toolCalls.push({
|
|
500
|
-
name: "unknown",
|
|
501
|
-
input: {},
|
|
502
|
-
result: resultContent,
|
|
503
|
-
isError,
|
|
504
|
-
...(imageDataList.length > 0
|
|
505
|
-
? { imageData: imageDataList[0], imageDataList }
|
|
506
|
-
: {}),
|
|
507
|
-
});
|
|
508
563
|
}
|
|
564
|
+
// Orphan tool_result with no matching tool_use — drop it. Synthesizing
|
|
565
|
+
// a "name: 'unknown'" phantom entry rendered in chat as "Used unknown"
|
|
566
|
+
// / "Completed 1 step" with no context, with a timestamp later than
|
|
567
|
+
// the assistant's final answer. Most commonly orphans appear when
|
|
568
|
+
// context-window compaction trims the parent tool_use block while
|
|
569
|
+
// leaving the paired tool_result. Losing the orphan's result content
|
|
570
|
+
// is correct: without the parent we can't tell the user what tool ran.
|
|
509
571
|
continue;
|
|
510
572
|
}
|
|
511
573
|
}
|
|
@@ -541,6 +603,7 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
|
|
|
541
603
|
contentOrder,
|
|
542
604
|
surfaces,
|
|
543
605
|
thinkingSegments,
|
|
606
|
+
attachments,
|
|
544
607
|
};
|
|
545
608
|
}
|
|
546
609
|
|
|
@@ -22,10 +22,11 @@
|
|
|
22
22
|
* `running`; the rollback path on a failed `start` restores from the
|
|
23
23
|
* current confirmed pointer (not from a per-call snapshot of a sibling
|
|
24
24
|
* optimistic write), so two overlapping starts that both fail cannot
|
|
25
|
-
* leave a phantom lock
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* leave a phantom lock. Each session carries a monotonic `dispatchedAt`
|
|
26
|
+
* counter so out-of-order `running` responses promote in dispatch order:
|
|
27
|
+
* the latest-dispatched start that the host confirms becomes the
|
|
28
|
+
* confirmed baseline, regardless of which response arrived last. The
|
|
29
|
+
* lock is released outright when the owning proxy's `dispose()` fires.
|
|
29
30
|
*
|
|
30
31
|
* `app_control_start` is the only tool that can acquire the lock — the
|
|
31
32
|
* user's medium-risk approval at start time is the consent boundary. All
|
|
@@ -84,8 +85,22 @@ export interface ActiveAppControlSession {
|
|
|
84
85
|
* the `app` of subsequent non-start tool calls.
|
|
85
86
|
*/
|
|
86
87
|
app: string;
|
|
88
|
+
/**
|
|
89
|
+
* Strictly monotonic counter assigned when the session is created (in
|
|
90
|
+
* `request()` for a `start`). Used by {@link promoteStartIfCurrent} to
|
|
91
|
+
* tell which of two confirmations from overlapping starts is newer when
|
|
92
|
+
* host responses arrive out of order. Larger values are newer.
|
|
93
|
+
*/
|
|
94
|
+
dispatchedAt: number;
|
|
87
95
|
}
|
|
88
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Monotonic counter that stamps each `start`'s {@link
|
|
99
|
+
* ActiveAppControlSession.dispatchedAt}. Process-lifetime monotonic; the
|
|
100
|
+
* absolute value is meaningless — only ordering matters.
|
|
101
|
+
*/
|
|
102
|
+
let nextDispatchedAt = 1;
|
|
103
|
+
|
|
89
104
|
/**
|
|
90
105
|
* Currently active session, or `undefined` when no session is held. This
|
|
91
106
|
* is the optimistic value: it is set the moment a `start` is dispatched
|
|
@@ -112,6 +127,13 @@ export function _getActiveAppControlSession():
|
|
|
112
127
|
return activeAppControlSession;
|
|
113
128
|
}
|
|
114
129
|
|
|
130
|
+
/** Test-only helper: read the last host-confirmed session. */
|
|
131
|
+
export function _getConfirmedAppControlSession():
|
|
132
|
+
| ActiveAppControlSession
|
|
133
|
+
| undefined {
|
|
134
|
+
return confirmedAppControlSession;
|
|
135
|
+
}
|
|
136
|
+
|
|
115
137
|
/** Test-only helper: clear both session pointers between test cases. */
|
|
116
138
|
export function _resetActiveAppControlSession(): void {
|
|
117
139
|
activeAppControlSession = undefined;
|
|
@@ -123,11 +145,18 @@ export function _resetActiveAppControlSession(): void {
|
|
|
123
145
|
* round-trip. Useful for tests that exercise non-start tool paths and
|
|
124
146
|
* don't need to verify the start flow itself.
|
|
125
147
|
*/
|
|
126
|
-
export function _setActiveAppControlSession(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
148
|
+
export function _setActiveAppControlSession(session: {
|
|
149
|
+
conversationId: string;
|
|
150
|
+
app: string;
|
|
151
|
+
dispatchedAt?: number;
|
|
152
|
+
}): void {
|
|
153
|
+
const full: ActiveAppControlSession = {
|
|
154
|
+
conversationId: session.conversationId,
|
|
155
|
+
app: session.app,
|
|
156
|
+
dispatchedAt: session.dispatchedAt ?? nextDispatchedAt++,
|
|
157
|
+
};
|
|
158
|
+
activeAppControlSession = full;
|
|
159
|
+
confirmedAppControlSession = full;
|
|
131
160
|
}
|
|
132
161
|
|
|
133
162
|
/**
|
|
@@ -280,6 +309,7 @@ export class HostAppControlProxy extends HostProxyBase<
|
|
|
280
309
|
attemptedSession = {
|
|
281
310
|
conversationId: this.conversationId,
|
|
282
311
|
app: input.app,
|
|
312
|
+
dispatchedAt: nextDispatchedAt++,
|
|
283
313
|
};
|
|
284
314
|
activeAppControlSession = attemptedSession;
|
|
285
315
|
} else {
|
|
@@ -356,15 +386,27 @@ export class HostAppControlProxy extends HostProxyBase<
|
|
|
356
386
|
}
|
|
357
387
|
|
|
358
388
|
/**
|
|
359
|
-
* Promote this start's
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
* The
|
|
366
|
-
*
|
|
367
|
-
*
|
|
389
|
+
* Promote this start's session to the confirmed pointer when the host
|
|
390
|
+
* returns `running`. Two gates:
|
|
391
|
+
*
|
|
392
|
+
* 1. The live optimistic write must still belong to this conversation —
|
|
393
|
+
* if `dispose()` cleared the lock or another conversation acquired
|
|
394
|
+
* it, this confirmation must not resurrect a stale session.
|
|
395
|
+
* 2. The confirming session must be at least as recent as the currently
|
|
396
|
+
* confirmed one, compared via {@link
|
|
397
|
+
* ActiveAppControlSession.dispatchedAt}. The dispatch counter is
|
|
398
|
+
* assigned synchronously in `request()`, so it captures dispatch
|
|
399
|
+
* order even when host responses arrive out of order. The latest
|
|
400
|
+
* dispatched start that confirms wins, which is the right baseline
|
|
401
|
+
* for the rollback path: if a newer start later fails, rollback
|
|
402
|
+
* restores the most recently confirmed session, not an older one.
|
|
403
|
+
*
|
|
404
|
+
* Also advance the active pointer when it is strictly older than the
|
|
405
|
+
* newly-confirmed session. This handles the case where an even newer
|
|
406
|
+
* optimistic write has already failed and rolled active back to the
|
|
407
|
+
* previous confirmed session; without this, observe/actions for the
|
|
408
|
+
* newly-confirmed session would target the older app. A newer
|
|
409
|
+
* in-flight optimistic write (higher `dispatchedAt`) is preserved.
|
|
368
410
|
*/
|
|
369
411
|
private promoteStartIfCurrent(
|
|
370
412
|
attempted: ActiveAppControlSession | undefined,
|
|
@@ -373,7 +415,16 @@ export class HostAppControlProxy extends HostProxyBase<
|
|
|
373
415
|
if (activeAppControlSession?.conversationId !== attempted.conversationId) {
|
|
374
416
|
return;
|
|
375
417
|
}
|
|
418
|
+
if (
|
|
419
|
+
confirmedAppControlSession != null &&
|
|
420
|
+
attempted.dispatchedAt <= confirmedAppControlSession.dispatchedAt
|
|
421
|
+
) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
376
424
|
confirmedAppControlSession = attempted;
|
|
425
|
+
if (activeAppControlSession.dispatchedAt < attempted.dispatchedAt) {
|
|
426
|
+
activeAppControlSession = attempted;
|
|
427
|
+
}
|
|
377
428
|
}
|
|
378
429
|
|
|
379
430
|
/**
|
|
@@ -280,7 +280,7 @@ export class HostCuProxy {
|
|
|
280
280
|
observation: CuObservationResult,
|
|
281
281
|
): ToolExecutionResult | undefined {
|
|
282
282
|
this._ownedRequests.delete(requestId);
|
|
283
|
-
const interaction = pendingInteractions.resolve(requestId);
|
|
283
|
+
const interaction = pendingInteractions.resolve(requestId, "answered");
|
|
284
284
|
if (!interaction?.rpcResolve) {
|
|
285
285
|
log.warn({ requestId }, "No pending host CU request for response");
|
|
286
286
|
return undefined;
|
|
@@ -227,7 +227,7 @@ export class HostFileProxy {
|
|
|
227
227
|
requestId: string,
|
|
228
228
|
response: { content: string; isError: boolean; imageData?: string },
|
|
229
229
|
): void {
|
|
230
|
-
const interaction = pendingInteractions.resolve(requestId);
|
|
230
|
+
const interaction = pendingInteractions.resolve(requestId, "answered");
|
|
231
231
|
if (!interaction?.rpcResolve) {
|
|
232
232
|
log.warn({ requestId }, "No pending host file request for response");
|
|
233
233
|
return;
|
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
import type { HostProxyCapability, InterfaceId } from "../channels/types.js";
|
|
30
30
|
import { supportsHostProxy } from "../channels/types.js";
|
|
31
31
|
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
32
|
+
import { getLogger } from "../util/logger.js";
|
|
33
|
+
|
|
34
|
+
const log = getLogger("host-proxy-preactivation");
|
|
32
35
|
|
|
33
36
|
/**
|
|
34
37
|
* Subset of Conversation/ProcessConversationContext that
|
|
@@ -36,9 +39,29 @@ import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
|
36
39
|
* `ProcessConversationContext` satisfy this structurally.
|
|
37
40
|
*/
|
|
38
41
|
export interface HostProxyPreactivationTarget {
|
|
42
|
+
readonly conversationId: string;
|
|
39
43
|
addPreactivatedSkillId(id: string): void;
|
|
40
44
|
}
|
|
41
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Why an attachment decision went the way it did. Logged per turn so that
|
|
48
|
+
* silent-gate failures (e.g. ATL-609: computer-use never reaches the LLM
|
|
49
|
+
* surface for a macOS user) can be diagnosed from production logs without
|
|
50
|
+
* extra instrumentation.
|
|
51
|
+
*/
|
|
52
|
+
export type HostProxyAttachmentReason =
|
|
53
|
+
| "native_support"
|
|
54
|
+
| "cross_client"
|
|
55
|
+
| "denied_no_interface"
|
|
56
|
+
| "denied_chrome_extension"
|
|
57
|
+
| "denied_no_clients";
|
|
58
|
+
|
|
59
|
+
export interface HostProxyAttachmentDecision {
|
|
60
|
+
shouldAttach: boolean;
|
|
61
|
+
reason: HostProxyAttachmentReason;
|
|
62
|
+
clientCount?: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
42
65
|
/**
|
|
43
66
|
* Registry mapping each host-proxy capability to the skill that must be
|
|
44
67
|
* preactivated when that capability is supported by the source interface.
|
|
@@ -62,45 +85,89 @@ export const HOST_PROXY_SKILL_PREACTIVATIONS: ReadonlyArray<{
|
|
|
62
85
|
];
|
|
63
86
|
|
|
64
87
|
/**
|
|
65
|
-
* Returns
|
|
66
|
-
*
|
|
88
|
+
* Returns the full attachment decision for a host-proxy capability — used both
|
|
89
|
+
* to gate proxy instantiation and to feed the structured preactivation log so
|
|
90
|
+
* silent gates can be diagnosed without re-instrumenting after the fact.
|
|
67
91
|
*
|
|
68
|
-
* 1.
|
|
69
|
-
* 2.
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
92
|
+
* 1. No source interface → `denied_no_interface`.
|
|
93
|
+
* 2. Source interface natively supports the capability → `native_support`.
|
|
94
|
+
* 3. `chrome-extension` source can never broker cross-client routing to a
|
|
95
|
+
* macOS client (security boundary) → `denied_chrome_extension`.
|
|
96
|
+
* 4. At least one connected client advertises the capability →
|
|
97
|
+
* `cross_client` with `clientCount`.
|
|
98
|
+
* 5. Otherwise → `denied_no_clients` with `clientCount: 0`.
|
|
73
99
|
*
|
|
74
|
-
*
|
|
75
|
-
|
|
100
|
+
* Single source of truth for preactivation and proxy instantiation.
|
|
101
|
+
*/
|
|
102
|
+
export function evaluateHostProxyAttachment(
|
|
103
|
+
capability: HostProxyCapability,
|
|
104
|
+
sourceInterface: InterfaceId | undefined,
|
|
105
|
+
): HostProxyAttachmentDecision {
|
|
106
|
+
if (!sourceInterface) {
|
|
107
|
+
return { shouldAttach: false, reason: "denied_no_interface" };
|
|
108
|
+
}
|
|
109
|
+
if (supportsHostProxy(sourceInterface, capability)) {
|
|
110
|
+
return { shouldAttach: true, reason: "native_support" };
|
|
111
|
+
}
|
|
112
|
+
if (sourceInterface === "chrome-extension") {
|
|
113
|
+
return { shouldAttach: false, reason: "denied_chrome_extension" };
|
|
114
|
+
}
|
|
115
|
+
const clientCount =
|
|
116
|
+
assistantEventHub.listClientsByCapability(capability).length;
|
|
117
|
+
if (clientCount > 0) {
|
|
118
|
+
return { shouldAttach: true, reason: "cross_client", clientCount };
|
|
119
|
+
}
|
|
120
|
+
return { shouldAttach: false, reason: "denied_no_clients", clientCount: 0 };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Boolean wrapper retained for the proxy-instantiation call sites that only
|
|
125
|
+
* need the gate result. Prefer `evaluateHostProxyAttachment` when the reason
|
|
126
|
+
* is also useful (e.g. for logging or telemetry).
|
|
76
127
|
*/
|
|
77
128
|
export function shouldAttachHostProxyForCapability(
|
|
78
129
|
capability: HostProxyCapability,
|
|
79
130
|
sourceInterface: InterfaceId | undefined,
|
|
80
131
|
): boolean {
|
|
81
|
-
|
|
82
|
-
if (supportsHostProxy(sourceInterface, capability)) return true;
|
|
83
|
-
if (sourceInterface === "chrome-extension") return false;
|
|
84
|
-
return assistantEventHub.listClientsByCapability(capability).length > 0;
|
|
132
|
+
return evaluateHostProxyAttachment(capability, sourceInterface).shouldAttach;
|
|
85
133
|
}
|
|
86
134
|
|
|
87
135
|
/**
|
|
88
136
|
* Preactivate every host-proxy-backed skill that the given source interface
|
|
89
|
-
* supports
|
|
137
|
+
* supports, and emit one structured `log.info` line per turn capturing each
|
|
138
|
+
* capability's decision + the final preactivated skill IDs.
|
|
139
|
+
*
|
|
140
|
+
* The log line fires unconditionally — even when `sourceInterface` is
|
|
141
|
+
* undefined — because "preactivation never ran because no interface" is
|
|
142
|
+
* itself the diagnostic signal we want visible in production.
|
|
90
143
|
*
|
|
91
144
|
* Callers are responsible for any additional gating (e.g. only preactivating
|
|
92
145
|
* when the conversation is idle vs. when re-adding after dequeue), since
|
|
93
|
-
* those constraints differ across create vs. drain paths.
|
|
94
|
-
* iterates the registry and dispatches.
|
|
146
|
+
* those constraints differ across create vs. drain paths.
|
|
95
147
|
*/
|
|
96
148
|
export function preactivateHostProxySkills(
|
|
97
149
|
conversation: HostProxyPreactivationTarget,
|
|
98
150
|
sourceInterface: InterfaceId | undefined,
|
|
99
151
|
): void {
|
|
100
|
-
|
|
152
|
+
const decisions: Record<string, HostProxyAttachmentDecision> = {};
|
|
153
|
+
const preactivatedSkillIds: string[] = [];
|
|
154
|
+
|
|
101
155
|
for (const { capability, skillId } of HOST_PROXY_SKILL_PREACTIVATIONS) {
|
|
102
|
-
|
|
156
|
+
const decision = evaluateHostProxyAttachment(capability, sourceInterface);
|
|
157
|
+
decisions[capability] = decision;
|
|
158
|
+
if (decision.shouldAttach) {
|
|
103
159
|
conversation.addPreactivatedSkillId(skillId);
|
|
160
|
+
preactivatedSkillIds.push(skillId);
|
|
104
161
|
}
|
|
105
162
|
}
|
|
163
|
+
|
|
164
|
+
log.info(
|
|
165
|
+
{
|
|
166
|
+
conversationId: conversation.conversationId,
|
|
167
|
+
sourceInterface,
|
|
168
|
+
decisions,
|
|
169
|
+
preactivatedSkillIds,
|
|
170
|
+
},
|
|
171
|
+
"host-proxy preactivation decision",
|
|
172
|
+
);
|
|
106
173
|
}
|
|
@@ -508,7 +508,7 @@ export class HostTransferProxy {
|
|
|
508
508
|
errorMessage?: string;
|
|
509
509
|
},
|
|
510
510
|
): void {
|
|
511
|
-
const interaction = pendingInteractions.resolve(requestId);
|
|
511
|
+
const interaction = pendingInteractions.resolve(requestId, "answered");
|
|
512
512
|
if (!interaction?.rpcResolve) {
|
|
513
513
|
log.warn({ requestId }, "No pending host transfer request for response");
|
|
514
514
|
return;
|