@vellumai/assistant 0.4.17 → 0.4.19
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/docs/runbook-trusted-contacts.md +5 -3
- package/eslint.config.mjs +2 -2
- package/package.json +1 -1
- package/src/__tests__/access-request-decision.test.ts +128 -120
- package/src/__tests__/account-registry.test.ts +121 -110
- package/src/__tests__/active-skill-tools.test.ts +200 -172
- package/src/__tests__/actor-token-service.test.ts +341 -274
- package/src/__tests__/agent-loop-thinking.test.ts +28 -19
- package/src/__tests__/agent-loop.test.ts +798 -378
- package/src/__tests__/anthropic-provider.test.ts +405 -247
- package/src/__tests__/app-builder-tool-scripts.test.ts +97 -97
- package/src/__tests__/app-bundler.test.ts +112 -79
- package/src/__tests__/app-executors.test.ts +205 -178
- package/src/__tests__/app-git-history.test.ts +90 -73
- package/src/__tests__/app-git-service.test.ts +67 -53
- package/src/__tests__/app-open-proxy.test.ts +29 -25
- package/src/__tests__/approval-conversation-turn.test.ts +100 -81
- package/src/__tests__/approval-hardcoded-copy-guard.test.ts +45 -17
- package/src/__tests__/approval-message-composer.test.ts +119 -119
- package/src/__tests__/approval-primitive.test.ts +264 -233
- package/src/__tests__/approval-routes-http.test.ts +4 -3
- package/src/__tests__/asset-materialize-tool.test.ts +250 -178
- package/src/__tests__/asset-search-tool.test.ts +251 -191
- package/src/__tests__/assistant-attachment-directive.test.ts +187 -142
- package/src/__tests__/assistant-attachments.test.ts +254 -186
- package/src/__tests__/assistant-event-hub.test.ts +105 -63
- package/src/__tests__/assistant-event.test.ts +66 -58
- package/src/__tests__/assistant-events-sse-hardening.test.ts +113 -73
- package/src/__tests__/assistant-feature-flag-guard.test.ts +78 -52
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +48 -45
- package/src/__tests__/assistant-feature-flags-integration.test.ts +118 -77
- package/src/__tests__/assistant-id-boundary-guard.test.ts +158 -104
- package/src/__tests__/attachments-store.test.ts +240 -183
- package/src/__tests__/attachments.test.ts +70 -62
- package/src/__tests__/audit-log-rotation.test.ts +50 -35
- package/src/__tests__/browser-fill-credential.test.ts +169 -101
- package/src/__tests__/browser-manager.test.ts +97 -75
- package/src/__tests__/browser-runtime-check.test.ts +16 -15
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +12 -10
- package/src/__tests__/browser-skill-endstate.test.ts +97 -72
- package/src/__tests__/bundle-scanner.test.ts +47 -22
- package/src/__tests__/bundled-asset.test.ts +74 -47
- package/src/__tests__/call-constants.test.ts +19 -19
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/call-conversation-messages.test.ts +90 -65
- package/src/__tests__/call-domain.test.ts +149 -121
- package/src/__tests__/call-pointer-message-composer.test.ts +113 -83
- package/src/__tests__/call-pointer-messages.test.ts +213 -154
- package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +9 -10
- package/src/__tests__/call-recovery.test.ts +232 -212
- package/src/__tests__/call-routes-http.test.ts +0 -1
- package/src/__tests__/call-start-guardian-guard.test.ts +32 -30
- package/src/__tests__/call-state-machine.test.ts +62 -51
- package/src/__tests__/call-state.test.ts +89 -75
- package/src/__tests__/call-store.test.ts +387 -316
- package/src/__tests__/callback-handoff-copy.test.ts +84 -82
- package/src/__tests__/canonical-guardian-store.test.ts +331 -280
- package/src/__tests__/channel-approval-routes.test.ts +1643 -1115
- package/src/__tests__/channel-approval.test.ts +139 -137
- package/src/__tests__/channel-approvals.test.ts +7 -2
- package/src/__tests__/channel-delivery-store.test.ts +232 -194
- package/src/__tests__/channel-guardian.test.ts +5 -3
- package/src/__tests__/channel-invite-transport.test.ts +107 -92
- package/src/__tests__/channel-policy.test.ts +42 -38
- package/src/__tests__/channel-readiness-service.test.ts +119 -102
- package/src/__tests__/channel-reply-delivery.test.ts +147 -118
- package/src/__tests__/channel-retry-sweep.test.ts +153 -110
- package/src/__tests__/checker.test.ts +3309 -1850
- package/src/__tests__/clarification-resolver.test.ts +91 -79
- package/src/__tests__/classifier.test.ts +64 -54
- package/src/__tests__/claude-code-skill-regression.test.ts +42 -37
- package/src/__tests__/claude-code-tool-profiles.test.ts +31 -29
- package/src/__tests__/clawhub.test.ts +92 -82
- package/src/__tests__/cli.test.ts +30 -30
- package/src/__tests__/clipboard.test.ts +53 -46
- package/src/__tests__/commit-guarantee.test.ts +59 -52
- package/src/__tests__/commit-message-enrichment-service.test.ts +203 -75
- package/src/__tests__/compaction.benchmark.test.ts +33 -31
- package/src/__tests__/computer-use-session-compaction.test.ts +60 -50
- package/src/__tests__/computer-use-session-lifecycle.test.ts +145 -117
- package/src/__tests__/computer-use-session-working-dir.test.ts +62 -48
- package/src/__tests__/computer-use-skill-baseline.test.ts +22 -19
- package/src/__tests__/computer-use-skill-endstate.test.ts +45 -31
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +121 -88
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +65 -42
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +33 -18
- package/src/__tests__/computer-use-tools.test.ts +121 -98
- package/src/__tests__/config-schema.test.ts +443 -347
- package/src/__tests__/config-watcher.test.ts +96 -81
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +148 -133
- package/src/__tests__/conflict-intent-tokenization.test.ts +96 -78
- package/src/__tests__/conflict-policy.test.ts +151 -80
- package/src/__tests__/conflict-store.test.ts +203 -157
- package/src/__tests__/connection-policy.test.ts +89 -59
- package/src/__tests__/contacts-tools.test.ts +247 -178
- package/src/__tests__/context-memory-e2e.test.ts +306 -214
- package/src/__tests__/context-token-estimator.test.ts +114 -74
- package/src/__tests__/context-window-manager.test.ts +269 -167
- package/src/__tests__/contradiction-checker.test.ts +161 -135
- package/src/__tests__/conversation-attention-store.test.ts +350 -290
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-pairing.test.ts +220 -113
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
- package/src/__tests__/conversation-store.test.ts +390 -235
- package/src/__tests__/credential-broker-browser-fill.test.ts +325 -250
- package/src/__tests__/credential-broker-server-use.test.ts +283 -243
- package/src/__tests__/credential-broker.test.ts +128 -74
- package/src/__tests__/credential-host-pattern-match.test.ts +64 -44
- package/src/__tests__/credential-metadata-store.test.ts +360 -311
- package/src/__tests__/credential-policy-validate.test.ts +81 -65
- package/src/__tests__/credential-resolve.test.ts +212 -145
- package/src/__tests__/credential-security-e2e.test.ts +144 -103
- package/src/__tests__/credential-security-invariants.test.ts +253 -208
- package/src/__tests__/credential-selection.test.ts +254 -146
- package/src/__tests__/credential-vault-unit.test.ts +531 -341
- package/src/__tests__/credential-vault.test.ts +761 -484
- package/src/__tests__/daemon-assistant-events.test.ts +91 -66
- package/src/__tests__/daemon-lifecycle.test.ts +258 -190
- package/src/__tests__/daemon-server-session-init.test.ts +2 -1
- package/src/__tests__/date-context.test.ts +314 -249
- package/src/__tests__/db-migration-rollback.test.ts +259 -130
- package/src/__tests__/db-schedule-syntax-migration.test.ts +78 -41
- package/src/__tests__/delete-managed-skill-tool.test.ts +77 -53
- package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -1
- package/src/__tests__/dictation-mode-detection.test.ts +77 -55
- package/src/__tests__/dictation-profile-store.test.ts +70 -56
- package/src/__tests__/dictation-text-processing.test.ts +53 -35
- package/src/__tests__/diff.test.ts +102 -98
- package/src/__tests__/domain-normalize.test.ts +54 -54
- package/src/__tests__/domain-policy.test.ts +71 -55
- package/src/__tests__/dynamic-page-surface.test.ts +31 -33
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +69 -69
- package/src/__tests__/edit-engine.test.ts +56 -56
- package/src/__tests__/elevenlabs-client.test.ts +117 -91
- package/src/__tests__/elevenlabs-config.test.ts +32 -31
- package/src/__tests__/email-classifier.test.ts +15 -12
- package/src/__tests__/email-cli.test.ts +121 -108
- package/src/__tests__/emit-signal-routing-intent.test.ts +76 -69
- package/src/__tests__/encrypted-store.test.ts +180 -154
- package/src/__tests__/entity-extractor.test.ts +108 -87
- package/src/__tests__/entity-search.test.ts +664 -258
- package/src/__tests__/ephemeral-permissions.test.ts +224 -188
- package/src/__tests__/event-bus.test.ts +81 -77
- package/src/__tests__/extract-email.test.ts +29 -20
- package/src/__tests__/file-edit-tool.test.ts +62 -44
- package/src/__tests__/file-ops-service.test.ts +131 -114
- package/src/__tests__/file-read-tool.test.ts +48 -31
- package/src/__tests__/file-write-tool.test.ts +43 -37
- package/src/__tests__/filesystem-tools.test.ts +238 -209
- package/src/__tests__/followup-tools.test.ts +237 -162
- package/src/__tests__/forbidden-legacy-symbols.test.ts +19 -20
- package/src/__tests__/frontmatter.test.ts +96 -81
- package/src/__tests__/fuzzy-match-property.test.ts +75 -81
- package/src/__tests__/fuzzy-match.test.ts +71 -65
- package/src/__tests__/gateway-client-managed-outbound.test.ts +76 -57
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-image-service.test.ts +113 -100
- package/src/__tests__/gemini-provider.test.ts +297 -220
- package/src/__tests__/get-weather.test.ts +188 -114
- package/src/__tests__/gmail-integration.test.ts +13 -5
- package/src/__tests__/guardian-action-conversation-turn.test.ts +226 -171
- package/src/__tests__/guardian-action-copy-generator.test.ts +111 -93
- package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
- package/src/__tests__/guardian-action-followup-store.test.ts +199 -167
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +297 -250
- package/src/__tests__/guardian-action-late-reply.test.ts +462 -316
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +23 -18
- package/src/__tests__/guardian-action-store.test.ts +158 -109
- package/src/__tests__/guardian-action-sweep.test.ts +114 -100
- package/src/__tests__/guardian-actions-endpoint.test.ts +440 -256
- package/src/__tests__/guardian-control-plane-policy.test.ts +497 -331
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +217 -215
- package/src/__tests__/guardian-dispatch.test.ts +316 -256
- package/src/__tests__/guardian-grant-minting.test.ts +247 -178
- package/src/__tests__/guardian-outbound-http.test.ts +5 -3
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +99 -96
- package/src/__tests__/guardian-question-copy.test.ts +17 -17
- package/src/__tests__/guardian-question-mode.test.ts +134 -100
- package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
- package/src/__tests__/guardian-routing-state.test.ts +0 -1
- package/src/__tests__/guardian-verification-intent-routing.test.ts +94 -88
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +0 -1
- package/src/__tests__/handle-user-message-secret-resume.test.ts +7 -2
- package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +92 -76
- package/src/__tests__/handlers-cu-observation-blob.test.ts +103 -70
- package/src/__tests__/handlers-ipc-blob-probe.test.ts +77 -51
- package/src/__tests__/handlers-slack-config.test.ts +63 -54
- package/src/__tests__/handlers-task-submit-slash.test.ts +18 -18
- package/src/__tests__/handlers-telegram-config.test.ts +662 -329
- package/src/__tests__/handlers-twitter-config.test.ts +525 -298
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +5 -2
- package/src/__tests__/headless-browser-interactions.test.ts +444 -280
- package/src/__tests__/headless-browser-navigate.test.ts +116 -79
- package/src/__tests__/headless-browser-read-tools.test.ts +123 -86
- package/src/__tests__/headless-browser-snapshot.test.ts +71 -56
- package/src/__tests__/heartbeat-service.test.ts +76 -58
- package/src/__tests__/history-repair-observability.test.ts +14 -14
- package/src/__tests__/history-repair.test.ts +171 -167
- package/src/__tests__/home-base-bootstrap.test.ts +30 -27
- package/src/__tests__/hooks-blocking.test.ts +86 -37
- package/src/__tests__/hooks-cli.test.ts +104 -68
- package/src/__tests__/hooks-config.test.ts +81 -43
- package/src/__tests__/hooks-discovery.test.ts +106 -96
- package/src/__tests__/hooks-integration.test.ts +78 -72
- package/src/__tests__/hooks-manager.test.ts +99 -61
- package/src/__tests__/hooks-runner.test.ts +94 -71
- package/src/__tests__/hooks-settings.test.ts +69 -64
- package/src/__tests__/hooks-templates.test.ts +85 -54
- package/src/__tests__/hooks-ts-runner.test.ts +82 -45
- package/src/__tests__/hooks-watch.test.ts +32 -22
- package/src/__tests__/host-file-edit-tool.test.ts +190 -148
- package/src/__tests__/host-file-read-tool.test.ts +86 -63
- package/src/__tests__/host-file-write-tool.test.ts +98 -64
- package/src/__tests__/host-shell-tool.test.ts +342 -233
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -1
- package/src/__tests__/ingress-member-store.test.ts +163 -159
- package/src/__tests__/ingress-reconcile.test.ts +13 -6
- package/src/__tests__/ingress-routes-http.test.ts +441 -356
- package/src/__tests__/ingress-url-consistency.test.ts +125 -64
- package/src/__tests__/integration-status.test.ts +93 -73
- package/src/__tests__/intent-routing.test.ts +148 -118
- package/src/__tests__/invite-redemption-service.test.ts +163 -121
- package/src/__tests__/ipc-blob-store.test.ts +104 -91
- package/src/__tests__/ipc-contract-inventory.test.ts +27 -15
- package/src/__tests__/ipc-contract.test.ts +24 -23
- package/src/__tests__/ipc-protocol.test.ts +52 -46
- package/src/__tests__/ipc-roundtrip.benchmark.test.ts +61 -50
- package/src/__tests__/ipc-snapshot.test.ts +1135 -1056
- package/src/__tests__/ipc-validate.test.ts +240 -179
- package/src/__tests__/key-migration.test.ts +123 -90
- package/src/__tests__/keychain.test.ts +150 -123
- package/src/__tests__/lifecycle-docs-guard.test.ts +65 -64
- package/src/__tests__/llm-usage-store.test.ts +112 -87
- package/src/__tests__/managed-skill-lifecycle.test.ts +147 -108
- package/src/__tests__/managed-store.test.ts +411 -360
- package/src/__tests__/mcp-cli.test.ts +190 -124
- package/src/__tests__/mcp-health-check.test.ts +26 -21
- package/src/__tests__/media-generate-image.test.ts +122 -99
- package/src/__tests__/media-reuse-story.e2e.test.ts +282 -214
- package/src/__tests__/media-visibility-policy.test.ts +86 -38
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +146 -100
- package/src/__tests__/memory-lifecycle-e2e.test.ts +385 -297
- package/src/__tests__/memory-query-builder.test.ts +32 -33
- package/src/__tests__/memory-recall-quality.test.ts +761 -407
- package/src/__tests__/memory-regressions.experimental.test.ts +443 -380
- package/src/__tests__/memory-regressions.test.ts +3725 -2642
- package/src/__tests__/memory-retrieval-budget.test.ts +7 -8
- package/src/__tests__/memory-retrieval.benchmark.test.ts +144 -109
- package/src/__tests__/memory-upsert-concurrency.test.ts +292 -201
- package/src/__tests__/messaging-send-tool.test.ts +36 -29
- package/src/__tests__/migration-cli-flows.test.ts +69 -53
- package/src/__tests__/migration-ordering.test.ts +103 -86
- package/src/__tests__/mime-builder.test.ts +55 -32
- package/src/__tests__/mock-signup-server.test.ts +384 -246
- package/src/__tests__/model-intents.test.ts +61 -37
- package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +9 -12
- package/src/__tests__/no-is-trusted-guard.test.ts +24 -21
- package/src/__tests__/non-member-access-request.test.ts +3 -2
- package/src/__tests__/notification-broadcaster.test.ts +99 -81
- package/src/__tests__/notification-decision-fallback.test.ts +223 -178
- package/src/__tests__/notification-decision-strategy.test.ts +375 -337
- package/src/__tests__/notification-deep-link.test.ts +67 -61
- package/src/__tests__/notification-guardian-path.test.ts +248 -206
- package/src/__tests__/notification-routing-intent.test.ts +166 -93
- package/src/__tests__/notification-thread-candidate-validation.test.ts +78 -75
- package/src/__tests__/notification-thread-candidates.test.ts +64 -61
- package/src/__tests__/oauth-callback-registry.test.ts +40 -30
- package/src/__tests__/oauth-connect-handler.test.ts +109 -89
- package/src/__tests__/oauth-scope-policy.test.ts +63 -55
- package/src/__tests__/oauth2-gateway-transport.test.ts +252 -174
- package/src/__tests__/onboarding-starter-tasks.test.ts +93 -89
- package/src/__tests__/onboarding-template-contract.test.ts +93 -94
- package/src/__tests__/openai-provider.test.ts +366 -274
- package/src/__tests__/pairing-concurrent.test.ts +18 -12
- package/src/__tests__/pairing-routes.test.ts +45 -41
- package/src/__tests__/parallel-tool.benchmark.test.ts +108 -58
- package/src/__tests__/parser.test.ts +316 -226
- package/src/__tests__/path-classifier.test.ts +24 -25
- package/src/__tests__/path-policy.test.ts +187 -147
- package/src/__tests__/phone.test.ts +36 -36
- package/src/__tests__/platform-move-helper.test.ts +48 -40
- package/src/__tests__/platform-socket-path.test.ts +23 -24
- package/src/__tests__/platform-workspace-migration.test.ts +464 -414
- package/src/__tests__/platform.test.ts +61 -53
- package/src/__tests__/playbook-execution.test.ts +397 -265
- package/src/__tests__/playbook-tools.test.ts +267 -196
- package/src/__tests__/prebuilt-home-base-seed.test.ts +30 -27
- package/src/__tests__/pricing.test.ts +316 -136
- package/src/__tests__/profile-compiler.test.ts +206 -188
- package/src/__tests__/provider-commit-message-generator.test.ts +114 -106
- package/src/__tests__/provider-error-scenarios.test.ts +212 -158
- package/src/__tests__/provider-fail-open-selection.test.ts +51 -44
- package/src/__tests__/provider-registry-ollama.test.ts +13 -9
- package/src/__tests__/provider-streaming.benchmark.test.ts +232 -183
- package/src/__tests__/proxy-approval-callback.test.ts +180 -119
- package/src/__tests__/public-ingress-urls.test.ts +112 -94
- package/src/__tests__/qdrant-manager.test.ts +147 -98
- package/src/__tests__/ratelimit.test.ts +152 -82
- package/src/__tests__/recording-handler.test.ts +273 -151
- package/src/__tests__/recording-intent-fallback.test.ts +94 -75
- package/src/__tests__/recording-intent-handler.test.ts +9 -2
- package/src/__tests__/recording-intent.test.ts +578 -379
- package/src/__tests__/recording-state-machine.test.ts +530 -316
- package/src/__tests__/recurrence-engine-rruleset.test.ts +150 -92
- package/src/__tests__/recurrence-engine.test.ts +81 -41
- package/src/__tests__/recurrence-types.test.ts +63 -44
- package/src/__tests__/relay-server.test.ts +2131 -1602
- package/src/__tests__/reminder-store.test.ts +158 -80
- package/src/__tests__/reminder.test.ts +113 -109
- package/src/__tests__/remote-skill-policy.test.ts +96 -72
- package/src/__tests__/request-file-tool.test.ts +74 -67
- package/src/__tests__/response-tier.test.ts +131 -74
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +167 -145
- package/src/__tests__/runtime-events-sse.test.ts +0 -1
- package/src/__tests__/sandbox-diagnostics.test.ts +66 -56
- package/src/__tests__/sandbox-host-parity.test.ts +377 -301
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +213 -161
- package/src/__tests__/schedule-store.test.ts +268 -205
- package/src/__tests__/schedule-tools.test.ts +702 -524
- package/src/__tests__/scheduler-recurrence.test.ts +240 -130
- package/src/__tests__/scoped-approval-grants.test.ts +258 -168
- package/src/__tests__/scoped-grant-security-matrix.test.ts +160 -146
- package/src/__tests__/script-proxy-certs.test.ts +38 -35
- package/src/__tests__/script-proxy-connect-tunnel.test.ts +71 -46
- package/src/__tests__/script-proxy-decision-trace.test.ts +161 -84
- package/src/__tests__/script-proxy-http-forwarder.test.ts +146 -129
- package/src/__tests__/script-proxy-injection-runtime.test.ts +139 -113
- package/src/__tests__/script-proxy-mitm-handler.test.ts +226 -142
- package/src/__tests__/script-proxy-policy-runtime.test.ts +126 -86
- package/src/__tests__/script-proxy-policy.test.ts +308 -153
- package/src/__tests__/script-proxy-rewrite-specificity.test.ts +74 -62
- package/src/__tests__/script-proxy-router.test.ts +111 -77
- package/src/__tests__/script-proxy-session-manager.test.ts +156 -113
- package/src/__tests__/script-proxy-session-runtime.test.ts +28 -24
- package/src/__tests__/secret-allowlist.test.ts +105 -90
- package/src/__tests__/secret-ingress-handler.test.ts +41 -30
- package/src/__tests__/secret-onetime-send.test.ts +67 -50
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +35 -31
- package/src/__tests__/secret-response-routing.test.ts +50 -41
- package/src/__tests__/secret-scanner-executor.test.ts +152 -111
- package/src/__tests__/secret-scanner.test.ts +495 -413
- package/src/__tests__/secure-keys.test.ts +132 -121
- package/src/__tests__/send-endpoint-busy.test.ts +8 -3
- package/src/__tests__/send-notification-tool.test.ts +43 -42
- package/src/__tests__/sensitive-output-placeholders.test.ts +72 -64
- package/src/__tests__/sequence-store.test.ts +335 -167
- package/src/__tests__/server-history-render.test.ts +341 -202
- package/src/__tests__/session-abort-tool-results.test.ts +133 -70
- package/src/__tests__/session-confirmation-signals.test.ts +252 -160
- package/src/__tests__/session-conflict-gate.test.ts +775 -585
- package/src/__tests__/session-error.test.ts +222 -191
- package/src/__tests__/session-evictor.test.ts +79 -62
- package/src/__tests__/session-init.benchmark.test.ts +170 -108
- package/src/__tests__/session-load-history-repair.test.ts +273 -139
- package/src/__tests__/session-messaging-secret-redirect.test.ts +130 -90
- package/src/__tests__/session-pre-run-repair.test.ts +106 -59
- package/src/__tests__/session-profile-injection.test.ts +198 -130
- package/src/__tests__/session-provider-retry-repair.test.ts +223 -141
- package/src/__tests__/session-queue.test.ts +624 -321
- package/src/__tests__/session-runtime-assembly.test.ts +425 -329
- package/src/__tests__/session-runtime-workspace.test.ts +69 -61
- package/src/__tests__/session-skill-tools.test.ts +973 -678
- package/src/__tests__/session-slash-known.test.ts +185 -133
- package/src/__tests__/session-slash-queue.test.ts +147 -81
- package/src/__tests__/session-slash-unknown.test.ts +135 -90
- package/src/__tests__/session-surfaces-task-progress.test.ts +122 -87
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +338 -177
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +63 -40
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +60 -37
- package/src/__tests__/session-tool-setup-tools-disabled.test.ts +28 -26
- package/src/__tests__/session-undo.test.ts +43 -30
- package/src/__tests__/session-workspace-cache-state.test.ts +108 -67
- package/src/__tests__/session-workspace-injection.test.ts +245 -117
- package/src/__tests__/session-workspace-tool-tracking.test.ts +260 -93
- package/src/__tests__/shared-filesystem-errors.test.ts +47 -47
- package/src/__tests__/shell-credential-ref.test.ts +126 -90
- package/src/__tests__/shell-identity.test.ts +134 -111
- package/src/__tests__/shell-parser-fuzz.test.ts +263 -179
- package/src/__tests__/shell-parser-property.test.ts +435 -288
- package/src/__tests__/shell-tool-proxy-mode.test.ts +142 -70
- package/src/__tests__/size-guard.test.ts +42 -44
- package/src/__tests__/skill-feature-flags-integration.test.ts +79 -52
- package/src/__tests__/skill-feature-flags.test.ts +75 -47
- package/src/__tests__/skill-include-graph.test.ts +143 -148
- package/src/__tests__/skill-load-feature-flag.test.ts +94 -59
- package/src/__tests__/skill-load-tool.test.ts +371 -199
- package/src/__tests__/skill-projection-feature-flag.test.ts +131 -88
- package/src/__tests__/skill-projection.benchmark.test.ts +93 -65
- package/src/__tests__/skill-script-runner-host.test.ts +460 -250
- package/src/__tests__/skill-script-runner-sandbox.test.ts +168 -108
- package/src/__tests__/skill-script-runner.test.ts +115 -74
- package/src/__tests__/skill-tool-factory.test.ts +140 -96
- package/src/__tests__/skill-tool-manifest.test.ts +306 -210
- package/src/__tests__/skill-version-hash.test.ts +70 -56
- package/src/__tests__/skills.test.ts +0 -1
- package/src/__tests__/slack-channel-config.test.ts +127 -84
- package/src/__tests__/slack-skill.test.ts +60 -47
- package/src/__tests__/slash-commands-catalog.test.ts +37 -31
- package/src/__tests__/slash-commands-parser.test.ts +71 -64
- package/src/__tests__/slash-commands-resolver.test.ts +143 -107
- package/src/__tests__/slash-commands-rewrite.test.ts +22 -22
- package/src/__tests__/sms-messaging-provider.test.ts +4 -0
- package/src/__tests__/speaker-identification.test.ts +28 -25
- package/src/__tests__/starter-bundle.test.ts +27 -23
- package/src/__tests__/starter-task-flow.test.ts +67 -52
- package/src/__tests__/subagent-manager-notify.test.ts +154 -108
- package/src/__tests__/subagent-tools.test.ts +311 -270
- package/src/__tests__/subagent-types.test.ts +40 -40
- package/src/__tests__/surface-mutex-cleanup.test.ts +42 -30
- package/src/__tests__/swarm-dag-pathological.test.ts +122 -111
- package/src/__tests__/swarm-orchestrator.test.ts +135 -101
- package/src/__tests__/swarm-plan-validator.test.ts +125 -73
- package/src/__tests__/swarm-recursion.test.ts +58 -46
- package/src/__tests__/swarm-router-planner.test.ts +99 -74
- package/src/__tests__/swarm-session-integration.test.ts +148 -91
- package/src/__tests__/swarm-tool.test.ts +65 -45
- package/src/__tests__/swarm-worker-backend.test.ts +59 -45
- package/src/__tests__/swarm-worker-runner.test.ts +133 -118
- package/src/__tests__/system-prompt.test.ts +311 -256
- package/src/__tests__/task-compiler.test.ts +176 -120
- package/src/__tests__/task-management-tools.test.ts +561 -456
- package/src/__tests__/task-memory-cleanup.test.ts +627 -362
- package/src/__tests__/task-runner.test.ts +117 -94
- package/src/__tests__/task-scheduler.test.ts +113 -84
- package/src/__tests__/task-tools.test.ts +349 -264
- package/src/__tests__/terminal-sandbox.test.ts +138 -108
- package/src/__tests__/terminal-tools.test.ts +350 -305
- package/src/__tests__/thread-seed-composer.test.ts +307 -180
- package/src/__tests__/tool-approval-handler.test.ts +238 -137
- package/src/__tests__/tool-audit-listener.test.ts +69 -69
- package/src/__tests__/tool-domain-event-publisher.test.ts +142 -132
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +155 -146
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +136 -105
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +355 -239
- package/src/__tests__/tool-executor-redaction.test.ts +112 -109
- package/src/__tests__/tool-executor-shell-integration.test.ts +130 -79
- package/src/__tests__/tool-executor.test.ts +1274 -674
- package/src/__tests__/tool-grant-request-escalation.test.ts +401 -283
- package/src/__tests__/tool-metrics-listener.test.ts +97 -85
- package/src/__tests__/tool-notification-listener.test.ts +42 -25
- package/src/__tests__/tool-permission-simulate-handler.test.ts +137 -113
- package/src/__tests__/tool-policy.test.ts +44 -25
- package/src/__tests__/tool-profiling-listener.test.ts +99 -93
- package/src/__tests__/tool-result-truncation.test.ts +5 -4
- package/src/__tests__/tool-trace-listener.test.ts +131 -111
- package/src/__tests__/top-level-renderer.test.ts +62 -58
- package/src/__tests__/top-level-scanner.test.ts +68 -64
- package/src/__tests__/trace-emitter.test.ts +56 -56
- package/src/__tests__/trust-context-guards.test.ts +65 -65
- package/src/__tests__/trust-store.test.ts +1239 -806
- 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__/trusted-contact-lifecycle-notifications.test.ts +3 -2
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -2
- package/src/__tests__/trusted-contact-verification.test.ts +251 -231
- package/src/__tests__/turn-commit.test.ts +259 -200
- package/src/__tests__/twilio-provider.test.ts +140 -126
- package/src/__tests__/twilio-rest.test.ts +22 -18
- package/src/__tests__/twilio-routes-elevenlabs.test.ts +0 -1
- package/src/__tests__/twilio-routes-twiml.test.ts +55 -55
- package/src/__tests__/twilio-routes.test.ts +0 -1
- package/src/__tests__/twitter-auth-handler.test.ts +184 -139
- package/src/__tests__/twitter-cli-error-shaping.test.ts +88 -73
- package/src/__tests__/twitter-cli-routing.test.ts +146 -99
- package/src/__tests__/twitter-oauth-client.test.ts +82 -65
- package/src/__tests__/update-bulletin-format.test.ts +69 -66
- package/src/__tests__/update-bulletin-state.test.ts +66 -60
- package/src/__tests__/update-bulletin.test.ts +150 -114
- package/src/__tests__/update-template-contract.test.ts +15 -10
- package/src/__tests__/url-safety.test.ts +288 -265
- package/src/__tests__/user-reference.test.ts +32 -32
- package/src/__tests__/view-image-tool.test.ts +118 -96
- package/src/__tests__/voice-invite-redemption.test.ts +111 -106
- package/src/__tests__/voice-quality.test.ts +117 -102
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +204 -146
- package/src/__tests__/voice-session-bridge.test.ts +351 -216
- package/src/__tests__/weather-skill-regression.test.ts +170 -120
- package/src/__tests__/web-fetch.test.ts +664 -526
- package/src/__tests__/web-search.test.ts +379 -213
- package/src/__tests__/work-item-output.test.ts +90 -53
- package/src/__tests__/workspace-git-service.test.ts +437 -356
- package/src/__tests__/workspace-heartbeat-service.test.ts +125 -91
- package/src/__tests__/workspace-lifecycle.test.ts +98 -64
- package/src/__tests__/workspace-policy.test.ts +139 -71
- package/src/cli/mcp.ts +81 -28
- package/src/commands/__tests__/cc-command-registry.test.ts +142 -134
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +48 -39
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +25 -10
- package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +0 -1
- package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +6 -11
- package/src/config/bundled-skills/messaging/SKILL.md +4 -3
- package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +15 -5
- package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +16 -5
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -2
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +34 -32
- package/src/config/bundled-skills/sms-setup/SKILL.md +8 -16
- package/src/config/bundled-skills/telegram-setup/SKILL.md +3 -3
- package/src/config/bundled-skills/trusted-contacts/SKILL.md +13 -25
- package/src/config/bundled-skills/twilio-setup/SKILL.md +13 -23
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/env.ts +3 -4
- package/src/config/system-prompt.ts +32 -0
- package/src/mcp/client.ts +2 -7
- package/src/memory/db-connection.ts +16 -10
- package/src/messaging/providers/gmail/adapter.ts +10 -3
- package/src/messaging/providers/gmail/client.ts +280 -72
- package/src/runtime/auth/__tests__/context.test.ts +75 -65
- package/src/runtime/auth/__tests__/credential-service.test.ts +137 -114
- package/src/runtime/auth/__tests__/guard-tests.test.ts +84 -90
- package/src/runtime/auth/__tests__/ipc-auth-context.test.ts +40 -40
- package/src/runtime/auth/__tests__/middleware.test.ts +80 -74
- package/src/runtime/auth/__tests__/policy.test.ts +9 -9
- package/src/runtime/auth/__tests__/route-policy.test.ts +76 -65
- package/src/runtime/auth/__tests__/scopes.test.ts +68 -60
- package/src/runtime/auth/__tests__/subject.test.ts +54 -54
- package/src/runtime/auth/__tests__/token-service.test.ts +115 -108
- package/src/runtime/auth/scopes.ts +3 -0
- package/src/runtime/auth/token-service.ts +4 -1
- package/src/runtime/auth/types.ts +2 -1
- package/src/runtime/http-server.ts +2 -1
- package/src/security/secure-keys.ts +120 -54
- package/src/tools/browser/__tests__/auth-cache.test.ts +69 -63
- package/src/tools/browser/__tests__/auth-detector.test.ts +218 -157
- package/src/tools/browser/__tests__/jit-auth.test.ts +83 -99
- package/src/tools/terminal/safe-env.ts +7 -0
|
@@ -1,26 +1,25 @@
|
|
|
1
|
-
import { mkdtempSync, rmSync } from
|
|
2
|
-
import { tmpdir } from
|
|
3
|
-
import { join } from
|
|
1
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
const testDir = mkdtempSync(join(tmpdir(), "approval-primitive-test-"));
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
mock.module('../util/platform.js', () => ({
|
|
8
|
+
mock.module("../util/platform.js", () => ({
|
|
10
9
|
getDataDir: () => testDir,
|
|
11
|
-
isMacOS: () => process.platform ===
|
|
12
|
-
isLinux: () => process.platform ===
|
|
13
|
-
isWindows: () => process.platform ===
|
|
14
|
-
getSocketPath: () => join(testDir,
|
|
15
|
-
getPidPath: () => join(testDir,
|
|
16
|
-
getDbPath: () => join(testDir,
|
|
17
|
-
getLogPath: () => join(testDir,
|
|
10
|
+
isMacOS: () => process.platform === "darwin",
|
|
11
|
+
isLinux: () => process.platform === "linux",
|
|
12
|
+
isWindows: () => process.platform === "win32",
|
|
13
|
+
getSocketPath: () => join(testDir, "test.sock"),
|
|
14
|
+
getPidPath: () => join(testDir, "test.pid"),
|
|
15
|
+
getDbPath: () => join(testDir, "test.db"),
|
|
16
|
+
getLogPath: () => join(testDir, "test.log"),
|
|
18
17
|
ensureDataDir: () => {},
|
|
19
18
|
migrateToDataLayout: () => {},
|
|
20
19
|
migrateToWorkspaceLayout: () => {},
|
|
21
20
|
}));
|
|
22
21
|
|
|
23
|
-
mock.module(
|
|
22
|
+
mock.module("../util/logger.js", () => ({
|
|
24
23
|
getLogger: () =>
|
|
25
24
|
new Proxy({} as Record<string, unknown>, {
|
|
26
25
|
get: () => () => {},
|
|
@@ -33,10 +32,10 @@ import {
|
|
|
33
32
|
consumeGrantForInvocation,
|
|
34
33
|
mintGrantFromDecision,
|
|
35
34
|
type MintGrantParams,
|
|
36
|
-
} from
|
|
37
|
-
import { getDb, initializeDb, resetDb } from
|
|
38
|
-
import { scopedApprovalGrants } from
|
|
39
|
-
import { computeToolApprovalDigest } from
|
|
35
|
+
} from "../approvals/approval-primitive.js";
|
|
36
|
+
import { getDb, initializeDb, resetDb } from "../memory/db.js";
|
|
37
|
+
import { scopedApprovalGrants } from "../memory/schema.js";
|
|
38
|
+
import { computeToolApprovalDigest } from "../security/tool-approval-digest.js";
|
|
40
39
|
|
|
41
40
|
initializeDb();
|
|
42
41
|
|
|
@@ -61,10 +60,10 @@ afterAll(() => {
|
|
|
61
60
|
function mintParams(overrides: Partial<MintGrantParams> = {}): MintGrantParams {
|
|
62
61
|
const futureExpiry = new Date(Date.now() + 60_000).toISOString();
|
|
63
62
|
return {
|
|
64
|
-
assistantId:
|
|
65
|
-
scopeMode:
|
|
66
|
-
requestChannel:
|
|
67
|
-
decisionChannel:
|
|
63
|
+
assistantId: "self",
|
|
64
|
+
scopeMode: "request_id",
|
|
65
|
+
requestChannel: "telegram",
|
|
66
|
+
decisionChannel: "telegram",
|
|
68
67
|
expiresAt: futureExpiry,
|
|
69
68
|
...overrides,
|
|
70
69
|
};
|
|
@@ -74,90 +73,90 @@ function mintParams(overrides: Partial<MintGrantParams> = {}): MintGrantParams {
|
|
|
74
73
|
// MINT TESTS
|
|
75
74
|
// ===========================================================================
|
|
76
75
|
|
|
77
|
-
describe(
|
|
76
|
+
describe("approval-primitive / mintGrantFromDecision", () => {
|
|
78
77
|
beforeEach(() => clearTables());
|
|
79
78
|
|
|
80
|
-
test(
|
|
79
|
+
test("mints a request_id scoped grant successfully", () => {
|
|
81
80
|
const result = mintGrantFromDecision(
|
|
82
|
-
mintParams({ scopeMode:
|
|
81
|
+
mintParams({ scopeMode: "request_id", requestId: "req-1" }),
|
|
83
82
|
);
|
|
84
83
|
expect(result.ok).toBe(true);
|
|
85
84
|
if (!result.ok) return;
|
|
86
|
-
expect(result.grant.status).toBe(
|
|
87
|
-
expect(result.grant.requestId).toBe(
|
|
88
|
-
expect(result.grant.scopeMode).toBe(
|
|
85
|
+
expect(result.grant.status).toBe("active");
|
|
86
|
+
expect(result.grant.requestId).toBe("req-1");
|
|
87
|
+
expect(result.grant.scopeMode).toBe("request_id");
|
|
89
88
|
});
|
|
90
89
|
|
|
91
|
-
test(
|
|
92
|
-
const digest = computeToolApprovalDigest(
|
|
90
|
+
test("mints a tool_signature scoped grant successfully", () => {
|
|
91
|
+
const digest = computeToolApprovalDigest("shell", { command: "ls" });
|
|
93
92
|
const result = mintGrantFromDecision(
|
|
94
93
|
mintParams({
|
|
95
|
-
scopeMode:
|
|
96
|
-
toolName:
|
|
94
|
+
scopeMode: "tool_signature",
|
|
95
|
+
toolName: "shell",
|
|
97
96
|
inputDigest: digest,
|
|
98
97
|
}),
|
|
99
98
|
);
|
|
100
99
|
expect(result.ok).toBe(true);
|
|
101
100
|
if (!result.ok) return;
|
|
102
|
-
expect(result.grant.toolName).toBe(
|
|
101
|
+
expect(result.grant.toolName).toBe("shell");
|
|
103
102
|
expect(result.grant.inputDigest).toBe(digest);
|
|
104
|
-
expect(result.grant.scopeMode).toBe(
|
|
103
|
+
expect(result.grant.scopeMode).toBe("tool_signature");
|
|
105
104
|
});
|
|
106
105
|
|
|
107
|
-
test(
|
|
106
|
+
test("rejects request_id scope when requestId is missing", () => {
|
|
108
107
|
const result = mintGrantFromDecision(
|
|
109
|
-
mintParams({ scopeMode:
|
|
108
|
+
mintParams({ scopeMode: "request_id", requestId: null }),
|
|
110
109
|
);
|
|
111
110
|
expect(result.ok).toBe(false);
|
|
112
111
|
if (result.ok) return;
|
|
113
|
-
expect(result.reason).toBe(
|
|
112
|
+
expect(result.reason).toBe("missing_request_id");
|
|
114
113
|
});
|
|
115
114
|
|
|
116
|
-
test(
|
|
115
|
+
test("rejects tool_signature scope when toolName is missing", () => {
|
|
117
116
|
const result = mintGrantFromDecision(
|
|
118
117
|
mintParams({
|
|
119
|
-
scopeMode:
|
|
118
|
+
scopeMode: "tool_signature",
|
|
120
119
|
toolName: null,
|
|
121
|
-
inputDigest:
|
|
120
|
+
inputDigest: "abc123",
|
|
122
121
|
}),
|
|
123
122
|
);
|
|
124
123
|
expect(result.ok).toBe(false);
|
|
125
124
|
if (result.ok) return;
|
|
126
|
-
expect(result.reason).toBe(
|
|
125
|
+
expect(result.reason).toBe("missing_tool_fields");
|
|
127
126
|
});
|
|
128
127
|
|
|
129
|
-
test(
|
|
128
|
+
test("rejects tool_signature scope when inputDigest is missing", () => {
|
|
130
129
|
const result = mintGrantFromDecision(
|
|
131
130
|
mintParams({
|
|
132
|
-
scopeMode:
|
|
133
|
-
toolName:
|
|
131
|
+
scopeMode: "tool_signature",
|
|
132
|
+
toolName: "shell",
|
|
134
133
|
inputDigest: null,
|
|
135
134
|
}),
|
|
136
135
|
);
|
|
137
136
|
expect(result.ok).toBe(false);
|
|
138
137
|
if (result.ok) return;
|
|
139
|
-
expect(result.reason).toBe(
|
|
138
|
+
expect(result.reason).toBe("missing_tool_fields");
|
|
140
139
|
});
|
|
141
140
|
|
|
142
|
-
test(
|
|
141
|
+
test("mints grant with full scope context fields", () => {
|
|
143
142
|
const result = mintGrantFromDecision(
|
|
144
143
|
mintParams({
|
|
145
|
-
scopeMode:
|
|
146
|
-
requestId:
|
|
147
|
-
conversationId:
|
|
148
|
-
callSessionId:
|
|
149
|
-
requesterExternalUserId:
|
|
150
|
-
guardianExternalUserId:
|
|
151
|
-
executionChannel:
|
|
144
|
+
scopeMode: "request_id",
|
|
145
|
+
requestId: "req-full",
|
|
146
|
+
conversationId: "conv-1",
|
|
147
|
+
callSessionId: "call-1",
|
|
148
|
+
requesterExternalUserId: "user-1",
|
|
149
|
+
guardianExternalUserId: "guardian-1",
|
|
150
|
+
executionChannel: "voice",
|
|
152
151
|
}),
|
|
153
152
|
);
|
|
154
153
|
expect(result.ok).toBe(true);
|
|
155
154
|
if (!result.ok) return;
|
|
156
|
-
expect(result.grant.conversationId).toBe(
|
|
157
|
-
expect(result.grant.callSessionId).toBe(
|
|
158
|
-
expect(result.grant.requesterExternalUserId).toBe(
|
|
159
|
-
expect(result.grant.guardianExternalUserId).toBe(
|
|
160
|
-
expect(result.grant.executionChannel).toBe(
|
|
155
|
+
expect(result.grant.conversationId).toBe("conv-1");
|
|
156
|
+
expect(result.grant.callSessionId).toBe("call-1");
|
|
157
|
+
expect(result.grant.requesterExternalUserId).toBe("user-1");
|
|
158
|
+
expect(result.grant.guardianExternalUserId).toBe("guardian-1");
|
|
159
|
+
expect(result.grant.executionChannel).toBe("voice");
|
|
161
160
|
});
|
|
162
161
|
});
|
|
163
162
|
|
|
@@ -165,286 +164,314 @@ describe('approval-primitive / mintGrantFromDecision', () => {
|
|
|
165
164
|
// CONSUME TESTS
|
|
166
165
|
// ===========================================================================
|
|
167
166
|
|
|
168
|
-
describe(
|
|
167
|
+
describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
169
168
|
beforeEach(() => clearTables());
|
|
170
169
|
|
|
171
|
-
test(
|
|
172
|
-
mintGrantFromDecision(
|
|
170
|
+
test("consumes a request_id grant when requestId matches", async () => {
|
|
171
|
+
mintGrantFromDecision(
|
|
172
|
+
mintParams({ scopeMode: "request_id", requestId: "req-100" }),
|
|
173
|
+
);
|
|
173
174
|
|
|
174
175
|
const result = await consumeGrantForInvocation({
|
|
175
|
-
requestId:
|
|
176
|
-
toolName:
|
|
177
|
-
inputDigest: computeToolApprovalDigest(
|
|
178
|
-
consumingRequestId:
|
|
179
|
-
assistantId:
|
|
176
|
+
requestId: "req-100",
|
|
177
|
+
toolName: "shell",
|
|
178
|
+
inputDigest: computeToolApprovalDigest("shell", { command: "ls" }),
|
|
179
|
+
consumingRequestId: "consumer-1",
|
|
180
|
+
assistantId: "self",
|
|
180
181
|
});
|
|
181
182
|
|
|
182
183
|
expect(result.ok).toBe(true);
|
|
183
184
|
if (!result.ok) return;
|
|
184
|
-
expect(result.grant.status).toBe(
|
|
185
|
-
expect(result.grant.consumedByRequestId).toBe(
|
|
185
|
+
expect(result.grant.status).toBe("consumed");
|
|
186
|
+
expect(result.grant.consumedByRequestId).toBe("consumer-1");
|
|
186
187
|
});
|
|
187
188
|
|
|
188
|
-
test(
|
|
189
|
-
const digest = computeToolApprovalDigest(
|
|
189
|
+
test("consumes a tool_signature grant when tool+input matches", async () => {
|
|
190
|
+
const digest = computeToolApprovalDigest("shell", { command: "ls" });
|
|
190
191
|
mintGrantFromDecision(
|
|
191
192
|
mintParams({
|
|
192
|
-
scopeMode:
|
|
193
|
-
toolName:
|
|
193
|
+
scopeMode: "tool_signature",
|
|
194
|
+
toolName: "shell",
|
|
194
195
|
inputDigest: digest,
|
|
195
196
|
}),
|
|
196
197
|
);
|
|
197
198
|
|
|
198
199
|
const result = await consumeGrantForInvocation({
|
|
199
|
-
toolName:
|
|
200
|
+
toolName: "shell",
|
|
200
201
|
inputDigest: digest,
|
|
201
|
-
consumingRequestId:
|
|
202
|
-
assistantId:
|
|
202
|
+
consumingRequestId: "consumer-2",
|
|
203
|
+
assistantId: "self",
|
|
203
204
|
});
|
|
204
205
|
|
|
205
206
|
expect(result.ok).toBe(true);
|
|
206
207
|
if (!result.ok) return;
|
|
207
|
-
expect(result.grant.status).toBe(
|
|
208
|
+
expect(result.grant.status).toBe("consumed");
|
|
208
209
|
});
|
|
209
210
|
|
|
210
|
-
test(
|
|
211
|
-
const digest = computeToolApprovalDigest(
|
|
211
|
+
test("falls back to tool_signature when request_id does not match", async () => {
|
|
212
|
+
const digest = computeToolApprovalDigest("shell", { command: "ls" });
|
|
212
213
|
// Mint a tool_signature grant (not request_id)
|
|
213
214
|
mintGrantFromDecision(
|
|
214
215
|
mintParams({
|
|
215
|
-
scopeMode:
|
|
216
|
-
toolName:
|
|
216
|
+
scopeMode: "tool_signature",
|
|
217
|
+
toolName: "shell",
|
|
217
218
|
inputDigest: digest,
|
|
218
219
|
}),
|
|
219
220
|
);
|
|
220
221
|
|
|
221
222
|
const result = await consumeGrantForInvocation({
|
|
222
|
-
requestId:
|
|
223
|
-
toolName:
|
|
223
|
+
requestId: "nonexistent-req",
|
|
224
|
+
toolName: "shell",
|
|
224
225
|
inputDigest: digest,
|
|
225
|
-
consumingRequestId:
|
|
226
|
-
assistantId:
|
|
226
|
+
consumingRequestId: "consumer-3",
|
|
227
|
+
assistantId: "self",
|
|
227
228
|
});
|
|
228
229
|
|
|
229
230
|
expect(result.ok).toBe(true);
|
|
230
231
|
if (!result.ok) return;
|
|
231
|
-
expect(result.grant.scopeMode).toBe(
|
|
232
|
+
expect(result.grant.scopeMode).toBe("tool_signature");
|
|
232
233
|
});
|
|
233
234
|
|
|
234
235
|
// ---------------------------------------------------------------------------
|
|
235
236
|
// Consume miss scenarios
|
|
236
237
|
// ---------------------------------------------------------------------------
|
|
237
238
|
|
|
238
|
-
test(
|
|
239
|
-
const result = await consumeGrantForInvocation(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
239
|
+
test("miss: no grants exist at all", async () => {
|
|
240
|
+
const result = await consumeGrantForInvocation(
|
|
241
|
+
{
|
|
242
|
+
toolName: "shell",
|
|
243
|
+
inputDigest: computeToolApprovalDigest("shell", { command: "ls" }),
|
|
244
|
+
consumingRequestId: "consumer-miss",
|
|
245
|
+
assistantId: "self",
|
|
246
|
+
},
|
|
247
|
+
{ maxWaitMs: 0 },
|
|
248
|
+
);
|
|
245
249
|
|
|
246
250
|
expect(result.ok).toBe(false);
|
|
247
251
|
if (result.ok) return;
|
|
248
|
-
expect(result.reason).toBe(
|
|
252
|
+
expect(result.reason).toBe("no_match");
|
|
249
253
|
});
|
|
250
254
|
|
|
251
|
-
test(
|
|
252
|
-
const digest = computeToolApprovalDigest(
|
|
255
|
+
test("miss: tool name mismatch", async () => {
|
|
256
|
+
const digest = computeToolApprovalDigest("shell", { command: "ls" });
|
|
253
257
|
mintGrantFromDecision(
|
|
254
258
|
mintParams({
|
|
255
|
-
scopeMode:
|
|
256
|
-
toolName:
|
|
259
|
+
scopeMode: "tool_signature",
|
|
260
|
+
toolName: "shell",
|
|
257
261
|
inputDigest: digest,
|
|
258
262
|
}),
|
|
259
263
|
);
|
|
260
264
|
|
|
261
|
-
const result = await consumeGrantForInvocation(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
const result = await consumeGrantForInvocation(
|
|
266
|
+
{
|
|
267
|
+
toolName: "file_write",
|
|
268
|
+
inputDigest: digest,
|
|
269
|
+
consumingRequestId: "consumer-mismatch-tool",
|
|
270
|
+
assistantId: "self",
|
|
271
|
+
},
|
|
272
|
+
{ maxWaitMs: 0 },
|
|
273
|
+
);
|
|
267
274
|
|
|
268
275
|
expect(result.ok).toBe(false);
|
|
269
276
|
if (result.ok) return;
|
|
270
|
-
expect(result.reason).toBe(
|
|
277
|
+
expect(result.reason).toBe("no_match");
|
|
271
278
|
});
|
|
272
279
|
|
|
273
|
-
test(
|
|
280
|
+
test("miss: input digest mismatch", async () => {
|
|
274
281
|
mintGrantFromDecision(
|
|
275
282
|
mintParams({
|
|
276
|
-
scopeMode:
|
|
277
|
-
toolName:
|
|
278
|
-
inputDigest: computeToolApprovalDigest(
|
|
283
|
+
scopeMode: "tool_signature",
|
|
284
|
+
toolName: "shell",
|
|
285
|
+
inputDigest: computeToolApprovalDigest("shell", { command: "ls" }),
|
|
279
286
|
}),
|
|
280
287
|
);
|
|
281
288
|
|
|
282
|
-
const result = await consumeGrantForInvocation(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
289
|
+
const result = await consumeGrantForInvocation(
|
|
290
|
+
{
|
|
291
|
+
toolName: "shell",
|
|
292
|
+
inputDigest: computeToolApprovalDigest("shell", {
|
|
293
|
+
command: "rm -rf /",
|
|
294
|
+
}),
|
|
295
|
+
consumingRequestId: "consumer-mismatch-input",
|
|
296
|
+
assistantId: "self",
|
|
297
|
+
},
|
|
298
|
+
{ maxWaitMs: 0 },
|
|
299
|
+
);
|
|
288
300
|
|
|
289
301
|
expect(result.ok).toBe(false);
|
|
290
302
|
if (result.ok) return;
|
|
291
|
-
expect(result.reason).toBe(
|
|
303
|
+
expect(result.reason).toBe("no_match");
|
|
292
304
|
});
|
|
293
305
|
|
|
294
|
-
test(
|
|
306
|
+
test("miss: assistant ID mismatch", async () => {
|
|
295
307
|
mintGrantFromDecision(
|
|
296
308
|
mintParams({
|
|
297
|
-
scopeMode:
|
|
298
|
-
requestId:
|
|
299
|
-
assistantId:
|
|
309
|
+
scopeMode: "request_id",
|
|
310
|
+
requestId: "req-assist",
|
|
311
|
+
assistantId: "assistant-A",
|
|
300
312
|
}),
|
|
301
313
|
);
|
|
302
314
|
|
|
303
|
-
const result = await consumeGrantForInvocation(
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
315
|
+
const result = await consumeGrantForInvocation(
|
|
316
|
+
{
|
|
317
|
+
requestId: "req-assist",
|
|
318
|
+
toolName: "shell",
|
|
319
|
+
inputDigest: computeToolApprovalDigest("shell", {}),
|
|
320
|
+
consumingRequestId: "consumer-assist-mismatch",
|
|
321
|
+
assistantId: "assistant-B",
|
|
322
|
+
},
|
|
323
|
+
{ maxWaitMs: 0 },
|
|
324
|
+
);
|
|
310
325
|
|
|
311
326
|
expect(result.ok).toBe(false);
|
|
312
327
|
if (result.ok) return;
|
|
313
|
-
expect(result.reason).toBe(
|
|
328
|
+
expect(result.reason).toBe("no_match");
|
|
314
329
|
});
|
|
315
330
|
|
|
316
|
-
test(
|
|
331
|
+
test("miss: grant expired", async () => {
|
|
317
332
|
const pastExpiry = new Date(Date.now() - 60_000).toISOString();
|
|
318
333
|
mintGrantFromDecision(
|
|
319
334
|
mintParams({
|
|
320
|
-
scopeMode:
|
|
321
|
-
requestId:
|
|
335
|
+
scopeMode: "request_id",
|
|
336
|
+
requestId: "req-expired",
|
|
322
337
|
expiresAt: pastExpiry,
|
|
323
338
|
}),
|
|
324
339
|
);
|
|
325
340
|
|
|
326
|
-
const result = await consumeGrantForInvocation(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
341
|
+
const result = await consumeGrantForInvocation(
|
|
342
|
+
{
|
|
343
|
+
requestId: "req-expired",
|
|
344
|
+
toolName: "shell",
|
|
345
|
+
inputDigest: computeToolApprovalDigest("shell", {}),
|
|
346
|
+
consumingRequestId: "consumer-expired",
|
|
347
|
+
assistantId: "self",
|
|
348
|
+
},
|
|
349
|
+
{ maxWaitMs: 0 },
|
|
350
|
+
);
|
|
333
351
|
|
|
334
352
|
expect(result.ok).toBe(false);
|
|
335
353
|
if (result.ok) return;
|
|
336
|
-
expect(result.reason).toBe(
|
|
354
|
+
expect(result.reason).toBe("no_match");
|
|
337
355
|
});
|
|
338
356
|
|
|
339
357
|
// ---------------------------------------------------------------------------
|
|
340
358
|
// One-time consume semantics
|
|
341
359
|
// ---------------------------------------------------------------------------
|
|
342
360
|
|
|
343
|
-
test(
|
|
361
|
+
test("one-time consume: second consume of the same grant fails", async () => {
|
|
344
362
|
mintGrantFromDecision(
|
|
345
|
-
mintParams({ scopeMode:
|
|
363
|
+
mintParams({ scopeMode: "request_id", requestId: "req-once" }),
|
|
346
364
|
);
|
|
347
365
|
|
|
348
366
|
const first = await consumeGrantForInvocation({
|
|
349
|
-
requestId:
|
|
350
|
-
toolName:
|
|
351
|
-
inputDigest: computeToolApprovalDigest(
|
|
352
|
-
consumingRequestId:
|
|
353
|
-
assistantId:
|
|
367
|
+
requestId: "req-once",
|
|
368
|
+
toolName: "shell",
|
|
369
|
+
inputDigest: computeToolApprovalDigest("shell", {}),
|
|
370
|
+
consumingRequestId: "consumer-first",
|
|
371
|
+
assistantId: "self",
|
|
354
372
|
});
|
|
355
373
|
expect(first.ok).toBe(true);
|
|
356
374
|
|
|
357
|
-
const second = await consumeGrantForInvocation(
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
375
|
+
const second = await consumeGrantForInvocation(
|
|
376
|
+
{
|
|
377
|
+
requestId: "req-once",
|
|
378
|
+
toolName: "shell",
|
|
379
|
+
inputDigest: computeToolApprovalDigest("shell", {}),
|
|
380
|
+
consumingRequestId: "consumer-second",
|
|
381
|
+
assistantId: "self",
|
|
382
|
+
},
|
|
383
|
+
{ maxWaitMs: 0 },
|
|
384
|
+
);
|
|
364
385
|
expect(second.ok).toBe(false);
|
|
365
386
|
if (second.ok) return;
|
|
366
|
-
expect(second.reason).toBe(
|
|
387
|
+
expect(second.reason).toBe("no_match");
|
|
367
388
|
});
|
|
368
389
|
|
|
369
|
-
test(
|
|
370
|
-
const digest = computeToolApprovalDigest(
|
|
390
|
+
test("one-time consume: tool_signature grant is consumed only once", async () => {
|
|
391
|
+
const digest = computeToolApprovalDigest("shell", { command: "deploy" });
|
|
371
392
|
mintGrantFromDecision(
|
|
372
393
|
mintParams({
|
|
373
|
-
scopeMode:
|
|
374
|
-
toolName:
|
|
394
|
+
scopeMode: "tool_signature",
|
|
395
|
+
toolName: "shell",
|
|
375
396
|
inputDigest: digest,
|
|
376
397
|
}),
|
|
377
398
|
);
|
|
378
399
|
|
|
379
400
|
const first = await consumeGrantForInvocation({
|
|
380
|
-
toolName:
|
|
401
|
+
toolName: "shell",
|
|
381
402
|
inputDigest: digest,
|
|
382
|
-
consumingRequestId:
|
|
383
|
-
assistantId:
|
|
403
|
+
consumingRequestId: "consumer-sig-first",
|
|
404
|
+
assistantId: "self",
|
|
384
405
|
});
|
|
385
406
|
expect(first.ok).toBe(true);
|
|
386
407
|
|
|
387
|
-
const second = await consumeGrantForInvocation(
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
408
|
+
const second = await consumeGrantForInvocation(
|
|
409
|
+
{
|
|
410
|
+
toolName: "shell",
|
|
411
|
+
inputDigest: digest,
|
|
412
|
+
consumingRequestId: "consumer-sig-second",
|
|
413
|
+
assistantId: "self",
|
|
414
|
+
},
|
|
415
|
+
{ maxWaitMs: 0 },
|
|
416
|
+
);
|
|
393
417
|
expect(second.ok).toBe(false);
|
|
394
418
|
if (second.ok) return;
|
|
395
|
-
expect(second.reason).toBe(
|
|
419
|
+
expect(second.reason).toBe("no_match");
|
|
396
420
|
});
|
|
397
421
|
|
|
398
422
|
// ---------------------------------------------------------------------------
|
|
399
423
|
// Context-scoped consume
|
|
400
424
|
// ---------------------------------------------------------------------------
|
|
401
425
|
|
|
402
|
-
test(
|
|
403
|
-
const digest = computeToolApprovalDigest(
|
|
426
|
+
test("consumes tool_signature grant with matching conversation context", async () => {
|
|
427
|
+
const digest = computeToolApprovalDigest("shell", { command: "test" });
|
|
404
428
|
mintGrantFromDecision(
|
|
405
429
|
mintParams({
|
|
406
|
-
scopeMode:
|
|
407
|
-
toolName:
|
|
430
|
+
scopeMode: "tool_signature",
|
|
431
|
+
toolName: "shell",
|
|
408
432
|
inputDigest: digest,
|
|
409
|
-
conversationId:
|
|
410
|
-
callSessionId:
|
|
433
|
+
conversationId: "conv-ctx",
|
|
434
|
+
callSessionId: "call-ctx",
|
|
411
435
|
}),
|
|
412
436
|
);
|
|
413
437
|
|
|
414
438
|
const result = await consumeGrantForInvocation({
|
|
415
|
-
toolName:
|
|
439
|
+
toolName: "shell",
|
|
416
440
|
inputDigest: digest,
|
|
417
|
-
consumingRequestId:
|
|
418
|
-
assistantId:
|
|
419
|
-
conversationId:
|
|
420
|
-
callSessionId:
|
|
441
|
+
consumingRequestId: "consumer-ctx",
|
|
442
|
+
assistantId: "self",
|
|
443
|
+
conversationId: "conv-ctx",
|
|
444
|
+
callSessionId: "call-ctx",
|
|
421
445
|
});
|
|
422
446
|
|
|
423
447
|
expect(result.ok).toBe(true);
|
|
424
448
|
});
|
|
425
449
|
|
|
426
|
-
test(
|
|
427
|
-
const digest = computeToolApprovalDigest(
|
|
450
|
+
test("miss: conversation context mismatch on tool_signature grant", async () => {
|
|
451
|
+
const digest = computeToolApprovalDigest("shell", { command: "test" });
|
|
428
452
|
mintGrantFromDecision(
|
|
429
453
|
mintParams({
|
|
430
|
-
scopeMode:
|
|
431
|
-
toolName:
|
|
454
|
+
scopeMode: "tool_signature",
|
|
455
|
+
toolName: "shell",
|
|
432
456
|
inputDigest: digest,
|
|
433
|
-
conversationId:
|
|
457
|
+
conversationId: "conv-A",
|
|
434
458
|
}),
|
|
435
459
|
);
|
|
436
460
|
|
|
437
|
-
const result = await consumeGrantForInvocation(
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
461
|
+
const result = await consumeGrantForInvocation(
|
|
462
|
+
{
|
|
463
|
+
toolName: "shell",
|
|
464
|
+
inputDigest: digest,
|
|
465
|
+
consumingRequestId: "consumer-ctx-mismatch",
|
|
466
|
+
assistantId: "self",
|
|
467
|
+
conversationId: "conv-B",
|
|
468
|
+
},
|
|
469
|
+
{ maxWaitMs: 0 },
|
|
470
|
+
);
|
|
444
471
|
|
|
445
472
|
expect(result.ok).toBe(false);
|
|
446
473
|
if (result.ok) return;
|
|
447
|
-
expect(result.reason).toBe(
|
|
474
|
+
expect(result.reason).toBe("no_match");
|
|
448
475
|
});
|
|
449
476
|
});
|
|
450
477
|
|
|
@@ -452,44 +479,44 @@ describe('approval-primitive / consumeGrantForInvocation', () => {
|
|
|
452
479
|
// RETRY POLLING TESTS
|
|
453
480
|
// ===========================================================================
|
|
454
481
|
|
|
455
|
-
describe(
|
|
482
|
+
describe("approval-primitive / consumeGrantForInvocation retry", () => {
|
|
456
483
|
beforeEach(() => clearTables());
|
|
457
484
|
|
|
458
|
-
test(
|
|
459
|
-
const digest = computeToolApprovalDigest(
|
|
485
|
+
test("succeeds immediately when grant already exists (no retry needed)", async () => {
|
|
486
|
+
const digest = computeToolApprovalDigest("shell", { command: "ls" });
|
|
460
487
|
mintGrantFromDecision(
|
|
461
488
|
mintParams({
|
|
462
|
-
scopeMode:
|
|
463
|
-
toolName:
|
|
489
|
+
scopeMode: "tool_signature",
|
|
490
|
+
toolName: "shell",
|
|
464
491
|
inputDigest: digest,
|
|
465
492
|
}),
|
|
466
493
|
);
|
|
467
494
|
|
|
468
495
|
const start = Date.now();
|
|
469
496
|
const result = await consumeGrantForInvocation({
|
|
470
|
-
toolName:
|
|
497
|
+
toolName: "shell",
|
|
471
498
|
inputDigest: digest,
|
|
472
|
-
consumingRequestId:
|
|
473
|
-
assistantId:
|
|
499
|
+
consumingRequestId: "consumer-async-immediate",
|
|
500
|
+
assistantId: "self",
|
|
474
501
|
});
|
|
475
502
|
const elapsed = Date.now() - start;
|
|
476
503
|
|
|
477
504
|
expect(result.ok).toBe(true);
|
|
478
505
|
if (!result.ok) return;
|
|
479
|
-
expect(result.grant.status).toBe(
|
|
506
|
+
expect(result.grant.status).toBe("consumed");
|
|
480
507
|
// Should return nearly instantly — well under the retry interval
|
|
481
508
|
expect(elapsed).toBeLessThan(200);
|
|
482
509
|
});
|
|
483
510
|
|
|
484
|
-
test(
|
|
485
|
-
const digest = computeToolApprovalDigest(
|
|
511
|
+
test("retries and succeeds when grant appears after a delay", async () => {
|
|
512
|
+
const digest = computeToolApprovalDigest("shell", { command: "delayed" });
|
|
486
513
|
|
|
487
514
|
// Mint the grant after 300ms — the async consumer should retry and find it
|
|
488
515
|
setTimeout(() => {
|
|
489
516
|
mintGrantFromDecision(
|
|
490
517
|
mintParams({
|
|
491
|
-
scopeMode:
|
|
492
|
-
toolName:
|
|
518
|
+
scopeMode: "tool_signature",
|
|
519
|
+
toolName: "shell",
|
|
493
520
|
inputDigest: digest,
|
|
494
521
|
}),
|
|
495
522
|
);
|
|
@@ -498,10 +525,10 @@ describe('approval-primitive / consumeGrantForInvocation retry', () => {
|
|
|
498
525
|
const start = Date.now();
|
|
499
526
|
const result = await consumeGrantForInvocation(
|
|
500
527
|
{
|
|
501
|
-
toolName:
|
|
528
|
+
toolName: "shell",
|
|
502
529
|
inputDigest: digest,
|
|
503
|
-
consumingRequestId:
|
|
504
|
-
assistantId:
|
|
530
|
+
consumingRequestId: "consumer-async-delayed",
|
|
531
|
+
assistantId: "self",
|
|
505
532
|
},
|
|
506
533
|
{ maxWaitMs: 5_000, intervalMs: 100 },
|
|
507
534
|
);
|
|
@@ -509,22 +536,24 @@ describe('approval-primitive / consumeGrantForInvocation retry', () => {
|
|
|
509
536
|
|
|
510
537
|
expect(result.ok).toBe(true);
|
|
511
538
|
if (!result.ok) return;
|
|
512
|
-
expect(result.grant.status).toBe(
|
|
539
|
+
expect(result.grant.status).toBe("consumed");
|
|
513
540
|
// Should have taken at least ~300ms (the delay) but less than the max wait
|
|
514
541
|
expect(elapsed).toBeGreaterThanOrEqual(250);
|
|
515
542
|
expect(elapsed).toBeLessThan(5_000);
|
|
516
543
|
});
|
|
517
544
|
|
|
518
|
-
test(
|
|
519
|
-
const digest = computeToolApprovalDigest(
|
|
545
|
+
test("returns failure after timeout when no grant appears", async () => {
|
|
546
|
+
const digest = computeToolApprovalDigest("shell", {
|
|
547
|
+
command: "never-minted",
|
|
548
|
+
});
|
|
520
549
|
|
|
521
550
|
const start = Date.now();
|
|
522
551
|
const result = await consumeGrantForInvocation(
|
|
523
552
|
{
|
|
524
|
-
toolName:
|
|
553
|
+
toolName: "shell",
|
|
525
554
|
inputDigest: digest,
|
|
526
|
-
consumingRequestId:
|
|
527
|
-
assistantId:
|
|
555
|
+
consumingRequestId: "consumer-async-timeout",
|
|
556
|
+
assistantId: "self",
|
|
528
557
|
},
|
|
529
558
|
{ maxWaitMs: 500, intervalMs: 100 },
|
|
530
559
|
);
|
|
@@ -532,14 +561,14 @@ describe('approval-primitive / consumeGrantForInvocation retry', () => {
|
|
|
532
561
|
|
|
533
562
|
expect(result.ok).toBe(false);
|
|
534
563
|
if (result.ok) return;
|
|
535
|
-
expect(result.reason).toBe(
|
|
564
|
+
expect(result.reason).toBe("no_match");
|
|
536
565
|
// Should have waited approximately the max wait time
|
|
537
566
|
expect(elapsed).toBeGreaterThanOrEqual(450);
|
|
538
567
|
expect(elapsed).toBeLessThan(1_500);
|
|
539
568
|
});
|
|
540
569
|
|
|
541
|
-
test(
|
|
542
|
-
const digest = computeToolApprovalDigest(
|
|
570
|
+
test("returns aborted when signal fires during retry polling", async () => {
|
|
571
|
+
const digest = computeToolApprovalDigest("shell", { command: "aborted" });
|
|
543
572
|
const controller = new AbortController();
|
|
544
573
|
|
|
545
574
|
// Abort after 200ms — well before the 2s max wait
|
|
@@ -548,10 +577,10 @@ describe('approval-primitive / consumeGrantForInvocation retry', () => {
|
|
|
548
577
|
const start = Date.now();
|
|
549
578
|
const result = await consumeGrantForInvocation(
|
|
550
579
|
{
|
|
551
|
-
toolName:
|
|
580
|
+
toolName: "shell",
|
|
552
581
|
inputDigest: digest,
|
|
553
|
-
consumingRequestId:
|
|
554
|
-
assistantId:
|
|
582
|
+
consumingRequestId: "consumer-aborted",
|
|
583
|
+
assistantId: "self",
|
|
555
584
|
},
|
|
556
585
|
{ maxWaitMs: 2_000, intervalMs: 50, signal: controller.signal },
|
|
557
586
|
);
|
|
@@ -559,23 +588,25 @@ describe('approval-primitive / consumeGrantForInvocation retry', () => {
|
|
|
559
588
|
|
|
560
589
|
expect(result.ok).toBe(false);
|
|
561
590
|
if (result.ok) return;
|
|
562
|
-
expect(result.reason).toBe(
|
|
591
|
+
expect(result.reason).toBe("aborted");
|
|
563
592
|
// Should have exited shortly after the abort (200ms), not waited the full 2s
|
|
564
593
|
expect(elapsed).toBeLessThan(1_000);
|
|
565
594
|
});
|
|
566
595
|
|
|
567
|
-
test(
|
|
568
|
-
const digest = computeToolApprovalDigest(
|
|
596
|
+
test("returns aborted immediately when signal is already aborted", async () => {
|
|
597
|
+
const digest = computeToolApprovalDigest("shell", {
|
|
598
|
+
command: "pre-aborted",
|
|
599
|
+
});
|
|
569
600
|
const controller = new AbortController();
|
|
570
601
|
controller.abort();
|
|
571
602
|
|
|
572
603
|
const start = Date.now();
|
|
573
604
|
const result = await consumeGrantForInvocation(
|
|
574
605
|
{
|
|
575
|
-
toolName:
|
|
606
|
+
toolName: "shell",
|
|
576
607
|
inputDigest: digest,
|
|
577
|
-
consumingRequestId:
|
|
578
|
-
assistantId:
|
|
608
|
+
consumingRequestId: "consumer-pre-aborted",
|
|
609
|
+
assistantId: "self",
|
|
579
610
|
},
|
|
580
611
|
{ maxWaitMs: 2_000, intervalMs: 50, signal: controller.signal },
|
|
581
612
|
);
|
|
@@ -583,21 +614,21 @@ describe('approval-primitive / consumeGrantForInvocation retry', () => {
|
|
|
583
614
|
|
|
584
615
|
expect(result.ok).toBe(false);
|
|
585
616
|
if (result.ok) return;
|
|
586
|
-
expect(result.reason).toBe(
|
|
617
|
+
expect(result.reason).toBe("aborted");
|
|
587
618
|
// Should return nearly instantly since signal was already aborted
|
|
588
619
|
expect(elapsed).toBeLessThan(200);
|
|
589
620
|
});
|
|
590
621
|
|
|
591
|
-
test(
|
|
592
|
-
const digest = computeToolApprovalDigest(
|
|
622
|
+
test("skips retry entirely when maxWaitMs is 0", async () => {
|
|
623
|
+
const digest = computeToolApprovalDigest("shell", { command: "no-retry" });
|
|
593
624
|
|
|
594
625
|
const start = Date.now();
|
|
595
626
|
const result = await consumeGrantForInvocation(
|
|
596
627
|
{
|
|
597
|
-
toolName:
|
|
628
|
+
toolName: "shell",
|
|
598
629
|
inputDigest: digest,
|
|
599
|
-
consumingRequestId:
|
|
600
|
-
assistantId:
|
|
630
|
+
consumingRequestId: "consumer-no-retry",
|
|
631
|
+
assistantId: "self",
|
|
601
632
|
},
|
|
602
633
|
{ maxWaitMs: 0 },
|
|
603
634
|
);
|
|
@@ -605,7 +636,7 @@ describe('approval-primitive / consumeGrantForInvocation retry', () => {
|
|
|
605
636
|
|
|
606
637
|
expect(result.ok).toBe(false);
|
|
607
638
|
if (result.ok) return;
|
|
608
|
-
expect(result.reason).toBe(
|
|
639
|
+
expect(result.reason).toBe("no_match");
|
|
609
640
|
// Should return nearly instantly — no retry loop
|
|
610
641
|
expect(elapsed).toBeLessThan(100);
|
|
611
642
|
});
|