@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
|
@@ -84,7 +84,10 @@ export class PermissionPrompter {
|
|
|
84
84
|
"Permission prompt timed out, defaulting to deny",
|
|
85
85
|
);
|
|
86
86
|
this.onStateChanged?.(requestId, "timed_out", "timeout", toolUseId);
|
|
87
|
-
resolve({
|
|
87
|
+
resolve({
|
|
88
|
+
decision: "deny",
|
|
89
|
+
decisionContext: `The permission prompt for the "${toolName}" tool timed out. The user did not explicitly deny this request — they may have been away or busy. You may retry this tool call if it is still needed for the current task.`,
|
|
90
|
+
});
|
|
88
91
|
}, timeoutMs);
|
|
89
92
|
|
|
90
93
|
this.pending.set(requestId, { resolve, reject, timer, toolUseId });
|
|
@@ -121,6 +124,7 @@ export class PermissionPrompter {
|
|
|
121
124
|
executionTarget,
|
|
122
125
|
persistentDecisionsAllowed: persistentDecisionsAllowed ?? true,
|
|
123
126
|
temporaryOptionsAvailable,
|
|
127
|
+
toolUseId,
|
|
124
128
|
});
|
|
125
129
|
|
|
126
130
|
this.onStateChanged?.(requestId, "pending", "system", toolUseId);
|
|
@@ -131,6 +135,11 @@ export class PermissionPrompter {
|
|
|
131
135
|
return this.pending.has(requestId);
|
|
132
136
|
}
|
|
133
137
|
|
|
138
|
+
/** Returns all currently pending request IDs. */
|
|
139
|
+
getPendingRequestIds(): string[] {
|
|
140
|
+
return [...this.pending.keys()];
|
|
141
|
+
}
|
|
142
|
+
|
|
134
143
|
/** Returns the toolUseId associated with a pending request, if any. */
|
|
135
144
|
getToolUseId(requestId: string): string | undefined {
|
|
136
145
|
return this.pending.get(requestId)?.toolUseId;
|
|
@@ -76,6 +76,19 @@ function getCompiledPattern(pattern: string): Minimatch | null {
|
|
|
76
76
|
return compiled;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Check whether a minimatch pattern matches a candidate string.
|
|
81
|
+
* Reuses the compiled pattern cache from trust rule evaluation.
|
|
82
|
+
*/
|
|
83
|
+
export function patternMatchesCandidate(
|
|
84
|
+
pattern: string,
|
|
85
|
+
candidate: string,
|
|
86
|
+
): boolean {
|
|
87
|
+
const compiled = getCompiledPattern(pattern);
|
|
88
|
+
if (!compiled) return false;
|
|
89
|
+
return compiled.match(candidate);
|
|
90
|
+
}
|
|
91
|
+
|
|
79
92
|
/** Rebuild the compiled pattern cache from the current rule set. */
|
|
80
93
|
function rebuildPatternCache(rules: TrustRule[]): void {
|
|
81
94
|
compiledPatterns.clear();
|
|
@@ -270,12 +283,28 @@ function loadFromDisk(): TrustRule[] {
|
|
|
270
283
|
// Restore persisted starter bundle flag
|
|
271
284
|
cachedStarterBundleAccepted = data.starterBundleAccepted === true;
|
|
272
285
|
|
|
286
|
+
// Defense-in-depth: strip any __internal: prefixed rules that may have
|
|
287
|
+
// been hand-edited into trust.json.
|
|
288
|
+
const sanitizedRules = rawRules.filter((r) => {
|
|
289
|
+
if (typeof r.tool === "string" && r.tool.startsWith("__internal:")) {
|
|
290
|
+
log.warn(
|
|
291
|
+
{ ruleId: r.id, tool: r.tool },
|
|
292
|
+
"Stripping __internal: rule from trust file on load",
|
|
293
|
+
);
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
return true;
|
|
297
|
+
});
|
|
298
|
+
|
|
273
299
|
if (
|
|
274
300
|
data.version === TRUST_FILE_VERSION ||
|
|
275
301
|
data.version === 1 ||
|
|
276
302
|
data.version === 2
|
|
277
303
|
) {
|
|
278
|
-
rules =
|
|
304
|
+
rules = sanitizedRules;
|
|
305
|
+
if (sanitizedRules.length < rawRules.length) {
|
|
306
|
+
needsSave = true;
|
|
307
|
+
}
|
|
279
308
|
if (data.version !== TRUST_FILE_VERSION) {
|
|
280
309
|
needsSave = true;
|
|
281
310
|
log.info(
|
|
@@ -382,6 +411,8 @@ export function addRule(
|
|
|
382
411
|
executionTarget?: string;
|
|
383
412
|
},
|
|
384
413
|
): TrustRule {
|
|
414
|
+
if (tool.startsWith("__internal:"))
|
|
415
|
+
throw new Error(`Cannot create internal pseudo-rule via addRule: ${tool}`);
|
|
385
416
|
// Re-read from disk to avoid lost updates if another call modified rules
|
|
386
417
|
// between our last read and now (e.g. two rapid trust rule additions).
|
|
387
418
|
cachedRules = null;
|
|
@@ -424,6 +455,10 @@ export function updateRule(
|
|
|
424
455
|
const defaultIds = new Set(getDefaultRuleTemplates().map((t) => t.id));
|
|
425
456
|
if (defaultIds.has(id))
|
|
426
457
|
throw new Error(`Cannot modify default trust rule: ${id}`);
|
|
458
|
+
if (updates.tool?.startsWith("__internal:"))
|
|
459
|
+
throw new Error(
|
|
460
|
+
`Cannot update tool to internal pseudo-rule: ${updates.tool}`,
|
|
461
|
+
);
|
|
427
462
|
|
|
428
463
|
// Re-read from disk to avoid lost updates from concurrent modifications.
|
|
429
464
|
cachedRules = null;
|
|
@@ -38,7 +38,9 @@ describe("buildCliReferenceSection", () => {
|
|
|
38
38
|
"prefer real `assistant` CLI workflows over any legacy account-record abstraction",
|
|
39
39
|
);
|
|
40
40
|
expect(result).toContain("assistant credentials");
|
|
41
|
-
expect(result).toContain(
|
|
41
|
+
expect(result).toContain(
|
|
42
|
+
"assistant oauth connections token <provider-key>",
|
|
43
|
+
);
|
|
42
44
|
expect(result).toContain("assistant mcp auth <name>");
|
|
43
45
|
expect(result).toContain("assistant platform status");
|
|
44
46
|
});
|
|
@@ -4,10 +4,10 @@ import { join } from "node:path";
|
|
|
4
4
|
import { CLI_HELP_REFERENCE } from "../cli/reference.js";
|
|
5
5
|
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
6
6
|
import { getBaseDataDir, getIsContainerized } from "../config/env-registry.js";
|
|
7
|
-
import { getConfig
|
|
7
|
+
import { getConfig } from "../config/loader.js";
|
|
8
8
|
import { skillFlagKey } from "../config/skill-state.js";
|
|
9
9
|
import { loadSkillCatalog, type SkillSummary } from "../config/skills.js";
|
|
10
|
-
import {
|
|
10
|
+
import { listConnections } from "../oauth/oauth-store.js";
|
|
11
11
|
import { resolveBundledDir } from "../util/bundled-asset.js";
|
|
12
12
|
import { getLogger } from "../util/logger.js";
|
|
13
13
|
import {
|
|
@@ -283,7 +283,7 @@ function buildAttachmentSection(): string {
|
|
|
283
283
|
"",
|
|
284
284
|
'Example: `<vellum-attachment source="sandbox" path="scratch/chart.png" />`',
|
|
285
285
|
"",
|
|
286
|
-
"Limits:
|
|
286
|
+
"Limits: 20 MB per attachment. Tool outputs that produce image or file content blocks are also automatically converted into attachments.",
|
|
287
287
|
"",
|
|
288
288
|
"### Inline Images and GIFs",
|
|
289
289
|
"Embed images/GIFs inline using markdown: ``. Do NOT wrap in code fences.",
|
|
@@ -368,13 +368,11 @@ export function buildVoiceSetupRoutingSection(): string {
|
|
|
368
368
|
return [
|
|
369
369
|
"## Routing: Voice Setup & Troubleshooting",
|
|
370
370
|
"",
|
|
371
|
-
"Voice features include push-to-talk (PTT)
|
|
371
|
+
"Voice features include push-to-talk (PTT) and text-to-speech.",
|
|
372
372
|
"",
|
|
373
373
|
"### Quick changes — use `voice_config_update` directly",
|
|
374
374
|
'- "Change my PTT key to ctrl" — call `voice_config_update` with `setting: "activation_key"`',
|
|
375
|
-
'- "
|
|
376
|
-
'- "Set my wake word to jarvis" — call `voice_config_update` with `setting: "wake_word_keyword"`',
|
|
377
|
-
'- "Set wake word timeout to 30 seconds" — call `voice_config_update` with `setting: "wake_word_timeout"`',
|
|
375
|
+
'- "Set conversation timeout to 30 seconds" — call `voice_config_update` with `setting: "conversation_timeout"`',
|
|
378
376
|
"",
|
|
379
377
|
"For simple setting changes, use the tool directly without loading the voice-setup skill.",
|
|
380
378
|
"",
|
|
@@ -384,15 +382,14 @@ export function buildVoiceSetupRoutingSection(): string {
|
|
|
384
382
|
"**Trigger phrases:**",
|
|
385
383
|
'- "Help me set up voice"',
|
|
386
384
|
'- "Set up push-to-talk"',
|
|
387
|
-
'- "Configure voice / PTT
|
|
385
|
+
'- "Configure voice / PTT"',
|
|
388
386
|
'- "PTT isn\'t working" / "push-to-talk not working"',
|
|
389
387
|
'- "Recording but no text"',
|
|
390
|
-
'- "Wake word not detecting"',
|
|
391
388
|
'- "Microphone not working"',
|
|
392
389
|
'- "Set up ElevenLabs" / "configure TTS"',
|
|
393
390
|
"",
|
|
394
391
|
"### Disambiguation",
|
|
395
|
-
"- Voice setup (this skill) = **local PTT,
|
|
392
|
+
"- Voice setup (this skill) = **local PTT, microphone permissions** on the Mac desktop app.",
|
|
396
393
|
"- Phone calls skill = **Twilio-powered voice calls** over the phone network. Completely separate.",
|
|
397
394
|
'- If the user says "voice" in the context of phone calls or Twilio, load `phone-calls` instead.',
|
|
398
395
|
].join("\n");
|
|
@@ -423,7 +420,7 @@ export function buildPhoneCallsRoutingSection(): string {
|
|
|
423
420
|
"",
|
|
424
421
|
"### Exclusivity rules",
|
|
425
422
|
"- Do NOT improvise Twilio setup instructions from general knowledge — always load the skill first.",
|
|
426
|
-
"- Do NOT confuse with voice-setup (local PTT/
|
|
423
|
+
"- Do NOT confuse with voice-setup (local PTT/microphone) or guardian-verify-setup (channel verification).",
|
|
427
424
|
'- If the user says "voice" in the context of phone calls or Twilio, load phone-calls, not voice-setup.',
|
|
428
425
|
"- For guardian voice verification specifically, load guardian-verify-setup instead.",
|
|
429
426
|
].join("\n");
|
|
@@ -630,42 +627,38 @@ function buildAccessPreferenceSection(hasNoClient: boolean): string {
|
|
|
630
627
|
"",
|
|
631
628
|
"### Foreground Computer Use — Last Resort",
|
|
632
629
|
"",
|
|
633
|
-
"
|
|
634
|
-
"
|
|
630
|
+
"Computer use tools (clicking, typing, scrolling) take over the user's cursor and keyboard.",
|
|
631
|
+
"They are disruptive and should be your LAST resort. Prefer this hierarchy:",
|
|
635
632
|
"",
|
|
636
633
|
"1. **CLI tools / osascript** — Use `host_bash` with shell commands or `osascript` with",
|
|
637
634
|
" AppleScript to accomplish tasks in the background without interrupting the user.",
|
|
638
635
|
"2. **Background computer use** — If you must interact with a GUI app, prefer AppleScript",
|
|
639
636
|
' automation (e.g. `tell application "Safari" to set URL of current tab to ...`).',
|
|
640
|
-
"3. **Foreground computer use** — Only
|
|
641
|
-
"
|
|
642
|
-
"
|
|
637
|
+
"3. **Foreground computer use** — Only use computer use tools when the task genuinely",
|
|
638
|
+
" cannot be done any other way (e.g. complex multi-step GUI interactions with no scripting",
|
|
639
|
+
" support) or the user explicitly asks you to take control.",
|
|
643
640
|
]
|
|
644
641
|
: []),
|
|
645
642
|
].join("\n");
|
|
646
643
|
}
|
|
647
644
|
|
|
648
645
|
function buildIntegrationSection(): string {
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
646
|
+
let connections: { providerKey: string; accountInfo?: string | null }[];
|
|
647
|
+
try {
|
|
648
|
+
connections = listConnections().filter((c) => c.status === "active");
|
|
649
|
+
} catch {
|
|
650
|
+
// DB not available — no connected services to show
|
|
651
|
+
return "";
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (connections.length === 0) return "";
|
|
655
655
|
|
|
656
|
-
const raw = loadRawConfig();
|
|
657
656
|
const lines = ["## Connected Services", ""];
|
|
658
|
-
for (const
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
)
|
|
663
|
-
// Fallback: legacy config path used before the namespace migration
|
|
664
|
-
getNestedValue(raw, `integrations.accountInfo.${cred.service}`)) as
|
|
665
|
-
| string
|
|
666
|
-
| undefined;
|
|
667
|
-
const state = acctInfo ? `Connected (${acctInfo})` : "Connected";
|
|
668
|
-
lines.push(`- **${cred.service}**: ${state}`);
|
|
657
|
+
for (const conn of connections) {
|
|
658
|
+
const state = conn.accountInfo
|
|
659
|
+
? `Connected (${conn.accountInfo})`
|
|
660
|
+
: "Connected";
|
|
661
|
+
lines.push(`- **${conn.providerKey}**: ${state}`);
|
|
669
662
|
}
|
|
670
663
|
|
|
671
664
|
return lines.join("\n");
|
|
@@ -697,7 +690,7 @@ function buildMemoryRecallSection(): string {
|
|
|
697
690
|
"- The auto-injected memory context doesn't contain what you need",
|
|
698
691
|
"- The user references something from a previous session",
|
|
699
692
|
"",
|
|
700
|
-
"The tool
|
|
693
|
+
"The tool uses hybrid search (dense and sparse vectors) supplemented by recency. Be specific in your query for best results.",
|
|
701
694
|
].join("\n");
|
|
702
695
|
}
|
|
703
696
|
|
|
@@ -852,10 +845,10 @@ export function buildCliReferenceSection(): string {
|
|
|
852
845
|
return [
|
|
853
846
|
"## Assistant CLI",
|
|
854
847
|
"",
|
|
855
|
-
"The `assistant` CLI is
|
|
848
|
+
"The `assistant` CLI is available in the sandbox. Always use the `bash` tool (never `host_bash`) when running `assistant` commands.",
|
|
856
849
|
"For account and authentication work, prefer real `assistant` CLI workflows over any legacy account-record abstraction.",
|
|
857
850
|
"- Use `assistant credentials ...` for stored secrets and credential metadata.",
|
|
858
|
-
"- Use `assistant oauth token <
|
|
851
|
+
"- Use `assistant oauth connections token <provider-key>` for connected integration tokens.",
|
|
859
852
|
"- Use `assistant mcp auth <name>` when an MCP server needs OAuth login.",
|
|
860
853
|
"- Use `assistant platform status` for platform-linked deployment and auth context.",
|
|
861
854
|
"- If a bundled skill documents a service-specific `assistant <service>` auth or session flow, follow that CLI exactly.",
|
|
@@ -967,6 +960,22 @@ function buildDynamicSkillWorkflowSection(
|
|
|
967
960
|
);
|
|
968
961
|
}
|
|
969
962
|
|
|
963
|
+
lines.push(
|
|
964
|
+
"",
|
|
965
|
+
"### Community Skills Discovery",
|
|
966
|
+
"",
|
|
967
|
+
"When no built-in skill satisfies a request, search the community skills.sh registry:",
|
|
968
|
+
"1. Run `assistant skills search <query>` to find community skills. Results include install counts and security audit badges (ATH, Socket, Snyk).",
|
|
969
|
+
"2. Present the search results to the user, highlighting the security audit status. ATH is Gen Agent Trust Hub. Audits show PASS (safe/low risk), WARN (medium risk), or FAIL (high/critical risk) for each provider.",
|
|
970
|
+
"3. Check the skill's **source owner** to determine the trust level:",
|
|
971
|
+
" - **Vellum-owned** (source starts with `vellum-ai/`): These are first-party skills published by the Vellum team. Install them directly without prompting — they are vetted and trusted.",
|
|
972
|
+
" - **Third-party** (any other owner): Ask the user for permission before installing. Say something like: \"I found a community skill that could help with this, but it's published by a third party — we haven't vetted it. Want to install it anyway?\" Share the skill name, source, audit results, and install count.",
|
|
973
|
+
"4. Install with `assistant skills add <owner>/<repo>@<skill-name>` (e.g., `assistant skills add vercel-labs/skills@find-skills`).",
|
|
974
|
+
"5. After installation, load the skill with `skill_load` as usual.",
|
|
975
|
+
"",
|
|
976
|
+
"**Never install third-party community skills without explicit user confirmation.** Vellum-owned skills (`vellum-ai/*`) can be installed automatically.",
|
|
977
|
+
);
|
|
978
|
+
|
|
970
979
|
return lines.join("\n");
|
|
971
980
|
}
|
|
972
981
|
|
|
@@ -1029,10 +1038,5 @@ function formatSkillsCatalog(skills: SkillSummary[]): string {
|
|
|
1029
1038
|
"",
|
|
1030
1039
|
lines.join("\n"),
|
|
1031
1040
|
"",
|
|
1032
|
-
"### Installing additional skills",
|
|
1033
|
-
"If `skill_load` fails because a skill is not found, additional first-party skills may be available in the Vellum catalog.",
|
|
1034
|
-
"Use `bash` to discover and install them:",
|
|
1035
|
-
"- `assistant skills list` — list all available catalog skills",
|
|
1036
|
-
"- `assistant skills install <skill-id>` — install a skill, then retry `skill_load`",
|
|
1037
1041
|
].join("\n");
|
|
1038
1042
|
}
|
|
@@ -84,8 +84,12 @@ function summarizeMessages(messages: Anthropic.MessageParam[]): string[] {
|
|
|
84
84
|
const blockDescs = content.map((b) => {
|
|
85
85
|
const bt = (b as { type: string }).type;
|
|
86
86
|
if (bt === "tool_use") return `tool_use(${(b as { id: string }).id})`;
|
|
87
|
+
if (bt === "server_tool_use")
|
|
88
|
+
return `server_tool_use(${(b as { id: string }).id})`;
|
|
87
89
|
if (bt === "tool_result")
|
|
88
90
|
return `tool_result(${(b as { tool_use_id: string }).tool_use_id})`;
|
|
91
|
+
if (bt === "web_search_tool_result")
|
|
92
|
+
return `web_search_tool_result(${(b as { tool_use_id: string }).tool_use_id})`;
|
|
89
93
|
return bt;
|
|
90
94
|
});
|
|
91
95
|
return `[${idx}] ${m.role}: ${blockDescs.join(", ") || "(empty)"}`;
|
|
@@ -103,16 +107,24 @@ function buildSyntheticToolResult(
|
|
|
103
107
|
};
|
|
104
108
|
}
|
|
105
109
|
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Collect ordered IDs of client-side tool_use blocks only.
|
|
113
|
+
* Server-side tools (server_tool_use / web_search_tool_result) are self-paired
|
|
114
|
+
* within the assistant message and do not need cross-message pairing.
|
|
115
|
+
*/
|
|
106
116
|
function getOrderedToolUseIds(
|
|
107
117
|
content: Anthropic.ContentBlockParam[],
|
|
108
118
|
): string[] {
|
|
109
119
|
const ids: string[] = [];
|
|
110
120
|
const seen = new Set<string>();
|
|
111
121
|
for (const block of content) {
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
if (isToolUseBlock(block)) {
|
|
123
|
+
if (!seen.has(block.id)) {
|
|
124
|
+
seen.add(block.id);
|
|
125
|
+
ids.push(block.id);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
116
128
|
}
|
|
117
129
|
return ids;
|
|
118
130
|
}
|
|
@@ -124,19 +136,29 @@ function hasOrderedToolResultPrefix(
|
|
|
124
136
|
if (content.length < orderedToolUseIds.length) return false;
|
|
125
137
|
for (let idx = 0; idx < orderedToolUseIds.length; idx++) {
|
|
126
138
|
const block = content[idx];
|
|
139
|
+
const expectedId = orderedToolUseIds[idx];
|
|
127
140
|
if (!isToolResultBlock(block)) return false;
|
|
128
|
-
if (block.tool_use_id !==
|
|
141
|
+
if (block.tool_use_id !== expectedId) return false;
|
|
129
142
|
}
|
|
130
143
|
return true;
|
|
131
144
|
}
|
|
132
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Split an assistant message into:
|
|
148
|
+
* - pairedContent: everything up to and including client-side tool_use blocks
|
|
149
|
+
* - carryoverContent: trailing non-tool blocks after the last tool_use
|
|
150
|
+
*
|
|
151
|
+
* Server-side tools (server_tool_use / web_search_tool_result) are treated as
|
|
152
|
+
* regular content — they are self-paired within the assistant message and must
|
|
153
|
+
* not be separated by the cross-message pairing logic.
|
|
154
|
+
*/
|
|
133
155
|
function splitAssistantForToolPairing(content: Anthropic.ContentBlockParam[]): {
|
|
134
156
|
pairedContent: Anthropic.ContentBlockParam[];
|
|
135
157
|
carryoverContent: Anthropic.ContentBlockParam[];
|
|
136
158
|
toolUseIds: string[];
|
|
137
159
|
} {
|
|
138
160
|
const leading: Anthropic.ContentBlockParam[] = [];
|
|
139
|
-
const toolUseBlocks: Anthropic.
|
|
161
|
+
const toolUseBlocks: Anthropic.ContentBlockParam[] = [];
|
|
140
162
|
const carryover: Anthropic.ContentBlockParam[] = [];
|
|
141
163
|
let seenToolUse = false;
|
|
142
164
|
|
|
@@ -182,7 +204,7 @@ function normalizeFollowingUserContent(
|
|
|
182
204
|
hadOrderedPrefix: boolean;
|
|
183
205
|
} {
|
|
184
206
|
const pendingIds = new Set(orderedToolUseIds);
|
|
185
|
-
const matchedById = new Map<string, Anthropic.
|
|
207
|
+
const matchedById = new Map<string, Anthropic.ContentBlockParam>();
|
|
186
208
|
const remaining: Anthropic.ContentBlockParam[] = [];
|
|
187
209
|
|
|
188
210
|
for (const block of nextContent) {
|
|
@@ -206,10 +228,7 @@ function normalizeFollowingUserContent(
|
|
|
206
228
|
toolResultPrefix: orderedResults,
|
|
207
229
|
remainingContent: remaining,
|
|
208
230
|
missingIds,
|
|
209
|
-
hadOrderedPrefix: hasOrderedToolResultPrefix(
|
|
210
|
-
nextContent,
|
|
211
|
-
orderedToolUseIds,
|
|
212
|
-
),
|
|
231
|
+
hadOrderedPrefix: hasOrderedToolResultPrefix(nextContent, orderedToolUseIds),
|
|
213
232
|
};
|
|
214
233
|
}
|
|
215
234
|
|
|
@@ -348,21 +367,23 @@ function ensureToolPairing(
|
|
|
348
367
|
}
|
|
349
368
|
}
|
|
350
369
|
|
|
351
|
-
// Self-validation: verify no tool_use/tool_result mismatches remain
|
|
370
|
+
// Self-validation: verify no client-side tool_use/tool_result mismatches remain.
|
|
371
|
+
// Server-side tools (server_tool_use / web_search_tool_result) are self-paired
|
|
372
|
+
// within assistant messages and are not validated here.
|
|
352
373
|
for (let j = 0; j < result.length; j++) {
|
|
353
374
|
const m = result[j];
|
|
354
375
|
if (m.role !== "assistant") continue;
|
|
355
376
|
const c = Array.isArray(m.content) ? m.content : [];
|
|
356
|
-
const
|
|
357
|
-
if (
|
|
377
|
+
const validationIds = getOrderedToolUseIds(c);
|
|
378
|
+
if (validationIds.length === 0) continue;
|
|
358
379
|
|
|
359
380
|
const nxt = result[j + 1];
|
|
360
381
|
const nxtContent =
|
|
361
382
|
nxt && nxt.role === "user" && Array.isArray(nxt.content)
|
|
362
383
|
? nxt.content
|
|
363
384
|
: [];
|
|
364
|
-
if (!hasOrderedToolResultPrefix(nxtContent,
|
|
365
|
-
const unmatchedIds =
|
|
385
|
+
if (!hasOrderedToolResultPrefix(nxtContent, validationIds)) {
|
|
386
|
+
const unmatchedIds = validationIds.filter((id, idx) => {
|
|
366
387
|
const block = nxtContent[idx];
|
|
367
388
|
return !(isToolResultBlock(block) && block.tool_use_id === id);
|
|
368
389
|
});
|
|
@@ -659,10 +680,14 @@ export class AnthropicProvider implements Provider {
|
|
|
659
680
|
onEvent?.({ type: "text_delta", text: " " });
|
|
660
681
|
}
|
|
661
682
|
hasSeenTextBlock = true;
|
|
662
|
-
} else if (
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
683
|
+
} else if (
|
|
684
|
+
event.type === "content_block_start" &&
|
|
685
|
+
event.content_block.type === "tool_use"
|
|
686
|
+
) {
|
|
687
|
+
// Reset only for client-side tool_use blocks, which create visual
|
|
688
|
+
// separators in the UI. Server-side tool blocks (server_tool_use,
|
|
689
|
+
// web_search_tool_result) are transparent in the text stream and
|
|
690
|
+
// need the space preserved between surrounding text blocks.
|
|
666
691
|
hasSeenTextBlock = false;
|
|
667
692
|
}
|
|
668
693
|
if (
|
|
@@ -687,6 +712,20 @@ export class AnthropicProvider implements Provider {
|
|
|
687
712
|
type: "server_tool_start",
|
|
688
713
|
name: event.content_block.name,
|
|
689
714
|
toolUseId: event.content_block.id,
|
|
715
|
+
input: (
|
|
716
|
+
event.content_block as { input?: Record<string, unknown> }
|
|
717
|
+
).input ?? {},
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
if (
|
|
721
|
+
event.type === "content_block_start" &&
|
|
722
|
+
event.content_block.type === "web_search_tool_result"
|
|
723
|
+
) {
|
|
724
|
+
onEvent?.({
|
|
725
|
+
type: "server_tool_complete",
|
|
726
|
+
toolUseId: (
|
|
727
|
+
event.content_block as { tool_use_id: string }
|
|
728
|
+
).tool_use_id,
|
|
690
729
|
});
|
|
691
730
|
}
|
|
692
731
|
if (event.type === "content_block_stop") {
|
package/src/providers/retry.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ProviderError } from "../util/errors.js";
|
|
2
|
-
import { getLogger
|
|
2
|
+
import { getLogger } from "../util/logger.js";
|
|
3
3
|
import {
|
|
4
4
|
computeRetryDelay,
|
|
5
5
|
DEFAULT_BASE_DELAY_MS,
|
|
@@ -96,43 +96,17 @@ export class RetryProvider implements Provider {
|
|
|
96
96
|
options?: SendMessageOptions,
|
|
97
97
|
): Promise<ProviderResponse> {
|
|
98
98
|
let lastError: unknown;
|
|
99
|
-
const debug = isDebug();
|
|
100
|
-
|
|
101
|
-
if (debug) {
|
|
102
|
-
log.debug(
|
|
103
|
-
{
|
|
104
|
-
provider: this.name,
|
|
105
|
-
messageCount: messages.length,
|
|
106
|
-
toolCount: tools?.length ?? 0,
|
|
107
|
-
},
|
|
108
|
-
"Provider sendMessage start",
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
99
|
|
|
112
100
|
const normalizedOptions = normalizeSendMessageOptions(this.name, options);
|
|
113
101
|
|
|
114
102
|
for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
|
|
115
103
|
try {
|
|
116
|
-
const start = Date.now();
|
|
117
104
|
const result = await this.inner.sendMessage(
|
|
118
105
|
messages,
|
|
119
106
|
tools,
|
|
120
107
|
systemPrompt,
|
|
121
108
|
normalizedOptions,
|
|
122
109
|
);
|
|
123
|
-
if (debug) {
|
|
124
|
-
log.debug(
|
|
125
|
-
{
|
|
126
|
-
provider: this.name,
|
|
127
|
-
durationMs: Date.now() - start,
|
|
128
|
-
attempt: attempt + 1,
|
|
129
|
-
model: result.model,
|
|
130
|
-
inputTokens: result.usage.inputTokens,
|
|
131
|
-
outputTokens: result.usage.outputTokens,
|
|
132
|
-
},
|
|
133
|
-
"Provider sendMessage success",
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
110
|
return result;
|
|
137
111
|
} catch (error) {
|
|
138
112
|
lastError = error;
|
package/src/providers/types.ts
CHANGED
|
@@ -117,7 +117,13 @@ export type ProviderEvent =
|
|
|
117
117
|
toolUseId: string;
|
|
118
118
|
accumulatedJson: string;
|
|
119
119
|
}
|
|
120
|
-
| {
|
|
120
|
+
| {
|
|
121
|
+
type: "server_tool_start";
|
|
122
|
+
name: string;
|
|
123
|
+
toolUseId: string;
|
|
124
|
+
input: Record<string, unknown>;
|
|
125
|
+
}
|
|
126
|
+
| { type: "server_tool_complete"; toolUseId: string };
|
|
121
127
|
|
|
122
128
|
export interface SendMessageConfig {
|
|
123
129
|
model?: string;
|
package/src/runtime/AGENTS.md
CHANGED
|
@@ -43,6 +43,15 @@ Host file allows the assistant to perform file operations (read, write, edit) on
|
|
|
43
43
|
- `POST /v1/host-file-result` — `{ requestId, content, isError }`
|
|
44
44
|
- **Tracking**: Uses the same `pending-interactions` tracker as approvals and host bash, with `kind: "host_file"`. The endpoint validates the interaction kind before resolving.
|
|
45
45
|
|
|
46
|
+
### Host CU (desktop proxy computer-use execution)
|
|
47
|
+
|
|
48
|
+
Host CU allows the assistant to proxy computer-use actions (screenshots, mouse/keyboard input) to the desktop host via the client, following the same pattern as host bash and host file.
|
|
49
|
+
|
|
50
|
+
- **Discovery**: Clients discover pending host CU requests via SSE events (`host_cu_request`) which include a `requestId`.
|
|
51
|
+
- **Resolution**: Clients execute the CU action on the host and respond via:
|
|
52
|
+
- `POST /v1/host-cu-result` — `{ requestId, axTree?, axDiff?, screenshot?, screenshotWidthPx?, screenshotHeightPx?, screenWidthPt?, screenHeightPt?, executionResult?, executionError?, secondaryWindows?, userGuidance? }`
|
|
53
|
+
- **Tracking**: Uses the same `pending-interactions` tracker as the other host proxy types, with `kind: "host_cu"`. Registration happens in `conversation-routes.ts` and the route handler is in `host-cu-routes.ts`.
|
|
54
|
+
|
|
46
55
|
### Channel approvals (Telegram, Slack)
|
|
47
56
|
|
|
48
57
|
Channel approval flows use `requestId` (not `runId`) as the primary identifier:
|
|
@@ -347,6 +347,12 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
347
347
|
{ endpoint: "skills:DELETE", scopes: ["settings.write"] },
|
|
348
348
|
{ endpoint: "skills:PATCH", scopes: ["settings.write"] },
|
|
349
349
|
|
|
350
|
+
// Memory items
|
|
351
|
+
{ endpoint: "memory-items:GET", scopes: ["settings.read"] },
|
|
352
|
+
{ endpoint: "memory-items:POST", scopes: ["settings.write"] },
|
|
353
|
+
{ endpoint: "memory-items:PATCH", scopes: ["settings.write"] },
|
|
354
|
+
{ endpoint: "memory-items:DELETE", scopes: ["settings.write"] },
|
|
355
|
+
|
|
350
356
|
// Trust rule CRUD management
|
|
351
357
|
{ endpoint: "trust-rules/manage:GET", scopes: ["settings.read"] },
|
|
352
358
|
{ endpoint: "trust-rules/manage:POST", scopes: ["settings.write"] },
|
|
@@ -358,9 +364,6 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
358
364
|
{ endpoint: "computer-use/sessions/abort", scopes: ["chat.write"] },
|
|
359
365
|
{ endpoint: "computer-use/observations", scopes: ["chat.write"] },
|
|
360
366
|
{ endpoint: "computer-use/tasks", scopes: ["chat.write"] },
|
|
361
|
-
{ endpoint: "computer-use/ride-shotgun/start", scopes: ["chat.write"] },
|
|
362
|
-
{ endpoint: "computer-use/ride-shotgun/stop", scopes: ["chat.write"] },
|
|
363
|
-
{ endpoint: "computer-use/ride-shotgun/status", scopes: ["chat.write"] },
|
|
364
367
|
{ endpoint: "computer-use/watch", scopes: ["chat.write"] },
|
|
365
368
|
|
|
366
369
|
// Recordings
|
|
@@ -381,9 +384,6 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
381
384
|
// Delivery ack
|
|
382
385
|
{ endpoint: "channels/delivery-ack", scopes: ["internal.write"] },
|
|
383
386
|
|
|
384
|
-
// MCP
|
|
385
|
-
{ endpoint: "mcp/reload", scopes: ["settings.write"] },
|
|
386
|
-
|
|
387
387
|
// Migrations
|
|
388
388
|
{ endpoint: "migrations/validate", scopes: ["settings.write"] },
|
|
389
389
|
{ endpoint: "migrations/export", scopes: ["settings.write"] },
|
|
@@ -208,43 +208,3 @@ export async function deliverReplyViaCallback(
|
|
|
208
208
|
break;
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Deliver only the attachments from the last assistant message, skipping text.
|
|
214
|
-
* Used when streaming already delivered the text content and only file
|
|
215
|
-
* attachments remain to be sent via the normal delivery path.
|
|
216
|
-
*/
|
|
217
|
-
export async function deliverAttachmentsOnly(
|
|
218
|
-
conversationId: string,
|
|
219
|
-
externalChatId: string,
|
|
220
|
-
callbackUrl: string,
|
|
221
|
-
bearerToken?: string,
|
|
222
|
-
assistantId?: string,
|
|
223
|
-
): Promise<void> {
|
|
224
|
-
const msgs = getMessages(conversationId);
|
|
225
|
-
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
226
|
-
if (msgs[i].role !== "assistant") continue;
|
|
227
|
-
|
|
228
|
-
const linked = attachmentsStore.getAttachmentMetadataForMessage(msgs[i].id);
|
|
229
|
-
if (linked.length === 0) return;
|
|
230
|
-
|
|
231
|
-
const replyAttachments: RuntimeAttachmentMetadata[] = linked.map((a) => ({
|
|
232
|
-
id: a.id,
|
|
233
|
-
filename: a.originalFilename,
|
|
234
|
-
mimeType: a.mimeType,
|
|
235
|
-
sizeBytes: a.sizeBytes,
|
|
236
|
-
kind: a.kind,
|
|
237
|
-
}));
|
|
238
|
-
|
|
239
|
-
await deliverChannelReply(
|
|
240
|
-
callbackUrl,
|
|
241
|
-
{
|
|
242
|
-
chatId: externalChatId,
|
|
243
|
-
attachments: replyAttachments,
|
|
244
|
-
assistantId,
|
|
245
|
-
},
|
|
246
|
-
bearerToken,
|
|
247
|
-
);
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
@@ -31,8 +31,6 @@ export interface ChannelReplyPayload {
|
|
|
31
31
|
ephemeral?: boolean;
|
|
32
32
|
/** Slack user ID — required when `ephemeral` is true. */
|
|
33
33
|
user?: string;
|
|
34
|
-
/** Telegram message_id for editing an existing message instead of sending a new one. */
|
|
35
|
-
messageId?: number;
|
|
36
34
|
/** When provided, instructs the delivery endpoint to update an existing message instead of posting a new one. */
|
|
37
35
|
messageTs?: string;
|
|
38
36
|
/** When true, auto-generate Block Kit blocks from text via textToBlocks(). */
|
|
@@ -45,8 +43,6 @@ export interface ChannelDeliveryResult {
|
|
|
45
43
|
ok: boolean;
|
|
46
44
|
/** The message timestamp returned by the delivery endpoint (e.g. Slack message ts). */
|
|
47
45
|
ts?: string;
|
|
48
|
-
/** The Telegram message_id returned when a new message was sent. */
|
|
49
|
-
messageId?: number;
|
|
50
46
|
}
|
|
51
47
|
|
|
52
48
|
interface ManagedOutboundCallbackContext {
|
|
@@ -100,9 +96,6 @@ export async function deliverChannelReply(
|
|
|
100
96
|
if (typeof responseBody.ts === "string") {
|
|
101
97
|
result.ts = responseBody.ts;
|
|
102
98
|
}
|
|
103
|
-
if (typeof responseBody.messageId === "number") {
|
|
104
|
-
result.messageId = responseBody.messageId;
|
|
105
|
-
}
|
|
106
99
|
} catch {
|
|
107
100
|
// Response may not be JSON for non-Slack channels; that's fine.
|
|
108
101
|
}
|