@vellumai/assistant 0.4.48 → 0.4.50
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 +26 -35
- package/README.md +5 -26
- package/docs/architecture/integrations.md +45 -41
- package/docs/architecture/keychain-broker.md +3 -3
- package/docs/architecture/memory.md +180 -119
- package/docs/runbook-trusted-contacts.md +3 -8
- package/hook-templates/debug-prompt-logger/hook.json +1 -1
- package/hook-templates/debug-prompt-logger/run.sh +1 -3
- package/package.json +2 -2
- package/src/__tests__/actor-token-service.test.ts +0 -1
- package/src/__tests__/agent-loop.test.ts +3 -1
- package/src/__tests__/anthropic-provider.test.ts +249 -2
- package/src/__tests__/approval-cascade.test.ts +796 -0
- package/src/__tests__/approval-primitive.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +4 -0
- package/src/__tests__/assistant-attachments.test.ts +12 -34
- package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/canonical-guardian-store.test.ts +95 -0
- package/src/__tests__/channel-guardian.test.ts +0 -2
- package/src/__tests__/channel-readiness-routes.test.ts +15 -6
- package/src/__tests__/channel-readiness-service.test.ts +10 -9
- package/src/__tests__/checker.test.ts +13 -20
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-tools.test.ts +2 -19
- package/src/__tests__/config-schema.test.ts +1 -68
- package/src/__tests__/config-watcher.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-image-dimensions.test.ts +332 -0
- package/src/__tests__/context-memory-e2e.test.ts +11 -100
- package/src/__tests__/context-token-estimator.test.ts +196 -13
- package/src/__tests__/conversation-attention-store.test.ts +0 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +152 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
- package/src/__tests__/credential-metadata-store.test.ts +64 -73
- package/src/__tests__/credential-security-e2e.test.ts +1 -0
- package/src/__tests__/credential-security-invariants.test.ts +13 -7
- package/src/__tests__/credential-vault-unit.test.ts +284 -49
- package/src/__tests__/credential-vault.test.ts +150 -16
- package/src/__tests__/credentials-cli.test.ts +71 -0
- package/src/__tests__/cu-unified-flow.test.ts +532 -0
- package/src/__tests__/date-context.test.ts +93 -77
- package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
- package/src/__tests__/heartbeat-service.test.ts +0 -1
- package/src/__tests__/history-repair.test.ts +245 -0
- package/src/__tests__/host-cu-proxy.test.ts +791 -0
- package/src/__tests__/host-shell-tool.test.ts +27 -15
- package/src/__tests__/http-user-message-parity.test.ts +2 -0
- package/src/__tests__/ingress-url-consistency.test.ts +14 -21
- package/src/__tests__/integration-status.test.ts +32 -51
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/invite-redemption-service.test.ts +65 -1
- package/src/__tests__/invite-routes-http.test.ts +10 -9
- package/src/__tests__/keychain-broker-client.test.ts +14 -46
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
- package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
- package/src/__tests__/memory-recall-quality.test.ts +244 -407
- package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
- package/src/__tests__/memory-regressions.test.ts +477 -2841
- package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
- package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
- package/src/__tests__/mime-builder.test.ts +28 -0
- package/src/__tests__/native-web-search.test.ts +1 -0
- package/src/__tests__/notification-routing-intent.test.ts +0 -1
- package/src/__tests__/oauth-cli.test.ts +941 -15
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
- package/src/__tests__/oauth-scope-policy.test.ts +4 -6
- package/src/__tests__/oauth-store.test.ts +870 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
- package/src/__tests__/provider-error-scenarios.test.ts +0 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +15 -21
- package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
- package/src/__tests__/recording-handler.test.ts +3 -4
- package/src/__tests__/registry.test.ts +2 -3
- package/src/__tests__/relay-server.test.ts +46 -1
- package/src/__tests__/runtime-events-sse.test.ts +55 -7
- package/src/__tests__/schedule-store.test.ts +0 -1
- package/src/__tests__/schedule-tools.test.ts +32 -0
- package/src/__tests__/scheduler-recurrence.test.ts +0 -1
- package/src/__tests__/scoped-approval-grants.test.ts +0 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/secret-ingress-handler.test.ts +0 -1
- package/src/__tests__/secret-onetime-send.test.ts +1 -0
- package/src/__tests__/secure-keys.test.ts +7 -2
- package/src/__tests__/send-endpoint-busy.test.ts +24 -6
- package/src/__tests__/sequence-store.test.ts +0 -1
- package/src/__tests__/session-abort-tool-results.test.ts +1 -14
- package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
- package/src/__tests__/session-agent-loop.test.ts +19 -15
- package/src/__tests__/session-confirmation-signals.test.ts +1 -15
- package/src/__tests__/session-error.test.ts +124 -2
- package/src/__tests__/session-history-web-search.test.ts +918 -0
- package/src/__tests__/session-init.benchmark.test.ts +4 -5
- package/src/__tests__/session-pre-run-repair.test.ts +1 -14
- package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
- package/src/__tests__/session-queue.test.ts +37 -27
- package/src/__tests__/session-runtime-assembly.test.ts +54 -0
- package/src/__tests__/session-slash-known.test.ts +1 -15
- package/src/__tests__/session-slash-queue.test.ts +1 -15
- package/src/__tests__/session-slash-unknown.test.ts +1 -15
- package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
- package/src/__tests__/session-workspace-injection.test.ts +3 -37
- package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
- package/src/__tests__/skill-include-graph.test.ts +66 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
- package/src/__tests__/skill-load-tool.test.ts +149 -1
- package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
- package/src/__tests__/skills-install-extract.test.ts +93 -0
- package/src/__tests__/skills-uninstall.test.ts +1 -1
- package/src/__tests__/skills.test.ts +3 -3
- package/src/__tests__/skillssh-registry.test.ts +451 -0
- package/src/__tests__/slack-channel-config.test.ts +67 -3
- package/src/__tests__/slack-share-routes.test.ts +17 -19
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
- package/src/__tests__/terminal-tools.test.ts +4 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
- package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
- package/src/__tests__/trust-store.test.ts +7 -13
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +0 -16
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
- package/src/__tests__/voice-invite-redemption.test.ts +32 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/agent/ax-tree-compaction.test.ts +286 -0
- package/src/agent/loop.ts +104 -131
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/guardian-request-resolvers.ts +14 -2
- package/src/bundler/compiler-tools.ts +66 -2
- package/src/calls/call-domain.ts +133 -6
- package/src/calls/call-store.ts +6 -0
- package/src/calls/relay-server.ts +52 -18
- package/src/calls/relay-setup-router.ts +17 -1
- package/src/calls/twilio-config.ts +3 -8
- package/src/calls/twilio-routes.ts +1 -2
- package/src/calls/types.ts +3 -1
- package/src/calls/voice-ingress-preflight.ts +1 -1
- package/src/cli/commands/browser-relay.ts +18 -12
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/credentials.ts +101 -15
- package/src/cli/commands/doctor.ts +4 -3
- package/src/cli/commands/mcp.ts +46 -59
- package/src/cli/commands/memory.ts +16 -165
- package/src/cli/commands/oauth/apps.ts +284 -0
- package/src/cli/commands/oauth/connections.ts +633 -0
- package/src/cli/commands/oauth/index.ts +52 -0
- package/src/cli/commands/oauth/providers.ts +256 -0
- package/src/cli/commands/sessions.ts +5 -2
- package/src/cli/commands/skills.ts +177 -339
- package/src/cli/http-client.ts +0 -20
- package/src/cli/main-screen.tsx +2 -2
- package/src/cli/program.ts +6 -11
- package/src/cli/reference.ts +1 -3
- package/src/cli.ts +4 -10
- package/src/config/assistant-feature-flags.ts +0 -3
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +23 -5
- package/src/config/bundled-skills/computer-use/tools/{computer-use-request-control.ts → computer-use-observe.ts} +1 -5
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +21 -16
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -4
- package/src/config/bundled-skills/settings/SKILL.md +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +2 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
- package/src/config/bundled-tool-registry.ts +2 -5
- package/src/config/env-registry.ts +14 -83
- package/src/config/env.ts +11 -50
- package/src/config/feature-flag-registry.json +16 -16
- package/src/config/loader.ts +0 -6
- package/src/config/schema.ts +4 -13
- package/src/config/schemas/memory-lifecycle.ts +0 -9
- package/src/config/schemas/memory-processing.ts +0 -180
- package/src/config/schemas/memory-retrieval.ts +32 -104
- package/src/config/schemas/memory.ts +0 -10
- package/src/config/skills.ts +21 -2
- package/src/config/types.ts +0 -4
- package/src/context/image-dimensions.ts +229 -0
- package/src/context/token-estimator.ts +75 -12
- package/src/context/window-manager.ts +53 -11
- package/src/daemon/assistant-attachments.ts +1 -13
- package/src/daemon/config-watcher.ts +61 -3
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +114 -31
- package/src/daemon/handlers/config-ingress.ts +8 -33
- package/src/daemon/handlers/config-slack-channel.ts +49 -46
- package/src/daemon/handlers/config-telegram.ts +32 -16
- package/src/daemon/handlers/sessions.ts +27 -36
- package/src/daemon/handlers/shared.ts +0 -130
- package/src/daemon/handlers/skills.ts +20 -1
- package/src/daemon/history-repair.ts +72 -8
- package/src/daemon/host-cu-proxy.ts +430 -0
- package/src/daemon/lifecycle.ts +67 -71
- package/src/daemon/mcp-reload-service.ts +2 -2
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/computer-use.ts +1 -129
- package/src/daemon/message-types/host-cu.ts +19 -0
- package/src/daemon/message-types/memory.ts +4 -16
- package/src/daemon/message-types/messages.ts +4 -0
- package/src/daemon/message-types/sessions.ts +4 -0
- package/src/daemon/server.ts +25 -21
- package/src/daemon/session-agent-loop-handlers.ts +40 -0
- package/src/daemon/session-agent-loop.ts +334 -48
- package/src/daemon/session-attachments.ts +1 -2
- package/src/daemon/session-error.ts +89 -6
- package/src/daemon/session-history.ts +17 -7
- package/src/daemon/session-media-retry.ts +6 -2
- package/src/daemon/session-memory.ts +69 -149
- package/src/daemon/session-process.ts +10 -1
- package/src/daemon/session-runtime-assembly.ts +49 -19
- package/src/daemon/session-slash.ts +1 -1
- package/src/daemon/session-surfaces.ts +43 -28
- package/src/daemon/session-tool-setup.ts +9 -10
- package/src/daemon/session.ts +150 -17
- package/src/daemon/tool-side-effects.ts +2 -8
- package/src/daemon/watch-handler.ts +2 -2
- package/src/events/tool-metrics-listener.ts +2 -2
- package/src/hooks/manager.ts +1 -4
- package/src/inbound/public-ingress-urls.ts +7 -7
- package/src/instrument.ts +61 -1
- package/src/logfire.ts +16 -5
- package/src/memory/admin.ts +2 -191
- package/src/memory/canonical-guardian-store.ts +38 -2
- package/src/memory/conversation-crud.ts +0 -33
- package/src/memory/conversation-key-store.ts +21 -0
- package/src/memory/conversation-queries.ts +22 -3
- package/src/memory/db-init.ts +32 -0
- package/src/memory/embedding-backend.ts +84 -8
- package/src/memory/embedding-types.ts +9 -1
- package/src/memory/indexer.ts +7 -46
- package/src/memory/items-extractor.ts +274 -76
- package/src/memory/job-handlers/backfill.ts +2 -127
- package/src/memory/job-handlers/cleanup.ts +2 -16
- package/src/memory/job-handlers/extraction.ts +2 -138
- package/src/memory/job-handlers/index-maintenance.ts +1 -6
- package/src/memory/job-handlers/summarization.ts +3 -148
- package/src/memory/job-utils.ts +21 -59
- package/src/memory/jobs-store.ts +1 -159
- package/src/memory/jobs-worker.ts +9 -52
- package/src/memory/migrations/104-core-indexes.ts +3 -3
- package/src/memory/migrations/149-oauth-tables.ts +62 -0
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
- package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
- package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
- package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
- package/src/memory/migrations/154-drop-fts.ts +20 -0
- package/src/memory/migrations/155-drop-conflicts.ts +7 -0
- package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
- package/src/memory/migrations/index.ts +8 -0
- package/src/memory/qdrant-client.ts +148 -51
- package/src/memory/raw-query.ts +1 -1
- package/src/memory/retriever.test.ts +294 -273
- package/src/memory/retriever.ts +421 -645
- package/src/memory/schema/calls.ts +2 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/memory-core.ts +3 -48
- package/src/memory/schema/oauth.ts +67 -0
- package/src/memory/search/formatting.ts +263 -176
- package/src/memory/search/lexical.ts +1 -254
- package/src/memory/search/ranking.ts +0 -455
- package/src/memory/search/semantic.ts +100 -14
- package/src/memory/search/staleness.ts +47 -0
- package/src/memory/search/tier-classifier.ts +21 -0
- package/src/memory/search/types.ts +15 -77
- package/src/memory/task-memory-cleanup.ts +4 -6
- package/src/messaging/provider.ts +4 -4
- package/src/messaging/providers/gmail/client.ts +82 -2
- package/src/messaging/providers/gmail/mime-builder.ts +17 -7
- package/src/messaging/providers/gmail/people-client.ts +10 -10
- package/src/messaging/providers/telegram-bot/adapter.ts +17 -17
- package/src/messaging/providers/whatsapp/adapter.ts +11 -8
- package/src/messaging/registry.ts +2 -32
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/signal.ts +4 -5
- package/src/oauth/byo-connection.test.ts +133 -25
- package/src/oauth/byo-connection.ts +22 -6
- package/src/oauth/connect-orchestrator.ts +113 -57
- package/src/oauth/connect-types.ts +17 -23
- package/src/oauth/connection-resolver.ts +35 -11
- package/src/oauth/connection.ts +1 -1
- package/src/oauth/manual-token-connection.ts +104 -0
- package/src/oauth/oauth-store.ts +582 -0
- package/src/oauth/platform-connection.test.ts +29 -0
- package/src/oauth/platform-connection.ts +6 -5
- package/src/oauth/provider-behaviors.ts +124 -0
- package/src/oauth/scope-policy.ts +9 -2
- package/src/oauth/seed-providers.ts +167 -0
- package/src/oauth/token-persistence.ts +81 -77
- package/src/permissions/checker.ts +3 -3
- package/src/permissions/defaults.ts +1 -1
- package/src/permissions/prompter.ts +10 -1
- package/src/permissions/trust-store.ts +36 -1
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
- package/src/prompts/system-prompt.ts +46 -42
- package/src/providers/anthropic/client.ts +59 -20
- package/src/providers/retry.ts +1 -27
- package/src/providers/types.ts +7 -1
- package/src/runtime/AGENTS.md +9 -0
- package/src/runtime/auth/route-policy.ts +6 -6
- package/src/runtime/channel-reply-delivery.ts +0 -40
- package/src/runtime/gateway-client.ts +0 -7
- package/src/runtime/guardian-reply-router.ts +24 -22
- package/src/runtime/http-server.ts +10 -8
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/invite-redemption-service.ts +19 -1
- package/src/runtime/invite-service.ts +25 -0
- package/src/runtime/middleware/twilio-validation.ts +1 -11
- package/src/runtime/pending-interactions.ts +14 -12
- package/src/runtime/routes/brain-graph-routes.ts +10 -90
- package/src/runtime/routes/channel-delivery-routes.ts +0 -1
- package/src/runtime/routes/conversation-routes.ts +81 -19
- package/src/runtime/routes/events-routes.ts +21 -11
- package/src/runtime/routes/host-cu-routes.ts +97 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
- package/src/runtime/routes/integrations/slack/share.ts +6 -7
- package/src/runtime/routes/log-export-routes.ts +126 -8
- package/src/runtime/routes/memory-item-routes.test.ts +754 -0
- package/src/runtime/routes/memory-item-routes.ts +503 -0
- package/src/runtime/routes/session-management-routes.ts +3 -3
- package/src/runtime/routes/settings-routes.ts +55 -48
- package/src/runtime/routes/surface-action-routes.ts +1 -1
- package/src/runtime/routes/trust-rules-routes.ts +14 -0
- package/src/runtime/routes/watch-routes.ts +128 -0
- package/src/runtime/routes/workspace-routes.ts +2 -1
- package/src/schedule/integration-status.ts +10 -9
- package/src/security/credential-key.ts +0 -156
- package/src/security/keychain-broker-client.ts +22 -10
- package/src/security/oauth2.ts +1 -1
- package/src/security/secure-keys.ts +25 -3
- package/src/security/token-manager.ts +137 -64
- package/src/skills/catalog-install.ts +414 -0
- package/src/skills/include-graph.ts +32 -0
- package/src/skills/skillssh-registry.ts +503 -0
- package/src/telegram/bot-username.ts +2 -3
- package/src/tools/assets/search.ts +5 -1
- package/src/tools/browser/network-recorder.ts +1 -1
- package/src/tools/browser/network-recording-types.ts +1 -1
- package/src/tools/computer-use/definitions.ts +36 -11
- package/src/tools/computer-use/registry.ts +5 -6
- package/src/tools/credentials/broker.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +17 -121
- package/src/tools/credentials/vault.ts +92 -167
- package/src/tools/memory/definitions.ts +4 -13
- package/src/tools/memory/handlers.test.ts +83 -103
- package/src/tools/memory/handlers.ts +50 -85
- package/src/tools/registry.ts +2 -7
- package/src/tools/schedule/create.ts +8 -1
- package/src/tools/schedule/update.ts +8 -1
- package/src/tools/skills/load.ts +85 -3
- package/src/tools/watch/watch-state.ts +0 -12
- package/src/util/logger.ts +7 -41
- package/src/util/platform.ts +9 -28
- package/src/watcher/providers/google-calendar.ts +2 -1
- package/src/__tests__/clarification-resolver.test.ts +0 -193
- package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
- package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
- package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
- package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
- package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
- package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
- package/src/__tests__/conflict-policy.test.ts +0 -269
- package/src/__tests__/conflict-store.test.ts +0 -372
- package/src/__tests__/contradiction-checker.test.ts +0 -361
- package/src/__tests__/entity-extractor.test.ts +0 -211
- package/src/__tests__/entity-search.test.ts +0 -1117
- package/src/__tests__/profile-compiler.test.ts +0 -392
- package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
- package/src/__tests__/session-conflict-gate.test.ts +0 -1228
- package/src/__tests__/session-profile-injection.test.ts +0 -557
- package/src/cli/commands/dev.ts +0 -129
- package/src/cli/commands/map.ts +0 -391
- package/src/cli/commands/oauth.ts +0 -77
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
- package/src/daemon/computer-use-session.ts +0 -1026
- package/src/daemon/ride-shotgun-handler.ts +0 -569
- package/src/daemon/session-conflict-gate.ts +0 -167
- package/src/daemon/session-dynamic-profile.ts +0 -77
- package/src/memory/clarification-resolver.ts +0 -417
- package/src/memory/conflict-intent.ts +0 -205
- package/src/memory/conflict-policy.ts +0 -127
- package/src/memory/conflict-store.ts +0 -410
- package/src/memory/contradiction-checker.ts +0 -508
- package/src/memory/entity-extractor.ts +0 -535
- package/src/memory/format-recall.ts +0 -47
- package/src/memory/fts-reconciler.ts +0 -165
- package/src/memory/job-handlers/conflict.ts +0 -200
- package/src/memory/profile-compiler.ts +0 -195
- package/src/memory/recall-cache.ts +0 -117
- package/src/memory/search/entity.ts +0 -535
- package/src/memory/search/query-expansion.test.ts +0 -70
- package/src/memory/search/query-expansion.ts +0 -118
- package/src/oauth/provider-base-urls.ts +0 -21
- package/src/oauth/provider-profiles.ts +0 -192
- package/src/prompts/computer-use-prompt.ts +0 -98
- package/src/runtime/routes/computer-use-routes.ts +0 -641
- package/src/runtime/routes/mcp-routes.ts +0 -20
- package/src/runtime/telegram-streaming-delivery.test.ts +0 -729
- package/src/runtime/telegram-streaming-delivery.ts +0 -393
- package/src/tools/computer-use/request-computer-control.ts +0 -56
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import { getConfig } from "../../config/loader.js";
|
|
18
18
|
import { renderHistoryContent } from "../../daemon/handlers/shared.js";
|
|
19
19
|
import { HostBashProxy } from "../../daemon/host-bash-proxy.js";
|
|
20
|
+
import { HostCuProxy } from "../../daemon/host-cu-proxy.js";
|
|
20
21
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
21
22
|
import type { ServerMessage } from "../../daemon/message-protocol.js";
|
|
22
23
|
import {
|
|
@@ -449,6 +450,12 @@ function makeHubPublisher(
|
|
|
449
450
|
conversationId,
|
|
450
451
|
kind: "host_file",
|
|
451
452
|
});
|
|
453
|
+
} else if (msg.type === "host_cu_request") {
|
|
454
|
+
pendingInteractions.register(msg.requestId, {
|
|
455
|
+
session,
|
|
456
|
+
conversationId,
|
|
457
|
+
kind: "host_cu",
|
|
458
|
+
});
|
|
452
459
|
}
|
|
453
460
|
|
|
454
461
|
// ServerMessage is a large union; sessionId exists on most but not all variants.
|
|
@@ -640,9 +647,22 @@ export async function handleSendMessage(
|
|
|
640
647
|
});
|
|
641
648
|
session.setHostFileProxy(fileProxy);
|
|
642
649
|
}
|
|
650
|
+
if (!session.isProcessing() || !session.hostCuProxy) {
|
|
651
|
+
const cuProxy = new HostCuProxy(onEvent, (requestId) => {
|
|
652
|
+
pendingInteractions.resolve(requestId);
|
|
653
|
+
});
|
|
654
|
+
session.setHostCuProxy(cuProxy);
|
|
655
|
+
}
|
|
656
|
+
// Only preactivate CU when the session is idle — if the session is
|
|
657
|
+
// processing, this message will be queued and preactivation is deferred
|
|
658
|
+
// to dequeue time in drainQueueImpl to avoid mutating in-flight turn state.
|
|
659
|
+
if (!session.isProcessing()) {
|
|
660
|
+
session.addPreactivatedSkillId("computer-use");
|
|
661
|
+
}
|
|
643
662
|
} else if (!session.isProcessing()) {
|
|
644
663
|
session.setHostBashProxy(undefined);
|
|
645
664
|
session.setHostFileProxy(undefined);
|
|
665
|
+
session.setHostCuProxy(undefined);
|
|
646
666
|
}
|
|
647
667
|
// Wire sendToClient to the SSE hub so all subsystems can reach the HTTP client.
|
|
648
668
|
// Called after setHostBashProxy so updateSender targets the current proxy.
|
|
@@ -679,7 +699,13 @@ export async function handleSendMessage(
|
|
|
679
699
|
attachments,
|
|
680
700
|
session,
|
|
681
701
|
onEvent,
|
|
682
|
-
|
|
702
|
+
// Desktop path: disable NL classification to avoid consuming non-decision
|
|
703
|
+
// messages while a tool confirmation is pending. Deterministic code-prefix
|
|
704
|
+
// and callback parsing remain active. Mirrors session-process.ts behavior.
|
|
705
|
+
approvalConversationGenerator:
|
|
706
|
+
sourceChannel === "vellum"
|
|
707
|
+
? undefined
|
|
708
|
+
: deps.approvalConversationGenerator,
|
|
683
709
|
verifiedActorExternalUserId,
|
|
684
710
|
verifiedActorPrincipalId,
|
|
685
711
|
});
|
|
@@ -687,6 +713,7 @@ export async function handleSendMessage(
|
|
|
687
713
|
return Response.json(
|
|
688
714
|
{
|
|
689
715
|
accepted: true,
|
|
716
|
+
conversationId: mapping.conversationId,
|
|
690
717
|
...(inlineReplyResult.messageId
|
|
691
718
|
? { messageId: inlineReplyResult.messageId }
|
|
692
719
|
: {}),
|
|
@@ -751,7 +778,10 @@ export async function handleSendMessage(
|
|
|
751
778
|
pendingInteractions.removeBySession(session);
|
|
752
779
|
}
|
|
753
780
|
|
|
754
|
-
return Response.json(
|
|
781
|
+
return Response.json(
|
|
782
|
+
{ accepted: true, queued: true, conversationId: mapping.conversationId },
|
|
783
|
+
{ status: 202 },
|
|
784
|
+
);
|
|
755
785
|
}
|
|
756
786
|
|
|
757
787
|
// Session is idle — persist and fire agent loop immediately
|
|
@@ -782,6 +812,7 @@ export async function handleSendMessage(
|
|
|
782
812
|
|
|
783
813
|
if (slashResult.kind === "unknown") {
|
|
784
814
|
session.processing = true;
|
|
815
|
+
let cleanupDeferred = false;
|
|
785
816
|
try {
|
|
786
817
|
const provenance = provenanceFromTrustContext(session.trustContext);
|
|
787
818
|
const channelMeta = {
|
|
@@ -818,26 +849,54 @@ export async function handleSendMessage(
|
|
|
818
849
|
sourceInterface,
|
|
819
850
|
);
|
|
820
851
|
|
|
821
|
-
//
|
|
822
|
-
//
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
onEvent({ type: "assistant_text_delta", text: slashResult.message });
|
|
829
|
-
onEvent({
|
|
830
|
-
type: "message_complete",
|
|
831
|
-
sessionId: mapping.conversationId,
|
|
832
|
-
});
|
|
852
|
+
// Snapshot model info now so the deferred callback cannot observe
|
|
853
|
+
// a config change from a concurrent request.
|
|
854
|
+
const modelInfoEvent =
|
|
855
|
+
isModelSlashCommand(rawContent) || isProviderShortcut(rawContent)
|
|
856
|
+
? buildModelInfoEvent()
|
|
857
|
+
: null;
|
|
833
858
|
|
|
834
|
-
|
|
835
|
-
{
|
|
859
|
+
const response = Response.json(
|
|
860
|
+
{
|
|
861
|
+
accepted: true,
|
|
862
|
+
messageId: persisted.id,
|
|
863
|
+
conversationId: mapping.conversationId,
|
|
864
|
+
},
|
|
836
865
|
{ status: 202 },
|
|
837
866
|
);
|
|
867
|
+
|
|
868
|
+
// Defer event publishing to next tick so the HTTP response reaches the
|
|
869
|
+
// client first. This ensures the client's serverToLocalSessionMap is
|
|
870
|
+
// populated before SSE events arrive, preventing dropped events in new
|
|
871
|
+
// desktop threads.
|
|
872
|
+
//
|
|
873
|
+
// session.processing and drainQueue are also deferred so the current
|
|
874
|
+
// slash command's events are emitted before the next queued message
|
|
875
|
+
// starts processing.
|
|
876
|
+
const conversationId = mapping.conversationId;
|
|
877
|
+
const message = slashResult.message;
|
|
878
|
+
setTimeout(() => {
|
|
879
|
+
if (modelInfoEvent) {
|
|
880
|
+
onEvent(modelInfoEvent);
|
|
881
|
+
}
|
|
882
|
+
onEvent({ type: "assistant_text_delta", text: message });
|
|
883
|
+
onEvent({
|
|
884
|
+
type: "message_complete",
|
|
885
|
+
sessionId: conversationId,
|
|
886
|
+
});
|
|
887
|
+
session.processing = false;
|
|
888
|
+
session.drainQueue().catch(() => {});
|
|
889
|
+
}, 0);
|
|
890
|
+
|
|
891
|
+
cleanupDeferred = true;
|
|
892
|
+
return response;
|
|
838
893
|
} finally {
|
|
839
|
-
|
|
840
|
-
|
|
894
|
+
// No-op for the slash-command early-return path (handled inside
|
|
895
|
+
// setTimeout above), but still needed for error paths.
|
|
896
|
+
if (!cleanupDeferred && session.processing) {
|
|
897
|
+
session.processing = false;
|
|
898
|
+
session.drainQueue().catch(() => {});
|
|
899
|
+
}
|
|
841
900
|
}
|
|
842
901
|
}
|
|
843
902
|
|
|
@@ -874,7 +933,10 @@ export async function handleSendMessage(
|
|
|
874
933
|
);
|
|
875
934
|
});
|
|
876
935
|
|
|
877
|
-
return Response.json(
|
|
936
|
+
return Response.json(
|
|
937
|
+
{ accepted: true, messageId, conversationId: mapping.conversationId },
|
|
938
|
+
{ status: 202 },
|
|
939
|
+
);
|
|
878
940
|
}
|
|
879
941
|
|
|
880
942
|
async function generateLlmSuggestion(
|
|
@@ -7,12 +7,17 @@
|
|
|
7
7
|
* is called. The AuthContext is threaded through from the HTTP server
|
|
8
8
|
* layer, so no additional actor-token verification is needed here.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
10
|
+
* When `conversationKey` is provided, subscribers receive events scoped to
|
|
11
|
+
* that conversation. When omitted, subscribers receive events from ALL
|
|
12
|
+
* conversations for this assistant (unfiltered).
|
|
11
13
|
*/
|
|
12
14
|
|
|
13
15
|
import { getOrCreateConversation } from "../../memory/conversation-key-store.js";
|
|
14
16
|
import { formatSseFrame, formatSseHeartbeat } from "../assistant-event.js";
|
|
15
|
-
import type {
|
|
17
|
+
import type {
|
|
18
|
+
AssistantEventFilter,
|
|
19
|
+
AssistantEventSubscription,
|
|
20
|
+
} from "../assistant-event-hub.js";
|
|
16
21
|
import {
|
|
17
22
|
AssistantEventHub,
|
|
18
23
|
assistantEventHub,
|
|
@@ -26,10 +31,12 @@ import type { RouteDefinition } from "../http-router.js";
|
|
|
26
31
|
const DEFAULT_HEARTBEAT_INTERVAL_MS = 30_000;
|
|
27
32
|
|
|
28
33
|
/**
|
|
29
|
-
* Stream assistant events as Server-Sent Events
|
|
34
|
+
* Stream assistant events as Server-Sent Events.
|
|
30
35
|
*
|
|
31
36
|
* Query params:
|
|
32
|
-
* conversationKey --
|
|
37
|
+
* conversationKey -- optional; when provided, scopes the stream to one
|
|
38
|
+
* conversation. When omitted, the stream delivers events
|
|
39
|
+
* from ALL conversations for this assistant.
|
|
33
40
|
*
|
|
34
41
|
* Options (for testing):
|
|
35
42
|
* hub -- override the event hub (defaults to process singleton).
|
|
@@ -56,15 +63,21 @@ export function handleSubscribeAssistantEvents(
|
|
|
56
63
|
// scope and principal type requirements.
|
|
57
64
|
|
|
58
65
|
const conversationKey = url.searchParams.get("conversationKey");
|
|
59
|
-
if (!conversationKey) {
|
|
60
|
-
return httpError("BAD_REQUEST", "conversationKey
|
|
66
|
+
if (url.searchParams.has("conversationKey") && !conversationKey?.trim()) {
|
|
67
|
+
return httpError("BAD_REQUEST", "conversationKey must not be empty", 400);
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
const hub = options?.hub ?? assistantEventHub;
|
|
64
71
|
const heartbeatIntervalMs =
|
|
65
72
|
options?.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
|
|
66
73
|
|
|
67
|
-
const
|
|
74
|
+
const filter: AssistantEventFilter = {
|
|
75
|
+
assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
|
|
76
|
+
};
|
|
77
|
+
if (conversationKey) {
|
|
78
|
+
const mapping = getOrCreateConversation(conversationKey);
|
|
79
|
+
filter.sessionId = mapping.conversationId;
|
|
80
|
+
}
|
|
68
81
|
const encoder = new TextEncoder();
|
|
69
82
|
|
|
70
83
|
// -- Eager subscribe --------------------------------------------------------
|
|
@@ -90,10 +103,7 @@ export function handleSubscribeAssistantEvents(
|
|
|
90
103
|
|
|
91
104
|
try {
|
|
92
105
|
sub = hub.subscribe(
|
|
93
|
-
|
|
94
|
-
assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
|
|
95
|
-
sessionId: mapping.conversationId,
|
|
96
|
-
},
|
|
106
|
+
filter,
|
|
97
107
|
(event) => {
|
|
98
108
|
const controller = controllerRef;
|
|
99
109
|
if (!controller) return;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route handler for host CU (computer-use) result submissions.
|
|
3
|
+
*
|
|
4
|
+
* Resolves pending host CU proxy requests by requestId when the desktop
|
|
5
|
+
* client returns observation results via HTTP.
|
|
6
|
+
*/
|
|
7
|
+
import { requireBoundGuardian } from "../auth/require-bound-guardian.js";
|
|
8
|
+
import type { AuthContext } from "../auth/types.js";
|
|
9
|
+
import { httpError } from "../http-errors.js";
|
|
10
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
11
|
+
import * as pendingInteractions from "../pending-interactions.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* POST /v1/host-cu-result — resolve a pending host CU request by requestId.
|
|
15
|
+
* Requires AuthContext with guardian-bound actor.
|
|
16
|
+
*/
|
|
17
|
+
export async function handleHostCuResult(
|
|
18
|
+
req: Request,
|
|
19
|
+
authContext: AuthContext,
|
|
20
|
+
): Promise<Response> {
|
|
21
|
+
const authError = requireBoundGuardian(authContext);
|
|
22
|
+
if (authError) return authError;
|
|
23
|
+
|
|
24
|
+
const body = (await req.json()) as {
|
|
25
|
+
requestId?: string;
|
|
26
|
+
axTree?: string;
|
|
27
|
+
axDiff?: string;
|
|
28
|
+
screenshot?: string;
|
|
29
|
+
screenshotWidthPx?: number;
|
|
30
|
+
screenshotHeightPx?: number;
|
|
31
|
+
screenWidthPt?: number;
|
|
32
|
+
screenHeightPt?: number;
|
|
33
|
+
executionResult?: string;
|
|
34
|
+
executionError?: string;
|
|
35
|
+
secondaryWindows?: string;
|
|
36
|
+
userGuidance?: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const { requestId } = body;
|
|
40
|
+
|
|
41
|
+
if (!requestId || typeof requestId !== "string") {
|
|
42
|
+
return httpError("BAD_REQUEST", "requestId is required", 400);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Peek first (non-destructive) so we can validate the interaction kind
|
|
46
|
+
// without accidentally consuming a confirmation or secret interaction.
|
|
47
|
+
const peeked = pendingInteractions.get(requestId);
|
|
48
|
+
if (!peeked) {
|
|
49
|
+
return httpError(
|
|
50
|
+
"NOT_FOUND",
|
|
51
|
+
"No pending interaction found for this requestId",
|
|
52
|
+
404,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (peeked.kind !== "host_cu") {
|
|
57
|
+
return httpError(
|
|
58
|
+
"CONFLICT",
|
|
59
|
+
`Pending interaction is of kind "${peeked.kind}", expected "host_cu"`,
|
|
60
|
+
409,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Validation passed — consume the pending interaction.
|
|
65
|
+
const interaction = pendingInteractions.resolve(requestId)!;
|
|
66
|
+
|
|
67
|
+
interaction.session.resolveHostCu(requestId, {
|
|
68
|
+
axTree: body.axTree,
|
|
69
|
+
axDiff: body.axDiff,
|
|
70
|
+
screenshot: body.screenshot,
|
|
71
|
+
screenshotWidthPx: body.screenshotWidthPx,
|
|
72
|
+
screenshotHeightPx: body.screenshotHeightPx,
|
|
73
|
+
screenWidthPt: body.screenWidthPt,
|
|
74
|
+
screenHeightPt: body.screenHeightPt,
|
|
75
|
+
executionResult: body.executionResult,
|
|
76
|
+
executionError: body.executionError,
|
|
77
|
+
secondaryWindows: body.secondaryWindows,
|
|
78
|
+
userGuidance: body.userGuidance,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return Response.json({ accepted: true });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Route definitions
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
export function hostCuRouteDefinitions(): RouteDefinition[] {
|
|
89
|
+
return [
|
|
90
|
+
{
|
|
91
|
+
endpoint: "host-cu-result",
|
|
92
|
+
method: "POST",
|
|
93
|
+
handler: async ({ req, authContext }) =>
|
|
94
|
+
handleHostCuResult(req, authContext),
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
}
|
|
@@ -334,7 +334,7 @@ export async function enforceIngressAcl(
|
|
|
334
334
|
dmCallbackUrl,
|
|
335
335
|
{
|
|
336
336
|
chatId: senderUserId,
|
|
337
|
-
text: "I've notified the owner.
|
|
337
|
+
text: "I've notified the owner that you'd like to chat with me. If they approve your request, they'll share a 6-digit verification code with you. You can reply with the code here.",
|
|
338
338
|
assistantId,
|
|
339
339
|
},
|
|
340
340
|
mintBearerToken(),
|
|
@@ -423,11 +423,12 @@ export async function enforceIngressAcl(
|
|
|
423
423
|
|
|
424
424
|
if (resolvedMember) {
|
|
425
425
|
if (resolvedMember.channel.status !== "active") {
|
|
426
|
+
const isBlockedMember = resolvedMember.channel.status === "blocked";
|
|
426
427
|
// Same bypass logic as the no-member branch: verification codes and
|
|
427
|
-
// bootstrap commands must pass through
|
|
428
|
-
// revoked
|
|
428
|
+
// bootstrap commands must pass through for re-verifiable states
|
|
429
|
+
// (pending/revoked), but never for blocked members.
|
|
429
430
|
let denyInactiveMember = true;
|
|
430
|
-
if (isGuardianVerifyCode) {
|
|
431
|
+
if (!isBlockedMember && isGuardianVerifyCode) {
|
|
431
432
|
const hasPendingChallenge = !!getPendingSession(sourceChannel);
|
|
432
433
|
const hasActiveOutboundSession = !!findActiveSession(sourceChannel);
|
|
433
434
|
if (hasPendingChallenge || hasActiveOutboundSession) {
|
|
@@ -444,7 +445,7 @@ export async function enforceIngressAcl(
|
|
|
444
445
|
);
|
|
445
446
|
}
|
|
446
447
|
}
|
|
447
|
-
if (isBootstrapCommand) {
|
|
448
|
+
if (!isBlockedMember && isBootstrapCommand) {
|
|
448
449
|
const bootstrapPayload = (
|
|
449
450
|
rawCommandIntentForAcl as Record<string, unknown>
|
|
450
451
|
).payload as string;
|
|
@@ -471,9 +472,11 @@ export async function enforceIngressAcl(
|
|
|
471
472
|
}
|
|
472
473
|
|
|
473
474
|
// ── Invite token intercept (inactive member) ──
|
|
474
|
-
//
|
|
475
|
-
//
|
|
476
|
-
|
|
475
|
+
// Invite tokens can reactivate revoked/pending members without
|
|
476
|
+
// requiring guardian approval, but blocked members are excluded so
|
|
477
|
+
// they are short-circuited at the ACL layer rather than entering the
|
|
478
|
+
// redemption path.
|
|
479
|
+
if (!isBlockedMember && inviteToken && denyInactiveMember) {
|
|
477
480
|
const inviteResult = await handleInviteTokenIntercept({
|
|
478
481
|
rawToken: inviteToken,
|
|
479
482
|
sourceChannel,
|
|
@@ -496,9 +499,15 @@ export async function enforceIngressAcl(
|
|
|
496
499
|
}
|
|
497
500
|
|
|
498
501
|
// ── 6-digit invite code intercept (inactive member) ──
|
|
499
|
-
//
|
|
500
|
-
//
|
|
501
|
-
|
|
502
|
+
// Codes can reactivate revoked/pending members; non-matching codes
|
|
503
|
+
// fall through. Blocked members are excluded here for consistency —
|
|
504
|
+
// the redemption service would reject them anyway, but early exit
|
|
505
|
+
// avoids unnecessary work.
|
|
506
|
+
if (
|
|
507
|
+
!isBlockedMember &&
|
|
508
|
+
denyInactiveMember &&
|
|
509
|
+
/^\d{6}$/.test(trimmedContent)
|
|
510
|
+
) {
|
|
502
511
|
const codeInterceptResult = await handleInviteCodeIntercept({
|
|
503
512
|
code: trimmedContent,
|
|
504
513
|
sourceChannel,
|
|
@@ -579,7 +588,7 @@ export async function enforceIngressAcl(
|
|
|
579
588
|
dmCallbackUrl,
|
|
580
589
|
{
|
|
581
590
|
chatId: senderUserId,
|
|
582
|
-
text: "I've notified the owner.
|
|
591
|
+
text: "I've notified the owner that you'd like to chat with me. If they approve your request, they'll share a 6-digit verification code with you. You can reply with the code here.",
|
|
583
592
|
assistantId,
|
|
584
593
|
},
|
|
585
594
|
mintBearerToken(),
|
|
@@ -31,12 +31,8 @@ import type {
|
|
|
31
31
|
ApprovalCopyGenerator,
|
|
32
32
|
MessageProcessor,
|
|
33
33
|
} from "../../http-types.js";
|
|
34
|
-
import { TelegramStreamingDelivery } from "../../telegram-streaming-delivery.js";
|
|
35
34
|
import { resolveRoutingState } from "../../trust-context-resolver.js";
|
|
36
|
-
import {
|
|
37
|
-
deliverAttachmentsOnly,
|
|
38
|
-
deliverReplyViaCallback,
|
|
39
|
-
} from "../channel-delivery-routes.js";
|
|
35
|
+
import { deliverReplyViaCallback } from "../channel-delivery-routes.js";
|
|
40
36
|
import { deliverGeneratedApprovalPrompt } from "../guardian-approval-prompt.js";
|
|
41
37
|
|
|
42
38
|
const log = getLogger("runtime-http");
|
|
@@ -112,12 +108,6 @@ export function processChannelMessageInBackground(
|
|
|
112
108
|
} = params;
|
|
113
109
|
|
|
114
110
|
(async () => {
|
|
115
|
-
const boundGuardianActor = isBoundGuardianActor({
|
|
116
|
-
trustClass: trustCtx.trustClass,
|
|
117
|
-
guardianExternalUserId: trustCtx.guardianExternalUserId,
|
|
118
|
-
requesterExternalUserId: trustCtx.requesterExternalUserId,
|
|
119
|
-
});
|
|
120
|
-
|
|
121
111
|
const typingCallbackUrl = shouldEmitTelegramTyping(
|
|
122
112
|
sourceChannel,
|
|
123
113
|
replyCallbackUrl,
|
|
@@ -181,16 +171,6 @@ export function processChannelMessageInBackground(
|
|
|
181
171
|
}
|
|
182
172
|
}
|
|
183
173
|
|
|
184
|
-
const telegramStreaming =
|
|
185
|
-
sourceChannel === "telegram" && replyCallbackUrl
|
|
186
|
-
? new TelegramStreamingDelivery({
|
|
187
|
-
callbackUrl: replyCallbackUrl,
|
|
188
|
-
chatId: externalChatId,
|
|
189
|
-
mintBearerToken,
|
|
190
|
-
assistantId,
|
|
191
|
-
})
|
|
192
|
-
: undefined;
|
|
193
|
-
|
|
194
174
|
try {
|
|
195
175
|
const cmdIntent =
|
|
196
176
|
commandIntent && typeof commandIntent.type === "string"
|
|
@@ -218,9 +198,6 @@ export function processChannelMessageInBackground(
|
|
|
218
198
|
trustContext: trustCtx,
|
|
219
199
|
isInteractive: resolveRoutingState(trustCtx).promptWaitingAllowed,
|
|
220
200
|
...(cmdIntent ? { commandIntent: cmdIntent } : {}),
|
|
221
|
-
...(telegramStreaming
|
|
222
|
-
? { onEvent: (msg) => telegramStreaming.onEvent(msg) }
|
|
223
|
-
: {}),
|
|
224
201
|
},
|
|
225
202
|
sourceChannel,
|
|
226
203
|
sourceInterface,
|
|
@@ -228,94 +205,18 @@ export function processChannelMessageInBackground(
|
|
|
228
205
|
deliveryCrud.linkMessage(eventId, userMessageId);
|
|
229
206
|
deliveryStatus.markProcessed(eventId);
|
|
230
207
|
|
|
231
|
-
if (telegramStreaming) {
|
|
232
|
-
// Retrieve approval metadata from pending interactions (if any)
|
|
233
|
-
// so approval buttons can be attached to the final streamed message.
|
|
234
|
-
// Approval prompts are guardian-only and must never be attached for
|
|
235
|
-
// non-guardian or unverified actors.
|
|
236
|
-
const prompt = boundGuardianActor
|
|
237
|
-
? getChannelApprovalPrompt(conversationId)
|
|
238
|
-
: undefined;
|
|
239
|
-
const pending = boundGuardianActor
|
|
240
|
-
? getApprovalInfoByConversation(conversationId)
|
|
241
|
-
: [];
|
|
242
|
-
const approvalMeta =
|
|
243
|
-
prompt && pending.length > 0
|
|
244
|
-
? buildApprovalUIMetadata(prompt, pending[0])
|
|
245
|
-
: undefined;
|
|
246
|
-
try {
|
|
247
|
-
await telegramStreaming.finish(approvalMeta);
|
|
248
|
-
deliveryChannels.updateDeliveredSegmentCount(eventId, 1);
|
|
249
|
-
} catch (err) {
|
|
250
|
-
log.error(
|
|
251
|
-
{ err, conversationId },
|
|
252
|
-
"Telegram streaming finalization failed",
|
|
253
|
-
);
|
|
254
|
-
// Fallback: deliver approval as a standalone message so buttons
|
|
255
|
-
// are not permanently lost when finish() fails.
|
|
256
|
-
if (approvalMeta && replyCallbackUrl) {
|
|
257
|
-
try {
|
|
258
|
-
await deliverChannelReply(
|
|
259
|
-
replyCallbackUrl,
|
|
260
|
-
{
|
|
261
|
-
chatId: externalChatId,
|
|
262
|
-
text: approvalMeta.plainTextFallback ?? "Action needed:",
|
|
263
|
-
approval: approvalMeta,
|
|
264
|
-
assistantId,
|
|
265
|
-
},
|
|
266
|
-
mintBearerToken(),
|
|
267
|
-
);
|
|
268
|
-
} catch (fallbackErr) {
|
|
269
|
-
log.error(
|
|
270
|
-
{ err: fallbackErr, conversationId },
|
|
271
|
-
"Fallback approval delivery also failed",
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
208
|
if (replyCallbackUrl) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
mintBearerToken(),
|
|
291
|
-
assistantId,
|
|
292
|
-
);
|
|
293
|
-
} else {
|
|
294
|
-
// Non-streaming path, or streaming partially failed (some text
|
|
295
|
-
// was delivered but finish/finalization threw). In the partial
|
|
296
|
-
// failure case the user has a truncated message, so we deliver
|
|
297
|
-
// the full response to ensure nothing is lost.
|
|
298
|
-
if (
|
|
299
|
-
telegramStreaming?.hasDeliveredText &&
|
|
300
|
-
!telegramStreaming.finishSucceeded
|
|
301
|
-
) {
|
|
302
|
-
log.warn(
|
|
303
|
-
{ conversationId },
|
|
304
|
-
"Telegram streaming partially failed — falling back to full text delivery",
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
await deliverReplyViaCallback(
|
|
308
|
-
conversationId,
|
|
309
|
-
externalChatId,
|
|
310
|
-
replyCallbackUrl,
|
|
311
|
-
mintBearerToken(),
|
|
312
|
-
assistantId,
|
|
313
|
-
{
|
|
314
|
-
onSegmentDelivered: (count) =>
|
|
315
|
-
deliveryChannels.updateDeliveredSegmentCount(eventId, count),
|
|
316
|
-
},
|
|
317
|
-
);
|
|
318
|
-
}
|
|
209
|
+
await deliverReplyViaCallback(
|
|
210
|
+
conversationId,
|
|
211
|
+
externalChatId,
|
|
212
|
+
replyCallbackUrl,
|
|
213
|
+
mintBearerToken(),
|
|
214
|
+
assistantId,
|
|
215
|
+
{
|
|
216
|
+
onSegmentDelivered: (count) =>
|
|
217
|
+
deliveryChannels.updateDeliveredSegmentCount(eventId, count),
|
|
218
|
+
},
|
|
219
|
+
);
|
|
319
220
|
}
|
|
320
221
|
} catch (err) {
|
|
321
222
|
log.error(
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
userInfo,
|
|
13
13
|
} from "../../../../messaging/providers/slack/client.js";
|
|
14
14
|
import type { SlackConversation } from "../../../../messaging/providers/slack/types.js";
|
|
15
|
-
import {
|
|
15
|
+
import { getConnectionByProvider } from "../../../../oauth/oauth-store.js";
|
|
16
16
|
import { getSecureKey } from "../../../../security/secure-keys.js";
|
|
17
17
|
import { getLogger } from "../../../../util/logger.js";
|
|
18
18
|
import { httpError } from "../../../http-errors.js";
|
|
@@ -25,14 +25,13 @@ const log = getLogger("slack-share");
|
|
|
25
25
|
// ---------------------------------------------------------------------------
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Resolve the Slack bot token from
|
|
29
|
-
* Prefers the OAuth integration token, falls back to the legacy channel token.
|
|
28
|
+
* Resolve the Slack bot token from the OAuth connection store.
|
|
30
29
|
*/
|
|
31
30
|
function resolveSlackToken(): string | undefined {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
getSecureKey(
|
|
35
|
-
|
|
31
|
+
const conn = getConnectionByProvider("integration:slack");
|
|
32
|
+
return conn
|
|
33
|
+
? getSecureKey(`oauth_connection/${conn.id}/access_token`)
|
|
34
|
+
: undefined;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
// ---------------------------------------------------------------------------
|