@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
|
@@ -201,18 +201,18 @@ describe("Permission Checker", () => {
|
|
|
201
201
|
});
|
|
202
202
|
});
|
|
203
203
|
|
|
204
|
-
// file_write is always
|
|
204
|
+
// file_write is always low (sandboxed)
|
|
205
205
|
describe("file_write", () => {
|
|
206
|
-
test("file_write is always
|
|
206
|
+
test("file_write is always low risk", async () => {
|
|
207
207
|
const risk = await classifyRisk("file_write", {
|
|
208
208
|
path: "/tmp/file.txt",
|
|
209
209
|
});
|
|
210
|
-
expect(risk).toBe(RiskLevel.
|
|
210
|
+
expect(risk).toBe(RiskLevel.Low);
|
|
211
211
|
});
|
|
212
212
|
|
|
213
|
-
test("file_write with any path is
|
|
213
|
+
test("file_write with any path is low risk", async () => {
|
|
214
214
|
const risk = await classifyRisk("file_write", { path: "/etc/passwd" });
|
|
215
|
-
expect(risk).toBe(RiskLevel.
|
|
215
|
+
expect(risk).toBe(RiskLevel.Low);
|
|
216
216
|
});
|
|
217
217
|
});
|
|
218
218
|
|
|
@@ -673,23 +673,22 @@ describe("Permission Checker", () => {
|
|
|
673
673
|
expect(result.decision).toBe("allow");
|
|
674
674
|
});
|
|
675
675
|
|
|
676
|
-
test("file_write
|
|
676
|
+
test("file_write → auto-allow (workspace-scoped)", async () => {
|
|
677
677
|
const result = await check(
|
|
678
678
|
"file_write",
|
|
679
679
|
{ path: "/tmp/file.txt" },
|
|
680
680
|
"/tmp",
|
|
681
681
|
);
|
|
682
|
-
expect(result.decision).toBe("
|
|
683
|
-
expect(result.reason).toContain("medium risk");
|
|
682
|
+
expect(result.decision).toBe("allow");
|
|
684
683
|
});
|
|
685
684
|
|
|
686
|
-
test("file_write outside workspace
|
|
685
|
+
test("file_write outside workspace → auto-allow (Low risk)", async () => {
|
|
687
686
|
const result = await check(
|
|
688
687
|
"file_write",
|
|
689
688
|
{ path: "/etc/some-file.txt" },
|
|
690
689
|
"/tmp",
|
|
691
690
|
);
|
|
692
|
-
expect(result.decision).toBe("
|
|
691
|
+
expect(result.decision).toBe("allow");
|
|
693
692
|
});
|
|
694
693
|
|
|
695
694
|
test("file_write with matching rule → allow", async () => {
|
|
@@ -1486,12 +1485,12 @@ describe("Permission Checker", () => {
|
|
|
1486
1485
|
expect(result.matchedRule!.id).toBe("default:allow-file_edit-updates");
|
|
1487
1486
|
});
|
|
1488
1487
|
|
|
1489
|
-
test("file_write of non-workspace file is
|
|
1488
|
+
test("file_write of non-workspace file is auto-allowed (Low risk)", async () => {
|
|
1490
1489
|
const otherPath = join(checkerTestDir, "workspace", "OTHER.md");
|
|
1491
1490
|
// Use a workingDir that doesn't contain the path so it's not workspace-scoped
|
|
1492
1491
|
const result = await check("file_write", { path: otherPath }, "/home");
|
|
1493
|
-
//
|
|
1494
|
-
expect(result.decision).toBe("
|
|
1492
|
+
// Low risk → auto-allowed even outside workspace
|
|
1493
|
+
expect(result.decision).toBe("allow");
|
|
1495
1494
|
});
|
|
1496
1495
|
});
|
|
1497
1496
|
|
|
@@ -2096,16 +2095,16 @@ describe("Permission Checker", () => {
|
|
|
2096
2095
|
expect(risk).toBe(RiskLevel.High);
|
|
2097
2096
|
});
|
|
2098
2097
|
|
|
2099
|
-
test("file_write to non-skill path
|
|
2098
|
+
test("file_write to non-skill path is Low risk", async () => {
|
|
2100
2099
|
const normalPath = "/tmp/some-file.txt";
|
|
2101
2100
|
const risk = await classifyRisk("file_write", { path: normalPath });
|
|
2102
|
-
expect(risk).toBe(RiskLevel.
|
|
2101
|
+
expect(risk).toBe(RiskLevel.Low);
|
|
2103
2102
|
});
|
|
2104
2103
|
|
|
2105
|
-
test("file_edit of non-skill path
|
|
2104
|
+
test("file_edit of non-skill path is Low risk", async () => {
|
|
2106
2105
|
const normalPath = "/tmp/some-file.txt";
|
|
2107
2106
|
const risk = await classifyRisk("file_edit", { path: normalPath });
|
|
2108
|
-
expect(risk).toBe(RiskLevel.
|
|
2107
|
+
expect(risk).toBe(RiskLevel.Low);
|
|
2109
2108
|
});
|
|
2110
2109
|
|
|
2111
2110
|
test("host_file_write to non-skill path remains Medium risk (via registry)", async () => {
|
|
@@ -2557,12 +2556,12 @@ describe("Permission Checker", () => {
|
|
|
2557
2556
|
expect(result.reason).toContain("requires approval");
|
|
2558
2557
|
});
|
|
2559
2558
|
|
|
2560
|
-
test("strict mode: file_write to non-skill path prompts as Strict mode
|
|
2559
|
+
test("strict mode: file_write to non-skill path prompts as Strict mode", async () => {
|
|
2561
2560
|
testConfig.permissions.mode = "strict";
|
|
2562
2561
|
const normalPath = "/tmp/some-file.txt";
|
|
2563
2562
|
const result = await check("file_write", { path: normalPath }, "/tmp");
|
|
2564
2563
|
expect(result.decision).toBe("prompt");
|
|
2565
|
-
//
|
|
2564
|
+
// Low-risk file_write in strict mode with no rule → Strict mode reason
|
|
2566
2565
|
expect(result.reason).toContain("Strict mode");
|
|
2567
2566
|
});
|
|
2568
2567
|
|
|
@@ -2865,7 +2864,7 @@ describe("Permission Checker", () => {
|
|
|
2865
2864
|
const symlinkedFile = join(symDir, "config.json");
|
|
2866
2865
|
const realFileResolved = join(realDirResolved, "config.json");
|
|
2867
2866
|
|
|
2868
|
-
// file_write is
|
|
2867
|
+
// file_write is Low risk — but add a rule to verify symlink path matching.
|
|
2869
2868
|
addRule("file_write", `file_write:${realFileResolved}`, "everywhere");
|
|
2870
2869
|
const result = await check(
|
|
2871
2870
|
"file_write",
|
|
@@ -3597,7 +3596,7 @@ describe("Permission Checker", () => {
|
|
|
3597
3596
|
expect(result.matchedRule!.pattern).toBe("skill_load:*");
|
|
3598
3597
|
});
|
|
3599
3598
|
|
|
3600
|
-
test("
|
|
3599
|
+
test("low-risk file_write with no rule prompts in strict mode", async () => {
|
|
3601
3600
|
testConfig.permissions.mode = "strict";
|
|
3602
3601
|
const result = await check(
|
|
3603
3602
|
"file_write",
|
|
@@ -3996,14 +3995,14 @@ describe("Permission Checker", () => {
|
|
|
3996
3995
|
);
|
|
3997
3996
|
|
|
3998
3997
|
test(
|
|
3999
|
-
"file_write to non-extra dir remains
|
|
3998
|
+
"file_write to non-extra dir remains Low when extra dirs are configured",
|
|
4000
3999
|
withExtraDirs(async () => {
|
|
4001
4000
|
const risk = await classifyRisk(
|
|
4002
4001
|
"file_write",
|
|
4003
4002
|
{ path: "/tmp/unrelated.txt" },
|
|
4004
4003
|
"/tmp",
|
|
4005
4004
|
);
|
|
4006
|
-
expect(risk).toBe(RiskLevel.
|
|
4005
|
+
expect(risk).toBe(RiskLevel.Low);
|
|
4007
4006
|
}),
|
|
4008
4007
|
);
|
|
4009
4008
|
|
|
@@ -4583,24 +4582,24 @@ describe("workspace mode — auto-allow workspace-scoped operations", () => {
|
|
|
4583
4582
|
expect(result.reason).toContain("Workspace mode");
|
|
4584
4583
|
});
|
|
4585
4584
|
|
|
4586
|
-
test("file_write within workspace →
|
|
4585
|
+
test("file_write within workspace → allow (workspace-scoped)", async () => {
|
|
4587
4586
|
const result = await check(
|
|
4588
4587
|
"file_write",
|
|
4589
4588
|
{ file_path: "/home/user/my-project/src/index.ts" },
|
|
4590
4589
|
workspaceDir,
|
|
4591
4590
|
);
|
|
4592
|
-
expect(result.decision).toBe("
|
|
4593
|
-
expect(result.reason).toContain("
|
|
4591
|
+
expect(result.decision).toBe("allow");
|
|
4592
|
+
expect(result.reason).toContain("Workspace mode");
|
|
4594
4593
|
});
|
|
4595
4594
|
|
|
4596
|
-
test("file_edit within workspace →
|
|
4595
|
+
test("file_edit within workspace → allow (workspace-scoped)", async () => {
|
|
4597
4596
|
const result = await check(
|
|
4598
4597
|
"file_edit",
|
|
4599
4598
|
{ file_path: "/home/user/my-project/src/index.ts" },
|
|
4600
4599
|
workspaceDir,
|
|
4601
4600
|
);
|
|
4602
|
-
expect(result.decision).toBe("
|
|
4603
|
-
expect(result.reason).toContain("
|
|
4601
|
+
expect(result.decision).toBe("allow");
|
|
4602
|
+
expect(result.reason).toContain("Workspace mode");
|
|
4604
4603
|
});
|
|
4605
4604
|
|
|
4606
4605
|
// ── file operations outside workspace follow risk-based fallback ──
|
|
@@ -4615,14 +4614,14 @@ describe("workspace mode — auto-allow workspace-scoped operations", () => {
|
|
|
4615
4614
|
expect(result.reason).toContain("Low risk");
|
|
4616
4615
|
});
|
|
4617
4616
|
|
|
4618
|
-
test("file_write outside workspace →
|
|
4617
|
+
test("file_write outside workspace → allow (Low risk fallback)", async () => {
|
|
4619
4618
|
const result = await check(
|
|
4620
4619
|
"file_write",
|
|
4621
4620
|
{ file_path: "/tmp/outside.txt" },
|
|
4622
4621
|
workspaceDir,
|
|
4623
4622
|
);
|
|
4624
|
-
expect(result.decision).toBe("
|
|
4625
|
-
expect(result.reason).toContain("risk");
|
|
4623
|
+
expect(result.decision).toBe("allow");
|
|
4624
|
+
expect(result.reason).toContain("Low risk");
|
|
4626
4625
|
});
|
|
4627
4626
|
|
|
4628
4627
|
// ── bash (sandbox) — default rule matches, workspace mode not reached ──
|
|
@@ -145,21 +145,37 @@ describe("ensureChromeWithCdp", () => {
|
|
|
145
145
|
throw new Error("Connection refused");
|
|
146
146
|
};
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
148
|
+
// Replace setTimeout with a zero-delay version to skip retry waits
|
|
149
|
+
const origSetTimeout = globalThis.setTimeout;
|
|
150
|
+
globalThis.setTimeout = ((
|
|
151
|
+
fn: TimerHandler,
|
|
152
|
+
_ms?: number,
|
|
153
|
+
...args: unknown[]
|
|
154
|
+
) => {
|
|
155
|
+
return origSetTimeout(fn, 0, ...args);
|
|
156
|
+
}) as typeof setTimeout;
|
|
157
|
+
try {
|
|
158
|
+
const session = await ensureChromeWithCdp({
|
|
159
|
+
startUrl: "https://example.com/",
|
|
160
|
+
});
|
|
161
|
+
expect(session.launchedByUs).toBe(true);
|
|
162
|
+
expect(session.baseUrl).toBe("http://localhost:9222");
|
|
163
|
+
expect(spawnMock).toHaveBeenCalledTimes(1);
|
|
164
|
+
|
|
165
|
+
// Verify spawn was called with the right Chrome path and args
|
|
166
|
+
const spawnArgs = spawnMock.mock.calls[0] as unknown as [
|
|
167
|
+
string,
|
|
168
|
+
string[],
|
|
169
|
+
];
|
|
170
|
+
expect(spawnArgs[0]).toContain("Google Chrome");
|
|
171
|
+
const flags = spawnArgs[1];
|
|
172
|
+
expect(flags).toContain("--remote-debugging-port=9222");
|
|
173
|
+
expect(flags).toContain("--force-renderer-accessibility");
|
|
174
|
+
expect(flags.some((f: string) => f.includes("Chrome-CDP"))).toBe(true);
|
|
175
|
+
expect(flags).toContain("https://example.com/");
|
|
176
|
+
} finally {
|
|
177
|
+
globalThis.setTimeout = origSetTimeout;
|
|
178
|
+
}
|
|
163
179
|
});
|
|
164
180
|
|
|
165
181
|
test("uses custom port when specified", async () => {
|
|
@@ -182,9 +198,22 @@ describe("ensureChromeWithCdp", () => {
|
|
|
182
198
|
throw new Error("Connection refused");
|
|
183
199
|
};
|
|
184
200
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
201
|
+
// Replace setTimeout with a zero-delay version to skip retry waits
|
|
202
|
+
const origSetTimeout = globalThis.setTimeout;
|
|
203
|
+
globalThis.setTimeout = ((
|
|
204
|
+
fn: TimerHandler,
|
|
205
|
+
_ms?: number,
|
|
206
|
+
...args: unknown[]
|
|
207
|
+
) => {
|
|
208
|
+
return origSetTimeout(fn, 0, ...args);
|
|
209
|
+
}) as typeof setTimeout;
|
|
210
|
+
try {
|
|
211
|
+
const promise = ensureChromeWithCdp();
|
|
212
|
+
await expect(promise).rejects.toThrow("CDP endpoint not responding");
|
|
213
|
+
} finally {
|
|
214
|
+
globalThis.setTimeout = origSetTimeout;
|
|
215
|
+
}
|
|
216
|
+
});
|
|
188
217
|
});
|
|
189
218
|
|
|
190
219
|
// ---------------------------------------------------------------------------
|
|
@@ -38,9 +38,9 @@ mock.module("../config/loader.js", () => ({
|
|
|
38
38
|
"image-generation": {
|
|
39
39
|
mode: "your-own",
|
|
40
40
|
provider: "gemini",
|
|
41
|
-
model: "gemini-
|
|
41
|
+
model: "gemini-3.1-flash-image-preview",
|
|
42
42
|
},
|
|
43
|
-
"web-search": { mode: "your-own", provider: "
|
|
43
|
+
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
44
44
|
},
|
|
45
45
|
}),
|
|
46
46
|
loadConfig: () => ({}),
|
|
@@ -76,9 +76,9 @@ mock.module("../config/loader.js", () => ({
|
|
|
76
76
|
"image-generation": {
|
|
77
77
|
mode: "your-own",
|
|
78
78
|
provider: "gemini",
|
|
79
|
-
model: "gemini-
|
|
79
|
+
model: "gemini-3.1-flash-image-preview",
|
|
80
80
|
},
|
|
81
|
-
"web-search": { mode: "your-own", provider: "
|
|
81
|
+
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
82
82
|
},
|
|
83
83
|
}),
|
|
84
84
|
loadConfig: () => ({}),
|
|
@@ -93,10 +93,12 @@ describe("AssistantConfigSchema", () => {
|
|
|
93
93
|
expect(result.services.inference.mode).toBe("your-own");
|
|
94
94
|
expect(result.services["image-generation"].provider).toBe("gemini");
|
|
95
95
|
expect(result.services["image-generation"].model).toBe(
|
|
96
|
-
"gemini-
|
|
96
|
+
"gemini-3.1-flash-image-preview",
|
|
97
97
|
);
|
|
98
98
|
expect(result.services["image-generation"].mode).toBe("your-own");
|
|
99
|
-
expect(result.services["web-search"].provider).toBe(
|
|
99
|
+
expect(result.services["web-search"].provider).toBe(
|
|
100
|
+
"inference-provider-native",
|
|
101
|
+
);
|
|
100
102
|
expect(result.services["web-search"].mode).toBe("your-own");
|
|
101
103
|
expect(result.maxTokens).toBe(16000);
|
|
102
104
|
expect(result.thinking).toEqual({
|
|
@@ -125,11 +127,10 @@ describe("AssistantConfigSchema", () => {
|
|
|
125
127
|
providerStreamTimeoutSec: 300,
|
|
126
128
|
});
|
|
127
129
|
expect(result.sandbox).toEqual({
|
|
128
|
-
enabled:
|
|
130
|
+
enabled: false,
|
|
129
131
|
});
|
|
130
132
|
expect(result.rateLimit).toEqual({
|
|
131
133
|
maxRequestsPerMinute: 0,
|
|
132
|
-
maxTokensPerSession: 0,
|
|
133
134
|
});
|
|
134
135
|
expect(result.secretDetection).toEqual({
|
|
135
136
|
enabled: true,
|
|
@@ -153,8 +154,7 @@ describe("AssistantConfigSchema", () => {
|
|
|
153
154
|
shellMaxTimeoutSec: 300,
|
|
154
155
|
permissionTimeoutSec: 60,
|
|
155
156
|
},
|
|
156
|
-
|
|
157
|
-
rateLimit: { maxRequestsPerMinute: 10, maxTokensPerSession: 100000 },
|
|
157
|
+
rateLimit: { maxRequestsPerMinute: 10 },
|
|
158
158
|
secretDetection: {
|
|
159
159
|
enabled: false,
|
|
160
160
|
action: "block" as const,
|
|
@@ -351,13 +351,6 @@ describe("AssistantConfigSchema", () => {
|
|
|
351
351
|
expect(result.success).toBe(false);
|
|
352
352
|
});
|
|
353
353
|
|
|
354
|
-
test("rejects non-integer rateLimit values", () => {
|
|
355
|
-
const result = AssistantConfigSchema.safeParse({
|
|
356
|
-
rateLimit: { maxTokensPerSession: 3.5 },
|
|
357
|
-
});
|
|
358
|
-
expect(result.success).toBe(false);
|
|
359
|
-
});
|
|
360
|
-
|
|
361
354
|
test("rejects negative auditLog.retentionDays", () => {
|
|
362
355
|
const result = AssistantConfigSchema.safeParse({
|
|
363
356
|
auditLog: { retentionDays: -7 },
|
|
@@ -376,11 +369,10 @@ describe("AssistantConfigSchema", () => {
|
|
|
376
369
|
|
|
377
370
|
test("accepts zero for non-negative fields", () => {
|
|
378
371
|
const result = AssistantConfigSchema.parse({
|
|
379
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
372
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
380
373
|
auditLog: { retentionDays: 0 },
|
|
381
374
|
});
|
|
382
375
|
expect(result.rateLimit.maxRequestsPerMinute).toBe(0);
|
|
383
|
-
expect(result.rateLimit.maxTokensPerSession).toBe(0);
|
|
384
376
|
expect(result.auditLog.retentionDays).toBe(0);
|
|
385
377
|
});
|
|
386
378
|
|
|
@@ -1105,7 +1097,7 @@ describe("loadConfig with schema validation", () => {
|
|
|
1105
1097
|
test("falls back for invalid sandbox.enabled", () => {
|
|
1106
1098
|
writeConfig({ sandbox: { enabled: "yes" } });
|
|
1107
1099
|
const config = loadConfig();
|
|
1108
|
-
expect(config.sandbox.enabled).toBe(
|
|
1100
|
+
expect(config.sandbox.enabled).toBe(false);
|
|
1109
1101
|
});
|
|
1110
1102
|
|
|
1111
1103
|
test("loads sandbox with only enabled field", () => {
|
|
@@ -1132,11 +1124,10 @@ describe("loadConfig with schema validation", () => {
|
|
|
1132
1124
|
|
|
1133
1125
|
test("falls back for invalid rateLimit values", () => {
|
|
1134
1126
|
writeConfig({
|
|
1135
|
-
rateLimit: { maxRequestsPerMinute: -1
|
|
1127
|
+
rateLimit: { maxRequestsPerMinute: -1 },
|
|
1136
1128
|
});
|
|
1137
1129
|
const config = loadConfig();
|
|
1138
1130
|
expect(config.rateLimit.maxRequestsPerMinute).toBe(0);
|
|
1139
|
-
expect(config.rateLimit.maxTokensPerSession).toBe(0);
|
|
1140
1131
|
});
|
|
1141
1132
|
|
|
1142
1133
|
test("falls back for invalid auditLog.retentionDays", () => {
|
|
@@ -175,7 +175,7 @@ describe("bridgeConfirmationRequestToGuardian", () => {
|
|
|
175
175
|
expect(emittedSignals).toHaveLength(1);
|
|
176
176
|
expect(emittedSignals[0].sourceEventName).toBe("guardian.question");
|
|
177
177
|
expect(emittedSignals[0].sourceChannel).toBe("telegram");
|
|
178
|
-
expect(emittedSignals[0].
|
|
178
|
+
expect(emittedSignals[0].sourceContextId).toBe("conv-1");
|
|
179
179
|
|
|
180
180
|
const payload = emittedSignals[0].contextPayload as Record<string, unknown>;
|
|
181
181
|
expect(payload.requestId).toBe(canonicalRequest.id);
|
|
@@ -47,7 +47,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
47
47
|
nonInteractiveLatestTurnCompression: "truncate",
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
50
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
51
51
|
daemon: {
|
|
52
52
|
startupSocketWaitMs: 5000,
|
|
53
53
|
stopTimeoutMs: 5000,
|
|
@@ -64,9 +64,9 @@ mock.module("../config/loader.js", () => ({
|
|
|
64
64
|
"image-generation": {
|
|
65
65
|
mode: "your-own",
|
|
66
66
|
provider: "gemini",
|
|
67
|
-
model: "gemini-
|
|
67
|
+
model: "gemini-3.1-flash-image-preview",
|
|
68
68
|
},
|
|
69
|
-
"web-search": { mode: "your-own", provider: "
|
|
69
|
+
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
70
70
|
},
|
|
71
71
|
}),
|
|
72
72
|
loadRawConfig: () => ({}),
|
|
@@ -133,7 +133,7 @@ mock.module("../memory/retriever.js", () => ({
|
|
|
133
133
|
injectedTokens: 0,
|
|
134
134
|
latencyMs: 0,
|
|
135
135
|
}),
|
|
136
|
-
|
|
136
|
+
injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
|
|
137
137
|
}));
|
|
138
138
|
|
|
139
139
|
mock.module("../context/window-manager.js", () => ({
|
|
@@ -50,7 +50,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
50
50
|
nonInteractiveLatestTurnCompression: "truncate",
|
|
51
51
|
},
|
|
52
52
|
},
|
|
53
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
53
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
54
54
|
workspaceGit: { turnCommitMaxWaitMs: 10 },
|
|
55
55
|
ui: {},
|
|
56
56
|
}),
|
|
@@ -171,7 +171,7 @@ mock.module("../memory/retriever.js", () => ({
|
|
|
171
171
|
injectedTokens: 0,
|
|
172
172
|
latencyMs: 0,
|
|
173
173
|
}),
|
|
174
|
-
|
|
174
|
+
injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
|
|
175
175
|
}));
|
|
176
176
|
|
|
177
177
|
mock.module("../memory/app-store.js", () => ({
|
|
@@ -38,7 +38,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
38
38
|
nonInteractiveLatestTurnCompression: "truncate",
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
41
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
42
42
|
workspaceGit: { turnCommitMaxWaitMs: 10 },
|
|
43
43
|
ui: {},
|
|
44
44
|
}),
|
|
@@ -154,7 +154,7 @@ mock.module("../memory/retriever.js", () => ({
|
|
|
154
154
|
injectedTokens: 0,
|
|
155
155
|
latencyMs: 0,
|
|
156
156
|
}),
|
|
157
|
-
|
|
157
|
+
injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
|
|
158
158
|
}));
|
|
159
159
|
|
|
160
160
|
mock.module("../memory/app-store.js", () => ({
|
|
@@ -1834,11 +1834,18 @@ describe("session-agent-loop", () => {
|
|
|
1834
1834
|
const ctx = makeCtx({ agentLoopRun });
|
|
1835
1835
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
1836
1836
|
|
|
1837
|
-
// The
|
|
1837
|
+
// The error should be sent as a conversation_error (not as an
|
|
1838
|
+
// assistant_text_delta, which would cause duplicate text rendering
|
|
1839
|
+
// alongside the InlineChatErrorAlert card).
|
|
1838
1840
|
const textDeltas = events.filter(
|
|
1839
1841
|
(e) => e.type === "assistant_text_delta",
|
|
1840
1842
|
);
|
|
1841
|
-
expect(textDeltas
|
|
1843
|
+
expect(textDeltas).toHaveLength(0);
|
|
1844
|
+
|
|
1845
|
+
const conversationErrors = events.filter(
|
|
1846
|
+
(e) => e.type === "conversation_error",
|
|
1847
|
+
);
|
|
1848
|
+
expect(conversationErrors.length).toBeGreaterThanOrEqual(1);
|
|
1842
1849
|
});
|
|
1843
1850
|
});
|
|
1844
1851
|
});
|
|
@@ -78,7 +78,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
78
78
|
summaryModel: "mock-model",
|
|
79
79
|
maxSummaryTokens: 512,
|
|
80
80
|
},
|
|
81
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
81
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
82
82
|
timeouts: { permissionTimeoutSec: 1 },
|
|
83
83
|
skills: { entries: {}, allowBundled: true },
|
|
84
84
|
permissions: { mode: "workspace" },
|
|
@@ -158,7 +158,7 @@ mock.module("../memory/retriever.js", () => ({
|
|
|
158
158
|
injectedTokens: 0,
|
|
159
159
|
latencyMs: 0,
|
|
160
160
|
}),
|
|
161
|
-
|
|
161
|
+
injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
|
|
162
162
|
}));
|
|
163
163
|
|
|
164
164
|
mock.module("../context/window-manager.js", () => ({
|
|
@@ -66,6 +66,8 @@ describe("classifyConversationError", () => {
|
|
|
66
66
|
"ETIMEDOUT",
|
|
67
67
|
"ENOTFOUND",
|
|
68
68
|
"socket hang up",
|
|
69
|
+
"The socket connection was closed unexpectedly",
|
|
70
|
+
"Anthropic request failed: The socket connection was closed unexpectedly. For more information, pass `verbose: true` in the second argument to fetch()",
|
|
69
71
|
"fetch failed",
|
|
70
72
|
"Connection refused by server",
|
|
71
73
|
"connection reset",
|
|
@@ -276,6 +278,37 @@ describe("classifyConversationError", () => {
|
|
|
276
278
|
});
|
|
277
279
|
});
|
|
278
280
|
|
|
281
|
+
describe("streaming corruption errors", () => {
|
|
282
|
+
const cases = [
|
|
283
|
+
"Unexpected event order, got message_start before receiving message_stop",
|
|
284
|
+
"Anthropic request failed: Unexpected event order, got message_start before receiving \"message_stop\"",
|
|
285
|
+
"stream ended without producing a Message",
|
|
286
|
+
"request ended without sending any chunks",
|
|
287
|
+
"stream has ended, this shouldn't happen",
|
|
288
|
+
];
|
|
289
|
+
|
|
290
|
+
for (const msg of cases) {
|
|
291
|
+
it(`classifies "${msg}" as PROVIDER_API (retryable)`, () => {
|
|
292
|
+
const result = classifyConversationError(new Error(msg), baseCtx);
|
|
293
|
+
expect(result.code).toBe("PROVIDER_API");
|
|
294
|
+
expect(result.retryable).toBe(true);
|
|
295
|
+
expect(result.userMessage).toContain("interrupted");
|
|
296
|
+
expect(result.errorCategory).toBe("stream_corruption");
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
it("classifies ProviderError without statusCode with streaming message as PROVIDER_API", () => {
|
|
301
|
+
const err = new ProviderError(
|
|
302
|
+
"Unexpected event order, got message_start before receiving message_stop",
|
|
303
|
+
"anthropic",
|
|
304
|
+
);
|
|
305
|
+
const result = classifyConversationError(err, baseCtx);
|
|
306
|
+
expect(result.code).toBe("PROVIDER_API");
|
|
307
|
+
expect(result.retryable).toBe(true);
|
|
308
|
+
expect(result.errorCategory).toBe("stream_corruption");
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
279
312
|
describe("abort/cancel errors (non-user-initiated)", () => {
|
|
280
313
|
it('classifies "aborted" as CONVERSATION_ABORTED', () => {
|
|
281
314
|
const result = classifyConversationError(
|
|
@@ -31,7 +31,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
31
31
|
summaryModel: "mock-model",
|
|
32
32
|
maxSummaryTokens: 512,
|
|
33
33
|
},
|
|
34
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
34
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
35
35
|
}),
|
|
36
36
|
loadRawConfig: () => ({}),
|
|
37
37
|
saveRawConfig: () => {},
|
|
@@ -45,7 +45,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
45
45
|
nonInteractiveLatestTurnCompression: "truncate",
|
|
46
46
|
},
|
|
47
47
|
},
|
|
48
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
48
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
49
49
|
daemon: {
|
|
50
50
|
startupSocketWaitMs: 5000,
|
|
51
51
|
stopTimeoutMs: 5000,
|
|
@@ -62,9 +62,9 @@ mock.module("../config/loader.js", () => ({
|
|
|
62
62
|
"image-generation": {
|
|
63
63
|
mode: "your-own",
|
|
64
64
|
provider: "gemini",
|
|
65
|
-
model: "gemini-
|
|
65
|
+
model: "gemini-3.1-flash-image-preview",
|
|
66
66
|
},
|
|
67
|
-
"web-search": { mode: "your-own", provider: "
|
|
67
|
+
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
68
68
|
},
|
|
69
69
|
}),
|
|
70
70
|
loadRawConfig: () => ({}),
|
|
@@ -123,7 +123,7 @@ mock.module("../memory/retriever.js", () => ({
|
|
|
123
123
|
injectedTokens: 0,
|
|
124
124
|
latencyMs: 0,
|
|
125
125
|
}),
|
|
126
|
-
|
|
126
|
+
injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
|
|
127
127
|
}));
|
|
128
128
|
|
|
129
129
|
// Mock AgentLoop to capture the messages it receives
|
|
@@ -45,7 +45,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
45
45
|
nonInteractiveLatestTurnCompression: "truncate",
|
|
46
46
|
},
|
|
47
47
|
},
|
|
48
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
48
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
49
49
|
services: {
|
|
50
50
|
inference: {
|
|
51
51
|
mode: "your-own",
|
|
@@ -55,9 +55,9 @@ mock.module("../config/loader.js", () => ({
|
|
|
55
55
|
"image-generation": {
|
|
56
56
|
mode: "your-own",
|
|
57
57
|
provider: "gemini",
|
|
58
|
-
model: "gemini-
|
|
58
|
+
model: "gemini-3.1-flash-image-preview",
|
|
59
59
|
},
|
|
60
|
-
"web-search": { mode: "your-own", provider: "
|
|
60
|
+
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
61
61
|
},
|
|
62
62
|
}),
|
|
63
63
|
loadRawConfig: () => ({}),
|
|
@@ -185,7 +185,7 @@ mock.module("../memory/retriever.js", () => ({
|
|
|
185
185
|
injectedTokens: 0,
|
|
186
186
|
latencyMs: 0,
|
|
187
187
|
}),
|
|
188
|
-
|
|
188
|
+
injectMemoryRecallAsUserBlock: (msgs: Message[]) => msgs,
|
|
189
189
|
}));
|
|
190
190
|
|
|
191
191
|
let maybeCompactCalls: Array<{ force: boolean }> = [];
|