@vellumai/assistant 0.4.56 → 0.4.57
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 +185 -173
- 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 +237 -15
- package/src/__tests__/ephemeral-permissions.test.ts +4 -5
- package/src/__tests__/event-bus.test.ts +3 -3
- 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-shell-tool.test.ts +6 -6
- package/src/__tests__/http-user-message-parity.test.ts +2 -2
- 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 +1 -1
- package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
- 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 +547 -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 +139 -274
- 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 +25 -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 +1 -0
- 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 +2 -2
- package/src/notifications/emit-signal.ts +4 -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 +166 -33
- package/src/prompts/templates/IDENTITY.md +8 -23
- 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 +46 -2
- 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 +1 -1
- 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 +63 -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 +9 -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/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 +8 -8
- 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 +263 -78
- package/src/skills/catalog-install.ts +10 -0
- package/src/skills/managed-store.ts +2 -0
- package/src/skills/skill-memory.ts +220 -0
- package/src/subagent/manager.ts +1 -4
- package/src/telemetry/types.ts +10 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +1 -1
- package/src/telemetry/usage-telemetry-reporter.ts +51 -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 +1 -1
- package/src/tools/filesystem/write.ts +1 -1
- package/src/tools/host-filesystem/edit.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -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/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,220 @@
|
|
|
1
|
+
import { and, eq } from "drizzle-orm";
|
|
2
|
+
import { v4 as uuid } from "uuid";
|
|
3
|
+
|
|
4
|
+
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
5
|
+
import { getConfig } from "../config/loader.js";
|
|
6
|
+
import { getDb } from "../memory/db.js";
|
|
7
|
+
import { computeMemoryFingerprint } from "../memory/fingerprint.js";
|
|
8
|
+
import { enqueueMemoryJob } from "../memory/jobs-store.js";
|
|
9
|
+
import { memoryItems } from "../memory/schema.js";
|
|
10
|
+
import { getLogger } from "../util/logger.js";
|
|
11
|
+
import { type CatalogSkill, resolveCatalog } from "./catalog-install.js";
|
|
12
|
+
|
|
13
|
+
const log = getLogger("skill-memory");
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Build a semantically rich capability statement from a catalog skill entry.
|
|
17
|
+
* Truncated to 500 chars max (matching the limit used by memory item extraction).
|
|
18
|
+
*/
|
|
19
|
+
export function buildCapabilityStatement(entry: CatalogSkill): string {
|
|
20
|
+
const displayName =
|
|
21
|
+
entry.metadata?.vellum?.["display-name"] ?? entry.name;
|
|
22
|
+
const activationHints = entry.metadata?.vellum?.["activation-hints"];
|
|
23
|
+
|
|
24
|
+
let statement = `The "${displayName}" skill (${entry.id}) is available. ${entry.description}.`;
|
|
25
|
+
if (activationHints && activationHints.length > 0) {
|
|
26
|
+
statement += ` Use when: ${activationHints.join("; ")}.`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Truncate to 500 chars max
|
|
30
|
+
if (statement.length > 500) {
|
|
31
|
+
statement = statement.slice(0, 500);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return statement;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Upsert a capability memory item for a catalog skill.
|
|
39
|
+
* Best-effort: errors are logged but never thrown.
|
|
40
|
+
*/
|
|
41
|
+
export function upsertSkillCapabilityMemory(
|
|
42
|
+
skillId: string,
|
|
43
|
+
entry: CatalogSkill,
|
|
44
|
+
): void {
|
|
45
|
+
try {
|
|
46
|
+
const db = getDb();
|
|
47
|
+
const subject = `skill:${skillId}`;
|
|
48
|
+
const statement = buildCapabilityStatement(entry);
|
|
49
|
+
const kind = "capability";
|
|
50
|
+
const scopeId = "default";
|
|
51
|
+
const confidence = 1.0;
|
|
52
|
+
const importance = 0.7;
|
|
53
|
+
const fingerprint = computeMemoryFingerprint(
|
|
54
|
+
scopeId,
|
|
55
|
+
kind,
|
|
56
|
+
subject,
|
|
57
|
+
statement,
|
|
58
|
+
);
|
|
59
|
+
const now = Date.now();
|
|
60
|
+
|
|
61
|
+
const existing = db
|
|
62
|
+
.select()
|
|
63
|
+
.from(memoryItems)
|
|
64
|
+
.where(
|
|
65
|
+
and(
|
|
66
|
+
eq(memoryItems.kind, kind),
|
|
67
|
+
eq(memoryItems.subject, subject),
|
|
68
|
+
eq(memoryItems.scopeId, scopeId),
|
|
69
|
+
),
|
|
70
|
+
)
|
|
71
|
+
.get();
|
|
72
|
+
|
|
73
|
+
if (existing) {
|
|
74
|
+
if (existing.status === "active" && existing.fingerprint === fingerprint) {
|
|
75
|
+
// Same content — just touch lastSeenAt
|
|
76
|
+
db.update(memoryItems)
|
|
77
|
+
.set({ lastSeenAt: now })
|
|
78
|
+
.where(eq(memoryItems.id, existing.id))
|
|
79
|
+
.run();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (existing.status === "active") {
|
|
84
|
+
// Content changed — update statement and fingerprint
|
|
85
|
+
db.update(memoryItems)
|
|
86
|
+
.set({
|
|
87
|
+
statement,
|
|
88
|
+
fingerprint,
|
|
89
|
+
lastSeenAt: now,
|
|
90
|
+
})
|
|
91
|
+
.where(eq(memoryItems.id, existing.id))
|
|
92
|
+
.run();
|
|
93
|
+
enqueueMemoryJob("embed_item", { itemId: existing.id });
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// status === "deleted" or other — reactivate
|
|
98
|
+
db.update(memoryItems)
|
|
99
|
+
.set({
|
|
100
|
+
status: "active",
|
|
101
|
+
statement,
|
|
102
|
+
fingerprint,
|
|
103
|
+
lastSeenAt: now,
|
|
104
|
+
firstSeenAt: now,
|
|
105
|
+
})
|
|
106
|
+
.where(eq(memoryItems.id, existing.id))
|
|
107
|
+
.run();
|
|
108
|
+
enqueueMemoryJob("embed_item", { itemId: existing.id });
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// No existing — insert new row
|
|
113
|
+
const id = uuid();
|
|
114
|
+
db.insert(memoryItems)
|
|
115
|
+
.values({
|
|
116
|
+
id,
|
|
117
|
+
kind,
|
|
118
|
+
subject,
|
|
119
|
+
statement,
|
|
120
|
+
status: "active",
|
|
121
|
+
confidence,
|
|
122
|
+
importance,
|
|
123
|
+
fingerprint,
|
|
124
|
+
scopeId,
|
|
125
|
+
firstSeenAt: now,
|
|
126
|
+
lastSeenAt: now,
|
|
127
|
+
})
|
|
128
|
+
.run();
|
|
129
|
+
enqueueMemoryJob("embed_item", { itemId: id });
|
|
130
|
+
} catch (err) {
|
|
131
|
+
log.warn({ err, skillId }, "Failed to upsert skill capability memory");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Soft-delete the capability memory item for a skill.
|
|
137
|
+
* Best-effort: errors are logged but never thrown.
|
|
138
|
+
*/
|
|
139
|
+
export function deleteSkillCapabilityMemory(skillId: string): void {
|
|
140
|
+
try {
|
|
141
|
+
const db = getDb();
|
|
142
|
+
const subject = `skill:${skillId}`;
|
|
143
|
+
const now = Date.now();
|
|
144
|
+
|
|
145
|
+
const existing = db
|
|
146
|
+
.select()
|
|
147
|
+
.from(memoryItems)
|
|
148
|
+
.where(
|
|
149
|
+
and(
|
|
150
|
+
eq(memoryItems.kind, "capability"),
|
|
151
|
+
eq(memoryItems.subject, subject),
|
|
152
|
+
eq(memoryItems.scopeId, "default"),
|
|
153
|
+
),
|
|
154
|
+
)
|
|
155
|
+
.get();
|
|
156
|
+
|
|
157
|
+
if (existing && existing.status !== "deleted") {
|
|
158
|
+
db.update(memoryItems)
|
|
159
|
+
.set({ status: "deleted", lastSeenAt: now })
|
|
160
|
+
.where(eq(memoryItems.id, existing.id))
|
|
161
|
+
.run();
|
|
162
|
+
}
|
|
163
|
+
} catch (err) {
|
|
164
|
+
log.warn({ err, skillId }, "Failed to delete skill capability memory");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Seed capability memory items for all catalog skills.
|
|
170
|
+
* Prunes stale entries whose skills are no longer in the catalog.
|
|
171
|
+
* Best-effort: errors are logged but never thrown.
|
|
172
|
+
*/
|
|
173
|
+
export async function seedCatalogSkillMemories(): Promise<void> {
|
|
174
|
+
try {
|
|
175
|
+
const catalog = await resolveCatalog();
|
|
176
|
+
const config = getConfig();
|
|
177
|
+
const catalogIds = new Set<string>();
|
|
178
|
+
|
|
179
|
+
for (const entry of catalog) {
|
|
180
|
+
// Skip skills whose feature flag is disabled
|
|
181
|
+
const flagId = entry.metadata?.vellum?.["feature-flag"];
|
|
182
|
+
if (flagId) {
|
|
183
|
+
const flagKey = `feature_flags.${flagId}.enabled`;
|
|
184
|
+
if (!isAssistantFeatureFlagEnabled(flagKey, config)) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
catalogIds.add(entry.id);
|
|
190
|
+
upsertSkillCapabilityMemory(entry.id, entry);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Prune stale capability memories for skills no longer in catalog
|
|
194
|
+
const db = getDb();
|
|
195
|
+
const allCapabilities = db
|
|
196
|
+
.select()
|
|
197
|
+
.from(memoryItems)
|
|
198
|
+
.where(
|
|
199
|
+
and(
|
|
200
|
+
eq(memoryItems.kind, "capability"),
|
|
201
|
+
eq(memoryItems.scopeId, "default"),
|
|
202
|
+
eq(memoryItems.status, "active"),
|
|
203
|
+
),
|
|
204
|
+
)
|
|
205
|
+
.all();
|
|
206
|
+
|
|
207
|
+
const now = Date.now();
|
|
208
|
+
for (const item of allCapabilities) {
|
|
209
|
+
const itemSkillId = item.subject.replace("skill:", "");
|
|
210
|
+
if (!catalogIds.has(itemSkillId)) {
|
|
211
|
+
db.update(memoryItems)
|
|
212
|
+
.set({ status: "deleted", lastSeenAt: now })
|
|
213
|
+
.where(eq(memoryItems.id, item.id))
|
|
214
|
+
.run();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} catch (err) {
|
|
218
|
+
log.warn({ err }, "Failed to seed catalog skill memories");
|
|
219
|
+
}
|
|
220
|
+
}
|
package/src/subagent/manager.ts
CHANGED
|
@@ -134,10 +134,7 @@ export class SubagentManager {
|
|
|
134
134
|
appConfig.providerOrder,
|
|
135
135
|
);
|
|
136
136
|
const { rateLimit } = appConfig;
|
|
137
|
-
if (
|
|
138
|
-
rateLimit.maxRequestsPerMinute > 0 ||
|
|
139
|
-
rateLimit.maxTokensPerSession > 0
|
|
140
|
-
) {
|
|
137
|
+
if (rateLimit.maxRequestsPerMinute > 0) {
|
|
141
138
|
provider = new RateLimitProvider(
|
|
142
139
|
provider,
|
|
143
140
|
rateLimit,
|
package/src/telemetry/types.ts
CHANGED
|
@@ -22,5 +22,14 @@ export interface TurnTelemetryEvent extends TelemetryEventBase {
|
|
|
22
22
|
type: "turn";
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/** Lifecycle event — app_open, hatch, etc. */
|
|
26
|
+
export interface LifecycleTelemetryEvent extends TelemetryEventBase {
|
|
27
|
+
type: "lifecycle";
|
|
28
|
+
event_name: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
25
31
|
/** Discriminated union of all telemetry event types. */
|
|
26
|
-
export type TelemetryEvent =
|
|
32
|
+
export type TelemetryEvent =
|
|
33
|
+
| LlmUsageTelemetryEvent
|
|
34
|
+
| TurnTelemetryEvent
|
|
35
|
+
| LifecycleTelemetryEvent;
|
|
@@ -193,7 +193,7 @@ describe("UsageTelemetryReporter", () => {
|
|
|
193
193
|
|
|
194
194
|
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
195
195
|
const [url, opts] = mockFetch.mock.calls[0] as [string, RequestInit];
|
|
196
|
-
expect(url).toBe("https://test.vellum.ai/v1/
|
|
196
|
+
expect(url).toBe("https://test.vellum.ai/v1/telemetry/ingest/");
|
|
197
197
|
expect((opts.headers as Record<string, string>)["Authorization"]).toBe(
|
|
198
198
|
"Api-Key test-key",
|
|
199
199
|
);
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
getMemoryCheckpoint,
|
|
20
20
|
setMemoryCheckpoint,
|
|
21
21
|
} from "../memory/checkpoints.js";
|
|
22
|
+
import { queryUnreportedLifecycleEvents } from "../memory/lifecycle-events-store.js";
|
|
22
23
|
import { queryUnreportedUsageEvents } from "../memory/llm-usage-store.js";
|
|
23
24
|
import { queryUnreportedTurnEvents } from "../memory/turn-events-store.js";
|
|
24
25
|
import { resolveManagedProxyContext } from "../providers/managed-proxy/context.js";
|
|
@@ -37,10 +38,14 @@ const CHECKPOINT_KEY_WATERMARK = "telemetry:usage:last_reported_at";
|
|
|
37
38
|
const CHECKPOINT_KEY_WATERMARK_ID = "telemetry:usage:last_reported_id";
|
|
38
39
|
const CHECKPOINT_KEY_TURN_WATERMARK = "telemetry:turns:last_reported_at";
|
|
39
40
|
const CHECKPOINT_KEY_TURN_WATERMARK_ID = "telemetry:turns:last_reported_id";
|
|
41
|
+
const CHECKPOINT_KEY_LIFECYCLE_WATERMARK =
|
|
42
|
+
"telemetry:lifecycle:last_reported_at";
|
|
43
|
+
const CHECKPOINT_KEY_LIFECYCLE_WATERMARK_ID =
|
|
44
|
+
"telemetry:lifecycle:last_reported_id";
|
|
40
45
|
const REPORT_INTERVAL_MS = 5 * 60 * 1000;
|
|
41
46
|
const BATCH_SIZE = 500;
|
|
42
47
|
const MAX_CONSECUTIVE_BATCHES = 10;
|
|
43
|
-
const TELEMETRY_PATH = "/v1/
|
|
48
|
+
const TELEMETRY_PATH = "/v1/telemetry/ingest/";
|
|
44
49
|
|
|
45
50
|
// ---------------------------------------------------------------------------
|
|
46
51
|
// Reporter
|
|
@@ -100,6 +105,13 @@ export class UsageTelemetryReporter {
|
|
|
100
105
|
const turnWatermarkId =
|
|
101
106
|
getMemoryCheckpoint(CHECKPOINT_KEY_TURN_WATERMARK_ID) ?? undefined;
|
|
102
107
|
|
|
108
|
+
// Read lifecycle watermark (compound cursor: createdAt + id)
|
|
109
|
+
const lifecycleWatermark = Number(
|
|
110
|
+
getMemoryCheckpoint(CHECKPOINT_KEY_LIFECYCLE_WATERMARK) ?? "0",
|
|
111
|
+
);
|
|
112
|
+
const lifecycleWatermarkId =
|
|
113
|
+
getMemoryCheckpoint(CHECKPOINT_KEY_LIFECYCLE_WATERMARK_ID) ?? undefined;
|
|
114
|
+
|
|
103
115
|
// Query unreported events
|
|
104
116
|
const events = queryUnreportedUsageEvents(
|
|
105
117
|
watermark,
|
|
@@ -111,8 +123,18 @@ export class UsageTelemetryReporter {
|
|
|
111
123
|
turnWatermarkId,
|
|
112
124
|
BATCH_SIZE,
|
|
113
125
|
);
|
|
126
|
+
const lifecycleEvents = queryUnreportedLifecycleEvents(
|
|
127
|
+
lifecycleWatermark,
|
|
128
|
+
lifecycleWatermarkId,
|
|
129
|
+
BATCH_SIZE,
|
|
130
|
+
);
|
|
114
131
|
|
|
115
|
-
if (
|
|
132
|
+
if (
|
|
133
|
+
events.length === 0 &&
|
|
134
|
+
turnEvents.length === 0 &&
|
|
135
|
+
lifecycleEvents.length === 0
|
|
136
|
+
)
|
|
137
|
+
return;
|
|
116
138
|
|
|
117
139
|
// Resolve auth context — skip flush when neither auth mode is viable
|
|
118
140
|
const proxyCtx = await resolveManagedProxyContext();
|
|
@@ -154,6 +176,14 @@ export class UsageTelemetryReporter {
|
|
|
154
176
|
recorded_at: e.createdAt,
|
|
155
177
|
}),
|
|
156
178
|
),
|
|
179
|
+
...lifecycleEvents.map(
|
|
180
|
+
(e): TelemetryEvent => ({
|
|
181
|
+
type: "lifecycle",
|
|
182
|
+
daemon_event_id: e.id,
|
|
183
|
+
event_name: e.eventName,
|
|
184
|
+
recorded_at: e.createdAt,
|
|
185
|
+
}),
|
|
186
|
+
),
|
|
157
187
|
];
|
|
158
188
|
|
|
159
189
|
const assistantId = getExternalAssistantId() ?? "self";
|
|
@@ -207,8 +237,25 @@ export class UsageTelemetryReporter {
|
|
|
207
237
|
setMemoryCheckpoint(CHECKPOINT_KEY_TURN_WATERMARK_ID, lastTurn.id);
|
|
208
238
|
}
|
|
209
239
|
|
|
210
|
-
//
|
|
211
|
-
if (
|
|
240
|
+
// Advance lifecycle watermark (compound cursor)
|
|
241
|
+
if (lifecycleEvents.length > 0) {
|
|
242
|
+
const lastLifecycle = lifecycleEvents[lifecycleEvents.length - 1];
|
|
243
|
+
setMemoryCheckpoint(
|
|
244
|
+
CHECKPOINT_KEY_LIFECYCLE_WATERMARK,
|
|
245
|
+
String(lastLifecycle.createdAt),
|
|
246
|
+
);
|
|
247
|
+
setMemoryCheckpoint(
|
|
248
|
+
CHECKPOINT_KEY_LIFECYCLE_WATERMARK_ID,
|
|
249
|
+
lastLifecycle.id,
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// If we got a full batch of any type, there may be more — recurse
|
|
254
|
+
if (
|
|
255
|
+
events.length === BATCH_SIZE ||
|
|
256
|
+
turnEvents.length === BATCH_SIZE ||
|
|
257
|
+
lifecycleEvents.length === BATCH_SIZE
|
|
258
|
+
) {
|
|
212
259
|
await this._doFlush(batchCount + 1);
|
|
213
260
|
}
|
|
214
261
|
} catch (err) {
|
package/src/tools/AGENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Tools
|
|
1
|
+
# Tools - Agent Instructions
|
|
2
2
|
|
|
3
3
|
## No New Tools Policy
|
|
4
4
|
|
|
@@ -8,11 +8,11 @@ The tool registration system (`class ... implements Tool` + `registerTool()`) is
|
|
|
8
8
|
|
|
9
9
|
## Why This Policy Exists
|
|
10
10
|
|
|
11
|
-
1. **Skills are preferred**
|
|
11
|
+
1. **Skills are preferred** - The project direction is to teach the assistant CLI tools via skills rather than hardcoding tool implementations. Skills are progressively disclosed into context, are more portable, and are often self-contained.
|
|
12
12
|
|
|
13
|
-
2. **Context overhead**
|
|
13
|
+
2. **Context overhead** - Each registered tool adds to the system prompt and increases token usage for every conversation.
|
|
14
14
|
|
|
15
|
-
3. **Maintenance burden**
|
|
15
|
+
3. **Maintenance burden** - Tools require ongoing maintenance, testing, and security review. Skills can be iterated on independently.
|
|
16
16
|
|
|
17
17
|
## What To Do Instead
|
|
18
18
|
|
|
@@ -20,9 +20,9 @@ Instead of creating a new tool, consider:
|
|
|
20
20
|
|
|
21
21
|
1. **Create a skill**
|
|
22
22
|
|
|
23
|
-
2. **Use existing tools**
|
|
23
|
+
2. **Use existing tools** - Many capabilities can be achieved by combining existing tools (bash, file operations, network tools) with skill instructions.
|
|
24
24
|
|
|
25
|
-
3. **External CLI tools**
|
|
25
|
+
3. **External CLI tools** - If you need new functionality, consider whether it can be exposed as a CLI tool that the assistant can invoke via bash.
|
|
26
26
|
|
|
27
27
|
## Approved Exception: Credential Execution Service (CES) Tools
|
|
28
28
|
|
|
@@ -36,16 +36,16 @@ The following three CES tools are the only approved exception to the no-new-tool
|
|
|
36
36
|
|
|
37
37
|
These tools exist as `class ... implements Tool` registrations because:
|
|
38
38
|
|
|
39
|
-
- They enforce hard process-boundary isolation
|
|
39
|
+
- They enforce hard process-boundary isolation - credential values are materialized only inside the CES process (`credential-executor/` package), never in the assistant process
|
|
40
40
|
- Skills run inside the assistant process and cannot provide this isolation guarantee
|
|
41
41
|
- The tools are thin RPC stubs; actual credential materialization and execution logic lives in the separate `credential-executor/` package
|
|
42
42
|
|
|
43
43
|
**Key constraints**:
|
|
44
44
|
|
|
45
|
-
- CES is a **separate package and image**
|
|
46
|
-
- **Grants and audit logs are CES-owned** durable state
|
|
47
|
-
- `host_bash` is **outside the strong CES secrecy guarantee**
|
|
48
|
-
- Secure generic authenticated HTTP **must not** run through `run_authenticated_command`
|
|
45
|
+
- CES is a **separate package and image** - no direct source imports from `assistant/` to `credential-executor/` or vice versa
|
|
46
|
+
- **Grants and audit logs are CES-owned** durable state - the assistant never reads or writes CES grant or audit tables directly
|
|
47
|
+
- `host_bash` is **outside the strong CES secrecy guarantee** - it does not enforce credential isolation
|
|
48
|
+
- Secure generic authenticated HTTP **must not** run through `run_authenticated_command` - use `make_authenticated_request` instead, which enforces domain validation and produces structured audit logs
|
|
49
49
|
- Managed rollout requires a **third runtime image** (alongside assistant and gateway) and `vembda` pod-template changes
|
|
50
50
|
|
|
51
51
|
See [`assistant/docs/credential-execution-service.md`](../../docs/credential-execution-service.md) for the full ADR.
|
package/src/tools/acp/spawn.ts
CHANGED
|
@@ -28,7 +28,7 @@ export interface ExecutorResult {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// ---------------------------------------------------------------------------
|
|
31
|
-
// Dependency interfaces
|
|
31
|
+
// Dependency interfaces - callers inject these rather than importing the
|
|
32
32
|
// app-store module directly, which makes the executors testable with mocks.
|
|
33
33
|
// ---------------------------------------------------------------------------
|
|
34
34
|
|
|
@@ -82,7 +82,7 @@ export type ProxyResolver = (
|
|
|
82
82
|
) => Promise<ExecutorResult>;
|
|
83
83
|
|
|
84
84
|
// ---------------------------------------------------------------------------
|
|
85
|
-
// Path resolution
|
|
85
|
+
// Path resolution - multifile apps default to src/ for file operations
|
|
86
86
|
// ---------------------------------------------------------------------------
|
|
87
87
|
|
|
88
88
|
/**
|
|
@@ -146,7 +146,7 @@ export async function executeAppCreate(
|
|
|
146
146
|
const autoOpen = input.auto_open !== false; // default true
|
|
147
147
|
const preview = input.preview;
|
|
148
148
|
|
|
149
|
-
// Validate required fields
|
|
149
|
+
// Validate required fields - LLM input is not type-checked at runtime
|
|
150
150
|
if (typeof name !== "string" || name.trim() === "") {
|
|
151
151
|
return {
|
|
152
152
|
content: JSON.stringify({
|
|
@@ -168,7 +168,7 @@ export async function executeAppCreate(
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
// Extract icon from preview if provided
|
|
171
|
+
// Extract icon from preview if provided - only persist emoji-like values,
|
|
172
172
|
// not URLs which would render as raw strings in UI and bundle manifests.
|
|
173
173
|
const rawIcon = preview?.icon as string | undefined;
|
|
174
174
|
const icon = rawIcon && !rawIcon.startsWith("http") ? rawIcon : undefined;
|
|
@@ -270,7 +270,7 @@ render(<App />, document.getElementById('app')!);
|
|
|
270
270
|
isError: false,
|
|
271
271
|
};
|
|
272
272
|
} catch {
|
|
273
|
-
// Preview emission failure is non-fatal
|
|
273
|
+
// Preview emission failure is non-fatal - the app was created successfully.
|
|
274
274
|
return {
|
|
275
275
|
content: JSON.stringify({
|
|
276
276
|
...app,
|
|
@@ -388,7 +388,7 @@ export function executeAppFileList(
|
|
|
388
388
|
|
|
389
389
|
if (app && isMultifileApp(app)) {
|
|
390
390
|
// Separate build output paths from source paths without mutating the
|
|
391
|
-
// file path strings
|
|
391
|
+
// file path strings - consumers need clean paths for subsequent tool calls.
|
|
392
392
|
const buildOutputPaths = files.filter((f) =>
|
|
393
393
|
f.replace(/\\/g, "/").startsWith("dist/"),
|
|
394
394
|
);
|
|
@@ -557,7 +557,7 @@ export async function executeAppGenerateIcon(
|
|
|
557
557
|
);
|
|
558
558
|
|
|
559
559
|
if (existsSync(iconPath)) {
|
|
560
|
-
// Success
|
|
560
|
+
// Success - clean up the old icon backup
|
|
561
561
|
if (existsSync(tempPath)) {
|
|
562
562
|
unlinkSync(tempPath);
|
|
563
563
|
}
|
|
@@ -567,7 +567,7 @@ export async function executeAppGenerateIcon(
|
|
|
567
567
|
};
|
|
568
568
|
}
|
|
569
569
|
|
|
570
|
-
// Generation failed
|
|
570
|
+
// Generation failed - restore the previous icon if we had one
|
|
571
571
|
if (existsSync(tempPath)) {
|
|
572
572
|
renameSync(tempPath, iconPath);
|
|
573
573
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Registers app proxy tools with the daemon's tool registry.
|
|
3
3
|
*
|
|
4
4
|
* Called once at daemon startup via initializeTools(). Only proxy tools
|
|
5
|
-
* (e.g. app_open) are registered here
|
|
5
|
+
* (e.g. app_open) are registered here - non-proxy data tools are now
|
|
6
6
|
* provided by the app-builder skill via its TOOLS.json manifest.
|
|
7
7
|
*/
|
|
8
8
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* asset_materialize
|
|
2
|
+
* asset_materialize - write a stored attachment to a sandbox file path.
|
|
3
3
|
*
|
|
4
4
|
* Accepts an attachment ID (from asset_search) and a destination path
|
|
5
5
|
* within the sandbox working directory. Decodes the base64 content and
|
|
@@ -31,11 +31,11 @@ import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
|
31
31
|
import { getAttachmentSourceConversations } from "./search.js";
|
|
32
32
|
|
|
33
33
|
// ---------------------------------------------------------------------------
|
|
34
|
-
// Size limit
|
|
34
|
+
// Size limit - prevent materializing excessively large attachments
|
|
35
35
|
// ---------------------------------------------------------------------------
|
|
36
36
|
|
|
37
|
-
/**
|
|
38
|
-
export const MAX_MATERIALIZE_BYTES =
|
|
37
|
+
/** 100 MB ceiling for materialized files. */
|
|
38
|
+
export const MAX_MATERIALIZE_BYTES = 100 * 1024 * 1024;
|
|
39
39
|
|
|
40
40
|
// ---------------------------------------------------------------------------
|
|
41
41
|
// Helpers
|
|
@@ -110,7 +110,7 @@ class AssetMaterializeTool implements Tool {
|
|
|
110
110
|
name = "asset_materialize";
|
|
111
111
|
description = definition.description;
|
|
112
112
|
category = "assets";
|
|
113
|
-
defaultRiskLevel = RiskLevel.
|
|
113
|
+
defaultRiskLevel = RiskLevel.Low;
|
|
114
114
|
|
|
115
115
|
getDefinition(): ToolDefinition {
|
|
116
116
|
return definition;
|
|
@@ -177,7 +177,7 @@ class AssetMaterializeTool implements Tool {
|
|
|
177
177
|
if (sources.length > 0) {
|
|
178
178
|
const hasStandard = sources.some((s) => s.conversationType !== "private");
|
|
179
179
|
if (!hasStandard) {
|
|
180
|
-
// All sources are private
|
|
180
|
+
// All sources are private - check if the caller is in any of those conversations
|
|
181
181
|
const callerInSourceConversation = sources.some((s) =>
|
|
182
182
|
isAttachmentVisible(
|
|
183
183
|
{ conversationId: s.conversationId, isPrivate: true },
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* asset_search
|
|
2
|
+
* asset_search - cross-conversation attachment metadata search.
|
|
3
3
|
*
|
|
4
4
|
* Queries the attachments store for matching assets by MIME type,
|
|
5
5
|
* filename, recency, or conversation scope. Returns metadata and
|
|
6
|
-
* attachment IDs only
|
|
6
|
+
* attachment IDs only - never base64 payloads. The IDs can be
|
|
7
7
|
* passed to asset_materialize (PR 35) to retrieve actual content.
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -33,7 +33,7 @@ import { registerTool } from "../registry.js";
|
|
|
33
33
|
import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
|
|
34
34
|
|
|
35
35
|
// ---------------------------------------------------------------------------
|
|
36
|
-
// Recency presets
|
|
36
|
+
// Recency presets - map human-readable labels to epoch-ms cutoff offsets
|
|
37
37
|
// ---------------------------------------------------------------------------
|
|
38
38
|
|
|
39
39
|
const RECENCY_MS: Record<string, number> = {
|
|
@@ -113,7 +113,7 @@ function isAttachmentVisibleFromContext(
|
|
|
113
113
|
return true;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
// All sources are private
|
|
116
|
+
// All sources are private - visible only if the caller is in one of those conversations
|
|
117
117
|
return sources.some((s) =>
|
|
118
118
|
isAttachmentVisible(
|
|
119
119
|
{ conversationId: s.conversationId, isPrivate: true },
|
|
@@ -143,13 +143,13 @@ export function searchAttachments(
|
|
|
143
143
|
const db = getDb();
|
|
144
144
|
const conditions = [];
|
|
145
145
|
|
|
146
|
-
// MIME type filter
|
|
146
|
+
// MIME type filter - supports wildcards like 'image/*' via LIKE
|
|
147
147
|
if (params.mime_type) {
|
|
148
148
|
const mimePattern = params.mime_type.replace(/\*/g, "%");
|
|
149
149
|
conditions.push(like(attachments.mimeType, mimePattern));
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
// Filename filter
|
|
152
|
+
// Filename filter - case-insensitive substring match (escape LIKE wildcards)
|
|
153
153
|
if (params.filename) {
|
|
154
154
|
conditions.push(
|
|
155
155
|
like(
|
|
@@ -159,7 +159,7 @@ export function searchAttachments(
|
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
// Recency filter
|
|
162
|
+
// Recency filter - computed cutoff timestamp
|
|
163
163
|
if (params.recency) {
|
|
164
164
|
const offsetMs = RECENCY_MS[params.recency];
|
|
165
165
|
if (offsetMs) {
|
|
@@ -168,7 +168,7 @@ export function searchAttachments(
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
// Conversation scope
|
|
171
|
+
// Conversation scope - join through message_attachments + messages
|
|
172
172
|
if (params.conversation_id) {
|
|
173
173
|
const linkedIds = db
|
|
174
174
|
.select({ attachmentId: messageAttachments.attachmentId })
|
|
@@ -239,7 +239,7 @@ export function searchAttachments(
|
|
|
239
239
|
}));
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
-
// No conversation constraint
|
|
242
|
+
// No conversation constraint - query attachments table directly
|
|
243
243
|
const limit = Math.min(params.limit ?? DEFAULT_LIMIT, MAX_RESULTS);
|
|
244
244
|
const where = conditions.length > 0 ? and(...conditions) : undefined;
|
|
245
245
|
|
|
@@ -271,7 +271,7 @@ const definition: ToolDefinition = {
|
|
|
271
271
|
name: "asset_search",
|
|
272
272
|
description:
|
|
273
273
|
"Search for previously uploaded media assets (images, documents, etc.) by metadata. " +
|
|
274
|
-
"Returns attachment IDs and metadata
|
|
274
|
+
"Returns attachment IDs and metadata - not file content. Use the returned IDs with " +
|
|
275
275
|
"asset_materialize to retrieve actual file data.",
|
|
276
276
|
input_schema: {
|
|
277
277
|
type: "object",
|
|
@@ -157,7 +157,7 @@ describe("AuthSessionCache", () => {
|
|
|
157
157
|
];
|
|
158
158
|
writeSessionsFile(tmpDir, sessions);
|
|
159
159
|
|
|
160
|
-
// Create a fresh cache
|
|
160
|
+
// Create a fresh cache - load() has NOT been called
|
|
161
161
|
const cache = new AuthSessionCache(tmpDir);
|
|
162
162
|
|
|
163
163
|
// markAuthenticated should ensureLoaded first, so existing sessions
|
|
@@ -192,7 +192,7 @@ describe("AuthSessionCache", () => {
|
|
|
192
192
|
];
|
|
193
193
|
writeSessionsFile(tmpDir, sessions);
|
|
194
194
|
|
|
195
|
-
// Create a fresh cache
|
|
195
|
+
// Create a fresh cache - load() has NOT been called
|
|
196
196
|
const cache = new AuthSessionCache(tmpDir);
|
|
197
197
|
|
|
198
198
|
// invalidate should ensureLoaded first, so unrelated sessions
|