@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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RenderedHistoryContent } from "../daemon/handlers/shared.js";
|
|
1
2
|
import { renderHistoryContent } from "../daemon/handlers/shared.js";
|
|
2
3
|
import { getAttachmentMetadataForMessage } from "../memory/attachments-store.js";
|
|
3
4
|
import {
|
|
@@ -76,6 +77,18 @@ function toDeliverableTextSegments(
|
|
|
76
77
|
return [];
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
function hasDeliverableReply(
|
|
81
|
+
rendered: RenderedHistoryContent,
|
|
82
|
+
attachments: RuntimeAttachmentMetadata[],
|
|
83
|
+
): boolean {
|
|
84
|
+
return (
|
|
85
|
+
toDeliverableTextSegments(rendered.textSegments, rendered.text).length >
|
|
86
|
+
0 ||
|
|
87
|
+
attachments.length > 0 ||
|
|
88
|
+
hasNoResponseMarker(rendered.textSegments)
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
79
92
|
export async function deliverRenderedReplyViaCallback(
|
|
80
93
|
params: DeliverRenderedReplyParams,
|
|
81
94
|
): Promise<void> {
|
|
@@ -169,6 +182,13 @@ export async function deliverRenderedReplyViaCallback(
|
|
|
169
182
|
}
|
|
170
183
|
|
|
171
184
|
export type DeliverReplyOptions = {
|
|
185
|
+
/** Persisted assistant message row to deliver; defaults to latest assistant. */
|
|
186
|
+
messageId?: string;
|
|
187
|
+
/**
|
|
188
|
+
* Internal conversation message id for the user row that started this
|
|
189
|
+
* delivery. When set, fallback scans never cross into older turns.
|
|
190
|
+
*/
|
|
191
|
+
sinceMessageId?: string;
|
|
172
192
|
startFromSegment?: number;
|
|
173
193
|
onSegmentDelivered?: (deliveredCount: number) => void;
|
|
174
194
|
/** Deliver as ephemeral (visible only to `user`). Fire-and-forget. */
|
|
@@ -181,6 +201,125 @@ export type DeliverReplyOptions = {
|
|
|
181
201
|
onMessageTs?: (ts: string) => void;
|
|
182
202
|
};
|
|
183
203
|
|
|
204
|
+
type PersistedMessage = ReturnType<typeof getMessages>[number];
|
|
205
|
+
|
|
206
|
+
function readPersistedAssistantReply(msg: PersistedMessage): {
|
|
207
|
+
rendered: RenderedHistoryContent;
|
|
208
|
+
replyAttachments: RuntimeAttachmentMetadata[];
|
|
209
|
+
} {
|
|
210
|
+
let parsed: unknown;
|
|
211
|
+
try {
|
|
212
|
+
parsed = JSON.parse(msg.content);
|
|
213
|
+
} catch {
|
|
214
|
+
parsed = msg.content;
|
|
215
|
+
}
|
|
216
|
+
const rendered = renderHistoryContent(parsed);
|
|
217
|
+
|
|
218
|
+
const linked = getAttachmentMetadataForMessage(msg.id);
|
|
219
|
+
const replyAttachments: RuntimeAttachmentMetadata[] = linked.map((a) => ({
|
|
220
|
+
id: a.id,
|
|
221
|
+
filename: a.originalFilename,
|
|
222
|
+
mimeType: a.mimeType,
|
|
223
|
+
sizeBytes: a.sizeBytes,
|
|
224
|
+
kind: a.kind,
|
|
225
|
+
}));
|
|
226
|
+
|
|
227
|
+
return { rendered, replyAttachments };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function isToolResultUserMessage(msg: PersistedMessage): boolean {
|
|
231
|
+
if (msg.role !== "user") return false;
|
|
232
|
+
try {
|
|
233
|
+
const parsed = JSON.parse(msg.content) as unknown;
|
|
234
|
+
return (
|
|
235
|
+
Array.isArray(parsed) &&
|
|
236
|
+
parsed.length > 0 &&
|
|
237
|
+
parsed.every(
|
|
238
|
+
(block) =>
|
|
239
|
+
block !== null &&
|
|
240
|
+
typeof block === "object" &&
|
|
241
|
+
(block as Record<string, unknown>).type === "tool_result",
|
|
242
|
+
)
|
|
243
|
+
);
|
|
244
|
+
} catch {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function findAssistantReplyMessageIdForTurn(
|
|
250
|
+
conversationId: string,
|
|
251
|
+
userMessageId: string,
|
|
252
|
+
): string | undefined {
|
|
253
|
+
const msgs = getMessages(conversationId);
|
|
254
|
+
const userIndex = msgs.findIndex((msg) => msg.id === userMessageId);
|
|
255
|
+
if (userIndex === -1) return undefined;
|
|
256
|
+
|
|
257
|
+
let turnEndIndex = msgs.length;
|
|
258
|
+
for (let i = userIndex + 1; i < msgs.length; i++) {
|
|
259
|
+
const msg = msgs[i];
|
|
260
|
+
if (msg.role === "user" && !isToolResultUserMessage(msg)) {
|
|
261
|
+
turnEndIndex = i;
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
for (let i = turnEndIndex - 1; i > userIndex; i--) {
|
|
267
|
+
const msg = msgs[i];
|
|
268
|
+
if (msg.role === "assistant") {
|
|
269
|
+
const { rendered, replyAttachments } = readPersistedAssistantReply(msg);
|
|
270
|
+
if (hasDeliverableReply(rendered, replyAttachments)) {
|
|
271
|
+
return msg.id;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async function deliverPersistedAssistantMessageViaCallback(
|
|
279
|
+
msg: PersistedMessage,
|
|
280
|
+
externalChatId: string,
|
|
281
|
+
callbackUrl: string,
|
|
282
|
+
assistantId: string | undefined,
|
|
283
|
+
options: DeliverReplyOptions | undefined,
|
|
284
|
+
): Promise<boolean> {
|
|
285
|
+
const { rendered, replyAttachments } = readPersistedAssistantReply(msg);
|
|
286
|
+
if (!hasDeliverableReply(rendered, replyAttachments)) {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Compose an `onMessageTs` that reconciles `slackMeta.channelTs` on the
|
|
291
|
+
// persisted assistant row once Slack returns the authoritative ts. The
|
|
292
|
+
// assistant row was written BEFORE the gateway POST in
|
|
293
|
+
// `handleMessageComplete`, so the partial `slackMeta` it carries is
|
|
294
|
+
// missing `channelTs` and would otherwise be rejected by
|
|
295
|
+
// `readSlackMetadata`, dropping the row out of chronological/thread-tag
|
|
296
|
+
// rendering. We only act on the FIRST ts (top-level segment); any
|
|
297
|
+
// subsequent split segments become independent Slack messages with
|
|
298
|
+
// their own ts and are not represented as separate DB rows.
|
|
299
|
+
const reconcileOnMessageTs = makeChannelTsReconciler(msg.id);
|
|
300
|
+
const callerOnMessageTs = options?.onMessageTs;
|
|
301
|
+
const composedOnMessageTs = (ts: string): void => {
|
|
302
|
+
reconcileOnMessageTs(ts);
|
|
303
|
+
callerOnMessageTs?.(ts);
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
await deliverRenderedReplyViaCallback({
|
|
307
|
+
callbackUrl,
|
|
308
|
+
chatId: externalChatId,
|
|
309
|
+
textSegments: rendered.textSegments,
|
|
310
|
+
fallbackText: rendered.text,
|
|
311
|
+
attachments: replyAttachments,
|
|
312
|
+
assistantId,
|
|
313
|
+
startFromSegment: options?.startFromSegment,
|
|
314
|
+
onSegmentDelivered: options?.onSegmentDelivered,
|
|
315
|
+
ephemeral: options?.ephemeral,
|
|
316
|
+
user: options?.user,
|
|
317
|
+
messageTs: options?.messageTs,
|
|
318
|
+
onMessageTs: composedOnMessageTs,
|
|
319
|
+
});
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
|
|
184
323
|
export async function deliverReplyViaCallback(
|
|
185
324
|
conversationId: string,
|
|
186
325
|
externalChatId: string,
|
|
@@ -188,58 +327,54 @@ export async function deliverReplyViaCallback(
|
|
|
188
327
|
assistantId?: string,
|
|
189
328
|
options?: DeliverReplyOptions,
|
|
190
329
|
): Promise<void> {
|
|
330
|
+
if (options?.messageId) {
|
|
331
|
+
const msg = getMessageById(options.messageId, conversationId);
|
|
332
|
+
if (!msg || msg.role !== "assistant") {
|
|
333
|
+
throw new Error(
|
|
334
|
+
`Target assistant reply message not found: ${options.messageId}`,
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
await deliverPersistedAssistantMessageViaCallback(
|
|
338
|
+
msg,
|
|
339
|
+
externalChatId,
|
|
340
|
+
callbackUrl,
|
|
341
|
+
assistantId,
|
|
342
|
+
options,
|
|
343
|
+
);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (options?.sinceMessageId) {
|
|
348
|
+
const replyMessageId = findAssistantReplyMessageIdForTurn(
|
|
349
|
+
conversationId,
|
|
350
|
+
options.sinceMessageId,
|
|
351
|
+
);
|
|
352
|
+
if (replyMessageId) {
|
|
353
|
+
const msg = getMessageById(replyMessageId, conversationId);
|
|
354
|
+
if (msg && msg.role === "assistant") {
|
|
355
|
+
await deliverPersistedAssistantMessageViaCallback(
|
|
356
|
+
msg,
|
|
357
|
+
externalChatId,
|
|
358
|
+
callbackUrl,
|
|
359
|
+
assistantId,
|
|
360
|
+
options,
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
191
367
|
const msgs = getMessages(conversationId);
|
|
192
368
|
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
193
369
|
if (msgs[i].role !== "assistant") continue;
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
parsed = JSON.parse(msgs[i].content);
|
|
198
|
-
} catch {
|
|
199
|
-
parsed = msgs[i].content;
|
|
200
|
-
}
|
|
201
|
-
const rendered = renderHistoryContent(parsed);
|
|
202
|
-
|
|
203
|
-
const linked = getAttachmentMetadataForMessage(msgs[i].id);
|
|
204
|
-
const replyAttachments: RuntimeAttachmentMetadata[] = linked.map((a) => ({
|
|
205
|
-
id: a.id,
|
|
206
|
-
filename: a.originalFilename,
|
|
207
|
-
mimeType: a.mimeType,
|
|
208
|
-
sizeBytes: a.sizeBytes,
|
|
209
|
-
kind: a.kind,
|
|
210
|
-
}));
|
|
211
|
-
|
|
212
|
-
// Compose an `onMessageTs` that reconciles `slackMeta.channelTs` on the
|
|
213
|
-
// persisted assistant row once Slack returns the authoritative ts. The
|
|
214
|
-
// assistant row was written BEFORE the gateway POST in
|
|
215
|
-
// `handleMessageComplete`, so the partial `slackMeta` it carries is
|
|
216
|
-
// missing `channelTs` and would otherwise be rejected by
|
|
217
|
-
// `readSlackMetadata`, dropping the row out of chronological/thread-tag
|
|
218
|
-
// rendering. We only act on the FIRST ts (top-level segment); any
|
|
219
|
-
// subsequent split segments become independent Slack messages with
|
|
220
|
-
// their own ts and are not represented as separate DB rows.
|
|
221
|
-
const reconcileOnMessageTs = makeChannelTsReconciler(msgs[i].id);
|
|
222
|
-
const callerOnMessageTs = options?.onMessageTs;
|
|
223
|
-
const composedOnMessageTs = (ts: string): void => {
|
|
224
|
-
reconcileOnMessageTs(ts);
|
|
225
|
-
callerOnMessageTs?.(ts);
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
await deliverRenderedReplyViaCallback({
|
|
370
|
+
const delivered = await deliverPersistedAssistantMessageViaCallback(
|
|
371
|
+
msgs[i],
|
|
372
|
+
externalChatId,
|
|
229
373
|
callbackUrl,
|
|
230
|
-
chatId: externalChatId,
|
|
231
|
-
textSegments: rendered.textSegments,
|
|
232
|
-
fallbackText: rendered.text,
|
|
233
|
-
attachments: replyAttachments,
|
|
234
374
|
assistantId,
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
user: options?.user,
|
|
239
|
-
messageTs: options?.messageTs,
|
|
240
|
-
onMessageTs: composedOnMessageTs,
|
|
241
|
-
});
|
|
242
|
-
break;
|
|
375
|
+
options,
|
|
376
|
+
);
|
|
377
|
+
if (delivered) break;
|
|
243
378
|
}
|
|
244
379
|
}
|
|
245
380
|
|
|
@@ -9,17 +9,28 @@ import {
|
|
|
9
9
|
} from "../channels/types.js";
|
|
10
10
|
import { getDiskPressureStatus } from "../daemon/disk-pressure-guard.js";
|
|
11
11
|
import { classifyDiskPressureTurnPolicy } from "../daemon/disk-pressure-policy.js";
|
|
12
|
+
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
12
13
|
import type { TrustContext } from "../daemon/trust-context.js";
|
|
13
14
|
import { updateDeliveredSegmentCount } from "../memory/delivery-channels.js";
|
|
14
|
-
import { clearPayload, linkMessage } from "../memory/delivery-crud.js";
|
|
15
15
|
import {
|
|
16
|
+
clearPayload,
|
|
17
|
+
linkMessage,
|
|
18
|
+
storeReplyMessageId,
|
|
19
|
+
} from "../memory/delivery-crud.js";
|
|
20
|
+
import {
|
|
21
|
+
getRetryableDeliveryEvents,
|
|
16
22
|
getRetryableEvents,
|
|
23
|
+
markDeliveryDelivered,
|
|
17
24
|
markProcessed,
|
|
18
25
|
markRetryableFailure,
|
|
26
|
+
recordDeliveryFailure,
|
|
19
27
|
recordProcessingFailure,
|
|
20
28
|
} from "../memory/delivery-status.js";
|
|
21
29
|
import { getLogger } from "../util/logger.js";
|
|
22
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
deliverReplyViaCallback,
|
|
32
|
+
findAssistantReplyMessageIdForTurn,
|
|
33
|
+
} from "./channel-reply-delivery.js";
|
|
23
34
|
import { deliverChannelReply } from "./gateway-client.js";
|
|
24
35
|
import type { MessageProcessor } from "./http-types.js";
|
|
25
36
|
import { resolveRoutingStateFromRuntime } from "./trust-context-resolver.js";
|
|
@@ -91,9 +102,13 @@ export async function sweepFailedEvents(
|
|
|
91
102
|
processMessage: MessageProcessor,
|
|
92
103
|
): Promise<void> {
|
|
93
104
|
const events = getRetryableEvents();
|
|
94
|
-
|
|
105
|
+
const deliveryEvents = getRetryableDeliveryEvents();
|
|
106
|
+
if (events.length === 0 && deliveryEvents.length === 0) return;
|
|
95
107
|
|
|
96
|
-
log.info(
|
|
108
|
+
log.info(
|
|
109
|
+
{ processingCount: events.length, deliveryCount: deliveryEvents.length },
|
|
110
|
+
"Retrying failed channel inbound events",
|
|
111
|
+
);
|
|
97
112
|
|
|
98
113
|
for (const event of events) {
|
|
99
114
|
if (!event.rawPayload) {
|
|
@@ -243,9 +258,20 @@ export async function sweepFailedEvents(
|
|
|
243
258
|
sourceMetadata.chatType.trim().length > 0
|
|
244
259
|
? sourceMetadata.chatType.trim()
|
|
245
260
|
: undefined;
|
|
261
|
+
let replyMessageId: string | undefined;
|
|
262
|
+
const observeAgentEvent = (msg: ServerMessage): void => {
|
|
263
|
+
if (
|
|
264
|
+
msg.type === "message_complete" &&
|
|
265
|
+
(msg.source === undefined || msg.source === "main") &&
|
|
266
|
+
typeof msg.messageId === "string"
|
|
267
|
+
) {
|
|
268
|
+
replyMessageId = msg.messageId;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
246
271
|
|
|
272
|
+
let userMessageId: string | undefined;
|
|
247
273
|
try {
|
|
248
|
-
const
|
|
274
|
+
const result = await processMessage(
|
|
249
275
|
event.conversationId,
|
|
250
276
|
content,
|
|
251
277
|
attachmentIds,
|
|
@@ -260,27 +286,39 @@ export async function sweepFailedEvents(
|
|
|
260
286
|
trustContext,
|
|
261
287
|
isInteractive:
|
|
262
288
|
resolveRoutingStateFromRuntime(trustContext).promptWaitingAllowed,
|
|
289
|
+
onEvent: observeAgentEvent,
|
|
263
290
|
},
|
|
264
291
|
sourceChannel,
|
|
265
292
|
sourceInterface,
|
|
266
293
|
);
|
|
294
|
+
userMessageId = result.messageId;
|
|
267
295
|
linkMessage(event.id, userMessageId);
|
|
268
296
|
markProcessed(event.id);
|
|
297
|
+
replyMessageId ??= result.assistantMessageId;
|
|
298
|
+
if (replyMessageId) {
|
|
299
|
+
storeReplyMessageId(event.id, replyMessageId);
|
|
300
|
+
}
|
|
269
301
|
log.info(
|
|
270
302
|
{ eventId: event.id },
|
|
271
303
|
"Successfully replayed failed channel event",
|
|
272
304
|
);
|
|
305
|
+
} catch (err) {
|
|
306
|
+
log.error({ err, eventId: event.id }, "Retry failed for channel event");
|
|
307
|
+
recordProcessingFailure(event.id, err);
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
273
310
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
311
|
+
const replyCallbackUrl =
|
|
312
|
+
typeof payload.replyCallbackUrl === "string"
|
|
313
|
+
? payload.replyCallbackUrl
|
|
314
|
+
: undefined;
|
|
315
|
+
if (replyCallbackUrl) {
|
|
316
|
+
const externalChatId =
|
|
317
|
+
typeof payload.externalChatId === "string"
|
|
318
|
+
? payload.externalChatId
|
|
277
319
|
: undefined;
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
typeof payload.externalChatId === "string"
|
|
281
|
-
? payload.externalChatId
|
|
282
|
-
: undefined;
|
|
283
|
-
if (externalChatId) {
|
|
320
|
+
if (externalChatId) {
|
|
321
|
+
try {
|
|
284
322
|
// processMessage above generated a fresh assistant response, so any
|
|
285
323
|
// previously tracked segment progress belongs to the old response and
|
|
286
324
|
// must not carry over. Reset to 0 so we deliver all segments of the
|
|
@@ -292,16 +330,103 @@ export async function sweepFailedEvents(
|
|
|
292
330
|
replyCallbackUrl,
|
|
293
331
|
assistantId,
|
|
294
332
|
{
|
|
333
|
+
messageId: replyMessageId,
|
|
334
|
+
sinceMessageId: userMessageId,
|
|
295
335
|
startFromSegment: 0,
|
|
296
336
|
onSegmentDelivered: (count) =>
|
|
297
337
|
updateDeliveredSegmentCount(event.id, count),
|
|
298
338
|
},
|
|
299
339
|
);
|
|
340
|
+
markDeliveryDelivered(event.id);
|
|
341
|
+
} catch (err) {
|
|
342
|
+
log.error(
|
|
343
|
+
{ err, eventId: event.id },
|
|
344
|
+
"Retry delivery failed for channel event",
|
|
345
|
+
);
|
|
346
|
+
recordDeliveryFailure(event.id, err);
|
|
300
347
|
}
|
|
301
348
|
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
for (const event of deliveryEvents) {
|
|
353
|
+
if (!event.rawPayload) {
|
|
354
|
+
recordDeliveryFailure(
|
|
355
|
+
event.id,
|
|
356
|
+
new Error("No raw payload stored for delivery retry"),
|
|
357
|
+
);
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
let payload: Record<string, unknown>;
|
|
362
|
+
try {
|
|
363
|
+
payload = JSON.parse(event.rawPayload) as Record<string, unknown>;
|
|
364
|
+
} catch {
|
|
365
|
+
recordDeliveryFailure(
|
|
366
|
+
event.id,
|
|
367
|
+
new Error("Failed to parse stored raw payload for delivery retry"),
|
|
368
|
+
);
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const replyCallbackUrl =
|
|
373
|
+
typeof payload.replyCallbackUrl === "string"
|
|
374
|
+
? payload.replyCallbackUrl
|
|
375
|
+
: undefined;
|
|
376
|
+
const externalChatId =
|
|
377
|
+
typeof payload.externalChatId === "string"
|
|
378
|
+
? payload.externalChatId
|
|
379
|
+
: undefined;
|
|
380
|
+
let replyMessageId =
|
|
381
|
+
typeof payload.replyMessageId === "string"
|
|
382
|
+
? payload.replyMessageId
|
|
383
|
+
: undefined;
|
|
384
|
+
const assistantId =
|
|
385
|
+
typeof payload.assistantId === "string" ? payload.assistantId : undefined;
|
|
386
|
+
if (!replyCallbackUrl || !externalChatId) {
|
|
387
|
+
recordDeliveryFailure(
|
|
388
|
+
event.id,
|
|
389
|
+
new Error("Stored payload is missing delivery callback details"),
|
|
390
|
+
);
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
if (!replyMessageId && event.messageId) {
|
|
394
|
+
replyMessageId = findAssistantReplyMessageIdForTurn(
|
|
395
|
+
event.conversationId,
|
|
396
|
+
event.messageId,
|
|
397
|
+
);
|
|
398
|
+
if (replyMessageId) {
|
|
399
|
+
storeReplyMessageId(event.id, replyMessageId);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (!replyMessageId) {
|
|
403
|
+
recordDeliveryFailure(
|
|
404
|
+
event.id,
|
|
405
|
+
new Error("Stored payload is missing assistant reply message id"),
|
|
406
|
+
);
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
try {
|
|
411
|
+
await deliverReplyViaCallback(
|
|
412
|
+
event.conversationId,
|
|
413
|
+
externalChatId,
|
|
414
|
+
replyCallbackUrl,
|
|
415
|
+
assistantId,
|
|
416
|
+
{
|
|
417
|
+
messageId: replyMessageId,
|
|
418
|
+
startFromSegment: event.deliveredSegmentCount,
|
|
419
|
+
onSegmentDelivered: (count) =>
|
|
420
|
+
updateDeliveredSegmentCount(event.id, count),
|
|
421
|
+
},
|
|
422
|
+
);
|
|
423
|
+
markDeliveryDelivered(event.id);
|
|
302
424
|
} catch (err) {
|
|
303
|
-
log.error(
|
|
304
|
-
|
|
425
|
+
log.error(
|
|
426
|
+
{ err, eventId: event.id },
|
|
427
|
+
"Retry delivery failed for processed channel event",
|
|
428
|
+
);
|
|
429
|
+
recordDeliveryFailure(event.id, err);
|
|
305
430
|
}
|
|
306
431
|
}
|
|
307
432
|
}
|
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
import { isHttpAuthDisabled } from "../config/env.js";
|
|
29
29
|
import { getIsPlatform } from "../config/env-registry.js";
|
|
30
30
|
import { getConfig } from "../config/loader.js";
|
|
31
|
+
import { createApprovalCopyGenerator } from "../daemon/approval-generators.js";
|
|
32
|
+
import { createGuardianActionCopyGenerator } from "../daemon/guardian-action-generators.js";
|
|
31
33
|
import { processMessage } from "../daemon/process-message.js";
|
|
32
34
|
import { createLiveVoiceSession } from "../live-voice/live-voice-session.js";
|
|
33
35
|
import { LiveVoiceSessionManager } from "../live-voice/live-voice-session-manager.js";
|
|
@@ -96,10 +98,8 @@ import { matchSkillRoute } from "./skill-route-registry.js";
|
|
|
96
98
|
export { isPrivateAddress } from "./middleware/auth.js";
|
|
97
99
|
|
|
98
100
|
import type {
|
|
99
|
-
ApprovalConversationGenerator,
|
|
100
101
|
ApprovalCopyGenerator,
|
|
101
102
|
GuardianActionCopyGenerator,
|
|
102
|
-
GuardianFollowUpConversationGenerator,
|
|
103
103
|
RuntimeHttpServerOptions,
|
|
104
104
|
} from "./http-types.js";
|
|
105
105
|
|
|
@@ -161,10 +161,8 @@ export class RuntimeHttpServer {
|
|
|
161
161
|
private port: number;
|
|
162
162
|
private hostname: string;
|
|
163
163
|
|
|
164
|
-
private approvalCopyGenerator
|
|
165
|
-
private
|
|
166
|
-
private guardianActionCopyGenerator?: GuardianActionCopyGenerator;
|
|
167
|
-
private guardianFollowUpConversationGenerator?: GuardianFollowUpConversationGenerator;
|
|
164
|
+
private readonly approvalCopyGenerator: ApprovalCopyGenerator;
|
|
165
|
+
private readonly guardianActionCopyGenerator: GuardianActionCopyGenerator;
|
|
168
166
|
private retrySweepTimer: ReturnType<typeof setInterval> | null = null;
|
|
169
167
|
private sweepInProgress = false;
|
|
170
168
|
|
|
@@ -175,11 +173,8 @@ export class RuntimeHttpServer {
|
|
|
175
173
|
this.port = options.port ?? DEFAULT_PORT;
|
|
176
174
|
this.hostname = options.hostname ?? DEFAULT_HOSTNAME;
|
|
177
175
|
|
|
178
|
-
this.approvalCopyGenerator =
|
|
179
|
-
this.
|
|
180
|
-
this.guardianActionCopyGenerator = options.guardianActionCopyGenerator;
|
|
181
|
-
this.guardianFollowUpConversationGenerator =
|
|
182
|
-
options.guardianFollowUpConversationGenerator;
|
|
176
|
+
this.approvalCopyGenerator = createApprovalCopyGenerator();
|
|
177
|
+
this.guardianActionCopyGenerator = createGuardianActionCopyGenerator();
|
|
183
178
|
this.liveVoiceSessionManager = new LiveVoiceSessionManager({
|
|
184
179
|
createSession: (context) => createLiveVoiceSession(context),
|
|
185
180
|
});
|
|
@@ -560,11 +555,7 @@ export class RuntimeHttpServer {
|
|
|
560
555
|
const endpoint = url.pathname.slice("/v1/".length).replace(/\/$/, "");
|
|
561
556
|
meta = this.router.findLoggingMetadata(req.method, endpoint) ?? undefined;
|
|
562
557
|
}
|
|
563
|
-
return withRequestLogging(
|
|
564
|
-
req,
|
|
565
|
-
() => this.routeRequest(req, server),
|
|
566
|
-
meta,
|
|
567
|
-
);
|
|
558
|
+
return withRequestLogging(req, () => this.routeRequest(req, server), meta);
|
|
568
559
|
}
|
|
569
560
|
|
|
570
561
|
private async routeRequest(
|
|
@@ -14,10 +14,6 @@ import type {
|
|
|
14
14
|
export type { SlackInboundMessageMetadata };
|
|
15
15
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
16
16
|
import type { AssistantEventHub } from "./assistant-event-hub.js";
|
|
17
|
-
import type {
|
|
18
|
-
ApprovalCopyGenerator,
|
|
19
|
-
GuardianActionCopyGenerator,
|
|
20
|
-
} from "./message-composer-types.js";
|
|
21
17
|
|
|
22
18
|
export type {
|
|
23
19
|
ApprovalCopyGenerator,
|
|
@@ -61,47 +57,13 @@ export type ApprovalConversationGenerator = (
|
|
|
61
57
|
context: ApprovalConversationContext,
|
|
62
58
|
) => Promise<ApprovalConversationResult>;
|
|
63
59
|
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
// Guardian follow-up conversation flow types
|
|
66
|
-
// ---------------------------------------------------------------------------
|
|
67
|
-
|
|
68
|
-
/** The disposition returned by the guardian follow-up conversation engine. */
|
|
69
|
-
export type GuardianFollowUpDisposition =
|
|
70
|
-
| "call_back"
|
|
71
|
-
| "decline"
|
|
72
|
-
| "keep_pending";
|
|
73
|
-
|
|
74
|
-
/** Structured result from a single turn of the guardian follow-up conversation. */
|
|
75
|
-
export interface GuardianFollowUpTurnResult {
|
|
76
|
-
disposition: GuardianFollowUpDisposition;
|
|
77
|
-
replyText: string;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** Input context for the guardian follow-up conversation engine. */
|
|
81
|
-
export interface GuardianFollowUpConversationContext {
|
|
82
|
-
/** The original question that was asked during the voice call. */
|
|
83
|
-
questionText: string;
|
|
84
|
-
/** The guardian's late answer text that initiated the follow-up. */
|
|
85
|
-
lateAnswerText: string;
|
|
86
|
-
/** The guardian's latest reply in the follow-up conversation. */
|
|
87
|
-
guardianReply: string;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Daemon-injected function that processes one turn of a guardian follow-up
|
|
92
|
-
* conversation. Classifies the guardian's intent into a structured disposition
|
|
93
|
-
* and produces a natural reply.
|
|
94
|
-
*/
|
|
95
|
-
export type GuardianFollowUpConversationGenerator = (
|
|
96
|
-
context: GuardianFollowUpConversationContext,
|
|
97
|
-
) => Promise<GuardianFollowUpTurnResult>;
|
|
98
|
-
|
|
99
60
|
export interface RuntimeMessageConversationOptions {
|
|
100
61
|
transport?: {
|
|
101
62
|
channelId: ChannelId;
|
|
102
63
|
hints?: string[];
|
|
103
64
|
uxBrief?: string;
|
|
104
65
|
chatType?: string;
|
|
66
|
+
clientTimezone?: string;
|
|
105
67
|
};
|
|
106
68
|
assistantId?: string;
|
|
107
69
|
trustContext?: TrustContext;
|
|
@@ -113,8 +75,6 @@ export interface RuntimeMessageConversationOptions {
|
|
|
113
75
|
isInteractive?: boolean;
|
|
114
76
|
/** Channel command intent metadata (e.g. Telegram /start). */
|
|
115
77
|
commandIntent?: { type: string; payload?: string; languageCode?: string };
|
|
116
|
-
/** Slack-only non-persisted notice injected into the active model turn. */
|
|
117
|
-
slackRuntimeContextNotice?: string;
|
|
118
78
|
/**
|
|
119
79
|
* Persisted user-facing content. When present, storage/UI use this value
|
|
120
80
|
* while the model-facing turn continues to use `content`.
|
|
@@ -145,7 +105,7 @@ export type MessageProcessor = (
|
|
|
145
105
|
options?: RuntimeMessageConversationOptions,
|
|
146
106
|
sourceChannel?: ChannelId,
|
|
147
107
|
sourceInterface?: InterfaceId,
|
|
148
|
-
) => Promise<{ messageId: string }>;
|
|
108
|
+
) => Promise<{ messageId: string; assistantMessageId?: string }>;
|
|
149
109
|
|
|
150
110
|
/**
|
|
151
111
|
* Dependencies for the POST /v1/messages handler.
|
|
@@ -173,14 +133,6 @@ export interface RuntimeHttpServerOptions {
|
|
|
173
133
|
port?: number;
|
|
174
134
|
/** Hostname / IP to bind to. Defaults to '127.0.0.1' (loopback-only). */
|
|
175
135
|
hostname?: string;
|
|
176
|
-
/** Daemon-injected generator for approval copy (provider-backed). */
|
|
177
|
-
approvalCopyGenerator?: ApprovalCopyGenerator;
|
|
178
|
-
/** Daemon-injected generator for conversational approval flow (provider-backed). */
|
|
179
|
-
approvalConversationGenerator?: ApprovalConversationGenerator;
|
|
180
|
-
/** Daemon-injected generator for guardian action copy (provider-backed). */
|
|
181
|
-
guardianActionCopyGenerator?: GuardianActionCopyGenerator;
|
|
182
|
-
/** Daemon-injected generator for guardian follow-up conversation (provider-backed). */
|
|
183
|
-
guardianFollowUpConversationGenerator?: GuardianFollowUpConversationGenerator;
|
|
184
136
|
}
|
|
185
137
|
|
|
186
138
|
export interface RuntimeAttachmentMetadata {
|
|
@@ -214,7 +166,6 @@ export interface RuntimeMessagePayload {
|
|
|
214
166
|
approvalReason?: string;
|
|
215
167
|
riskThreshold?: string;
|
|
216
168
|
}>;
|
|
217
|
-
interfaces?: string[];
|
|
218
169
|
surfaces?: Array<{
|
|
219
170
|
surfaceId: string;
|
|
220
171
|
surfaceType: string;
|
|
@@ -236,8 +187,13 @@ export interface RuntimeMessagePayload {
|
|
|
236
187
|
};
|
|
237
188
|
slackMessage?: {
|
|
238
189
|
channelId: string;
|
|
190
|
+
channelName?: string;
|
|
239
191
|
channelTs: string;
|
|
240
192
|
threadTs?: string;
|
|
193
|
+
sender?: {
|
|
194
|
+
displayName?: string;
|
|
195
|
+
externalUserId?: string;
|
|
196
|
+
};
|
|
241
197
|
messageLink?: {
|
|
242
198
|
appUrl?: string;
|
|
243
199
|
webUrl?: string;
|