@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,222 @@
|
|
|
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 = entry.metadata?.vellum?.["display-name"] ?? entry.name;
|
|
21
|
+
const activationHints = entry.metadata?.vellum?.["activation-hints"];
|
|
22
|
+
|
|
23
|
+
let statement = `The "${displayName}" skill (${entry.id}) is available. ${entry.description}.`;
|
|
24
|
+
if (activationHints && activationHints.length > 0) {
|
|
25
|
+
statement += ` Use when: ${activationHints.join("; ")}.`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Truncate to 500 chars max
|
|
29
|
+
if (statement.length > 500) {
|
|
30
|
+
statement = statement.slice(0, 500);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return statement;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Upsert a capability memory item for a catalog skill.
|
|
38
|
+
* Best-effort: errors are logged but never thrown.
|
|
39
|
+
*/
|
|
40
|
+
export function upsertSkillCapabilityMemory(
|
|
41
|
+
skillId: string,
|
|
42
|
+
entry: CatalogSkill,
|
|
43
|
+
): void {
|
|
44
|
+
try {
|
|
45
|
+
const db = getDb();
|
|
46
|
+
const subject = `skill:${skillId}`;
|
|
47
|
+
const statement = buildCapabilityStatement(entry);
|
|
48
|
+
const kind = "capability";
|
|
49
|
+
const scopeId = "default";
|
|
50
|
+
const confidence = 1.0;
|
|
51
|
+
const importance = 0.7;
|
|
52
|
+
const fingerprint = computeMemoryFingerprint(
|
|
53
|
+
scopeId,
|
|
54
|
+
kind,
|
|
55
|
+
subject,
|
|
56
|
+
statement,
|
|
57
|
+
);
|
|
58
|
+
const now = Date.now();
|
|
59
|
+
|
|
60
|
+
const existing = db
|
|
61
|
+
.select()
|
|
62
|
+
.from(memoryItems)
|
|
63
|
+
.where(
|
|
64
|
+
and(
|
|
65
|
+
eq(memoryItems.kind, kind),
|
|
66
|
+
eq(memoryItems.subject, subject),
|
|
67
|
+
eq(memoryItems.scopeId, scopeId),
|
|
68
|
+
),
|
|
69
|
+
)
|
|
70
|
+
.get();
|
|
71
|
+
|
|
72
|
+
if (existing) {
|
|
73
|
+
if (
|
|
74
|
+
existing.status === "active" &&
|
|
75
|
+
existing.fingerprint === fingerprint
|
|
76
|
+
) {
|
|
77
|
+
// Same content — just touch lastSeenAt
|
|
78
|
+
db.update(memoryItems)
|
|
79
|
+
.set({ lastSeenAt: now })
|
|
80
|
+
.where(eq(memoryItems.id, existing.id))
|
|
81
|
+
.run();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (existing.status === "active") {
|
|
86
|
+
// Content changed — update statement and fingerprint
|
|
87
|
+
db.update(memoryItems)
|
|
88
|
+
.set({
|
|
89
|
+
statement,
|
|
90
|
+
fingerprint,
|
|
91
|
+
lastSeenAt: now,
|
|
92
|
+
})
|
|
93
|
+
.where(eq(memoryItems.id, existing.id))
|
|
94
|
+
.run();
|
|
95
|
+
enqueueMemoryJob("embed_item", { itemId: existing.id });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// status === "deleted" or other — reactivate
|
|
100
|
+
db.update(memoryItems)
|
|
101
|
+
.set({
|
|
102
|
+
status: "active",
|
|
103
|
+
statement,
|
|
104
|
+
fingerprint,
|
|
105
|
+
lastSeenAt: now,
|
|
106
|
+
firstSeenAt: now,
|
|
107
|
+
})
|
|
108
|
+
.where(eq(memoryItems.id, existing.id))
|
|
109
|
+
.run();
|
|
110
|
+
enqueueMemoryJob("embed_item", { itemId: existing.id });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// No existing — insert new row
|
|
115
|
+
const id = uuid();
|
|
116
|
+
db.insert(memoryItems)
|
|
117
|
+
.values({
|
|
118
|
+
id,
|
|
119
|
+
kind,
|
|
120
|
+
subject,
|
|
121
|
+
statement,
|
|
122
|
+
status: "active",
|
|
123
|
+
confidence,
|
|
124
|
+
importance,
|
|
125
|
+
fingerprint,
|
|
126
|
+
scopeId,
|
|
127
|
+
firstSeenAt: now,
|
|
128
|
+
lastSeenAt: now,
|
|
129
|
+
})
|
|
130
|
+
.run();
|
|
131
|
+
enqueueMemoryJob("embed_item", { itemId: id });
|
|
132
|
+
} catch (err) {
|
|
133
|
+
log.warn({ err, skillId }, "Failed to upsert skill capability memory");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Soft-delete the capability memory item for a skill.
|
|
139
|
+
* Best-effort: errors are logged but never thrown.
|
|
140
|
+
*/
|
|
141
|
+
export function deleteSkillCapabilityMemory(skillId: string): void {
|
|
142
|
+
try {
|
|
143
|
+
const db = getDb();
|
|
144
|
+
const subject = `skill:${skillId}`;
|
|
145
|
+
const now = Date.now();
|
|
146
|
+
|
|
147
|
+
const existing = db
|
|
148
|
+
.select()
|
|
149
|
+
.from(memoryItems)
|
|
150
|
+
.where(
|
|
151
|
+
and(
|
|
152
|
+
eq(memoryItems.kind, "capability"),
|
|
153
|
+
eq(memoryItems.subject, subject),
|
|
154
|
+
eq(memoryItems.scopeId, "default"),
|
|
155
|
+
),
|
|
156
|
+
)
|
|
157
|
+
.get();
|
|
158
|
+
|
|
159
|
+
if (existing && existing.status !== "deleted") {
|
|
160
|
+
db.update(memoryItems)
|
|
161
|
+
.set({ status: "deleted", lastSeenAt: now })
|
|
162
|
+
.where(eq(memoryItems.id, existing.id))
|
|
163
|
+
.run();
|
|
164
|
+
}
|
|
165
|
+
} catch (err) {
|
|
166
|
+
log.warn({ err, skillId }, "Failed to delete skill capability memory");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Seed capability memory items for all catalog skills.
|
|
172
|
+
* Prunes stale entries whose skills are no longer in the catalog.
|
|
173
|
+
* Best-effort: errors are logged but never thrown.
|
|
174
|
+
*/
|
|
175
|
+
export async function seedCatalogSkillMemories(): Promise<void> {
|
|
176
|
+
try {
|
|
177
|
+
const catalog = await resolveCatalog();
|
|
178
|
+
const config = getConfig();
|
|
179
|
+
const catalogIds = new Set<string>();
|
|
180
|
+
|
|
181
|
+
for (const entry of catalog) {
|
|
182
|
+
// Skip skills whose feature flag is disabled
|
|
183
|
+
const flagId = entry.metadata?.vellum?.["feature-flag"];
|
|
184
|
+
if (flagId) {
|
|
185
|
+
const flagKey = `feature_flags.${flagId}.enabled`;
|
|
186
|
+
if (!isAssistantFeatureFlagEnabled(flagKey, config)) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
catalogIds.add(entry.id);
|
|
192
|
+
upsertSkillCapabilityMemory(entry.id, entry);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Prune stale capability memories for skills no longer in catalog
|
|
196
|
+
const db = getDb();
|
|
197
|
+
const allCapabilities = db
|
|
198
|
+
.select()
|
|
199
|
+
.from(memoryItems)
|
|
200
|
+
.where(
|
|
201
|
+
and(
|
|
202
|
+
eq(memoryItems.kind, "capability"),
|
|
203
|
+
eq(memoryItems.scopeId, "default"),
|
|
204
|
+
eq(memoryItems.status, "active"),
|
|
205
|
+
),
|
|
206
|
+
)
|
|
207
|
+
.all();
|
|
208
|
+
|
|
209
|
+
const now = Date.now();
|
|
210
|
+
for (const item of allCapabilities) {
|
|
211
|
+
const itemSkillId = item.subject.replace("skill:", "");
|
|
212
|
+
if (!catalogIds.has(itemSkillId)) {
|
|
213
|
+
db.update(memoryItems)
|
|
214
|
+
.set({ status: "deleted", lastSeenAt: now })
|
|
215
|
+
.where(eq(memoryItems.id, item.id))
|
|
216
|
+
.run();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
} catch (err) {
|
|
220
|
+
log.warn({ err }, "Failed to seed catalog skill memories");
|
|
221
|
+
}
|
|
222
|
+
}
|
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;
|
|
@@ -89,6 +89,10 @@ mock.module("../util/logger.js", () => ({
|
|
|
89
89
|
}),
|
|
90
90
|
}));
|
|
91
91
|
|
|
92
|
+
mock.module("../version.js", () => ({
|
|
93
|
+
APP_VERSION: "1.2.3-test",
|
|
94
|
+
}));
|
|
95
|
+
|
|
92
96
|
// ---------------------------------------------------------------------------
|
|
93
97
|
// Production import (after mocks)
|
|
94
98
|
// ---------------------------------------------------------------------------
|
|
@@ -193,7 +197,7 @@ describe("UsageTelemetryReporter", () => {
|
|
|
193
197
|
|
|
194
198
|
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
195
199
|
const [url, opts] = mockFetch.mock.calls[0] as [string, RequestInit];
|
|
196
|
-
expect(url).toBe("https://test.vellum.ai/v1/
|
|
200
|
+
expect(url).toBe("https://test.vellum.ai/v1/telemetry/ingest/");
|
|
197
201
|
expect((opts.headers as Record<string, string>)["Authorization"]).toBe(
|
|
198
202
|
"Api-Key test-key",
|
|
199
203
|
);
|
|
@@ -370,8 +374,9 @@ describe("UsageTelemetryReporter", () => {
|
|
|
370
374
|
(mockFetch.mock.calls[0] as [string, RequestInit])[1].body as string,
|
|
371
375
|
);
|
|
372
376
|
|
|
373
|
-
// Top-level: installation_id and events array (no turn_events key)
|
|
377
|
+
// Top-level: installation_id, app_version, and events array (no turn_events key)
|
|
374
378
|
expect(body.installation_id).toBe("test-device-id");
|
|
379
|
+
expect(body.app_version).toBe("1.2.3-test");
|
|
375
380
|
expect(Array.isArray(body.events)).toBe(true);
|
|
376
381
|
expect(body.events.length).toBe(1);
|
|
377
382
|
expect(body.turn_events).toBeUndefined();
|
|
@@ -19,12 +19,14 @@ 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";
|
|
25
26
|
import { getExternalAssistantId } from "../runtime/auth/external-assistant-id.js";
|
|
26
27
|
import { getDeviceId } from "../util/device-id.js";
|
|
27
28
|
import { getLogger } from "../util/logger.js";
|
|
29
|
+
import { APP_VERSION } from "../version.js";
|
|
28
30
|
import type { TelemetryEvent } from "./types.js";
|
|
29
31
|
|
|
30
32
|
const log = getLogger("usage-telemetry");
|
|
@@ -37,10 +39,14 @@ const CHECKPOINT_KEY_WATERMARK = "telemetry:usage:last_reported_at";
|
|
|
37
39
|
const CHECKPOINT_KEY_WATERMARK_ID = "telemetry:usage:last_reported_id";
|
|
38
40
|
const CHECKPOINT_KEY_TURN_WATERMARK = "telemetry:turns:last_reported_at";
|
|
39
41
|
const CHECKPOINT_KEY_TURN_WATERMARK_ID = "telemetry:turns:last_reported_id";
|
|
42
|
+
const CHECKPOINT_KEY_LIFECYCLE_WATERMARK =
|
|
43
|
+
"telemetry:lifecycle:last_reported_at";
|
|
44
|
+
const CHECKPOINT_KEY_LIFECYCLE_WATERMARK_ID =
|
|
45
|
+
"telemetry:lifecycle:last_reported_id";
|
|
40
46
|
const REPORT_INTERVAL_MS = 5 * 60 * 1000;
|
|
41
47
|
const BATCH_SIZE = 500;
|
|
42
48
|
const MAX_CONSECUTIVE_BATCHES = 10;
|
|
43
|
-
const TELEMETRY_PATH = "/v1/
|
|
49
|
+
const TELEMETRY_PATH = "/v1/telemetry/ingest/";
|
|
44
50
|
|
|
45
51
|
// ---------------------------------------------------------------------------
|
|
46
52
|
// Reporter
|
|
@@ -100,6 +106,13 @@ export class UsageTelemetryReporter {
|
|
|
100
106
|
const turnWatermarkId =
|
|
101
107
|
getMemoryCheckpoint(CHECKPOINT_KEY_TURN_WATERMARK_ID) ?? undefined;
|
|
102
108
|
|
|
109
|
+
// Read lifecycle watermark (compound cursor: createdAt + id)
|
|
110
|
+
const lifecycleWatermark = Number(
|
|
111
|
+
getMemoryCheckpoint(CHECKPOINT_KEY_LIFECYCLE_WATERMARK) ?? "0",
|
|
112
|
+
);
|
|
113
|
+
const lifecycleWatermarkId =
|
|
114
|
+
getMemoryCheckpoint(CHECKPOINT_KEY_LIFECYCLE_WATERMARK_ID) ?? undefined;
|
|
115
|
+
|
|
103
116
|
// Query unreported events
|
|
104
117
|
const events = queryUnreportedUsageEvents(
|
|
105
118
|
watermark,
|
|
@@ -111,8 +124,18 @@ export class UsageTelemetryReporter {
|
|
|
111
124
|
turnWatermarkId,
|
|
112
125
|
BATCH_SIZE,
|
|
113
126
|
);
|
|
127
|
+
const lifecycleEvents = queryUnreportedLifecycleEvents(
|
|
128
|
+
lifecycleWatermark,
|
|
129
|
+
lifecycleWatermarkId,
|
|
130
|
+
BATCH_SIZE,
|
|
131
|
+
);
|
|
114
132
|
|
|
115
|
-
if (
|
|
133
|
+
if (
|
|
134
|
+
events.length === 0 &&
|
|
135
|
+
turnEvents.length === 0 &&
|
|
136
|
+
lifecycleEvents.length === 0
|
|
137
|
+
)
|
|
138
|
+
return;
|
|
116
139
|
|
|
117
140
|
// Resolve auth context — skip flush when neither auth mode is viable
|
|
118
141
|
const proxyCtx = await resolveManagedProxyContext();
|
|
@@ -154,6 +177,14 @@ export class UsageTelemetryReporter {
|
|
|
154
177
|
recorded_at: e.createdAt,
|
|
155
178
|
}),
|
|
156
179
|
),
|
|
180
|
+
...lifecycleEvents.map(
|
|
181
|
+
(e): TelemetryEvent => ({
|
|
182
|
+
type: "lifecycle",
|
|
183
|
+
daemon_event_id: e.id,
|
|
184
|
+
event_name: e.eventName,
|
|
185
|
+
recorded_at: e.createdAt,
|
|
186
|
+
}),
|
|
187
|
+
),
|
|
157
188
|
];
|
|
158
189
|
|
|
159
190
|
const assistantId = getExternalAssistantId() ?? "self";
|
|
@@ -162,6 +193,7 @@ export class UsageTelemetryReporter {
|
|
|
162
193
|
const payload = {
|
|
163
194
|
installation_id: getDeviceId(),
|
|
164
195
|
assistant_id: assistantId,
|
|
196
|
+
app_version: APP_VERSION,
|
|
165
197
|
...(organizationId ? { organization_id: organizationId } : {}),
|
|
166
198
|
...(userId ? { user_id: userId } : {}),
|
|
167
199
|
events: typedEvents,
|
|
@@ -207,8 +239,25 @@ export class UsageTelemetryReporter {
|
|
|
207
239
|
setMemoryCheckpoint(CHECKPOINT_KEY_TURN_WATERMARK_ID, lastTurn.id);
|
|
208
240
|
}
|
|
209
241
|
|
|
210
|
-
//
|
|
211
|
-
if (
|
|
242
|
+
// Advance lifecycle watermark (compound cursor)
|
|
243
|
+
if (lifecycleEvents.length > 0) {
|
|
244
|
+
const lastLifecycle = lifecycleEvents[lifecycleEvents.length - 1];
|
|
245
|
+
setMemoryCheckpoint(
|
|
246
|
+
CHECKPOINT_KEY_LIFECYCLE_WATERMARK,
|
|
247
|
+
String(lastLifecycle.createdAt),
|
|
248
|
+
);
|
|
249
|
+
setMemoryCheckpoint(
|
|
250
|
+
CHECKPOINT_KEY_LIFECYCLE_WATERMARK_ID,
|
|
251
|
+
lastLifecycle.id,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// If we got a full batch of any type, there may be more — recurse
|
|
256
|
+
if (
|
|
257
|
+
events.length === BATCH_SIZE ||
|
|
258
|
+
turnEvents.length === BATCH_SIZE ||
|
|
259
|
+
lifecycleEvents.length === BATCH_SIZE
|
|
260
|
+
) {
|
|
212
261
|
await this._doFlush(batchCount + 1);
|
|
213
262
|
}
|
|
214
263
|
} 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",
|