@vellumai/assistant 0.6.3 → 0.6.4
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 +273 -10
- package/Dockerfile +2 -3
- package/bun.lock +5 -13
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/stt-provider-onboarding.md +120 -0
- package/knip.json +12 -2
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +3 -3
- package/openapi.yaml +982 -72
- package/package.json +4 -6
- package/scripts/generate-openapi.ts +0 -1
- package/scripts/test.sh +73 -18
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop.test.ts +123 -0
- package/src/__tests__/anthropic-provider.test.ts +263 -10
- package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
- package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
- package/src/__tests__/browser-fill-credential.test.ts +11 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/browser-skill-endstate.test.ts +31 -7
- package/src/__tests__/btw-routes.test.ts +7 -0
- package/src/__tests__/call-controller.test.ts +581 -20
- package/src/__tests__/catalog-files.test.ts +138 -0
- package/src/__tests__/channel-invite-transport.test.ts +2 -2
- package/src/__tests__/channel-readiness-routes.test.ts +16 -20
- package/src/__tests__/channel-readiness-service.test.ts +12 -7
- package/src/__tests__/checker.test.ts +157 -10
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/config-analysis.test.ts +100 -0
- package/src/__tests__/config-schema.test.ts +1013 -66
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +43 -8
- package/src/__tests__/contact-store-user-file.test.ts +512 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-window-manager.test.ts +88 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +98 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +135 -0
- package/src/__tests__/conversation-error.test.ts +70 -0
- package/src/__tests__/conversation-history-web-search.test.ts +11 -4
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +901 -60
- package/src/__tests__/conversation-routes-disk-view.test.ts +270 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +55 -0
- package/src/__tests__/conversation-skill-tools.test.ts +7 -4
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +89 -18
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/credential-vault-unit.test.ts +379 -3
- package/src/__tests__/credentials-cli.test.ts +40 -16
- package/src/__tests__/cross-provider-web-search.test.ts +146 -35
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
- package/src/__tests__/email-html-renderer.test.ts +71 -0
- package/src/__tests__/email-invite-adapter.test.ts +36 -32
- package/src/__tests__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +75 -8
- package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +64 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
- package/src/__tests__/gmail-archive-gate.test.ts +246 -0
- package/src/__tests__/gmail-preferences.test.ts +117 -0
- package/src/__tests__/headless-browser-interactions.test.ts +43 -0
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +142 -5
- package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
- package/src/__tests__/heartbeat-service.test.ts +70 -17
- package/src/__tests__/home-state-routes.test.ts +162 -0
- package/src/__tests__/host-bash-proxy.test.ts +0 -5
- package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
- package/src/__tests__/host-cu-proxy.test.ts +0 -5
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/llm-context-normalization.test.ts +488 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/media-stream-output.test.ts +555 -0
- package/src/__tests__/media-stream-parser.test.ts +374 -0
- package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
- package/src/__tests__/media-stream-stt-session.test.ts +588 -0
- package/src/__tests__/media-turn-detector.test.ts +440 -0
- package/src/__tests__/message-queue.test.ts +125 -0
- package/src/__tests__/migration-export-http.test.ts +6 -6
- package/src/__tests__/migration-import-commit-http.test.ts +8 -6
- package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +151 -0
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +2 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
- package/src/__tests__/oauth-providers-routes.test.ts +2 -0
- package/src/__tests__/oauth-store.test.ts +85 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +249 -6
- package/src/__tests__/onboarding-template-contract.test.ts +6 -13
- package/src/__tests__/openai-provider.test.ts +176 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1105 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outlook-unsubscribe.test.ts +31 -2
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +174 -0
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
- package/src/__tests__/relationship-state-contract.test.ts +175 -0
- package/src/__tests__/relay-server.test.ts +423 -5
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-scanner-executor.test.ts +4 -0
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +5 -1
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +49 -0
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
- package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
- package/src/__tests__/skills.test.ts +5 -2
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +564 -1
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/system-prompt.test.ts +112 -26
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +18 -7
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +33 -24
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +345 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
- package/src/__tests__/twilio-routes.test.ts +376 -0
- package/src/__tests__/unicode.test.ts +293 -0
- package/src/__tests__/update-bulletin-format.test.ts +59 -0
- package/src/__tests__/update-bulletin.test.ts +206 -5
- package/src/__tests__/usage-routes.test.ts +25 -4
- package/src/__tests__/user-reference.test.ts +46 -61
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
- package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
- package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
- package/src/__tests__/workspace-migration-meets.test.ts +244 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
- package/src/__tests__/workspace-policy.test.ts +2 -0
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +43 -3
- package/src/backup/__tests__/backup-key.test.ts +152 -0
- package/src/backup/__tests__/backup-worker.test.ts +767 -0
- package/src/backup/__tests__/list-snapshots.test.ts +87 -0
- package/src/backup/__tests__/local-writer.test.ts +218 -0
- package/src/backup/__tests__/offsite-writer.test.ts +641 -0
- package/src/backup/__tests__/paths.test.ts +300 -0
- package/src/backup/__tests__/restore.test.ts +498 -0
- package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
- package/src/backup/__tests__/stream-crypt.test.ts +228 -0
- package/src/backup/backup-key.ts +137 -0
- package/src/backup/backup-worker.ts +459 -0
- package/src/backup/list-snapshots.ts +147 -0
- package/src/backup/local-writer.ts +133 -0
- package/src/backup/offsite-writer.ts +222 -0
- package/src/backup/paths.ts +226 -0
- package/src/backup/restore.ts +322 -0
- package/src/backup/snapshot-lock.ts +431 -0
- package/src/backup/stream-crypt.ts +263 -0
- package/src/bundler/package-resolver.ts +4 -0
- package/src/calls/audio-store.ts +11 -5
- package/src/calls/call-controller.ts +226 -71
- package/src/calls/call-domain.ts +9 -0
- package/src/calls/call-speech-output.ts +190 -0
- package/src/calls/call-transport.ts +77 -0
- package/src/calls/media-stream-audio-transcode.ts +173 -0
- package/src/calls/media-stream-output.ts +660 -0
- package/src/calls/media-stream-parser.ts +300 -0
- package/src/calls/media-stream-protocol.ts +166 -0
- package/src/calls/media-stream-server.ts +592 -0
- package/src/calls/media-stream-stt-session.ts +460 -0
- package/src/calls/media-turn-detector.ts +230 -0
- package/src/calls/relay-server.ts +90 -75
- package/src/calls/resolve-call-tts-provider.ts +136 -0
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +161 -0
- package/src/calls/tts-text-sanitizer.ts +32 -16
- package/src/calls/twilio-routes.ts +281 -17
- package/src/calls/voice-quality.ts +78 -35
- package/src/calls/voice-session-bridge.ts +8 -1
- package/src/channels/types.ts +16 -0
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
- package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
- package/src/cli/commands/__tests__/email-download.test.ts +16 -1
- package/src/cli/commands/__tests__/email-list.test.ts +22 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +37 -4
- package/src/cli/commands/__tests__/email-status.test.ts +5 -1
- package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/conversations.ts +77 -0
- package/src/cli/commands/credentials.ts +0 -1
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +255 -3
- package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +15 -0
- package/src/cli/commands/oauth/shared.ts +2 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -9
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
- package/src/cli/program.ts +30 -4
- package/src/config/__tests__/backup-schema.test.ts +134 -0
- package/src/config/assistant-feature-flags.ts +61 -62
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
- package/src/config/bundled-skills/browser/SKILL.md +30 -5
- package/src/config/bundled-skills/browser/TOOLS.json +123 -0
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
- package/src/config/bundled-skills/contacts/SKILL.md +2 -2
- package/src/config/bundled-skills/gmail/SKILL.md +53 -7
- package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
- package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/outlook/SKILL.md +2 -2
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
- package/src/config/bundled-skills/slack/SKILL.md +1 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
- package/src/config/bundled-tool-registry.ts +8 -0
- package/src/config/env-registry.ts +24 -0
- package/src/config/env.ts +34 -10
- package/src/config/feature-flag-registry.json +46 -14
- package/src/config/loader.ts +26 -12
- package/src/config/schema.ts +35 -10
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +51 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -26
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +47 -7
- package/src/config/schemas/heartbeat.ts +27 -5
- package/src/config/schemas/host-browser.ts +47 -1
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/services.ts +44 -0
- package/src/config/schemas/stt.ts +59 -0
- package/src/config/schemas/tts.ts +230 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/skills.ts +4 -0
- package/src/config/types.ts +4 -0
- package/src/contacts/contact-store.ts +56 -11
- package/src/contacts/contacts-write.ts +38 -1
- package/src/context/post-turn-tool-result-truncation.ts +3 -2
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +45 -12
- package/src/credential-execution/executable-discovery.ts +12 -2
- package/src/credential-execution/process-manager.ts +33 -2
- package/src/credential-health/credential-health-service.ts +366 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/config-watcher.ts +99 -5
- package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
- package/src/daemon/conversation-agent-loop.ts +101 -24
- package/src/daemon/conversation-error.ts +11 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +59 -9
- package/src/daemon/conversation-messaging.ts +37 -3
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +581 -19
- package/src/daemon/conversation-queue-manager.ts +24 -0
- package/src/daemon/conversation-runtime-assembly.ts +11 -1
- package/src/daemon/conversation-slash.ts +36 -0
- package/src/daemon/conversation-surfaces.ts +94 -4
- package/src/daemon/conversation-tool-setup.ts +25 -0
- package/src/daemon/conversation-usage.ts +7 -4
- package/src/daemon/conversation.ts +86 -28
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +4 -1
- package/src/daemon/handlers/shared.ts +22 -0
- package/src/daemon/handlers/skills.ts +321 -77
- package/src/daemon/host-browser-proxy.ts +2 -1
- package/src/daemon/lifecycle.ts +122 -25
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/conversations.ts +34 -1
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +14 -0
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +16 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/server.ts +347 -2
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +9 -0
- package/src/email/html-renderer.ts +76 -0
- package/src/heartbeat/heartbeat-service.ts +93 -7
- package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
- package/src/home/__tests__/emit-feed-event.test.ts +169 -0
- package/src/home/__tests__/feed-scheduler.test.ts +194 -0
- package/src/home/__tests__/feed-types.test.ts +275 -0
- package/src/home/__tests__/feed-writer.test.ts +688 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
- package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
- package/src/home/__tests__/progress-formula.test.ts +213 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
- package/src/home/__tests__/rollup-producer.test.ts +398 -0
- package/src/home/assistant-feed-authoring.ts +124 -0
- package/src/home/emit-feed-event.ts +158 -0
- package/src/home/feed-scheduler.ts +247 -0
- package/src/home/feed-types.ts +181 -0
- package/src/home/feed-writer.ts +469 -0
- package/src/home/platform-gmail-digest.ts +163 -0
- package/src/home/progress-formula.ts +86 -0
- package/src/home/relationship-state-writer.ts +824 -0
- package/src/home/relationship-state.ts +143 -0
- package/src/home/rollup-producer.ts +384 -0
- package/src/hooks/runner.ts +7 -0
- package/src/inbound/platform-callback-registration.ts +12 -3
- package/src/inbound/public-ingress-urls.ts +12 -0
- package/src/instrument.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/cli-client.ts +151 -0
- package/src/ipc/cli-server.ts +234 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/index.ts +5 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
- package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/app-store.ts +1 -1
- package/src/memory/attachments-store.ts +70 -0
- package/src/memory/auto-analysis-enqueue.ts +127 -0
- package/src/memory/auto-analysis-guard.ts +27 -0
- package/src/memory/cleanup-schedule-state.ts +37 -0
- package/src/memory/conversation-analyze-job.ts +73 -0
- package/src/memory/conversation-crud.ts +99 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +34 -2
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/db-init.ts +6 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/graph/conversation-graph-memory.ts +15 -0
- package/src/memory/graph/extraction.test.ts +23 -0
- package/src/memory/graph/extraction.ts +8 -0
- package/src/memory/graph/retriever.ts +27 -18
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/group-crud.ts +6 -1
- package/src/memory/indexer.ts +95 -16
- package/src/memory/job-handlers/cleanup.ts +11 -8
- package/src/memory/job-handlers/conversation-starters.ts +16 -10
- package/src/memory/jobs-store.ts +64 -4
- package/src/memory/jobs-worker.ts +22 -9
- package/src/memory/llm-usage-store.ts +92 -56
- package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
- package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/oauth.ts +3 -0
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/client.ts +57 -6
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +143 -38
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/notifications/decision-engine.ts +3 -3
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
- package/src/oauth/byo-connection.test.ts +18 -1
- package/src/oauth/byo-connection.ts +3 -1
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.ts +6 -2
- package/src/oauth/connection.ts +2 -0
- package/src/oauth/oauth-store.ts +9 -0
- package/src/oauth/platform-connection.test.ts +98 -0
- package/src/oauth/platform-connection.ts +52 -31
- package/src/oauth/seed-providers.ts +7 -0
- package/src/permissions/checker.ts +16 -6
- package/src/permissions/defaults.ts +49 -1
- package/src/permissions/trust-store.ts +3 -3
- package/src/permissions/workspace-policy.ts +3 -0
- package/src/platform/client.test.ts +10 -0
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +126 -2
- package/src/prompts/system-prompt.ts +59 -18
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/prompts/templates/UPDATES.md +12 -0
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-format.ts +26 -9
- package/src/prompts/update-bulletin.ts +34 -23
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/anthropic/client.ts +157 -61
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +9 -1
- package/src/providers/model-catalog.ts +6 -0
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +474 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +502 -0
- package/src/providers/openrouter/client.ts +101 -4
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +14 -3
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
- package/src/providers/speech-to-text/deepgram.test.ts +332 -0
- package/src/providers/speech-to-text/deepgram.ts +115 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
- package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
- package/src/providers/speech-to-text/google-gemini.ts +101 -0
- package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
- package/src/providers/speech-to-text/openai-whisper.ts +63 -33
- package/src/providers/speech-to-text/provider-catalog.ts +306 -0
- package/src/providers/speech-to-text/resolve.ts +386 -6
- package/src/providers/types.ts +9 -0
- package/src/runtime/AGENTS.md +43 -1
- package/src/runtime/__tests__/agent-wake.test.ts +831 -0
- package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
- package/src/runtime/agent-wake.ts +512 -0
- package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
- package/src/runtime/auth/route-policy.ts +30 -5
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/capability-tokens.ts +10 -10
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-invite-transports/email.ts +14 -6
- package/src/runtime/channel-readiness-service.ts +12 -22
- package/src/runtime/chrome-extension-registry.ts +38 -2
- package/src/runtime/http-server.ts +395 -10
- package/src/runtime/http-types.ts +6 -2
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/migration-transport.ts +1 -0
- package/src/runtime/migrations/migration-wizard.ts +1 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
- package/src/runtime/migrations/vbundle-importer.ts +34 -0
- package/src/runtime/pending-interactions.ts +0 -11
- package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
- package/src/runtime/routes/app-management-routes.ts +12 -18
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/backup-routes.ts +519 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
- package/src/runtime/routes/btw-routes.ts +8 -6
- package/src/runtime/routes/contact-routes.test.ts +298 -0
- package/src/runtime/routes/contact-routes.ts +132 -5
- package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
- package/src/runtime/routes/conversation-management-routes.ts +115 -0
- package/src/runtime/routes/conversation-routes.ts +367 -146
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/home-feed-routes.ts +334 -0
- package/src/runtime/routes/home-state-routes.ts +138 -0
- package/src/runtime/routes/host-browser-routes.ts +3 -14
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +3 -17
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
- package/src/runtime/routes/integrations/slack/channel.ts +11 -3
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +303 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/migration-routes.ts +40 -5
- package/src/runtime/routes/settings-routes.ts +22 -5
- package/src/runtime/routes/skills-routes.ts +76 -7
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/surface-action-routes.ts +41 -2
- package/src/runtime/routes/tts-routes.ts +108 -24
- package/src/runtime/routes/usage-routes.ts +30 -2
- package/src/runtime/routes/user-route-dispatcher.ts +50 -5
- package/src/runtime/routes/user-routes.ts +13 -1
- package/src/runtime/routes/work-items-routes.ts +8 -1
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
- package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
- package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
- package/src/runtime/services/analyze-conversation.ts +344 -0
- package/src/runtime/services/analyze-deps-singleton.ts +32 -0
- package/src/runtime/services/auto-analysis-prompt.ts +55 -0
- package/src/runtime/skill-route-registry.ts +49 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +50 -0
- package/src/security/oauth2.ts +26 -4
- package/src/security/secure-keys.ts +25 -2
- package/src/security/token-manager.ts +8 -0
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-files.ts +64 -2
- package/src/skills/category-inference.ts +122 -0
- package/src/skills/clawhub-files.ts +213 -0
- package/src/skills/clawhub.ts +84 -23
- package/src/skills/skill-file-provider.ts +40 -0
- package/src/skills/skillssh-files.ts +395 -0
- package/src/skills/skillssh-registry.ts +4 -4
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +195 -0
- package/src/stt/stt-stream-session.ts +499 -0
- package/src/stt/types.ts +330 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +38 -14
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
- package/src/tools/browser/browser-execution.ts +1163 -23
- package/src/tools/browser/browser-manager.ts +45 -0
- package/src/tools/browser/browser-mode-constants.ts +12 -0
- package/src/tools/browser/browser-mode.ts +92 -0
- package/src/tools/browser/browser-status-constants.ts +33 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +183 -17
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
- package/src/tools/browser/cdp-client/errors.ts +15 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
- package/src/tools/browser/cdp-client/factory.ts +797 -87
- package/src/tools/browser/cdp-client/index.ts +16 -2
- package/src/tools/browser/cdp-client/types.ts +68 -0
- package/src/tools/credentials/vault.ts +35 -6
- package/src/tools/network/web-fetch.ts +5 -2
- package/src/tools/network/web-search.ts +5 -2
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +2 -0
- package/src/tools/skills/sandbox-runner.ts +3 -2
- package/src/tools/terminal/safe-env.ts +10 -2
- package/src/tools/terminal/shell.ts +15 -4
- package/src/tools/tool-manifest.ts +21 -0
- package/src/tools/types.ts +17 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tts/__tests__/provider-adapters.test.ts +834 -0
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
- package/src/tts/__tests__/provider-catalog.test.ts +183 -0
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +201 -0
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +219 -0
- package/src/tts/providers/elevenlabs-provider.ts +211 -0
- package/src/tts/providers/fish-audio-provider.ts +183 -0
- package/src/tts/providers/index.ts +42 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +153 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/util/abort-reasons.ts +58 -0
- package/src/util/device-id.ts +32 -16
- package/src/util/errors.ts +9 -1
- package/src/util/platform.ts +54 -10
- package/src/util/pricing.ts +66 -3
- package/src/util/spawn.ts +1 -1
- package/src/util/truncate.ts +4 -2
- package/src/util/unicode.ts +201 -0
- package/src/version.ts +19 -24
- package/src/watcher/engine.ts +23 -0
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/migrations/003-seed-device-id.ts +9 -3
- package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
- package/src/workspace/migrations/029-seed-pkb.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +317 -0
- package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
- package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
- package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
- package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
- package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
- package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
- package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/top-level-renderer.ts +13 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/cli/commands/browser-relay.ts +0 -466
- package/src/email/guardrails.ts +0 -221
- package/src/email/provider.ts +0 -117
- package/src/email/providers/agentmail.ts +0 -361
- package/src/email/providers/index.ts +0 -65
- package/src/email/service.ts +0 -384
- package/src/email/types.ts +0 -126
- package/src/prompts/templates/USER.md +0 -13
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/runtime/routes/browser-cdp-routes.ts +0 -229
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync assistant identity fields to the platform Assistant record.
|
|
3
|
+
*
|
|
4
|
+
* When IDENTITY.md changes on disk the daemon broadcasts an
|
|
5
|
+
* `identity_changed` event to connected clients. This module hooks into
|
|
6
|
+
* that same change signal and PATCHes the platform `Assistant` record so
|
|
7
|
+
* the name (and, in future, other fields) stays in sync.
|
|
8
|
+
*
|
|
9
|
+
* Requests are serialized so that rapid name changes (A → B) never race:
|
|
10
|
+
* only the most recently requested name is sent, and a stale in-flight
|
|
11
|
+
* response cannot overwrite a newer value.
|
|
12
|
+
*
|
|
13
|
+
* The sync is best-effort and fire-and-forget — network failures are
|
|
14
|
+
* logged but never surface to callers.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { getLogger } from "../util/logger.js";
|
|
18
|
+
import { VellumPlatformClient } from "./client.js";
|
|
19
|
+
|
|
20
|
+
const log = getLogger("sync-identity");
|
|
21
|
+
|
|
22
|
+
/** Track the last successfully synced name (used inside doSync to skip redundant PATCHes). */
|
|
23
|
+
let lastSyncedName: string | null = null;
|
|
24
|
+
|
|
25
|
+
/** Track the last requested name (used for dedup at enqueue time). */
|
|
26
|
+
let lastRequestedName: string | null = null;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Monotonically increasing sequence number. Each call to
|
|
30
|
+
* `syncIdentityNameToPlatform` bumps this; after a PATCH completes we
|
|
31
|
+
* only update `lastSyncedName` when `seq` still matches, guaranteeing
|
|
32
|
+
* the newest name always wins.
|
|
33
|
+
*/
|
|
34
|
+
let seq = 0;
|
|
35
|
+
|
|
36
|
+
/** Chain promise that serializes in-flight PATCH requests. */
|
|
37
|
+
let pending: Promise<void> = Promise.resolve();
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Push the current assistant name to the platform `Assistant` record.
|
|
41
|
+
*
|
|
42
|
+
* No-op when:
|
|
43
|
+
* - The platform client cannot be created (not platform-hosted / missing creds).
|
|
44
|
+
* - No assistant ID is configured.
|
|
45
|
+
* - The name is empty or unchanged since the last request.
|
|
46
|
+
*/
|
|
47
|
+
export function syncIdentityNameToPlatform(name: string): void {
|
|
48
|
+
if (!name || name === lastRequestedName) return;
|
|
49
|
+
|
|
50
|
+
lastRequestedName = name;
|
|
51
|
+
|
|
52
|
+
const mySeq = ++seq;
|
|
53
|
+
|
|
54
|
+
pending = pending
|
|
55
|
+
.then(() => doSync(name, mySeq))
|
|
56
|
+
.catch(() => {
|
|
57
|
+
// swallowed — doSync already logs internally
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function doSync(name: string, requestSeq: number): Promise<void> {
|
|
62
|
+
try {
|
|
63
|
+
// A newer call has already been enqueued — skip this stale request.
|
|
64
|
+
if (requestSeq !== seq) return;
|
|
65
|
+
|
|
66
|
+
// Re-check after awaiting the previous request in the chain.
|
|
67
|
+
if (name === lastSyncedName) return;
|
|
68
|
+
|
|
69
|
+
const client = await VellumPlatformClient.create();
|
|
70
|
+
if (!client) {
|
|
71
|
+
clearRequestedIfLatest(requestSeq);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const assistantId = client.platformAssistantId;
|
|
76
|
+
if (!assistantId) {
|
|
77
|
+
clearRequestedIfLatest(requestSeq);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const resp = await client.fetch(
|
|
82
|
+
`/v1/assistants/${encodeURIComponent(assistantId)}/`,
|
|
83
|
+
{
|
|
84
|
+
method: "PATCH",
|
|
85
|
+
headers: { "Content-Type": "application/json" },
|
|
86
|
+
body: JSON.stringify({ name }),
|
|
87
|
+
signal: AbortSignal.timeout(15_000),
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (resp.ok) {
|
|
92
|
+
// Only update cache if no newer request has been enqueued since we
|
|
93
|
+
// started this PATCH — prevents a slow response from overwriting a
|
|
94
|
+
// fresher value.
|
|
95
|
+
if (requestSeq === seq) {
|
|
96
|
+
lastSyncedName = name;
|
|
97
|
+
}
|
|
98
|
+
log.info({ name, assistantId }, "Synced assistant name to platform");
|
|
99
|
+
} else {
|
|
100
|
+
clearRequestedIfLatest(requestSeq);
|
|
101
|
+
const text = await resp.text();
|
|
102
|
+
log.warn(
|
|
103
|
+
{ status: resp.status, body: text, assistantId },
|
|
104
|
+
"Failed to sync assistant name to platform",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
} catch (err) {
|
|
108
|
+
clearRequestedIfLatest(requestSeq);
|
|
109
|
+
log.warn({ err }, "Error syncing assistant name to platform");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Reset `lastRequestedName` when the latest request failed, so that the
|
|
115
|
+
* next call with the same name is allowed through instead of being deduped.
|
|
116
|
+
*/
|
|
117
|
+
function clearRequestedIfLatest(requestSeq: number): void {
|
|
118
|
+
if (requestSeq === seq) {
|
|
119
|
+
lastRequestedName = lastSyncedName;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Reset cached state (for testing). */
|
|
124
|
+
export function _resetSyncState(): void {
|
|
125
|
+
lastSyncedName = null;
|
|
126
|
+
lastRequestedName = null;
|
|
127
|
+
seq = 0;
|
|
128
|
+
pending = Promise.resolve();
|
|
129
|
+
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
writeFileSync,
|
|
6
|
+
} from "node:fs";
|
|
7
|
+
import { basename, dirname, join } from "node:path";
|
|
3
8
|
|
|
4
9
|
import {
|
|
5
10
|
findContactByChannelExternalId,
|
|
@@ -16,6 +21,28 @@ import { stripCommentLines } from "../util/strip-comment-lines.js";
|
|
|
16
21
|
|
|
17
22
|
const log = getLogger("persona-resolver");
|
|
18
23
|
|
|
24
|
+
// ── Guardian persona template ─────────────────────────────────────
|
|
25
|
+
//
|
|
26
|
+
// Scaffold written to `users/<slug>.md` when a guardian is resolved
|
|
27
|
+
// but no per-user persona file yet exists. Kept in sync with the
|
|
28
|
+
// legacy workspace USER.md template so that upgrading users preserve
|
|
29
|
+
// the same editable shape. Exported so consumers can detect the
|
|
30
|
+
// unmodified scaffold (e.g. heartbeat's `isShallowProfile`).
|
|
31
|
+
export const GUARDIAN_PERSONA_TEMPLATE = `_ Lines starting with _ are comments - they won't appear in the system prompt
|
|
32
|
+
|
|
33
|
+
# User Profile
|
|
34
|
+
|
|
35
|
+
Store details about your user here. Edit freely - build this over time as you learn about them. Don't be pushy about seeking details, but when you learn something, write it down. More context makes you more useful.
|
|
36
|
+
|
|
37
|
+
- Preferred name/reference:
|
|
38
|
+
- Pronouns:
|
|
39
|
+
- Locale:
|
|
40
|
+
- Work role:
|
|
41
|
+
- Goals:
|
|
42
|
+
- Hobbies/fun:
|
|
43
|
+
- Daily tools:
|
|
44
|
+
`;
|
|
45
|
+
|
|
19
46
|
// ── Types ──────────────────────────────────────────────────────────
|
|
20
47
|
|
|
21
48
|
export interface PersonaContext {
|
|
@@ -98,6 +125,22 @@ function resolveUserFilename(
|
|
|
98
125
|
return null;
|
|
99
126
|
}
|
|
100
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Resolve the absolute on-disk path to the guardian's per-user persona
|
|
130
|
+
* file (e.g. `<workspace>/users/sidd.md`). Returns `null` when no
|
|
131
|
+
* guardian is resolvable (no guardian contact, or its `userFile` is
|
|
132
|
+
* unusable / fails basename validation).
|
|
133
|
+
*
|
|
134
|
+
* This does not check whether the file exists — it only resolves the
|
|
135
|
+
* path. Callers use it alongside `ensureGuardianPersonaFile` to open
|
|
136
|
+
* or scaffold the file.
|
|
137
|
+
*/
|
|
138
|
+
export function resolveGuardianPersonaPath(): string | null {
|
|
139
|
+
const filename = resolveUserFilename(undefined);
|
|
140
|
+
if (!filename) return null;
|
|
141
|
+
return join(getWorkspaceDir(), "users", filename);
|
|
142
|
+
}
|
|
143
|
+
|
|
101
144
|
/**
|
|
102
145
|
* Resolve a short slug identifying the current user, derived from
|
|
103
146
|
* their contact's userFile. Used to scope per-user workspace directories
|
|
@@ -192,3 +235,84 @@ export function resolvePersonaContext(
|
|
|
192
235
|
export function resolveGuardianPersona(): string | null {
|
|
193
236
|
return resolveUserPersona(undefined);
|
|
194
237
|
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Resolve the guardian's user persona strictly from their own
|
|
241
|
+
* `users/<slug>.md` file, with NO fallback to `users/default.md`.
|
|
242
|
+
*
|
|
243
|
+
* Returns `null` when no guardian contact is resolvable, the
|
|
244
|
+
* guardian's userFile is unset, or the file is missing / empty.
|
|
245
|
+
*
|
|
246
|
+
* Used by callers that derive guardian-specific attributes (name,
|
|
247
|
+
* pronouns) where `default.md` content would incorrectly override an
|
|
248
|
+
* intentional caller-supplied fallback such as `Contact.displayName`.
|
|
249
|
+
* System-prompt callers that want the default.md fallback should
|
|
250
|
+
* continue to use `resolveGuardianPersona`.
|
|
251
|
+
*/
|
|
252
|
+
export function resolveGuardianPersonaStrict(): string | null {
|
|
253
|
+
const filename = resolveUserFilename(undefined);
|
|
254
|
+
if (!filename) return null;
|
|
255
|
+
const filePath = join(getWorkspaceDir(), "users", filename);
|
|
256
|
+
if (!existsSync(filePath)) return null;
|
|
257
|
+
return readPersonaFile(filePath);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Write the guardian persona template scaffold to `users/<userFile>`
|
|
262
|
+
* when the file does not yet exist. No-op when the file already
|
|
263
|
+
* exists (safe against clobbering user edits).
|
|
264
|
+
*
|
|
265
|
+
* @param userFile - A filename (not a bare slug), matching the shape
|
|
266
|
+
* of `Contact.userFile` — a basename with a `.md` suffix
|
|
267
|
+
* (e.g. `"sidd.md"`). The path traversal guard rejects values that
|
|
268
|
+
* are not a clean basename.
|
|
269
|
+
*
|
|
270
|
+
* Creates the parent `users/` directory if missing.
|
|
271
|
+
*/
|
|
272
|
+
export function ensureGuardianPersonaFile(userFile: string): void {
|
|
273
|
+
if (basename(userFile) !== userFile || userFile === ".." || userFile === ".") {
|
|
274
|
+
log.warn(
|
|
275
|
+
{ userFile },
|
|
276
|
+
"Guardian persona userFile contains path traversal; refusing to write",
|
|
277
|
+
);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const filePath = join(getWorkspaceDir(), "users", userFile);
|
|
282
|
+
if (existsSync(filePath)) return;
|
|
283
|
+
|
|
284
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
285
|
+
writeFileSync(filePath, GUARDIAN_PERSONA_TEMPLATE, "utf-8");
|
|
286
|
+
log.debug({ path: filePath }, "Wrote guardian persona scaffold");
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Return `true` when the persona file at `filePath` has been edited by
|
|
291
|
+
* the user (its stripped content differs from the bare scaffold
|
|
292
|
+
* template). Returns `false` when the file is missing, unreadable,
|
|
293
|
+
* empty after stripping, or byte-identical to the template after
|
|
294
|
+
* stripping comment lines.
|
|
295
|
+
*
|
|
296
|
+
* Used by the vbundle importer to decide whether a legacy
|
|
297
|
+
* `prompts/USER.md` entry may safely overwrite `users/<slug>.md`.
|
|
298
|
+
*/
|
|
299
|
+
export function isGuardianPersonaCustomized(filePath: string): boolean {
|
|
300
|
+
if (!existsSync(filePath)) return false;
|
|
301
|
+
|
|
302
|
+
let content: string;
|
|
303
|
+
try {
|
|
304
|
+
content = readFileSync(filePath, "utf-8");
|
|
305
|
+
} catch (err) {
|
|
306
|
+
log.warn(
|
|
307
|
+
{ err, path: filePath },
|
|
308
|
+
"Failed to read persona file while checking customization",
|
|
309
|
+
);
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const stripped = stripCommentLines(content);
|
|
314
|
+
if (stripped.length === 0) return false;
|
|
315
|
+
|
|
316
|
+
const templateStripped = stripCommentLines(GUARDIAN_PERSONA_TEMPLATE);
|
|
317
|
+
return stripped !== templateStripped;
|
|
318
|
+
}
|
|
@@ -11,6 +11,7 @@ import { join } from "node:path";
|
|
|
11
11
|
import { getIsContainerized } from "../config/env-registry.js";
|
|
12
12
|
import { loadConfig } from "../config/loader.js";
|
|
13
13
|
import { listConnections } from "../oauth/oauth-store.js";
|
|
14
|
+
import type { OnboardingContext } from "../types/onboarding-context.js";
|
|
14
15
|
import { resolveBundledDir } from "../util/bundled-asset.js";
|
|
15
16
|
import { getLogger } from "../util/logger.js";
|
|
16
17
|
import {
|
|
@@ -25,7 +26,27 @@ export { SYSTEM_PROMPT_CACHE_BOUNDARY };
|
|
|
25
26
|
|
|
26
27
|
const log = getLogger("system-prompt");
|
|
27
28
|
|
|
28
|
-
const PROMPT_FILES = ["SOUL.md", "IDENTITY.md"
|
|
29
|
+
const PROMPT_FILES = ["SOUL.md", "IDENTITY.md"] as const;
|
|
30
|
+
|
|
31
|
+
function hasPopulatedUsersDir(): boolean {
|
|
32
|
+
try {
|
|
33
|
+
const usersDir = join(getWorkspaceDir(), "users");
|
|
34
|
+
if (!existsSync(usersDir)) return false;
|
|
35
|
+
return readdirSync(usersDir).length > 0;
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function hasExistingConversations(): boolean {
|
|
42
|
+
try {
|
|
43
|
+
const convDir = getConversationsDir();
|
|
44
|
+
if (!existsSync(convDir)) return false;
|
|
45
|
+
return readdirSync(convDir).length > 0;
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
29
50
|
|
|
30
51
|
/**
|
|
31
52
|
* Copy template prompt files into the data directory if they don't already exist.
|
|
@@ -43,10 +64,16 @@ export function ensurePromptFiles(): void {
|
|
|
43
64
|
"templates",
|
|
44
65
|
);
|
|
45
66
|
|
|
46
|
-
// Track whether this is a fresh workspace
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
67
|
+
// Track whether this is a fresh workspace. A workspace counts as fresh
|
|
68
|
+
// only when none of these signals are present: core prompt files, a
|
|
69
|
+
// populated `users/` directory, or existing conversations. Upgraded
|
|
70
|
+
// workspaces that dropped USER.md but still carry personas or history
|
|
71
|
+
// would otherwise be mistaken for fresh installs and re-trigger
|
|
72
|
+
// onboarding.
|
|
73
|
+
const isFirstRun =
|
|
74
|
+
PROMPT_FILES.every((file) => !existsSync(getWorkspacePromptPath(file))) &&
|
|
75
|
+
!hasPopulatedUsersDir() &&
|
|
76
|
+
!hasExistingConversations();
|
|
50
77
|
|
|
51
78
|
for (const file of PROMPT_FILES) {
|
|
52
79
|
const dest = getWorkspacePromptPath(file);
|
|
@@ -190,7 +217,7 @@ export function ensurePromptFiles(): void {
|
|
|
190
217
|
*
|
|
191
218
|
* Composition:
|
|
192
219
|
* 1. Base prompt: IDENTITY.md + SOUL.md (guaranteed to exist after ensurePromptFiles)
|
|
193
|
-
* 2. Append
|
|
220
|
+
* 2. Append the resolved user persona from users/<slug>.md (via options.userPersona)
|
|
194
221
|
* 3. If BOOTSTRAP.md exists, append first-run ritual instructions
|
|
195
222
|
*/
|
|
196
223
|
export interface BuildSystemPromptOptions {
|
|
@@ -199,6 +226,7 @@ export interface BuildSystemPromptOptions {
|
|
|
199
226
|
userPersona?: string | null;
|
|
200
227
|
channelPersona?: string | null;
|
|
201
228
|
userSlug?: string | null;
|
|
229
|
+
onboardingContext?: OnboardingContext;
|
|
202
230
|
}
|
|
203
231
|
|
|
204
232
|
/**
|
|
@@ -215,7 +243,7 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
|
|
|
215
243
|
// ── Static instruction sections (stable across turns) ──
|
|
216
244
|
// These sections are deterministic within a process lifetime. They form
|
|
217
245
|
// the first cache block so they remain cached even when workspace files
|
|
218
|
-
// (IDENTITY.md, SOUL.md,
|
|
246
|
+
// (IDENTITY.md, SOUL.md, users/<slug>.md, etc.) are edited between turns.
|
|
219
247
|
const staticParts: string[] = [];
|
|
220
248
|
const customPrefix = readCustomSystemPromptPrefix();
|
|
221
249
|
if (customPrefix) staticParts.push(customPrefix);
|
|
@@ -242,13 +270,11 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
|
|
|
242
270
|
|
|
243
271
|
const soulPath = getWorkspacePromptPath("SOUL.md");
|
|
244
272
|
const identityPath = getWorkspacePromptPath("IDENTITY.md");
|
|
245
|
-
const userPath = getWorkspacePromptPath("USER.md");
|
|
246
273
|
const bootstrapPath = getWorkspacePromptPath("BOOTSTRAP.md");
|
|
247
274
|
const updatesPath = getWorkspacePromptPath("UPDATES.md");
|
|
248
275
|
|
|
249
276
|
const soul = readPromptFile(soulPath);
|
|
250
277
|
const identity = readPromptFile(identityPath);
|
|
251
|
-
const user = readPromptFile(userPath);
|
|
252
278
|
const bootstrap = readPromptFile(bootstrapPath);
|
|
253
279
|
const updates = readPromptFile(updatesPath);
|
|
254
280
|
|
|
@@ -262,7 +288,6 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
|
|
|
262
288
|
// source and skip them — SOUL.md provides sufficient personality defaults
|
|
263
289
|
// until onboarding completes.
|
|
264
290
|
const identityIsTemplate = isTemplateContent(identity, "IDENTITY.md");
|
|
265
|
-
const userIsTemplate = isTemplateContent(user, "USER.md");
|
|
266
291
|
|
|
267
292
|
if (identity && !identityIsTemplate) {
|
|
268
293
|
// Strip placeholder lines (e.g. "- **Name:** _(not yet chosen)_") so
|
|
@@ -278,13 +303,28 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
|
|
|
278
303
|
if (soul) dynamicParts.push(soul);
|
|
279
304
|
if (options?.userPersona) dynamicParts.push(options.userPersona);
|
|
280
305
|
if (options?.channelPersona) dynamicParts.push(options.channelPersona);
|
|
281
|
-
if (user && !userIsTemplate && !options?.userPersona) dynamicParts.push(user);
|
|
282
306
|
if (includeBootstrap) {
|
|
307
|
+
const userSlug = options?.userSlug ?? "default";
|
|
308
|
+
const bootstrapWithSlug = bootstrap.replaceAll(
|
|
309
|
+
"{{USER_PERSONA_FILE}}",
|
|
310
|
+
`${userSlug}.md`,
|
|
311
|
+
);
|
|
283
312
|
dynamicParts.push(
|
|
284
313
|
"# First-Run Ritual\n\n" +
|
|
285
314
|
"BOOTSTRAP.md is present — this is your first conversation. Follow its instructions.\n\n" +
|
|
286
|
-
|
|
315
|
+
bootstrapWithSlug,
|
|
287
316
|
);
|
|
317
|
+
|
|
318
|
+
if (options?.onboardingContext) {
|
|
319
|
+
dynamicParts.push(
|
|
320
|
+
"## Pre-chat Onboarding Context\n\n" +
|
|
321
|
+
"The user completed the native pre-chat onboarding. Here is their context:\n\n" +
|
|
322
|
+
"```json\n" +
|
|
323
|
+
JSON.stringify(options.onboardingContext, null, 2) +
|
|
324
|
+
"\n```\n\n" +
|
|
325
|
+
"Use this to personalize your opener and skip redundant discovery.",
|
|
326
|
+
);
|
|
327
|
+
}
|
|
288
328
|
}
|
|
289
329
|
if (updates) {
|
|
290
330
|
dynamicParts.push(
|
|
@@ -423,9 +463,11 @@ function buildContainerizedSection(): string {
|
|
|
423
463
|
function buildParallelToolCallsSection(): string {
|
|
424
464
|
return [
|
|
425
465
|
"<use_parallel_tool_calls>",
|
|
426
|
-
"
|
|
466
|
+
"Batch independent tool calls into the same response. An extra LLM round trip costs orders of magnitude more than a few wasted tool calls — err on the side of parallelizing when calls are independent. Reading multiple files, `glob`/`grep`, `ls`, `git status`/`diff`/`log`, type-checks, and tests should be batched.",
|
|
467
|
+
"",
|
|
468
|
+
"Before emitting a single tool call, ask whether your next turn would be another tool call that doesn't consume this one's output — if so, they belong together. Serialized tool calls without a real data dependency are a bug.",
|
|
427
469
|
"",
|
|
428
|
-
"For non-trivial independent workstreams — research, coding
|
|
470
|
+
"For non-trivial independent workstreams — research, coding, multi-step investigations — delegate to subagents (load the `subagent` skill) and spawn them early and in parallel; an unnecessary subagent is cheaper than serialized work.",
|
|
429
471
|
"</use_parallel_tool_calls>",
|
|
430
472
|
].join("\n");
|
|
431
473
|
}
|
|
@@ -490,7 +532,7 @@ function readPromptFile(path: string): string | null {
|
|
|
490
532
|
}
|
|
491
533
|
|
|
492
534
|
/**
|
|
493
|
-
* Reads the core identity/personality prompt files (SOUL.md, IDENTITY.md
|
|
535
|
+
* Reads the core identity/personality prompt files (SOUL.md, IDENTITY.md)
|
|
494
536
|
* and concatenates whichever exist. Returns null if none are present.
|
|
495
537
|
*
|
|
496
538
|
* This is useful for injecting identity context into subsystems (e.g. memory
|
|
@@ -504,10 +546,9 @@ export function buildCoreIdentityContext(opts?: {
|
|
|
504
546
|
const content = readPromptFile(getWorkspacePromptPath(file));
|
|
505
547
|
if (!content) continue;
|
|
506
548
|
// SOUL.md is always included — it provides personality defaults even
|
|
507
|
-
// before onboarding completes. Only skip IDENTITY.md
|
|
508
|
-
//
|
|
549
|
+
// before onboarding completes. Only skip IDENTITY.md when it is still
|
|
550
|
+
// an unmodified template (matching buildSystemPrompt).
|
|
509
551
|
if (file !== "SOUL.md" && isTemplateContent(content, file)) continue;
|
|
510
|
-
if (file === "USER.md" && opts?.userPersona) continue;
|
|
511
552
|
parts.push(content);
|
|
512
553
|
}
|
|
513
554
|
if (opts?.userPersona) parts.push(opts.userPersona);
|
|
@@ -16,7 +16,7 @@ This is your first conversation. This document gives you goals and constraints
|
|
|
16
16
|
|
|
17
17
|
5. **Offer the next level** — once you know something, offer a capability it enables. Not as a reward — as a natural relationship step.
|
|
18
18
|
|
|
19
|
-
6. **Write everything immediately** — every fact learned gets saved to
|
|
19
|
+
6. **Write everything immediately** — every fact learned gets saved to users/{{USER_PERSONA_FILE}} the same turn. Style observations go to SOUL.md. No batching.
|
|
20
20
|
|
|
21
21
|
7. **Clean up** — delete BOOTSTRAP.md and BOOTSTRAP-REFERENCE.md at the end of this conversation, regardless of how far you got. One-shot.
|
|
22
22
|
|
|
@@ -37,15 +37,15 @@ This is your first conversation. This document gives you goals and constraints
|
|
|
37
37
|
|
|
38
38
|
## Technical Contract (what must be prescribed)
|
|
39
39
|
|
|
40
|
-
**Files to create/update:** IDENTITY.md, SOUL.md,
|
|
40
|
+
**Files to create/update:** IDENTITY.md, SOUL.md, users/{{USER_PERSONA_FILE}}
|
|
41
41
|
|
|
42
42
|
**File format:** preserve existing field structure:
|
|
43
43
|
- IDENTITY.md: Name, Emoji, Nature, Personality, Role
|
|
44
|
-
-
|
|
44
|
+
- users/{{USER_PERSONA_FILE}}: Preferred name, Pronouns, Locale, Work role, Goals, Hobbies/fun, Daily tools
|
|
45
45
|
|
|
46
46
|
Use `file_edit` immediately, silently, never mention file names or tool names to the user.
|
|
47
47
|
|
|
48
|
-
The contents of IDENTITY.md, SOUL.md, and
|
|
48
|
+
The contents of IDENTITY.md, SOUL.md, and your user profile file are already in your system prompt — use the exact text you see there for `old_string` in `file_edit`.
|
|
49
49
|
|
|
50
50
|
After tool calls, do not repeat yourself — your text before tool calls is already visible to the user.
|
|
51
51
|
|
|
@@ -90,7 +90,7 @@ If an `onboarding` JSON context is present in this conversation, the user alread
|
|
|
90
90
|
- `tools` array -> know which integration offers to surface first, infer work profile
|
|
91
91
|
- `tasks` array -> know what "prove value fast" means for this person
|
|
92
92
|
- `tone` string -> calibrate warmth/formality
|
|
93
|
-
- `userName` / `assistantName` -> write to IDENTITY.md and
|
|
93
|
+
- `userName` / `assistantName` -> write to IDENTITY.md and users/{{USER_PERSONA_FILE}} immediately, skip name exchange
|
|
94
94
|
|
|
95
95
|
If no onboarding context is present, infer everything fresh from conversation.
|
|
96
96
|
|
|
@@ -73,7 +73,9 @@ You have a personal knowledge base (`pkb/`) in your workspace. It holds facts, p
|
|
|
73
73
|
- **threads.md** - Active commitments, follow-ups, and projects. Always in your context.
|
|
74
74
|
- **buffer.md** - Inbox of recently learned facts, waiting to be filed.
|
|
75
75
|
|
|
76
|
-
**When you learn something:** Call `remember` IMMEDIATELY.
|
|
76
|
+
**When you learn something:** Call `remember` IMMEDIATELY. Capture anything concrete about their life — preferences, names, times, plans, states, habits, opinions, health details, routines, commitments. Don't judge importance; filing decides that later. Default to remembering; only skip obvious noise (small talk, hypotheticals, things they're just musing about). Call it multiple times per conversation. Remembering too much costs nothing (one line appended to a file). Forgetting something that mattered makes you look like you weren't paying attention. Don't categorize, don't batch, don't wait. Just capture it and stay in the conversation. Filing happens later.
|
|
77
|
+
|
|
78
|
+
**Corrections are the highest priority.** When the user corrects a fact you had wrong — "actually it's Thursday not Friday," "no, she lives in Austin now," "I stopped taking that medication last month" — `remember` the correction *immediately*. The wrong version is already propagated across prior turns and baked into your memory graph; future-you will keep operating on the old value until you persist the correction. A correction is not a "small fix," it's a structural edit to what you believe. Never skip a correction even if you'd skip the equivalent fresh fact.
|
|
77
79
|
|
|
78
80
|
**Topic files** live in subdirectories of `pkb/` (health, preferences, people, schedule, work, etc.). You created these and you manage them. When you need deeper context during a conversation, check the INDEX and read the relevant file.
|
|
79
81
|
|
|
@@ -10,6 +10,12 @@ _ Format is freeform markdown. Write notes that help the assistant
|
|
|
10
10
|
_ understand what changed and how it affects behavior, capabilities,
|
|
11
11
|
_ or available tools. Focus on what matters to the user experience.
|
|
12
12
|
|
|
13
|
+
<!-- vellum-update-release:gemini-live-stt -->
|
|
14
|
+
## Google Gemini speech-to-text now uses the Live API
|
|
15
|
+
|
|
16
|
+
If your user is configured with `services.stt.provider: "google-gemini"`, transcription now streams over the Gemini Live WebSocket API and emits true partial transcripts in real time, instead of the previous polling approximation that re-uploaded the full audio buffer every second. Same Gemini API key, same setup — only the transport changed. Latency for partials should drop noticeably.
|
|
17
|
+
<!-- /vellum-update-release:gemini-live-stt -->
|
|
18
|
+
|
|
13
19
|
<!-- vellum-update-release:rm-dangerous-skip-perms -->
|
|
14
20
|
## `dangerouslySkipPermissions` removed
|
|
15
21
|
|
|
@@ -36,3 +42,9 @@ Some Slack image attachments were stored incorrectly due to a missing OAuth scop
|
|
|
36
42
|
This has been fixed automatically: the corrupted attachments were removed from affected conversations during this update, and the OAuth scope issue has been resolved so new image uploads work correctly. If your user mentions missing images from earlier conversations, this is why — the images were never successfully received in the first place.
|
|
37
43
|
<!-- /vellum-update-release:corrupted-attachment-cleanup -->
|
|
38
44
|
|
|
45
|
+
<!-- vellum-update-release:llm-log-retention-setting -->
|
|
46
|
+
## LLM request log retention is now configurable
|
|
47
|
+
|
|
48
|
+
Your user can now choose how long LLM request logs are kept on their device from Settings → Permissions & Privacy on the macOS app. The default stays at 1 day, but they can pick 7, 30, or 90 days, or "Never" to retain logs indefinitely. If your user asks about managing their privacy or controlling how much LLM request history is retained locally, point them at this new picker.
|
|
49
|
+
<!-- /vellum-update-release:llm-log-retention-setting -->
|
|
50
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
_ Lines starting with _ are comments - they won't appear in the system prompt
|
|
2
|
+
_ This file shapes how you behave when responding in Slack. Edit it freely.
|
|
3
|
+
|
|
4
|
+
# Slack
|
|
5
|
+
|
|
6
|
+
## Delivery
|
|
7
|
+
|
|
8
|
+
Skip the research narration. In Slack, every message you send before your final answer posts as a separate visible message - not a live stream. "Let me look that up" and "Researching now..." just add noise. Use your tools, then deliver the result.
|
|
9
|
+
|
|
10
|
+
Your personality, warmth, humor, and opinions are welcome. Just don't narrate the process of finding the answer.
|
|
11
|
+
|
|
12
|
+
## Formatting
|
|
13
|
+
|
|
14
|
+
Never use markdown tables (pipe-delimited). Slack cannot render them. Use bullet points with bold labels instead.
|
|
15
|
+
|
|
16
|
+
When presenting information from web search, cite sources as inline hyperlinks woven into your text (e.g., "the round closed at $122B, [per CNBC](url)"). Don't dump a references list at the end.
|
|
17
|
+
|
|
18
|
+
## Long-form content
|
|
19
|
+
|
|
20
|
+
When your response would be long, dense, or highly structured (reports, teardowns, detailed analyses), use your judgment on whether to write it as an attached file vs posting inline. Consider what reads better in Slack - a wall of text with "See more" truncation often doesn't.
|
|
@@ -42,18 +42,35 @@ export function appendReleaseBlock(
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
45
|
+
* Filters template content to only include content blocks whose opening
|
|
46
|
+
* markers are not already present in the existing workspace content.
|
|
47
|
+
*
|
|
48
|
+
* Each content block is delimited by opening/closing marker pairs:
|
|
49
|
+
* <!-- vellum-update-release:id --> ... <!-- /vellum-update-release:id -->
|
|
50
|
+
*
|
|
51
|
+
* If the template has no block structure (no matched open/close pairs),
|
|
52
|
+
* returns the original body unchanged for backward compatibility.
|
|
53
|
+
* Returns empty string when all blocks are already present.
|
|
48
54
|
*/
|
|
49
|
-
export function
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
export function filterNewContentBlocks(
|
|
56
|
+
body: string,
|
|
57
|
+
existing: string,
|
|
58
|
+
): string {
|
|
59
|
+
const blockRegex =
|
|
60
|
+
/(<!-- vellum-update-release:(.+?) -->[\s\S]*?<!-- \/vellum-update-release:\2 -->)/g;
|
|
61
|
+
const blocks: Array<{ full: string; id: string }> = [];
|
|
52
62
|
let match: RegExpExecArray | null;
|
|
53
|
-
while ((match =
|
|
54
|
-
|
|
63
|
+
while ((match = blockRegex.exec(body)) !== null) {
|
|
64
|
+
blocks.push({ full: match[1], id: match[2] });
|
|
55
65
|
}
|
|
56
|
-
|
|
66
|
+
|
|
67
|
+
if (blocks.length === 0) return body;
|
|
68
|
+
|
|
69
|
+
const newBlocks = blocks.filter((b) => !hasReleaseBlock(existing, b.id));
|
|
70
|
+
|
|
71
|
+
if (newBlocks.length === 0) return "";
|
|
72
|
+
|
|
73
|
+
return newBlocks.map((b) => b.full).join("\n\n");
|
|
57
74
|
}
|
|
58
75
|
|
|
59
76
|
/** Extracts all version strings from release markers found in `content`. */
|