@vellumai/assistant 0.5.13 → 0.5.15
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/.env.example +1 -6
- package/AGENTS.md +4 -0
- package/ARCHITECTURE.md +0 -1
- package/bunfig.toml +1 -0
- package/docs/architecture/memory.md +3 -3
- package/openapi.yaml +127 -22
- package/package.json +1 -1
- package/src/__tests__/access-request-decision.test.ts +2 -32
- package/src/__tests__/actor-token-service.test.ts +1 -31
- package/src/__tests__/anthropic-provider.test.ts +53 -40
- package/src/__tests__/app-git-history.test.ts +9 -17
- package/src/__tests__/app-git-service.test.ts +14 -20
- package/src/__tests__/app-store-dir-names.test.ts +10 -20
- package/src/__tests__/approval-cascade.test.ts +2 -19
- package/src/__tests__/approval-primitive.test.ts +2 -27
- package/src/__tests__/approval-routes-http.test.ts +2 -30
- package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -28
- package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -45
- package/src/__tests__/attachments-store.test.ts +5 -32
- package/src/__tests__/audit-log-rotation.test.ts +5 -36
- package/src/__tests__/avatar-e2e.test.ts +1 -9
- package/src/__tests__/avatar-generator.test.ts +1 -7
- package/src/__tests__/browser-fill-credential.test.ts +0 -4
- package/src/__tests__/browser-manager.test.ts +0 -6
- package/src/__tests__/call-controller.test.ts +1 -22
- package/src/__tests__/call-conversation-messages.test.ts +0 -21
- package/src/__tests__/call-domain.test.ts +0 -25
- package/src/__tests__/call-pointer-messages.test.ts +0 -21
- package/src/__tests__/call-recovery.test.ts +0 -22
- package/src/__tests__/call-routes-http.test.ts +0 -24
- package/src/__tests__/call-store.test.ts +0 -21
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -24
- package/src/__tests__/canonical-guardian-store.test.ts +48 -21
- package/src/__tests__/channel-approval-routes.test.ts +6 -26
- package/src/__tests__/channel-approvals.test.ts +1 -38
- package/src/__tests__/channel-delivery-store.test.ts +0 -21
- package/src/__tests__/channel-guardian.test.ts +0 -26
- package/src/__tests__/channel-reply-delivery.test.ts +5 -0
- package/src/__tests__/channel-retry-sweep.test.ts +0 -21
- package/src/__tests__/checker.test.ts +26 -61
- package/src/__tests__/clawhub.test.ts +9 -25
- package/src/__tests__/cli-command-risk-guard.test.ts +0 -18
- package/src/__tests__/config-loader-backfill.test.ts +9 -28
- package/src/__tests__/config-schema-cmd.test.ts +5 -25
- package/src/__tests__/config-schema.test.ts +21 -40
- package/src/__tests__/config-watcher.test.ts +4 -91
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -21
- package/src/__tests__/contacts-tools.test.ts +0 -21
- package/src/__tests__/context-memory-e2e.test.ts +0 -21
- package/src/__tests__/context-window-manager.test.ts +130 -3
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -4
- package/src/__tests__/conversation-agent-loop.test.ts +0 -4
- package/src/__tests__/conversation-attachments.test.ts +1 -24
- package/src/__tests__/conversation-attention-store.test.ts +0 -21
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -22
- package/src/__tests__/conversation-clear-safety.test.ts +0 -22
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -21
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -24
- package/src/__tests__/conversation-disk-view-integration.test.ts +1 -23
- package/src/__tests__/conversation-disk-view.test.ts +5 -27
- package/src/__tests__/conversation-error.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +1 -33
- package/src/__tests__/conversation-fork-route.test.ts +0 -27
- package/src/__tests__/conversation-history-web-search.test.ts +23 -16
- package/src/__tests__/conversation-init.benchmark.test.ts +22 -43
- package/src/__tests__/conversation-key-store-disk-view.test.ts +8 -34
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -4
- package/src/__tests__/conversation-pre-run-repair.test.ts +0 -4
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -4
- package/src/__tests__/conversation-queue.test.ts +8 -8
- package/src/__tests__/conversation-routes-disk-view.test.ts +13 -51
- package/src/__tests__/conversation-runtime-assembly.test.ts +64 -38
- package/src/__tests__/conversation-slash-commands.test.ts +5 -0
- package/src/__tests__/conversation-slash-queue.test.ts +0 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -4
- package/src/__tests__/conversation-speed-override.test.ts +326 -0
- package/src/__tests__/conversation-starter-routes.test.ts +0 -23
- package/src/__tests__/conversation-store.test.ts +0 -21
- package/src/__tests__/conversation-unread-route.test.ts +0 -24
- package/src/__tests__/conversation-usage.test.ts +56 -21
- package/src/__tests__/conversation-wipe.test.ts +0 -21
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -4
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -4
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +8 -5
- package/src/__tests__/credential-vault-unit.test.ts +9 -428
- package/src/__tests__/credentials-cli.test.ts +10 -10
- package/src/__tests__/daemon-assistant-events.test.ts +0 -19
- package/src/__tests__/date-context.test.ts +77 -97
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +7 -24
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +29 -42
- package/src/__tests__/delete-managed-skill-tool.test.ts +2 -10
- package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -26
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +61 -15
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -36
- package/src/__tests__/email-cli.test.ts +6 -6
- package/src/__tests__/ephemeral-permissions.test.ts +5 -17
- package/src/__tests__/first-greeting.test.ts +4 -32
- package/src/__tests__/followup-tools.test.ts +0 -21
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -20
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -23
- package/src/__tests__/guardian-action-followup-executor.test.ts +0 -23
- package/src/__tests__/guardian-action-followup-store.test.ts +0 -21
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -21
- package/src/__tests__/guardian-action-late-reply.test.ts +0 -21
- package/src/__tests__/guardian-action-store.test.ts +0 -21
- package/src/__tests__/guardian-action-sweep.test.ts +0 -21
- package/src/__tests__/guardian-binding-drift-heal.test.ts +0 -23
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +172 -22
- package/src/__tests__/guardian-dispatch.test.ts +0 -21
- package/src/__tests__/guardian-grant-minting.test.ts +0 -22
- package/src/__tests__/guardian-outbound-http.test.ts +0 -22
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -23
- package/src/__tests__/guardian-routing-invariants.test.ts +0 -22
- package/src/__tests__/guardian-routing-state.test.ts +0 -22
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -24
- package/src/__tests__/headless-browser-interactions.test.ts +0 -4
- package/src/__tests__/headless-browser-navigate.test.ts +0 -4
- package/src/__tests__/headless-browser-read-tools.test.ts +0 -4
- package/src/__tests__/headless-browser-snapshot.test.ts +0 -4
- package/src/__tests__/heartbeat-service.test.ts +99 -26
- package/src/__tests__/hooks-blocking.test.ts +3 -3
- package/src/__tests__/hooks-config.test.ts +7 -7
- package/src/__tests__/hooks-discovery.test.ts +3 -3
- package/src/__tests__/hooks-integration.test.ts +5 -5
- package/src/__tests__/hooks-manager.test.ts +3 -3
- package/src/__tests__/hooks-runner.test.ts +5 -23
- package/src/__tests__/hooks-settings.test.ts +3 -3
- package/src/__tests__/hooks-templates.test.ts +3 -3
- package/src/__tests__/http-conversation-lineage.test.ts +0 -27
- package/src/__tests__/identity-intro-cache.test.ts +0 -4
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -22
- package/src/__tests__/inline-skill-load-permissions.test.ts +5 -16
- package/src/__tests__/intent-routing.test.ts +2 -55
- package/src/__tests__/invite-redemption-service.test.ts +0 -21
- package/src/__tests__/invite-routes-http.test.ts +0 -21
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +0 -17
- package/src/__tests__/journal-context.test.ts +8 -75
- package/src/__tests__/list-messages-attachments.test.ts +0 -22
- package/src/__tests__/llm-context-route-provider.test.ts +0 -21
- package/src/__tests__/llm-request-log-turn-query.test.ts +46 -28
- package/src/__tests__/llm-usage-store.test.ts +0 -21
- package/src/__tests__/log-export-workspace.test.ts +1 -1
- package/src/__tests__/managed-skill-lifecycle.test.ts +1 -1
- package/src/__tests__/managed-store.test.ts +1 -1
- package/src/__tests__/mcp-cli.test.ts +7 -10
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -21
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +0 -11
- package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -21
- package/src/__tests__/memory-recall-log-store.test.ts +0 -27
- package/src/__tests__/memory-recall-quality.test.ts +0 -21
- package/src/__tests__/memory-regressions.experimental.test.ts +31 -30
- package/src/__tests__/memory-regressions.test.ts +282 -70
- package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -21
- package/src/__tests__/memory-upsert-concurrency.test.ts +0 -21
- package/src/__tests__/messaging-send-tool.test.ts +201 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +18 -13
- package/src/__tests__/migration-export-http.test.ts +7 -1
- package/src/__tests__/migration-import-commit-http.test.ts +16 -14
- package/src/__tests__/migration-import-preflight-http.test.ts +27 -44
- package/src/__tests__/migration-validate-http.test.ts +1 -28
- package/src/__tests__/native-web-search.test.ts +25 -22
- package/src/__tests__/non-member-access-request.test.ts +0 -22
- package/src/__tests__/notification-guardian-path.test.ts +0 -21
- package/src/__tests__/notification-schedule-dedup.test.ts +1 -25
- package/src/__tests__/oauth-apps-routes.test.ts +103 -2
- package/src/__tests__/oauth-cli.test.ts +52 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +0 -16
- package/src/__tests__/oauth-provider-serializer.test.ts +232 -0
- package/src/__tests__/oauth-providers-routes.test.ts +257 -0
- package/src/__tests__/oauth-store.test.ts +0 -21
- package/src/__tests__/onboarding-template-contract.test.ts +2 -2
- package/src/__tests__/openai-provider.test.ts +261 -0
- package/src/__tests__/pairing-concurrent.test.ts +6 -6
- package/src/__tests__/pairing-routes.test.ts +7 -1
- package/src/__tests__/path-policy.test.ts +1 -1
- package/src/__tests__/platform.test.ts +64 -88
- package/src/__tests__/playbook-execution.test.ts +0 -21
- package/src/__tests__/playbook-tools.test.ts +0 -21
- package/src/__tests__/pricing.test.ts +100 -0
- package/src/__tests__/relay-server.test.ts +1 -25
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -24
- package/src/__tests__/runtime-events-sse-parity.test.ts +2 -24
- package/src/__tests__/runtime-events-sse.test.ts +0 -24
- package/src/__tests__/sandbox-diagnostics.test.ts +2 -1
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -1
- package/src/__tests__/schedule-store.test.ts +0 -21
- package/src/__tests__/schedule-tools.test.ts +0 -21
- package/src/__tests__/scheduler-recurrence.test.ts +0 -21
- package/src/__tests__/scoped-approval-grants.test.ts +0 -21
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -21
- package/src/__tests__/secret-allowlist.test.ts +1 -1
- package/src/__tests__/secret-ingress-channel.test.ts +0 -5
- package/src/__tests__/secret-ingress-cli.test.ts +0 -6
- package/src/__tests__/secret-ingress-http.test.ts +0 -5
- package/src/__tests__/secret-ingress.test.ts +0 -5
- package/src/__tests__/send-endpoint-busy.test.ts +0 -24
- package/src/__tests__/sequence-store.test.ts +0 -21
- package/src/__tests__/server-history-render.test.ts +0 -24
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -4
- package/src/__tests__/skill-load-inline-command.test.ts +9 -0
- package/src/__tests__/skill-load-inline-includes.test.ts +9 -0
- package/src/__tests__/skill-load-tool.test.ts +11 -0
- package/src/__tests__/skills-uninstall.test.ts +10 -8
- package/src/__tests__/skills.test.ts +1 -1
- package/src/__tests__/slack-channel-config.test.ts +1 -1
- package/src/__tests__/slack-inbound-verification.test.ts +0 -22
- package/src/__tests__/starter-bundle.test.ts +4 -1
- package/src/__tests__/suggestion-routes.test.ts +2 -0
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/test-preload.ts +31 -0
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +0 -20
- package/src/__tests__/tool-input-summary.test.ts +124 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -1
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +1 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +1 -1
- package/src/__tests__/trusted-contact-verification.test.ts +1 -1
- package/src/__tests__/turn-boundary-resolution.test.ts +1 -1
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/update-bulletin.test.ts +1 -1
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +1 -1
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -1
- package/src/__tests__/voice-session-bridge.test.ts +1 -1
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -4
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -1
- package/src/__tests__/workspace-migration-down-functions.test.ts +15 -3
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +40 -4
- package/src/agent/loop.ts +6 -9
- package/src/approvals/guardian-decision-primitive.ts +46 -18
- package/src/approvals/guardian-request-resolvers.ts +19 -2
- package/src/calls/active-call-lease.ts +2 -2
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/commands/doctor.ts +9 -9
- package/src/cli/commands/memory.ts +142 -0
- package/src/cli/commands/oauth/__tests__/connect.test.ts +13 -11
- package/src/cli/commands/oauth/__tests__/ping.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +13 -12
- package/src/cli/commands/oauth/index.ts +1 -1
- package/src/cli/commands/oauth/providers.ts +47 -62
- package/src/cli/commands/platform/__tests__/connect.test.ts +72 -46
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +54 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +36 -0
- package/src/cli/commands/platform/connect.ts +17 -7
- package/src/cli/commands/platform/disconnect.ts +28 -3
- package/src/cli/commands/platform/index.ts +3 -3
- package/src/cli.ts +1 -299
- package/src/config/assistant-feature-flags.ts +23 -15
- package/src/config/bundled-skills/app-builder/TOOLS.json +16 -0
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +4 -0
- package/src/config/bundled-skills/app-builder/tools/app-delete.ts +5 -1
- package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +9 -1
- package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +5 -1
- package/src/config/bundled-skills/contacts/TOOLS.json +8 -0
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +10 -1
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +16 -2
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +1 -0
- package/src/config/bundled-skills/messaging/SKILL.md +7 -7
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +37 -0
- package/src/config/bundled-skills/slack/SKILL.md +18 -0
- package/src/config/env-registry.ts +15 -11
- package/src/config/env.ts +1 -11
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/heartbeat.ts +6 -1
- package/src/config/schemas/inference.ts +14 -3
- package/src/config/schemas/memory-processing.ts +16 -8
- package/src/config/schemas/memory-retrieval.ts +3 -3
- package/src/config/skills.ts +1 -1
- package/src/context/window-manager.ts +174 -51
- package/src/credential-execution/executable-discovery.ts +2 -2
- package/src/daemon/approved-devices-store.ts +2 -2
- package/src/daemon/assistant-attachments.ts +2 -0
- package/src/daemon/config-watcher.ts +4 -50
- package/src/daemon/conversation-agent-loop-handlers.ts +9 -1
- package/src/daemon/conversation-agent-loop.ts +12 -0
- package/src/daemon/conversation-error.ts +3 -5
- package/src/daemon/conversation-history.ts +7 -3
- package/src/daemon/conversation-lifecycle.ts +16 -0
- package/src/daemon/conversation-messaging.ts +1 -0
- package/src/daemon/conversation-notifiers.ts +67 -30
- package/src/daemon/conversation-process.ts +161 -2
- package/src/daemon/conversation-queue-manager.ts +2 -0
- package/src/daemon/conversation-runtime-assembly.ts +33 -11
- package/src/daemon/conversation-slash.ts +14 -3
- package/src/daemon/conversation-tool-setup.ts +2 -0
- package/src/daemon/conversation-usage.ts +32 -4
- package/src/daemon/conversation.ts +33 -1
- package/src/daemon/daemon-control.ts +32 -16
- package/src/daemon/date-context.ts +47 -45
- package/src/daemon/dictation-profile-store.ts +2 -2
- package/src/daemon/handlers/conversations.ts +19 -0
- package/src/daemon/handlers/shared.ts +14 -21
- package/src/daemon/lifecycle.ts +5 -7
- package/src/daemon/message-types/conversations.ts +2 -0
- package/src/daemon/message-types/guardian-actions.ts +3 -17
- package/src/daemon/message-types/integrations.ts +11 -1
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/pairing-store.ts +2 -79
- package/src/daemon/server.ts +154 -8
- package/src/daemon/watch-handler.ts +65 -21
- package/src/email/guardrails.ts +3 -3
- package/src/heartbeat/heartbeat-service.ts +14 -7
- package/src/hooks/cli.ts +2 -2
- package/src/hooks/config.ts +2 -2
- package/src/hooks/discovery.ts +2 -2
- package/src/hooks/manager.ts +2 -2
- package/src/hooks/runner.ts +5 -2
- package/src/hooks/templates.ts +2 -2
- package/src/memory/admin.ts +181 -2
- package/src/memory/app-git-service.ts +61 -4
- package/src/memory/attachments-store.ts +2 -0
- package/src/memory/canonical-guardian-store.ts +16 -0
- package/src/memory/db-init.ts +8 -0
- package/src/memory/embedding-local.ts +5 -2
- package/src/memory/indexer.ts +44 -26
- package/src/memory/items-extractor.ts +34 -82
- package/src/memory/job-handlers/batch-extraction.ts +741 -0
- package/src/memory/job-handlers/journal-carry-forward.test.ts +383 -0
- package/src/memory/job-handlers/journal-carry-forward.ts +255 -0
- package/src/memory/jobs-store.ts +28 -0
- package/src/memory/jobs-worker.ts +56 -9
- package/src/memory/lifecycle-events-store.ts +4 -2
- package/src/memory/llm-request-log-store.ts +40 -2
- package/src/memory/llm-usage-store.ts +4 -3
- package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +71 -0
- package/src/memory/migrations/200-usage-llm-call-count.ts +20 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/query-expansion.ts +83 -0
- package/src/memory/retriever.test.ts +119 -0
- package/src/memory/retriever.ts +513 -105
- package/src/memory/schema/guardian.ts +4 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/search/formatting.test.ts +140 -0
- package/src/memory/search/formatting.ts +143 -198
- package/src/memory/search/mmr.ts +136 -0
- package/src/memory/search/staleness.ts +0 -15
- package/src/memory/search/tier-classifier.ts +10 -21
- package/src/memory/search/types.ts +17 -0
- package/src/messaging/providers/slack/adapter.ts +51 -5
- package/src/notifications/broadcaster.ts +13 -0
- package/src/notifications/copy-composer.ts +8 -0
- package/src/oauth/connect-orchestrator.ts +1 -1
- package/src/oauth/connection-resolver.ts +2 -2
- package/src/oauth/provider-serializer.ts +116 -0
- package/src/permissions/trust-store.ts +24 -7
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +5 -0
- package/src/prompts/journal-context.ts +50 -35
- package/src/prompts/persona-resolver.ts +1 -1
- package/src/prompts/system-prompt.ts +27 -28
- package/src/prompts/templates/BOOTSTRAP.md +14 -1
- package/src/prompts/templates/HEARTBEAT.md +10 -0
- package/src/prompts/templates/NOW.md +19 -25
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/prompts/templates/UPDATES.md +12 -0
- package/src/prompts/update-bulletin.ts +1 -1
- package/src/providers/anthropic/client.ts +89 -18
- package/src/providers/model-catalog.ts +22 -2
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/client.ts +40 -1
- package/src/providers/retry.ts +23 -4
- package/src/providers/types.ts +2 -0
- package/src/runtime/assistant-scope.ts +1 -1
- package/src/runtime/auth/__tests__/credential-service.test.ts +1 -0
- package/src/runtime/auth/route-policy.ts +1 -0
- package/src/runtime/auth/token-service.ts +51 -29
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -1
- package/src/runtime/guardian-decision-types.ts +16 -10
- package/src/runtime/http-server.ts +3 -14
- package/src/runtime/http-types.ts +1 -0
- package/src/runtime/migrations/vbundle-builder.ts +7 -4
- package/src/runtime/migrations/vbundle-import-analyzer.ts +0 -4
- package/src/runtime/migrations/vbundle-importer.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +40 -8
- package/src/runtime/routes/conversation-routes.ts +125 -3
- package/src/runtime/routes/guardian-action-routes.ts +9 -3
- package/src/runtime/routes/identity-routes.ts +25 -4
- package/src/runtime/routes/llm-context-normalization.ts +1 -0
- package/src/runtime/routes/log-export-routes.ts +34 -12
- package/src/runtime/routes/migration-routes.ts +6 -10
- package/src/runtime/routes/oauth-apps.ts +2 -9
- package/src/runtime/routes/oauth-providers.ts +60 -0
- package/src/runtime/routes/pairing-routes.ts +0 -8
- package/src/runtime/routes/settings-routes.ts +0 -1
- package/src/runtime/routes/telemetry-routes.ts +16 -4
- package/src/security/encrypted-store.ts +2 -2
- package/src/security/secret-allowlist.ts +3 -3
- package/src/signals/emit-event.ts +42 -0
- package/src/signals/user-message.ts +37 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +83 -19
- package/src/telemetry/usage-telemetry-reporter.ts +23 -17
- package/src/tools/browser/runtime-check.ts +2 -2
- package/src/tools/credentials/vault.ts +2 -249
- package/src/tools/memory/definitions.ts +1 -1
- package/src/tools/memory/handlers.test.ts +50 -8
- package/src/tools/memory/handlers.ts +3 -1
- package/src/tools/side-effects.ts +1 -6
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +11 -14
- package/src/tools/tool-approval-handler.ts +20 -1
- package/src/tools/tool-input-summary.ts +66 -0
- package/src/tools/types.ts +4 -0
- package/src/usage/types.ts +4 -0
- package/src/util/device-id.ts +10 -10
- package/src/util/platform.ts +71 -33
- package/src/util/pricing.ts +19 -6
- package/src/util/strip-comment-lines.ts +28 -0
- package/src/workspace/git-service.ts +8 -18
- package/src/workspace/migrations/003-seed-device-id.ts +6 -4
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +7 -1
- package/src/workspace/migrations/017-seed-persona-dirs.ts +2 -4
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +84 -0
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +94 -0
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +86 -0
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +126 -0
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +3 -6
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/signals/confirm.ts +0 -82
- package/src/signals/trust-rule.ts +0 -174
package/src/daemon/server.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
|
|
4
4
|
import {
|
|
@@ -48,11 +48,13 @@ import { getSigningKeyFingerprint } from "../runtime/auth/token-service.js";
|
|
|
48
48
|
import { bridgeConfirmationRequestToGuardian } from "../runtime/confirmation-request-guardian-bridge.js";
|
|
49
49
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
50
50
|
import { checkIngressForSecrets } from "../security/secret-ingress.js";
|
|
51
|
+
import { redactSecrets } from "../security/secret-scanner.js";
|
|
51
52
|
import { registerCancelCallback } from "../signals/cancel.js";
|
|
52
53
|
import { registerConversationUndoCallback } from "../signals/conversation-undo.js";
|
|
53
54
|
import { appendEventToStream } from "../signals/event-stream.js";
|
|
54
55
|
import { registerUserMessageCallback } from "../signals/user-message.js";
|
|
55
56
|
import { getSubagentManager } from "../subagent/index.js";
|
|
57
|
+
import { summarizeToolInput } from "../tools/tool-input-summary.js";
|
|
56
58
|
import { getLogger } from "../util/logger.js";
|
|
57
59
|
import {
|
|
58
60
|
getSandboxWorkingDir,
|
|
@@ -66,6 +68,7 @@ import {
|
|
|
66
68
|
DEFAULT_MEMORY_POLICY,
|
|
67
69
|
} from "./conversation.js";
|
|
68
70
|
import { ConversationEvictor } from "./conversation-evictor.js";
|
|
71
|
+
import { formatCompactResult } from "./conversation-process.js";
|
|
69
72
|
import { resolveChannelCapabilities } from "./conversation-runtime-assembly.js";
|
|
70
73
|
import { resolveSlash, type SlashContext } from "./conversation-slash.js";
|
|
71
74
|
import { undoLastMessage } from "./handlers/conversations.js";
|
|
@@ -78,7 +81,10 @@ import type { SkillOperationContext } from "./handlers/skills.js";
|
|
|
78
81
|
import { HostBashProxy } from "./host-bash-proxy.js";
|
|
79
82
|
import { HostCuProxy } from "./host-cu-proxy.js";
|
|
80
83
|
import { HostFileProxy } from "./host-file-proxy.js";
|
|
81
|
-
import type {
|
|
84
|
+
import type {
|
|
85
|
+
ServerMessage,
|
|
86
|
+
UserMessageAttachment,
|
|
87
|
+
} from "./message-protocol.js";
|
|
82
88
|
|
|
83
89
|
const log = getLogger("server");
|
|
84
90
|
|
|
@@ -175,6 +181,14 @@ function makePendingInteractionRegistrar(
|
|
|
175
181
|
try {
|
|
176
182
|
const trustContext = conversation.trustContext;
|
|
177
183
|
const sourceChannel = trustContext?.sourceChannel ?? "vellum";
|
|
184
|
+
const inputRecord = msg.input as Record<string, unknown>;
|
|
185
|
+
const activityRaw =
|
|
186
|
+
(typeof inputRecord.activity === "string"
|
|
187
|
+
? inputRecord.activity
|
|
188
|
+
: undefined) ??
|
|
189
|
+
(typeof inputRecord.reason === "string"
|
|
190
|
+
? inputRecord.reason
|
|
191
|
+
: undefined);
|
|
178
192
|
const canonicalRequest = createCanonicalGuardianRequest({
|
|
179
193
|
id: msg.requestId,
|
|
180
194
|
kind: "tool_approval",
|
|
@@ -186,6 +200,15 @@ function makePendingInteractionRegistrar(
|
|
|
186
200
|
guardianExternalUserId: trustContext?.guardianExternalUserId,
|
|
187
201
|
guardianPrincipalId: trustContext?.guardianPrincipalId ?? undefined,
|
|
188
202
|
toolName: msg.toolName,
|
|
203
|
+
commandPreview:
|
|
204
|
+
redactSecrets(
|
|
205
|
+
summarizeToolInput(msg.toolName, inputRecord),
|
|
206
|
+
) || undefined,
|
|
207
|
+
riskLevel: msg.riskLevel,
|
|
208
|
+
activityText: activityRaw
|
|
209
|
+
? redactSecrets(activityRaw)
|
|
210
|
+
: undefined,
|
|
211
|
+
executionTarget: msg.executionTarget,
|
|
189
212
|
status: "pending",
|
|
190
213
|
requestCode: generateCanonicalRequestCode(),
|
|
191
214
|
expiresAt: Date.now() + 5 * 60 * 1000,
|
|
@@ -545,14 +568,68 @@ export class DaemonServer {
|
|
|
545
568
|
params.conversationKey,
|
|
546
569
|
);
|
|
547
570
|
const conversation = await this.getOrCreateConversation(conversationId);
|
|
571
|
+
|
|
572
|
+
// Register file-backed attachments so they flow through the send
|
|
573
|
+
// pipeline as images the LLM can see directly.
|
|
574
|
+
const attachmentIds: string[] = [];
|
|
575
|
+
const resolvedAttachments: UserMessageAttachment[] = [];
|
|
576
|
+
if (params.attachments && params.attachments.length > 0) {
|
|
577
|
+
for (const a of params.attachments) {
|
|
578
|
+
try {
|
|
579
|
+
const size = statSync(a.path).size;
|
|
580
|
+
const stored = attachmentsStore.uploadFileBackedAttachment(
|
|
581
|
+
a.filename,
|
|
582
|
+
a.mimeType,
|
|
583
|
+
a.path,
|
|
584
|
+
size,
|
|
585
|
+
);
|
|
586
|
+
attachmentIds.push(stored.id);
|
|
587
|
+
const fileData = readFileSync(a.path).toString("base64");
|
|
588
|
+
resolvedAttachments.push({
|
|
589
|
+
id: stored.id,
|
|
590
|
+
filename: a.filename,
|
|
591
|
+
mimeType: a.mimeType,
|
|
592
|
+
data: fileData,
|
|
593
|
+
filePath: a.path,
|
|
594
|
+
});
|
|
595
|
+
} catch (err) {
|
|
596
|
+
log.warn(
|
|
597
|
+
{ err, path: a.path },
|
|
598
|
+
"Failed to register signal attachment",
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Build a hub-publishing sender so events reach SSE clients.
|
|
605
|
+
const hubSender = (msg: ServerMessage) => {
|
|
606
|
+
const msgConversationId =
|
|
607
|
+
"conversationId" in msg &&
|
|
608
|
+
typeof (msg as { conversationId?: unknown }).conversationId ===
|
|
609
|
+
"string"
|
|
610
|
+
? (msg as { conversationId: string }).conversationId
|
|
611
|
+
: undefined;
|
|
612
|
+
const event = buildAssistantEvent(
|
|
613
|
+
DAEMON_INTERNAL_ASSISTANT_ID,
|
|
614
|
+
msg,
|
|
615
|
+
msgConversationId ?? conversationId,
|
|
616
|
+
);
|
|
617
|
+
assistantEventHub.publish(event).catch((err) => {
|
|
618
|
+
log.warn(
|
|
619
|
+
{ err },
|
|
620
|
+
"assistant-events hub subscriber threw during signal user-message",
|
|
621
|
+
);
|
|
622
|
+
});
|
|
623
|
+
};
|
|
624
|
+
|
|
548
625
|
if (conversation.isProcessing()) {
|
|
549
626
|
const requestId = crypto.randomUUID();
|
|
550
627
|
const resolvedChannel = resolveTurnChannel(params.sourceChannel);
|
|
551
628
|
const resolvedInterface = resolveTurnInterface(params.sourceInterface);
|
|
552
629
|
const result = conversation.enqueueMessage(
|
|
553
630
|
params.content,
|
|
554
|
-
|
|
555
|
-
|
|
631
|
+
resolvedAttachments,
|
|
632
|
+
hubSender,
|
|
556
633
|
requestId,
|
|
557
634
|
undefined,
|
|
558
635
|
undefined,
|
|
@@ -568,8 +645,8 @@ export class DaemonServer {
|
|
|
568
645
|
await this.persistAndProcessMessage(
|
|
569
646
|
conversationId,
|
|
570
647
|
params.content,
|
|
571
|
-
undefined,
|
|
572
|
-
|
|
648
|
+
attachmentIds.length > 0 ? attachmentIds : undefined,
|
|
649
|
+
{ onEvent: hubSender },
|
|
573
650
|
params.sourceChannel,
|
|
574
651
|
params.sourceInterface,
|
|
575
652
|
);
|
|
@@ -773,6 +850,7 @@ export class DaemonServer {
|
|
|
773
850
|
(msg) => this.broadcast(msg),
|
|
774
851
|
memoryPolicy,
|
|
775
852
|
sharedCesClient,
|
|
853
|
+
storedOptions?.speed,
|
|
776
854
|
);
|
|
777
855
|
newConversation.updateClient(sendToClient, true);
|
|
778
856
|
await newConversation.loadFromDb();
|
|
@@ -885,9 +963,29 @@ export class DaemonServer {
|
|
|
885
963
|
conversation.setAssistantId(
|
|
886
964
|
options?.assistantId ?? DAEMON_INTERNAL_ASSISTANT_ID,
|
|
887
965
|
);
|
|
888
|
-
|
|
889
|
-
|
|
966
|
+
// Only overwrite trust/auth context when explicitly provided. Callers that
|
|
967
|
+
// don't supply a trust context (e.g. signal-injected messages) should
|
|
968
|
+
// inherit whatever the conversation already has from a prior session.
|
|
969
|
+
if (options?.trustContext !== undefined) {
|
|
970
|
+
conversation.setTrustContext(options.trustContext);
|
|
971
|
+
}
|
|
972
|
+
if (options?.authContext !== undefined) {
|
|
973
|
+
conversation.setAuthContext(options.authContext);
|
|
974
|
+
}
|
|
890
975
|
await conversation.ensureActorScopedHistory();
|
|
976
|
+
|
|
977
|
+
// Persist the conversation's current trust/auth context so it survives
|
|
978
|
+
// eviction and recreation. The restore path in getOrCreateConversation
|
|
979
|
+
// reads from storedOptions.trustContext / storedOptions.authContext.
|
|
980
|
+
const currentTrust = conversation.trustContext;
|
|
981
|
+
const currentAuth = conversation.authContext;
|
|
982
|
+
if (currentTrust || currentAuth) {
|
|
983
|
+
this.conversationOptions.set(conversationId, {
|
|
984
|
+
...this.conversationOptions.get(conversationId),
|
|
985
|
+
...(currentTrust ? { trustContext: currentTrust } : {}),
|
|
986
|
+
...(currentAuth ? { authContext: currentAuth } : {}),
|
|
987
|
+
});
|
|
988
|
+
}
|
|
891
989
|
conversation.setChannelCapabilities(
|
|
892
990
|
resolveChannelCapabilities(
|
|
893
991
|
sourceChannel,
|
|
@@ -1155,6 +1253,54 @@ export class DaemonServer {
|
|
|
1155
1253
|
return { messageId: persisted.id };
|
|
1156
1254
|
}
|
|
1157
1255
|
|
|
1256
|
+
if (slashResult.kind === "compact") {
|
|
1257
|
+
const serverTurnCtx = conversation.getTurnChannelContext();
|
|
1258
|
+
const serverProvenance = provenanceFromTrustContext(
|
|
1259
|
+
conversation.trustContext,
|
|
1260
|
+
);
|
|
1261
|
+
const compactChannelMeta = {
|
|
1262
|
+
...serverProvenance,
|
|
1263
|
+
...(serverTurnCtx
|
|
1264
|
+
? {
|
|
1265
|
+
userMessageChannel: serverTurnCtx.userMessageChannel,
|
|
1266
|
+
assistantMessageChannel: serverTurnCtx.assistantMessageChannel,
|
|
1267
|
+
}
|
|
1268
|
+
: {}),
|
|
1269
|
+
...(serverInterfaceCtx
|
|
1270
|
+
? {
|
|
1271
|
+
userMessageInterface: serverInterfaceCtx.userMessageInterface,
|
|
1272
|
+
assistantMessageInterface:
|
|
1273
|
+
serverInterfaceCtx.assistantMessageInterface,
|
|
1274
|
+
}
|
|
1275
|
+
: {}),
|
|
1276
|
+
};
|
|
1277
|
+
const cleanMsg = createUserMessage(content, attachments);
|
|
1278
|
+
const persisted = await addMessage(
|
|
1279
|
+
conversationId,
|
|
1280
|
+
"user",
|
|
1281
|
+
JSON.stringify(cleanMsg.content),
|
|
1282
|
+
compactChannelMeta,
|
|
1283
|
+
);
|
|
1284
|
+
conversation.getMessages().push(cleanMsg);
|
|
1285
|
+
|
|
1286
|
+
conversation.emitActivityState(
|
|
1287
|
+
"thinking",
|
|
1288
|
+
"context_compacting",
|
|
1289
|
+
"assistant_turn",
|
|
1290
|
+
);
|
|
1291
|
+
const result = await conversation.forceCompact();
|
|
1292
|
+
const responseText = formatCompactResult(result);
|
|
1293
|
+
const assistantMsg = createAssistantMessage(responseText);
|
|
1294
|
+
await addMessage(
|
|
1295
|
+
conversationId,
|
|
1296
|
+
"assistant",
|
|
1297
|
+
JSON.stringify(assistantMsg.content),
|
|
1298
|
+
compactChannelMeta,
|
|
1299
|
+
);
|
|
1300
|
+
conversation.getMessages().push(assistantMsg);
|
|
1301
|
+
return { messageId: persisted.id };
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1158
1304
|
const resolvedContent = slashResult.content;
|
|
1159
1305
|
|
|
1160
1306
|
const requestId = crypto.randomUUID();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { recordRequestLog } from "../memory/llm-request-log-store.js";
|
|
1
2
|
import {
|
|
2
3
|
extractText,
|
|
3
4
|
getConfiguredProvider,
|
|
@@ -20,11 +21,16 @@ import type { WatchObservation } from "./message-protocol.js";
|
|
|
20
21
|
const log = getLogger("watch-handler");
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
|
-
* Module-level maps to store commentary/summary text
|
|
24
|
-
* notifier callbacks can retrieve
|
|
24
|
+
* Module-level maps to store commentary/summary text (and associated LLM log
|
|
25
|
+
* IDs) so that session notifier callbacks can retrieve them from the
|
|
26
|
+
* WatchSession's conversationId and link logs to the persisted message.
|
|
25
27
|
*/
|
|
26
|
-
export
|
|
27
|
-
|
|
28
|
+
export interface WatchResult {
|
|
29
|
+
text: string;
|
|
30
|
+
logIds: string[];
|
|
31
|
+
}
|
|
32
|
+
export const lastCommentaryByConversation = new Map<string, WatchResult>();
|
|
33
|
+
export const lastSummaryByConversation = new Map<string, WatchResult>();
|
|
28
34
|
|
|
29
35
|
export async function handleWatchObservation(
|
|
30
36
|
msg: WatchObservation,
|
|
@@ -116,15 +122,15 @@ async function generateCommentary(session: WatchSession): Promise<void> {
|
|
|
116
122
|
return;
|
|
117
123
|
}
|
|
118
124
|
const lastThree = session.observations.slice(-3);
|
|
119
|
-
const
|
|
125
|
+
const previousResult = lastCommentaryByConversation.get(
|
|
120
126
|
session.conversationId,
|
|
121
127
|
);
|
|
122
128
|
|
|
123
129
|
const userContent = [
|
|
124
130
|
`Focus area: ${session.focusArea}`,
|
|
125
131
|
"",
|
|
126
|
-
|
|
127
|
-
? `Previous commentary: "${
|
|
132
|
+
previousResult
|
|
133
|
+
? `Previous commentary: "${previousResult.text}"`
|
|
128
134
|
: "No previous commentary yet.",
|
|
129
135
|
"",
|
|
130
136
|
...lastThree.map(
|
|
@@ -164,10 +170,29 @@ async function generateCommentary(session: WatchSession): Promise<void> {
|
|
|
164
170
|
},
|
|
165
171
|
);
|
|
166
172
|
|
|
173
|
+
const logIds: string[] = [];
|
|
174
|
+
if (response.rawRequest && response.rawResponse) {
|
|
175
|
+
try {
|
|
176
|
+
const logId = recordRequestLog(
|
|
177
|
+
session.conversationId,
|
|
178
|
+
JSON.stringify(response.rawRequest),
|
|
179
|
+
JSON.stringify(response.rawResponse),
|
|
180
|
+
undefined,
|
|
181
|
+
response.actualProvider ?? provider.name,
|
|
182
|
+
);
|
|
183
|
+
logIds.push(logId);
|
|
184
|
+
} catch (err) {
|
|
185
|
+
log.warn({ err }, "Failed to persist watch commentary LLM log");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
167
189
|
const commentaryText = extractText(response);
|
|
168
190
|
|
|
169
191
|
if (commentaryText && commentaryText !== "SKIP") {
|
|
170
|
-
lastCommentaryByConversation.set(session.conversationId,
|
|
192
|
+
lastCommentaryByConversation.set(session.conversationId, {
|
|
193
|
+
text: commentaryText,
|
|
194
|
+
logIds,
|
|
195
|
+
});
|
|
171
196
|
fireWatchCommentaryNotifier(session.conversationId, session);
|
|
172
197
|
session.commentaryCount++;
|
|
173
198
|
}
|
|
@@ -206,10 +231,10 @@ export async function generateSummary(session: WatchSession): Promise<void> {
|
|
|
206
231
|
{ watchId: session.watchId },
|
|
207
232
|
"Configured provider unavailable for summary generation",
|
|
208
233
|
);
|
|
209
|
-
lastSummaryByConversation.set(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
);
|
|
234
|
+
lastSummaryByConversation.set(session.conversationId, {
|
|
235
|
+
text: "[error] Configured provider unavailable. Check your settings.",
|
|
236
|
+
logIds: [],
|
|
237
|
+
});
|
|
213
238
|
fireWatchCompletionNotifier(session.conversationId, session);
|
|
214
239
|
return;
|
|
215
240
|
}
|
|
@@ -310,6 +335,22 @@ export async function generateSummary(session: WatchSession): Promise<void> {
|
|
|
310
335
|
},
|
|
311
336
|
);
|
|
312
337
|
|
|
338
|
+
const logIds: string[] = [];
|
|
339
|
+
if (response.rawRequest && response.rawResponse) {
|
|
340
|
+
try {
|
|
341
|
+
const logId = recordRequestLog(
|
|
342
|
+
session.conversationId,
|
|
343
|
+
JSON.stringify(response.rawRequest),
|
|
344
|
+
JSON.stringify(response.rawResponse),
|
|
345
|
+
undefined,
|
|
346
|
+
response.actualProvider ?? provider.name,
|
|
347
|
+
);
|
|
348
|
+
logIds.push(logId);
|
|
349
|
+
} catch (err) {
|
|
350
|
+
log.warn({ err }, "Failed to persist watch summary LLM log");
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
313
354
|
log.debug(
|
|
314
355
|
{ watchId: session.watchId },
|
|
315
356
|
"LLM API call completed successfully",
|
|
@@ -323,7 +364,10 @@ export async function generateSummary(session: WatchSession): Promise<void> {
|
|
|
323
364
|
);
|
|
324
365
|
|
|
325
366
|
if (summaryText) {
|
|
326
|
-
lastSummaryByConversation.set(session.conversationId,
|
|
367
|
+
lastSummaryByConversation.set(session.conversationId, {
|
|
368
|
+
text: summaryText,
|
|
369
|
+
logIds,
|
|
370
|
+
});
|
|
327
371
|
log.debug(
|
|
328
372
|
{ watchId: session.watchId, conversationId: session.conversationId },
|
|
329
373
|
"Firing completion notifier with summary",
|
|
@@ -334,10 +378,10 @@ export async function generateSummary(session: WatchSession): Promise<void> {
|
|
|
334
378
|
{ watchId: session.watchId },
|
|
335
379
|
"Summary was empty from API response",
|
|
336
380
|
);
|
|
337
|
-
lastSummaryByConversation.set(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
);
|
|
381
|
+
lastSummaryByConversation.set(session.conversationId, {
|
|
382
|
+
text: "[error] The API returned an empty summary. This may indicate a service issue.",
|
|
383
|
+
logIds,
|
|
384
|
+
});
|
|
341
385
|
fireWatchCompletionNotifier(session.conversationId, session);
|
|
342
386
|
}
|
|
343
387
|
} catch (err) {
|
|
@@ -346,10 +390,10 @@ export async function generateSummary(session: WatchSession): Promise<void> {
|
|
|
346
390
|
"Error generating watch summary — LLM API call failed",
|
|
347
391
|
);
|
|
348
392
|
const message = err instanceof Error ? err.message : String(err);
|
|
349
|
-
lastSummaryByConversation.set(
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
);
|
|
393
|
+
lastSummaryByConversation.set(session.conversationId, {
|
|
394
|
+
text: `[error] Summary generation failed: ${message}`,
|
|
395
|
+
logIds: [],
|
|
396
|
+
});
|
|
353
397
|
fireWatchCompletionNotifier(session.conversationId, session);
|
|
354
398
|
}
|
|
355
399
|
}
|
package/src/email/guardrails.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { join } from "node:path";
|
|
|
8
8
|
|
|
9
9
|
import { minimatch } from "minimatch";
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { getWorkspaceDir } from "../util/platform.js";
|
|
12
12
|
|
|
13
13
|
export interface AddressRule {
|
|
14
14
|
id: string;
|
|
@@ -36,7 +36,7 @@ const DEFAULT_STATE: GuardrailsState = {
|
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
function getGuardrailsPath(): string {
|
|
39
|
-
return join(
|
|
39
|
+
return join(getWorkspaceDir(), "email-guardrails.json");
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
function loadState(): GuardrailsState {
|
|
@@ -59,7 +59,7 @@ function loadState(): GuardrailsState {
|
|
|
59
59
|
|
|
60
60
|
function saveState(state: GuardrailsState): void {
|
|
61
61
|
const path = getGuardrailsPath();
|
|
62
|
-
const dir =
|
|
62
|
+
const dir = getWorkspaceDir();
|
|
63
63
|
if (!existsSync(dir)) {
|
|
64
64
|
mkdirSync(dir, { recursive: true });
|
|
65
65
|
}
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import { getConfig } from "../config/loader.js";
|
|
2
|
+
import type { Speed } from "../config/schemas/inference.js";
|
|
2
3
|
import type { HeartbeatAlert } from "../daemon/message-protocol.js";
|
|
3
4
|
import { bootstrapConversation } from "../memory/conversation-bootstrap.js";
|
|
4
5
|
import { readTextFileSync } from "../util/fs.js";
|
|
5
6
|
import { getLogger } from "../util/logger.js";
|
|
6
7
|
import { getWorkspacePromptPath } from "../util/platform.js";
|
|
8
|
+
import { stripCommentLines } from "../util/strip-comment-lines.js";
|
|
7
9
|
|
|
8
10
|
const log = getLogger("heartbeat-check");
|
|
9
11
|
|
|
10
|
-
const DEFAULT_CHECKLIST = `- Check
|
|
11
|
-
-
|
|
12
|
-
-
|
|
12
|
+
const DEFAULT_CHECKLIST = `- Check in with yourself. Read NOW.md. Is it still accurate? Update it if anything has changed.
|
|
13
|
+
- Think about your user. Is there anything from recent conversations you should follow up on? Anything you noticed that you should bring up?
|
|
14
|
+
- Check if there's anything on the horizon — events, deadlines, things they mentioned wanting to do.
|
|
15
|
+
- If you have a thought worth sharing, send it. A follow-up, a useful find, a check-in. Not every beat, but when it feels right.`;
|
|
13
16
|
|
|
14
17
|
export interface HeartbeatDeps {
|
|
15
18
|
processMessage: (
|
|
16
19
|
conversationId: string,
|
|
17
20
|
content: string,
|
|
21
|
+
options?: { speed?: Speed },
|
|
18
22
|
) => Promise<{ messageId: string }>;
|
|
19
23
|
alerter: (alert: HeartbeatAlert) => void;
|
|
20
24
|
onConversationCreated?: (info: {
|
|
@@ -167,6 +171,7 @@ export class HeartbeatService {
|
|
|
167
171
|
log.info("Running heartbeat");
|
|
168
172
|
|
|
169
173
|
try {
|
|
174
|
+
const config = getConfig().heartbeat;
|
|
170
175
|
const checklist = this.readChecklist();
|
|
171
176
|
const prompt = this.buildPrompt(checklist);
|
|
172
177
|
|
|
@@ -182,7 +187,9 @@ export class HeartbeatService {
|
|
|
182
187
|
title: "Heartbeat",
|
|
183
188
|
});
|
|
184
189
|
|
|
185
|
-
await this.deps.processMessage(conversation.id, prompt
|
|
190
|
+
await this.deps.processMessage(conversation.id, prompt, {
|
|
191
|
+
speed: config.speed,
|
|
192
|
+
});
|
|
186
193
|
log.info({ conversationId: conversation.id }, "Heartbeat completed");
|
|
187
194
|
} catch (err) {
|
|
188
195
|
log.error({ err }, "Heartbeat failed");
|
|
@@ -199,10 +206,10 @@ export class HeartbeatService {
|
|
|
199
206
|
}
|
|
200
207
|
|
|
201
208
|
private readChecklist(): string {
|
|
202
|
-
|
|
209
|
+
const raw =
|
|
203
210
|
readTextFileSync(getWorkspacePromptPath("HEARTBEAT.md")) ??
|
|
204
|
-
DEFAULT_CHECKLIST
|
|
205
|
-
);
|
|
211
|
+
DEFAULT_CHECKLIST;
|
|
212
|
+
return stripCommentLines(raw);
|
|
206
213
|
}
|
|
207
214
|
|
|
208
215
|
/** @internal Exposed for testing. */
|
package/src/hooks/cli.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Command } from "commander";
|
|
|
5
5
|
|
|
6
6
|
import { pathExists } from "../util/fs.js";
|
|
7
7
|
import { getCliLogger } from "../util/logger.js";
|
|
8
|
-
import {
|
|
8
|
+
import { getWorkspaceHooksDir } from "../util/platform.js";
|
|
9
9
|
import { ensureHookInConfig, removeHook, setHookEnabled } from "./config.js";
|
|
10
10
|
import { discoverHooks, isValidInstallManifest } from "./discovery.js";
|
|
11
11
|
|
|
@@ -171,7 +171,7 @@ Examples:
|
|
|
171
171
|
process.exit(1);
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
const hooksDir =
|
|
174
|
+
const hooksDir = getWorkspaceHooksDir();
|
|
175
175
|
const resolvedHooksDir = resolve(hooksDir);
|
|
176
176
|
const targetDir = resolve(join(hooksDir, manifest.name));
|
|
177
177
|
if (!targetDir.startsWith(resolvedHooksDir + sep)) {
|
package/src/hooks/config.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { dirname, join } from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import { ensureDir, readTextFileSync } from "../util/fs.js";
|
|
5
5
|
import { getLogger } from "../util/logger.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getWorkspaceHooksDir } from "../util/platform.js";
|
|
7
7
|
import type { HookConfig, HookConfigEntry, HookManifest } from "./types.js";
|
|
8
8
|
|
|
9
9
|
const log = getLogger("hooks-config");
|
|
@@ -11,7 +11,7 @@ const log = getLogger("hooks-config");
|
|
|
11
11
|
const HOOKS_CONFIG_VERSION = 1;
|
|
12
12
|
|
|
13
13
|
function getConfigPath(): string {
|
|
14
|
-
return join(
|
|
14
|
+
return join(getWorkspaceHooksDir(), "config.json");
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function loadHooksConfig(): HookConfig {
|
package/src/hooks/discovery.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { join, relative, resolve } from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import { pathExists } from "../util/fs.js";
|
|
5
5
|
import { getLogger } from "../util/logger.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getWorkspaceHooksDir } from "../util/platform.js";
|
|
7
7
|
import { loadHooksConfig } from "./config.js";
|
|
8
8
|
import type { DiscoveredHook, HookManifest } from "./types.js";
|
|
9
9
|
|
|
@@ -64,7 +64,7 @@ export function isValidInstallManifest(
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
export function discoverHooks(hooksDir?: string): DiscoveredHook[] {
|
|
67
|
-
const dir = hooksDir ??
|
|
67
|
+
const dir = hooksDir ?? getWorkspaceHooksDir();
|
|
68
68
|
if (!pathExists(dir)) return [];
|
|
69
69
|
|
|
70
70
|
const config = loadHooksConfig();
|
package/src/hooks/manager.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { getIsContainerized } from "../config/env-registry.js";
|
|
|
4
4
|
import { Debouncer } from "../util/debounce.js";
|
|
5
5
|
import { pathExists } from "../util/fs.js";
|
|
6
6
|
import { getLogger } from "../util/logger.js";
|
|
7
|
-
import {
|
|
7
|
+
import { getWorkspaceHooksDir } from "../util/platform.js";
|
|
8
8
|
import { discoverHooks } from "./discovery.js";
|
|
9
9
|
import { runHookScript } from "./runner.js";
|
|
10
10
|
import type {
|
|
@@ -121,7 +121,7 @@ export class HookManager {
|
|
|
121
121
|
|
|
122
122
|
watch(): void {
|
|
123
123
|
if (getIsContainerized()) return;
|
|
124
|
-
const hooksDir =
|
|
124
|
+
const hooksDir = getWorkspaceHooksDir();
|
|
125
125
|
if (!pathExists(hooksDir)) return;
|
|
126
126
|
|
|
127
127
|
this.stopWatching();
|
package/src/hooks/runner.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { homedir } from "node:os";
|
|
|
3
3
|
import { basename, extname, join } from "node:path";
|
|
4
4
|
|
|
5
5
|
import { pathExists } from "../util/fs.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getWorkspaceDir } from "../util/platform.js";
|
|
7
7
|
import { getHookSettings } from "./config.js";
|
|
8
8
|
import type { DiscoveredHook, HookEventData } from "./types.js";
|
|
9
9
|
|
|
@@ -69,7 +69,10 @@ export async function runHookScript(
|
|
|
69
69
|
...process.env,
|
|
70
70
|
VELLUM_HOOK_EVENT: eventData.event,
|
|
71
71
|
VELLUM_HOOK_NAME: hook.name,
|
|
72
|
-
VELLUM_ROOT_DIR
|
|
72
|
+
// @deprecated — usage of VELLUM_ROOT_DIR by hook scripts is deprecated.
|
|
73
|
+
// Removing this requires an LLM-based migration or declarative migration
|
|
74
|
+
// file to update existing user-authored hooks to use VELLUM_WORKSPACE_DIR.
|
|
75
|
+
VELLUM_ROOT_DIR: join(homedir(), ".vellum"),
|
|
73
76
|
VELLUM_WORKSPACE_DIR: getWorkspaceDir(),
|
|
74
77
|
VELLUM_HOOK_SETTINGS: JSON.stringify(
|
|
75
78
|
getHookSettings(hook.name, hook.manifest),
|
package/src/hooks/templates.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { join } from "node:path";
|
|
|
11
11
|
import { resolveBundledDir } from "../util/bundled-asset.js";
|
|
12
12
|
import { pathExists } from "../util/fs.js";
|
|
13
13
|
import { getLogger } from "../util/logger.js";
|
|
14
|
-
import {
|
|
14
|
+
import { getWorkspaceHooksDir } from "../util/platform.js";
|
|
15
15
|
import { ensureHookInConfig } from "./config.js";
|
|
16
16
|
|
|
17
17
|
const log = getLogger("hooks-templates");
|
|
@@ -30,7 +30,7 @@ export function installTemplates(): void {
|
|
|
30
30
|
);
|
|
31
31
|
if (!pathExists(templatesDir)) return;
|
|
32
32
|
|
|
33
|
-
const hooksDir =
|
|
33
|
+
const hooksDir = getWorkspaceHooksDir();
|
|
34
34
|
const entries = readdirSync(templatesDir, {
|
|
35
35
|
withFileTypes: true,
|
|
36
36
|
}) as Dirent[];
|