@vellumai/assistant 0.8.2 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +11 -12
- package/docker-entrypoint.sh +13 -2
- package/docker-init-apt-root.sh +79 -6
- package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
- package/openapi.yaml +945 -36
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +271 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- package/src/__tests__/agent-loop.test.ts +88 -3
- package/src/__tests__/anthropic-provider.test.ts +272 -0
- package/src/__tests__/approval-cascade.test.ts +1 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/channel-delivery-store.test.ts +193 -0
- package/src/__tests__/channel-reply-delivery.test.ts +284 -5
- package/src/__tests__/channel-retry-sweep.test.ts +274 -1
- package/src/__tests__/compaction-events.test.ts +1 -1
- package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
- package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/context-token-estimator.test.ts +112 -57
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
- package/src/__tests__/conversation-agent-loop.test.ts +77 -3
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-clean-command.test.ts +137 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +161 -0
- package/src/__tests__/conversation-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-media-retry.test.ts +19 -8
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-process-callsite.test.ts +1 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +290 -85
- package/src/__tests__/conversation-seed-composer.test.ts +66 -4
- package/src/__tests__/conversation-slash-commands.test.ts +36 -8
- package/src/__tests__/conversation-slash-queue.test.ts +1 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
- package/src/__tests__/conversation-speed-override.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +6 -0
- package/src/__tests__/cu-unified-flow.test.ts +10 -1
- package/src/__tests__/date-context.test.ts +45 -0
- package/src/__tests__/dm-backfill.test.ts +64 -0
- package/src/__tests__/dm-persistence.test.ts +33 -0
- package/src/__tests__/document-find-replace.test.ts +501 -0
- package/src/__tests__/external-plugin-loader.test.ts +91 -19
- package/src/__tests__/first-greeting.test.ts +23 -2
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/headless-browser-navigate.test.ts +172 -0
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/host-app-control-proxy.test.ts +241 -0
- package/src/__tests__/host-bash-proxy.test.ts +6 -0
- package/src/__tests__/host-browser-proxy.test.ts +10 -0
- package/src/__tests__/host-cu-proxy.test.ts +8 -1
- package/src/__tests__/host-file-proxy.test.ts +8 -1
- package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
- package/src/__tests__/host-transfer-proxy.test.ts +8 -1
- package/src/__tests__/identity-routes.test.ts +57 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
- package/src/__tests__/injector-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +7 -0
- package/src/__tests__/injector-document-comments.test.ts +378 -0
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -2
- package/src/__tests__/list-messages-attachments.test.ts +21 -17
- package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
- package/src/__tests__/list-messages-page-latest.test.ts +130 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
- package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +3 -0
- package/src/__tests__/llm-context-normalization.test.ts +0 -2
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
- package/src/__tests__/llm-resolver.test.ts +340 -3
- package/src/__tests__/log-export-routes.test.ts +99 -2
- package/src/__tests__/managed-profile-guard.test.ts +10 -0
- package/src/__tests__/message-queue-steer.test.ts +114 -0
- package/src/__tests__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
- package/src/__tests__/openai-provider.test.ts +323 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
- package/src/__tests__/openai-responses-provider.test.ts +4 -4
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
- package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
- package/src/__tests__/platform-proxy-context.test.ts +6 -1
- package/src/__tests__/platform.test.ts +0 -3
- package/src/__tests__/plugin-source-watcher.test.ts +302 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
- package/src/__tests__/plugin-types.test.ts +2 -2
- package/src/__tests__/process-message-background-slack.test.ts +1 -51
- package/src/__tests__/process-message-display-content.test.ts +21 -16
- package/src/__tests__/provider-catalog-visibility.test.ts +16 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +83 -4
- package/src/__tests__/steer-tool-repair.test.ts +249 -0
- package/src/__tests__/system-prompt.test.ts +57 -101
- package/src/__tests__/terminal-tools.test.ts +11 -1
- package/src/__tests__/thinking-block-replay.test.ts +113 -0
- package/src/__tests__/thread-backfill.test.ts +370 -22
- package/src/__tests__/tool-executor.test.ts +90 -1
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/web-fetch.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +88 -5
- package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
- package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
- package/src/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/agent/attachments.ts +1 -0
- package/src/agent/loop.ts +208 -22
- package/src/background-wake/next-wake.test.ts +289 -0
- package/src/background-wake/next-wake.ts +172 -0
- package/src/browser/operations.ts +15 -0
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +14 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +469 -0
- package/src/cli/commands/conversations.ts +128 -1
- package/src/cli/commands/inference-providers.ts +147 -1
- package/src/cli/commands/memory-v2.ts +308 -0
- package/src/cli/commands/notifications.ts +89 -37
- package/src/cli/commands/plugins.ts +67 -0
- package/src/cli/commands/schedules.ts +297 -5
- package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
- package/src/cli/lib/install-from-github.ts +8 -9
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/program.ts +14 -0
- package/src/cli/utils/conversation-id.ts +17 -5
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
- package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
- package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
- package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +8 -0
- package/src/config/bundled-tool-registry.ts +22 -12
- package/src/config/call-site-defaults.ts +124 -0
- package/src/config/feature-flag-registry.json +111 -23
- package/src/config/llm-resolver.ts +66 -1
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +7 -3
- package/src/config/schemas/call-site-catalog.ts +21 -0
- package/src/config/schemas/channels.ts +9 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +14 -0
- package/src/config/schemas/llm.ts +4 -3
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +51 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/context/compactor.ts +80 -13
- package/src/context/token-estimator.ts +72 -31
- package/src/context/window-manager.ts +25 -0
- package/src/credential-health/credential-health-service.ts +34 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +231 -23
- package/src/daemon/conversation-agent-loop.ts +252 -56
- package/src/daemon/conversation-lifecycle.ts +142 -116
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +273 -0
- package/src/daemon/conversation-queue-manager.ts +14 -0
- package/src/daemon/conversation-runtime-assembly.ts +144 -75
- package/src/daemon/conversation-slash.ts +37 -5
- package/src/daemon/conversation-surfaces.ts +45 -2
- package/src/daemon/conversation-tool-setup.ts +7 -0
- package/src/daemon/conversation.ts +42 -12
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/first-greeting.ts +10 -0
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +449 -0
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +80 -0
- package/src/daemon/handlers/shared.ts +92 -29
- package/src/daemon/host-app-control-proxy.ts +69 -18
- package/src/daemon/host-bash-proxy.ts +1 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/host-file-proxy.ts +1 -1
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/host-transfer-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +67 -65
- package/src/daemon/memory-v2-startup.ts +49 -13
- package/src/daemon/message-protocol.ts +4 -0
- package/src/daemon/message-types/conversations.ts +8 -0
- package/src/daemon/message-types/document-comments.ts +50 -0
- package/src/daemon/message-types/messages.ts +68 -1
- package/src/daemon/message-types/notifications.ts +21 -0
- package/src/daemon/message-types/surfaces.ts +3 -1
- package/src/daemon/message-types/web-activity.ts +57 -0
- package/src/daemon/pkb-reminder-builder.test.ts +10 -53
- package/src/daemon/pkb-reminder-builder.ts +4 -19
- package/src/daemon/plugin-source-watcher.ts +135 -3
- package/src/daemon/process-message.ts +72 -12
- package/src/daemon/query-complexity-router.ts +75 -0
- package/src/daemon/skill-memory-refresh.ts +5 -1
- package/src/daemon/trust-context.ts +6 -0
- package/src/daemon/wake-target-adapter.ts +2 -0
- package/src/documents/document-comments-store.test.ts +338 -0
- package/src/documents/document-comments-store.ts +237 -0
- package/src/documents/document-store.ts +202 -0
- package/src/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -1
- package/src/heartbeat/heartbeat-service.ts +35 -191
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/__tests__/suggested-prompts.test.ts +33 -2
- package/src/home/feed-types.ts +20 -3
- package/src/home/home-content-refresh.ts +52 -0
- package/src/home/home-greeting-cache.ts +69 -0
- package/src/home/home-greeting.ts +94 -0
- package/src/home/suggested-prompts.ts +177 -9
- package/src/ipc/cli-client.ts +147 -45
- package/src/memory/__tests__/conversation-queries.test.ts +220 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +407 -10
- package/src/memory/conversation-crud.ts +133 -43
- package/src/memory/conversation-queries.ts +87 -1
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +22 -0
- package/src/memory/delivery-crud.ts +41 -0
- package/src/memory/delivery-status.ts +141 -15
- package/src/memory/external-conversation-store.ts +32 -1
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
- package/src/memory/graph/conversation-graph-memory.ts +18 -6
- package/src/memory/graph/tools.ts +6 -37
- package/src/memory/invite-store.ts +53 -0
- package/src/memory/jobs-worker.ts +21 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/memory-retrospective-constants.ts +28 -0
- package/src/memory/memory-retrospective-enqueue.ts +4 -22
- package/src/memory/memory-retrospective-job.ts +438 -21
- package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
- package/src/memory/memory-v2-activation-log-store.ts +26 -8
- package/src/memory/migrations/100-core-tables.ts +1 -0
- package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
- package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
- package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
- package/src/memory/migrations/253-document-comments.ts +47 -0
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
- package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
- package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
- package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
- package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
- package/src/memory/migrations/index.ts +20 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/onboarding-events-store.ts +7 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +2 -0
- package/src/memory/schema/infrastructure.ts +2 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/memory/v2/__tests__/injection.test.ts +221 -17
- package/src/memory/v2/__tests__/page-index.test.ts +365 -1
- package/src/memory/v2/__tests__/router.test.ts +489 -1
- package/src/memory/v2/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/consolidation-job.ts +14 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection-events.ts +101 -0
- package/src/memory/v2/injection.ts +69 -29
- package/src/memory/v2/page-index.ts +246 -19
- package/src/memory/v2/page-store.ts +18 -0
- package/src/memory/v2/router.ts +209 -55
- package/src/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +18 -3
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
- package/src/messaging/providers/slack/adapter.ts +178 -25
- package/src/messaging/providers/slack/api.test.ts +54 -0
- package/src/messaging/providers/slack/api.ts +119 -3
- package/src/messaging/providers/slack/client.ts +12 -0
- package/src/messaging/providers/slack/deep-link.ts +20 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
- package/src/messaging/providers/slack/message-metadata.ts +156 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
- package/src/messaging/providers/slack/render-transcript.ts +176 -49
- package/src/messaging/providers/slack/send.test.ts +77 -0
- package/src/messaging/providers/slack/send.ts +8 -2
- package/src/messaging/providers/slack/types.ts +14 -0
- package/src/notifications/__tests__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +5 -1
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +521 -36
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/conversation-seed-composer.ts +14 -2
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +111 -44
- package/src/notifications/deferred-emit.ts +135 -0
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +10 -1
- package/src/notifications/home-feed-side-effect.ts +136 -27
- package/src/notifications/signal.ts +0 -4
- package/src/notifications/types.ts +8 -0
- package/src/oauth/connect-orchestrator.ts +3 -0
- package/src/oauth/credential-token-resolver.ts +2 -0
- package/src/oauth/manual-token-connection.ts +19 -0
- package/src/oauth/oauth-store.ts +12 -0
- package/src/oauth/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +13 -4
- package/src/oauth/seed-providers.ts +22 -0
- package/src/permissions/prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +4 -1
- package/src/plugins/defaults/injectors.ts +118 -26
- package/src/plugins/external-plugin-loader.ts +82 -10
- package/src/plugins/types.ts +16 -7
- package/src/prompts/__tests__/system-prompt.test.ts +44 -45
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
- package/src/prompts/normalize-onboarding.ts +40 -0
- package/src/prompts/sections.ts +32 -14
- package/src/prompts/system-prompt.ts +105 -76
- package/src/prompts/template-detection.ts +37 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/VOICE.md +3 -0
- package/src/prompts/templates/system-sections.ts +51 -10
- package/src/providers/__tests__/inference.test.ts +2 -0
- package/src/providers/anthropic/client.ts +132 -5
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +63 -13
- package/src/providers/fireworks/client.ts +20 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
- package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +24 -21
- package/src/providers/inference/auth.ts +15 -3
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/codex-token-refresh.ts +128 -0
- package/src/providers/inference/connections.ts +85 -5
- package/src/providers/inference/resolve-auth.ts +50 -5
- package/src/providers/model-catalog.ts +244 -242
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +215 -25
- package/src/providers/openai/responses-provider.ts +9 -3
- package/src/providers/openrouter/client.ts +46 -4
- package/src/providers/platform-proxy/constants.ts +3 -4
- package/src/providers/provider-catalog-visibility.ts +3 -1
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +30 -1
- package/src/providers/types.ts +25 -0
- package/src/runtime/__tests__/agent-wake.test.ts +214 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
- package/src/runtime/agent-wake.ts +212 -57
- package/src/runtime/auth/route-policy.ts +20 -3
- package/src/runtime/background-job-runner.ts +26 -0
- package/src/runtime/channel-reply-delivery.ts +182 -47
- package/src/runtime/channel-retry-sweep.ts +141 -16
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +7 -51
- package/src/runtime/pending-interactions.ts +51 -8
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +121 -5
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
- package/src/runtime/routes/approval-routes.ts +4 -1
- package/src/runtime/routes/channel-availability-routes.ts +5 -0
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -0
- package/src/runtime/routes/content-source-routes.ts +78 -0
- package/src/runtime/routes/conversation-cli-routes.ts +146 -1
- package/src/runtime/routes/conversation-query-routes.ts +130 -12
- package/src/runtime/routes/conversation-routes.ts +288 -76
- package/src/runtime/routes/document-comments-routes.ts +287 -0
- package/src/runtime/routes/documents-routes.ts +33 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -3
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-browser-routes.ts +8 -1
- package/src/runtime/routes/identity-routes.ts +21 -0
- package/src/runtime/routes/inbound-message-handler.ts +288 -58
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
- package/src/runtime/routes/index.ts +14 -4
- package/src/runtime/routes/inference-provider-connection-routes.ts +192 -3
- package/src/runtime/routes/integrations/a2a.ts +294 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
- package/src/runtime/routes/log-export-routes.ts +39 -0
- package/src/runtime/routes/memory-v2-routes.ts +217 -0
- package/src/runtime/routes/notification-routes.ts +19 -2
- package/src/runtime/routes/question-routes.ts +4 -1
- package/src/runtime/routes/sanity-routes.ts +159 -0
- package/src/runtime/routes/slack-channel-routes.ts +187 -0
- package/src/runtime/routes/subagents-routes.ts +41 -0
- package/src/runtime/services/conversation-serializer.ts +30 -4
- package/src/schedule/integration-status.ts +3 -1
- package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
- package/src/security/oauth2-device-code.ts +307 -0
- package/src/security/oauth2.ts +26 -9
- package/src/security/secure-keys.ts +5 -0
- package/src/skills/catalog-install.ts +6 -2
- package/src/subagent/manager.ts +2 -0
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
- package/src/tools/browser/browser-execution.ts +93 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
- package/src/tools/browser/cdp-client/factory.ts +87 -3
- package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
- package/src/tools/browser/cdp-client/types.ts +36 -0
- package/src/tools/browser/pinned-tabs.ts +90 -0
- package/src/tools/document/document-comment-tool.test.ts +379 -0
- package/src/tools/document/document-comment-tool.ts +156 -0
- package/src/tools/document/document-tool.ts +128 -2
- package/src/tools/memory/register.ts +1 -9
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
- package/src/tools/network/domain-normalize.ts +17 -0
- package/src/tools/network/web-fetch.ts +213 -64
- package/src/tools/network/web-search.ts +191 -66
- package/src/tools/registry.ts +2 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/tool-approval-handler.ts +19 -12
- package/src/tools/types.ts +41 -2
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/types/onboarding-context.ts +4 -0
- package/src/util/__tests__/favicon.test.ts +84 -0
- package/src/util/favicon.ts +40 -0
- package/src/util/platform.ts +0 -5
- package/src/workspace/git-service.ts +75 -4
- package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- package/src/config/bundled-skills/document/SKILL.md +0 -54
- package/src/config/bundled-skills/document/TOOLS.json +0 -106
- package/src/daemon/seed-files.ts +0 -18
- package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
- package/src/runtime/routes/interface-routes.ts +0 -43
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Personalized home-page greeting generator.
|
|
3
|
+
*
|
|
4
|
+
* Produces a short greeting in the assistant's tone/persona for the
|
|
5
|
+
* Home page header. Uses the BTW side-chain for LLM generation and
|
|
6
|
+
* caches the result for 4 hours (busted when identity files change).
|
|
7
|
+
*
|
|
8
|
+
* The GET handler reads only from cache (`getPersonalizedGreeting`).
|
|
9
|
+
* Generation runs in the background via `refreshPersonalizedGreeting`,
|
|
10
|
+
* called at daemon startup and periodically by the home-content
|
|
11
|
+
* refresh timer.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
15
|
+
import { getConfig } from "../config/loader.js";
|
|
16
|
+
import { resolvePersonaContext } from "../prompts/persona-resolver.js";
|
|
17
|
+
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
18
|
+
import { getConfiguredProvider } from "../providers/provider-send-message.js";
|
|
19
|
+
import { runBtwSidechain } from "../runtime/btw-sidechain.js";
|
|
20
|
+
import { getLogger } from "../util/logger.js";
|
|
21
|
+
import {
|
|
22
|
+
getCachedHomeGreeting,
|
|
23
|
+
setCachedHomeGreeting,
|
|
24
|
+
} from "./home-greeting-cache.js";
|
|
25
|
+
|
|
26
|
+
const log = getLogger("home-greeting");
|
|
27
|
+
|
|
28
|
+
const GENERATION_TIMEOUT_MS = 5_000;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Return the cached personalized greeting, or `null` when none is
|
|
32
|
+
* available yet. This is a synchronous cache read — safe for GET
|
|
33
|
+
* handlers.
|
|
34
|
+
*/
|
|
35
|
+
export function getPersonalizedGreeting(): string | null {
|
|
36
|
+
return getCachedHomeGreeting();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Generate a personalized greeting via LLM and write it to cache.
|
|
41
|
+
* No-ops when the cache is still fresh. Intended for background
|
|
42
|
+
* invocation (daemon startup / periodic refresh), not the GET path.
|
|
43
|
+
*/
|
|
44
|
+
export async function refreshPersonalizedGreeting(): Promise<void> {
|
|
45
|
+
const cached = getCachedHomeGreeting();
|
|
46
|
+
if (cached) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const config = getConfig();
|
|
52
|
+
const resolved = resolveCallSiteConfig("homeGreeting", config.llm);
|
|
53
|
+
|
|
54
|
+
const provider = await getConfiguredProvider("homeGreeting");
|
|
55
|
+
if (!provider) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const { userPersona, userSlug, channelPersona } = resolvePersonaContext(
|
|
60
|
+
undefined,
|
|
61
|
+
undefined,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const systemPrompt = buildSystemPrompt({
|
|
65
|
+
excludeBootstrap: true,
|
|
66
|
+
excludeCustomPrefix: true,
|
|
67
|
+
userPersona,
|
|
68
|
+
channelPersona,
|
|
69
|
+
userSlug,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const result = await runBtwSidechain({
|
|
73
|
+
content:
|
|
74
|
+
"Generate a short, casual greeting for the home page (max 10 words). " +
|
|
75
|
+
"It should convey the meaning of 'here's what's been going on' but in " +
|
|
76
|
+
"your unique tone and personality. Just output the greeting text, nothing else. " +
|
|
77
|
+
"No quotes, no preamble.",
|
|
78
|
+
provider,
|
|
79
|
+
systemPrompt,
|
|
80
|
+
messages: [],
|
|
81
|
+
tools: [],
|
|
82
|
+
callSite: "homeGreeting",
|
|
83
|
+
maxTokens: resolved.maxTokens,
|
|
84
|
+
timeoutMs: GENERATION_TIMEOUT_MS,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const text = result.text.trim();
|
|
88
|
+
if (text) {
|
|
89
|
+
setCachedHomeGreeting(text);
|
|
90
|
+
}
|
|
91
|
+
} catch (err) {
|
|
92
|
+
log.warn({ err }, "Failed to generate personalized home greeting");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -6,11 +6,23 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Two sources of prompts:
|
|
8
8
|
* - **Deterministic** — derived from missing OAuth connections.
|
|
9
|
+
* Computed inline (read-only, safe for GET).
|
|
9
10
|
* - **Assistant-generated** — contextual suggestions from the LLM
|
|
10
|
-
*
|
|
11
|
+
* based on what's relevant to the user. Read from an in-memory
|
|
12
|
+
* cache in the GET path; generation runs in the background via
|
|
13
|
+
* `refreshAssistantSuggestedPrompts`.
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
|
-
import {
|
|
16
|
+
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
17
|
+
import { getConfig } from "../config/loader.js";
|
|
18
|
+
import { listProviders } from "../oauth/oauth-store.js";
|
|
19
|
+
import { resolvePersonaContext } from "../prompts/persona-resolver.js";
|
|
20
|
+
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
21
|
+
import { getConfiguredProvider } from "../providers/provider-send-message.js";
|
|
22
|
+
import { buildAssistantEvent } from "../runtime/assistant-event.js";
|
|
23
|
+
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
24
|
+
import { runBtwSidechain } from "../runtime/btw-sidechain.js";
|
|
25
|
+
import { isOAuthProviderConnected } from "../schedule/integration-status.js";
|
|
14
26
|
import { getLogger } from "../util/logger.js";
|
|
15
27
|
import type { SuggestedPrompt } from "./feed-types.js";
|
|
16
28
|
|
|
@@ -72,27 +84,88 @@ const CONNECT_PROMPT_META: Record<
|
|
|
72
84
|
},
|
|
73
85
|
};
|
|
74
86
|
|
|
87
|
+
const LLM_SUGGESTIONS_TIMEOUT_MS = 5_000;
|
|
88
|
+
const LLM_CACHE_TTL_MS = 30 * 60 * 1000; // 30 minutes
|
|
89
|
+
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
// In-memory cache for LLM-generated suggestions
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
|
|
94
|
+
let cachedLLMPrompts: SuggestedPrompt[] = [];
|
|
95
|
+
let cachedLLMPromptsAt = 0;
|
|
96
|
+
|
|
75
97
|
/**
|
|
76
|
-
* Produce
|
|
77
|
-
*
|
|
78
|
-
*
|
|
98
|
+
* Produce suggested prompts from both deterministic and cached LLM sources.
|
|
99
|
+
* Deterministic prompts always come first; cached LLM-generated prompts are
|
|
100
|
+
* appended when available. No LLM calls happen in this path — safe for GET.
|
|
79
101
|
*/
|
|
80
102
|
export async function getSuggestedPrompts(): Promise<SuggestedPrompt[]> {
|
|
81
103
|
const prompts: SuggestedPrompt[] = [];
|
|
82
104
|
|
|
105
|
+
let deterministicPrompts: SuggestedPrompt[] = [];
|
|
83
106
|
try {
|
|
84
|
-
|
|
107
|
+
deterministicPrompts = await getDeterministicPrompts();
|
|
85
108
|
prompts.push(...deterministicPrompts);
|
|
86
109
|
} catch (err) {
|
|
87
110
|
log.warn({ err }, "Failed to compute deterministic suggested prompts");
|
|
88
111
|
}
|
|
89
112
|
|
|
90
|
-
|
|
91
|
-
|
|
113
|
+
if (Date.now() - cachedLLMPromptsAt < LLM_CACHE_TTL_MS) {
|
|
114
|
+
prompts.push(...cachedLLMPrompts);
|
|
115
|
+
}
|
|
92
116
|
|
|
93
117
|
return prompts;
|
|
94
118
|
}
|
|
95
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Drops the in-memory LLM suggestion cache so the next call to
|
|
122
|
+
* `getSuggestedPrompts()` returns only the fresh deterministic list (and
|
|
123
|
+
* a follow-up background refresh repopulates the LLM half).
|
|
124
|
+
*
|
|
125
|
+
* Called from OAuth connect/disconnect paths so a freshly-connected
|
|
126
|
+
* provider stops surfacing as a "Connect X" pill within one reload — the
|
|
127
|
+
* 30-minute TTL would otherwise pin a stale suggestion until the next
|
|
128
|
+
* periodic refresh.
|
|
129
|
+
*/
|
|
130
|
+
export function invalidateAssistantSuggestedPromptsCache(): void {
|
|
131
|
+
cachedLLMPrompts = [];
|
|
132
|
+
cachedLLMPromptsAt = 0;
|
|
133
|
+
assistantEventHub
|
|
134
|
+
.publish(
|
|
135
|
+
buildAssistantEvent({
|
|
136
|
+
type: "home_feed_updated",
|
|
137
|
+
updatedAt: new Date().toISOString(),
|
|
138
|
+
newItemCount: 0,
|
|
139
|
+
}),
|
|
140
|
+
)
|
|
141
|
+
.catch((err) => {
|
|
142
|
+
log.warn(
|
|
143
|
+
{ err },
|
|
144
|
+
"Failed to publish home_feed_updated after prompt cache invalidation",
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Generate LLM-based suggestion prompts and write them to the in-memory
|
|
151
|
+
* cache. No-ops when the cache is still fresh. Intended for background
|
|
152
|
+
* invocation (daemon startup / periodic refresh), not the GET path.
|
|
153
|
+
*/
|
|
154
|
+
export async function refreshAssistantSuggestedPrompts(): Promise<void> {
|
|
155
|
+
if (Date.now() - cachedLLMPromptsAt < LLM_CACHE_TTL_MS) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
const deterministicPrompts = await getDeterministicPrompts();
|
|
161
|
+
const llmPrompts = await generateAssistantPrompts(deterministicPrompts);
|
|
162
|
+
cachedLLMPrompts = llmPrompts;
|
|
163
|
+
cachedLLMPromptsAt = Date.now();
|
|
164
|
+
} catch (err) {
|
|
165
|
+
log.warn({ err }, "Failed to refresh assistant suggested prompts");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
96
169
|
/**
|
|
97
170
|
* Check which well-known OAuth providers are not connected and return
|
|
98
171
|
* a "Connect X" prompt for each. For connected providers that have
|
|
@@ -107,7 +180,7 @@ async function getDeterministicPrompts(): Promise<SuggestedPrompt[]> {
|
|
|
107
180
|
const meta = CONNECT_PROMPT_META[provider.provider];
|
|
108
181
|
if (!meta) continue;
|
|
109
182
|
|
|
110
|
-
const connected = await
|
|
183
|
+
const connected = await isOAuthProviderConnected(provider.provider);
|
|
111
184
|
|
|
112
185
|
if (!connected) {
|
|
113
186
|
prompts.push({
|
|
@@ -135,3 +208,98 @@ async function getDeterministicPrompts(): Promise<SuggestedPrompt[]> {
|
|
|
135
208
|
|
|
136
209
|
return prompts;
|
|
137
210
|
}
|
|
211
|
+
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
// LLM-generated suggestions
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
|
|
216
|
+
interface LLMSuggestion {
|
|
217
|
+
label: string;
|
|
218
|
+
prompt: string;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Ask the LLM to generate contextual conversation-starter suggestions
|
|
223
|
+
* based on the assistant's persona and the user's connected services.
|
|
224
|
+
* Returns an empty array on failure so deterministic prompts still show.
|
|
225
|
+
*/
|
|
226
|
+
async function generateAssistantPrompts(
|
|
227
|
+
deterministicPrompts: SuggestedPrompt[],
|
|
228
|
+
): Promise<SuggestedPrompt[]> {
|
|
229
|
+
const config = getConfig();
|
|
230
|
+
const resolved = resolveCallSiteConfig("homeSuggestedPrompts", config.llm);
|
|
231
|
+
|
|
232
|
+
const provider = await getConfiguredProvider("homeSuggestedPrompts");
|
|
233
|
+
if (!provider) {
|
|
234
|
+
return [];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const { userPersona, userSlug, channelPersona } = resolvePersonaContext(
|
|
238
|
+
undefined,
|
|
239
|
+
undefined,
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
const systemPrompt = buildSystemPrompt({
|
|
243
|
+
excludeBootstrap: true,
|
|
244
|
+
excludeCustomPrefix: true,
|
|
245
|
+
userPersona,
|
|
246
|
+
channelPersona,
|
|
247
|
+
userSlug,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const existingLabels = deterministicPrompts.map((p) => p.label).join(", ");
|
|
251
|
+
const contextNote = existingLabels
|
|
252
|
+
? `The user already has these suggestions: ${existingLabels}. Do NOT duplicate them.`
|
|
253
|
+
: "";
|
|
254
|
+
|
|
255
|
+
const result = await runBtwSidechain({
|
|
256
|
+
content:
|
|
257
|
+
"Suggest 2-3 short, actionable conversation starters for the home page. " +
|
|
258
|
+
"Each should be something specific and helpful you can do for the user right now. " +
|
|
259
|
+
`${contextNote} ` +
|
|
260
|
+
'Return ONLY a JSON array of objects with "label" (max 5 words) and "prompt" (the full message to send). ' +
|
|
261
|
+
"No markdown fences, no explanation.",
|
|
262
|
+
provider,
|
|
263
|
+
systemPrompt,
|
|
264
|
+
messages: [],
|
|
265
|
+
tools: [],
|
|
266
|
+
callSite: "homeSuggestedPrompts",
|
|
267
|
+
maxTokens: resolved.maxTokens,
|
|
268
|
+
timeoutMs: LLM_SUGGESTIONS_TIMEOUT_MS,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const text = result.text.trim();
|
|
272
|
+
if (!text) {
|
|
273
|
+
return [];
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const parsed = parseLLMSuggestions(text);
|
|
277
|
+
return parsed.map((s, i) => ({
|
|
278
|
+
id: `assistant-${i}-${s.label.toLowerCase().replace(/\s+/g, "-")}`,
|
|
279
|
+
label: s.label,
|
|
280
|
+
prompt: s.prompt,
|
|
281
|
+
source: "assistant" as const,
|
|
282
|
+
}));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function parseLLMSuggestions(text: string): LLMSuggestion[] {
|
|
286
|
+
try {
|
|
287
|
+
const cleaned = text
|
|
288
|
+
.replace(/^```(?:json)?\n?/m, "")
|
|
289
|
+
.replace(/\n?```$/m, "");
|
|
290
|
+
const parsed = JSON.parse(cleaned);
|
|
291
|
+
if (!Array.isArray(parsed)) {
|
|
292
|
+
return [];
|
|
293
|
+
}
|
|
294
|
+
return parsed.filter(
|
|
295
|
+
(item): item is LLMSuggestion =>
|
|
296
|
+
typeof item === "object" &&
|
|
297
|
+
item !== null &&
|
|
298
|
+
typeof item.label === "string" &&
|
|
299
|
+
typeof item.prompt === "string",
|
|
300
|
+
);
|
|
301
|
+
} catch {
|
|
302
|
+
log.warn("Failed to parse LLM suggestions response");
|
|
303
|
+
return [];
|
|
304
|
+
}
|
|
305
|
+
}
|
package/src/ipc/cli-client.ts
CHANGED
|
@@ -135,19 +135,26 @@ export async function cliIpcCall<T = unknown>(
|
|
|
135
135
|
|
|
136
136
|
const reqId = crypto.randomUUID();
|
|
137
137
|
|
|
138
|
-
opts?.signal?.addEventListener(
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
opts?.signal?.addEventListener(
|
|
139
|
+
"abort",
|
|
140
|
+
() => {
|
|
141
|
+
finish({ ok: false, error: "Request aborted" });
|
|
142
|
+
},
|
|
143
|
+
{ once: true },
|
|
144
|
+
);
|
|
141
145
|
|
|
142
146
|
const reader = new IpcFrameReader(
|
|
143
147
|
(envelope) => {
|
|
144
148
|
if (envelope.id !== reqId) return;
|
|
145
149
|
const msg = envelope as IpcResponse;
|
|
146
150
|
if (msg.error) {
|
|
147
|
-
finish({
|
|
151
|
+
finish({
|
|
152
|
+
ok: false,
|
|
153
|
+
error: msg.error,
|
|
148
154
|
...(msg.statusCode != null && { statusCode: msg.statusCode }),
|
|
149
155
|
...(msg.errorCode != null && { errorCode: msg.errorCode }),
|
|
150
|
-
...(msg.errorDetails != null && { errorDetails: msg.errorDetails })
|
|
156
|
+
...(msg.errorDetails != null && { errorDetails: msg.errorDetails }),
|
|
157
|
+
});
|
|
151
158
|
} else {
|
|
152
159
|
finish({ ok: true, result: msg.result as T });
|
|
153
160
|
}
|
|
@@ -199,7 +206,13 @@ export async function cliIpcCallBinary(
|
|
|
199
206
|
opts?: { timeoutMs?: number; signal?: AbortSignal },
|
|
200
207
|
): Promise<
|
|
201
208
|
| { ok: true; headers: Record<string, string>; bytes: Uint8Array }
|
|
202
|
-
| {
|
|
209
|
+
| {
|
|
210
|
+
ok: false;
|
|
211
|
+
error: string;
|
|
212
|
+
statusCode?: number;
|
|
213
|
+
errorCode?: string;
|
|
214
|
+
errorDetails?: unknown;
|
|
215
|
+
}
|
|
203
216
|
> {
|
|
204
217
|
if (opts?.signal?.aborted) {
|
|
205
218
|
throw opts.signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
@@ -215,7 +228,13 @@ export async function cliIpcCallBinary(
|
|
|
215
228
|
const finish = (
|
|
216
229
|
result:
|
|
217
230
|
| { ok: true; headers: Record<string, string>; bytes: Uint8Array }
|
|
218
|
-
| {
|
|
231
|
+
| {
|
|
232
|
+
ok: false;
|
|
233
|
+
error: string;
|
|
234
|
+
statusCode?: number;
|
|
235
|
+
errorCode?: string;
|
|
236
|
+
errorDetails?: unknown;
|
|
237
|
+
},
|
|
219
238
|
) => {
|
|
220
239
|
if (settled) return;
|
|
221
240
|
settled = true;
|
|
@@ -226,8 +245,14 @@ export async function cliIpcCallBinary(
|
|
|
226
245
|
};
|
|
227
246
|
|
|
228
247
|
const connectTimer = setTimeout(() => {
|
|
229
|
-
log.debug(
|
|
230
|
-
|
|
248
|
+
log.debug(
|
|
249
|
+
{ method, socketPath, timeoutMs: CONNECT_TIMEOUT_MS },
|
|
250
|
+
"CLI IPC binary connect timed out",
|
|
251
|
+
);
|
|
252
|
+
finish({
|
|
253
|
+
ok: false,
|
|
254
|
+
error: `Could not connect to the assistant at ${socketPath}.\nRun \`assistant status\` to check, or \`assistant gateway start\` to start it.`,
|
|
255
|
+
});
|
|
231
256
|
}, CONNECT_TIMEOUT_MS);
|
|
232
257
|
|
|
233
258
|
const socket = new Socket();
|
|
@@ -235,7 +260,10 @@ export async function cliIpcCallBinary(
|
|
|
235
260
|
|
|
236
261
|
socket.on("error", (err) => {
|
|
237
262
|
const code = (err as NodeJS.ErrnoException).code;
|
|
238
|
-
log.debug(
|
|
263
|
+
log.debug(
|
|
264
|
+
{ err, code, method, socketPath },
|
|
265
|
+
"CLI IPC binary socket error",
|
|
266
|
+
);
|
|
239
267
|
finish({
|
|
240
268
|
ok: false,
|
|
241
269
|
error:
|
|
@@ -258,23 +286,37 @@ export async function cliIpcCallBinary(
|
|
|
258
286
|
|
|
259
287
|
const reqId = crypto.randomUUID();
|
|
260
288
|
|
|
261
|
-
opts?.signal?.addEventListener(
|
|
262
|
-
|
|
263
|
-
|
|
289
|
+
opts?.signal?.addEventListener(
|
|
290
|
+
"abort",
|
|
291
|
+
() => {
|
|
292
|
+
finish({ ok: false, error: "Request aborted" });
|
|
293
|
+
},
|
|
294
|
+
{ once: true },
|
|
295
|
+
);
|
|
264
296
|
|
|
265
297
|
const reader = new IpcFrameReader(
|
|
266
298
|
(envelope, binary) => {
|
|
267
299
|
if (envelope.id !== reqId) return;
|
|
268
300
|
const msg = envelope as IpcResponse;
|
|
269
301
|
if (msg.error) {
|
|
270
|
-
finish({
|
|
302
|
+
finish({
|
|
303
|
+
ok: false,
|
|
304
|
+
error: msg.error,
|
|
271
305
|
...(msg.statusCode != null && { statusCode: msg.statusCode }),
|
|
272
306
|
...(msg.errorCode != null && { errorCode: msg.errorCode }),
|
|
273
|
-
...(msg.errorDetails != null && { errorDetails: msg.errorDetails })
|
|
307
|
+
...(msg.errorDetails != null && { errorDetails: msg.errorDetails }),
|
|
308
|
+
});
|
|
274
309
|
} else if (binary === undefined) {
|
|
275
|
-
finish({
|
|
310
|
+
finish({
|
|
311
|
+
ok: false,
|
|
312
|
+
error: "Expected binary frame but received JSON-only response",
|
|
313
|
+
});
|
|
276
314
|
} else {
|
|
277
|
-
finish({
|
|
315
|
+
finish({
|
|
316
|
+
ok: true,
|
|
317
|
+
headers: (envelope.headers ?? {}) as Record<string, string>,
|
|
318
|
+
bytes: binary,
|
|
319
|
+
});
|
|
278
320
|
}
|
|
279
321
|
},
|
|
280
322
|
(err) => finish({ ok: false, error: err.message }),
|
|
@@ -285,7 +327,10 @@ export async function cliIpcCallBinary(
|
|
|
285
327
|
writeMessage(socket, { id: reqId, method, params });
|
|
286
328
|
|
|
287
329
|
callTimer = setTimeout(() => {
|
|
288
|
-
log.debug(
|
|
330
|
+
log.debug(
|
|
331
|
+
{ method, socketPath, timeoutMs: callTimeoutMs },
|
|
332
|
+
"CLI IPC binary call timed out",
|
|
333
|
+
);
|
|
289
334
|
finish({ ok: false, error: "Request timed out" });
|
|
290
335
|
}, callTimeoutMs);
|
|
291
336
|
|
|
@@ -323,24 +368,42 @@ export async function cliIpcCallStream(
|
|
|
323
368
|
params?: Record<string, unknown>,
|
|
324
369
|
opts?: { firstByteTimeoutMs?: number; signal?: AbortSignal },
|
|
325
370
|
): Promise<
|
|
326
|
-
| {
|
|
327
|
-
|
|
371
|
+
| {
|
|
372
|
+
ok: true;
|
|
373
|
+
headers: Record<string, string>;
|
|
374
|
+
body: ReadableStream<Uint8Array>;
|
|
375
|
+
abort: () => void;
|
|
376
|
+
}
|
|
377
|
+
| {
|
|
378
|
+
ok: false;
|
|
379
|
+
error: string;
|
|
380
|
+
statusCode?: number;
|
|
381
|
+
errorCode?: string;
|
|
382
|
+
errorDetails?: unknown;
|
|
383
|
+
}
|
|
328
384
|
> {
|
|
329
385
|
if (opts?.signal?.aborted) {
|
|
330
386
|
throw opts.signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
331
387
|
}
|
|
332
388
|
|
|
333
389
|
const socketPath = getAssistantSocketPath();
|
|
334
|
-
const firstByteTimeoutMs =
|
|
390
|
+
const firstByteTimeoutMs =
|
|
391
|
+
opts?.firstByteTimeoutMs ?? DEFAULT_FIRST_BYTE_TIMEOUT_MS;
|
|
335
392
|
|
|
336
393
|
return new Promise((resolve) => {
|
|
337
394
|
let settled = false;
|
|
338
395
|
let firstByteTimer: ReturnType<typeof setTimeout> | undefined;
|
|
339
|
-
let streamController:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
396
|
+
let streamController:
|
|
397
|
+
| ReadableStreamDefaultController<Uint8Array>
|
|
398
|
+
| undefined;
|
|
399
|
+
|
|
400
|
+
const finishError = (result: {
|
|
401
|
+
ok: false;
|
|
402
|
+
error: string;
|
|
403
|
+
statusCode?: number;
|
|
404
|
+
errorCode?: string;
|
|
405
|
+
errorDetails?: unknown;
|
|
406
|
+
}) => {
|
|
344
407
|
if (settled) return;
|
|
345
408
|
settled = true;
|
|
346
409
|
clearTimeout(connectTimer);
|
|
@@ -366,8 +429,14 @@ export async function cliIpcCallStream(
|
|
|
366
429
|
};
|
|
367
430
|
|
|
368
431
|
const connectTimer = setTimeout(() => {
|
|
369
|
-
log.debug(
|
|
370
|
-
|
|
432
|
+
log.debug(
|
|
433
|
+
{ method, socketPath, timeoutMs: CONNECT_TIMEOUT_MS },
|
|
434
|
+
"CLI IPC stream connect timed out",
|
|
435
|
+
);
|
|
436
|
+
finishError({
|
|
437
|
+
ok: false,
|
|
438
|
+
error: `Could not connect to the assistant at ${socketPath}.\nRun \`assistant status\` to check, or \`assistant gateway start\` to start it.`,
|
|
439
|
+
});
|
|
371
440
|
}, CONNECT_TIMEOUT_MS);
|
|
372
441
|
|
|
373
442
|
const socket = new Socket();
|
|
@@ -375,7 +444,10 @@ export async function cliIpcCallStream(
|
|
|
375
444
|
|
|
376
445
|
socket.on("error", (err) => {
|
|
377
446
|
const code = (err as NodeJS.ErrnoException).code;
|
|
378
|
-
log.debug(
|
|
447
|
+
log.debug(
|
|
448
|
+
{ err, code, method, socketPath },
|
|
449
|
+
"CLI IPC stream socket error",
|
|
450
|
+
);
|
|
379
451
|
if (!settled) {
|
|
380
452
|
finishError({
|
|
381
453
|
ok: false,
|
|
@@ -399,24 +471,35 @@ export async function cliIpcCallStream(
|
|
|
399
471
|
: "Connection closed before response",
|
|
400
472
|
});
|
|
401
473
|
} else if (streamController) {
|
|
402
|
-
streamController.error(
|
|
474
|
+
streamController.error(
|
|
475
|
+
new Error("Connection closed before stream ended"),
|
|
476
|
+
);
|
|
403
477
|
streamController = undefined;
|
|
404
478
|
}
|
|
405
479
|
});
|
|
406
480
|
|
|
407
481
|
const reqId = crypto.randomUUID();
|
|
408
482
|
|
|
409
|
-
opts?.signal?.addEventListener(
|
|
483
|
+
opts?.signal?.addEventListener(
|
|
484
|
+
"abort",
|
|
485
|
+
() => {
|
|
486
|
+
abort();
|
|
487
|
+
},
|
|
488
|
+
{ once: true },
|
|
489
|
+
);
|
|
410
490
|
|
|
411
491
|
const reader = new IpcFrameReader(
|
|
412
492
|
(envelope) => {
|
|
413
493
|
// Non-streaming envelope with error (e.g. method not found, auth failure)
|
|
414
494
|
if (envelope.id !== reqId) return;
|
|
415
495
|
const msg = envelope as IpcResponse;
|
|
416
|
-
finishError({
|
|
496
|
+
finishError({
|
|
497
|
+
ok: false,
|
|
498
|
+
error: msg.error ?? "Unexpected non-streaming response",
|
|
417
499
|
...(msg.statusCode != null && { statusCode: msg.statusCode }),
|
|
418
500
|
...(msg.errorCode != null && { errorCode: msg.errorCode }),
|
|
419
|
-
...(msg.errorDetails != null && { errorDetails: msg.errorDetails })
|
|
501
|
+
...(msg.errorDetails != null && { errorDetails: msg.errorDetails }),
|
|
502
|
+
});
|
|
420
503
|
},
|
|
421
504
|
(err) => finishError({ ok: false, error: err.message }),
|
|
422
505
|
{
|
|
@@ -437,7 +520,12 @@ export async function cliIpcCallStream(
|
|
|
437
520
|
});
|
|
438
521
|
settled = true;
|
|
439
522
|
clearTimeout(connectTimer);
|
|
440
|
-
resolve({
|
|
523
|
+
resolve({
|
|
524
|
+
ok: true,
|
|
525
|
+
headers: (envelope.headers ?? {}) as Record<string, string>,
|
|
526
|
+
body,
|
|
527
|
+
abort,
|
|
528
|
+
});
|
|
441
529
|
},
|
|
442
530
|
onStreamChunk: (chunk) => {
|
|
443
531
|
streamController?.enqueue(chunk);
|
|
@@ -455,8 +543,14 @@ export async function cliIpcCallStream(
|
|
|
455
543
|
writeMessage(socket, { id: reqId, method, params });
|
|
456
544
|
|
|
457
545
|
firstByteTimer = setTimeout(() => {
|
|
458
|
-
log.debug(
|
|
459
|
-
|
|
546
|
+
log.debug(
|
|
547
|
+
{ method, socketPath, timeoutMs: firstByteTimeoutMs },
|
|
548
|
+
"CLI IPC stream first-byte timeout",
|
|
549
|
+
);
|
|
550
|
+
finishError({
|
|
551
|
+
ok: false,
|
|
552
|
+
error: "Stream timed out waiting for first byte",
|
|
553
|
+
});
|
|
460
554
|
}, firstByteTimeoutMs);
|
|
461
555
|
|
|
462
556
|
socket.on("data", (chunk) => {
|
|
@@ -491,13 +585,21 @@ export function exitFromIpcResult(
|
|
|
491
585
|
_cmd?: unknown,
|
|
492
586
|
): never {
|
|
493
587
|
process.stderr.write((r.error ?? "Unknown error") + "\n");
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
588
|
+
process.exit(exitCodeFromIpcResult(r));
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Map an IPC error result to its CLI process exit code without exiting.
|
|
593
|
+
*
|
|
594
|
+
* Use this when callers want to emit a structured response (e.g. a JSON
|
|
595
|
+
* error envelope in `--json` mode) before terminating with the same status
|
|
596
|
+
* code that {@link exitFromIpcResult} would produce.
|
|
597
|
+
*
|
|
598
|
+
* Exit code matrix matches {@link exitFromIpcResult}.
|
|
599
|
+
*/
|
|
600
|
+
export function exitCodeFromIpcResult(r: { statusCode?: number }): number {
|
|
601
|
+
if (r.statusCode === undefined) return 10;
|
|
602
|
+
if (r.statusCode >= 500) return 3;
|
|
603
|
+
if (r.statusCode >= 400) return 2;
|
|
604
|
+
return 1;
|
|
503
605
|
}
|