@vellumai/assistant 0.6.4 → 0.6.6
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/.prettierignore +5 -0
- package/AGENTS.md +9 -1
- package/ARCHITECTURE.md +43 -49
- package/Dockerfile +17 -3
- package/README.md +3 -4
- package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
- package/bun.lock +8 -3
- package/docs/architecture/integrations.md +33 -59
- package/docs/architecture/memory.md +25 -30
- package/docs/architecture/security.md +19 -18
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/error-handling.md +111 -0
- package/docs/plugins.md +761 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +2 -1
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/knip.json +9 -2
- package/node_modules/@vellumai/ces-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
- package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
- package/node_modules/@vellumai/credential-storage/package.json +2 -2
- package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
- package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
- package/node_modules/@vellumai/egress-proxy/package.json +2 -2
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/openapi.yaml +334 -78
- package/package.json +6 -3
- package/scripts/generate-openapi.ts +50 -11
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
- package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
- package/src/__tests__/agent-loop.test.ts +112 -1
- package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
- package/src/__tests__/anthropic-provider.test.ts +171 -2
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/approval-cascade.test.ts +36 -10
- package/src/__tests__/approval-routes-http.test.ts +134 -10
- package/src/__tests__/assistant-attachments.test.ts +44 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
- package/src/__tests__/browser-skill-endstate.test.ts +51 -182
- package/src/__tests__/btw-routes.test.ts +47 -1
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/call-controller.test.ts +1 -2
- package/src/__tests__/call-site-routing-provider.test.ts +214 -0
- package/src/__tests__/catalog-cache.test.ts +96 -4
- package/src/__tests__/channel-approval-routes.test.ts +4 -4
- package/src/__tests__/channel-reply-delivery.test.ts +300 -2
- package/src/__tests__/checker.test.ts +870 -655
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
- package/src/__tests__/compaction-events.test.ts +501 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/config-analysis.test.ts +11 -28
- package/src/__tests__/config-loader-backfill.test.ts +174 -0
- package/src/__tests__/config-loader-corrupt.test.ts +183 -0
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
- package/src/__tests__/config-model-image-provider.test.ts +110 -0
- package/src/__tests__/config-schema-cmd.test.ts +11 -5
- package/src/__tests__/config-schema.test.ts +440 -114
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +72 -73
- package/src/__tests__/contacts-tools.test.ts +26 -0
- package/src/__tests__/contacts-write.test.ts +4 -4
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-token-estimator.test.ts +191 -1
- package/src/__tests__/context-window-manager.test.ts +883 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +32 -15
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +86 -46
- package/src/__tests__/conversation-agent-loop.test.ts +435 -216
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +36 -10
- package/src/__tests__/conversation-error.test.ts +37 -6
- package/src/__tests__/conversation-history-web-search.test.ts +7 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +34 -12
- package/src/__tests__/conversation-lifecycle.test.ts +336 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
- package/src/__tests__/conversation-pairing.test.ts +174 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +32 -15
- package/src/__tests__/conversation-process-callsite.test.ts +309 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +44 -21
- package/src/__tests__/conversation-queue.test.ts +68 -38
- package/src/__tests__/conversation-routes-disk-view.test.ts +36 -7
- package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +2877 -152
- package/src/__tests__/conversation-runtime-workspace.test.ts +35 -50
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-skill-tools.test.ts +12 -146
- package/src/__tests__/conversation-slash-queue.test.ts +39 -19
- package/src/__tests__/conversation-slash-unknown.test.ts +53 -16
- package/src/__tests__/conversation-speed-override.test.ts +36 -12
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
- package/src/__tests__/conversation-title-service.test.ts +118 -2
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
- package/src/__tests__/conversation-unread-route.test.ts +2 -2
- package/src/__tests__/conversation-usage.test.ts +4 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +33 -9
- package/src/__tests__/conversation-workspace-injection.test.ts +46 -15
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +46 -15
- package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +5 -2
- package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
- package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
- package/src/__tests__/credential-vault-unit.test.ts +135 -19
- package/src/__tests__/credentials-cli.test.ts +1 -9
- package/src/__tests__/cross-provider-web-search.test.ts +84 -0
- package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
- package/src/__tests__/delete-propagation.test.ts +437 -0
- package/src/__tests__/dm-backfill.test.ts +417 -0
- package/src/__tests__/dm-persistence.test.ts +227 -0
- package/src/__tests__/edit-propagation.test.ts +280 -0
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/ephemeral-permissions.test.ts +93 -3
- package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
- package/src/__tests__/estimator-calibration.test.ts +213 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +29 -10
- package/src/__tests__/file-write-tool.test.ts +151 -1
- package/src/__tests__/filing-service.test.ts +255 -0
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/gemini-provider.test.ts +0 -3
- package/src/__tests__/guardian-grant-minting.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +1 -1
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/heartbeat-service.test.ts +96 -15
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
- package/src/__tests__/host-proxy-interface.test.ts +36 -2
- package/src/__tests__/host-shell-tool.test.ts +124 -18
- package/src/__tests__/http-user-message-parity.test.ts +29 -1
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
- package/src/__tests__/injector-chain.test.ts +526 -0
- package/src/__tests__/intent-routing.test.ts +1 -66
- package/src/__tests__/llm-call-pipeline.test.ts +285 -0
- package/src/__tests__/llm-catalog-parity.test.ts +174 -0
- package/src/__tests__/llm-context-normalization.test.ts +121 -0
- package/src/__tests__/llm-resolver.test.ts +214 -0
- package/src/__tests__/llm-schema.test.ts +223 -0
- package/src/__tests__/managed-proxy-context.test.ts +6 -2
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
- package/src/__tests__/messaging-skill-split.test.ts +3 -34
- package/src/__tests__/migration-import-from-url.test.ts +621 -0
- package/src/__tests__/model-intents.test.ts +11 -83
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-fallback.test.ts +0 -10
- package/src/__tests__/notification-decision-identity.test.ts +0 -9
- package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
- package/src/__tests__/oauth-apps-routes.test.ts +1 -1
- package/src/__tests__/oauth-cli.test.ts +14 -12
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
- package/src/__tests__/oauth-providers-routes.test.ts +3 -2
- package/src/__tests__/oauth-store.test.ts +46 -78
- package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
- package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/openai-provider.test.ts +7 -0
- package/src/__tests__/openai-responses-provider.test.ts +396 -0
- package/src/__tests__/openrouter-provider-only.test.ts +135 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
- package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +1 -25
- package/src/__tests__/permission-mode.test.ts +16 -0
- package/src/__tests__/permission-types.test.ts +0 -1
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +377 -0
- package/src/__tests__/persona-resolver.test.ts +13 -13
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/pkb-autoinject.test.ts +37 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
- package/src/__tests__/platform.test.ts +5 -2
- package/src/__tests__/plugin-bootstrap.test.ts +483 -0
- package/src/__tests__/plugin-registry.test.ts +273 -0
- package/src/__tests__/plugin-route-contribution.test.ts +288 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +93 -14
- package/src/__tests__/profiler-routes.test.ts +1 -1
- package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
- package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
- package/src/__tests__/provider-error-scenarios.test.ts +135 -6
- package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
- package/src/__tests__/provider-registry-ollama.test.ts +1 -2
- package/src/__tests__/proxy-approval-callback.test.ts +69 -9
- package/src/__tests__/reaction-persistence.test.ts +561 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +0 -2
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
- package/src/__tests__/risk-classifier-parity.test.ts +230 -0
- package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
- package/src/__tests__/schedule-routes.test.ts +131 -1
- package/src/__tests__/scheduler-recurrence.test.ts +14 -70
- package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
- package/src/__tests__/secret-detection-handler.test.ts +0 -10
- package/src/__tests__/secret-ingress-http.test.ts +28 -0
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
- package/src/__tests__/secret-scanner-executor.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +29 -1
- package/src/__tests__/server-history-render.test.ts +31 -0
- package/src/__tests__/shell-identity.test.ts +0 -134
- package/src/__tests__/shell-parser-property.test.ts +13 -13
- package/src/__tests__/skill-cache-store.test.ts +182 -0
- package/src/__tests__/skills.test.ts +19 -33
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-skill.test.ts +3 -8
- package/src/__tests__/starter-bundle.test.ts +35 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
- package/src/__tests__/suggestion-routes.test.ts +259 -3
- package/src/__tests__/system-prompt.test.ts +22 -35
- package/src/__tests__/task-memory-cleanup.test.ts +1 -0
- package/src/__tests__/task-runner.test.ts +3 -1
- package/src/__tests__/task-scheduler.test.ts +3 -15
- package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
- package/src/__tests__/terminal-tools.test.ts +8 -0
- package/src/__tests__/test-preload.ts +11 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
- package/src/__tests__/thread-backfill.test.ts +941 -0
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -8
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
- package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
- package/src/__tests__/tool-executor.test.ts +201 -94
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/trust-store.test.ts +442 -109
- package/src/__tests__/update-bulletin-job.test.ts +389 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
- package/src/__tests__/user-plugin-loader.test.ts +191 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
- package/src/__tests__/voice-session-bridge.test.ts +39 -0
- package/src/__tests__/volume-security-guard.test.ts +3 -2
- package/src/__tests__/web-search-history.test.ts +337 -0
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
- package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
- package/src/__tests__/workspace-policy.test.ts +22 -16
- package/src/acp/client-handler.ts +1 -2
- package/src/agent/loop.ts +545 -115
- package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
- package/src/approvals/guardian-request-resolvers.ts +80 -0
- package/src/avatar/resvg-lazy.test.ts +136 -0
- package/src/avatar/resvg-lazy.ts +82 -9
- package/src/avatar/traits-png-sync.ts +21 -1
- package/src/backup/__tests__/backup-worker.test.ts +2 -13
- package/src/backup/backup-worker.ts +3 -15
- package/src/browser/__tests__/operations.test.ts +163 -0
- package/src/browser/identifiers.ts +51 -0
- package/src/browser/operations.ts +660 -0
- package/src/browser/types.ts +81 -0
- package/src/bundler/app-compiler.ts +84 -1
- package/src/calls/call-state.ts +2 -2
- package/src/calls/guardian-question-copy.ts +2 -2
- package/src/calls/telephony-stt-routing.ts +1 -1
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/channels/__tests__/types.test.ts +3 -3
- package/src/channels/types.ts +6 -4
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/__tests__/notifications.test.ts +87 -211
- package/src/cli/commands/__tests__/attachment.test.ts +438 -0
- package/src/cli/commands/__tests__/backup.test.ts +1 -1
- package/src/cli/commands/__tests__/browser.test.ts +554 -0
- package/src/cli/commands/__tests__/cache.test.ts +623 -0
- package/src/cli/commands/__tests__/email-list.test.ts +6 -0
- package/src/cli/commands/__tests__/email-send.test.ts +93 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +886 -0
- package/src/cli/commands/__tests__/inference-send.test.ts +463 -0
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
- package/src/cli/commands/__tests__/task.test.ts +913 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +606 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
- package/src/cli/commands/__tests__/ui.test.ts +1215 -0
- package/src/cli/commands/__tests__/watchers.test.ts +716 -0
- package/src/cli/commands/attachment.ts +182 -0
- package/src/cli/commands/backup.ts +2 -2
- package/src/cli/commands/browser.ts +350 -0
- package/src/cli/commands/cache.ts +341 -0
- package/src/cli/commands/clients.ts +138 -0
- package/src/cli/commands/completions.ts +2 -12
- package/src/cli/commands/config.ts +6 -6
- package/src/cli/commands/conversations-import.ts +347 -0
- package/src/cli/commands/conversations.ts +69 -8
- package/src/cli/commands/email.ts +234 -194
- package/src/cli/commands/image-generation.ts +299 -0
- package/src/cli/commands/inference.ts +200 -0
- package/src/cli/commands/memory.ts +127 -17
- package/src/cli/commands/notifications.ts +68 -103
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +2 -2
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
- package/src/cli/commands/skills.ts +3 -4
- package/src/cli/commands/stt.ts +339 -0
- package/src/cli/commands/task.ts +795 -0
- package/src/cli/commands/trust.ts +50 -19
- package/src/cli/commands/tts.ts +273 -0
- package/src/cli/commands/ui.ts +670 -0
- package/src/cli/commands/watchers.ts +509 -0
- package/src/cli/lib/daemon-credential-client.ts +0 -19
- package/src/cli/program.ts +39 -24
- package/src/cli.ts +0 -37
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +20 -1
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +69 -12
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-tool-registry.ts +0 -190
- package/src/config/env.ts +7 -2
- package/src/config/feature-flag-registry.json +42 -10
- package/src/config/llm-resolver.ts +128 -0
- package/src/config/loader.ts +194 -10
- package/src/config/raw-config-utils.ts +30 -2
- package/src/config/sanitize-for-transfer.ts +35 -0
- package/src/config/schema.ts +49 -41
- package/src/config/schemas/analysis.ts +3 -22
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/calls.ts +0 -4
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/filing.ts +2 -7
- package/src/config/schemas/heartbeat.ts +0 -5
- package/src/config/schemas/inference.ts +3 -23
- package/src/config/schemas/llm.ts +317 -0
- package/src/config/schemas/memory-processing.ts +1 -9
- package/src/config/schemas/notifications.ts +4 -11
- package/src/config/schemas/platform.ts +3 -9
- package/src/config/schemas/security.ts +33 -0
- package/src/config/schemas/services.ts +9 -4
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/schemas/tts.ts +64 -0
- package/src/config/schemas/updates.ts +1 -1
- package/src/config/schemas/workspace-git.ts +3 -40
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +96 -7
- package/src/context/__tests__/compact-prompt.test.ts +63 -0
- package/src/context/__tests__/microcompact.test.ts +805 -0
- package/src/context/estimator-calibration.ts +136 -0
- package/src/context/microcompact.ts +443 -0
- package/src/context/prompts/compact.md +26 -0
- package/src/context/token-estimator.ts +61 -3
- package/src/context/tool-result-truncation.ts +3 -63
- package/src/context/window-manager.ts +417 -39
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/executable-discovery.ts +19 -8
- package/src/credential-execution/process-manager.test.ts +109 -0
- package/src/credential-execution/process-manager.ts +65 -2
- package/src/credential-health/credential-health-service.ts +19 -6
- package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/approval-generators.ts +29 -4
- package/src/daemon/assistant-attachments.ts +24 -13
- package/src/daemon/classifier.ts +2 -2
- package/src/daemon/config-watcher.ts +0 -3
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/context-overflow-reducer.ts +4 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +162 -34
- package/src/daemon/conversation-agent-loop.ts +1282 -599
- package/src/daemon/conversation-attachments.ts +2 -6
- package/src/daemon/conversation-error.ts +36 -1
- package/src/daemon/conversation-history.ts +10 -19
- package/src/daemon/conversation-lifecycle.ts +59 -17
- package/src/daemon/conversation-messaging.ts +73 -4
- package/src/daemon/conversation-notifiers.ts +2 -110
- package/src/daemon/conversation-process.ts +24 -11
- package/src/daemon/conversation-queue-manager.ts +3 -0
- package/src/daemon/conversation-runtime-assembly.ts +1063 -211
- package/src/daemon/conversation-slash.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +389 -1
- package/src/daemon/conversation-tool-setup.ts +51 -9
- package/src/daemon/conversation-usage.ts +1 -1
- package/src/daemon/conversation.ts +197 -64
- package/src/daemon/external-plugins-bootstrap.ts +478 -0
- package/src/daemon/external-skills-bootstrap.ts +41 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/guardian-action-generators.ts +34 -14
- package/src/daemon/handlers/config-model.test.ts +86 -0
- package/src/daemon/handlers/config-model.ts +65 -12
- package/src/daemon/handlers/conversations.ts +9 -2
- package/src/daemon/handlers/shared.ts +39 -11
- package/src/daemon/handlers/skills.ts +7 -3
- package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
- package/src/daemon/lifecycle.ts +109 -82
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +63 -0
- package/src/daemon/message-types/messages.ts +21 -1
- package/src/daemon/message-types/trust.ts +0 -2
- package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
- package/src/daemon/pkb-context-tracker.test.ts +169 -0
- package/src/daemon/pkb-context-tracker.ts +125 -0
- package/src/daemon/pkb-reminder-builder.test.ts +70 -0
- package/src/daemon/pkb-reminder-builder.ts +31 -0
- package/src/daemon/providers-setup.ts +6 -0
- package/src/daemon/server.ts +122 -12
- package/src/daemon/shutdown-handlers.ts +2 -12
- package/src/daemon/tool-side-effects.ts +14 -65
- package/src/daemon/web-search-history.ts +126 -0
- package/src/events/domain-events.ts +0 -1
- package/src/filing/filing-service.ts +9 -10
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
- package/src/heartbeat/heartbeat-service.ts +99 -28
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/__tests__/feed-scheduler.test.ts +39 -11
- package/src/home/__tests__/rollup-producer.test.ts +44 -0
- package/src/home/assistant-feed-authoring.ts +4 -0
- package/src/home/emit-feed-event.ts +11 -0
- package/src/home/feed-scheduler.ts +20 -4
- package/src/home/feed-types.ts +97 -4
- package/src/home/relationship-state-writer.ts +2 -2
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/home/rollup-producer.ts +34 -5
- package/src/home/suggested-prompts.ts +101 -0
- package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
- package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
- package/src/ipc/__tests__/socket-path.test.ts +34 -0
- package/src/ipc/__tests__/task-ipc.test.ts +577 -0
- package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
- package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
- package/src/ipc/cli-client.ts +2 -1
- package/src/ipc/cli-server.ts +26 -8
- package/src/ipc/gateway-client.ts +6 -3
- package/src/ipc/routes/attachment.ts +114 -0
- package/src/ipc/routes/browser-context.ts +63 -0
- package/src/ipc/routes/browser.ts +97 -0
- package/src/ipc/routes/cache.ts +96 -0
- package/src/ipc/routes/get-contact.ts +16 -0
- package/src/ipc/routes/index.ts +31 -1
- package/src/ipc/routes/list-clients.ts +31 -0
- package/src/ipc/routes/merge-contacts.ts +17 -0
- package/src/ipc/routes/notification.ts +133 -0
- package/src/ipc/routes/rename-conversation.ts +59 -0
- package/src/ipc/routes/search-contacts.ts +19 -0
- package/src/ipc/routes/task-queue.ts +226 -0
- package/src/ipc/routes/task.ts +173 -0
- package/src/ipc/routes/ui-request.ts +50 -0
- package/src/ipc/routes/upsert-contact.ts +25 -0
- package/src/ipc/routes/watcher.ts +203 -0
- package/src/ipc/socket-path.ts +76 -0
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
- package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
- package/src/memory/admin.ts +18 -0
- package/src/memory/conversation-analyze-job.ts +14 -13
- package/src/memory/conversation-attention-store.ts +13 -6
- package/src/memory/conversation-crud.ts +133 -3
- package/src/memory/conversation-group-migration.ts +38 -6
- package/src/memory/conversation-queries.ts +57 -4
- package/src/memory/conversation-title-service.ts +32 -4
- package/src/memory/db-init.ts +10 -0
- package/src/memory/embedding-backend.ts +1 -1
- package/src/memory/embedding-gemini.test.ts +41 -2
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/graph/bootstrap.test.ts +282 -0
- package/src/memory/graph/bootstrap.ts +8 -5
- package/src/memory/graph/compaction.ts +299 -0
- package/src/memory/graph/consolidation.ts +4 -4
- package/src/memory/graph/conversation-graph-memory.ts +89 -29
- package/src/memory/graph/extraction.test.ts +272 -2
- package/src/memory/graph/extraction.ts +183 -53
- package/src/memory/graph/graph-search.test.ts +93 -0
- package/src/memory/graph/graph-search.ts +4 -1
- package/src/memory/graph/inspect.ts +2 -2
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.test.ts +459 -0
- package/src/memory/graph/retriever.ts +237 -48
- package/src/memory/graph/store.ts +41 -0
- package/src/memory/graph/tool-handlers.ts +27 -0
- package/src/memory/graph/tools.ts +6 -1
- package/src/memory/indexer.ts +5 -5
- package/src/memory/job-handlers/conversation-starters.ts +23 -20
- package/src/memory/job-handlers/summarization.ts +2 -2
- package/src/memory/job-utils.ts +7 -1
- package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
- package/src/memory/jobs/embed-pkb-file.ts +54 -0
- package/src/memory/jobs-store.ts +44 -3
- package/src/memory/jobs-worker.ts +4 -0
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/index.ts +5 -0
- package/src/memory/pkb/pkb-index.test.ts +369 -0
- package/src/memory/pkb/pkb-index.ts +255 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +252 -0
- package/src/memory/pkb/pkb-reconcile.ts +148 -0
- package/src/memory/pkb/pkb-search.test.ts +499 -0
- package/src/memory/pkb/pkb-search.ts +159 -0
- package/src/memory/pkb/types.ts +53 -0
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +147 -1
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/schema/oauth.ts +4 -1
- package/src/memory/slack-thread-store.ts +37 -0
- package/src/messaging/providers/gmail/adapter.ts +6 -16
- package/src/messaging/providers/gmail/client.ts +22 -0
- package/src/messaging/providers/gmail/types.ts +7 -0
- package/src/messaging/providers/slack/adapter.ts +14 -2
- package/src/messaging/providers/slack/backfill.test.ts +257 -0
- package/src/messaging/providers/slack/backfill.ts +101 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
- package/src/messaging/providers/slack/message-metadata.ts +123 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1421 -0
- package/src/messaging/providers/slack/render-transcript.ts +501 -0
- package/src/messaging/style-analyzer.ts +5 -2
- package/src/notifications/README.md +9 -5
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/decision-engine.ts +3 -9
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/preference-extractor.ts +2 -6
- package/src/notifications/signal.ts +1 -2
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +31 -14
- package/src/oauth/platform-connection.test.ts +47 -0
- package/src/oauth/platform-connection.ts +15 -5
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -106
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/permissions/approval-policy.test.ts +1223 -0
- package/src/permissions/approval-policy.ts +309 -0
- package/src/permissions/arg-parser.test.ts +161 -0
- package/src/permissions/arg-parser.ts +141 -0
- package/src/permissions/bash-risk-classifier.test.ts +1620 -0
- package/src/permissions/bash-risk-classifier.ts +950 -0
- package/src/permissions/checker.ts +348 -711
- package/src/permissions/command-registry.test.ts +774 -0
- package/src/permissions/command-registry.ts +1005 -0
- package/src/permissions/defaults.ts +28 -79
- package/src/permissions/file-risk-classifier.test.ts +535 -0
- package/src/permissions/file-risk-classifier.ts +274 -0
- package/src/permissions/gateway-threshold-reader.ts +196 -0
- package/src/permissions/prompter.ts +4 -0
- package/src/permissions/risk-types.ts +262 -0
- package/src/permissions/schedule-risk-classifier.test.ts +129 -0
- package/src/permissions/schedule-risk-classifier.ts +85 -0
- package/src/permissions/secret-prompter.ts +53 -2
- package/src/permissions/shell-identity.ts +2 -42
- package/src/permissions/skill-risk-classifier.test.ts +311 -0
- package/src/permissions/skill-risk-classifier.ts +214 -0
- package/src/permissions/trust-client.ts +52 -25
- package/src/permissions/trust-store-interface.ts +1 -6
- package/src/permissions/trust-store.ts +161 -62
- package/src/permissions/types.ts +25 -14
- package/src/permissions/web-risk-classifier.test.ts +170 -0
- package/src/permissions/web-risk-classifier.ts +89 -0
- package/src/permissions/workspace-policy.ts +9 -19
- package/src/platform/client.ts +19 -1
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +491 -0
- package/src/plugins/defaults/llm-call.ts +82 -0
- package/src/plugins/defaults/memory-retrieval.ts +226 -0
- package/src/plugins/defaults/overflow-reduce.ts +181 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +104 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +241 -0
- package/src/plugins/types.ts +1134 -0
- package/src/plugins/user-loader.ts +177 -0
- package/src/prompts/persona-resolver.ts +3 -3
- package/src/prompts/system-prompt.ts +19 -20
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/prompts/templates/SOUL.md +2 -2
- package/src/prompts/update-bulletin-job.ts +190 -0
- package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
- package/src/providers/__tests__/retry-callsite.test.ts +424 -0
- package/src/providers/anthropic/client.ts +183 -14
- package/src/providers/call-site-routing.ts +71 -0
- package/src/providers/gemini/client.ts +65 -2
- package/src/providers/managed-proxy/constants.ts +2 -1
- package/src/providers/model-catalog.ts +524 -33
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/openai/chat-completions-provider.ts +57 -1
- package/src/providers/openai/responses-provider.ts +86 -9
- package/src/providers/openrouter/client.ts +80 -9
- package/src/providers/provider-env-vars.ts +56 -0
- package/src/providers/provider-send-message.ts +22 -5
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/registry.ts +19 -8
- package/src/providers/retry.ts +174 -39
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
- package/src/providers/speech-to-text/provider-catalog.ts +17 -0
- package/src/providers/speech-to-text/resolve.ts +7 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +646 -0
- package/src/providers/speech-to-text/xai-realtime.ts +821 -0
- package/src/providers/speech-to-text/xai.test.ts +155 -0
- package/src/providers/speech-to-text/xai.ts +97 -0
- package/src/providers/types.ts +93 -3
- package/src/runtime/AGENTS.md +27 -18
- package/src/runtime/__tests__/agent-wake.test.ts +43 -2
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
- package/src/runtime/__tests__/client-registry.test.ts +293 -0
- package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
- package/src/runtime/agent-wake.ts +63 -22
- package/src/runtime/auth/route-policy.ts +4 -0
- package/src/runtime/btw-sidechain.ts +13 -3
- package/src/runtime/channel-reply-delivery.ts +106 -2
- package/src/runtime/client-registry.ts +261 -0
- package/src/runtime/decision-token.ts +116 -0
- package/src/runtime/gateway-client.ts +2 -2
- package/src/runtime/http-router.ts +32 -0
- package/src/runtime/http-server.ts +129 -9
- package/src/runtime/http-types.ts +23 -3
- package/src/runtime/interactive-ui.ts +362 -0
- package/src/runtime/invite-instruction-generator.ts +2 -2
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
- package/src/runtime/migrations/gcs-signed-url.ts +162 -0
- package/src/runtime/migrations/vbundle-builder.ts +1 -22
- package/src/runtime/migrations/vbundle-importer.ts +154 -9
- package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
- package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
- package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
- package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
- package/src/runtime/migrations/vbundle-validator.ts +15 -6
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +78 -0
- package/src/runtime/routes/approval-routes.ts +29 -17
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
- package/src/runtime/routes/avatar-routes.ts +20 -4
- package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
- package/src/runtime/routes/btw-routes.ts +1 -4
- package/src/runtime/routes/conversation-management-routes.ts +20 -2
- package/src/runtime/routes/conversation-routes.ts +351 -138
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +6 -4
- package/src/runtime/routes/events-routes.ts +16 -0
- package/src/runtime/routes/guardian-approval-interception.ts +33 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
- package/src/runtime/routes/home-feed-routes.ts +120 -2
- package/src/runtime/routes/inbound-message-handler.ts +987 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
- package/src/runtime/routes/integrations/slack/channel.ts +25 -3
- package/src/runtime/routes/llm-context-normalization.ts +23 -1
- package/src/runtime/routes/memory-item-routes.test.ts +1 -0
- package/src/runtime/routes/migration-routes.ts +720 -127
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
- package/src/runtime/routes/playground/deps.ts +56 -0
- package/src/runtime/routes/playground/force-compact.ts +73 -0
- package/src/runtime/routes/playground/guard.ts +37 -0
- package/src/runtime/routes/playground/index.ts +28 -0
- package/src/runtime/routes/playground/inject-failures.ts +159 -0
- package/src/runtime/routes/playground/reset-circuit.ts +115 -0
- package/src/runtime/routes/playground/seed-conversation.ts +139 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
- package/src/runtime/routes/playground/state.ts +78 -0
- package/src/runtime/routes/schedule-routes.ts +89 -8
- package/src/runtime/routes/settings-routes.ts +4 -2
- package/src/runtime/routes/trust-rules-routes.ts +30 -14
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +3 -2
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
- package/src/runtime/services/analyze-conversation.ts +12 -16
- package/src/runtime/skill-route-registry.ts +97 -15
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +7 -1
- package/src/schedule/scheduler.ts +56 -8
- package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
- package/src/security/__tests__/untrusted-content.test.ts +109 -0
- package/src/security/oauth2.ts +98 -35
- package/src/security/secure-keys.ts +7 -8
- package/src/security/token-manager.ts +27 -13
- package/src/security/untrusted-content.ts +102 -0
- package/src/skills/catalog-cache.ts +35 -9
- package/src/skills/catalog-install.ts +31 -3
- package/src/skills/skill-cache-store.ts +97 -0
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
- package/src/stt/daemon-batch-transcriber.ts +33 -0
- package/src/stt/stt-stream-session.ts +8 -1
- package/src/stt/types.ts +5 -1
- package/src/subagent/manager.ts +41 -13
- package/src/tasks/ephemeral-permissions.ts +9 -4
- package/src/telemetry/usage-telemetry-reporter.ts +27 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +234 -2
- package/src/tools/browser/browser-execution.ts +150 -54
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/credentials/tool-policy.ts +39 -5
- package/src/tools/credentials/vault.ts +9 -4
- package/src/tools/executor.ts +129 -73
- package/src/tools/filesystem/write.ts +52 -0
- package/src/tools/host-terminal/host-shell.ts +45 -5
- package/src/tools/memory/register.test.ts +185 -0
- package/src/tools/memory/register.ts +3 -1
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/network/web-fetch.ts +20 -10
- package/src/tools/network/web-search.ts +19 -4
- package/src/tools/permission-checker.ts +116 -46
- package/src/tools/policy-context.ts +29 -8
- package/src/tools/registry.ts +195 -6
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +0 -51
- package/src/tools/side-effects.ts +0 -11
- package/src/tools/skills/execute.ts +2 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/terminal/backends/native.ts +51 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +1 -0
- package/src/tools/tool-manifest.ts +6 -21
- package/src/tools/types.ts +40 -5
- package/src/tools/verification-control-plane-policy.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +240 -13
- package/src/tts/provider-catalog.ts +18 -0
- package/src/tts/providers/index.ts +2 -0
- package/src/tts/providers/xai-provider.ts +224 -0
- package/src/tts/types.ts +46 -0
- package/src/types/tar-stream.d.ts +66 -0
- package/src/util/json.ts +17 -0
- package/src/util/platform.ts +9 -4
- package/src/util/pricing.ts +41 -8
- package/src/watcher/engine.ts +1 -1
- package/src/watcher/providers/google-calendar.ts +134 -8
- package/src/watcher/providers/outlook-calendar.ts +42 -2
- package/src/workspace/git-service.ts +23 -4
- package/src/workspace/migrations/006-services-config.ts +2 -4
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
- package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +56 -0
- package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
- package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
- package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/registry.ts +28 -0
- package/src/workspace/provider-commit-message-generator.ts +19 -38
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
- package/src/__tests__/gmail-archive-gate.test.ts +0 -246
- package/src/__tests__/gmail-preferences.test.ts +0 -117
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/outlook-attachments.test.ts +0 -301
- package/src/__tests__/outlook-automation-tools.test.ts +0 -425
- package/src/__tests__/outlook-categories.test.ts +0 -212
- package/src/__tests__/outlook-compose-tools.test.ts +0 -325
- package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
- package/src/__tests__/outlook-follow-up.test.ts +0 -196
- package/src/__tests__/outlook-trash.test.ts +0 -77
- package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/__tests__/update-bulletin-format.test.ts +0 -181
- package/src/__tests__/update-bulletin-state.test.ts +0 -135
- package/src/__tests__/update-bulletin.test.ts +0 -478
- package/src/__tests__/update-template-contract.test.ts +0 -29
- package/src/cli/commands/doctor.ts +0 -341
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/config/bundled-skills/browser/SKILL.md +0 -88
- package/src/config/bundled-skills/browser/TOOLS.json +0 -516
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -66
- package/src/config/bundled-skills/gmail/SKILL.md +0 -221
- package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
- package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
- package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
- package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/google-calendar/types.ts +0 -97
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/outlook/SKILL.md +0 -196
- package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
- package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/config/bundled-skills/slack/SKILL.md +0 -108
- package/src/config/bundled-skills/tasks/SKILL.md +0 -37
- package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
- package/src/config/bundled-skills/tasks/icon.svg +0 -34
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
- package/src/config/bundled-skills/watcher/SKILL.md +0 -31
- package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/oauth/scope-policy.ts +0 -89
- package/src/prompts/templates/UPDATES.md +0 -50
- package/src/prompts/update-bulletin-format.ts +0 -85
- package/src/prompts/update-bulletin-state.ts +0 -58
- package/src/prompts/update-bulletin-template-path.ts +0 -13
- package/src/prompts/update-bulletin.ts +0 -139
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/shared/provider-env-vars.ts +0 -19
- package/src/signals/shotgun.ts +0 -203
- package/src/tools/watch/screen-watch.ts +0 -144
- package/src/tools/watch/watch-state.ts +0 -142
- package/src/tools/watcher/create.ts +0 -86
- package/src/tools/watcher/delete.ts +0 -36
- package/src/tools/watcher/digest.ts +0 -54
- package/src/tools/watcher/list.ts +0 -83
- package/src/tools/watcher/update.ts +0 -71
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure chronological thread-tag rendering for Slack transcripts.
|
|
3
|
+
*
|
|
4
|
+
* Given a list of stored messages (post-upgrade rows with structured metadata
|
|
5
|
+
* AND legacy pre-upgrade rows with `metadata === null`), produces a flat
|
|
6
|
+
* `{role, content}[]` chronologically ordered with compact thread tags so
|
|
7
|
+
* the model can reason across sibling threads in one channel.
|
|
8
|
+
*
|
|
9
|
+
* The function is pure: no I/O, no implicit clock reads. Time is taken from
|
|
10
|
+
* `opts.now` only when needed for relative formatting. Sort and tag rendering
|
|
11
|
+
* are deterministic.
|
|
12
|
+
*
|
|
13
|
+
* Consumers wire this into inbound history rendering and the compaction
|
|
14
|
+
* boundary.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
|
+
|
|
19
|
+
import type { ContentBlock, Message } from "../../../providers/types.js";
|
|
20
|
+
import type { SlackMessageMetadata } from "./message-metadata.js";
|
|
21
|
+
|
|
22
|
+
export interface RenderableSlackMessage {
|
|
23
|
+
role: "user" | "assistant";
|
|
24
|
+
content: string;
|
|
25
|
+
/** `null` indicates a legacy pre-upgrade row stored without Slack metadata. */
|
|
26
|
+
metadata: SlackMessageMetadata | null;
|
|
27
|
+
/**
|
|
28
|
+
* Sender display name to prepend to the tag line (e.g. `"@alice"`), or
|
|
29
|
+
* `null` to omit the label entirely. Callers should pass `null` when the
|
|
30
|
+
* label would be redundant with the `role` slot — i.e. assistant rows and
|
|
31
|
+
* user rows with no real Slack displayName. Reaction rows always need a
|
|
32
|
+
* subject, so they receive a role-derived fallback if `null` is passed.
|
|
33
|
+
*/
|
|
34
|
+
senderLabel: string | null;
|
|
35
|
+
/** Fallback sort key for legacy rows; ignored when metadata.channelTs is set. */
|
|
36
|
+
createdAt: number;
|
|
37
|
+
/**
|
|
38
|
+
* Full structured content blocks parsed from the persisted row, when
|
|
39
|
+
* available. Optional so existing fixtures and callers that only need the
|
|
40
|
+
* flattened `content` string continue to compile. `renderSlackTranscript`
|
|
41
|
+
* consumes this field to preserve replayable Anthropic blocks
|
|
42
|
+
* (`tool_use`, `tool_result`, `thinking`, `redacted_thinking`, `image`,
|
|
43
|
+
* `file`) in their original order, emitting the tag line inline at the
|
|
44
|
+
* position of the first `text` block. Non-replayable blocks
|
|
45
|
+
* (`ui_surface`, `server_tool_use`, `web_search_tool_result`, unknown
|
|
46
|
+
* types) are stripped; when stripping empties the row entirely, a
|
|
47
|
+
* fallback tag-line text block is emitted so chronology is preserved.
|
|
48
|
+
*/
|
|
49
|
+
readonly contentBlocks?: readonly ContentBlock[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface RenderOptions {
|
|
53
|
+
/** Reserved for future relative-time rendering; currently unused. */
|
|
54
|
+
now?: Date;
|
|
55
|
+
/** Cap rendered reactions per parent message; default 5. */
|
|
56
|
+
maxReactionsPerMessage?: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const DEFAULT_MAX_REACTIONS = 5;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Replayable Anthropic content-block types that we preserve verbatim from a
|
|
63
|
+
* persisted row when rendering the Slack chronological transcript.
|
|
64
|
+
*
|
|
65
|
+
* `text` is intentionally omitted — text content is subsumed into the tag
|
|
66
|
+
* line (e.g. `[11/14/23 14:25 @alice]: ...`) so callers reading the
|
|
67
|
+
* rendered output see one human-readable line per row rather than a raw
|
|
68
|
+
* text block stripped of thread context.
|
|
69
|
+
*
|
|
70
|
+
* Non-replayable types (`ui_surface`, `server_tool_use`,
|
|
71
|
+
* `web_search_tool_result`, unknown types) are dropped: `ui_surface` blocks
|
|
72
|
+
* are the assistant's ephemeral local UI scaffolding and not meaningful to
|
|
73
|
+
* replay; `server_tool_use` / `web_search_tool_result` carry provider-
|
|
74
|
+
* specific `encrypted_content` that becomes stale and is rejected by the
|
|
75
|
+
* provider on re-send.
|
|
76
|
+
*/
|
|
77
|
+
const REPLAYABLE_BLOCK_TYPES = new Set<ContentBlock["type"]>([
|
|
78
|
+
"tool_use",
|
|
79
|
+
"tool_result",
|
|
80
|
+
"thinking",
|
|
81
|
+
"redacted_thinking",
|
|
82
|
+
"image",
|
|
83
|
+
"file",
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Compute a short, stable, deterministic alias for a Slack message ts.
|
|
88
|
+
*
|
|
89
|
+
* Used as the "parent label" inside thread-reply tags so the model can
|
|
90
|
+
* cross-reference children with their parent without leaking raw ts values.
|
|
91
|
+
* First 6 hex chars of sha256(channelTs) prefixed with `M`.
|
|
92
|
+
*/
|
|
93
|
+
export function parentAlias(channelTs: string): string {
|
|
94
|
+
const hash = createHash("sha256").update(channelTs).digest("hex");
|
|
95
|
+
return `M${hash.slice(0, 6)}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Trailing signature of a reaction or reaction-overflow line, both of
|
|
100
|
+
* which end with a `parentAlias` target and a closing bracket:
|
|
101
|
+
* `[... reacted 👍 to M1a2b3c]`, `[... removed 👍 from M1a2b3c]`,
|
|
102
|
+
* `[…and N more reactions to M1a2b3c]`. Regular message tag lines end
|
|
103
|
+
* with the message body, not with `]`, so they never match.
|
|
104
|
+
*/
|
|
105
|
+
const REACTION_TAG_LINE_SUFFIX = /M[0-9a-f]{6}\]$/;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Whether a rendered tag-line string was produced by the reaction or
|
|
109
|
+
* reaction-overflow code paths (`renderReaction` / the overflow trailer).
|
|
110
|
+
*
|
|
111
|
+
* Reaction lines already embed the actor attribution inline
|
|
112
|
+
* (`[11/14/23 14:28 @assistant reacted 👍 to M1a2b3c]`), so consumers
|
|
113
|
+
* that flatten the rendered transcript and re-apply role labels should
|
|
114
|
+
* skip these lines to avoid double-attribution.
|
|
115
|
+
*
|
|
116
|
+
* Co-located with `renderReaction` and `parentAlias` so the format
|
|
117
|
+
* knowledge lives with the functions that own the line shape.
|
|
118
|
+
*/
|
|
119
|
+
export function isReactionTagLine(text: string): boolean {
|
|
120
|
+
return REACTION_TAG_LINE_SUFFIX.test(text);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Format a Slack ts (`"1700000000.000100"`) as `MM/DD/YY HH:MM` (UTC).
|
|
125
|
+
*
|
|
126
|
+
* Slack ts is `<unix-seconds>.<microseconds>`; we treat it as a unix epoch
|
|
127
|
+
* second value for display purposes. Pure — derives only from the ts string.
|
|
128
|
+
*/
|
|
129
|
+
function formatSlackTs(channelTs: string): string {
|
|
130
|
+
const seconds = Number.parseFloat(channelTs);
|
|
131
|
+
if (!Number.isFinite(seconds)) return "??/??/?? ??:??";
|
|
132
|
+
return formatEpochMs(seconds * 1000);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Format an epoch millisecond timestamp as `MM/DD/YY HH:MM` (UTC).
|
|
137
|
+
*/
|
|
138
|
+
function formatEpochMs(ms: number): string {
|
|
139
|
+
if (!Number.isFinite(ms)) return "??/??/?? ??:??";
|
|
140
|
+
const d = new Date(ms);
|
|
141
|
+
const mo = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
142
|
+
const da = String(d.getUTCDate()).padStart(2, "0");
|
|
143
|
+
const yy = String(d.getUTCFullYear() % 100).padStart(2, "0");
|
|
144
|
+
const hh = String(d.getUTCHours()).padStart(2, "0");
|
|
145
|
+
const mm = String(d.getUTCMinutes()).padStart(2, "0");
|
|
146
|
+
return `${mo}/${da}/${yy} ${hh}:${mm}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Sort key for chronological ordering.
|
|
151
|
+
*
|
|
152
|
+
* Post-upgrade rows are ordered by their Slack `channelTs`; legacy rows
|
|
153
|
+
* (metadata === null) fall back to `createdAt`. Both produce a numeric
|
|
154
|
+
* seconds-since-epoch value so they intermix correctly.
|
|
155
|
+
*/
|
|
156
|
+
function sortKey(msg: RenderableSlackMessage): number {
|
|
157
|
+
if (msg.metadata) {
|
|
158
|
+
const n = Number.parseFloat(msg.metadata.channelTs);
|
|
159
|
+
if (Number.isFinite(n)) return n;
|
|
160
|
+
}
|
|
161
|
+
// createdAt is epoch ms; convert to seconds for like-with-like comparison.
|
|
162
|
+
return msg.createdAt / 1000;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Render a single non-reaction message (post-upgrade or legacy) as one
|
|
167
|
+
* tagged line.
|
|
168
|
+
*
|
|
169
|
+
* Assistant rows emit their content verbatim with no bracketed wrapper.
|
|
170
|
+
* The `role` slot already conveys identity, and the assistant replies
|
|
171
|
+
* ~immediately after the triggering user message so the chronological
|
|
172
|
+
* adjacency carries the same information as a timestamp. Keeping a
|
|
173
|
+
* `[MM/DD/YY HH:MM]:` prefix on the assistant's own past turns caused
|
|
174
|
+
* the model to mimic the exact format as a literal prefix in new
|
|
175
|
+
* outbound Slack replies (`[04/22/26 21:25]: on it. ...`). Deleted
|
|
176
|
+
* assistant rows collapse to the short `[deleted]` sentinel so chronology
|
|
177
|
+
* is preserved without carrying a mimickable timestamp.
|
|
178
|
+
*
|
|
179
|
+
* Tradeoffs deliberately accepted by this simplification:
|
|
180
|
+
* - Thread arrows (`→ Mxxxxxx`) are dropped from assistant rows. In the
|
|
181
|
+
* common single-thread-at-a-time case, role alternation + chronological
|
|
182
|
+
* adjacency tells the model which user turn each assistant reply answers,
|
|
183
|
+
* so no attribution is lost. The degenerate case is a channel where the
|
|
184
|
+
* assistant is fielding two thread conversations in parallel and the
|
|
185
|
+
* model has to disambiguate which reply lands in which thread from the
|
|
186
|
+
* full chronological transcript — the bracketed arrow previously carried
|
|
187
|
+
* that signal and is now absent. The `<active_thread>` focus block
|
|
188
|
+
* (single thread by construction) is unaffected.
|
|
189
|
+
* - Edited assistant rows render only the latest content, not an edit
|
|
190
|
+
* marker. Edits are rare for the assistant and the latest content is the
|
|
191
|
+
* only replayable signal anyway.
|
|
192
|
+
*
|
|
193
|
+
* Any alternative "subtle" marker (e.g. an unbracketed `→ Mxxxxxx`) would
|
|
194
|
+
* reintroduce a consistent, mimickable prefix pattern — the very problem
|
|
195
|
+
* this function is designed to avoid — so we keep the content-only form.
|
|
196
|
+
*/
|
|
197
|
+
function renderMessage(msg: RenderableSlackMessage): string {
|
|
198
|
+
if (msg.role === "assistant") {
|
|
199
|
+
if (msg.metadata?.deletedAt !== undefined) return "[deleted]";
|
|
200
|
+
return msg.content;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const meta = msg.metadata;
|
|
204
|
+
const senderPart = msg.senderLabel ? ` ${msg.senderLabel}` : "";
|
|
205
|
+
if (!meta) {
|
|
206
|
+
// Legacy pre-upgrade row: flat render, no thread tag.
|
|
207
|
+
const time = formatEpochMs(msg.createdAt);
|
|
208
|
+
return `[${time}${senderPart}]: ${msg.content}`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const time = formatSlackTs(meta.channelTs);
|
|
212
|
+
|
|
213
|
+
if (meta.deletedAt !== undefined) {
|
|
214
|
+
const dtime = formatEpochMs(meta.deletedAt);
|
|
215
|
+
return `[${time}${senderPart} — deleted ${dtime}]`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
let head = `[${time}${senderPart}`;
|
|
219
|
+
if (meta.threadTs && meta.threadTs !== meta.channelTs) {
|
|
220
|
+
head += ` → ${parentAlias(meta.threadTs)}`;
|
|
221
|
+
}
|
|
222
|
+
if (meta.editedAt !== undefined) {
|
|
223
|
+
head += `, edited ${formatEpochMs(meta.editedAt)}`;
|
|
224
|
+
}
|
|
225
|
+
head += `]: ${msg.content}`;
|
|
226
|
+
return head;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Render a single reaction event as one tagged line.
|
|
231
|
+
*
|
|
232
|
+
* `[11/14/23 14:28 @bob reacted 👍 to M1a2b3c]` or
|
|
233
|
+
* `[11/14/23 14:28 @bob removed 👍 from M1a2b3c]`.
|
|
234
|
+
*/
|
|
235
|
+
function renderReaction(msg: RenderableSlackMessage): string | null {
|
|
236
|
+
const meta = msg.metadata;
|
|
237
|
+
if (!meta || meta.eventKind !== "reaction" || !meta.reaction) return null;
|
|
238
|
+
const time = formatSlackTs(meta.channelTs);
|
|
239
|
+
const actor =
|
|
240
|
+
msg.senderLabel ?? (msg.role === "assistant" ? "@assistant" : "@user");
|
|
241
|
+
const verb = meta.reaction.op === "added" ? "reacted" : "removed";
|
|
242
|
+
const prep = meta.reaction.op === "added" ? "to" : "from";
|
|
243
|
+
const target = parentAlias(meta.reaction.targetChannelTs);
|
|
244
|
+
return `[${time} ${actor} ${verb} ${meta.reaction.emoji} ${prep} ${target}]`;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Build the content blocks for a single non-reaction message.
|
|
249
|
+
*
|
|
250
|
+
* Emits the tag line (`[MM/DD/YY HH:MM @sender ...]: body`) inline at the position of
|
|
251
|
+
* the first `text` block in `contentBlocks`, and preserves any replayable
|
|
252
|
+
* blocks (`tool_use`, `tool_result`, `thinking`, `redacted_thinking`,
|
|
253
|
+
* `image`, `file`) in their original order. Non-replayable blocks
|
|
254
|
+
* (`ui_surface`, `server_tool_use`, `web_search_tool_result`, unknown types)
|
|
255
|
+
* are dropped.
|
|
256
|
+
*
|
|
257
|
+
* Special cases:
|
|
258
|
+
* - **Deleted rows**: always emit a single tag-line block; replayable blocks
|
|
259
|
+
* (if any) are discarded because the delete is a logical erasure.
|
|
260
|
+
* - **Legacy rows** (no structured `contentBlocks`, or empty array): fall
|
|
261
|
+
* back to a single tag-line block to preserve pre-plumbing behaviour.
|
|
262
|
+
* - **Pure tool-only rows** (`contentBlocks` present but no `text` block):
|
|
263
|
+
* emit only the replayable blocks — no tag line. Anthropic accepts role-
|
|
264
|
+
* correct messages with only tool blocks.
|
|
265
|
+
* - **All-non-replayable rows** (`contentBlocks` present but every block is
|
|
266
|
+
* filtered out — e.g. a row whose only blocks are `server_tool_use` or
|
|
267
|
+
* `ui_surface`): emit a single fallback tag-line text block annotated
|
|
268
|
+
* with the stripped block types/names. Dropping the row entirely would
|
|
269
|
+
* silently alter chronology and can orphan adjacent tool_result context
|
|
270
|
+
* in later repair/conversion steps.
|
|
271
|
+
*/
|
|
272
|
+
function buildMessageContentBlocks(
|
|
273
|
+
msg: RenderableSlackMessage,
|
|
274
|
+
tagLine: string,
|
|
275
|
+
): ContentBlock[] {
|
|
276
|
+
const isDeleted = msg.metadata?.deletedAt !== undefined;
|
|
277
|
+
const blocks = msg.contentBlocks;
|
|
278
|
+
|
|
279
|
+
// Deleted rows: single tag line, drop any replayable content.
|
|
280
|
+
if (isDeleted) {
|
|
281
|
+
return [{ type: "text", text: tagLine }];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Legacy / unplumbed rows: fall back to single tag line.
|
|
285
|
+
if (!blocks || blocks.length === 0) {
|
|
286
|
+
return [{ type: "text", text: tagLine }];
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const out: ContentBlock[] = [];
|
|
290
|
+
let tagEmitted = false;
|
|
291
|
+
const strippedLabels: string[] = [];
|
|
292
|
+
for (const block of blocks) {
|
|
293
|
+
if (block.type === "text") {
|
|
294
|
+
if (!tagEmitted) {
|
|
295
|
+
out.push({ type: "text", text: tagLine });
|
|
296
|
+
tagEmitted = true;
|
|
297
|
+
}
|
|
298
|
+
// Subsequent text blocks are already subsumed into the tag line.
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (REPLAYABLE_BLOCK_TYPES.has(block.type)) {
|
|
302
|
+
out.push(block);
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
// Non-replayable (ui_surface, server_tool_use, web_search_tool_result,
|
|
306
|
+
// unknown) — drop, but remember what we saw in case we need a fallback.
|
|
307
|
+
if (block.type === "server_tool_use") {
|
|
308
|
+
strippedLabels.push(`server_tool_use(${block.name})`);
|
|
309
|
+
} else {
|
|
310
|
+
strippedLabels.push(block.type);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Non-empty source fully filtered to nothing: emit a fallback tag line so
|
|
315
|
+
// the turn still appears in chronology. Annotate with the stripped block
|
|
316
|
+
// types/names so the model has a hint about what was there.
|
|
317
|
+
if (out.length === 0) {
|
|
318
|
+
const suffix =
|
|
319
|
+
strippedLabels.length > 0
|
|
320
|
+
? ` [stripped non-replayable: ${strippedLabels.join(", ")}]`
|
|
321
|
+
: "";
|
|
322
|
+
return [{ type: "text", text: `${tagLine}${suffix}` }];
|
|
323
|
+
}
|
|
324
|
+
return out;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Render a chronological transcript with compact thread tags.
|
|
329
|
+
*
|
|
330
|
+
* Sort is stable: messages with identical sort keys preserve their input
|
|
331
|
+
* order so callers controlling input ordering can break ties deterministically.
|
|
332
|
+
*
|
|
333
|
+
* Reactions are rendered as their own lines (`[time @actor reacted ... to Mxxx]`),
|
|
334
|
+
* but capped per-target at `opts.maxReactionsPerMessage` (default 5). Excess
|
|
335
|
+
* reactions on the same target are collapsed into a single trailer line
|
|
336
|
+
* (`[…and N more reactions to Mxxx]`, singular `reaction` when N===1), emitted
|
|
337
|
+
* at the point the overflow window closes — i.e. immediately before the next
|
|
338
|
+
* event that is not an overflowing reaction for the same target — so trailers
|
|
339
|
+
* stay in chronological position rather than clustered at the end.
|
|
340
|
+
*/
|
|
341
|
+
export function renderSlackTranscript(
|
|
342
|
+
messages: RenderableSlackMessage[],
|
|
343
|
+
opts?: RenderOptions,
|
|
344
|
+
): Message[] {
|
|
345
|
+
if (messages.length === 0) return [];
|
|
346
|
+
|
|
347
|
+
const maxReactions = Math.max(
|
|
348
|
+
1,
|
|
349
|
+
Math.floor(opts?.maxReactionsPerMessage ?? DEFAULT_MAX_REACTIONS),
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
// Stable sort: decorate-sort-undecorate so equal keys preserve input order.
|
|
353
|
+
const indexed = messages.map((m, i) => ({ m, i, k: sortKey(m) }));
|
|
354
|
+
indexed.sort((a, b) => {
|
|
355
|
+
if (a.k !== b.k) return a.k - b.k;
|
|
356
|
+
return a.i - b.i;
|
|
357
|
+
});
|
|
358
|
+
const sorted = indexed.map((x) => x.m);
|
|
359
|
+
|
|
360
|
+
// Per-target reaction counters used to enforce the cap.
|
|
361
|
+
const reactionCount = new Map<string, number>();
|
|
362
|
+
// Open per-target overflow windows. Excess reactions accumulate here; the
|
|
363
|
+
// window is closed (trailer emitted) as soon as the chronological walk
|
|
364
|
+
// reaches an event that is not an overflowing reaction for that target.
|
|
365
|
+
const overflowAccumulator = new Map<
|
|
366
|
+
string,
|
|
367
|
+
{ excess: number; role: "user" | "assistant" }
|
|
368
|
+
>();
|
|
369
|
+
|
|
370
|
+
const trailerMessage = (
|
|
371
|
+
target: string,
|
|
372
|
+
acc: { excess: number; role: "user" | "assistant" },
|
|
373
|
+
): Message => ({
|
|
374
|
+
role: acc.role,
|
|
375
|
+
content: [
|
|
376
|
+
{
|
|
377
|
+
type: "text" as const,
|
|
378
|
+
text: `[…and ${acc.excess} more ${acc.excess === 1 ? "reaction" : "reactions"} to ${parentAlias(target)}]`,
|
|
379
|
+
},
|
|
380
|
+
],
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
const flushOverflowExcept = (out: Message[], keepTarget: string | null) => {
|
|
384
|
+
for (const target of Array.from(overflowAccumulator.keys())) {
|
|
385
|
+
if (target === keepTarget) continue;
|
|
386
|
+
const acc = overflowAccumulator.get(target)!;
|
|
387
|
+
out.push(trailerMessage(target, acc));
|
|
388
|
+
overflowAccumulator.delete(target);
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
const out: Message[] = [];
|
|
393
|
+
for (const m of sorted) {
|
|
394
|
+
const meta = m.metadata;
|
|
395
|
+
if (meta?.eventKind === "reaction" && meta.reaction) {
|
|
396
|
+
const target = meta.reaction.targetChannelTs;
|
|
397
|
+
const seen = reactionCount.get(target) ?? 0;
|
|
398
|
+
if (seen < maxReactions) {
|
|
399
|
+
// Reaction fits under the cap for `target`. Any open overflow windows
|
|
400
|
+
// for other targets are now behind us chronologically — close them.
|
|
401
|
+
flushOverflowExcept(out, null);
|
|
402
|
+
reactionCount.set(target, seen + 1);
|
|
403
|
+
const line = renderReaction(m);
|
|
404
|
+
if (line !== null) {
|
|
405
|
+
out.push({
|
|
406
|
+
role: m.role,
|
|
407
|
+
content: [{ type: "text" as const, text: line }],
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
} else {
|
|
411
|
+
// Reaction overflows for `target`. Close any other open windows, then
|
|
412
|
+
// extend this target's open window.
|
|
413
|
+
flushOverflowExcept(out, target);
|
|
414
|
+
const acc = overflowAccumulator.get(target) ?? {
|
|
415
|
+
excess: 0,
|
|
416
|
+
role: m.role,
|
|
417
|
+
};
|
|
418
|
+
acc.excess += 1;
|
|
419
|
+
overflowAccumulator.set(target, acc);
|
|
420
|
+
}
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
// Non-reaction event: every open overflow window closes here.
|
|
424
|
+
flushOverflowExcept(out, null);
|
|
425
|
+
const tagLine = renderMessage(m);
|
|
426
|
+
const blocks = buildMessageContentBlocks(m, tagLine);
|
|
427
|
+
if (blocks.length === 0) continue;
|
|
428
|
+
out.push({
|
|
429
|
+
role: m.role,
|
|
430
|
+
content: blocks,
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// End of the walk: flush any still-open overflow windows.
|
|
435
|
+
flushOverflowExcept(out, null);
|
|
436
|
+
|
|
437
|
+
return filterOrphanToolPairs(out);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Final safety pass that drops unpaired `tool_use` ↔ `tool_result` blocks.
|
|
442
|
+
*
|
|
443
|
+
* Anthropic's API requires every `tool_use` in an assistant turn to be
|
|
444
|
+
* matched by a `tool_result` in the following user turn (and vice versa).
|
|
445
|
+
* In normal operation `renderSlackTranscript` emits fully-paired turns
|
|
446
|
+
* because the persisted transcript reflects completed tool exchanges, but
|
|
447
|
+
* edge cases (mid-turn compaction, partial failures, a race between
|
|
448
|
+
* producer persistence and consumer persistence) can leave an orphan in
|
|
449
|
+
* the rendered output. Sending an orphan to the provider hard-fails the
|
|
450
|
+
* entire request, so we defensively prune any unpaired block here.
|
|
451
|
+
*
|
|
452
|
+
* Server-side block types (`server_tool_use`, `web_search_tool_result`) are
|
|
453
|
+
* stripped earlier by `buildMessageContentBlocks` — they carry stale
|
|
454
|
+
* provider-specific `encrypted_content` and are never replayed — so they
|
|
455
|
+
* cannot reach this filter.
|
|
456
|
+
*
|
|
457
|
+
* A message that becomes empty after filtering (e.g. an assistant row that
|
|
458
|
+
* carried only an orphaned `tool_use`) is dropped entirely rather than
|
|
459
|
+
* emitted as `{role, content: []}` — empty-content messages are also
|
|
460
|
+
* rejected by the provider.
|
|
461
|
+
*/
|
|
462
|
+
function filterOrphanToolPairs(messages: Message[]): Message[] {
|
|
463
|
+
const produced = new Set<string>();
|
|
464
|
+
const consumed = new Set<string>();
|
|
465
|
+
for (const msg of messages) {
|
|
466
|
+
for (const b of msg.content) {
|
|
467
|
+
if (b.type === "tool_use") produced.add(b.id);
|
|
468
|
+
else if (b.type === "tool_result" || b.type === "web_search_tool_result")
|
|
469
|
+
consumed.add(b.tool_use_id);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
const out: Message[] = [];
|
|
473
|
+
for (const msg of messages) {
|
|
474
|
+
const kept: ContentBlock[] = [];
|
|
475
|
+
for (const b of msg.content) {
|
|
476
|
+
if (b.type === "tool_use" && !consumed.has(b.id)) continue;
|
|
477
|
+
if (
|
|
478
|
+
(b.type === "tool_result" || b.type === "web_search_tool_result") &&
|
|
479
|
+
!produced.has(b.tool_use_id)
|
|
480
|
+
)
|
|
481
|
+
continue;
|
|
482
|
+
kept.push(b);
|
|
483
|
+
}
|
|
484
|
+
if (kept.length > 0) out.push({ role: msg.role, content: kept });
|
|
485
|
+
}
|
|
486
|
+
return out;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Extract the first text-block text from each rendered message.
|
|
491
|
+
*
|
|
492
|
+
* Used by callers (e.g. the active-thread focus block) that need a flat
|
|
493
|
+
* `string[]` of rendered tag lines rather than the structured `Message[]`
|
|
494
|
+
* output. Messages with no text block yield an empty string.
|
|
495
|
+
*/
|
|
496
|
+
export function extractTagLineTexts(rendered: Message[]): string[] {
|
|
497
|
+
return rendered.map((msg) => {
|
|
498
|
+
const first = msg.content.find((b) => b.type === "text");
|
|
499
|
+
return first && first.type === "text" ? first.text : "";
|
|
500
|
+
});
|
|
501
|
+
}
|
|
@@ -127,7 +127,7 @@ export async function extractStylePatterns(
|
|
|
127
127
|
.map((e, i) => `--- Message ${i + 1} ---\n${e}`)
|
|
128
128
|
.join("\n\n");
|
|
129
129
|
|
|
130
|
-
const provider = await getConfiguredProvider();
|
|
130
|
+
const provider = await getConfiguredProvider("styleAnalyzer");
|
|
131
131
|
if (!provider) {
|
|
132
132
|
return { stylePatterns: [], contactObservations: [] };
|
|
133
133
|
}
|
|
@@ -147,7 +147,10 @@ export async function extractStylePatterns(
|
|
|
147
147
|
promptMessages,
|
|
148
148
|
[storeStyleAnalysisTool],
|
|
149
149
|
STYLE_EXTRACTION_SYSTEM_PROMPT,
|
|
150
|
-
{
|
|
150
|
+
{
|
|
151
|
+
signal: AbortSignal.timeout(30_000),
|
|
152
|
+
config: { callSite: "styleAnalyzer" },
|
|
153
|
+
},
|
|
151
154
|
);
|
|
152
155
|
|
|
153
156
|
const toolBlock = response.content.find((b) => b.type === "tool_use");
|
|
@@ -31,7 +31,7 @@ The candidate set is serialized into a compact `<conversation-candidates>` block
|
|
|
31
31
|
|
|
32
32
|
### 3. Decision
|
|
33
33
|
|
|
34
|
-
The decision engine (`decision-engine.ts`) sends the signal to an LLM (configured via `
|
|
34
|
+
The decision engine (`decision-engine.ts`) sends the signal to an LLM (configured via `llm.callSites.notificationDecision`) along with available channels, the user's preference summary, and the conversation candidate set. The LLM responds with a structured decision: whether to notify, which channels, rendered copy per channel, a deduplication key, and **per-channel conversation actions**.
|
|
35
35
|
|
|
36
36
|
**Conversation actions:** For each selected channel, the LLM decides:
|
|
37
37
|
|
|
@@ -538,10 +538,14 @@ Preferences are sanitized against prompt injection (angle brackets replaced with
|
|
|
538
538
|
|
|
539
539
|
## Configuration
|
|
540
540
|
|
|
541
|
-
|
|
541
|
+
The decision engine and preference extractor pick their per-call LLM config
|
|
542
|
+
from the unified `llm` block. Override defaults by setting either of:
|
|
542
543
|
|
|
543
|
-
| Key
|
|
544
|
-
|
|
|
545
|
-
| `
|
|
544
|
+
| Key | Type | Default | Description |
|
|
545
|
+
| ------------------------------------ | ------- | -------------- | --------------------------------------------------------------------------- |
|
|
546
|
+
| `llm.callSites.notificationDecision` | object | _(unset)_ | Provider/model/effort/etc. override for the decision engine call site |
|
|
547
|
+
| `llm.callSites.preferenceExtraction` | object | _(unset)_ | Provider/model/effort/etc. override for the preference extractor call site |
|
|
548
|
+
|
|
549
|
+
When a call site override is unset, the resolver falls back to `llm.default`.
|
|
546
550
|
|
|
547
551
|
The notification pipeline is always active -- signals are processed and dispatched as soon as the daemon is running. The audit trail (events, decisions, deliveries) is written for every signal.
|
|
@@ -8,8 +8,12 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Resolution order:
|
|
10
10
|
* 1. Explicit `reuse_existing` conversation action — highest precedence.
|
|
11
|
-
* 2. Binding-key reuse — for `continue_existing_conversation` channels
|
|
12
|
-
*
|
|
11
|
+
* 2. Binding-key reuse — for `continue_existing_conversation` channels:
|
|
12
|
+
* a. Inbound conversation lookup — checks the un-prefixed binding
|
|
13
|
+
* (sourceChannel, externalChatId) for a conversation created by
|
|
14
|
+
* the inbound message handler. Preferred for reply continuity.
|
|
15
|
+
* b. Notification-scoped binding — checks the `notification:`-prefixed
|
|
16
|
+
* binding for a prior notification conversation.
|
|
13
17
|
* 3. Default — creates a fresh conversation and, when binding context is
|
|
14
18
|
* present, upserts it into the external-conversation store for future reuse.
|
|
15
19
|
*/
|
|
@@ -78,8 +82,11 @@ export interface PairingOptions {
|
|
|
78
82
|
*
|
|
79
83
|
* Resolution precedence:
|
|
80
84
|
* 1. `options.conversationAction === "reuse_existing"` — reuse the explicit target.
|
|
81
|
-
* 2. `continue_existing_conversation` strategy with binding context
|
|
82
|
-
*
|
|
85
|
+
* 2. `continue_existing_conversation` strategy with binding context:
|
|
86
|
+
* a. Un-prefixed (inbound) binding — preferred for reply continuity so
|
|
87
|
+
* the user's replies include the notification in their history.
|
|
88
|
+
* b. `notification:`-prefixed binding — used when no inbound conversation
|
|
89
|
+
* exists yet (e.g. first notification before the user has messaged).
|
|
83
90
|
* 3. Create a new conversation (and upsert the binding when context is present).
|
|
84
91
|
*
|
|
85
92
|
* Invalid/stale targets at any level fall through to the next.
|
|
@@ -228,21 +235,73 @@ export async function pairDeliveryWithConversation(
|
|
|
228
235
|
bindingContext?.sourceChannel &&
|
|
229
236
|
bindingContext?.externalChatId
|
|
230
237
|
) {
|
|
231
|
-
//
|
|
232
|
-
//
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
238
|
+
// ── Step 1: Prefer the inbound conversation for reply continuity ──
|
|
239
|
+
//
|
|
240
|
+
// When the user has previously messaged in this channel, the inbound
|
|
241
|
+
// pipeline created a binding at the un-prefixed (sourceChannel,
|
|
242
|
+
// externalChatId) key. Posting to that conversation means the
|
|
243
|
+
// user's subsequent replies will include the notification in their
|
|
244
|
+
// conversation history — avoiding "split brain" where proactive
|
|
245
|
+
// messages live in one conversation and replies route to another.
|
|
246
|
+
//
|
|
247
|
+
// The source check is intentionally skipped here: the inbound
|
|
248
|
+
// conversation will have a different source (typically null) from
|
|
249
|
+
// notifications, but it is the correct target for reply continuity.
|
|
250
|
+
const inboundBinding = getBindingByChannelChat(
|
|
251
|
+
bindingContext.sourceChannel,
|
|
252
|
+
bindingContext.externalChatId,
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
if (inboundBinding) {
|
|
256
|
+
const inboundConversation = getConversation(
|
|
257
|
+
inboundBinding.conversationId,
|
|
241
258
|
);
|
|
242
259
|
|
|
243
|
-
|
|
260
|
+
if (inboundConversation) {
|
|
261
|
+
const message = await addMessage(
|
|
262
|
+
inboundConversation.id,
|
|
263
|
+
"assistant",
|
|
264
|
+
messageContent,
|
|
265
|
+
undefined,
|
|
266
|
+
{ skipIndexing: true },
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
log.info(
|
|
270
|
+
{
|
|
271
|
+
signalId: signal.signalId,
|
|
272
|
+
channel,
|
|
273
|
+
strategy,
|
|
274
|
+
conversationId: inboundConversation.id,
|
|
275
|
+
messageId: message.id,
|
|
276
|
+
bindingKey: `${bindingContext.sourceChannel}:${bindingContext.externalChatId}`,
|
|
277
|
+
},
|
|
278
|
+
"Appended notification to inbound conversation for reply continuity",
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
conversationId: inboundConversation.id,
|
|
283
|
+
messageId: message.id,
|
|
284
|
+
strategy,
|
|
285
|
+
createdNewConversation: false,
|
|
286
|
+
conversationFallbackUsed: false,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ── Step 2: Fall back to notification-scoped binding ──
|
|
292
|
+
//
|
|
293
|
+
// Before the user has ever messaged in this channel, there is no
|
|
294
|
+
// inbound binding. Check the notification-prefixed namespace for a
|
|
295
|
+
// prior notification conversation so successive deliveries still
|
|
296
|
+
// accumulate in the same thread.
|
|
297
|
+
const notificationBinding = getBindingByChannelChat(
|
|
298
|
+
notificationChannel(bindingContext.sourceChannel),
|
|
299
|
+
bindingContext.externalChatId,
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
if (notificationBinding) {
|
|
244
303
|
const boundConversation = getConversation(
|
|
245
|
-
|
|
304
|
+
notificationBinding.conversationId,
|
|
246
305
|
);
|
|
247
306
|
|
|
248
307
|
const effectiveSource =
|
|
@@ -272,7 +331,7 @@ export async function pairDeliveryWithConversation(
|
|
|
272
331
|
messageId: message.id,
|
|
273
332
|
bindingKey: `${bindingContext.sourceChannel}:${bindingContext.externalChatId}`,
|
|
274
333
|
},
|
|
275
|
-
"Reused bound conversation for channel destination",
|
|
334
|
+
"Reused bound notification conversation for channel destination",
|
|
276
335
|
);
|
|
277
336
|
|
|
278
337
|
return {
|
|
@@ -290,11 +349,11 @@ export async function pairDeliveryWithConversation(
|
|
|
290
349
|
{
|
|
291
350
|
signalId: signal.signalId,
|
|
292
351
|
channel,
|
|
293
|
-
boundConversationId:
|
|
352
|
+
boundConversationId: notificationBinding.conversationId,
|
|
294
353
|
boundConversationExists: !!boundConversation,
|
|
295
354
|
boundConversationSource: boundConversation?.source,
|
|
296
355
|
},
|
|
297
|
-
"Bound conversation stale or invalid — creating fresh conversation",
|
|
356
|
+
"Bound notification conversation stale or invalid — creating fresh conversation",
|
|
298
357
|
);
|
|
299
358
|
}
|
|
300
359
|
}
|