@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
|
@@ -118,6 +118,8 @@ function makeIdleSession(opts?: {
|
|
|
118
118
|
updateClient: () => {},
|
|
119
119
|
setHostBashProxy: () => {},
|
|
120
120
|
setHostFileProxy: () => {},
|
|
121
|
+
setHostCuProxy: () => {},
|
|
122
|
+
addPreactivatedSkillId: () => {},
|
|
121
123
|
enqueueMessage: () => ({ queued: false, requestId: "noop" }),
|
|
122
124
|
hasAnyPendingConfirmation: () => false,
|
|
123
125
|
runAgentLoop: async (
|
|
@@ -181,6 +183,8 @@ function makeConfirmationEmittingSession(opts?: {
|
|
|
181
183
|
updateClient: () => {},
|
|
182
184
|
setHostBashProxy: () => {},
|
|
183
185
|
setHostFileProxy: () => {},
|
|
186
|
+
setHostCuProxy: () => {},
|
|
187
|
+
addPreactivatedSkillId: () => {},
|
|
184
188
|
enqueueMessage: () => ({ queued: false, requestId: "noop" }),
|
|
185
189
|
hasAnyPendingConfirmation: () => false,
|
|
186
190
|
runAgentLoop: async (
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
estimateBase64Bytes,
|
|
11
11
|
inferMimeType,
|
|
12
12
|
MAX_ASSISTANT_ATTACHMENT_BYTES,
|
|
13
|
-
MAX_ASSISTANT_ATTACHMENTS,
|
|
14
13
|
validateDrafts,
|
|
15
14
|
} from "../daemon/assistant-attachments.js";
|
|
16
15
|
|
|
@@ -163,33 +162,27 @@ describe("validateDrafts", () => {
|
|
|
163
162
|
expect(result.warnings[0]).toContain("exceeds");
|
|
164
163
|
});
|
|
165
164
|
|
|
166
|
-
test("
|
|
167
|
-
const drafts = Array.from(
|
|
168
|
-
{
|
|
169
|
-
(_, i) => makeDraft({ filename: `file-${i}.txt` }),
|
|
165
|
+
test("accepts many drafts without count limit", () => {
|
|
166
|
+
const drafts = Array.from({ length: 20 }, (_, i) =>
|
|
167
|
+
makeDraft({ filename: `file-${i}.txt` }),
|
|
170
168
|
);
|
|
171
169
|
const result = validateDrafts(drafts);
|
|
172
|
-
expect(result.accepted).toHaveLength(
|
|
173
|
-
expect(result.warnings).toHaveLength(
|
|
174
|
-
expect(result.warnings[0]).toContain(
|
|
175
|
-
`file-${MAX_ASSISTANT_ATTACHMENTS}.txt`,
|
|
176
|
-
);
|
|
177
|
-
expect(result.warnings[0]).toContain("exceeded maximum");
|
|
170
|
+
expect(result.accepted).toHaveLength(20);
|
|
171
|
+
expect(result.warnings).toHaveLength(0);
|
|
178
172
|
});
|
|
179
173
|
|
|
180
|
-
test("rejects oversized
|
|
174
|
+
test("rejects oversized while accepting all valid drafts", () => {
|
|
181
175
|
const drafts = [
|
|
182
176
|
makeDraft({
|
|
183
177
|
filename: "big.bin",
|
|
184
178
|
sizeBytes: MAX_ASSISTANT_ATTACHMENT_BYTES + 1,
|
|
185
179
|
}),
|
|
186
|
-
...Array.from({ length:
|
|
180
|
+
...Array.from({ length: 10 }, (_, i) =>
|
|
187
181
|
makeDraft({ filename: `ok-${i}.txt` }),
|
|
188
182
|
),
|
|
189
183
|
];
|
|
190
184
|
const result = validateDrafts(drafts);
|
|
191
|
-
|
|
192
|
-
expect(result.accepted).toHaveLength(MAX_ASSISTANT_ATTACHMENTS);
|
|
185
|
+
expect(result.accepted).toHaveLength(10);
|
|
193
186
|
expect(result.warnings).toHaveLength(1);
|
|
194
187
|
expect(result.warnings[0]).toContain("big.bin");
|
|
195
188
|
});
|
|
@@ -431,11 +424,8 @@ describe("contentBlocksToDrafts", () => {
|
|
|
431
424
|
// ---------------------------------------------------------------------------
|
|
432
425
|
|
|
433
426
|
describe("validateDrafts with reversed tool drafts", () => {
|
|
434
|
-
test("
|
|
435
|
-
|
|
436
|
-
// After reversing, the most recent (highest index) should appear first
|
|
437
|
-
// and win the MAX_ASSISTANT_ATTACHMENTS cap.
|
|
438
|
-
const totalScreenshots = MAX_ASSISTANT_ATTACHMENTS + 3;
|
|
427
|
+
test("all tool screenshots accepted after reversing", () => {
|
|
428
|
+
const totalScreenshots = 8;
|
|
439
429
|
const toolDrafts = Array.from({ length: totalScreenshots }, (_, i) =>
|
|
440
430
|
makeDraft({
|
|
441
431
|
sourceType: "tool_block",
|
|
@@ -446,23 +436,11 @@ describe("validateDrafts with reversed tool drafts", () => {
|
|
|
446
436
|
}),
|
|
447
437
|
);
|
|
448
438
|
|
|
449
|
-
// Reverse to prioritize most recent
|
|
450
439
|
toolDrafts.reverse();
|
|
451
440
|
|
|
452
441
|
const result = validateDrafts(toolDrafts);
|
|
453
|
-
expect(result.accepted).toHaveLength(
|
|
454
|
-
|
|
455
|
-
// The accepted drafts should be the most recent screenshots (highest step numbers)
|
|
456
|
-
const acceptedFilenames = result.accepted.map((d) => d.filename);
|
|
457
|
-
for (let i = 0; i < MAX_ASSISTANT_ATTACHMENTS; i++) {
|
|
458
|
-
expect(acceptedFilenames[i]).toBe(
|
|
459
|
-
`screenshot-step-${totalScreenshots - 1 - i}.png`,
|
|
460
|
-
);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// The oldest screenshots should be dropped
|
|
464
|
-
expect(result.warnings).toHaveLength(3);
|
|
465
|
-
expect(result.warnings[0]).toContain("screenshot-step-2.png");
|
|
442
|
+
expect(result.accepted).toHaveLength(totalScreenshots);
|
|
443
|
+
expect(result.warnings).toHaveLength(0);
|
|
466
444
|
});
|
|
467
445
|
});
|
|
468
446
|
|
|
@@ -170,29 +170,6 @@ describe("assistant feature flag guard", () => {
|
|
|
170
170
|
// Test: registry entries have required fields
|
|
171
171
|
// ---------------------------------------------------------------------------
|
|
172
172
|
|
|
173
|
-
// ---------------------------------------------------------------------------
|
|
174
|
-
// Test: bundled registry copy stays in sync with canonical meta/ copy
|
|
175
|
-
// ---------------------------------------------------------------------------
|
|
176
|
-
|
|
177
|
-
test("bundled assistant/src/config/feature-flag-registry.json matches canonical meta/ copy", () => {
|
|
178
|
-
const canonicalPath = getRegistryPath();
|
|
179
|
-
const bundledPath = join(
|
|
180
|
-
process.cwd(),
|
|
181
|
-
"src",
|
|
182
|
-
"config",
|
|
183
|
-
"feature-flag-registry.json",
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
const canonical = JSON.parse(readFileSync(canonicalPath, "utf-8"));
|
|
187
|
-
const bundled = JSON.parse(readFileSync(bundledPath, "utf-8"));
|
|
188
|
-
|
|
189
|
-
expect(bundled).toEqual(canonical);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
// ---------------------------------------------------------------------------
|
|
193
|
-
// Test: registry entries have required fields
|
|
194
|
-
// ---------------------------------------------------------------------------
|
|
195
|
-
|
|
196
173
|
test("all assistant-scope entries in the unified registry have required fields", () => {
|
|
197
174
|
const registry = loadRegistry();
|
|
198
175
|
const assistantFlags = registry.flags.filter(
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
* `isAssistantFeatureFlagEnabled('<key>', ...)` in production code must be
|
|
11
11
|
* declared in the unified registry. This keeps flag usage declarative while
|
|
12
12
|
* allowing skills to exist without corresponding feature flags.
|
|
13
|
+
*
|
|
14
|
+
* 3. Indirect key coverage: all `feature_flags.<id>.enabled` string literals
|
|
15
|
+
* anywhere in production code (maps, constants, variables, etc.) must be
|
|
16
|
+
* declared in the unified registry. This catches indirect key patterns that
|
|
17
|
+
* Guard 2 would miss, such as flag keys stored in lookup maps or constants.
|
|
13
18
|
*/
|
|
14
19
|
|
|
15
20
|
import { execSync } from "node:child_process";
|
|
@@ -197,3 +202,74 @@ describe("assistant feature flag declaration coverage guard", () => {
|
|
|
197
202
|
}
|
|
198
203
|
});
|
|
199
204
|
});
|
|
205
|
+
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
// Guard 3: Indirect key coverage — flag key literals anywhere in production code
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
describe("assistant feature flag indirect key coverage guard", () => {
|
|
211
|
+
test("all feature_flags.<id>.enabled string literals in production code are declared in the unified registry", () => {
|
|
212
|
+
const repoRoot = getRepoRoot();
|
|
213
|
+
|
|
214
|
+
// Load the unified registry and extract all declared keys (any scope)
|
|
215
|
+
const registry = loadRegistry();
|
|
216
|
+
const declaredKeys = new Set(registry.flags.map((f) => f.key));
|
|
217
|
+
|
|
218
|
+
// Search for any string literal matching the canonical key pattern
|
|
219
|
+
// in production .ts files under assistant/src/ and gateway/src/.
|
|
220
|
+
// This catches keys in maps, constants, variables, or any other
|
|
221
|
+
// indirect patterns that Guard 2 would miss.
|
|
222
|
+
let grepOutput = "";
|
|
223
|
+
try {
|
|
224
|
+
grepOutput = execSync(
|
|
225
|
+
`git grep -nE "feature_flags\\.[a-z0-9_-]+\\.enabled\\b" -- 'assistant/src/**/*.ts' 'gateway/src/**/*.ts'`,
|
|
226
|
+
{ encoding: "utf-8", cwd: repoRoot },
|
|
227
|
+
).trim();
|
|
228
|
+
} catch (err) {
|
|
229
|
+
// Exit code 1 means no matches — happy path
|
|
230
|
+
if ((err as { status?: number }).status === 1) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
throw err;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const keyPattern = /feature_flags\.[a-z0-9_-]+\.enabled\b/g;
|
|
237
|
+
const undeclared: string[] = [];
|
|
238
|
+
|
|
239
|
+
for (const line of grepOutput.split("\n")) {
|
|
240
|
+
if (!line) continue;
|
|
241
|
+
|
|
242
|
+
// Format: "file:line:content"
|
|
243
|
+
const colonIdx = line.indexOf(":");
|
|
244
|
+
if (colonIdx === -1) continue;
|
|
245
|
+
const filePath = line.slice(0, colonIdx);
|
|
246
|
+
|
|
247
|
+
// Skip test files
|
|
248
|
+
if (isTestFile(filePath)) continue;
|
|
249
|
+
|
|
250
|
+
// Extract all key occurrences from this line
|
|
251
|
+
const content = line.slice(colonIdx + 1);
|
|
252
|
+
for (const match of content.matchAll(keyPattern)) {
|
|
253
|
+
const key = match[0];
|
|
254
|
+
if (!declaredKeys.has(key)) {
|
|
255
|
+
undeclared.push(`${filePath}: ${key}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (undeclared.length > 0) {
|
|
261
|
+
const message = [
|
|
262
|
+
"Found feature_flags.<id>.enabled string literals in production code that are NOT declared in the unified registry.",
|
|
263
|
+
"This catches indirect flag key usage (maps, constants, variables) that the direct-call guard misses.",
|
|
264
|
+
`Registry: meta/feature-flags/feature-flag-registry.json`,
|
|
265
|
+
"",
|
|
266
|
+
"Undeclared keys:",
|
|
267
|
+
...undeclared.map((k) => ` - ${k}`),
|
|
268
|
+
"",
|
|
269
|
+
"To fix: add the missing key(s) to the unified registry, or remove the stale reference.",
|
|
270
|
+
].join("\n");
|
|
271
|
+
|
|
272
|
+
expect(undeclared, message).toEqual([]);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
});
|
|
@@ -55,10 +55,10 @@ describe("browser skill cutover — startup tool payload", () => {
|
|
|
55
55
|
const definitions = getAllToolDefinitions();
|
|
56
56
|
const serialized = JSON.stringify(definitions);
|
|
57
57
|
// Startup payload is ~22 000 chars without browser tools.
|
|
58
|
-
// Floor at
|
|
58
|
+
// Floor at 14 000 catches accidental wholesale removal; ceiling at 35 000
|
|
59
59
|
// gives headroom while still catching browser tool leakage
|
|
60
60
|
// (~4 640 chars would push it past the ceiling).
|
|
61
|
-
expect(serialized.length).toBeGreaterThan(
|
|
61
|
+
expect(serialized.length).toBeGreaterThan(14_000);
|
|
62
62
|
expect(serialized.length).toBeLessThan(35_000);
|
|
63
63
|
});
|
|
64
64
|
|
|
@@ -26,11 +26,13 @@ mock.module("../util/logger.js", () => ({
|
|
|
26
26
|
import {
|
|
27
27
|
createCanonicalGuardianDelivery,
|
|
28
28
|
createCanonicalGuardianRequest,
|
|
29
|
+
expireAllPendingCanonicalRequests,
|
|
29
30
|
getCanonicalGuardianRequest,
|
|
30
31
|
listCanonicalGuardianDeliveries,
|
|
31
32
|
listCanonicalGuardianRequests,
|
|
32
33
|
listPendingCanonicalGuardianRequestsByDestinationChat,
|
|
33
34
|
listPendingCanonicalGuardianRequestsByDestinationConversation,
|
|
35
|
+
listPendingRequestsByConversationScope,
|
|
34
36
|
resolveCanonicalGuardianRequest,
|
|
35
37
|
updateCanonicalGuardianDelivery,
|
|
36
38
|
updateCanonicalGuardianRequest,
|
|
@@ -717,4 +719,97 @@ describe("canonical-guardian-store", () => {
|
|
|
717
719
|
);
|
|
718
720
|
expect(pending).toHaveLength(0);
|
|
719
721
|
});
|
|
722
|
+
|
|
723
|
+
// ── listPendingRequestsByConversationScope expiry filtering ─────────
|
|
724
|
+
|
|
725
|
+
test("listPendingRequestsByConversationScope excludes expired requests", () => {
|
|
726
|
+
// Create a pending request that has already expired
|
|
727
|
+
createCanonicalGuardianRequest({
|
|
728
|
+
kind: "tool_approval",
|
|
729
|
+
sourceType: "desktop",
|
|
730
|
+
conversationId: "conv-scope-1",
|
|
731
|
+
guardianPrincipalId: TEST_PRINCIPAL,
|
|
732
|
+
expiresAt: new Date(Date.now() - 10_000).toISOString(),
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
// Create a pending request that has not expired
|
|
736
|
+
const unexpired = createCanonicalGuardianRequest({
|
|
737
|
+
kind: "tool_approval",
|
|
738
|
+
sourceType: "desktop",
|
|
739
|
+
conversationId: "conv-scope-1",
|
|
740
|
+
guardianPrincipalId: TEST_PRINCIPAL,
|
|
741
|
+
expiresAt: new Date(Date.now() + 60_000).toISOString(),
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
const results = listPendingRequestsByConversationScope("conv-scope-1");
|
|
745
|
+
expect(results).toHaveLength(1);
|
|
746
|
+
expect(results[0].id).toBe(unexpired.id);
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
test("listPendingRequestsByConversationScope includes requests with no expiresAt", () => {
|
|
750
|
+
const noExpiry = createCanonicalGuardianRequest({
|
|
751
|
+
kind: "tool_approval",
|
|
752
|
+
sourceType: "desktop",
|
|
753
|
+
conversationId: "conv-scope-2",
|
|
754
|
+
guardianPrincipalId: TEST_PRINCIPAL,
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
const results = listPendingRequestsByConversationScope("conv-scope-2");
|
|
758
|
+
expect(results).toHaveLength(1);
|
|
759
|
+
expect(results[0].id).toBe(noExpiry.id);
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
// ── expireAllPendingCanonicalRequests ───────────────────────────────
|
|
763
|
+
|
|
764
|
+
test("expireAllPendingCanonicalRequests transitions all pending to expired", () => {
|
|
765
|
+
const req1 = createCanonicalGuardianRequest({
|
|
766
|
+
kind: "tool_approval",
|
|
767
|
+
sourceType: "desktop",
|
|
768
|
+
conversationId: "conv-bulk-1",
|
|
769
|
+
guardianPrincipalId: TEST_PRINCIPAL,
|
|
770
|
+
expiresAt: new Date(Date.now() + 60_000).toISOString(),
|
|
771
|
+
});
|
|
772
|
+
const req2 = createCanonicalGuardianRequest({
|
|
773
|
+
kind: "tool_approval",
|
|
774
|
+
sourceType: "channel",
|
|
775
|
+
conversationId: "conv-bulk-2",
|
|
776
|
+
guardianPrincipalId: TEST_PRINCIPAL,
|
|
777
|
+
expiresAt: new Date(Date.now() + 60_000).toISOString(),
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
const count = expireAllPendingCanonicalRequests();
|
|
781
|
+
expect(count).toBe(2);
|
|
782
|
+
|
|
783
|
+
expect(getCanonicalGuardianRequest(req1.id)!.status).toBe("expired");
|
|
784
|
+
expect(getCanonicalGuardianRequest(req2.id)!.status).toBe("expired");
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
test("expireAllPendingCanonicalRequests does not affect already-resolved requests", () => {
|
|
788
|
+
const approved = createCanonicalGuardianRequest({
|
|
789
|
+
kind: "tool_approval",
|
|
790
|
+
sourceType: "desktop",
|
|
791
|
+
conversationId: "conv-bulk-3",
|
|
792
|
+
guardianPrincipalId: TEST_PRINCIPAL,
|
|
793
|
+
});
|
|
794
|
+
updateCanonicalGuardianRequest(approved.id, { status: "approved" });
|
|
795
|
+
|
|
796
|
+
const denied = createCanonicalGuardianRequest({
|
|
797
|
+
kind: "tool_approval",
|
|
798
|
+
sourceType: "desktop",
|
|
799
|
+
conversationId: "conv-bulk-3",
|
|
800
|
+
guardianPrincipalId: TEST_PRINCIPAL,
|
|
801
|
+
});
|
|
802
|
+
updateCanonicalGuardianRequest(denied.id, { status: "denied" });
|
|
803
|
+
|
|
804
|
+
const count = expireAllPendingCanonicalRequests();
|
|
805
|
+
expect(count).toBe(0);
|
|
806
|
+
|
|
807
|
+
expect(getCanonicalGuardianRequest(approved.id)!.status).toBe("approved");
|
|
808
|
+
expect(getCanonicalGuardianRequest(denied.id)!.status).toBe("denied");
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
test("expireAllPendingCanonicalRequests returns 0 when no pending requests exist", () => {
|
|
812
|
+
const count = expireAllPendingCanonicalRequests();
|
|
813
|
+
expect(count).toBe(0);
|
|
814
|
+
});
|
|
720
815
|
});
|
|
@@ -1305,8 +1305,6 @@ function createMockCtx(): {
|
|
|
1305
1305
|
let captured: ChannelVerificationSessionResponse | null = null;
|
|
1306
1306
|
const ctx = {
|
|
1307
1307
|
sessions: new Map(),
|
|
1308
|
-
cuSessions: new Map(),
|
|
1309
|
-
cuObservationParseSequence: new Map(),
|
|
1310
1308
|
sharedRequestTimestamps: [],
|
|
1311
1309
|
debounceTimers: {
|
|
1312
1310
|
schedule: () => {},
|
|
@@ -11,7 +11,6 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
|
11
11
|
// Mocks — must be set up before importing the service
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
|
|
14
|
-
let mockTwilioPhoneNumberEnv: string | undefined;
|
|
15
14
|
let mockRawConfig: Record<string, unknown> | undefined;
|
|
16
15
|
let mockSecureKeys: Record<string, string>;
|
|
17
16
|
let mockHasTwilioCredentials: boolean;
|
|
@@ -23,16 +22,27 @@ mock.module("../calls/twilio-rest.js", () => ({
|
|
|
23
22
|
getTollFreeVerificationStatus: async () => null,
|
|
24
23
|
}));
|
|
25
24
|
|
|
26
|
-
mock.module("../config/env.js", () => ({
|
|
27
|
-
getTwilioPhoneNumberEnv: () => mockTwilioPhoneNumberEnv,
|
|
28
|
-
}));
|
|
25
|
+
mock.module("../config/env.js", () => ({}));
|
|
29
26
|
|
|
30
27
|
mock.module("../config/loader.js", () => ({
|
|
31
28
|
loadRawConfig: () => mockRawConfig,
|
|
29
|
+
loadConfig: () => {
|
|
30
|
+
const raw = mockRawConfig ?? {};
|
|
31
|
+
const wa = (raw.whatsapp ?? {}) as Record<string, unknown>;
|
|
32
|
+
const tw = (raw.twilio ?? {}) as Record<string, unknown>;
|
|
33
|
+
return {
|
|
34
|
+
twilio: { phoneNumber: (tw.phoneNumber as string) ?? "" },
|
|
35
|
+
whatsapp: { phoneNumber: (wa.phoneNumber as string) ?? "" },
|
|
36
|
+
};
|
|
37
|
+
},
|
|
32
38
|
getConfig: () => {
|
|
33
39
|
const raw = mockRawConfig ?? {};
|
|
34
40
|
const wa = (raw.whatsapp ?? {}) as Record<string, unknown>;
|
|
35
|
-
|
|
41
|
+
const tw = (raw.twilio ?? {}) as Record<string, unknown>;
|
|
42
|
+
return {
|
|
43
|
+
twilio: { phoneNumber: (tw.phoneNumber as string) ?? "" },
|
|
44
|
+
whatsapp: { phoneNumber: (wa.phoneNumber as string) ?? "" },
|
|
45
|
+
};
|
|
36
46
|
},
|
|
37
47
|
invalidateConfigCache: () => {},
|
|
38
48
|
}));
|
|
@@ -60,7 +70,6 @@ import { credentialKey } from "../security/credential-key.js";
|
|
|
60
70
|
|
|
61
71
|
describe("channel readiness routes — email and WhatsApp probes", () => {
|
|
62
72
|
beforeEach(() => {
|
|
63
|
-
mockTwilioPhoneNumberEnv = undefined;
|
|
64
73
|
mockRawConfig = undefined;
|
|
65
74
|
mockSecureKeys = {};
|
|
66
75
|
mockHasTwilioCredentials = false;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
let
|
|
3
|
+
let mockTwilioPhoneNumber: string | undefined;
|
|
4
4
|
let mockRawConfig: Record<string, unknown> | undefined;
|
|
5
5
|
let mockSecureKeys: Record<string, string>;
|
|
6
6
|
let mockHasTwilioCredentials: boolean;
|
|
@@ -27,16 +27,17 @@ mock.module("../channels/config.js", () => ({
|
|
|
27
27
|
}),
|
|
28
28
|
}));
|
|
29
29
|
|
|
30
|
-
mock.module("../config/env.js", () => ({
|
|
31
|
-
getTwilioPhoneNumberEnv: () => mockTwilioPhoneNumberEnv,
|
|
32
|
-
}));
|
|
30
|
+
mock.module("../config/env.js", () => ({}));
|
|
33
31
|
|
|
34
32
|
mock.module("../config/loader.js", () => ({
|
|
35
33
|
loadRawConfig: () => mockRawConfig,
|
|
34
|
+
loadConfig: () => ({
|
|
35
|
+
twilio: { phoneNumber: mockTwilioPhoneNumber ?? "" },
|
|
36
|
+
whatsapp: { phoneNumber: "" },
|
|
37
|
+
}),
|
|
36
38
|
getConfig: () => ({
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
},
|
|
39
|
+
twilio: { phoneNumber: mockTwilioPhoneNumber ?? "" },
|
|
40
|
+
whatsapp: { phoneNumber: "" },
|
|
40
41
|
}),
|
|
41
42
|
}));
|
|
42
43
|
|
|
@@ -100,7 +101,7 @@ describe("ChannelReadinessService", () => {
|
|
|
100
101
|
|
|
101
102
|
beforeEach(() => {
|
|
102
103
|
service = new ChannelReadinessService();
|
|
103
|
-
|
|
104
|
+
mockTwilioPhoneNumber = undefined;
|
|
104
105
|
mockRawConfig = undefined;
|
|
105
106
|
mockSecureKeys = {};
|
|
106
107
|
mockHasTwilioCredentials = false;
|
|
@@ -406,7 +407,7 @@ describe("ChannelReadinessService", () => {
|
|
|
406
407
|
|
|
407
408
|
test("voice readiness includes gateway_health when ingress is configured", async () => {
|
|
408
409
|
mockHasTwilioCredentials = true;
|
|
409
|
-
|
|
410
|
+
mockTwilioPhoneNumber = "+15550001111";
|
|
410
411
|
mockRawConfig = {
|
|
411
412
|
ingress: {
|
|
412
413
|
enabled: true,
|
|
@@ -135,9 +135,7 @@ registerTool(mockBundledSkillTool);
|
|
|
135
135
|
// Register CU tools so classifyRisk returns their declared Low risk level
|
|
136
136
|
// instead of falling through to Medium (unknown tool).
|
|
137
137
|
import { registerComputerUseActionTools } from "../tools/computer-use/registry.js";
|
|
138
|
-
import { requestComputerControlTool } from "../tools/computer-use/request-computer-control.js";
|
|
139
138
|
registerComputerUseActionTools();
|
|
140
|
-
registerTool(requestComputerControlTool);
|
|
141
139
|
|
|
142
140
|
function writeSkill(
|
|
143
141
|
skillId: string,
|
|
@@ -673,14 +671,14 @@ describe("Permission Checker", () => {
|
|
|
673
671
|
expect(result.decision).toBe("allow");
|
|
674
672
|
});
|
|
675
673
|
|
|
676
|
-
test("file_write within workspace with no rule →
|
|
674
|
+
test("file_write within workspace with no rule → prompt (medium risk bypasses workspace auto-allow)", async () => {
|
|
677
675
|
const result = await check(
|
|
678
676
|
"file_write",
|
|
679
677
|
{ path: "/tmp/file.txt" },
|
|
680
678
|
"/tmp",
|
|
681
679
|
);
|
|
682
|
-
expect(result.decision).toBe("
|
|
683
|
-
expect(result.reason).toContain("
|
|
680
|
+
expect(result.decision).toBe("prompt");
|
|
681
|
+
expect(result.reason).toContain("medium risk");
|
|
684
682
|
});
|
|
685
683
|
|
|
686
684
|
test("file_write outside workspace with no rule → prompt", async () => {
|
|
@@ -897,16 +895,16 @@ describe("Permission Checker", () => {
|
|
|
897
895
|
);
|
|
898
896
|
});
|
|
899
897
|
|
|
900
|
-
test("
|
|
898
|
+
test("computer_use_observe prompts by default via computer-use ask rule", async () => {
|
|
901
899
|
const result = await check(
|
|
902
|
-
"
|
|
903
|
-
{
|
|
900
|
+
"computer_use_observe",
|
|
901
|
+
{ reason: "Check current screen state before acting" },
|
|
904
902
|
"/tmp",
|
|
905
903
|
);
|
|
906
904
|
expect(result.decision).toBe("prompt");
|
|
907
905
|
expect(result.reason).toContain("ask rule");
|
|
908
906
|
expect(result.matchedRule?.id).toBe(
|
|
909
|
-
"default:ask-
|
|
907
|
+
"default:ask-computer_use_observe-global",
|
|
910
908
|
);
|
|
911
909
|
});
|
|
912
910
|
|
|
@@ -4407,11 +4405,6 @@ describe("computer-use tool permission defaults", () => {
|
|
|
4407
4405
|
expect(risk).toBe(RiskLevel.Low);
|
|
4408
4406
|
}
|
|
4409
4407
|
});
|
|
4410
|
-
|
|
4411
|
-
test("computer_use_request_control classifies as Low risk", async () => {
|
|
4412
|
-
const risk = await classifyRisk("computer_use_request_control", {});
|
|
4413
|
-
expect(risk).toBe(RiskLevel.Low);
|
|
4414
|
-
});
|
|
4415
4408
|
});
|
|
4416
4409
|
|
|
4417
4410
|
// ---------------------------------------------------------------------------
|
|
@@ -4588,24 +4581,24 @@ describe("workspace mode — auto-allow workspace-scoped operations", () => {
|
|
|
4588
4581
|
expect(result.reason).toContain("Workspace mode");
|
|
4589
4582
|
});
|
|
4590
4583
|
|
|
4591
|
-
test("file_write within workspace →
|
|
4584
|
+
test("file_write within workspace → prompt (Medium risk bypasses workspace auto-allow)", async () => {
|
|
4592
4585
|
const result = await check(
|
|
4593
4586
|
"file_write",
|
|
4594
4587
|
{ file_path: "/home/user/my-project/src/index.ts" },
|
|
4595
4588
|
workspaceDir,
|
|
4596
4589
|
);
|
|
4597
|
-
expect(result.decision).toBe("
|
|
4598
|
-
expect(result.reason).toContain("
|
|
4590
|
+
expect(result.decision).toBe("prompt");
|
|
4591
|
+
expect(result.reason).toContain("medium risk");
|
|
4599
4592
|
});
|
|
4600
4593
|
|
|
4601
|
-
test("file_edit within workspace →
|
|
4594
|
+
test("file_edit within workspace → prompt (Medium risk bypasses workspace auto-allow)", async () => {
|
|
4602
4595
|
const result = await check(
|
|
4603
4596
|
"file_edit",
|
|
4604
4597
|
{ file_path: "/home/user/my-project/src/index.ts" },
|
|
4605
4598
|
workspaceDir,
|
|
4606
4599
|
);
|
|
4607
|
-
expect(result.decision).toBe("
|
|
4608
|
-
expect(result.reason).toContain("
|
|
4600
|
+
expect(result.decision).toBe("prompt");
|
|
4601
|
+
expect(result.reason).toContain("medium risk");
|
|
4609
4602
|
});
|
|
4610
4603
|
|
|
4611
4604
|
// ── file operations outside workspace follow risk-based fallback ──
|
|
@@ -29,7 +29,7 @@ const manifestPath = resolve(
|
|
|
29
29
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
30
30
|
|
|
31
31
|
describe("computer-use skill manifest regression", () => {
|
|
32
|
-
test("manifest has exactly
|
|
32
|
+
test("manifest has exactly 11 tools", () => {
|
|
33
33
|
expect(manifest.tools).toHaveLength(COMPUTER_USE_TOOL_COUNT);
|
|
34
34
|
});
|
|
35
35
|
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
computerUseTypeTextTool,
|
|
14
14
|
computerUseWaitTool,
|
|
15
15
|
} from "../tools/computer-use/definitions.js";
|
|
16
|
-
import { requestComputerControlTool } from "../tools/computer-use/request-computer-control.js";
|
|
17
16
|
import { forwardComputerUseProxyTool } from "../tools/computer-use/skill-proxy-bridge.js";
|
|
18
17
|
import type { ToolContext } from "../tools/types.js";
|
|
19
18
|
|
|
@@ -40,22 +39,20 @@ const ctx: ToolContext = {
|
|
|
40
39
|
// ── Tool definitions ────────────────────────────────────────────────
|
|
41
40
|
|
|
42
41
|
describe("computer-use tool definitions", () => {
|
|
43
|
-
test("allComputerUseTools contains
|
|
44
|
-
expect(allComputerUseTools.length).toBe(
|
|
42
|
+
test("allComputerUseTools contains 11 tools", () => {
|
|
43
|
+
expect(allComputerUseTools.length).toBe(11);
|
|
45
44
|
});
|
|
46
45
|
|
|
47
46
|
test("all tools have proxy execution mode", () => {
|
|
48
47
|
for (const tool of allComputerUseTools) {
|
|
49
48
|
expect(tool.executionMode).toBe("proxy");
|
|
50
49
|
}
|
|
51
|
-
expect(requestComputerControlTool.executionMode).toBe("proxy");
|
|
52
50
|
});
|
|
53
51
|
|
|
54
52
|
test("all tools belong to computer-use category", () => {
|
|
55
53
|
for (const tool of allComputerUseTools) {
|
|
56
54
|
expect(tool.category).toBe("computer-use");
|
|
57
55
|
}
|
|
58
|
-
expect(requestComputerControlTool.category).toBe("computer-use");
|
|
59
56
|
});
|
|
60
57
|
|
|
61
58
|
test("all tools have unique names", () => {
|
|
@@ -225,20 +222,6 @@ describe("computer_use_respond", () => {
|
|
|
225
222
|
});
|
|
226
223
|
});
|
|
227
224
|
|
|
228
|
-
// ── request_computer_control ────────────────────────────────────────
|
|
229
|
-
|
|
230
|
-
describe("computer_use_request_control", () => {
|
|
231
|
-
test("requires task parameter", () => {
|
|
232
|
-
expect(schema(requestComputerControlTool).required).toContain("task");
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
test("execute throws proxy error", () => {
|
|
236
|
-
expect(() => requestComputerControlTool.execute({}, ctx)).toThrow(
|
|
237
|
-
"surfaceProxyResolver",
|
|
238
|
-
);
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
|
|
242
225
|
// ── skill-proxy-bridge ──────────────────────────────────────────────
|
|
243
226
|
|
|
244
227
|
describe("forwardComputerUseProxyTool", () => {
|