@vellumai/assistant 0.4.56 → 0.5.0
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 +10 -10
- package/Dockerfile +3 -0
- package/README.md +11 -11
- package/docs/architecture/integrations.md +2 -2
- package/docs/architecture/memory.md +3 -4
- package/docs/credential-execution-service.md +13 -20
- package/node_modules/@vellumai/ces-contracts/src/error.ts +5 -4
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +7 -7
- package/src/__tests__/anthropic-provider.test.ts +172 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +15 -1
- package/src/__tests__/approval-cascade.test.ts +2 -2
- package/src/__tests__/approval-routes-http.test.ts +3 -4
- package/src/__tests__/asset-materialize-tool.test.ts +5 -5
- package/src/__tests__/asset-search-tool.test.ts +1 -1
- package/src/__tests__/assistant-attachments.test.ts +5 -5
- package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
- package/src/__tests__/assistant-feature-flags-integration.test.ts +50 -38
- package/src/__tests__/attachments-store.test.ts +2 -2
- package/src/__tests__/avatar-e2e.test.ts +5 -3
- package/src/__tests__/browser-skill-endstate.test.ts +0 -1
- package/src/__tests__/call-routes-http.test.ts +2 -2
- package/src/__tests__/callback-handoff-copy.test.ts +1 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +158 -0
- package/src/__tests__/channel-readiness-routes.test.ts +0 -1
- package/src/__tests__/channel-readiness-service.test.ts +0 -1
- package/src/__tests__/checker.test.ts +31 -32
- package/src/__tests__/chrome-cdp.test.ts +47 -18
- package/src/__tests__/claude-code-skill-regression.test.ts +2 -2
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +9 -18
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -2
- package/src/__tests__/conversation-agent-loop.test.ts +11 -4
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +33 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -1
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +1 -1
- package/src/__tests__/conversation-pre-run-repair.test.ts +4 -4
- package/src/__tests__/conversation-provider-retry-repair.test.ts +4 -4
- package/src/__tests__/conversation-queue.test.ts +23 -14
- package/src/__tests__/conversation-routes-slash-commands.test.ts +3 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +204 -185
- package/src/__tests__/conversation-seed-composer.test.ts +1 -1
- package/src/__tests__/conversation-slash-queue.test.ts +4 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -4
- package/src/__tests__/conversation-starter-routes.test.ts +291 -0
- package/src/__tests__/conversation-wipe.test.ts +438 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -3
- package/src/__tests__/conversation-workspace-injection.test.ts +4 -5
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -5
- package/src/__tests__/credential-security-e2e.test.ts +20 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +227 -0
- package/src/__tests__/credentials-cli.test.ts +3 -0
- package/src/__tests__/date-context.test.ts +59 -377
- package/src/__tests__/drop-capability-card-state-migration.test.ts +169 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +11 -45
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
- package/src/__tests__/encrypted-store.test.ts +249 -15
- package/src/__tests__/ephemeral-permissions.test.ts +4 -5
- package/src/__tests__/event-bus.test.ts +3 -3
- package/src/__tests__/file-read-tool.test.ts +40 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +2 -2
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/gemini-image-service.test.ts +4 -4
- package/src/__tests__/gemini-provider.test.ts +6 -9
- package/src/__tests__/guardian-binding-drift-heal.test.ts +128 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/host-file-read-tool.test.ts +87 -0
- package/src/__tests__/host-shell-tool.test.ts +6 -6
- package/src/__tests__/http-user-message-parity.test.ts +2 -2
- package/src/__tests__/identity-intro-cache.test.ts +209 -0
- package/src/__tests__/intent-routing.test.ts +51 -99
- package/src/__tests__/invite-routes-http.test.ts +5 -0
- package/src/__tests__/list-messages-attachments.test.ts +1 -1
- package/src/__tests__/managed-proxy-context.test.ts +2 -5
- package/src/__tests__/managed-skill-lifecycle.test.ts +8 -8
- package/src/__tests__/media-generate-image.test.ts +32 -15
- package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +1 -1
- package/src/__tests__/memory-lifecycle-e2e.test.ts +24 -18
- package/src/__tests__/memory-recall-quality.test.ts +4 -3
- package/src/__tests__/memory-regressions.test.ts +86 -90
- package/src/__tests__/migration-cross-version-compatibility.test.ts +32 -32
- package/src/__tests__/migration-export-http.test.ts +26 -27
- package/src/__tests__/migration-import-commit-http.test.ts +165 -37
- package/src/__tests__/migration-import-preflight-http.test.ts +81 -20
- package/src/__tests__/migration-validate-http.test.ts +16 -16
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
- package/src/__tests__/non-member-access-request.test.ts +3 -3
- package/src/__tests__/notification-broadcaster.test.ts +1 -1
- package/src/__tests__/notification-decision-fallback.test.ts +2 -2
- package/src/__tests__/notification-decision-identity.test.ts +8 -9
- package/src/__tests__/notification-decision-strategy.test.ts +1 -1
- package/src/__tests__/notification-deep-link.test.ts +1 -1
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/notification-schedule-dedup.test.ts +7 -7
- package/src/__tests__/oauth-store.test.ts +1 -3
- package/src/__tests__/oauth2-gateway-transport.test.ts +6 -1
- package/src/__tests__/onboarding-template-contract.test.ts +23 -59
- package/src/__tests__/provider-error-scenarios.test.ts +154 -0
- package/src/__tests__/provider-fail-open-selection.test.ts +2 -2
- package/src/__tests__/provider-managed-proxy-integration.test.ts +8 -9
- package/src/__tests__/provider-registry-ollama.test.ts +5 -2
- package/src/__tests__/qdrant-manager.test.ts +7 -7
- package/src/__tests__/ratelimit.test.ts +0 -74
- package/src/__tests__/recording-handler.test.ts +0 -1
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/scheduler-recurrence.test.ts +46 -2
- package/src/__tests__/schema-transforms.test.ts +114 -54
- package/src/__tests__/secret-onetime-send.test.ts +20 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -2
- package/src/__tests__/secret-scanner-executor.test.ts +1 -2
- package/src/__tests__/send-endpoint-busy.test.ts +63 -4
- package/src/__tests__/send-notification-tool.test.ts +2 -2
- package/src/__tests__/shell-credential-ref.test.ts +0 -1
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -2
- package/src/__tests__/skill-memory.test.ts +549 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -2
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -0
- package/src/__tests__/slack-channel-config.test.ts +109 -94
- package/src/__tests__/swarm-conversation-integration.test.ts +2 -2
- package/src/__tests__/swarm-recursion.test.ts +2 -2
- package/src/__tests__/swarm-tool.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +19 -66
- package/src/__tests__/telegram-config.test.ts +121 -0
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +1 -1
- package/src/__tests__/trace-emitter.test.ts +8 -1
- package/src/__tests__/trust-store.test.ts +7 -8
- package/src/__tests__/twilio-routes.test.ts +1 -18
- package/src/__tests__/user-reference.test.ts +82 -2
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +196 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
- package/src/approvals/guardian-request-resolvers.ts +3 -3
- package/src/avatar/ascii-renderer.ts +2 -2
- package/src/avatar/png-renderer.ts +2 -2
- package/src/avatar/resvg-lazy.ts +21 -0
- package/src/calls/guardian-dispatch.ts +1 -1
- package/src/calls/relay-access-wait.ts +2 -2
- package/src/calls/twilio-rest.ts +0 -248
- package/src/cli/AGENTS.md +5 -8
- package/src/cli/__tests__/notifications.test.ts +5 -5
- package/src/cli/commands/avatar.ts +64 -2
- package/src/cli/commands/conversations.ts +131 -1
- package/src/cli/commands/credentials.ts +2 -0
- package/src/cli/commands/notifications.ts +3 -3
- package/src/cli.ts +10 -0
- package/src/config/bundled-skills/acp/SKILL.md +5 -5
- package/src/config/bundled-skills/acp/TOOLS.json +6 -6
- package/src/config/bundled-skills/app-builder/SKILL.md +42 -42
- package/src/config/bundled-skills/app-builder/TOOLS.json +10 -10
- package/src/config/bundled-skills/browser/SKILL.md +15 -15
- package/src/config/bundled-skills/browser/TOOLS.json +14 -14
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +2 -2
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +1 -1
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
- package/src/config/bundled-skills/claude-code/SKILL.md +5 -5
- package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -15
- package/src/config/bundled-skills/contacts/SKILL.md +3 -3
- package/src/config/bundled-skills/contacts/TOOLS.json +4 -4
- package/src/config/bundled-skills/document/SKILL.md +4 -4
- package/src/config/bundled-skills/document/TOOLS.json +2 -2
- package/src/config/bundled-skills/followups/TOOLS.json +3 -3
- package/src/config/bundled-skills/gmail/SKILL.md +32 -32
- package/src/config/bundled-skills/gmail/TOOLS.json +16 -16
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
- package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
- package/src/config/bundled-skills/google-calendar/TOOLS.json +5 -5
- package/src/config/bundled-skills/google-calendar/types.ts +1 -1
- package/src/config/bundled-skills/heartbeat/SKILL.md +43 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +3 -3
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -3
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +16 -12
- package/src/config/bundled-skills/media-processing/SKILL.md +40 -40
- package/src/config/bundled-skills/media-processing/TOOLS.json +8 -8
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +2 -2
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +1 -1
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +5 -5
- package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/reduce.ts +3 -3
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +29 -25
- package/src/config/bundled-skills/messaging/TOOLS.json +11 -11
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
- package/src/config/bundled-skills/notifications/SKILL.md +3 -3
- package/src/config/bundled-skills/notifications/TOOLS.json +2 -2
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +3 -3
- package/src/config/bundled-skills/orchestration/SKILL.md +1 -1
- package/src/config/bundled-skills/orchestration/TOOLS.json +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +18 -14
- package/src/config/bundled-skills/phone-calls/TOOLS.json +3 -3
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +1 -1
- package/src/config/bundled-skills/playbooks/TOOLS.json +4 -4
- package/src/config/bundled-skills/schedule/SKILL.md +26 -26
- package/src/config/bundled-skills/schedule/TOOLS.json +5 -5
- package/src/config/bundled-skills/screen-watch/SKILL.md +3 -3
- package/src/config/bundled-skills/screen-watch/TOOLS.json +1 -1
- package/src/config/bundled-skills/sequences/SKILL.md +2 -2
- package/src/config/bundled-skills/sequences/TOOLS.json +10 -10
- package/src/config/bundled-skills/sequences/tools/sequence-analytics.ts +2 -2
- package/src/config/bundled-skills/sequences/tools/sequence-enroll.ts +2 -2
- package/src/config/bundled-skills/sequences/tools/sequence-enrollment-list.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-get.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-import.ts +3 -3
- package/src/config/bundled-skills/sequences/tools/sequence-list.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-update.ts +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +5 -5
- package/src/config/bundled-skills/skills-catalog/SKILL.md +84 -0
- package/src/config/bundled-skills/slack/SKILL.md +2 -2
- package/src/config/bundled-skills/slack/TOOLS.json +8 -8
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +3 -3
- package/src/config/bundled-skills/subagent/TOOLS.json +5 -5
- package/src/config/bundled-skills/tasks/SKILL.md +1 -1
- package/src/config/bundled-skills/tasks/TOOLS.json +9 -9
- package/src/config/bundled-skills/transcribe/SKILL.md +5 -5
- package/src/config/bundled-skills/transcribe/TOOLS.json +1 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +10 -10
- package/src/config/bundled-skills/watcher/SKILL.md +4 -4
- package/src/config/bundled-skills/watcher/TOOLS.json +5 -5
- package/src/config/feature-flag-registry.json +33 -17
- package/src/config/schemas/sandbox.ts +1 -1
- package/src/config/schemas/services.ts +13 -3
- package/src/config/schemas/timeouts.ts +0 -10
- package/src/contacts/contact-store.ts +63 -0
- package/src/contacts/contacts-write.ts +1 -1
- package/src/daemon/assistant-attachments.ts +2 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -2
- package/src/daemon/conversation-agent-loop.ts +7 -30
- package/src/daemon/conversation-error.ts +24 -0
- package/src/daemon/conversation-memory.ts +8 -7
- package/src/daemon/conversation-runtime-assembly.ts +141 -275
- package/src/daemon/conversation-slash.ts +7 -26
- package/src/daemon/conversation-surfaces.ts +14 -0
- package/src/daemon/conversation-tool-setup.ts +9 -8
- package/src/daemon/conversation.ts +2 -0
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +10 -83
- package/src/daemon/handlers/config-channels.ts +12 -2
- package/src/daemon/handlers/config-slack-channel.ts +7 -1
- package/src/daemon/handlers/config-telegram.ts +6 -1
- package/src/daemon/handlers/conversations.ts +2 -2
- package/src/daemon/handlers/skills.ts +4 -0
- package/src/daemon/lifecycle.ts +28 -4
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +1 -5
- package/src/daemon/shutdown-handlers.ts +9 -3
- package/src/daemon/tool-side-effects.ts +40 -0
- package/src/daemon/trace-emitter.ts +26 -2
- package/src/events/domain-events.ts +1 -1
- package/src/events/tool-permission-telemetry-listener.ts +46 -0
- package/src/inbound/platform-callback-registration.ts +0 -18
- package/src/media/app-icon-generator.ts +15 -8
- package/src/media/avatar-router.ts +15 -8
- package/src/media/gemini-image-service.ts +125 -21
- package/src/memory/attachments-store.ts +3 -3
- package/src/memory/channel-verification-sessions.ts +6 -6
- package/src/memory/conversation-crud.ts +196 -1
- package/src/memory/{thread-starters-cadence.ts → conversation-starters-cadence.ts} +9 -42
- package/src/memory/conversation-title-service.ts +2 -3
- package/src/memory/db-init.ts +25 -1
- package/src/memory/invite-store.ts +4 -4
- package/src/memory/items-extractor.ts +4 -4
- package/src/memory/job-handlers/{thread-starters.ts → conversation-starters.ts} +123 -38
- package/src/memory/jobs-store.ts +3 -2
- package/src/memory/jobs-worker.ts +7 -5
- package/src/memory/lifecycle-events-store.ts +63 -0
- package/src/memory/migrations/172-rename-created-by-session-id.ts +27 -0
- package/src/memory/migrations/173-rename-source-session-id.ts +16 -0
- package/src/memory/migrations/174-rename-thread-starters-table.ts +52 -0
- package/src/memory/migrations/175-create-lifecycle-events.ts +15 -0
- package/src/memory/migrations/176-drop-capability-card-state.ts +36 -0
- package/src/memory/migrations/177-create-trace-events-table.ts +40 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/retriever.test.ts +223 -96
- package/src/memory/retriever.ts +115 -138
- package/src/memory/schema/calls.ts +1 -1
- package/src/memory/schema/contacts.ts +1 -1
- package/src/memory/schema/infrastructure.ts +29 -0
- package/src/memory/schema/memory-core.ts +7 -17
- package/src/memory/schema/notifications.ts +1 -1
- package/src/memory/search/formatting.ts +23 -6
- package/src/memory/search/lexical.ts +2 -0
- package/src/memory/search/semantic.ts +2 -0
- package/src/memory/search/staleness.ts +5 -1
- package/src/memory/search/types.ts +4 -0
- package/src/memory/task-memory-cleanup.ts +96 -6
- package/src/memory/trace-event-store.ts +148 -0
- package/src/notifications/README.md +1 -1
- package/src/notifications/decision-engine.ts +45 -4
- package/src/notifications/emit-signal.ts +5 -4
- package/src/notifications/events-store.ts +4 -4
- package/src/notifications/signal.ts +1 -1
- package/src/oauth/manual-token-connection.ts +49 -25
- package/src/permissions/checker.ts +6 -5
- package/src/permissions/defaults.ts +4 -4
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +9 -90
- package/src/prompts/cache-boundary.ts +8 -0
- package/src/prompts/system-prompt.ts +105 -634
- package/src/prompts/templates/BOOTSTRAP.md +172 -33
- package/src/prompts/templates/IDENTITY.md +8 -24
- package/src/prompts/templates/SOUL.md +20 -41
- package/src/prompts/templates/USER.md +3 -19
- package/src/prompts/user-reference.ts +14 -16
- package/src/providers/anthropic/client.ts +51 -19
- package/src/providers/gemini/client.ts +6 -9
- package/src/providers/managed-proxy/constants.ts +1 -7
- package/src/providers/managed-proxy/context.ts +0 -1
- package/src/providers/model-intents.ts +5 -5
- package/src/providers/openai/client.ts +10 -1
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/ratelimit.ts +0 -35
- package/src/providers/registry.ts +3 -5
- package/src/providers/retry.ts +18 -1
- package/src/runtime/access-request-helper.ts +16 -2
- package/src/runtime/auth/route-policy.ts +7 -0
- package/src/runtime/channel-verification-service.ts +1 -1
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/guardian-vellum-migration.ts +61 -1
- package/src/runtime/http-server.ts +8 -4
- package/src/runtime/migrations/vbundle-builder.ts +212 -32
- package/src/runtime/migrations/vbundle-import-analyzer.ts +74 -8
- package/src/runtime/migrations/vbundle-importer.ts +66 -1
- package/src/runtime/migrations/vbundle-validator.ts +17 -3
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +4 -4
- package/src/runtime/routes/attachment-routes.ts +2 -2
- package/src/runtime/routes/btw-routes.ts +93 -0
- package/src/runtime/routes/channel-verification-routes.ts +19 -2
- package/src/runtime/routes/conversation-management-routes.ts +55 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +49 -5
- package/src/runtime/routes/conversation-starter-routes.ts +207 -0
- package/src/runtime/routes/guardian-bootstrap-routes.ts +13 -9
- package/src/runtime/routes/identity-intro-cache.ts +105 -0
- package/src/runtime/routes/identity-routes.ts +51 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -1
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +1 -1
- package/src/runtime/routes/migration-routes.ts +25 -13
- package/src/runtime/routes/secret-routes.ts +18 -0
- package/src/runtime/routes/settings-routes.ts +9 -9
- package/src/runtime/routes/telemetry-routes.ts +53 -0
- package/src/runtime/routes/trace-event-routes.ts +62 -0
- package/src/runtime/tool-grant-request-helper.ts +1 -1
- package/src/runtime/verification-outbound-actions.ts +47 -31
- package/src/security/encrypted-store.ts +262 -78
- package/src/skills/catalog-install.ts +10 -0
- package/src/skills/managed-store.ts +2 -0
- package/src/skills/skill-memory.ts +222 -0
- package/src/subagent/manager.ts +1 -4
- package/src/telemetry/types.ts +10 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +7 -2
- package/src/telemetry/usage-telemetry-reporter.ts +53 -4
- package/src/tools/AGENTS.md +11 -11
- package/src/tools/acp/spawn.ts +1 -1
- package/src/tools/apps/executors.ts +8 -8
- package/src/tools/apps/registry.ts +1 -1
- package/src/tools/assets/materialize.ts +6 -6
- package/src/tools/assets/search.ts +10 -10
- package/src/tools/browser/__tests__/auth-cache.test.ts +2 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +4 -4
- package/src/tools/browser/auth-detector.ts +6 -6
- package/src/tools/browser/browser-execution.ts +13 -13
- package/src/tools/browser/browser-manager.ts +3 -3
- package/src/tools/browser/chrome-cdp.ts +5 -5
- package/src/tools/browser/jit-auth.ts +2 -2
- package/src/tools/browser/network-recorder.test.ts +2 -2
- package/src/tools/browser/network-recorder.ts +3 -3
- package/src/tools/browser/runtime-check.ts +3 -3
- package/src/tools/claude-code/claude-code.ts +2 -2
- package/src/tools/computer-use/definitions.ts +18 -18
- package/src/tools/credential-execution/make-authenticated-request.ts +4 -4
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -3
- package/src/tools/credential-execution/run-authenticated-command.ts +4 -4
- package/src/tools/credentials/broker-types.ts +5 -5
- package/src/tools/credentials/broker.ts +15 -15
- package/src/tools/credentials/metadata-store.ts +2 -2
- package/src/tools/credentials/resolve.ts +1 -1
- package/src/tools/credentials/selection.ts +1 -1
- package/src/tools/credentials/tool-policy.ts +1 -1
- package/src/tools/credentials/vault.ts +115 -25
- package/src/tools/execution-target.ts +2 -2
- package/src/tools/executor.ts +7 -7
- package/src/tools/filesystem/edit.ts +2 -2
- package/src/tools/filesystem/read.ts +15 -4
- package/src/tools/filesystem/write.ts +1 -1
- package/src/tools/host-filesystem/edit.ts +2 -1
- package/src/tools/host-filesystem/read.ts +18 -1
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +9 -8
- package/src/tools/mcp/mcp-tool-factory.ts +7 -6
- package/src/tools/memory/definitions.ts +6 -5
- package/src/tools/memory/handlers.test.ts +1 -1
- package/src/tools/network/__tests__/web-search.test.ts +3 -3
- package/src/tools/network/domain-normalize.ts +2 -2
- package/src/tools/network/script-proxy/session-manager.ts +10 -10
- package/src/tools/network/web-fetch.ts +1 -1
- package/src/tools/network/web-search.ts +3 -3
- package/src/tools/permission-checker.ts +8 -8
- package/src/tools/registry.ts +7 -7
- package/src/tools/schedule/list.ts +2 -2
- package/src/tools/schema-transforms.ts +31 -21
- package/src/tools/secret-detection-handler.ts +1 -1
- package/src/tools/sensitive-output-placeholders.ts +1 -1
- package/src/tools/shared/filesystem/edit-engine.ts +1 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +3 -3
- package/src/tools/shared/filesystem/image-read.ts +25 -5
- package/src/tools/shared/filesystem/path-policy.ts +2 -2
- package/src/tools/shared/shell-output.ts +1 -1
- package/src/tools/side-effects.ts +1 -1
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/load.ts +3 -3
- package/src/tools/skills/sandbox-runner.ts +3 -3
- package/src/tools/subagent/read.ts +1 -1
- package/src/tools/subagent/spawn.ts +2 -2
- package/src/tools/swarm/delegate.ts +3 -3
- package/src/tools/system/request-permission.ts +5 -4
- package/src/tools/terminal/backends/native.ts +4 -4
- package/src/tools/terminal/parser.ts +6 -6
- package/src/tools/terminal/sandbox-diagnostics.ts +1 -1
- package/src/tools/terminal/shell.ts +16 -16
- package/src/tools/tool-approval-handler.ts +21 -12
- package/src/tools/tool-manifest.ts +4 -4
- package/src/tools/types.ts +3 -3
- package/src/tools/ui-surface/definitions.ts +9 -37
- package/src/tools/watcher/list.ts +1 -1
- package/src/util/logger.ts +7 -2
- package/src/util/pricing.ts +4 -0
- package/src/util/retry.ts +29 -1
- package/src/workspace/migrations/007-web-search-provider-rename.ts +37 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/cli-help-reference-sync.test.ts +0 -26
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -190
- package/src/cli/reference.ts +0 -38
- package/src/memory/job-handlers/capability-cards.ts +0 -420
- package/src/runtime/routes/thread-starter-routes.ts +0 -294
|
@@ -38,7 +38,6 @@ describe("RateLimitProvider", () => {
|
|
|
38
38
|
test("allows requests under the limit", async () => {
|
|
39
39
|
const config: RateLimitConfig = {
|
|
40
40
|
maxRequestsPerMinute: 5,
|
|
41
|
-
maxTokensPerSession: 0,
|
|
42
41
|
};
|
|
43
42
|
const provider = new RateLimitProvider(makeProvider(), config);
|
|
44
43
|
|
|
@@ -50,7 +49,6 @@ describe("RateLimitProvider", () => {
|
|
|
50
49
|
test("throws RateLimitError when exceeding request limit", async () => {
|
|
51
50
|
const config: RateLimitConfig = {
|
|
52
51
|
maxRequestsPerMinute: 2,
|
|
53
|
-
maxTokensPerSession: 0,
|
|
54
52
|
};
|
|
55
53
|
const provider = new RateLimitProvider(makeProvider(), config);
|
|
56
54
|
|
|
@@ -63,7 +61,6 @@ describe("RateLimitProvider", () => {
|
|
|
63
61
|
test("unlimited when maxRequestsPerMinute is 0", async () => {
|
|
64
62
|
const config: RateLimitConfig = {
|
|
65
63
|
maxRequestsPerMinute: 0,
|
|
66
|
-
maxTokensPerSession: 0,
|
|
67
64
|
};
|
|
68
65
|
const provider = new RateLimitProvider(makeProvider(), config);
|
|
69
66
|
|
|
@@ -73,56 +70,10 @@ describe("RateLimitProvider", () => {
|
|
|
73
70
|
});
|
|
74
71
|
});
|
|
75
72
|
|
|
76
|
-
describe("session token limiting", () => {
|
|
77
|
-
test("allows requests under the token budget", async () => {
|
|
78
|
-
const config: RateLimitConfig = {
|
|
79
|
-
maxRequestsPerMinute: 0,
|
|
80
|
-
maxTokensPerSession: 1000,
|
|
81
|
-
};
|
|
82
|
-
const provider = new RateLimitProvider(makeProvider(), config);
|
|
83
|
-
|
|
84
|
-
// Each call uses 150 tokens (100 input + 50 output)
|
|
85
|
-
for (let i = 0; i < 6; i++) {
|
|
86
|
-
await provider.sendMessage(messages);
|
|
87
|
-
}
|
|
88
|
-
// 6 * 150 = 900, still under 1000
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test("throws RateLimitError when token budget exhausted", async () => {
|
|
92
|
-
const config: RateLimitConfig = {
|
|
93
|
-
maxRequestsPerMinute: 0,
|
|
94
|
-
maxTokensPerSession: 300,
|
|
95
|
-
};
|
|
96
|
-
const provider = new RateLimitProvider(makeProvider(), config);
|
|
97
|
-
|
|
98
|
-
// 150 tokens per call
|
|
99
|
-
await provider.sendMessage(messages); // 150
|
|
100
|
-
await provider.sendMessage(messages); // 300
|
|
101
|
-
|
|
102
|
-
expect(provider.sendMessage(messages)).rejects.toThrow(RateLimitError);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test("unlimited when maxTokensPerSession is 0", async () => {
|
|
106
|
-
const config: RateLimitConfig = {
|
|
107
|
-
maxRequestsPerMinute: 0,
|
|
108
|
-
maxTokensPerSession: 0,
|
|
109
|
-
};
|
|
110
|
-
const provider = new RateLimitProvider(
|
|
111
|
-
makeProvider({ usage: { inputTokens: 10000, outputTokens: 10000 } }),
|
|
112
|
-
config,
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
for (let i = 0; i < 10; i++) {
|
|
116
|
-
await provider.sendMessage(messages);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
73
|
describe("passthrough behavior", () => {
|
|
122
74
|
test("delegates to inner provider", async () => {
|
|
123
75
|
const config: RateLimitConfig = {
|
|
124
76
|
maxRequestsPerMinute: 0,
|
|
125
|
-
maxTokensPerSession: 0,
|
|
126
77
|
};
|
|
127
78
|
const inner = makeProvider({ model: "custom-model" });
|
|
128
79
|
const provider = new RateLimitProvider(inner, config);
|
|
@@ -134,7 +85,6 @@ describe("RateLimitProvider", () => {
|
|
|
134
85
|
test("preserves provider name", () => {
|
|
135
86
|
const config: RateLimitConfig = {
|
|
136
87
|
maxRequestsPerMinute: 0,
|
|
137
|
-
maxTokensPerSession: 0,
|
|
138
88
|
};
|
|
139
89
|
const provider = new RateLimitProvider(makeProvider(), config);
|
|
140
90
|
expect(provider.name).toBe("mock");
|
|
@@ -143,7 +93,6 @@ describe("RateLimitProvider", () => {
|
|
|
143
93
|
test("passes through all arguments to inner provider", async () => {
|
|
144
94
|
const config: RateLimitConfig = {
|
|
145
95
|
maxRequestsPerMinute: 0,
|
|
146
|
-
maxTokensPerSession: 0,
|
|
147
96
|
};
|
|
148
97
|
let receivedArgs: unknown[] = [];
|
|
149
98
|
const inner: Provider = {
|
|
@@ -173,27 +122,10 @@ describe("RateLimitProvider", () => {
|
|
|
173
122
|
});
|
|
174
123
|
});
|
|
175
124
|
|
|
176
|
-
describe("combined limits", () => {
|
|
177
|
-
test("enforces both limits simultaneously", async () => {
|
|
178
|
-
const config: RateLimitConfig = {
|
|
179
|
-
maxRequestsPerMinute: 10,
|
|
180
|
-
maxTokensPerSession: 300,
|
|
181
|
-
};
|
|
182
|
-
const provider = new RateLimitProvider(makeProvider(), config);
|
|
183
|
-
|
|
184
|
-
// Token limit should hit first (2 * 150 = 300)
|
|
185
|
-
await provider.sendMessage(messages);
|
|
186
|
-
await provider.sendMessage(messages);
|
|
187
|
-
|
|
188
|
-
expect(provider.sendMessage(messages)).rejects.toThrow(RateLimitError);
|
|
189
|
-
});
|
|
190
|
-
});
|
|
191
|
-
|
|
192
125
|
describe("shared request timestamps", () => {
|
|
193
126
|
test("multiple providers sharing timestamps enforce a global rate limit", async () => {
|
|
194
127
|
const config: RateLimitConfig = {
|
|
195
128
|
maxRequestsPerMinute: 2,
|
|
196
|
-
maxTokensPerSession: 0,
|
|
197
129
|
};
|
|
198
130
|
const shared: number[] = [];
|
|
199
131
|
const provider1 = new RateLimitProvider(makeProvider(), config, shared);
|
|
@@ -215,7 +147,6 @@ describe("RateLimitProvider", () => {
|
|
|
215
147
|
test("out-of-order timestamps are pruned correctly (clock skew)", async () => {
|
|
216
148
|
const config: RateLimitConfig = {
|
|
217
149
|
maxRequestsPerMinute: 3,
|
|
218
|
-
maxTokensPerSession: 0,
|
|
219
150
|
};
|
|
220
151
|
const shared: number[] = [];
|
|
221
152
|
const provider = new RateLimitProvider(makeProvider(), config, shared);
|
|
@@ -236,7 +167,6 @@ describe("RateLimitProvider", () => {
|
|
|
236
167
|
test("waitSec uses actual oldest timestamp under clock skew", async () => {
|
|
237
168
|
const config: RateLimitConfig = {
|
|
238
169
|
maxRequestsPerMinute: 2,
|
|
239
|
-
maxTokensPerSession: 0,
|
|
240
170
|
};
|
|
241
171
|
const shared: number[] = [];
|
|
242
172
|
const provider = new RateLimitProvider(makeProvider(), config, shared);
|
|
@@ -266,7 +196,6 @@ describe("RateLimitProvider", () => {
|
|
|
266
196
|
const highLimit = 200_000;
|
|
267
197
|
const config: RateLimitConfig = {
|
|
268
198
|
maxRequestsPerMinute: highLimit,
|
|
269
|
-
maxTokensPerSession: 0,
|
|
270
199
|
};
|
|
271
200
|
const shared: number[] = [];
|
|
272
201
|
const provider = new RateLimitProvider(makeProvider(), config, shared);
|
|
@@ -286,7 +215,6 @@ describe("RateLimitProvider", () => {
|
|
|
286
215
|
test("shared array reference survives pruning", async () => {
|
|
287
216
|
const config: RateLimitConfig = {
|
|
288
217
|
maxRequestsPerMinute: 100,
|
|
289
|
-
maxTokensPerSession: 0,
|
|
290
218
|
};
|
|
291
219
|
const shared: number[] = [];
|
|
292
220
|
const provider1 = new RateLimitProvider(makeProvider(), config, shared);
|
|
@@ -311,7 +239,6 @@ describe("RateLimitProvider", () => {
|
|
|
311
239
|
test("concurrent calls are rate-limited because timestamp is recorded before await", async () => {
|
|
312
240
|
const config: RateLimitConfig = {
|
|
313
241
|
maxRequestsPerMinute: 1,
|
|
314
|
-
maxTokensPerSession: 0,
|
|
315
242
|
};
|
|
316
243
|
// Slow provider that yields to the event loop
|
|
317
244
|
const inner: Provider = {
|
|
@@ -343,7 +270,6 @@ describe("RateLimitProvider", () => {
|
|
|
343
270
|
test("failed inner calls still count toward request rate", async () => {
|
|
344
271
|
const config: RateLimitConfig = {
|
|
345
272
|
maxRequestsPerMinute: 1,
|
|
346
|
-
maxTokensPerSession: 0,
|
|
347
273
|
};
|
|
348
274
|
const inner: Provider = {
|
|
349
275
|
name: "failing",
|
|
@@ -24,7 +24,6 @@ mock.module("../config/loader.js", () => ({
|
|
|
24
24
|
daemon: { standaloneRecording: true },
|
|
25
25
|
provider: "mock-provider",
|
|
26
26
|
permissions: { mode: "workspace" },
|
|
27
|
-
sandbox: { enabled: false },
|
|
28
27
|
timeouts: { toolExecutionTimeoutSec: 30, permissionTimeoutSec: 5 },
|
|
29
28
|
skills: { load: { extraDirs: [] } },
|
|
30
29
|
secretDetection: { enabled: false, allowOneTimeSend: false },
|
|
@@ -50,7 +50,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
50
50
|
model: "test",
|
|
51
51
|
provider: "test",
|
|
52
52
|
memory: { enabled: false },
|
|
53
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
53
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
54
54
|
secretDetection: { enabled: false },
|
|
55
55
|
}),
|
|
56
56
|
}));
|
|
@@ -42,7 +42,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
42
42
|
model: "test",
|
|
43
43
|
provider: "test",
|
|
44
44
|
memory: { enabled: false },
|
|
45
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
45
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
46
46
|
secretDetection: { enabled: false },
|
|
47
47
|
}),
|
|
48
48
|
}));
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
afterAll,
|
|
6
|
+
beforeAll,
|
|
7
|
+
beforeEach,
|
|
8
|
+
describe,
|
|
9
|
+
expect,
|
|
10
|
+
mock,
|
|
11
|
+
test,
|
|
12
|
+
} from "bun:test";
|
|
5
13
|
|
|
6
14
|
const testDir = mkdtempSync(join(tmpdir(), "scheduler-recurrence-test-"));
|
|
7
15
|
|
|
@@ -86,7 +94,30 @@ function buildEndedRrule(): string {
|
|
|
86
94
|
|
|
87
95
|
// ── RRULE schedule fires through the scheduler ──────────────────────
|
|
88
96
|
|
|
97
|
+
// Replace setTimeout with a zero-delay version so the 500ms scheduler
|
|
98
|
+
// wait calls fire instantly instead of waiting real time.
|
|
99
|
+
let origSetTimeout: typeof globalThis.setTimeout;
|
|
100
|
+
|
|
89
101
|
describe("scheduler RRULE execution", () => {
|
|
102
|
+
beforeAll(() => {
|
|
103
|
+
origSetTimeout = globalThis.setTimeout;
|
|
104
|
+
globalThis.setTimeout = ((
|
|
105
|
+
fn: TimerHandler,
|
|
106
|
+
_ms?: number,
|
|
107
|
+
...args: unknown[]
|
|
108
|
+
) => {
|
|
109
|
+
// Use a small real delay so fire-and-forget async ticks have time to
|
|
110
|
+
// settle, while still cutting the 500ms waits down dramatically.
|
|
111
|
+
// 200ms gives headroom for the run_task path which does a dynamic
|
|
112
|
+
// import of task-runner.js on first invocation.
|
|
113
|
+
return origSetTimeout(fn, 200, ...args);
|
|
114
|
+
}) as typeof setTimeout;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
afterAll(() => {
|
|
118
|
+
globalThis.setTimeout = origSetTimeout;
|
|
119
|
+
});
|
|
120
|
+
|
|
90
121
|
beforeEach(() => {
|
|
91
122
|
const db = getDb();
|
|
92
123
|
db.run("DELETE FROM cron_runs");
|
|
@@ -157,8 +188,11 @@ describe("scheduler RRULE execution", () => {
|
|
|
157
188
|
forceScheduleDue(schedule.id);
|
|
158
189
|
|
|
159
190
|
const directCalls: { conversationId: string; message: string }[] = [];
|
|
191
|
+
let onMessage: (() => void) | undefined;
|
|
192
|
+
const messageReceived = new Promise<void>((r) => (onMessage = r));
|
|
160
193
|
const processMessage = async (conversationId: string, message: string) => {
|
|
161
194
|
directCalls.push({ conversationId, message });
|
|
195
|
+
onMessage?.();
|
|
162
196
|
};
|
|
163
197
|
|
|
164
198
|
const scheduler = startScheduler(
|
|
@@ -166,7 +200,17 @@ describe("scheduler RRULE execution", () => {
|
|
|
166
200
|
() => {},
|
|
167
201
|
() => {},
|
|
168
202
|
);
|
|
169
|
-
|
|
203
|
+
// The run_task path involves a dynamic import which can take >50ms in CI,
|
|
204
|
+
// exceeding the patched setTimeout delay. Await the actual callback instead
|
|
205
|
+
// of relying on a fixed timeout.
|
|
206
|
+
await Promise.race([
|
|
207
|
+
messageReceived,
|
|
208
|
+
new Promise((r) => origSetTimeout(r, 2000)),
|
|
209
|
+
]);
|
|
210
|
+
// Yield to the macrotask queue so all pending microtasks settle —
|
|
211
|
+
// the scheduler tick still needs to create the schedule run after
|
|
212
|
+
// processMessage returns.
|
|
213
|
+
await new Promise((r) => origSetTimeout(r, 0));
|
|
170
214
|
scheduler.stop();
|
|
171
215
|
|
|
172
216
|
// runTask renders the template, so processMessage gets the template text
|
|
@@ -2,8 +2,8 @@ import { describe, expect, test } from "bun:test";
|
|
|
2
2
|
|
|
3
3
|
import type { ToolDefinition } from "../providers/types.js";
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
ACTIVITY_SKIP_SET,
|
|
6
|
+
injectActivityField,
|
|
7
7
|
schemaDefinesProperty,
|
|
8
8
|
} from "../tools/schema-transforms.js";
|
|
9
9
|
|
|
@@ -14,26 +14,26 @@ function makeDef(
|
|
|
14
14
|
return { name, description: `Tool ${name}`, input_schema: schema };
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
describe("
|
|
18
|
-
test("
|
|
19
|
-
expect(
|
|
20
|
-
expect(REASON_SKIP_SET.has("bash")).toBe(true);
|
|
21
|
-
expect(REASON_SKIP_SET.has("host_bash")).toBe(true);
|
|
22
|
-
expect(REASON_SKIP_SET.has("request_system_permission")).toBe(true);
|
|
23
|
-
expect(REASON_SKIP_SET.size).toBe(4);
|
|
17
|
+
describe("ACTIVITY_SKIP_SET", () => {
|
|
18
|
+
test("is empty (all tools now define their own activity property)", () => {
|
|
19
|
+
expect(ACTIVITY_SKIP_SET.size).toBe(0);
|
|
24
20
|
});
|
|
25
21
|
});
|
|
26
22
|
|
|
27
|
-
describe("
|
|
28
|
-
test("injects
|
|
23
|
+
describe("injectActivityField", () => {
|
|
24
|
+
test("injects activity on a tool without it", () => {
|
|
29
25
|
const defs = [makeDef("my_tool")];
|
|
30
|
-
const result =
|
|
26
|
+
const result = injectActivityField(defs);
|
|
31
27
|
const schema = result[0].input_schema as Record<string, unknown>;
|
|
32
28
|
const props = schema.properties as Record<string, unknown>;
|
|
33
|
-
expect(props.
|
|
29
|
+
expect(props.activity).toEqual({
|
|
30
|
+
type: "string",
|
|
31
|
+
description:
|
|
32
|
+
"Brief, natural description of what you're doing, shown as a live status update (e.g. 'Checking your project settings')",
|
|
33
|
+
});
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
test("adds
|
|
36
|
+
test("adds activity to required array", () => {
|
|
37
37
|
const defs = [
|
|
38
38
|
makeDef("my_tool", {
|
|
39
39
|
type: "object",
|
|
@@ -41,9 +41,9 @@ describe("injectReasonField", () => {
|
|
|
41
41
|
required: ["foo"],
|
|
42
42
|
}),
|
|
43
43
|
];
|
|
44
|
-
const result =
|
|
44
|
+
const result = injectActivityField(defs);
|
|
45
45
|
const schema = result[0].input_schema as Record<string, unknown>;
|
|
46
|
-
expect(schema.required).toEqual(["foo", "
|
|
46
|
+
expect(schema.required).toEqual(["foo", "activity"]);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
test("creates required array if missing", () => {
|
|
@@ -53,38 +53,38 @@ describe("injectReasonField", () => {
|
|
|
53
53
|
properties: { foo: { type: "string" } },
|
|
54
54
|
}),
|
|
55
55
|
];
|
|
56
|
-
const result =
|
|
56
|
+
const result = injectActivityField(defs);
|
|
57
57
|
const schema = result[0].input_schema as Record<string, unknown>;
|
|
58
|
-
expect(schema.required).toEqual(["
|
|
58
|
+
expect(schema.required).toEqual(["activity"]);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
test("skips tools in skip set (returns unchanged)", () => {
|
|
62
62
|
const defs = [makeDef("bash"), makeDef("host_bash")];
|
|
63
|
-
const result =
|
|
63
|
+
const result = injectActivityField(defs, new Set(["bash", "host_bash"]));
|
|
64
64
|
// Should be the exact same object references
|
|
65
65
|
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
66
66
|
expect(Object.is(result[1], defs[1])).toBe(true);
|
|
67
|
-
// No
|
|
67
|
+
// No activity injected
|
|
68
68
|
const schema0 = result[0].input_schema as Record<string, unknown>;
|
|
69
69
|
const props0 = schema0.properties as Record<string, unknown>;
|
|
70
|
-
expect("
|
|
70
|
+
expect("activity" in props0).toBe(false);
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
test("skips tools that already have
|
|
73
|
+
test("skips tools that already have activity in properties", () => {
|
|
74
74
|
const defs = [
|
|
75
75
|
makeDef("my_tool", {
|
|
76
76
|
type: "object",
|
|
77
|
-
properties: {
|
|
77
|
+
properties: { activity: { type: "number" } },
|
|
78
78
|
required: [],
|
|
79
79
|
}),
|
|
80
80
|
];
|
|
81
|
-
const result =
|
|
81
|
+
const result = injectActivityField(defs);
|
|
82
82
|
// Should be the exact same object reference (no clone needed)
|
|
83
83
|
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
84
84
|
const schema = result[0].input_schema as Record<string, unknown>;
|
|
85
85
|
const props = schema.properties as Record<string, unknown>;
|
|
86
|
-
// Original
|
|
87
|
-
expect(props.
|
|
86
|
+
// Original activity type preserved
|
|
87
|
+
expect(props.activity).toEqual({ type: "number" });
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
test("does NOT mutate original definition objects", () => {
|
|
@@ -97,10 +97,10 @@ describe("injectReasonField", () => {
|
|
|
97
97
|
};
|
|
98
98
|
const defs = [makeDef("my_tool", originalSchema)];
|
|
99
99
|
|
|
100
|
-
const result =
|
|
100
|
+
const result = injectActivityField(defs);
|
|
101
101
|
|
|
102
102
|
// Original properties object is untouched
|
|
103
|
-
expect("
|
|
103
|
+
expect("activity" in originalProps).toBe(false);
|
|
104
104
|
// Original required array is untouched
|
|
105
105
|
expect(originalRequired).toEqual(["foo"]);
|
|
106
106
|
// Original schema properties ref is the same object
|
|
@@ -115,40 +115,40 @@ describe("injectReasonField", () => {
|
|
|
115
115
|
|
|
116
116
|
test("passes through non-object schemas unchanged", () => {
|
|
117
117
|
const defs = [makeDef("my_tool", { type: "string" })];
|
|
118
|
-
const result =
|
|
118
|
+
const result = injectActivityField(defs);
|
|
119
119
|
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
120
120
|
});
|
|
121
121
|
|
|
122
122
|
test("passes through schemas without properties unchanged", () => {
|
|
123
123
|
const defs = [makeDef("my_tool", { type: "object" })];
|
|
124
|
-
const result =
|
|
124
|
+
const result = injectActivityField(defs);
|
|
125
125
|
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
-
test("skips tools with
|
|
128
|
+
test("skips tools with activity defined inside allOf member (composite schema)", () => {
|
|
129
129
|
const defs = [
|
|
130
130
|
makeDef("my_tool", {
|
|
131
131
|
type: "object",
|
|
132
132
|
properties: { foo: { type: "string" } },
|
|
133
133
|
allOf: [
|
|
134
134
|
{
|
|
135
|
-
properties: {
|
|
135
|
+
properties: { activity: { type: "string" } },
|
|
136
136
|
},
|
|
137
137
|
],
|
|
138
138
|
required: [],
|
|
139
139
|
}),
|
|
140
140
|
];
|
|
141
|
-
const result =
|
|
141
|
+
const result = injectActivityField(defs);
|
|
142
142
|
// Should be the exact same object reference (no injection)
|
|
143
143
|
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
144
144
|
const schema = result[0].input_schema as Record<string, unknown>;
|
|
145
145
|
const props = schema.properties as Record<string, unknown>;
|
|
146
|
-
// Top-level properties should NOT have
|
|
147
|
-
expect("
|
|
146
|
+
// Top-level properties should NOT have activity injected
|
|
147
|
+
expect("activity" in props).toBe(false);
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
test("handles empty definitions array", () => {
|
|
151
|
-
const result =
|
|
151
|
+
const result = injectActivityField([]);
|
|
152
152
|
expect(result).toEqual([]);
|
|
153
153
|
});
|
|
154
154
|
});
|
|
@@ -157,44 +157,44 @@ describe("schemaDefinesProperty", () => {
|
|
|
157
157
|
test("returns true for direct properties match", () => {
|
|
158
158
|
const schema = {
|
|
159
159
|
type: "object",
|
|
160
|
-
properties: {
|
|
160
|
+
properties: { activity: { type: "string" } },
|
|
161
161
|
};
|
|
162
|
-
expect(schemaDefinesProperty(schema, "
|
|
162
|
+
expect(schemaDefinesProperty(schema, "activity")).toBe(true);
|
|
163
163
|
});
|
|
164
164
|
|
|
165
165
|
test("returns true for property in allOf member", () => {
|
|
166
166
|
const schema = {
|
|
167
|
-
allOf: [{ properties: {
|
|
167
|
+
allOf: [{ properties: { activity: { type: "string" } } }],
|
|
168
168
|
};
|
|
169
|
-
expect(schemaDefinesProperty(schema, "
|
|
169
|
+
expect(schemaDefinesProperty(schema, "activity")).toBe(true);
|
|
170
170
|
});
|
|
171
171
|
|
|
172
172
|
test("returns true for property in oneOf member", () => {
|
|
173
173
|
const schema = {
|
|
174
174
|
oneOf: [
|
|
175
175
|
{ properties: { foo: { type: "string" } } },
|
|
176
|
-
{ properties: {
|
|
176
|
+
{ properties: { activity: { type: "string" } } },
|
|
177
177
|
],
|
|
178
178
|
};
|
|
179
|
-
expect(schemaDefinesProperty(schema, "
|
|
179
|
+
expect(schemaDefinesProperty(schema, "activity")).toBe(true);
|
|
180
180
|
});
|
|
181
181
|
|
|
182
182
|
test("returns true for property in anyOf member", () => {
|
|
183
183
|
const schema = {
|
|
184
|
-
anyOf: [{ properties: {
|
|
184
|
+
anyOf: [{ properties: { activity: { type: "string" } } }],
|
|
185
185
|
};
|
|
186
|
-
expect(schemaDefinesProperty(schema, "
|
|
186
|
+
expect(schemaDefinesProperty(schema, "activity")).toBe(true);
|
|
187
187
|
});
|
|
188
188
|
|
|
189
189
|
test("returns true for nested allOf within oneOf", () => {
|
|
190
190
|
const schema = {
|
|
191
191
|
oneOf: [
|
|
192
192
|
{
|
|
193
|
-
allOf: [{ properties: {
|
|
193
|
+
allOf: [{ properties: { activity: { type: "string" } } }],
|
|
194
194
|
},
|
|
195
195
|
],
|
|
196
196
|
};
|
|
197
|
-
expect(schemaDefinesProperty(schema, "
|
|
197
|
+
expect(schemaDefinesProperty(schema, "activity")).toBe(true);
|
|
198
198
|
});
|
|
199
199
|
|
|
200
200
|
test("returns false when property not defined", () => {
|
|
@@ -202,25 +202,85 @@ describe("schemaDefinesProperty", () => {
|
|
|
202
202
|
type: "object",
|
|
203
203
|
properties: { foo: { type: "string" } },
|
|
204
204
|
};
|
|
205
|
-
expect(schemaDefinesProperty(schema, "
|
|
205
|
+
expect(schemaDefinesProperty(schema, "activity")).toBe(false);
|
|
206
206
|
});
|
|
207
207
|
|
|
208
|
-
test("returns false for $ref (fail-closed)", () => {
|
|
208
|
+
test("returns false for $ref with default behavior (fail-closed)", () => {
|
|
209
209
|
const schema = { $ref: "#/definitions/Foo" };
|
|
210
|
-
expect(schemaDefinesProperty(schema, "
|
|
210
|
+
expect(schemaDefinesProperty(schema, "activity")).toBe(false);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("returns true for $ref with assume-defined behavior (fail-open)", () => {
|
|
214
|
+
const schema = { $ref: "#/definitions/Foo" };
|
|
215
|
+
expect(
|
|
216
|
+
schemaDefinesProperty(schema, "activity", {
|
|
217
|
+
refBehavior: "assume-defined",
|
|
218
|
+
}),
|
|
219
|
+
).toBe(true);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("returns true for $ref nested in allOf with assume-defined refBehavior", () => {
|
|
223
|
+
const schema = {
|
|
224
|
+
allOf: [{ $ref: "#/definitions/Foo" }],
|
|
225
|
+
};
|
|
226
|
+
expect(
|
|
227
|
+
schemaDefinesProperty(schema, "activity", {
|
|
228
|
+
refBehavior: "assume-defined",
|
|
229
|
+
}),
|
|
230
|
+
).toBe(true);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("returns false for $ref nested in allOf with assume-undefined refBehavior", () => {
|
|
234
|
+
const schema = {
|
|
235
|
+
allOf: [{ $ref: "#/definitions/Foo" }],
|
|
236
|
+
};
|
|
237
|
+
expect(
|
|
238
|
+
schemaDefinesProperty(schema, "activity", {
|
|
239
|
+
refBehavior: "assume-undefined",
|
|
240
|
+
}),
|
|
241
|
+
).toBe(false);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test("returns true for $ref nested in oneOf with assume-defined refBehavior", () => {
|
|
245
|
+
const schema = {
|
|
246
|
+
oneOf: [{ $ref: "#/definitions/Foo" }],
|
|
247
|
+
};
|
|
248
|
+
expect(
|
|
249
|
+
schemaDefinesProperty(schema, "activity", {
|
|
250
|
+
refBehavior: "assume-defined",
|
|
251
|
+
}),
|
|
252
|
+
).toBe(true);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test("returns true for $ref nested in anyOf with assume-defined refBehavior", () => {
|
|
256
|
+
const schema = {
|
|
257
|
+
anyOf: [{ $ref: "#/definitions/Foo" }],
|
|
258
|
+
};
|
|
259
|
+
expect(
|
|
260
|
+
schemaDefinesProperty(schema, "activity", {
|
|
261
|
+
refBehavior: "assume-defined",
|
|
262
|
+
}),
|
|
263
|
+
).toBe(true);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test("returns false for $ref nested in allOf with default refBehavior (fail-closed)", () => {
|
|
267
|
+
const schema = {
|
|
268
|
+
allOf: [{ $ref: "#/definitions/Foo" }],
|
|
269
|
+
};
|
|
270
|
+
expect(schemaDefinesProperty(schema, "activity")).toBe(false);
|
|
211
271
|
});
|
|
212
272
|
|
|
213
273
|
test("returns false for null schema", () => {
|
|
214
|
-
expect(schemaDefinesProperty(null, "
|
|
274
|
+
expect(schemaDefinesProperty(null, "activity")).toBe(false);
|
|
215
275
|
});
|
|
216
276
|
|
|
217
277
|
test("returns false for undefined schema", () => {
|
|
218
|
-
expect(schemaDefinesProperty(undefined, "
|
|
278
|
+
expect(schemaDefinesProperty(undefined, "activity")).toBe(false);
|
|
219
279
|
});
|
|
220
280
|
|
|
221
281
|
test("returns false for non-object schema", () => {
|
|
222
|
-
expect(schemaDefinesProperty("not-an-object", "
|
|
223
|
-
expect(schemaDefinesProperty(42, "
|
|
224
|
-
expect(schemaDefinesProperty(true, "
|
|
282
|
+
expect(schemaDefinesProperty("not-an-object", "activity")).toBe(false);
|
|
283
|
+
expect(schemaDefinesProperty(42, "activity")).toBe(false);
|
|
284
|
+
expect(schemaDefinesProperty(true, "activity")).toBe(false);
|
|
225
285
|
});
|
|
226
286
|
});
|
|
@@ -14,9 +14,29 @@ const mockConfig = {
|
|
|
14
14
|
timeouts: { permissionTimeoutSec: 300 },
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
function setMockNestedValue(
|
|
18
|
+
obj: Record<string, unknown>,
|
|
19
|
+
path: string,
|
|
20
|
+
value: unknown,
|
|
21
|
+
): void {
|
|
22
|
+
const keys = path.split(".");
|
|
23
|
+
let current = obj;
|
|
24
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
25
|
+
const key = keys[i];
|
|
26
|
+
if (current[key] == null || typeof current[key] !== "object") {
|
|
27
|
+
current[key] = {};
|
|
28
|
+
}
|
|
29
|
+
current = current[key] as Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
current[keys[keys.length - 1]] = value;
|
|
32
|
+
}
|
|
33
|
+
|
|
17
34
|
mock.module("../config/loader.js", () => ({
|
|
18
35
|
getConfig: () => mockConfig,
|
|
19
36
|
loadConfig: () => mockConfig,
|
|
37
|
+
loadRawConfig: () => ({}),
|
|
38
|
+
saveRawConfig: () => {},
|
|
39
|
+
setNestedValue: setMockNestedValue,
|
|
20
40
|
invalidateConfigCache: () => {},
|
|
21
41
|
}));
|
|
22
42
|
|
|
@@ -24,9 +24,12 @@ const mockConfig = {
|
|
|
24
24
|
"image-generation": {
|
|
25
25
|
mode: "your-own" as const,
|
|
26
26
|
provider: "gemini",
|
|
27
|
-
model: "gemini-
|
|
27
|
+
model: "gemini-3.1-flash-image-preview",
|
|
28
|
+
},
|
|
29
|
+
"web-search": {
|
|
30
|
+
mode: "your-own" as const,
|
|
31
|
+
provider: "inference-provider-native",
|
|
28
32
|
},
|
|
29
|
-
"web-search": { mode: "your-own" as const, provider: "anthropic-native" },
|
|
30
33
|
},
|
|
31
34
|
};
|
|
32
35
|
|
|
@@ -20,8 +20,7 @@ const mockConfig = {
|
|
|
20
20
|
shellMaxTimeoutSec: 600,
|
|
21
21
|
permissionTimeoutSec: 300,
|
|
22
22
|
},
|
|
23
|
-
|
|
24
|
-
rateLimit: { maxRequestsPerMinute: 0, maxTokensPerSession: 0 },
|
|
23
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
25
24
|
secretDetection: {
|
|
26
25
|
enabled: true,
|
|
27
26
|
action: "warn" as "redact" | "warn" | "block",
|