@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
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { describe, expect, test } from "bun:test";
|
|
4
|
+
|
|
5
|
+
const REPO_ROOT = resolve(import.meta.dirname ?? __dirname, "..", "..", "..");
|
|
6
|
+
const SKILL_PATH = resolve(REPO_ROOT, "skills", "slack-app-setup", "SKILL.md");
|
|
7
|
+
|
|
8
|
+
const skillContent = readFileSync(SKILL_PATH, "utf-8");
|
|
9
|
+
|
|
10
|
+
describe("slack-app-setup skill regression", () => {
|
|
11
|
+
test("keeps Slack token collection on the secure credential prompt path", () => {
|
|
12
|
+
expect(skillContent).toContain('`credential_store` with `action: "prompt"`');
|
|
13
|
+
expect(skillContent).toContain(
|
|
14
|
+
"same Slack settings handler used by Settings",
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("forbids plaintext forms and chat-pasted secrets", () => {
|
|
19
|
+
expect(skillContent).toContain("Do NOT use `ui_show`");
|
|
20
|
+
expect(skillContent).toContain("Do NOT ask the user to paste them in chat");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("does not instruct the agent to reimplement Slack validation in shell", () => {
|
|
24
|
+
expect(skillContent).not.toContain(
|
|
25
|
+
"assistant credentials reveal --service slack_channel",
|
|
26
|
+
);
|
|
27
|
+
expect(skillContent).not.toContain(
|
|
28
|
+
'curl -sf -X POST "https://slack.com/api/auth.test"',
|
|
29
|
+
);
|
|
30
|
+
expect(skillContent).not.toContain("assistant config set slack.teamId");
|
|
31
|
+
expect(skillContent).not.toContain("assistant config set slack.teamName");
|
|
32
|
+
expect(skillContent).not.toContain("assistant config set slack.botUserId");
|
|
33
|
+
expect(skillContent).not.toContain(
|
|
34
|
+
"assistant config set slack.botUsername",
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -4,6 +4,11 @@ import { join } from "node:path";
|
|
|
4
4
|
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
5
5
|
|
|
6
6
|
const testDir = mkdtempSync(join(tmpdir(), "slack-channel-cfg-test-"));
|
|
7
|
+
const secureStorePath = join(testDir, "keys.enc");
|
|
8
|
+
const metadataPath = join(testDir, "metadata.json");
|
|
9
|
+
const originalVellumDev = process.env.VELLUM_DEV;
|
|
10
|
+
|
|
11
|
+
process.env.VELLUM_DEV = "1";
|
|
7
12
|
|
|
8
13
|
// In-memory config store for tests
|
|
9
14
|
let configStore: Record<string, unknown> = {};
|
|
@@ -84,32 +89,6 @@ mock.module("../util/logger.js", () => ({
|
|
|
84
89
|
}),
|
|
85
90
|
}));
|
|
86
91
|
|
|
87
|
-
// Mock secure key storage
|
|
88
|
-
let secureKeyStore: Record<string, string> = {};
|
|
89
|
-
|
|
90
|
-
mock.module("../security/secure-keys.js", () => {
|
|
91
|
-
const syncSet = (account: string, value: string) => {
|
|
92
|
-
secureKeyStore[account] = value;
|
|
93
|
-
return true;
|
|
94
|
-
};
|
|
95
|
-
const syncDelete = (account: string) => {
|
|
96
|
-
if (account in secureKeyStore) {
|
|
97
|
-
delete secureKeyStore[account];
|
|
98
|
-
return "deleted" as const;
|
|
99
|
-
}
|
|
100
|
-
return "not-found" as const;
|
|
101
|
-
};
|
|
102
|
-
return {
|
|
103
|
-
getSecureKeyAsync: async (account: string) =>
|
|
104
|
-
secureKeyStore[account] ?? undefined,
|
|
105
|
-
setSecureKeyAsync: async (account: string, value: string) =>
|
|
106
|
-
syncSet(account, value),
|
|
107
|
-
deleteSecureKeyAsync: async (account: string) => syncDelete(account),
|
|
108
|
-
listSecureKeysAsync: async () => Object.keys(secureKeyStore),
|
|
109
|
-
_resetBackend: () => {},
|
|
110
|
-
};
|
|
111
|
-
});
|
|
112
|
-
|
|
113
92
|
// Mock oauth-store (getConnectionByProvider)
|
|
114
93
|
let oauthConnectionStore: Record<
|
|
115
94
|
string,
|
|
@@ -148,54 +127,28 @@ mock.module("../oauth/manual-token-connection.js", () => ({
|
|
|
148
127
|
removeManualTokenConnection: (providerKey: string) => {
|
|
149
128
|
delete oauthConnectionStore[providerKey];
|
|
150
129
|
},
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
let credentialMetadataStore: Array<{
|
|
155
|
-
service: string;
|
|
156
|
-
field: string;
|
|
157
|
-
accountInfo?: string;
|
|
158
|
-
}> = [];
|
|
159
|
-
|
|
160
|
-
mock.module("../tools/credentials/metadata-store.js", () => ({
|
|
161
|
-
getCredentialMetadata: (service: string, field: string) =>
|
|
162
|
-
credentialMetadataStore.find(
|
|
163
|
-
(m) => m.service === service && m.field === field,
|
|
164
|
-
) ?? undefined,
|
|
165
|
-
upsertCredentialMetadata: (
|
|
166
|
-
service: string,
|
|
167
|
-
field: string,
|
|
168
|
-
policy?: Record<string, unknown>,
|
|
130
|
+
syncManualTokenConnection: async (
|
|
131
|
+
providerKey: string,
|
|
132
|
+
accountInfo?: string,
|
|
169
133
|
) => {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
134
|
+
const { getSecureKeyAsync } = await import("../security/secure-keys.js");
|
|
135
|
+
if (providerKey !== "slack_channel") return;
|
|
136
|
+
const hasBotToken = !!(await getSecureKeyAsync(
|
|
137
|
+
credentialKey("slack_channel", "bot_token"),
|
|
138
|
+
));
|
|
139
|
+
const hasAppToken = !!(await getSecureKeyAsync(
|
|
140
|
+
credentialKey("slack_channel", "app_token"),
|
|
141
|
+
));
|
|
142
|
+
if (hasBotToken && hasAppToken) {
|
|
143
|
+
oauthConnectionStore[providerKey] = {
|
|
144
|
+
id: `conn-${providerKey}`,
|
|
145
|
+
status: "active",
|
|
146
|
+
accountInfo: accountInfo ?? null,
|
|
147
|
+
};
|
|
148
|
+
return;
|
|
177
149
|
}
|
|
178
|
-
|
|
179
|
-
service,
|
|
180
|
-
field,
|
|
181
|
-
accountInfo: policy?.accountInfo as string | undefined,
|
|
182
|
-
};
|
|
183
|
-
credentialMetadataStore.push(record);
|
|
184
|
-
return record;
|
|
185
|
-
},
|
|
186
|
-
deleteCredentialMetadata: (service: string, field: string) => {
|
|
187
|
-
const idx = credentialMetadataStore.findIndex(
|
|
188
|
-
(m) => m.service === service && m.field === field,
|
|
189
|
-
);
|
|
190
|
-
if (idx !== -1) {
|
|
191
|
-
credentialMetadataStore.splice(idx, 1);
|
|
192
|
-
return true;
|
|
193
|
-
}
|
|
194
|
-
return false;
|
|
150
|
+
delete oauthConnectionStore[providerKey];
|
|
195
151
|
},
|
|
196
|
-
listCredentialMetadata: () => credentialMetadataStore,
|
|
197
|
-
assertMetadataWritable: () => {},
|
|
198
|
-
_setMetadataPath: () => {},
|
|
199
152
|
}));
|
|
200
153
|
|
|
201
154
|
// Mock fetch for Slack API validation
|
|
@@ -207,9 +160,28 @@ import {
|
|
|
207
160
|
setSlackChannelConfig,
|
|
208
161
|
} from "../daemon/handlers/config-slack-channel.js";
|
|
209
162
|
import { credentialKey } from "../security/credential-key.js";
|
|
163
|
+
import { _setStorePath } from "../security/encrypted-store.js";
|
|
164
|
+
import {
|
|
165
|
+
_resetBackend,
|
|
166
|
+
getSecureKeyAsync,
|
|
167
|
+
setSecureKeyAsync,
|
|
168
|
+
} from "../security/secure-keys.js";
|
|
169
|
+
import {
|
|
170
|
+
_setMetadataPath,
|
|
171
|
+
listCredentialMetadata,
|
|
172
|
+
upsertCredentialMetadata,
|
|
173
|
+
} from "../tools/credentials/metadata-store.js";
|
|
210
174
|
|
|
211
175
|
afterAll(() => {
|
|
212
176
|
globalThis.fetch = originalFetch;
|
|
177
|
+
_setMetadataPath(null);
|
|
178
|
+
_setStorePath(null);
|
|
179
|
+
_resetBackend();
|
|
180
|
+
if (originalVellumDev === undefined) {
|
|
181
|
+
delete process.env.VELLUM_DEV;
|
|
182
|
+
} else {
|
|
183
|
+
process.env.VELLUM_DEV = originalVellumDev;
|
|
184
|
+
}
|
|
213
185
|
try {
|
|
214
186
|
rmSync(testDir, { recursive: true });
|
|
215
187
|
} catch {
|
|
@@ -219,11 +191,14 @@ afterAll(() => {
|
|
|
219
191
|
|
|
220
192
|
describe("Slack channel config handler", () => {
|
|
221
193
|
beforeEach(() => {
|
|
222
|
-
secureKeyStore = {};
|
|
223
|
-
credentialMetadataStore = [];
|
|
224
194
|
oauthConnectionStore = {};
|
|
225
195
|
configStore = {};
|
|
226
196
|
globalThis.fetch = originalFetch;
|
|
197
|
+
rmSync(secureStorePath, { force: true });
|
|
198
|
+
rmSync(metadataPath, { force: true });
|
|
199
|
+
_setStorePath(secureStorePath);
|
|
200
|
+
_resetBackend();
|
|
201
|
+
_setMetadataPath(metadataPath);
|
|
227
202
|
});
|
|
228
203
|
|
|
229
204
|
test("GET returns correct shape when not configured", async () => {
|
|
@@ -239,8 +214,16 @@ describe("Slack channel config handler", () => {
|
|
|
239
214
|
id: "conn-slack",
|
|
240
215
|
status: "active",
|
|
241
216
|
};
|
|
242
|
-
|
|
243
|
-
|
|
217
|
+
await Promise.all([
|
|
218
|
+
setSecureKeyAsync(
|
|
219
|
+
credentialKey("slack_channel", "bot_token"),
|
|
220
|
+
"xoxb-test",
|
|
221
|
+
),
|
|
222
|
+
setSecureKeyAsync(
|
|
223
|
+
credentialKey("slack_channel", "app_token"),
|
|
224
|
+
"xapp-test",
|
|
225
|
+
),
|
|
226
|
+
]);
|
|
244
227
|
|
|
245
228
|
const result = await getSlackChannelConfig();
|
|
246
229
|
expect(result.success).toBe(true);
|
|
@@ -249,13 +232,35 @@ describe("Slack channel config handler", () => {
|
|
|
249
232
|
expect(result.connected).toBe(true);
|
|
250
233
|
});
|
|
251
234
|
|
|
235
|
+
test("GET backfills the slack_channel connection row when chat setup stored both credentials", async () => {
|
|
236
|
+
await Promise.all([
|
|
237
|
+
setSecureKeyAsync(
|
|
238
|
+
credentialKey("slack_channel", "bot_token"),
|
|
239
|
+
"xoxb-test",
|
|
240
|
+
),
|
|
241
|
+
setSecureKeyAsync(
|
|
242
|
+
credentialKey("slack_channel", "app_token"),
|
|
243
|
+
"xapp-test",
|
|
244
|
+
),
|
|
245
|
+
]);
|
|
246
|
+
|
|
247
|
+
const result = await getSlackChannelConfig();
|
|
248
|
+
|
|
249
|
+
expect(result.success).toBe(true);
|
|
250
|
+
expect(result.connected).toBe(true);
|
|
251
|
+
expect(oauthConnectionStore["slack_channel"]).toBeDefined();
|
|
252
|
+
});
|
|
253
|
+
|
|
252
254
|
test("GET reports per-field token presence independently of connection row", async () => {
|
|
253
255
|
// Only bot_token in keychain, no app_token, but connection row exists
|
|
254
256
|
oauthConnectionStore["slack_channel"] = {
|
|
255
257
|
id: "conn-slack",
|
|
256
258
|
status: "active",
|
|
257
259
|
};
|
|
258
|
-
|
|
260
|
+
await setSecureKeyAsync(
|
|
261
|
+
credentialKey("slack_channel", "bot_token"),
|
|
262
|
+
"xoxb-test",
|
|
263
|
+
);
|
|
259
264
|
|
|
260
265
|
const result = await getSlackChannelConfig();
|
|
261
266
|
expect(result.success).toBe(true);
|
|
@@ -270,8 +275,16 @@ describe("Slack channel config handler", () => {
|
|
|
270
275
|
id: "conn-slack",
|
|
271
276
|
status: "active",
|
|
272
277
|
};
|
|
273
|
-
|
|
274
|
-
|
|
278
|
+
await Promise.all([
|
|
279
|
+
setSecureKeyAsync(
|
|
280
|
+
credentialKey("slack_channel", "bot_token"),
|
|
281
|
+
"xoxb-test",
|
|
282
|
+
),
|
|
283
|
+
setSecureKeyAsync(
|
|
284
|
+
credentialKey("slack_channel", "app_token"),
|
|
285
|
+
"xapp-test",
|
|
286
|
+
),
|
|
287
|
+
]);
|
|
275
288
|
configStore = {
|
|
276
289
|
slack: {
|
|
277
290
|
teamId: "T123",
|
|
@@ -301,9 +314,9 @@ describe("Slack channel config handler", () => {
|
|
|
301
314
|
);
|
|
302
315
|
expect(result.success).toBe(true);
|
|
303
316
|
expect(result.hasAppToken).toBe(true);
|
|
304
|
-
expect(
|
|
305
|
-
"
|
|
306
|
-
);
|
|
317
|
+
expect(
|
|
318
|
+
await getSecureKeyAsync(credentialKey("slack_channel", "app_token")),
|
|
319
|
+
).toBe("xapp-valid-token-123");
|
|
307
320
|
});
|
|
308
321
|
|
|
309
322
|
test("POST validates bot token via Slack auth.test API and writes config", async () => {
|
|
@@ -357,16 +370,18 @@ describe("Slack channel config handler", () => {
|
|
|
357
370
|
});
|
|
358
371
|
|
|
359
372
|
test("DELETE clears credentials and config", async () => {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
373
|
+
await Promise.all([
|
|
374
|
+
setSecureKeyAsync(
|
|
375
|
+
credentialKey("slack_channel", "bot_token"),
|
|
376
|
+
"xoxb-test",
|
|
377
|
+
),
|
|
378
|
+
setSecureKeyAsync(
|
|
379
|
+
credentialKey("slack_channel", "app_token"),
|
|
380
|
+
"xapp-test",
|
|
381
|
+
),
|
|
382
|
+
]);
|
|
383
|
+
upsertCredentialMetadata("slack_channel", "bot_token", {});
|
|
384
|
+
upsertCredentialMetadata("slack_channel", "app_token", {});
|
|
370
385
|
configStore = {
|
|
371
386
|
slack: {
|
|
372
387
|
teamId: "T123",
|
|
@@ -383,12 +398,12 @@ describe("Slack channel config handler", () => {
|
|
|
383
398
|
expect(result.connected).toBe(false);
|
|
384
399
|
|
|
385
400
|
expect(
|
|
386
|
-
|
|
401
|
+
await getSecureKeyAsync(credentialKey("slack_channel", "bot_token")),
|
|
387
402
|
).toBeUndefined();
|
|
388
403
|
expect(
|
|
389
|
-
|
|
404
|
+
await getSecureKeyAsync(credentialKey("slack_channel", "app_token")),
|
|
390
405
|
).toBeUndefined();
|
|
391
|
-
expect(
|
|
406
|
+
expect(listCredentialMetadata()).toHaveLength(0);
|
|
392
407
|
|
|
393
408
|
// Assert config values were cleared
|
|
394
409
|
const slack = configStore.slack as Record<string, unknown>;
|
|
@@ -44,9 +44,9 @@ mock.module("../config/loader.js", () => ({
|
|
|
44
44
|
"image-generation": {
|
|
45
45
|
mode: "your-own",
|
|
46
46
|
provider: "gemini",
|
|
47
|
-
model: "gemini-
|
|
47
|
+
model: "gemini-3.1-flash-image-preview",
|
|
48
48
|
},
|
|
49
|
-
"web-search": { mode: "your-own", provider: "
|
|
49
|
+
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
50
50
|
},
|
|
51
51
|
}),
|
|
52
52
|
}));
|
|
@@ -56,9 +56,9 @@ mock.module("../config/loader.js", () => ({
|
|
|
56
56
|
"image-generation": {
|
|
57
57
|
mode: "your-own",
|
|
58
58
|
provider: "gemini",
|
|
59
|
-
model: "gemini-
|
|
59
|
+
model: "gemini-3.1-flash-image-preview",
|
|
60
60
|
},
|
|
61
|
-
"web-search": { mode: "your-own", provider: "
|
|
61
|
+
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
62
62
|
},
|
|
63
63
|
}),
|
|
64
64
|
}));
|
|
@@ -36,9 +36,9 @@ mock.module("../config/loader.js", () => ({
|
|
|
36
36
|
"image-generation": {
|
|
37
37
|
mode: "your-own",
|
|
38
38
|
provider: "gemini",
|
|
39
|
-
model: "gemini-
|
|
39
|
+
model: "gemini-3.1-flash-image-preview",
|
|
40
40
|
},
|
|
41
|
-
"web-search": { mode: "your-own", provider: "
|
|
41
|
+
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
42
42
|
},
|
|
43
43
|
}),
|
|
44
44
|
getSwarmDisabledConfig: () => ({
|
|
@@ -43,9 +43,12 @@ mock.module("../util/platform.js", () => ({
|
|
|
43
43
|
readSessionToken: () => null,
|
|
44
44
|
}));
|
|
45
45
|
|
|
46
|
-
const noopLogger
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
const noopLogger: Record<string, unknown> = new Proxy(
|
|
47
|
+
{} as Record<string, unknown>,
|
|
48
|
+
{
|
|
49
|
+
get: (_target, prop) => (prop === "child" ? () => noopLogger : () => {}),
|
|
50
|
+
},
|
|
51
|
+
);
|
|
49
52
|
|
|
50
53
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
51
54
|
const realLogger = require("../util/logger.js");
|
|
@@ -62,7 +65,6 @@ mock.module("../config/loader.js", () => ({
|
|
|
62
65
|
getConfig: () => ({
|
|
63
66
|
ui: {},
|
|
64
67
|
|
|
65
|
-
sandbox: { enabled: true },
|
|
66
68
|
services: {
|
|
67
69
|
inference: {
|
|
68
70
|
mode: "your-own",
|
|
@@ -72,9 +74,9 @@ mock.module("../config/loader.js", () => ({
|
|
|
72
74
|
"image-generation": {
|
|
73
75
|
mode: "your-own",
|
|
74
76
|
provider: "gemini",
|
|
75
|
-
model: "gemini-
|
|
77
|
+
model: "gemini-3.1-flash-image-preview",
|
|
76
78
|
},
|
|
77
|
-
"web-search": { mode: "your-own", provider: "
|
|
79
|
+
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
78
80
|
},
|
|
79
81
|
}),
|
|
80
82
|
loadConfig: () => ({}),
|
|
@@ -100,7 +102,6 @@ const {
|
|
|
100
102
|
buildSystemPrompt,
|
|
101
103
|
ensurePromptFiles,
|
|
102
104
|
stripCommentLines,
|
|
103
|
-
buildExternalCommsIdentitySection,
|
|
104
105
|
SYSTEM_PROMPT_CACHE_BOUNDARY,
|
|
105
106
|
} = await import("../prompts/system-prompt.js");
|
|
106
107
|
|
|
@@ -119,16 +120,13 @@ function basePrompt(result: string): string {
|
|
|
119
120
|
boundaryIdx >= 0
|
|
120
121
|
? result.slice(boundaryIdx + SYSTEM_PROMPT_CACHE_BOUNDARY.length)
|
|
121
122
|
: result;
|
|
122
|
-
// Strip the hardcoded em-dash instruction preamble (in case boundary is absent)
|
|
123
|
-
const emDashLine =
|
|
124
|
-
"IMPORTANT: Never use em dashes (\u2014) in your messages. Use commas, periods, or just start a new sentence instead.";
|
|
125
|
-
if (s.startsWith(emDashLine)) {
|
|
126
|
-
s = s.slice(emDashLine.length).replace(/^\n\n/, "");
|
|
127
|
-
}
|
|
128
123
|
for (const heading of [
|
|
129
124
|
"## Configuration",
|
|
130
125
|
"## Skills Catalog",
|
|
131
126
|
"## Available Skills",
|
|
127
|
+
"## External Communications Identity",
|
|
128
|
+
"## Connected Services",
|
|
129
|
+
"## Dynamic Skill Authoring Workflow",
|
|
132
130
|
]) {
|
|
133
131
|
if (s.startsWith(heading)) {
|
|
134
132
|
s = "";
|
|
@@ -211,13 +209,7 @@ describe("buildSystemPrompt", () => {
|
|
|
211
209
|
const result = buildSystemPrompt();
|
|
212
210
|
expect(result).toContain("Custom identity");
|
|
213
211
|
expect(result).toContain("## Available Skills");
|
|
214
|
-
expect(result).toContain("
|
|
215
|
-
expect(result).toContain('id="release-checklist"');
|
|
216
|
-
expect(result).toContain('name="Release Checklist"');
|
|
217
|
-
expect(result).toContain('description="Deployment checks."');
|
|
218
|
-
expect(result).toContain(
|
|
219
|
-
"call `skill_load` to load the full instructions, then use `skill_execute` to invoke the skill's tools.",
|
|
220
|
-
);
|
|
212
|
+
expect(result).toContain("**release-checklist**: Deployment checks");
|
|
221
213
|
});
|
|
222
214
|
|
|
223
215
|
test("keeps SOUL.md and IDENTITY.md additive with skills", () => {
|
|
@@ -239,39 +231,15 @@ describe("buildSystemPrompt", () => {
|
|
|
239
231
|
);
|
|
240
232
|
});
|
|
241
233
|
|
|
242
|
-
test("includes
|
|
243
|
-
const result = buildSystemPrompt();
|
|
244
|
-
expect(result).toContain("## Parallel Task Orchestration");
|
|
245
|
-
expect(result).toContain("swarm_delegate");
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
test("includes external service access preference section", () => {
|
|
234
|
+
test("includes external service access section", () => {
|
|
249
235
|
const result = buildSystemPrompt();
|
|
250
|
-
expect(result).toContain("## External Service Access
|
|
251
|
-
expect(result).toContain("
|
|
252
|
-
expect(result).toContain("Browser automation as last resort");
|
|
236
|
+
expect(result).toContain("## External Service Access");
|
|
237
|
+
expect(result).toContain("browser automation as last resort");
|
|
253
238
|
});
|
|
254
239
|
|
|
255
|
-
test("
|
|
240
|
+
test("does not include removed sections", () => {
|
|
256
241
|
const result = buildSystemPrompt();
|
|
257
|
-
expect(result).toContain("## External Communications Identity");
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
test("external comms identity section contains assistant guidance and resolved user reference", () => {
|
|
261
|
-
const result = buildSystemPrompt();
|
|
262
|
-
expect(result).toContain("Refer to yourself as an **assistant**");
|
|
263
|
-
expect(result).toContain("on behalf of **John**");
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
test("buildExternalCommsIdentitySection returns section with expected content", () => {
|
|
267
|
-
const section = buildExternalCommsIdentitySection();
|
|
268
|
-
expect(section).toContain("## External Communications Identity");
|
|
269
|
-
expect(section).toContain("assistant");
|
|
270
|
-
expect(section).toContain("John");
|
|
271
|
-
expect(section).toContain(
|
|
272
|
-
"Do not volunteer that you are an AI unless directly asked",
|
|
273
|
-
);
|
|
274
|
-
expect(section).toContain("Occasional variations are acceptable");
|
|
242
|
+
expect(result).not.toContain("## External Communications Identity");
|
|
275
243
|
});
|
|
276
244
|
|
|
277
245
|
test("does not include removed domain routing sections", () => {
|
|
@@ -282,18 +250,9 @@ describe("buildSystemPrompt", () => {
|
|
|
282
250
|
expect(result).not.toContain("## Routing: Starter Tasks");
|
|
283
251
|
});
|
|
284
252
|
|
|
285
|
-
test("
|
|
253
|
+
test("does not include removed memory persistence section", () => {
|
|
286
254
|
const result = buildSystemPrompt();
|
|
287
|
-
expect(result).toContain("## Memory Persistence");
|
|
288
|
-
expect(result).toContain("memory_manage");
|
|
289
|
-
expect(result).toContain("Saved > unsaved. Always.");
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
test("config section uses workspace directory from platform util", () => {
|
|
293
|
-
const result = buildSystemPrompt();
|
|
294
|
-
expect(result).toContain(
|
|
295
|
-
`Your configuration directory is \`${TEST_DIR}/\`.`,
|
|
296
|
-
);
|
|
255
|
+
expect(result).not.toContain("## Memory Persistence");
|
|
297
256
|
});
|
|
298
257
|
|
|
299
258
|
test("omits user skills from catalog when none are configured", () => {
|
|
@@ -380,12 +339,6 @@ describe("buildSystemPrompt", () => {
|
|
|
380
339
|
expect(result).not.toContain("### Update Handling");
|
|
381
340
|
});
|
|
382
341
|
|
|
383
|
-
test("config section lists UPDATES.md", () => {
|
|
384
|
-
const result = buildSystemPrompt();
|
|
385
|
-
expect(result).toContain("`UPDATES.md`");
|
|
386
|
-
expect(result).toContain("Release update notes");
|
|
387
|
-
});
|
|
388
|
-
|
|
389
342
|
test("strips comment lines starting with _ from prompt files", () => {
|
|
390
343
|
writeFileSync(
|
|
391
344
|
join(TEST_DIR, "IDENTITY.md"),
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { credentialKey } from "../security/credential-key.js";
|
|
4
|
+
|
|
5
|
+
let secureKeyStore: Record<string, string> = {};
|
|
6
|
+
let oauthConnectionStore: Record<
|
|
7
|
+
string,
|
|
8
|
+
{ id: string; status: string; accountInfo?: string | null }
|
|
9
|
+
> = {};
|
|
10
|
+
const syncCalls: Array<{ providerKey: string; accountInfo?: string }> = [];
|
|
11
|
+
|
|
12
|
+
mock.module("../config/loader.js", () => ({
|
|
13
|
+
getConfig: () => ({ telegram: {}, ui: {} }),
|
|
14
|
+
loadRawConfig: () => ({}),
|
|
15
|
+
saveRawConfig: () => {},
|
|
16
|
+
saveConfig: () => {},
|
|
17
|
+
invalidateConfigCache: () => {},
|
|
18
|
+
setNestedValue: () => {},
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
mock.module("../inbound/platform-callback-registration.js", () => ({
|
|
22
|
+
registerCallbackRoute: async () => {},
|
|
23
|
+
shouldUsePlatformCallbacks: () => false,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
mock.module("../daemon/handlers/shared.js", () => ({
|
|
27
|
+
log: {
|
|
28
|
+
warn: () => {},
|
|
29
|
+
info: () => {},
|
|
30
|
+
error: () => {},
|
|
31
|
+
debug: () => {},
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
mock.module("../security/secure-keys.js", () => ({
|
|
36
|
+
getSecureKeyAsync: async (account: string) =>
|
|
37
|
+
secureKeyStore[account] ?? undefined,
|
|
38
|
+
setSecureKeyAsync: async (account: string, value: string) => {
|
|
39
|
+
secureKeyStore[account] = value;
|
|
40
|
+
return true;
|
|
41
|
+
},
|
|
42
|
+
deleteSecureKeyAsync: async (account: string) => {
|
|
43
|
+
if (account in secureKeyStore) {
|
|
44
|
+
delete secureKeyStore[account];
|
|
45
|
+
return "deleted" as const;
|
|
46
|
+
}
|
|
47
|
+
return "not-found" as const;
|
|
48
|
+
},
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
mock.module("../oauth/oauth-store.js", () => ({
|
|
52
|
+
getConnectionByProvider: (providerKey: string) =>
|
|
53
|
+
oauthConnectionStore[providerKey] ?? undefined,
|
|
54
|
+
}));
|
|
55
|
+
|
|
56
|
+
mock.module("../oauth/manual-token-connection.js", () => ({
|
|
57
|
+
ensureManualTokenConnection: async () => {},
|
|
58
|
+
removeManualTokenConnection: () => {},
|
|
59
|
+
syncManualTokenConnection: async (
|
|
60
|
+
providerKey: string,
|
|
61
|
+
accountInfo?: string,
|
|
62
|
+
) => {
|
|
63
|
+
syncCalls.push({ providerKey, accountInfo });
|
|
64
|
+
if (providerKey !== "telegram") return;
|
|
65
|
+
const hasBotToken =
|
|
66
|
+
!!secureKeyStore[credentialKey("telegram", "bot_token")];
|
|
67
|
+
const hasWebhookSecret =
|
|
68
|
+
!!secureKeyStore[credentialKey("telegram", "webhook_secret")];
|
|
69
|
+
if (hasBotToken && hasWebhookSecret) {
|
|
70
|
+
oauthConnectionStore[providerKey] = {
|
|
71
|
+
id: `conn-${providerKey}`,
|
|
72
|
+
status: "active",
|
|
73
|
+
accountInfo: accountInfo ?? null,
|
|
74
|
+
};
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
delete oauthConnectionStore[providerKey];
|
|
78
|
+
},
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
mock.module("../telegram/bot-username.js", () => ({
|
|
82
|
+
getTelegramBotId: () => "123456",
|
|
83
|
+
getTelegramBotUsername: () => "testbot",
|
|
84
|
+
}));
|
|
85
|
+
|
|
86
|
+
mock.module("../tools/credentials/metadata-store.js", () => ({
|
|
87
|
+
deleteCredentialMetadata: () => true,
|
|
88
|
+
upsertCredentialMetadata: () => ({}),
|
|
89
|
+
}));
|
|
90
|
+
|
|
91
|
+
const originalFetch = globalThis.fetch;
|
|
92
|
+
|
|
93
|
+
import { getTelegramConfig } from "../daemon/handlers/config-telegram.js";
|
|
94
|
+
|
|
95
|
+
describe("Telegram config handler", () => {
|
|
96
|
+
beforeEach(() => {
|
|
97
|
+
secureKeyStore = {};
|
|
98
|
+
oauthConnectionStore = {};
|
|
99
|
+
syncCalls.length = 0;
|
|
100
|
+
globalThis.fetch = originalFetch;
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
afterEach(() => {
|
|
104
|
+
globalThis.fetch = originalFetch;
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("GET backfills telegram connection metadata with @botUsername", async () => {
|
|
108
|
+
secureKeyStore[credentialKey("telegram", "bot_token")] = "123:abc";
|
|
109
|
+
secureKeyStore[credentialKey("telegram", "webhook_secret")] = "secret";
|
|
110
|
+
|
|
111
|
+
const result = await getTelegramConfig();
|
|
112
|
+
|
|
113
|
+
expect(result.success).toBe(true);
|
|
114
|
+
expect(result.botUsername).toBe("testbot");
|
|
115
|
+
expect(result.connected).toBe(true);
|
|
116
|
+
expect(syncCalls).toEqual([
|
|
117
|
+
{ providerKey: "telegram", accountInfo: "@testbot" },
|
|
118
|
+
]);
|
|
119
|
+
expect(oauthConnectionStore["telegram"]?.accountInfo).toBe("@testbot");
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -662,7 +662,7 @@ describe("Shell tool input validation", () => {
|
|
|
662
662
|
};
|
|
663
663
|
expect(def.name).toBe("bash");
|
|
664
664
|
expect(schema.required).toContain("command");
|
|
665
|
-
expect(schema.required).toContain("
|
|
665
|
+
expect(schema.required).toContain("activity");
|
|
666
666
|
expect(schema.properties.command).toBeDefined();
|
|
667
667
|
expect(schema.properties.timeout_seconds).toBeDefined();
|
|
668
668
|
expect(schema.properties.network_mode).toBeDefined();
|
|
@@ -32,8 +32,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
32
32
|
shellMaxTimeoutSec: 600,
|
|
33
33
|
permissionTimeoutSec: 300,
|
|
34
34
|
},
|
|
35
|
-
|
|
36
|
-
rateLimit: { maxRequestsPerMinute: 0, maxTokensPerSession: 0 },
|
|
35
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
37
36
|
secretDetection: {
|
|
38
37
|
enabled: false,
|
|
39
38
|
action: "warn" as const,
|