@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,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP route handlers for filing management.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
import { getConfig } from "../../config/loader.js";
|
|
8
|
+
import type { FilingService } from "../../filing/filing-service.js";
|
|
9
|
+
import { getLogger } from "../../util/logger.js";
|
|
10
|
+
import { httpError } from "../http-errors.js";
|
|
11
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
12
|
+
|
|
13
|
+
const log = getLogger("filing-routes");
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Handlers
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
function handleGetConfig(filingService?: FilingService): Response {
|
|
20
|
+
const config = getConfig().filing;
|
|
21
|
+
return Response.json({
|
|
22
|
+
enabled: config.enabled,
|
|
23
|
+
intervalMs: config.intervalMs,
|
|
24
|
+
activeHoursStart: config.activeHoursStart ?? null,
|
|
25
|
+
activeHoursEnd: config.activeHoursEnd ?? null,
|
|
26
|
+
nextRunAt: filingService?.nextRunAt ?? null,
|
|
27
|
+
lastRunAt: filingService?.lastRunAt ?? null,
|
|
28
|
+
success: true,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function handleRunNow(
|
|
33
|
+
filingService?: FilingService,
|
|
34
|
+
): Promise<Response> {
|
|
35
|
+
if (!filingService) {
|
|
36
|
+
return httpError(
|
|
37
|
+
"SERVICE_UNAVAILABLE",
|
|
38
|
+
"Filing service not available",
|
|
39
|
+
503,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const ran = await filingService.runOnce({ force: true });
|
|
45
|
+
return Response.json({ success: true, ran });
|
|
46
|
+
} catch (err) {
|
|
47
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
48
|
+
log.error({ err }, "Filing run-now failed");
|
|
49
|
+
return Response.json({ success: false, ran: false, error: message });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Route definitions
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
export function filingRouteDefinitions(deps: {
|
|
58
|
+
getFilingService?: () => FilingService | undefined;
|
|
59
|
+
}): RouteDefinition[] {
|
|
60
|
+
return [
|
|
61
|
+
{
|
|
62
|
+
endpoint: "filing/config",
|
|
63
|
+
method: "GET",
|
|
64
|
+
policyKey: "filing",
|
|
65
|
+
summary: "Get filing config",
|
|
66
|
+
description: "Return the current filing schedule configuration.",
|
|
67
|
+
tags: ["filing"],
|
|
68
|
+
responseBody: z.object({
|
|
69
|
+
enabled: z.boolean(),
|
|
70
|
+
intervalMs: z.number(),
|
|
71
|
+
activeHoursStart: z.number().nullable(),
|
|
72
|
+
activeHoursEnd: z.number().nullable(),
|
|
73
|
+
nextRunAt: z.number().nullable(),
|
|
74
|
+
lastRunAt: z.number().nullable(),
|
|
75
|
+
success: z.boolean(),
|
|
76
|
+
}),
|
|
77
|
+
handler: () => handleGetConfig(deps.getFilingService?.()),
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
endpoint: "filing/run-now",
|
|
81
|
+
method: "POST",
|
|
82
|
+
policyKey: "filing",
|
|
83
|
+
summary: "Run filing now",
|
|
84
|
+
description: "Trigger an immediate filing run.",
|
|
85
|
+
tags: ["filing"],
|
|
86
|
+
responseBody: z.object({
|
|
87
|
+
success: z.boolean(),
|
|
88
|
+
ran: z.boolean().describe("Whether the filing actually ran"),
|
|
89
|
+
}),
|
|
90
|
+
handler: () => handleRunNow(deps.getFilingService?.()),
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Home activity feed HTTP routes.
|
|
3
|
+
*
|
|
4
|
+
* Exposes the three endpoints the macOS Home page uses to render and
|
|
5
|
+
* interact with the activity feed:
|
|
6
|
+
*
|
|
7
|
+
* - `GET /v1/home/feed` — read + filter
|
|
8
|
+
* - `PATCH /v1/home/feed/:id` — mark seen / acted_on
|
|
9
|
+
* - `POST /v1/home/feed/:id/actions/:actionId` — trigger an action
|
|
10
|
+
*
|
|
11
|
+
* The routes are always available — the `home-feed` feature flag gates
|
|
12
|
+
* the client rendering path only, so the daemon surface can ship ahead
|
|
13
|
+
* of the rollout and client versions can adopt independently of
|
|
14
|
+
* feature-flag timing.
|
|
15
|
+
*
|
|
16
|
+
* All persistence goes through `readHomeFeed` / `patchFeedItemStatus`
|
|
17
|
+
* in `home/feed-writer.ts`; this module does not touch the on-disk
|
|
18
|
+
* file directly. The writer already applies the TTL filter on read
|
|
19
|
+
* and owns all SSE publication, so the route handlers stay pure
|
|
20
|
+
* shape + validation + banner computation.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { z } from "zod";
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
type FeedItem,
|
|
27
|
+
feedItemSchema,
|
|
28
|
+
type FeedItemStatus,
|
|
29
|
+
} from "../../home/feed-types.js";
|
|
30
|
+
import { patchFeedItemStatus, readHomeFeed } from "../../home/feed-writer.js";
|
|
31
|
+
import {
|
|
32
|
+
addMessage,
|
|
33
|
+
createConversation,
|
|
34
|
+
} from "../../memory/conversation-crud.js";
|
|
35
|
+
import { getLogger } from "../../util/logger.js";
|
|
36
|
+
import { httpError } from "../http-errors.js";
|
|
37
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
38
|
+
|
|
39
|
+
const log = getLogger("home-feed-routes");
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Response / request schemas
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
const contextBannerSchema = z.object({
|
|
46
|
+
greeting: z.string(),
|
|
47
|
+
timeAwayLabel: z.string(),
|
|
48
|
+
newCount: z.number().int().min(0),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const getHomeFeedResponseSchema = z.object({
|
|
52
|
+
items: z.array(feedItemSchema),
|
|
53
|
+
updatedAt: z.string(),
|
|
54
|
+
contextBanner: contextBannerSchema,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const patchFeedItemRequestSchema = z.object({
|
|
58
|
+
status: z.enum(["new", "seen", "acted_on"]),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Pure helpers (exported for direct testing — see home-feed-routes.test.ts)
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Map the server's wall-clock hour to a human greeting. Pure function;
|
|
67
|
+
* no LLM. The buckets match the plan:
|
|
68
|
+
* - 05:00–11:59 → "Good morning"
|
|
69
|
+
* - 12:00–16:59 → "Good afternoon"
|
|
70
|
+
* - 17:00–21:59 → "Good evening"
|
|
71
|
+
* - otherwise → "Welcome back"
|
|
72
|
+
*/
|
|
73
|
+
export function computeGreeting(now: Date): string {
|
|
74
|
+
const hour = now.getHours();
|
|
75
|
+
if (hour >= 5 && hour < 12) return "Good morning";
|
|
76
|
+
if (hour >= 12 && hour < 17) return "Good afternoon";
|
|
77
|
+
if (hour >= 17 && hour < 22) return "Good evening";
|
|
78
|
+
return "Welcome back";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Format a `timeAwaySeconds` value as a coarse relative-time label.
|
|
83
|
+
* Kept in-file since no other caller needs it yet; extract to a shared
|
|
84
|
+
* util module when a second caller appears.
|
|
85
|
+
*/
|
|
86
|
+
export function formatRelativeTime(seconds: number): string {
|
|
87
|
+
if (!Number.isFinite(seconds) || seconds < 60) return "just now";
|
|
88
|
+
if (seconds < 3600) {
|
|
89
|
+
const mins = Math.floor(seconds / 60);
|
|
90
|
+
return `${mins} minute${mins === 1 ? "" : "s"} ago`;
|
|
91
|
+
}
|
|
92
|
+
if (seconds < 86400) {
|
|
93
|
+
const hours = Math.floor(seconds / 3600);
|
|
94
|
+
return `${hours} hour${hours === 1 ? "" : "s"} ago`;
|
|
95
|
+
}
|
|
96
|
+
if (seconds < 172800) return "yesterday";
|
|
97
|
+
const days = Math.floor(seconds / 86400);
|
|
98
|
+
return `${days} day${days === 1 ? "" : "s"} ago`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Bucket `timeAwaySeconds` into coarse ranges used only for debug
|
|
103
|
+
* logging cardinality control. Not exposed to clients.
|
|
104
|
+
*/
|
|
105
|
+
function timeAwayBucket(seconds: number): string {
|
|
106
|
+
if (seconds < 1800) return "<1800";
|
|
107
|
+
if (seconds < 14400) return "1800-14400";
|
|
108
|
+
if (seconds < 43200) return "14400-43200";
|
|
109
|
+
if (seconds < 86400) return "43200-86400";
|
|
110
|
+
return ">=86400";
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// Handlers
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* `GET /v1/home/feed`.
|
|
119
|
+
*
|
|
120
|
+
* Required query param: `timeAwaySeconds` (non-negative integer). The
|
|
121
|
+
* handler reads the feed via `readHomeFeed()` (which has already
|
|
122
|
+
* applied TTL filtering), drops items whose `minTimeAway` exceeds the
|
|
123
|
+
* client-reported time away, then computes the context banner.
|
|
124
|
+
*/
|
|
125
|
+
export async function handleGetHomeFeed(req: Request): Promise<Response> {
|
|
126
|
+
const url = new URL(req.url);
|
|
127
|
+
const raw = url.searchParams.get("timeAwaySeconds");
|
|
128
|
+
if (raw === null) {
|
|
129
|
+
return httpError(
|
|
130
|
+
"BAD_REQUEST",
|
|
131
|
+
"Missing required query parameter: timeAwaySeconds",
|
|
132
|
+
400,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
const parsed = Number(raw);
|
|
136
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
137
|
+
return httpError(
|
|
138
|
+
"BAD_REQUEST",
|
|
139
|
+
"timeAwaySeconds must be a non-negative integer",
|
|
140
|
+
400,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
const timeAwaySeconds = parsed;
|
|
144
|
+
|
|
145
|
+
const feed = readHomeFeed();
|
|
146
|
+
const filtered = feed.items.filter((item) => {
|
|
147
|
+
if (item.minTimeAway === undefined) return true;
|
|
148
|
+
return item.minTimeAway <= timeAwaySeconds;
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const now = new Date();
|
|
152
|
+
const contextBanner = {
|
|
153
|
+
greeting: computeGreeting(now),
|
|
154
|
+
timeAwayLabel: formatRelativeTime(timeAwaySeconds),
|
|
155
|
+
newCount: filtered.filter((i) => i.status === "new").length,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
log.debug(
|
|
159
|
+
{
|
|
160
|
+
timeAwayBucket: timeAwayBucket(timeAwaySeconds),
|
|
161
|
+
totalItems: feed.items.length,
|
|
162
|
+
filteredItems: filtered.length,
|
|
163
|
+
newCount: contextBanner.newCount,
|
|
164
|
+
},
|
|
165
|
+
"GET /v1/home/feed",
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
return Response.json({
|
|
169
|
+
items: filtered,
|
|
170
|
+
updatedAt: feed.updatedAt,
|
|
171
|
+
contextBanner,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* `PATCH /v1/home/feed/:id`.
|
|
177
|
+
*
|
|
178
|
+
* Body: `{ status: "new" | "seen" | "acted_on" }`. Returns the updated
|
|
179
|
+
* `FeedItem` on success.
|
|
180
|
+
*
|
|
181
|
+
* Disambiguates the writer's `null` return by looking up the item via
|
|
182
|
+
* `readHomeFeed()` first — if the lookup finds the item and the patch
|
|
183
|
+
* still returns null, it's a write failure (500), not a missing id
|
|
184
|
+
* (404).
|
|
185
|
+
*/
|
|
186
|
+
export async function handlePatchFeedItem(
|
|
187
|
+
req: Request,
|
|
188
|
+
itemId: string,
|
|
189
|
+
): Promise<Response> {
|
|
190
|
+
let body: unknown;
|
|
191
|
+
try {
|
|
192
|
+
body = await req.json();
|
|
193
|
+
} catch {
|
|
194
|
+
return httpError("BAD_REQUEST", "Invalid JSON body", 400);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const parsed = patchFeedItemRequestSchema.safeParse(body);
|
|
198
|
+
if (!parsed.success) {
|
|
199
|
+
return httpError("BAD_REQUEST", "Invalid request body", 400, {
|
|
200
|
+
issues: parsed.error.issues,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
const status: FeedItemStatus = parsed.data.status;
|
|
204
|
+
|
|
205
|
+
// Pre-check for existence so we can distinguish "unknown id" (404)
|
|
206
|
+
// from "found, but write failed" (500). The writer applies the patch
|
|
207
|
+
// inside its coalescing queue against the same on-disk state we just
|
|
208
|
+
// read, so a race where the item disappears between the check and
|
|
209
|
+
// the write resolves cleanly as a 500 (write failed / no such item).
|
|
210
|
+
const currentFeed = readHomeFeed();
|
|
211
|
+
const existing = currentFeed.items.find((i) => i.id === itemId);
|
|
212
|
+
if (!existing) {
|
|
213
|
+
return httpError("NOT_FOUND", `Feed item not found: ${itemId}`, 404);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const updated = await patchFeedItemStatus(itemId, status);
|
|
217
|
+
if (!updated) {
|
|
218
|
+
log.warn(
|
|
219
|
+
{ itemId, status },
|
|
220
|
+
"patchFeedItemStatus returned null despite pre-check — treating as write failure",
|
|
221
|
+
);
|
|
222
|
+
return httpError(
|
|
223
|
+
"INTERNAL_ERROR",
|
|
224
|
+
"Failed to persist feed item status",
|
|
225
|
+
500,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return Response.json(updated);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* `POST /v1/home/feed/:id/actions/:actionId`.
|
|
234
|
+
*
|
|
235
|
+
* Looks up the item + action, creates a new conversation pre-seeded
|
|
236
|
+
* with the action's `prompt` as the first user message, and returns
|
|
237
|
+
* `{ conversationId }`. Any lookup failure → 404; conversation create
|
|
238
|
+
* error → 500.
|
|
239
|
+
*/
|
|
240
|
+
export async function handlePostFeedAction(
|
|
241
|
+
_req: Request,
|
|
242
|
+
itemId: string,
|
|
243
|
+
actionId: string,
|
|
244
|
+
): Promise<Response> {
|
|
245
|
+
const feed = readHomeFeed();
|
|
246
|
+
const item: FeedItem | undefined = feed.items.find((i) => i.id === itemId);
|
|
247
|
+
if (!item) {
|
|
248
|
+
return httpError("NOT_FOUND", `Feed item not found: ${itemId}`, 404);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const action = item.actions?.find((a) => a.id === actionId);
|
|
252
|
+
if (!action) {
|
|
253
|
+
return httpError(
|
|
254
|
+
"NOT_FOUND",
|
|
255
|
+
`Action not found on item ${itemId}: ${actionId}`,
|
|
256
|
+
404,
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
const conversation = createConversation({
|
|
262
|
+
title: action.label,
|
|
263
|
+
source: "home-feed",
|
|
264
|
+
});
|
|
265
|
+
await addMessage(
|
|
266
|
+
conversation.id,
|
|
267
|
+
"user",
|
|
268
|
+
JSON.stringify([{ type: "text", text: action.prompt }]),
|
|
269
|
+
);
|
|
270
|
+
return Response.json({ conversationId: conversation.id });
|
|
271
|
+
} catch (err) {
|
|
272
|
+
log.warn(
|
|
273
|
+
{ err, itemId, actionId },
|
|
274
|
+
"Failed to create conversation from feed action",
|
|
275
|
+
);
|
|
276
|
+
return httpError(
|
|
277
|
+
"INTERNAL_ERROR",
|
|
278
|
+
"Failed to create conversation for feed action",
|
|
279
|
+
500,
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ---------------------------------------------------------------------------
|
|
285
|
+
// Route definitions
|
|
286
|
+
// ---------------------------------------------------------------------------
|
|
287
|
+
|
|
288
|
+
export function homeFeedRouteDefinitions(): RouteDefinition[] {
|
|
289
|
+
return [
|
|
290
|
+
{
|
|
291
|
+
endpoint: "home/feed",
|
|
292
|
+
method: "GET",
|
|
293
|
+
handler: ({ req }) => handleGetHomeFeed(req),
|
|
294
|
+
summary: "Get home activity feed",
|
|
295
|
+
description:
|
|
296
|
+
"Return the current Home activity feed with TTL + time-away filtering applied. Also returns a context banner (greeting, relative time-away label, new-item count).",
|
|
297
|
+
tags: ["home"],
|
|
298
|
+
queryParams: [
|
|
299
|
+
{
|
|
300
|
+
name: "timeAwaySeconds",
|
|
301
|
+
type: "integer",
|
|
302
|
+
required: true,
|
|
303
|
+
description:
|
|
304
|
+
"Seconds since the user was last active in the client. Used to filter items with a `minTimeAway` gate and to compute the context-banner relative-time label.",
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
responseBody: getHomeFeedResponseSchema,
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
endpoint: "home/feed/:id",
|
|
311
|
+
method: "PATCH",
|
|
312
|
+
handler: ({ req, params }) => handlePatchFeedItem(req, params.id),
|
|
313
|
+
summary: "Patch home feed item status",
|
|
314
|
+
description:
|
|
315
|
+
"Update the `status` field of a single feed item (e.g. mark it seen or acted_on). Returns the updated item on success, 404 if the item does not exist, 500 if the underlying write fails.",
|
|
316
|
+
tags: ["home"],
|
|
317
|
+
requestBody: patchFeedItemRequestSchema,
|
|
318
|
+
responseBody: feedItemSchema,
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
endpoint: "home/feed/:id/actions/:actionId",
|
|
322
|
+
method: "POST",
|
|
323
|
+
handler: ({ req, params }) =>
|
|
324
|
+
handlePostFeedAction(req, params.id, params.actionId),
|
|
325
|
+
summary: "Trigger home feed action",
|
|
326
|
+
description:
|
|
327
|
+
"Create a new conversation pre-seeded with the action's prompt as the first user message. Returns the new `conversationId`.",
|
|
328
|
+
tags: ["home"],
|
|
329
|
+
responseBody: z.object({
|
|
330
|
+
conversationId: z.string(),
|
|
331
|
+
}),
|
|
332
|
+
},
|
|
333
|
+
];
|
|
334
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Home state HTTP routes.
|
|
3
|
+
*
|
|
4
|
+
* Exposes `GET /v1/home/state` so macOS (and other) clients can fetch
|
|
5
|
+
* the current `RelationshipState` snapshot. The normal path reads
|
|
6
|
+
* the JSON file produced by `writeRelationshipState()`; if that file
|
|
7
|
+
* is missing — e.g. on a fresh install before the writer has landed
|
|
8
|
+
* its first snapshot — the handler falls back to computing the
|
|
9
|
+
* state on-demand so the client never sees a 404 and the UI can
|
|
10
|
+
* always render.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
14
|
+
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
computeRelationshipState,
|
|
19
|
+
getRelationshipStatePath,
|
|
20
|
+
} from "../../home/relationship-state-writer.js";
|
|
21
|
+
import { getLogger } from "../../util/logger.js";
|
|
22
|
+
import { httpError } from "../http-errors.js";
|
|
23
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
24
|
+
|
|
25
|
+
const log = getLogger("home-state-routes");
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Response schema (shared with the OpenAPI generator and runtime validation)
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
const factSchema = z.object({
|
|
32
|
+
id: z.string(),
|
|
33
|
+
category: z.enum(["voice", "world", "priorities"]),
|
|
34
|
+
text: z.string(),
|
|
35
|
+
confidence: z.enum(["strong", "uncertain"]),
|
|
36
|
+
source: z.enum(["onboarding", "inferred"]),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const capabilitySchema = z.object({
|
|
40
|
+
id: z.string(),
|
|
41
|
+
name: z.string(),
|
|
42
|
+
description: z.string(),
|
|
43
|
+
tier: z.enum(["unlocked", "next-up", "earned"]),
|
|
44
|
+
gate: z.string(),
|
|
45
|
+
unlockHint: z.string().optional(),
|
|
46
|
+
ctaLabel: z.string().optional(),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const relationshipStateSchema = z.object({
|
|
50
|
+
version: z.literal(1),
|
|
51
|
+
assistantId: z.string(),
|
|
52
|
+
tier: z.union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)]),
|
|
53
|
+
progressPercent: z.number(),
|
|
54
|
+
facts: z.array(factSchema),
|
|
55
|
+
capabilities: z.array(capabilitySchema),
|
|
56
|
+
conversationCount: z.number(),
|
|
57
|
+
hatchedDate: z.string(),
|
|
58
|
+
assistantName: z.string(),
|
|
59
|
+
userName: z.string().optional(),
|
|
60
|
+
updatedAt: z.string(),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Handle `GET /v1/home/state`.
|
|
65
|
+
*
|
|
66
|
+
* Always computes a fresh snapshot so the response reflects the
|
|
67
|
+
* latest OAuth connection state, conversation count, and extracted
|
|
68
|
+
* facts — not just whatever the conversation-complete writer last
|
|
69
|
+
* persisted. This avoids serving stale capability tiers when the
|
|
70
|
+
* user connects an integration between turns, or when a delete/wipe
|
|
71
|
+
* flow mutates conversation count outside the turn-boundary writer.
|
|
72
|
+
*
|
|
73
|
+
* The persisted `relationship-state.json` remains useful as:
|
|
74
|
+
* - A seed for the existing-user backfill on daemon startup.
|
|
75
|
+
* - A fallback when live compute fails (e.g. DB not yet ready at
|
|
76
|
+
* cold start, or a transient filesystem error).
|
|
77
|
+
*
|
|
78
|
+
* The route does NOT write to disk or emit SSE on read — writes are
|
|
79
|
+
* still owned exclusively by the writer so turn-boundary SSE events
|
|
80
|
+
* remain tied to real state transitions rather than GET traffic.
|
|
81
|
+
*/
|
|
82
|
+
export async function handleGetHomeState(): Promise<Response> {
|
|
83
|
+
try {
|
|
84
|
+
const state = await computeRelationshipState();
|
|
85
|
+
return Response.json(state);
|
|
86
|
+
} catch (computeErr) {
|
|
87
|
+
log.warn(
|
|
88
|
+
{ err: computeErr },
|
|
89
|
+
"Live compute failed; falling back to persisted relationship-state.json",
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const path = getRelationshipStatePath();
|
|
94
|
+
if (existsSync(path)) {
|
|
95
|
+
try {
|
|
96
|
+
const raw = readFileSync(path, "utf-8");
|
|
97
|
+
const parsed: unknown = JSON.parse(raw);
|
|
98
|
+
const validated = relationshipStateSchema.safeParse(parsed);
|
|
99
|
+
if (validated.success) {
|
|
100
|
+
return Response.json(validated.data);
|
|
101
|
+
}
|
|
102
|
+
log.warn(
|
|
103
|
+
{ path, issues: validated.error.issues },
|
|
104
|
+
"Persisted relationship-state.json failed schema validation",
|
|
105
|
+
);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
log.warn(
|
|
108
|
+
{ err, path },
|
|
109
|
+
"Failed to read persisted relationship-state.json as fallback",
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return httpError(
|
|
115
|
+
"INTERNAL_ERROR",
|
|
116
|
+
"Failed to compute relationship state",
|
|
117
|
+
500,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// Route definitions
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
export function homeStateRouteDefinitions(): RouteDefinition[] {
|
|
126
|
+
return [
|
|
127
|
+
{
|
|
128
|
+
endpoint: "home/state",
|
|
129
|
+
method: "GET",
|
|
130
|
+
handler: () => handleGetHomeState(),
|
|
131
|
+
summary: "Get relationship state",
|
|
132
|
+
description:
|
|
133
|
+
"Return the current `RelationshipState` snapshot. Reads the persisted `relationship-state.json` when present; falls back to an on-demand compute so fresh installs never see a 404.",
|
|
134
|
+
tags: ["home"],
|
|
135
|
+
responseBody: relationshipStateSchema,
|
|
136
|
+
},
|
|
137
|
+
];
|
|
138
|
+
}
|
|
@@ -21,8 +21,8 @@ import * as pendingInteractions from "../pending-interactions.js";
|
|
|
21
21
|
* the HTTP endpoint and the WS relay path so they share the same validation
|
|
22
22
|
* and resolution semantics.
|
|
23
23
|
*
|
|
24
|
-
* Success → the pending interaction was consumed and the conversation
|
|
25
|
-
*
|
|
24
|
+
* Success → the pending interaction was consumed and the conversation was
|
|
25
|
+
* notified.
|
|
26
26
|
*
|
|
27
27
|
* Error variants mirror the HTTP status codes the `/v1/host-browser-result`
|
|
28
28
|
* endpoint returns, so the caller can log/translate them consistently.
|
|
@@ -40,7 +40,7 @@ export type HostBrowserResultResolution =
|
|
|
40
40
|
* Shared resolver used by both the HTTP route handler and the WS
|
|
41
41
|
* `host_browser_result` frame handler. Looks up the pending interaction
|
|
42
42
|
* by requestId, validates its kind, and forwards the response to the
|
|
43
|
-
* owning conversation
|
|
43
|
+
* owning conversation.
|
|
44
44
|
*
|
|
45
45
|
* This function does NOT perform auth — callers are expected to have
|
|
46
46
|
* already authenticated the caller (the HTTP route uses
|
|
@@ -90,17 +90,6 @@ export function resolveHostBrowserResultByRequestId(frame: {
|
|
|
90
90
|
const normalizedContent = typeof content === "string" ? content : "";
|
|
91
91
|
const normalizedIsError = typeof isError === "boolean" ? isError : false;
|
|
92
92
|
|
|
93
|
-
// CLI shim path: pending interactions registered by /v1/browser-cdp carry
|
|
94
|
-
// a directBrowserResolve callback and are not bound to a Conversation.
|
|
95
|
-
// Resolve them in place without touching the conversation object.
|
|
96
|
-
if (interaction.directBrowserResolve) {
|
|
97
|
-
interaction.directBrowserResolve({
|
|
98
|
-
content: normalizedContent,
|
|
99
|
-
isError: normalizedIsError,
|
|
100
|
-
});
|
|
101
|
-
return { ok: true };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
93
|
// The host_browser kind always has a conversation attached at register time
|
|
105
94
|
// (HostBrowserProxy.request wires it through), so this guard exists so a
|
|
106
95
|
// future refactor of pending-interactions can change the type without
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* The intro (a short identity tagline) is generated via the
|
|
5
5
|
* /v1/btw endpoint and displayed on the Identity panel. To avoid redundant LLM
|
|
6
6
|
* calls, we cache the result for 4 hours with content-hash-based invalidation:
|
|
7
|
-
* when
|
|
7
|
+
* when IDENTITY.md, SOUL.md, or the guardian's per-user persona file change,
|
|
8
|
+
* the cache is busted.
|
|
8
9
|
*
|
|
9
10
|
* Storage uses the existing `memory_checkpoints` table (simple key-value store).
|
|
10
11
|
*/
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
getMemoryCheckpoint,
|
|
17
18
|
setMemoryCheckpoint,
|
|
18
19
|
} from "../../memory/checkpoints.js";
|
|
20
|
+
import { resolveGuardianPersona } from "../../prompts/persona-resolver.js";
|
|
19
21
|
import { getWorkspacePromptPath } from "../../util/platform.js";
|
|
20
22
|
|
|
21
23
|
// ---------------------------------------------------------------------------
|
|
@@ -29,7 +31,7 @@ const CHECKPOINT_KEY_HASH = "identity:intro:content_hash";
|
|
|
29
31
|
const CHECKPOINT_KEY_TIMESTAMP = "identity:intro:cached_at";
|
|
30
32
|
|
|
31
33
|
/** Workspace files whose content influences the identity intro. */
|
|
32
|
-
const IDENTITY_FILES = ["
|
|
34
|
+
const IDENTITY_FILES = ["IDENTITY.md", "SOUL.md"] as const;
|
|
33
35
|
|
|
34
36
|
// ---------------------------------------------------------------------------
|
|
35
37
|
// Helpers
|
|
@@ -48,7 +50,9 @@ function readWorkspaceFile(name: string): string {
|
|
|
48
50
|
|
|
49
51
|
/** Compute a SHA-256 hex hash of the concatenated identity file contents. */
|
|
50
52
|
export function computeIdentityContentHash(): string {
|
|
51
|
-
const
|
|
53
|
+
const staticFiles = IDENTITY_FILES.map(readWorkspaceFile).join("\n---\n");
|
|
54
|
+
const guardianPersona = resolveGuardianPersona() ?? "";
|
|
55
|
+
const combined = staticFiles + "\n---\n" + guardianPersona;
|
|
52
56
|
return createHash("sha256").update(combined).digest("hex");
|
|
53
57
|
}
|
|
54
58
|
|
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import { existsSync, readFileSync, statfsSync, statSync } from "node:fs";
|
|
6
6
|
import { availableParallelism, cpus, totalmem } from "node:os";
|
|
7
|
-
import { dirname, join } from "node:path";
|
|
8
|
-
import { fileURLToPath } from "node:url";
|
|
9
7
|
|
|
10
8
|
import { z } from "zod";
|
|
11
9
|
|
|
@@ -17,6 +15,7 @@ import {
|
|
|
17
15
|
getWorkspaceDir,
|
|
18
16
|
getWorkspacePromptPath,
|
|
19
17
|
} from "../../util/platform.js";
|
|
18
|
+
import { APP_VERSION } from "../../version.js";
|
|
20
19
|
import { WORKSPACE_MIGRATIONS } from "../../workspace/migrations/registry.js";
|
|
21
20
|
import { getLastWorkspaceMigrationId } from "../../workspace/migrations/runner.js";
|
|
22
21
|
import { httpError } from "../http-errors.js";
|
|
@@ -370,19 +369,6 @@ function getCpuInfo(): CpuInfo {
|
|
|
370
369
|
};
|
|
371
370
|
}
|
|
372
371
|
|
|
373
|
-
function getPackageVersion(): string | undefined {
|
|
374
|
-
try {
|
|
375
|
-
const pkgPath = join(
|
|
376
|
-
dirname(fileURLToPath(import.meta.url)),
|
|
377
|
-
"../../../package.json",
|
|
378
|
-
);
|
|
379
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
380
|
-
return pkg.version;
|
|
381
|
-
} catch {
|
|
382
|
-
return undefined;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
372
|
export function handleHealth(): Response {
|
|
387
373
|
return Response.json({ status: "ok" });
|
|
388
374
|
}
|
|
@@ -398,7 +384,7 @@ export function handleDetailedHealth(): Response {
|
|
|
398
384
|
return Response.json({
|
|
399
385
|
status: "healthy",
|
|
400
386
|
timestamp: new Date().toISOString(),
|
|
401
|
-
version:
|
|
387
|
+
version: APP_VERSION,
|
|
402
388
|
disk: getDiskSpaceInfo(),
|
|
403
389
|
memory: getMemoryInfo(),
|
|
404
390
|
cpu: getCpuInfo(),
|
|
@@ -424,7 +410,7 @@ export function handleGetIdentity(): Response {
|
|
|
424
410
|
const content = readFileSync(identityPath, "utf-8");
|
|
425
411
|
const fields = parseIdentityFields(content);
|
|
426
412
|
|
|
427
|
-
const version =
|
|
413
|
+
const version = APP_VERSION;
|
|
428
414
|
|
|
429
415
|
// Read createdAt from IDENTITY.md file birthtime
|
|
430
416
|
let createdAt: string | undefined;
|