@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
|
@@ -35,6 +35,7 @@ import * as pendingInteractions from "../../runtime/pending-interactions.js";
|
|
|
35
35
|
import { getSubagentManager } from "../../subagent/index.js";
|
|
36
36
|
import { truncate } from "../../util/truncate.js";
|
|
37
37
|
import { HostBashProxy } from "../host-bash-proxy.js";
|
|
38
|
+
import { HostCuProxy } from "../host-cu-proxy.js";
|
|
38
39
|
import { HostFileProxy } from "../host-file-proxy.js";
|
|
39
40
|
import type {
|
|
40
41
|
CancelRequest,
|
|
@@ -60,7 +61,6 @@ import {
|
|
|
60
61
|
type HandlerContext,
|
|
61
62
|
log,
|
|
62
63
|
pendingStandaloneSecrets,
|
|
63
|
-
wireEscalationHandler,
|
|
64
64
|
} from "./shared.js";
|
|
65
65
|
|
|
66
66
|
/**
|
|
@@ -165,6 +165,12 @@ export function makeEventSender(params: {
|
|
|
165
165
|
conversationId,
|
|
166
166
|
kind: "host_file",
|
|
167
167
|
});
|
|
168
|
+
} else if (event.type === "host_cu_request") {
|
|
169
|
+
pendingInteractions.register(event.requestId, {
|
|
170
|
+
session,
|
|
171
|
+
conversationId,
|
|
172
|
+
kind: "host_cu",
|
|
173
|
+
});
|
|
168
174
|
}
|
|
169
175
|
|
|
170
176
|
ctx.send(event);
|
|
@@ -195,21 +201,6 @@ export function handleConfirmationResponse(
|
|
|
195
201
|
}
|
|
196
202
|
}
|
|
197
203
|
|
|
198
|
-
// Also check computer-use sessions — they have their own PermissionPrompter
|
|
199
|
-
for (const [, cuSession] of ctx.cuSessions) {
|
|
200
|
-
if (cuSession.hasPendingConfirmation(msg.requestId)) {
|
|
201
|
-
cuSession.handleConfirmationResponse(
|
|
202
|
-
msg.requestId,
|
|
203
|
-
msg.decision,
|
|
204
|
-
msg.selectedPattern,
|
|
205
|
-
msg.selectedScope,
|
|
206
|
-
);
|
|
207
|
-
syncCanonicalStatusFromConfirmationDecision(msg.requestId, msg.decision);
|
|
208
|
-
pendingInteractions.resolve(msg.requestId);
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
204
|
log.warn(
|
|
214
205
|
{ requestId: msg.requestId },
|
|
215
206
|
"No session found with pending confirmation for requestId",
|
|
@@ -362,7 +353,6 @@ export async function handleSessionCreate(
|
|
|
362
353
|
maxResponseTokens: msg.maxResponseTokens,
|
|
363
354
|
transport: msg.transport,
|
|
364
355
|
});
|
|
365
|
-
wireEscalationHandler(session, ctx);
|
|
366
356
|
|
|
367
357
|
// Pre-activate skills before sending session_info so they're available
|
|
368
358
|
// for the initial message processing.
|
|
@@ -431,6 +421,11 @@ export async function handleSessionCreate(
|
|
|
431
421
|
pendingInteractions.resolve(requestId);
|
|
432
422
|
});
|
|
433
423
|
session.setHostFileProxy(fileProxy);
|
|
424
|
+
const cuProxy = new HostCuProxy(sendEvent, (requestId) => {
|
|
425
|
+
pendingInteractions.resolve(requestId);
|
|
426
|
+
});
|
|
427
|
+
session.setHostCuProxy(cuProxy);
|
|
428
|
+
session.addPreactivatedSkillId("computer-use");
|
|
434
429
|
}
|
|
435
430
|
session.updateClient(sendEvent, false);
|
|
436
431
|
session
|
|
@@ -492,13 +487,7 @@ export async function switchSession(
|
|
|
492
487
|
// Load the session without rebinding the client — the session stays headless
|
|
493
488
|
await ctx.getOrCreateSession(sessionId);
|
|
494
489
|
} else {
|
|
495
|
-
|
|
496
|
-
// Only wire the escalation handler if one isn't already set — handleTaskSubmit
|
|
497
|
-
// sets a handler with the client's actual screen dimensions, and overwriting it
|
|
498
|
-
// here would replace those dimensions with the daemon's defaults.
|
|
499
|
-
if (!session.hasEscalationHandler()) {
|
|
500
|
-
wireEscalationHandler(session, ctx);
|
|
501
|
-
}
|
|
490
|
+
await ctx.getOrCreateSession(sessionId);
|
|
502
491
|
}
|
|
503
492
|
|
|
504
493
|
return {
|
|
@@ -589,23 +578,24 @@ export function handleCancel(msg: CancelRequest, ctx: HandlerContext): void {
|
|
|
589
578
|
}
|
|
590
579
|
|
|
591
580
|
/**
|
|
592
|
-
* Undo the last message in a session. Returns the removed count, or null if
|
|
581
|
+
* Undo the last message in a session. Returns the removed count, or null if
|
|
582
|
+
* the conversation does not exist. Restores evicted sessions from the database.
|
|
593
583
|
*/
|
|
594
|
-
export function undoLastMessage(
|
|
584
|
+
export async function undoLastMessage(
|
|
595
585
|
sessionId: string,
|
|
596
586
|
ctx: HandlerContext,
|
|
597
|
-
): { removedCount: number } | null {
|
|
598
|
-
|
|
599
|
-
if (!session) {
|
|
587
|
+
): Promise<{ removedCount: number } | null> {
|
|
588
|
+
if (!getConversation(sessionId)) {
|
|
600
589
|
return null;
|
|
601
590
|
}
|
|
591
|
+
const session = await ctx.getOrCreateSession(sessionId);
|
|
602
592
|
ctx.touchSession(sessionId);
|
|
603
593
|
const removedCount = session.undo();
|
|
604
594
|
return { removedCount };
|
|
605
595
|
}
|
|
606
596
|
|
|
607
|
-
export function handleUndo(msg: UndoRequest, ctx: HandlerContext): void {
|
|
608
|
-
const result = undoLastMessage(msg.sessionId, ctx);
|
|
597
|
+
export async function handleUndo(msg: UndoRequest, ctx: HandlerContext): Promise<void> {
|
|
598
|
+
const result = await undoLastMessage(msg.sessionId, ctx);
|
|
609
599
|
if (!result) {
|
|
610
600
|
ctx.send({ type: "error", message: "No active session" });
|
|
611
601
|
return;
|
|
@@ -620,17 +610,18 @@ export function handleUndo(msg: UndoRequest, ctx: HandlerContext): void {
|
|
|
620
610
|
/**
|
|
621
611
|
* Regenerate the last assistant response for a session. The caller provides
|
|
622
612
|
* a `sendEvent` callback for delivering streaming events via HTTP/SSE.
|
|
623
|
-
* Returns null if the
|
|
613
|
+
* Returns null if the conversation does not exist. Restores evicted sessions
|
|
614
|
+
* from the database when needed. Throws on regeneration errors.
|
|
624
615
|
*/
|
|
625
616
|
export async function regenerateResponse(
|
|
626
617
|
sessionId: string,
|
|
627
618
|
ctx: HandlerContext,
|
|
628
619
|
sendEvent: (event: ServerMessage) => void,
|
|
629
620
|
): Promise<{ requestId: string } | null> {
|
|
630
|
-
|
|
631
|
-
if (!session) {
|
|
621
|
+
if (!getConversation(sessionId)) {
|
|
632
622
|
return null;
|
|
633
623
|
}
|
|
624
|
+
const session = await ctx.getOrCreateSession(sessionId);
|
|
634
625
|
ctx.touchSession(sessionId);
|
|
635
626
|
session.updateClient(sendEvent, false);
|
|
636
627
|
const requestId = uuid();
|
|
@@ -661,11 +652,11 @@ export async function handleRegenerate(
|
|
|
661
652
|
msg: RegenerateRequest,
|
|
662
653
|
ctx: HandlerContext,
|
|
663
654
|
): Promise<void> {
|
|
664
|
-
|
|
665
|
-
if (!session) {
|
|
655
|
+
if (!getConversation(msg.sessionId)) {
|
|
666
656
|
ctx.send({ type: "error", message: "No active session" });
|
|
667
657
|
return;
|
|
668
658
|
}
|
|
659
|
+
const session = await ctx.getOrCreateSession(msg.sessionId);
|
|
669
660
|
|
|
670
661
|
const regenerateChannel =
|
|
671
662
|
parseChannelId(session.getTurnChannelContext()?.assistantMessageChannel) ??
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
2
|
-
|
|
3
1
|
import { v4 as uuid } from "uuid";
|
|
4
2
|
|
|
5
3
|
import { getConfig } from "../../config/loader.js";
|
|
6
4
|
import type { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
|
|
7
5
|
import type { SecretPromptResult } from "../../permissions/secret-prompter.js";
|
|
8
|
-
import { RateLimitProvider } from "../../providers/ratelimit.js";
|
|
9
|
-
import { getFailoverProvider } from "../../providers/registry.js";
|
|
10
6
|
import type { AuthContext } from "../../runtime/auth/types.js";
|
|
11
7
|
import type { DebouncerMap } from "../../util/debounce.js";
|
|
12
8
|
import { getLogger } from "../../util/logger.js";
|
|
13
9
|
import { estimateBase64Bytes } from "../assistant-attachments.js";
|
|
14
|
-
import { ComputerUseSession } from "../computer-use-session.js";
|
|
15
10
|
import type {
|
|
16
11
|
ServerMessage,
|
|
17
12
|
SessionTransportMetadata,
|
|
@@ -28,9 +23,6 @@ export const CONFIG_RELOAD_DEBOUNCE_MS = 300;
|
|
|
28
23
|
|
|
29
24
|
const HISTORY_ATTACHMENT_TEXT_LIMIT = 500;
|
|
30
25
|
|
|
31
|
-
export const FALLBACK_SCREEN = { width: 1920, height: 1080 };
|
|
32
|
-
let cachedScreenDims: { width: number; height: number } | null = null;
|
|
33
|
-
|
|
34
26
|
// Module-level map for non-session secret prompts (e.g. publish_page)
|
|
35
27
|
export const pendingStandaloneSecrets = new Map<
|
|
36
28
|
string,
|
|
@@ -150,8 +142,6 @@ export interface SessionCreateOptions {
|
|
|
150
142
|
*/
|
|
151
143
|
export interface HandlerContext {
|
|
152
144
|
sessions: Map<string, Session>;
|
|
153
|
-
cuSessions: Map<string, ComputerUseSession>;
|
|
154
|
-
cuObservationParseSequence: Map<string, number>;
|
|
155
145
|
sharedRequestTimestamps: number[];
|
|
156
146
|
debounceTimers: DebouncerMap;
|
|
157
147
|
suppressConfigReload: boolean;
|
|
@@ -170,126 +160,6 @@ export interface HandlerContext {
|
|
|
170
160
|
heartbeatService?: HeartbeatService;
|
|
171
161
|
}
|
|
172
162
|
|
|
173
|
-
/**
|
|
174
|
-
* Query the main display dimensions via CoreGraphics.
|
|
175
|
-
* Cached after the first successful call; falls back to 1920x1080.
|
|
176
|
-
*/
|
|
177
|
-
export function getScreenDimensions(): { width: number; height: number } {
|
|
178
|
-
if (cachedScreenDims) return cachedScreenDims;
|
|
179
|
-
if (process.platform !== "darwin") return FALLBACK_SCREEN;
|
|
180
|
-
try {
|
|
181
|
-
// Use osascript (JXA) instead of `swift` to avoid the
|
|
182
|
-
// "Install Command Line Developer Tools" popup on fresh macOS installs.
|
|
183
|
-
const out = execSync(
|
|
184
|
-
`osascript -l JavaScript -e 'ObjC.import("AppKit"); var f = $.NSScreen.mainScreen.frame; Math.round(f.size.width) + "x" + Math.round(f.size.height)'`,
|
|
185
|
-
{ timeout: 10_000, encoding: "utf-8" },
|
|
186
|
-
).trim();
|
|
187
|
-
const [w, h] = out.split("x").map(Number);
|
|
188
|
-
if (w > 0 && h > 0) {
|
|
189
|
-
cachedScreenDims = { width: w, height: h };
|
|
190
|
-
return cachedScreenDims;
|
|
191
|
-
}
|
|
192
|
-
} catch (err) {
|
|
193
|
-
log.debug({ err }, "Failed to query screen dimensions, using fallback");
|
|
194
|
-
}
|
|
195
|
-
return FALLBACK_SCREEN;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Wire the escalation handler on a text_qa session so that invoking
|
|
200
|
-
* `computer_use_request_control` creates a CU session and notifies the client.
|
|
201
|
-
*
|
|
202
|
-
* In the HTTP-only world, the escalation handler broadcasts events via
|
|
203
|
-
* `ctx.broadcast` instead of targeting a specific socket.
|
|
204
|
-
*/
|
|
205
|
-
export function wireEscalationHandler(
|
|
206
|
-
session: Session,
|
|
207
|
-
ctx: HandlerContext,
|
|
208
|
-
explicitWidth?: number,
|
|
209
|
-
explicitHeight?: number,
|
|
210
|
-
): void {
|
|
211
|
-
const dims =
|
|
212
|
-
explicitWidth && explicitHeight
|
|
213
|
-
? { width: explicitWidth, height: explicitHeight }
|
|
214
|
-
: getScreenDimensions();
|
|
215
|
-
const screenWidth = dims.width;
|
|
216
|
-
const screenHeight = dims.height;
|
|
217
|
-
session.setEscalationHandler(
|
|
218
|
-
(task: string, sourceSessionId: string): boolean => {
|
|
219
|
-
const cuSessionId = uuid();
|
|
220
|
-
|
|
221
|
-
// Inline CU session creation (previously delegated to deleted handlers/computer-use.ts)
|
|
222
|
-
const existingSession = ctx.cuSessions.get(cuSessionId);
|
|
223
|
-
if (existingSession) {
|
|
224
|
-
existingSession.abort();
|
|
225
|
-
ctx.cuSessions.delete(cuSessionId);
|
|
226
|
-
ctx.cuObservationParseSequence.delete(cuSessionId);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const config = getConfig();
|
|
230
|
-
let provider = getFailoverProvider(config.provider, config.providerOrder);
|
|
231
|
-
const { rateLimit } = config;
|
|
232
|
-
if (
|
|
233
|
-
rateLimit.maxRequestsPerMinute > 0 ||
|
|
234
|
-
rateLimit.maxTokensPerSession > 0
|
|
235
|
-
) {
|
|
236
|
-
provider = new RateLimitProvider(
|
|
237
|
-
provider,
|
|
238
|
-
rateLimit,
|
|
239
|
-
ctx.sharedRequestTimestamps,
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const sendToClient = (serverMsg: ServerMessage) => {
|
|
244
|
-
ctx.send(serverMsg);
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
const sessionRef: { current?: ComputerUseSession } = {};
|
|
248
|
-
const onTerminal = (sid: string) => {
|
|
249
|
-
const current = ctx.cuSessions.get(sid);
|
|
250
|
-
if (sessionRef.current && current && current !== sessionRef.current) {
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
ctx.cuSessions.delete(sid);
|
|
254
|
-
ctx.cuObservationParseSequence.delete(sid);
|
|
255
|
-
log.info(
|
|
256
|
-
{ sessionId: sid },
|
|
257
|
-
"Computer-use session cleaned up after terminal state",
|
|
258
|
-
);
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
const cuSession = new ComputerUseSession(
|
|
262
|
-
cuSessionId,
|
|
263
|
-
task,
|
|
264
|
-
screenWidth,
|
|
265
|
-
screenHeight,
|
|
266
|
-
provider,
|
|
267
|
-
sendToClient,
|
|
268
|
-
"computer_use",
|
|
269
|
-
onTerminal,
|
|
270
|
-
);
|
|
271
|
-
sessionRef.current = cuSession;
|
|
272
|
-
|
|
273
|
-
ctx.cuSessions.set(cuSessionId, cuSession);
|
|
274
|
-
|
|
275
|
-
log.info(
|
|
276
|
-
{ sessionId: cuSessionId, taskLength: task.length },
|
|
277
|
-
"Computer-use session created via escalation",
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
ctx.broadcast({
|
|
281
|
-
type: "task_routed",
|
|
282
|
-
sessionId: cuSessionId,
|
|
283
|
-
interactionType: "computer_use",
|
|
284
|
-
task,
|
|
285
|
-
escalatedFrom: sourceSessionId,
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
return true;
|
|
289
|
-
},
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
163
|
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
294
164
|
return typeof value === "object" && value != null;
|
|
295
165
|
}
|
|
@@ -250,12 +250,20 @@ export interface SkillListItem {
|
|
|
250
250
|
provenance: SkillProvenance;
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
+
/** Sorting rank for provenance-based ordering: first-party first, local last. */
|
|
254
|
+
function provenanceSortRank(p: SkillProvenance): number {
|
|
255
|
+
if (p.kind === "first-party") return 0;
|
|
256
|
+
if (p.kind === "third-party" && p.provider) return 1;
|
|
257
|
+
if (p.kind === "third-party") return 2;
|
|
258
|
+
return 3; // local
|
|
259
|
+
}
|
|
260
|
+
|
|
253
261
|
export function listSkills(_ctx: SkillOperationContext): SkillListItem[] {
|
|
254
262
|
const config = getConfig();
|
|
255
263
|
const catalog = loadSkillCatalog();
|
|
256
264
|
const resolved = resolveSkillStates(catalog, config);
|
|
257
265
|
|
|
258
|
-
|
|
266
|
+
const items = resolved.map((r) => ({
|
|
259
267
|
id: r.summary.id,
|
|
260
268
|
name: r.summary.displayName,
|
|
261
269
|
description: r.summary.description,
|
|
@@ -272,6 +280,17 @@ export function listSkills(_ctx: SkillOperationContext): SkillListItem[] {
|
|
|
272
280
|
userInvocable: r.summary.userInvocable,
|
|
273
281
|
provenance: resolveProvenance(r.summary),
|
|
274
282
|
}));
|
|
283
|
+
|
|
284
|
+
// Sort: first-party > third-party with provider > third-party without > local,
|
|
285
|
+
// alphabetical by name within each tier.
|
|
286
|
+
items.sort((a, b) => {
|
|
287
|
+
const rankDiff =
|
|
288
|
+
provenanceSortRank(a.provenance) - provenanceSortRank(b.provenance);
|
|
289
|
+
if (rankDiff !== 0) return rankDiff;
|
|
290
|
+
return a.name.localeCompare(b.name);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
return items;
|
|
275
294
|
}
|
|
276
295
|
|
|
277
296
|
export function enableSkill(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ContentBlock,
|
|
3
3
|
Message,
|
|
4
|
+
ServerToolUseContent,
|
|
4
5
|
ToolResultContent,
|
|
5
6
|
ToolUseContent,
|
|
6
7
|
} from "../providers/types.js";
|
|
@@ -20,6 +21,11 @@ export interface RepairResult {
|
|
|
20
21
|
const SYNTHETIC_RESULT =
|
|
21
22
|
"<synthesized_result>tool result missing from history</synthesized_result>";
|
|
22
23
|
|
|
24
|
+
const SYNTHETIC_WEB_SEARCH_ERROR = {
|
|
25
|
+
type: "web_search_tool_result_error",
|
|
26
|
+
error_code: "unavailable",
|
|
27
|
+
};
|
|
28
|
+
|
|
23
29
|
export function repairHistory(messages: Message[]): RepairResult {
|
|
24
30
|
const stats: RepairStats = {
|
|
25
31
|
assistantToolResultsMigrated: 0,
|
|
@@ -45,12 +51,15 @@ export function repairHistory(messages: Message[]): RepairResult {
|
|
|
45
51
|
recoveredResults = new Map();
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
// Strip tool_result blocks from assistant messages,
|
|
49
|
-
// so they can be migrated to the correct user message
|
|
54
|
+
// Strip client-side tool_result blocks from assistant messages,
|
|
55
|
+
// preserving them so they can be migrated to the correct user message.
|
|
56
|
+
// Server-side tools (server_tool_use / web_search_tool_result) are
|
|
57
|
+
// self-paired within the assistant message and must NOT be separated.
|
|
50
58
|
const cleanedContent: ContentBlock[] = [];
|
|
51
59
|
const newRecovered = new Map<string, ToolResultContent>();
|
|
52
60
|
for (const block of msg.content) {
|
|
53
61
|
if (block.type === "tool_result") {
|
|
62
|
+
// guard:allow-tool-result-only — only client-side tool_result belongs in recovered; web_search_tool_result stays in the assistant message
|
|
54
63
|
const tr = block as ToolResultContent;
|
|
55
64
|
newRecovered.set(tr.tool_use_id, tr);
|
|
56
65
|
stats.assistantToolResultsMigrated++;
|
|
@@ -59,9 +68,34 @@ export function repairHistory(messages: Message[]): RepairResult {
|
|
|
59
68
|
}
|
|
60
69
|
}
|
|
61
70
|
|
|
71
|
+
// Ensure every server_tool_use has a paired web_search_tool_result
|
|
72
|
+
// in the same assistant message (handles interrupted streams)
|
|
73
|
+
const serverToolIds = new Set(
|
|
74
|
+
cleanedContent
|
|
75
|
+
.filter(
|
|
76
|
+
(b): b is ServerToolUseContent => b.type === "server_tool_use",
|
|
77
|
+
)
|
|
78
|
+
.map((b) => b.id),
|
|
79
|
+
);
|
|
80
|
+
const matchedServerIds = new Set(
|
|
81
|
+
cleanedContent
|
|
82
|
+
.filter((b) => b.type === "web_search_tool_result")
|
|
83
|
+
.map((b) => (b as { tool_use_id: string }).tool_use_id),
|
|
84
|
+
);
|
|
85
|
+
for (const id of serverToolIds) {
|
|
86
|
+
if (!matchedServerIds.has(id)) {
|
|
87
|
+
cleanedContent.push({
|
|
88
|
+
type: "web_search_tool_result",
|
|
89
|
+
tool_use_id: id,
|
|
90
|
+
content: SYNTHETIC_WEB_SEARCH_ERROR,
|
|
91
|
+
});
|
|
92
|
+
stats.missingToolResultsInserted++;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
62
96
|
result.push({ role: "assistant", content: cleanedContent });
|
|
63
97
|
|
|
64
|
-
//
|
|
98
|
+
// Only track client-side tool_use IDs as pending (not server_tool_use)
|
|
65
99
|
pendingToolUseIds = new Set(
|
|
66
100
|
cleanedContent
|
|
67
101
|
.filter((b): b is ToolUseContent => b.type === "tool_use")
|
|
@@ -76,14 +110,28 @@ export function repairHistory(messages: Message[]): RepairResult {
|
|
|
76
110
|
|
|
77
111
|
for (const block of msg.content) {
|
|
78
112
|
if (block.type === "tool_result") {
|
|
113
|
+
// guard:allow-tool-result-only — matches client-side tool_use; web_search_tool_result is handled separately below
|
|
79
114
|
const tr = block as ToolResultContent;
|
|
80
115
|
if (pendingToolUseIds.has(tr.tool_use_id)) {
|
|
81
116
|
matchedIds.add(tr.tool_use_id);
|
|
82
117
|
newContent.push(block);
|
|
83
118
|
} else {
|
|
84
119
|
stats.orphanToolResultsDowngraded++;
|
|
85
|
-
newContent.push(
|
|
120
|
+
newContent.push(downgradeResult(tr));
|
|
86
121
|
}
|
|
122
|
+
} else if (block.type === "web_search_tool_result") {
|
|
123
|
+
// web_search_tool_result in a user message is orphaned — server-side
|
|
124
|
+
// results belong in the assistant message, not here
|
|
125
|
+
stats.orphanToolResultsDowngraded++;
|
|
126
|
+
newContent.push(
|
|
127
|
+
downgradeResult(
|
|
128
|
+
block as {
|
|
129
|
+
type: "web_search_tool_result";
|
|
130
|
+
tool_use_id: string;
|
|
131
|
+
content: unknown;
|
|
132
|
+
},
|
|
133
|
+
),
|
|
134
|
+
);
|
|
87
135
|
} else {
|
|
88
136
|
newContent.push(block);
|
|
89
137
|
}
|
|
@@ -112,11 +160,21 @@ export function repairHistory(messages: Message[]): RepairResult {
|
|
|
112
160
|
pendingToolUseIds = new Set();
|
|
113
161
|
recoveredResults = new Map();
|
|
114
162
|
} else {
|
|
115
|
-
// No pending tool_use — any tool_result here is orphaned
|
|
163
|
+
// No pending tool_use — any tool_result/web_search_tool_result here is orphaned
|
|
116
164
|
const newContent: ContentBlock[] = msg.content.map((block) => {
|
|
117
165
|
if (block.type === "tool_result") {
|
|
118
166
|
stats.orphanToolResultsDowngraded++;
|
|
119
|
-
return
|
|
167
|
+
return downgradeResult(block as ToolResultContent);
|
|
168
|
+
}
|
|
169
|
+
if (block.type === "web_search_tool_result") {
|
|
170
|
+
stats.orphanToolResultsDowngraded++;
|
|
171
|
+
return downgradeResult(
|
|
172
|
+
block as {
|
|
173
|
+
type: "web_search_tool_result";
|
|
174
|
+
tool_use_id: string;
|
|
175
|
+
content: unknown;
|
|
176
|
+
},
|
|
177
|
+
);
|
|
120
178
|
}
|
|
121
179
|
return block;
|
|
122
180
|
});
|
|
@@ -207,9 +265,15 @@ export function deepRepairHistory(messages: Message[]): RepairResult {
|
|
|
207
265
|
return repairHistory(merged);
|
|
208
266
|
}
|
|
209
267
|
|
|
210
|
-
function
|
|
268
|
+
function downgradeResult(tr: {
|
|
269
|
+
type: string;
|
|
270
|
+
tool_use_id: string;
|
|
271
|
+
content?: unknown;
|
|
272
|
+
}): ContentBlock {
|
|
273
|
+
const content =
|
|
274
|
+
tr.type === "tool_result" ? tr.content : "[web search result]"; // guard:allow-tool-result-only — distinguishes content format between the two types
|
|
211
275
|
return {
|
|
212
276
|
type: "text",
|
|
213
|
-
text: `[orphaned
|
|
277
|
+
text: `[orphaned ${tr.type} for ${tr.tool_use_id}]: ${content}`,
|
|
214
278
|
};
|
|
215
279
|
}
|