@vellumai/assistant 0.11.8 → 0.11.9-staging.1
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 +2 -2
- package/Dockerfile +8 -48
- package/docker-entrypoint.sh +5 -1
- package/docker-kata-apt-env.sh +3 -0
- package/docker-kata-apt-shims.sh +127 -0
- package/docker-kata-apt-wrapper.sh +45 -0
- package/docker-kata-chroot-exec.sh +35 -0
- package/docker-kata-pip.sh +8 -2
- package/docs/architecture/memory.md +8 -4
- package/docs/guardian-request-flow.md +18 -14
- package/docs/trusted-contact-access.md +1 -7
- package/node_modules/@vellumai/avatar-catalog/src/catalog.ts +7 -1
- package/node_modules/@vellumai/avatar-catalog/src/index.ts +1 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +4 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +4 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-request-contract.test.ts +0 -18
- package/node_modules/@vellumai/gateway-client/src/__tests__/inbound-event-kind.test.ts +110 -5
- package/node_modules/@vellumai/gateway-client/src/guardian-request-contract.ts +5 -33
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +3 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-event-kind.ts +100 -9
- package/node_modules/@vellumai/gateway-client/src/index.ts +1 -2
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +9 -0
- package/node_modules/@vellumai/service-contracts/package.json +4 -1
- package/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
- package/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
- package/openapi.yaml +193 -4
- package/package.json +2 -2
- package/src/__tests__/access-request-card-view.test.ts +6 -5
- package/src/__tests__/access-request-seed-content-blocks.test.ts +5 -2
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +43 -82
- package/src/__tests__/always-loaded-tools-guard.test.ts +8 -2
- package/src/__tests__/attachment-stored-path-annotation.test.ts +80 -0
- package/src/__tests__/attachments-store.test.ts +27 -0
- package/src/__tests__/attachments.test.ts +43 -0
- package/src/__tests__/canned-reply-release.test.ts +48 -5
- package/src/__tests__/channel-delivery-store.test.ts +129 -18
- package/src/__tests__/channel-reply-delivery.test.ts +553 -93
- package/src/__tests__/channel-retry-sweep.test.ts +199 -0
- package/src/__tests__/client-os-metadata-persistence.test.ts +32 -3
- package/src/__tests__/conversation-error.test.ts +15 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +118 -0
- package/src/__tests__/conversation-pairing.test.ts +141 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +28 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +125 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +79 -0
- package/src/__tests__/conversation-store-ephemeral.test.ts +323 -10
- package/src/__tests__/conversation-sync-tags.test.ts +2 -37
- package/src/__tests__/credential-health-service.test.ts +98 -10
- package/src/__tests__/delete-propagation.test.ts +469 -0
- package/src/__tests__/dm-persistence.test.ts +16 -0
- package/src/__tests__/docker-kata-apt-shims.test.ts +135 -0
- package/src/__tests__/forbidden-legacy-symbols.test.ts +12 -0
- package/src/__tests__/guardian-card-withdrawal.test.ts +0 -22
- package/src/__tests__/guardian-gateway-sim.ts +0 -23
- package/src/__tests__/guardian-question-mode.test.ts +108 -0
- package/src/__tests__/guardian-reply-router-answer-mode.test.ts +0 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +26 -12
- package/src/__tests__/host-proxy-interface.test.ts +10 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +16 -0
- package/src/__tests__/injector-v3-suppression.test.ts +43 -9
- package/src/__tests__/list-messages-page-latest.test.ts +127 -0
- package/src/__tests__/list-messages-system-card.test.ts +103 -0
- package/src/__tests__/media-resolve-image-validation.test.ts +77 -0
- package/src/__tests__/notification-decision-fallback.test.ts +199 -77
- package/src/__tests__/notification-decision-strategy.test.ts +198 -213
- package/src/__tests__/notification-discord-adapter.test.ts +25 -0
- package/src/__tests__/notification-slack-adapter.test.ts +133 -0
- package/src/__tests__/notification-telegram-adapter.test.ts +36 -0
- package/src/__tests__/openai-provider.test.ts +5 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +85 -72
- package/src/__tests__/persist-user-message-set-processing-failure.test.ts +83 -65
- package/src/__tests__/platform-client-verify-credential.test.ts +100 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +1 -1
- package/src/__tests__/process-message-display-content.test.ts +20 -9
- package/src/__tests__/processing-acquire-fenced-guard.test.ts +56 -0
- package/src/__tests__/provider-meta-persistence.test.ts +67 -0
- package/src/__tests__/reaction-persistence.test.ts +22 -198
- package/src/__tests__/run-conversation-turn-persistence.test.ts +5 -2
- package/src/__tests__/scripted-turn-metadata-persistence.test.ts +16 -0
- package/src/__tests__/skill-load-tool.test.ts +27 -0
- package/src/__tests__/skills.test.ts +34 -1
- package/src/__tests__/strip-memory-injections.test.ts +3 -4
- package/src/__tests__/terminal-tools.test.ts +9 -0
- package/src/__tests__/thread-backfill.test.ts +5 -3
- package/src/__tests__/unified-turn-context-location.test.ts +76 -0
- package/src/__tests__/voice-session-bridge.test.ts +18 -0
- package/src/__tests__/watch-retro-report-payload.test.ts +185 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +82 -0
- package/src/__tests__/workspace-migration-151-repair-renamed-fireworks-deepseek-pro-model-id.test.ts +235 -0
- package/src/__tests__/workspace-migration-152-repair-retired-fireworks-minimax-m2p7-model-id.test.ts +233 -0
- package/src/agent/attachments.ts +13 -2
- package/src/agent/loop.ts +3 -19
- package/src/api/README.md +9 -5
- package/src/api/index.ts +9 -8
- package/src/api/package.json +1 -0
- package/src/api/responses/conversation-message.ts +8 -0
- package/src/api/responses/home.ts +7 -18
- package/src/api/surfaces.ts +114 -7
- package/src/approvals/AGENTS.md +1 -1
- package/src/channels/__tests__/gateway-guardian-requests.test.ts +1 -23
- package/src/channels/__tests__/types.test.ts +22 -1
- package/src/channels/gateway-guardian-requests.ts +0 -22
- package/src/channels/types.ts +8 -6
- package/src/cli/__tests__/catalog-search-help.test.ts +12 -0
- package/src/cli/commands/channels/__tests__/channels.test.ts +26 -0
- package/src/cli/commands/channels/index.help.ts +15 -1
- package/src/cli/commands/channels/index.ts +6 -2
- package/src/cli/commands/db/__tests__/status.test.ts +22 -0
- package/src/cli/commands/db/index.help.ts +1 -1
- package/src/cli/commands/db/status.ts +172 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +29 -0
- package/src/cli/commands/platform/connect.ts +14 -5
- package/src/cli/commands/plugins.help.ts +6 -5
- package/src/cli/lib/__tests__/install-from-github.test.ts +0 -8
- package/src/cli/lib/__tests__/install-from-platform.test.ts +72 -0
- package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +33 -0
- package/src/cli/lib/bundled-marketplace.json +14 -0
- package/src/cli/lib/install-from-github.ts +9 -5
- package/src/cli/lib/install-from-platform.ts +12 -1
- package/src/config/__tests__/assistant-initiated-threads-gate.test.ts +61 -0
- package/src/config/assistant-initiated-threads-gate.ts +50 -0
- package/src/config/bundled-skills/acp/SKILL.md +10 -3
- package/src/config/bundled-skills/schedule/SKILL.md +25 -11
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +3 -1
- package/src/config/call-site-defaults.ts +4 -1
- package/src/config/feature-flag-registry.json +21 -4
- package/src/config/schemas/memory-v3.ts +4 -3
- package/src/context/strip-injections.ts +17 -56
- package/src/conversations/__tests__/message-consolidation.test.ts +39 -0
- package/src/conversations/message-consolidation.ts +4 -3
- package/src/credential-health/credential-health-service.ts +130 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +31 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +55 -59
- package/src/daemon/conversation-error.ts +2 -0
- package/src/daemon/conversation-messaging.ts +195 -47
- package/src/daemon/conversation-process.ts +20 -5
- package/src/daemon/conversation-runtime-assembly.ts +48 -39
- package/src/daemon/conversation-store.ts +159 -11
- package/src/daemon/conversation-tool-setup.ts +9 -2
- package/src/daemon/conversation.ts +290 -19
- package/src/daemon/dictation-text-processing.ts +2 -7
- package/src/daemon/handlers/config-channels.ts +33 -3
- package/src/daemon/handlers/shared.ts +9 -0
- package/src/daemon/port-oversized-content.test.ts +117 -0
- package/src/daemon/port-oversized-content.ts +110 -0
- package/src/daemon/process-message.ts +87 -16
- package/src/daemon/reaction-record.test.ts +23 -11
- package/src/daemon/reaction-record.ts +6 -9
- package/src/documents/document-store.ts +1 -5
- package/src/home/conversation-starter-validation.ts +1 -5
- package/src/live-voice/__tests__/live-voice-photo.test.ts +910 -50
- package/src/live-voice/__tests__/live-voice-sight-frame-inline.test.ts +31 -25
- package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +70 -1
- package/src/live-voice/live-voice-photo.ts +544 -61
- package/src/live-voice/live-voice-session.ts +6 -2
- package/src/live-voice/protocol.ts +20 -1
- package/src/messaging/provider-message-metadata.ts +40 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +10 -2
- package/src/messaging/providers/channel-transport.ts +28 -0
- package/src/messaging/providers/discord/send.ts +3 -2
- package/src/messaging/providers/slack/api.ts +11 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +133 -0
- package/src/messaging/providers/slack/message-metadata.ts +141 -1
- package/src/messaging/providers/slack/send.test.ts +58 -0
- package/src/messaging/providers/slack/send.ts +4 -4
- package/src/messaging/providers/slack/transport.ts +28 -2
- package/src/messaging/providers/telegram-bot/send.test.ts +159 -0
- package/src/messaging/providers/telegram-bot/send.ts +93 -0
- package/src/messaging/providers/telegram-bot/transport.ts +71 -0
- package/src/messaging/reaction-envelopes.test.ts +73 -0
- package/src/messaging/reaction-envelopes.ts +33 -5
- package/src/messaging/read-provider-metadata.ts +4 -3
- package/src/monitoring/recovery/__tests__/stranded-delivery-events.test.ts +208 -0
- package/src/monitoring/recovery/db.ts +35 -0
- package/src/monitoring/recovery/orphaned-channel-events.ts +3 -22
- package/src/monitoring/recovery/run-recovery.ts +6 -2
- package/src/monitoring/recovery/stale-processing.ts +3 -20
- package/src/monitoring/recovery/stranded-delivery-events.ts +68 -0
- package/src/notifications/AGENTS.md +2 -2
- package/src/notifications/README.md +2 -2
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +11 -9
- package/src/notifications/__tests__/broadcaster.test.ts +35 -4
- package/src/notifications/__tests__/notification-utils.test.ts +31 -0
- package/src/notifications/access-request-copy.ts +126 -114
- package/src/notifications/adapters/discord.ts +9 -5
- package/src/notifications/adapters/shared.ts +17 -4
- package/src/notifications/adapters/slack.ts +14 -4
- package/src/notifications/adapters/telegram.ts +8 -4
- package/src/notifications/approval-card-data.ts +5 -2
- package/src/notifications/assistant-reply-producer.ts +7 -7
- package/src/notifications/broadcaster.ts +57 -25
- package/src/notifications/conversation-pairing.ts +68 -2
- package/src/notifications/copy-composer.ts +13 -32
- package/src/notifications/decision-engine.ts +56 -237
- package/src/notifications/guardian-delivery-recorder.ts +5 -9
- package/src/notifications/guardian-feed-projection.ts +0 -15
- package/src/notifications/guardian-question-mode.ts +147 -6
- package/src/notifications/notification-utils.ts +117 -1
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/prompter.ts +1 -1
- package/src/persistence/conversation-crud.ts +93 -14
- package/src/persistence/conversation-queries.ts +144 -17
- package/src/persistence/conversation-types.ts +39 -5
- package/src/persistence/delivery-crud.ts +224 -28
- package/src/persistence/delivery-status.ts +21 -2
- package/src/persistence/migrations/374-channel-inbound-message-id-index.ts +26 -0
- package/src/persistence/migrations/375-create-channel-outbound-posts.ts +52 -0
- package/src/persistence/migrations/__tests__/375-create-channel-outbound-posts.test.ts +84 -0
- package/src/persistence/schema/conversations.ts +71 -2
- package/src/persistence/schema-contract.test.ts +78 -0
- package/src/persistence/schema-contract.ts +96 -0
- package/src/persistence/steps.ts +4 -0
- package/src/platform/client.ts +55 -0
- package/src/plugins/__tests__/mcp-servers.test.ts +46 -0
- package/src/plugins/defaults/injector-order.ts +2 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +2 -2
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +13 -15
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +10 -0
- package/src/plugins/defaults/memory/injectors.ts +1 -1
- package/src/plugins/defaults/memory/memory-marker.ts +17 -7
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +1 -5
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +54 -41
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +3 -3
- package/src/plugins/defaults/memory/v3/injector.ts +14 -15
- package/src/plugins/defaults/memory/v3/types.ts +15 -4
- package/src/plugins/defaults/turn-context/injectors.ts +3 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +24 -0
- package/src/plugins/mcp-servers.ts +14 -2
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +50 -0
- package/src/providers/__tests__/registry-native-web-search.test.ts +49 -2
- package/src/providers/anthropic/client.ts +21 -24
- package/src/providers/call-site-routing.ts +5 -4
- package/src/providers/connection-resolution.ts +29 -1
- package/src/providers/content-block-size.test.ts +82 -0
- package/src/providers/content-block-size.ts +99 -0
- package/src/providers/file-block-text.test.ts +64 -0
- package/src/providers/file-block-text.ts +28 -0
- package/src/providers/gemini/client.ts +12 -7
- package/src/providers/inference/auth.ts +6 -6
- package/src/providers/media-resolve.ts +14 -0
- package/src/providers/model-catalog.ts +31 -34
- package/src/providers/openai/chat-completions-provider.ts +9 -25
- package/src/providers/openai/responses-provider.ts +11 -18
- package/src/providers/registry.ts +10 -7
- package/src/providers/routing-identity.ts +2 -1
- package/src/providers/types.ts +1 -4
- package/src/providers/vellum-model-routing.ts +3 -2
- package/src/runtime/AGENTS.md +40 -15
- package/src/runtime/approval-message-composer.ts +1 -6
- package/src/runtime/assistant-event-hub.ts +2 -39
- package/src/runtime/channel-approval-types.ts +1 -5
- package/src/runtime/channel-reply-delivery.ts +182 -115
- package/src/runtime/{slack-reply-session.test.ts → channel-reply-session.test.ts} +294 -156
- package/src/runtime/{slack-reply-session.ts → channel-reply-session.ts} +107 -86
- package/src/runtime/channel-retry-sweep.ts +102 -1
- package/src/runtime/finalize-event-delivery.ts +4 -4
- package/src/runtime/guardian-action-message-composer.ts +1 -4
- package/src/runtime/guardian-reply-router.ts +4 -75
- package/src/runtime/http-router.ts +1 -5
- package/src/runtime/question-request-guardian-bridge.ts +2 -3
- package/src/runtime/routes/__tests__/conversation-list-assistant-section.test.ts +359 -0
- package/src/runtime/routes/__tests__/dictation-command-mode.test.ts +120 -0
- package/src/runtime/routes/__tests__/sight-frame-routes.test.ts +487 -0
- package/src/runtime/routes/acp-routes.ts +1 -1
- package/src/runtime/routes/canned-reply-release.ts +19 -9
- package/src/runtime/routes/channel-route-shared.ts +0 -39
- package/src/runtime/routes/channel-verification-routes.ts +4 -1
- package/src/runtime/routes/conversation-list-routes.ts +44 -3
- package/src/runtime/routes/conversation-management-routes.ts +2 -1
- package/src/runtime/routes/conversation-routes.ts +138 -59
- package/src/runtime/routes/diagnostics-routes.ts +111 -60
- package/src/runtime/routes/guardian-action-routes.ts +10 -14
- package/src/runtime/routes/guardian-approval-interception.ts +0 -5
- package/src/runtime/routes/inbound-message-handler.ts +170 -48
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +4 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +169 -8
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +82 -14
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +23 -48
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +454 -94
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +309 -102
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/platform-routes.ts +99 -10
- package/src/runtime/routes/sight-frame-routes.ts +136 -0
- package/src/runtime/sync/resource-sync-events.ts +14 -37
- package/src/runtime/sync/sync-publisher.test.ts +5 -4
- package/src/tools/__tests__/tool-input-schemas.test.ts +2 -0
- package/src/tools/client-os.ts +11 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/terminal/safe-env.ts +4 -0
- package/src/tools/tool-input-schemas.ts +2 -0
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/ui-surface/definitions.ts +4 -3
- package/src/tools/watch/watch-retro-report.ts +205 -0
- package/src/watch/__tests__/watch-retro.test.ts +268 -40
- package/src/watch/watch-retro.ts +190 -77
- package/src/workspace/migrations/151-repair-renamed-fireworks-deepseek-pro-model-id.ts +195 -0
- package/src/workspace/migrations/152-repair-retired-fireworks-minimax-m2p7-model-id.ts +198 -0
- package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +0 -10
- package/src/workspace/migrations/registry.ts +4 -0
- package/docker-kata-pip-chroot.sh +0 -22
- package/src/__tests__/slack-reaction-approvals.test.ts +0 -97
- package/src/__tests__/slack-reaction-guardian-approval.test.ts +0 -307
- package/src/api/events/conversation-list-invalidated.ts +0 -38
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from "../../../contacts/guardian-delivery-reader.js";
|
|
20
20
|
import { isConversationBusyError } from "../../../daemon/conversation-messaging.js";
|
|
21
21
|
import type { TrustContext } from "../../../daemon/trust-context-types.js";
|
|
22
|
+
import type { ProviderMessageMetadata } from "../../../messaging/provider-message-metadata.js";
|
|
22
23
|
import {
|
|
23
24
|
channelActivityRefreshMs,
|
|
24
25
|
setChannelActivity,
|
|
@@ -27,6 +28,7 @@ import {
|
|
|
27
28
|
import {
|
|
28
29
|
getSiblingStreamedReplyTs,
|
|
29
30
|
linkMessage,
|
|
31
|
+
storeInboundChannelMetadata,
|
|
30
32
|
storeInboundSlackMetadata,
|
|
31
33
|
storeReplyMessageId,
|
|
32
34
|
storeStreamedReplyTs,
|
|
@@ -34,6 +36,7 @@ import {
|
|
|
34
36
|
import {
|
|
35
37
|
deferRetryUntilIdle,
|
|
36
38
|
isDeduplicatedDeliveryOwnedBySibling,
|
|
39
|
+
markDeliveryDelivered,
|
|
37
40
|
markProcessed,
|
|
38
41
|
recordProcessingFailure,
|
|
39
42
|
} from "../../../persistence/delivery-status.js";
|
|
@@ -45,6 +48,7 @@ import {
|
|
|
45
48
|
getApprovalInfoByConversation,
|
|
46
49
|
getChannelApprovalPrompt,
|
|
47
50
|
} from "../../channel-approvals.js";
|
|
51
|
+
import { createChannelReplySession } from "../../channel-reply-session.js";
|
|
48
52
|
import { deliverChannelReply } from "../../gateway-client.js";
|
|
49
53
|
import type {
|
|
50
54
|
ApprovalCopyGenerator,
|
|
@@ -52,7 +56,6 @@ import type {
|
|
|
52
56
|
SlackInboundMessageMetadata,
|
|
53
57
|
} from "../../http-types.js";
|
|
54
58
|
import { hasDeliverableAssistantText } from "../../no-response.js";
|
|
55
|
-
import { createSlackReplySession } from "../../slack-reply-session.js";
|
|
56
59
|
import { isContactTrustClass } from "../../trust-class.js";
|
|
57
60
|
import { resolveRoutingState } from "../../trust-context-resolver.js";
|
|
58
61
|
import { finalizeEventDelivery } from "../channel-delivery-routes.js";
|
|
@@ -110,6 +113,30 @@ export interface BackgroundProcessingParams {
|
|
|
110
113
|
* `slackMeta` envelope for the chronological renderer.
|
|
111
114
|
*/
|
|
112
115
|
slackInbound?: SlackInboundMessageMetadata;
|
|
116
|
+
/**
|
|
117
|
+
* Neutral per-row channel envelope for non-Slack channels, the counterpart
|
|
118
|
+
* of `slackInbound`: threaded through to `persistUserMessage` so the row
|
|
119
|
+
* is tagged with `providerMeta` and can say which external message it is.
|
|
120
|
+
* A reaction-driven wake turn rides the same lane with its reaction
|
|
121
|
+
* envelope, so the turn's own persisted row IS the reaction row.
|
|
122
|
+
*/
|
|
123
|
+
channelInbound?: ProviderMessageMetadata;
|
|
124
|
+
/** See `ProcessMessageOptions.slackReactionRowMeta`. TRANSITIONAL. */
|
|
125
|
+
slackReactionRowMeta?: string;
|
|
126
|
+
/** Explicit idempotency key for this turn's persisted row. */
|
|
127
|
+
clientMessageId?: string;
|
|
128
|
+
/** Persist the triggering row without indexing it. */
|
|
129
|
+
skipUserMessageIndexing?: boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Called when the turn could not run because a non-channel turn re-took
|
|
132
|
+
* the processing lock after admission. When present it REPLACES the
|
|
133
|
+
* retry-sweep deferral: that lane rebuilds a turn from its stored payload
|
|
134
|
+
* as a plain message, so a caller whose event stores nothing a turn can be
|
|
135
|
+
* rebuilt from (a reaction wake, whose payload is delivery-only) degrades
|
|
136
|
+
* through this hook instead, e.g. by persisting the passive row the turn
|
|
137
|
+
* would have created.
|
|
138
|
+
*/
|
|
139
|
+
onTurnLostToBusy?: () => Promise<void>;
|
|
113
140
|
}
|
|
114
141
|
|
|
115
142
|
/**
|
|
@@ -141,16 +168,26 @@ export function processChannelMessageInBackground(
|
|
|
141
168
|
clientTimezone,
|
|
142
169
|
slackBotMentioned,
|
|
143
170
|
slackInbound,
|
|
171
|
+
channelInbound,
|
|
172
|
+
slackReactionRowMeta,
|
|
173
|
+
clientMessageId,
|
|
174
|
+
skipUserMessageIndexing,
|
|
175
|
+
onTurnLostToBusy,
|
|
144
176
|
} = params;
|
|
145
177
|
|
|
146
|
-
// Capture the
|
|
147
|
-
// the admission wait or any processing
|
|
148
|
-
// mid-turn, the retry sweep replays with the SAME
|
|
149
|
-
// used.
|
|
150
|
-
// against a turn this attempt already persisted) and
|
|
178
|
+
// Capture the channel ingress metadata onto the stored payload up front,
|
|
179
|
+
// before the admission wait or any processing, so if the daemon dies
|
|
180
|
+
// mid-wait or mid-turn, the retry sweep replays with the SAME envelope this
|
|
181
|
+
// turn used. For Slack that keeps the derived idempotency key identical
|
|
182
|
+
// (the replay dedups against a turn this attempt already persisted) and
|
|
183
|
+
// carries full slackMeta; for every other channel it carries the same
|
|
184
|
+
// `providerMeta` onto the replayed row.
|
|
151
185
|
if (slackInbound) {
|
|
152
186
|
storeInboundSlackMetadata(eventId, slackInbound);
|
|
153
187
|
}
|
|
188
|
+
if (channelInbound) {
|
|
189
|
+
storeInboundChannelMetadata(eventId, channelInbound);
|
|
190
|
+
}
|
|
154
191
|
|
|
155
192
|
// Defer the whole turn + delivery until the conversation's processing lock is
|
|
156
193
|
// free, serialized per conversation so same-conversation replies stay ordered.
|
|
@@ -210,9 +247,7 @@ export function processChannelMessageInBackground(
|
|
|
210
247
|
}
|
|
211
248
|
: undefined;
|
|
212
249
|
let replyMessageId: string | undefined;
|
|
213
|
-
const
|
|
214
|
-
sourceChannel,
|
|
215
|
-
chatType,
|
|
250
|
+
const replySession = createChannelReplySession({
|
|
216
251
|
replyCallbackUrl,
|
|
217
252
|
chatId: externalChatId,
|
|
218
253
|
recipientUserId: slackInbound?.actorExternalUserId,
|
|
@@ -230,7 +265,7 @@ export function processChannelMessageInBackground(
|
|
|
230
265
|
) {
|
|
231
266
|
replyMessageId = msg.messageId;
|
|
232
267
|
}
|
|
233
|
-
|
|
268
|
+
replySession?.observeEvent(msg);
|
|
234
269
|
channelActivity?.observeEvent(msg);
|
|
235
270
|
};
|
|
236
271
|
|
|
@@ -252,6 +287,10 @@ export function processChannelMessageInBackground(
|
|
|
252
287
|
...(displayContent !== undefined ? { displayContent } : {}),
|
|
253
288
|
...(cmdIntent ? { commandIntent: cmdIntent } : {}),
|
|
254
289
|
...(slackInbound ? { slackInbound } : {}),
|
|
290
|
+
...(channelInbound ? { channelInbound } : {}),
|
|
291
|
+
...(slackReactionRowMeta ? { slackReactionRowMeta } : {}),
|
|
292
|
+
...(clientMessageId ? { clientMessageId } : {}),
|
|
293
|
+
...(skipUserMessageIndexing ? { skipUserMessageIndexing } : {}),
|
|
255
294
|
onEvent: observeAgentEvent,
|
|
256
295
|
sourceChannel,
|
|
257
296
|
sourceInterface,
|
|
@@ -259,22 +298,40 @@ export function processChannelMessageInBackground(
|
|
|
259
298
|
userMessageId = result.messageId;
|
|
260
299
|
deduplicatedIngress = result.deduplicated === true;
|
|
261
300
|
linkMessage(eventId, userMessageId);
|
|
262
|
-
|
|
301
|
+
// Record the reply row BEFORE marking the event processed. Stranded
|
|
302
|
+
// delivery recovery treats `processed` as the point an event becomes
|
|
303
|
+
// eligible and reads the reply id from the stored payload, so an
|
|
304
|
+
// event that becomes eligible first would be skipped by that step
|
|
305
|
+
// and never deliver. Crashing between these two leaves the row
|
|
306
|
+
// `pending` instead, which the orphan step already recovers.
|
|
263
307
|
replyMessageId ??= result.assistantMessageId;
|
|
264
308
|
if (replyMessageId) {
|
|
265
309
|
storeReplyMessageId(eventId, replyMessageId);
|
|
266
310
|
}
|
|
311
|
+
markProcessed(eventId);
|
|
267
312
|
} catch (err) {
|
|
268
313
|
// Stop any live Slack stream cleanly. Its `ts` is already durably
|
|
269
314
|
// recorded via `onStreamOpen`, so the retry sweep can reconcile
|
|
270
315
|
// against that message rather than posting a duplicate.
|
|
271
|
-
await
|
|
316
|
+
await replySession?.finish();
|
|
272
317
|
if (isConversationBusyError(err)) {
|
|
318
|
+
if (onTurnLostToBusy) {
|
|
319
|
+
// The sweep's processing lane cannot rebuild this turn (see the
|
|
320
|
+
// hook's doc), so the caller degrades in its own way instead.
|
|
321
|
+
// Nothing was persisted: the busy error is thrown before the
|
|
322
|
+
// row insert.
|
|
323
|
+
log.info(
|
|
324
|
+
{ conversationId, eventId },
|
|
325
|
+
"Channel turn lost the processing lock after admission; degrading via caller fallback",
|
|
326
|
+
);
|
|
327
|
+
await onTurnLostToBusy();
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
273
330
|
// Admission observed the conversation idle, but a non-channel turn
|
|
274
331
|
// (web / wake / voice) re-took the processing lock before this turn
|
|
275
332
|
// could. Re-schedule for the retry sweep without burning a retry
|
|
276
333
|
// attempt (`deferRetryUntilIdle`) so it reprocesses and delivers from
|
|
277
|
-
// the stored payload once the lock frees
|
|
334
|
+
// the stored payload once the lock frees: a plain processing-failure
|
|
278
335
|
// record would classify the busy message as fatal and dead-letter it
|
|
279
336
|
// (a silent drop), and even a retryable one could exhaust the budget
|
|
280
337
|
// under sustained contention.
|
|
@@ -289,6 +346,13 @@ export function processChannelMessageInBackground(
|
|
|
289
346
|
{ err, conversationId },
|
|
290
347
|
"Background channel message processing failed",
|
|
291
348
|
);
|
|
349
|
+
if (onTurnLostToBusy) {
|
|
350
|
+
// A caller that opted out of sweep replay has no retry lane at
|
|
351
|
+
// all: its event is already marked processed, so a failure record
|
|
352
|
+
// would only feed the sweep an event it cannot rebuild. The
|
|
353
|
+
// best-effort turn is simply lost.
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
292
356
|
recordProcessingFailure(eventId, err);
|
|
293
357
|
return;
|
|
294
358
|
}
|
|
@@ -330,6 +394,10 @@ export function processChannelMessageInBackground(
|
|
|
330
394
|
{ conversationId, eventId },
|
|
331
395
|
"Skipping channel reply delivery for deduplicated ingress event; a prior attempt owns delivery",
|
|
332
396
|
);
|
|
397
|
+
// The sibling owns delivery, so settle this row rather than leaving it
|
|
398
|
+
// `pending`, which stranded-delivery recovery reads as delivery still
|
|
399
|
+
// owed and would act on after a restart.
|
|
400
|
+
markDeliveryDelivered(eventId);
|
|
333
401
|
} else if (replyCallbackUrl) {
|
|
334
402
|
try {
|
|
335
403
|
await finalizeEventDelivery({
|
|
@@ -340,7 +408,7 @@ export function processChannelMessageInBackground(
|
|
|
340
408
|
assistantId,
|
|
341
409
|
replyMessageId,
|
|
342
410
|
userMessageId,
|
|
343
|
-
|
|
411
|
+
replySession,
|
|
344
412
|
...(recoveredStreamMessageTs
|
|
345
413
|
? { priorStreamMessageTs: recoveredStreamMessageTs }
|
|
346
414
|
: {}),
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
* Extracted from inbound-message-handler.ts to keep the top-level handler
|
|
10
10
|
* focused on orchestration.
|
|
11
11
|
*/
|
|
12
|
-
import type { InboundReactionPayload } from "@vellumai/gateway-client";
|
|
13
12
|
|
|
14
13
|
import {
|
|
15
14
|
listGuardianRequestsOrEmpty,
|
|
@@ -37,22 +36,11 @@ export interface GuardianReplyInterceptParams {
|
|
|
37
36
|
trimmedContent: string;
|
|
38
37
|
hasCallbackData: boolean;
|
|
39
38
|
callbackData: string | undefined;
|
|
40
|
-
reaction?: InboundReactionPayload;
|
|
41
|
-
/**
|
|
42
|
-
* For emoji-reaction decisions: the channel-native id (Slack `ts`) of the
|
|
43
|
-
* message the reaction was attached to. Threaded to the router so it can
|
|
44
|
-
* recover the target request from the reacted card's delivery record.
|
|
45
|
-
*/
|
|
46
|
-
reactedMessageTs?: string;
|
|
47
39
|
rawSenderId: string | undefined;
|
|
48
40
|
canonicalSenderId: string | null;
|
|
49
41
|
sourceChannel: ChannelId;
|
|
50
42
|
conversationExternalId: string;
|
|
51
|
-
/**
|
|
52
|
-
* Conversation the message arrived in. Reactions resolve their target by the
|
|
53
|
-
* reacted card's own address and are routed before any conversation is
|
|
54
|
-
* known, so they pass none.
|
|
55
|
-
*/
|
|
43
|
+
/** Conversation the message arrived in. */
|
|
56
44
|
conversationId?: string;
|
|
57
45
|
/** Inbound event id, echoed on the consumed response when the caller has one. */
|
|
58
46
|
eventId?: string;
|
|
@@ -84,8 +72,6 @@ export async function handleGuardianReplyIntercept(
|
|
|
84
72
|
trimmedContent,
|
|
85
73
|
hasCallbackData,
|
|
86
74
|
callbackData,
|
|
87
|
-
reaction,
|
|
88
|
-
reactedMessageTs,
|
|
89
75
|
rawSenderId,
|
|
90
76
|
canonicalSenderId,
|
|
91
77
|
sourceChannel,
|
|
@@ -137,43 +123,34 @@ export async function handleGuardianReplyIntercept(
|
|
|
137
123
|
// guardian can reply before the row is persisted. Cross-chat
|
|
138
124
|
// contamination is unlikely there because each chat is a distinct
|
|
139
125
|
// conversation with no thread concept.
|
|
140
|
-
// Reactions address one specific request by the reacted card's message id,
|
|
141
|
-
// so they bypass the pending-request list scoping that the text/NL paths
|
|
142
|
-
// need — the router's reaction branch resolves the target directly.
|
|
143
|
-
const isReaction = reaction !== undefined;
|
|
144
126
|
let pendingScope: GuardianPendingScope | undefined;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
});
|
|
163
|
-
for (const r of identityPending) {
|
|
164
|
-
deliveryIds.add(r.id);
|
|
165
|
-
}
|
|
166
|
-
pendingScope = { mode: "scoped", requestIds: [...deliveryIds] };
|
|
167
|
-
} else if (sourceChannel === "slack") {
|
|
168
|
-
// Block identity-based fallback on Slack to prevent cross-chat
|
|
169
|
-
// NL/free-text interception. See comment above for rationale.
|
|
170
|
-
pendingScope = { mode: "blocked" };
|
|
127
|
+
// Hint reads degrade to empty on gateway failure: Slack then blocks the
|
|
128
|
+
// identity fallback (safe), other channels keep it (unchanged posture).
|
|
129
|
+
const deliveryScopedPendingRequests =
|
|
130
|
+
await listPendingRequestsByDestinationOrEmpty({
|
|
131
|
+
channel: sourceChannel,
|
|
132
|
+
chatId: conversationExternalId,
|
|
133
|
+
});
|
|
134
|
+
if (deliveryScopedPendingRequests.length > 0) {
|
|
135
|
+
const deliveryIds = new Set(deliveryScopedPendingRequests.map((r) => r.id));
|
|
136
|
+
// Also include identity-based pending requests so we don't hide them
|
|
137
|
+
const identityId = canonicalSenderId ?? rawSenderId!;
|
|
138
|
+
const identityPending = await listGuardianRequestsOrEmpty({
|
|
139
|
+
status: "pending",
|
|
140
|
+
guardianExternalUserId: identityId,
|
|
141
|
+
});
|
|
142
|
+
for (const r of identityPending) {
|
|
143
|
+
deliveryIds.add(r.id);
|
|
171
144
|
}
|
|
145
|
+
pendingScope = { mode: "scoped", requestIds: [...deliveryIds] };
|
|
146
|
+
} else if (sourceChannel === "slack") {
|
|
147
|
+
// Block identity-based fallback on Slack to prevent cross-chat
|
|
148
|
+
// NL/free-text interception. See comment above for rationale.
|
|
149
|
+
pendingScope = { mode: "blocked" };
|
|
172
150
|
}
|
|
173
151
|
|
|
174
152
|
const routerResult = await routeGuardianReply({
|
|
175
153
|
messageText: trimmedContent,
|
|
176
|
-
channel: sourceChannel,
|
|
177
154
|
actor: {
|
|
178
155
|
actorPrincipalId: guardianPrincipalId ?? undefined,
|
|
179
156
|
actorExternalUserId: canonicalSenderId ?? rawSenderId!,
|
|
@@ -182,8 +159,6 @@ export async function handleGuardianReplyIntercept(
|
|
|
182
159
|
},
|
|
183
160
|
conversationId,
|
|
184
161
|
callbackData,
|
|
185
|
-
...(reaction ? { reaction } : {}),
|
|
186
|
-
reactedMessageTs,
|
|
187
162
|
pendingScope,
|
|
188
163
|
approvalConversationGenerator,
|
|
189
164
|
channelDeliveryContext: {
|