@vellumai/assistant 0.8.1 → 0.8.2
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 +2 -7
- package/Dockerfile +75 -1
- package/bun.lock +11 -1
- package/docker-entrypoint.sh +5 -0
- package/docker-init-apt-root.sh +94 -0
- package/docker-kata-apt-env.sh +39 -0
- package/docs/plugins.md +88 -47
- package/docs/skills.md +9 -7
- package/examples/plugins/echo/README.md +27 -27
- package/examples/plugins/echo/package.json +3 -0
- package/examples/plugins/echo/register.ts +31 -31
- package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
- package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
- package/openapi.yaml +325 -3
- package/package.json +3 -1
- package/scripts/generate-openapi.ts +83 -10
- package/scripts/sync-llm-catalog.ts +2 -2
- package/scripts/sync-web-search-catalog.ts +47 -25
- package/src/__tests__/agent-image-optimize.test.ts +11 -3
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
- package/src/__tests__/anthropic-provider.test.ts +45 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
- package/src/__tests__/app-executors.test.ts +220 -4
- package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/channel-availability-routes.test.ts +206 -0
- package/src/__tests__/channel-delivery-store.test.ts +289 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
- package/src/__tests__/clawhub.test.ts +75 -16
- package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
- package/src/__tests__/config-schema.test.ts +21 -0
- package/src/__tests__/config-set-route.test.ts +80 -0
- package/src/__tests__/config-sounds-sync.test.ts +97 -0
- package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
- package/src/__tests__/context-search-conversations-source.test.ts +117 -2
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +7 -0
- package/src/__tests__/context-token-estimator.test.ts +1 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
- package/src/__tests__/conversation-agent-loop.test.ts +2 -0
- package/src/__tests__/conversation-error.test.ts +42 -3
- package/src/__tests__/conversation-fork-crud.test.ts +82 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
- package/src/__tests__/conversation-lifecycle.test.ts +173 -0
- package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
- package/src/__tests__/conversation-pairing.test.ts +54 -0
- package/src/__tests__/conversation-process-callsite.test.ts +4 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
- package/src/__tests__/conversation-queue.test.ts +4 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +76 -9
- package/src/__tests__/conversation-slash-queue.test.ts +59 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
- package/src/__tests__/conversation-sync-tags.test.ts +235 -0
- 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 +3 -2
- package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
- package/src/__tests__/disk-pressure-tools.test.ts +1 -0
- package/src/__tests__/dm-backfill.test.ts +121 -10
- package/src/__tests__/document-tool-security.test.ts +258 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/edit-propagation.test.ts +33 -0
- package/src/__tests__/empty-response-pipeline.test.ts +0 -4
- package/src/__tests__/external-plugin-loader.test.ts +60 -36
- package/src/__tests__/filing-service.test.ts +140 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
- package/src/__tests__/helpers/tar-fixtures.ts +39 -0
- package/src/__tests__/helpers/wait-for.ts +21 -0
- package/src/__tests__/history-repair-pipeline.test.ts +0 -3
- package/src/__tests__/history-repair.test.ts +73 -0
- package/src/__tests__/host-app-control-proxy.test.ts +266 -10
- package/src/__tests__/image-credentials.test.ts +1 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
- package/src/__tests__/inference-profile-reaper.test.ts +4 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
- package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
- package/src/__tests__/injector-chain.test.ts +10 -8
- package/src/__tests__/install-skill-routing.test.ts +155 -37
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +92 -3
- package/src/__tests__/list-messages-page-latest.test.ts +55 -0
- package/src/__tests__/llm-call-pipeline.test.ts +0 -3
- package/src/__tests__/llm-catalog-parity.test.ts +55 -13
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +34 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
- package/src/__tests__/llm-usage-store.test.ts +114 -0
- package/src/__tests__/managed-profile-guard.test.ts +31 -29
- package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
- package/src/__tests__/managed-store.test.ts +84 -192
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
- package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
- package/src/__tests__/oauth-commands-routes.test.ts +168 -16
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
- package/src/__tests__/openai-provider.test.ts +24 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
- package/src/__tests__/persistence-pipeline.test.ts +0 -2
- package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
- package/src/__tests__/platform.test.ts +2 -0
- package/src/__tests__/plugin-api-shim.test.ts +125 -0
- package/src/__tests__/plugin-bootstrap.test.ts +10 -36
- package/src/__tests__/plugin-external-api.test.ts +68 -0
- package/src/__tests__/plugin-registry.test.ts +0 -77
- package/src/__tests__/plugin-route-contribution.test.ts +0 -1
- package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
- package/src/__tests__/plugin-types.test.ts +3 -13
- package/src/__tests__/process-message-background-slack.test.ts +8 -1
- package/src/__tests__/process-message-display-content.test.ts +421 -0
- package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
- package/src/__tests__/provider-error-scenarios.test.ts +111 -0
- package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +8 -8
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
- package/src/__tests__/schedule-routes.test.ts +50 -3
- package/src/__tests__/schedule-store.test.ts +94 -0
- package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
- package/src/__tests__/schema-transforms.test.ts +20 -0
- package/src/__tests__/search-skills-unified.test.ts +0 -5
- package/src/__tests__/server-history-render.test.ts +43 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
- package/src/__tests__/skill-load-tool.test.ts +27 -89
- package/src/__tests__/skill-memory.test.ts +23 -3
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
- package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
- package/src/__tests__/skills-install-extract.test.ts +49 -38
- package/src/__tests__/skills-install-staging.test.ts +159 -0
- package/src/__tests__/skills-uninstall.test.ts +9 -41
- package/src/__tests__/skills.test.ts +51 -58
- package/src/__tests__/slack-channel-config.test.ts +9 -0
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/system-prompt.test.ts +737 -63
- package/src/__tests__/terminal-tools.test.ts +28 -1
- package/src/__tests__/thread-backfill.test.ts +557 -27
- package/src/__tests__/title-generate-pipeline.test.ts +0 -13
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
- package/src/__tests__/tool-error-pipeline.test.ts +0 -3
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +16 -4
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
- package/src/__tests__/turn-events-store.test.ts +256 -0
- package/src/__tests__/twilio-routes.test.ts +4 -0
- package/src/__tests__/user-plugin-loader.test.ts +0 -7
- package/src/__tests__/voice-session-bridge.test.ts +198 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
- package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
- package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
- package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
- package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
- package/src/acp/resolve-agent.ts +1 -1
- package/src/agent/image-optimize.ts +13 -5
- package/src/calls/voice-session-bridge.ts +61 -42
- package/src/channels/types.ts +108 -0
- package/src/cli/__tests__/unknown-command.test.ts +24 -0
- package/src/cli/commands/__tests__/changelog.test.ts +304 -319
- package/src/cli/commands/__tests__/schedules.test.ts +491 -0
- package/src/cli/commands/changelog.ts +106 -42
- package/src/cli/commands/conversations.ts +102 -17
- package/src/cli/commands/default-action.ts +10 -53
- package/src/cli/commands/notifications.ts +329 -317
- package/src/cli/commands/plugins.ts +185 -0
- package/src/cli/commands/schedules.ts +391 -0
- package/src/cli/commands/telemetry.ts +40 -0
- package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
- package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
- package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
- package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
- package/src/cli/lib/cli-colors.ts +12 -0
- package/src/cli/lib/confirm-prompt.ts +79 -0
- package/src/cli/lib/install-from-github.ts +304 -0
- package/src/cli/lib/list-installed-plugins.ts +137 -0
- package/src/cli/lib/uninstall-plugin.ts +82 -0
- package/src/cli/lib/unknown-command.ts +111 -0
- package/src/cli/program.ts +38 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
- package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
- package/src/config/bundled-skills/document/SKILL.md +23 -3
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
- package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
- package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
- package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
- package/src/config/bundled-tool-registry.ts +6 -0
- package/src/config/feature-flag-registry.json +41 -1
- package/src/config/loader.ts +64 -38
- package/src/config/schema.ts +7 -10
- package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
- package/src/config/schemas/channels.ts +8 -0
- package/src/config/schemas/compaction.ts +28 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm-request-logs.ts +31 -7
- package/src/config/schemas/llm.ts +3 -0
- package/src/config/schemas/memory-retrieval.ts +18 -0
- package/src/config/schemas/tools.ts +14 -0
- package/src/config/skills.ts +3 -96
- package/src/context/compactor.ts +1047 -0
- package/src/context/token-estimator.ts +2 -2
- package/src/context/window-manager.ts +197 -1520
- package/src/credential-execution/managed-catalog.ts +37 -0
- package/src/credential-health/credential-health-service.ts +280 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +34 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
- package/src/daemon/approval-generators.ts +8 -6
- package/src/daemon/config-watcher.ts +94 -31
- package/src/daemon/conversation-agent-loop.ts +169 -9
- package/src/daemon/conversation-error.ts +171 -37
- package/src/daemon/conversation-lifecycle.ts +53 -40
- package/src/daemon/conversation-messaging.ts +25 -6
- package/src/daemon/conversation-process.ts +49 -12
- package/src/daemon/conversation-runtime-assembly.ts +16 -1
- package/src/daemon/conversation-slash.ts +12 -5
- package/src/daemon/conversation-store.ts +11 -4
- package/src/daemon/conversation-tool-setup.ts +39 -7
- package/src/daemon/conversation.ts +33 -1
- package/src/daemon/external-plugins-bootstrap.ts +217 -181
- package/src/daemon/first-greeting.ts +22 -2
- package/src/daemon/handlers/config-model.ts +6 -5
- package/src/daemon/handlers/config-slack-channel.ts +15 -3
- package/src/daemon/handlers/shared.ts +14 -5
- package/src/daemon/handlers/skills.ts +111 -108
- package/src/daemon/history-repair.ts +28 -1
- package/src/daemon/host-app-control-proxy.ts +98 -23
- package/src/daemon/lifecycle.ts +45 -35
- package/src/daemon/meet-host-supervisor.ts +5 -4
- package/src/daemon/memory-v2-startup.ts +49 -0
- package/src/daemon/message-protocol.ts +1 -0
- package/src/daemon/message-types/conversations.ts +25 -0
- package/src/daemon/message-types/messages.ts +61 -0
- package/src/daemon/message-types/subagents.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pkb-reminder-builder.test.ts +1 -1
- package/src/daemon/pkb-reminder-builder.ts +1 -1
- package/src/daemon/plugin-source-watcher.ts +146 -0
- package/src/daemon/process-message.ts +21 -3
- package/src/daemon/server.ts +11 -2
- package/src/daemon/skill-memory-refresh.ts +29 -0
- package/src/documents/document-store.ts +221 -3
- package/src/embedded/plugin-api.ts +40 -0
- package/src/filing/filing-service.ts +39 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +91 -6
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +41 -0
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/feed-types.ts +22 -0
- package/src/home/post-connect-feed.ts +1 -0
- package/src/index.ts +18 -1
- package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
- package/src/mcp/client.ts +20 -4
- package/src/media/image-credentials.ts +3 -3
- package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
- package/src/memory/__tests__/conversation-queries.test.ts +263 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
- package/src/memory/__tests__/message-content.test.ts +35 -0
- package/src/memory/bookmark-crud.ts +42 -10
- package/src/memory/context-search/sources/conversations.ts +62 -2
- package/src/memory/context-search/sources/workspace.ts +4 -0
- package/src/memory/conversation-crud.ts +63 -19
- package/src/memory/conversation-queries.ts +110 -10
- package/src/memory/db-init.ts +6 -0
- package/src/memory/delivery-crud.ts +152 -5
- package/src/memory/embedding-backend.ts +4 -4
- package/src/memory/external-conversation-store.ts +66 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
- package/src/memory/graph/conversation-graph-memory.ts +31 -15
- package/src/memory/graph/tools.ts +3 -3
- package/src/memory/indexer.ts +34 -29
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
- package/src/memory/jobs/embed-concept-page.ts +20 -11
- package/src/memory/jobs-worker.ts +6 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +17 -10
- package/src/memory/llm-request-log-source.ts +19 -52
- package/src/memory/llm-usage-store.ts +125 -5
- package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
- package/src/memory/message-content.ts +1 -1
- package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
- package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
- package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
- package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
- package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/onboarding-events-store.ts +106 -0
- package/src/memory/schema/bookmarks.ts +0 -2
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/inference.ts +1 -3
- package/src/memory/schema/infrastructure.ts +12 -0
- package/src/memory/turn-events-store.ts +127 -2
- package/src/memory/v2/__tests__/activation.test.ts +0 -8
- package/src/memory/v2/__tests__/injection.test.ts +98 -8
- package/src/memory/v2/__tests__/migration.test.ts +87 -0
- package/src/memory/v2/__tests__/page-index.test.ts +83 -0
- package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
- package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
- package/src/memory/v2/__tests__/router.test.ts +15 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
- package/src/memory/v2/injection.ts +32 -6
- package/src/memory/v2/migration.ts +49 -19
- package/src/memory/v2/page-index.ts +35 -5
- package/src/memory/v2/prompts/router.ts +11 -8
- package/src/memory/v2/prompts/sweep.ts +2 -2
- package/src/memory/v2/qdrant.ts +135 -7
- package/src/memory/v2/router.ts +9 -8
- package/src/memory/v2/skill-store.ts +120 -35
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
- package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
- package/src/messaging/providers/slack/adapter.ts +43 -5
- package/src/messaging/providers/slack/client.ts +27 -0
- package/src/messaging/providers/slack/deep-link.ts +65 -0
- package/src/messaging/providers/slack/download.ts +104 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
- package/src/messaging/providers/slack/message-metadata.ts +27 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
- package/src/messaging/providers/slack/render-transcript.ts +69 -5
- package/src/messaging/providers/slack/types.ts +20 -1
- package/src/notifications/conversation-pairing.ts +2 -1
- package/src/notifications/decision-engine.ts +2 -1
- package/src/notifications/emit-signal.ts +20 -1
- package/src/notifications/home-feed-side-effect.ts +54 -0
- package/src/notifications/signal.ts +3 -1
- package/src/oauth/connection-resolver.ts +8 -4
- package/src/oauth/platform-connection.ts +6 -2
- package/src/oauth/seed-providers.ts +10 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/question-prompter.test.ts +416 -0
- package/src/permissions/question-prompter.ts +294 -0
- package/src/platform/client.test.ts +1 -1
- package/src/platform/client.ts +1 -1
- package/src/plugin-api/constants.ts +26 -0
- package/src/plugin-api/index.ts +34 -1
- package/src/plugin-api/types.ts +104 -22
- package/src/plugins/defaults/circuit-breaker.ts +0 -5
- package/src/plugins/defaults/compaction.ts +0 -4
- package/src/plugins/defaults/empty-response.ts +0 -2
- package/src/plugins/defaults/history-repair.ts +0 -2
- package/src/plugins/defaults/injectors.ts +36 -3
- package/src/plugins/defaults/llm-call.ts +0 -2
- package/src/plugins/defaults/memory-retrieval.ts +0 -1
- package/src/plugins/defaults/overflow-reduce.ts +0 -1
- package/src/plugins/defaults/persistence.ts +0 -2
- package/src/plugins/defaults/title-generate.ts +0 -5
- package/src/plugins/defaults/token-estimate.ts +0 -2
- package/src/plugins/defaults/tool-error.ts +0 -7
- package/src/plugins/defaults/tool-execute.ts +0 -2
- package/src/plugins/defaults/tool-result-truncate.ts +0 -4
- package/src/plugins/ensure-plugin-api-shim.ts +96 -0
- package/src/plugins/external-api.ts +104 -0
- package/src/plugins/external-plugin-loader.ts +105 -32
- package/src/plugins/feature-gate.ts +22 -0
- package/src/plugins/pipeline.ts +37 -0
- package/src/plugins/registry.ts +48 -80
- package/src/plugins/types.ts +31 -26
- package/src/plugins/user-loader.ts +21 -2
- package/src/proactive-artifact/aux-message-injector.ts +11 -0
- package/src/proactive-artifact/job.test.ts +37 -5
- package/src/prompts/__tests__/system-prompt.test.ts +12 -0
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
- package/src/prompts/normalize-onboarding.ts +27 -0
- package/src/prompts/sections.ts +302 -0
- package/src/prompts/system-prompt.ts +63 -166
- package/src/prompts/templates/BOOTSTRAP.md +17 -1
- package/src/prompts/templates/system-sections.ts +173 -0
- package/src/providers/__tests__/inference.test.ts +22 -7
- package/src/providers/anthropic/client.ts +28 -28
- package/src/providers/connection-resolution.ts +7 -0
- package/src/providers/inference/adapter-factory.ts +41 -4
- package/src/providers/inference/connections.ts +74 -29
- package/src/providers/inference/resolve-auth.ts +12 -4
- package/src/providers/model-catalog.ts +294 -12
- package/src/providers/openai/chat-completions-provider.ts +10 -2
- package/src/providers/openrouter/client.ts +7 -0
- package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
- package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
- package/src/providers/provider-availability.ts +17 -2
- package/src/providers/provider-catalog-visibility.ts +36 -0
- package/src/providers/registry.ts +22 -14
- package/src/providers/retry.ts +47 -1
- package/src/runtime/__tests__/agent-wake.test.ts +152 -0
- package/src/runtime/agent-wake.ts +42 -14
- package/src/runtime/auth/route-policy.ts +8 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/http-types.ts +19 -0
- package/src/runtime/migrations/origin-mode.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +107 -20
- package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
- package/src/runtime/routes/acp-routes-list.test.ts +143 -0
- package/src/runtime/routes/acp-routes.ts +5 -3
- package/src/runtime/routes/auth-routes.ts +1 -1
- package/src/runtime/routes/bookmark-routes.ts +5 -3
- package/src/runtime/routes/btw-routes.ts +5 -1
- package/src/runtime/routes/channel-availability-routes.ts +121 -0
- package/src/runtime/routes/conversation-cli-routes.ts +44 -3
- package/src/runtime/routes/conversation-list-routes.ts +3 -20
- package/src/runtime/routes/conversation-management-routes.ts +17 -42
- package/src/runtime/routes/conversation-query-routes.ts +40 -35
- package/src/runtime/routes/conversation-routes.ts +90 -11
- package/src/runtime/routes/documents-routes.ts +25 -86
- package/src/runtime/routes/group-routes.ts +5 -0
- package/src/runtime/routes/inbound-conversation.ts +28 -8
- package/src/runtime/routes/inbound-message-handler.ts +236 -41
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
- package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
- package/src/runtime/routes/inference-provider-connection-routes.ts +65 -21
- package/src/runtime/routes/integrations/slack/share.ts +4 -52
- package/src/runtime/routes/integrations/slack/token.ts +43 -0
- package/src/runtime/routes/integrations/twilio.ts +6 -13
- package/src/runtime/routes/notification-routes.ts +1 -1
- package/src/runtime/routes/oauth-commands-routes.ts +105 -15
- package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
- package/src/runtime/routes/question-routes.ts +259 -0
- package/src/runtime/routes/rename-conversation-routes.ts +2 -33
- package/src/runtime/routes/schedule-routes.ts +4 -7
- package/src/runtime/routes/subagents-routes.ts +57 -18
- package/src/runtime/routes/telemetry-routes.ts +27 -0
- package/src/runtime/routes/tts-routes.ts +27 -2
- package/src/runtime/routes/workspace-routes.test.ts +43 -0
- package/src/runtime/routes/workspace-routes.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +39 -7
- package/src/runtime/sync/resource-sync-events.ts +93 -1
- package/src/schedule/schedule-store.ts +27 -2
- package/src/schedule/scheduler.ts +9 -1
- package/src/security/__tests__/untrusted-content.test.ts +86 -0
- package/src/security/untrusted-content.ts +93 -8
- package/src/skills/catalog-files.ts +1 -1
- package/src/skills/catalog-install.ts +233 -116
- package/src/skills/clawhub.ts +70 -13
- package/src/skills/managed-store.ts +4 -119
- package/src/skills/skillssh-registry.ts +27 -48
- package/src/subagent/manager.ts +15 -7
- package/src/telemetry/types.ts +113 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
- package/src/telemetry/usage-telemetry-reporter.ts +113 -7
- package/src/tools/apps/executors.ts +58 -7
- package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
- package/src/tools/ask-question/ask-question-tool.ts +304 -0
- package/src/tools/browser/browser-execution.ts +15 -11
- package/src/tools/computer-use/definitions.ts +3 -3
- package/src/tools/credentials/vault.ts +1 -1
- package/src/tools/document/document-tool.ts +124 -1
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +5 -2
- package/src/tools/host-filesystem/transfer.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +1 -1
- package/src/tools/permission-checker.ts +1 -1
- package/src/tools/registry.ts +17 -7
- package/src/tools/schedule/create.ts +2 -2
- package/src/tools/schema-transforms.ts +7 -2
- package/src/tools/side-effects.ts +1 -0
- package/src/tools/skills/delete-managed.ts +4 -4
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/scaffold-managed.ts +3 -2
- package/src/tools/subagent/notify-parent.ts +1 -1
- package/src/tools/system/request-permission.ts +2 -2
- package/src/tools/terminal/safe-env.ts +60 -1
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/types.ts +72 -21
- package/src/tools/ui-surface/definitions.ts +6 -5
- package/src/tts/__tests__/provider-adapters.test.ts +76 -2
- package/src/tts/providers/elevenlabs-provider.ts +75 -1
- package/src/types/onboarding-context.ts +2 -0
- package/src/util/errors.ts +17 -0
- package/src/util/platform.ts +10 -0
- package/src/watcher/__tests__/engine.test.ts +22 -0
- package/src/watcher/engine.ts +6 -2
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
- package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
- package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
- package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/runner.ts +39 -9
- package/src/workspace/migrations/types.ts +4 -0
- package/examples/plugins/echo/bun.lock +0 -25
- package/src/__tests__/context-window-manager.test.ts +0 -2481
- package/src/context/__tests__/compact-prompt.test.ts +0 -63
- package/src/context/prompts/compact.md +0 -26
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
- /package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
1
2
|
import { loadConfig } from "../config/loader.js";
|
|
2
3
|
import { wrapWithCallSiteRouting } from "../providers/call-site-routing.js";
|
|
3
4
|
import { resolveDefaultProvider } from "../providers/connection-resolution.js";
|
|
5
|
+
import { listProviders } from "../providers/registry.js";
|
|
4
6
|
import type { Provider } from "../providers/types.js";
|
|
5
7
|
import {
|
|
6
8
|
APPROVAL_COPY_MAX_TOKENS,
|
|
@@ -16,6 +18,7 @@ import type {
|
|
|
16
18
|
ApprovalConversationResult,
|
|
17
19
|
ApprovalCopyGenerator,
|
|
18
20
|
} from "../runtime/http-types.js";
|
|
21
|
+
import { ProviderNotConfiguredError } from "../util/errors.js";
|
|
19
22
|
|
|
20
23
|
// ---------------------------------------------------------------------------
|
|
21
24
|
// Approval conversation generator constants
|
|
@@ -142,14 +145,13 @@ export function createApprovalConversationGenerator(): ApprovalConversationGener
|
|
|
142
145
|
// Connection-aware default + per-call routing. `resolveDefaultProvider`
|
|
143
146
|
// throws `ConnectionResolutionError` on hard config errors (missing /
|
|
144
147
|
// unknown / mismatched connection) and returns null on soft credential
|
|
145
|
-
// failures (
|
|
146
|
-
// provider available" and throw a domain-specific error below. We do
|
|
147
|
-
// not pre-gate on `listProviders()` because the default provider lives
|
|
148
|
-
// behind a `provider_connection` and never appears in the registry's
|
|
149
|
-
// initialization-time provider list.
|
|
148
|
+
// failures (missing credential, platform auth unavailable).
|
|
150
149
|
const baseProvider = await resolveDefaultProvider(config);
|
|
151
150
|
if (!baseProvider) {
|
|
152
|
-
|
|
151
|
+
const resolved = resolveCallSiteConfig("mainAgent", config.llm);
|
|
152
|
+
throw new ProviderNotConfiguredError(resolved.provider, listProviders(), {
|
|
153
|
+
connectionName: resolved.provider_connection,
|
|
154
|
+
});
|
|
153
155
|
}
|
|
154
156
|
const provider = wrapWithCallSiteRouting(baseProvider, config);
|
|
155
157
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* for changes.
|
|
5
5
|
*/
|
|
6
6
|
import {
|
|
7
|
+
type Dirent,
|
|
7
8
|
existsSync,
|
|
8
9
|
type FSWatcher,
|
|
9
10
|
mkdirSync,
|
|
@@ -12,13 +13,12 @@ import {
|
|
|
12
13
|
watch,
|
|
13
14
|
watchFile,
|
|
14
15
|
} from "node:fs";
|
|
15
|
-
import { join } from "node:path";
|
|
16
|
+
import { join, relative } from "node:path";
|
|
16
17
|
|
|
17
18
|
import { getConfig, invalidateConfigCache } from "../config/loader.js";
|
|
18
19
|
import type { MemoryCleanupConfig } from "../config/schemas/memory-lifecycle.js";
|
|
19
20
|
import { resetCleanupScheduleThrottle } from "../memory/cleanup-schedule-state.js";
|
|
20
21
|
import { clearEmbeddingBackendCache } from "../memory/embedding-backend.js";
|
|
21
|
-
import { invalidateLlmRequestLogSourceCache } from "../memory/llm-request-log-source.js";
|
|
22
22
|
import { initializeProviders } from "../providers/registry.js";
|
|
23
23
|
import { handleCancelSignal } from "../signals/cancel.js";
|
|
24
24
|
import { handleConversationUndoSignal } from "../signals/conversation-undo.js";
|
|
@@ -38,6 +38,25 @@ import { reloadMcpServers } from "./mcp-reload-service.js";
|
|
|
38
38
|
|
|
39
39
|
const log = getLogger("config-watcher");
|
|
40
40
|
|
|
41
|
+
const SKILL_WATCH_SKIPPED_DIRS = new Set([
|
|
42
|
+
"node_modules",
|
|
43
|
+
".git",
|
|
44
|
+
"__pycache__",
|
|
45
|
+
".install-staging",
|
|
46
|
+
".cache",
|
|
47
|
+
".next",
|
|
48
|
+
".turbo",
|
|
49
|
+
".venv",
|
|
50
|
+
"coverage",
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
function isSkippedSkillWatchPath(relativePath: string): boolean {
|
|
54
|
+
if (relativePath === "(unknown)") return false;
|
|
55
|
+
|
|
56
|
+
const segments = relativePath.split(/[\\/]+/).filter(Boolean);
|
|
57
|
+
return segments.some((segment) => SKILL_WATCH_SKIPPED_DIRS.has(segment));
|
|
58
|
+
}
|
|
59
|
+
|
|
41
60
|
/**
|
|
42
61
|
* Attach a resilient error handler to an FSWatcher so that async errors
|
|
43
62
|
* (e.g. ENXIO when a Unix socket file like `gateway.sock` appears in a
|
|
@@ -141,7 +160,6 @@ export class ConfigWatcher {
|
|
|
141
160
|
return false;
|
|
142
161
|
}
|
|
143
162
|
clearEmbeddingBackendCache();
|
|
144
|
-
invalidateLlmRequestLogSourceCache();
|
|
145
163
|
// If cleanup retention settings changed, reset the cleanup scheduler
|
|
146
164
|
// throttle so the next worker tick re-enqueues jobs with the new values
|
|
147
165
|
// instead of waiting out the remaining enqueueIntervalMs (default 6h).
|
|
@@ -160,6 +178,8 @@ export class ConfigWatcher {
|
|
|
160
178
|
* Start all file watchers. `onConversationEvict` is called when watched
|
|
161
179
|
* files change and conversations need to be evicted for reload.
|
|
162
180
|
* `onIdentityChanged` is called when IDENTITY.md changes on disk.
|
|
181
|
+
* `onSkillsChanged` is called after skill directory changes evict
|
|
182
|
+
* conversations.
|
|
163
183
|
*/
|
|
164
184
|
start(
|
|
165
185
|
onConversationEvict: () => void,
|
|
@@ -167,6 +187,7 @@ export class ConfigWatcher {
|
|
|
167
187
|
onSoundsConfigChanged?: () => void,
|
|
168
188
|
onAvatarChanged?: () => void,
|
|
169
189
|
onConfigChanged?: () => void,
|
|
190
|
+
onSkillsChanged?: () => void,
|
|
170
191
|
): void {
|
|
171
192
|
// Reset the stopped flag so a stop()→start() cycle on the same
|
|
172
193
|
// instance resumes hot-reload instead of silently bailing in every
|
|
@@ -222,7 +243,7 @@ export class ConfigWatcher {
|
|
|
222
243
|
|
|
223
244
|
this.startSignalsWatcher();
|
|
224
245
|
this.startUsersWatcher(onConversationEvict);
|
|
225
|
-
this.startSkillsWatchers(onConversationEvict);
|
|
246
|
+
this.startSkillsWatchers(onConversationEvict, onSkillsChanged);
|
|
226
247
|
}
|
|
227
248
|
|
|
228
249
|
stop(): void {
|
|
@@ -422,14 +443,20 @@ export class ConfigWatcher {
|
|
|
422
443
|
}
|
|
423
444
|
}
|
|
424
445
|
|
|
425
|
-
private startSkillsWatchers(
|
|
446
|
+
private startSkillsWatchers(
|
|
447
|
+
onConversationEvict: () => void,
|
|
448
|
+
onSkillsChanged?: () => void,
|
|
449
|
+
): void {
|
|
426
450
|
const skillsDir = getWorkspaceSkillsDir();
|
|
427
451
|
if (!existsSync(skillsDir)) return;
|
|
428
452
|
|
|
429
453
|
const scheduleSkillsReload = (file: string): void => {
|
|
430
|
-
|
|
454
|
+
if (isSkippedSkillWatchPath(file)) return;
|
|
455
|
+
|
|
456
|
+
this.debounceTimers.schedule("skills:catalog", () => {
|
|
431
457
|
log.info({ file }, "Skill file changed, reloading");
|
|
432
458
|
onConversationEvict();
|
|
459
|
+
onSkillsChanged?.();
|
|
433
460
|
});
|
|
434
461
|
};
|
|
435
462
|
|
|
@@ -478,43 +505,79 @@ export class ConfigWatcher {
|
|
|
478
505
|
}
|
|
479
506
|
};
|
|
480
507
|
|
|
481
|
-
const
|
|
482
|
-
|
|
508
|
+
const formatSkillChangeLabel = (
|
|
509
|
+
dirPath: string,
|
|
510
|
+
filename: string,
|
|
511
|
+
): string => {
|
|
512
|
+
if (filename === "(unknown)") {
|
|
513
|
+
const relativeDir = relative(skillsDir, dirPath);
|
|
514
|
+
return relativeDir || "(unknown)";
|
|
515
|
+
}
|
|
516
|
+
const relativeFile = relative(skillsDir, join(dirPath, filename));
|
|
517
|
+
return relativeFile || filename;
|
|
518
|
+
};
|
|
483
519
|
|
|
520
|
+
const enumerateSkillSubdirectories = (
|
|
521
|
+
dirPath: string,
|
|
522
|
+
acc: Set<string>,
|
|
523
|
+
): boolean => {
|
|
524
|
+
let entries: Dirent[];
|
|
484
525
|
try {
|
|
485
|
-
|
|
486
|
-
for (const entry of entries) {
|
|
487
|
-
if (!entry.isDirectory()) continue;
|
|
488
|
-
const childDir = join(skillsDir, entry.name);
|
|
489
|
-
nextChildDirs.add(childDir);
|
|
490
|
-
|
|
491
|
-
if (childWatchers.has(childDir)) continue;
|
|
492
|
-
|
|
493
|
-
const watcher = watchDir(childDir, (filename) => {
|
|
494
|
-
const label =
|
|
495
|
-
filename === "(unknown)"
|
|
496
|
-
? entry.name
|
|
497
|
-
: `${entry.name}/${filename}`;
|
|
498
|
-
scheduleSkillsReload(label);
|
|
499
|
-
});
|
|
500
|
-
if (watcher) {
|
|
501
|
-
childWatchers.set(childDir, watcher);
|
|
502
|
-
}
|
|
503
|
-
}
|
|
526
|
+
entries = readdirSync(dirPath, { withFileTypes: true });
|
|
504
527
|
} catch (err) {
|
|
505
|
-
log.warn({ err,
|
|
528
|
+
log.warn({ err, dirPath }, "Failed to enumerate skill directories");
|
|
529
|
+
return dirPath !== skillsDir;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
for (const entry of entries) {
|
|
533
|
+
if (!entry.isDirectory()) continue;
|
|
534
|
+
if (SKILL_WATCH_SKIPPED_DIRS.has(entry.name)) continue;
|
|
535
|
+
const childDir = join(dirPath, entry.name);
|
|
536
|
+
acc.add(childDir);
|
|
537
|
+
enumerateSkillSubdirectories(childDir, acc);
|
|
538
|
+
}
|
|
539
|
+
return true;
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
const closeChildWatcher = (dirPath: string, watcher: FSWatcher): void => {
|
|
543
|
+
watcher.close();
|
|
544
|
+
childWatchers.delete(dirPath);
|
|
545
|
+
removeWatcher(watcher);
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
const refreshChildWatchers = (): void => {
|
|
549
|
+
const nextChildDirs = new Set<string>();
|
|
550
|
+
if (!enumerateSkillSubdirectories(skillsDir, nextChildDirs)) {
|
|
551
|
+
for (const [childDir, watcher] of childWatchers.entries()) {
|
|
552
|
+
closeChildWatcher(childDir, watcher);
|
|
553
|
+
}
|
|
506
554
|
return;
|
|
507
555
|
}
|
|
508
556
|
|
|
509
557
|
for (const [childDir, watcher] of childWatchers.entries()) {
|
|
510
558
|
if (nextChildDirs.has(childDir)) continue;
|
|
511
|
-
watcher
|
|
512
|
-
|
|
513
|
-
|
|
559
|
+
closeChildWatcher(childDir, watcher);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
for (const childDir of nextChildDirs) {
|
|
563
|
+
if (childWatchers.has(childDir)) continue;
|
|
564
|
+
|
|
565
|
+
const watcher = watchDir(childDir, (filename) => {
|
|
566
|
+
const file = formatSkillChangeLabel(childDir, filename);
|
|
567
|
+
if (isSkippedSkillWatchPath(file)) return;
|
|
568
|
+
|
|
569
|
+
scheduleSkillsReload(file);
|
|
570
|
+
refreshChildWatchers();
|
|
571
|
+
});
|
|
572
|
+
if (watcher) {
|
|
573
|
+
childWatchers.set(childDir, watcher);
|
|
574
|
+
}
|
|
514
575
|
}
|
|
515
576
|
};
|
|
516
577
|
|
|
517
578
|
const rootWatcher = watchDir(skillsDir, (filename) => {
|
|
579
|
+
if (isSkippedSkillWatchPath(filename)) return;
|
|
580
|
+
|
|
518
581
|
scheduleSkillsReload(filename);
|
|
519
582
|
refreshChildWatchers();
|
|
520
583
|
});
|
|
@@ -33,6 +33,7 @@ import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
|
33
33
|
import { getConfig } from "../config/loader.js";
|
|
34
34
|
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
35
35
|
import type { ContextWindowConfig } from "../config/types.js";
|
|
36
|
+
import { runEmergencyCompaction } from "../context/compactor.js";
|
|
36
37
|
import {
|
|
37
38
|
derefToolResultReReads,
|
|
38
39
|
postTurnTruncateToolResults,
|
|
@@ -42,6 +43,7 @@ import {
|
|
|
42
43
|
getCalibrationProviderKey,
|
|
43
44
|
} from "../context/token-estimator.js";
|
|
44
45
|
import type { ContextWindowManager } from "../context/window-manager.js";
|
|
46
|
+
import { getDocumentsForConversation } from "../documents/document-store.js";
|
|
45
47
|
import type { ToolProfiler } from "../events/tool-profiling-listener.js";
|
|
46
48
|
import { writeRelationshipState } from "../home/relationship-state-writer.js";
|
|
47
49
|
import {
|
|
@@ -79,6 +81,8 @@ import {
|
|
|
79
81
|
shouldExposePersonalMemory,
|
|
80
82
|
} from "../memory/v2/static-context.js";
|
|
81
83
|
import type { PermissionPrompter } from "../permissions/prompter.js";
|
|
84
|
+
import { HOOKS } from "../plugin-api/constants.js";
|
|
85
|
+
import type { UserPromptSubmitContext } from "../plugin-api/types.js";
|
|
82
86
|
import { defaultCompactionTerminal } from "../plugins/defaults/compaction.js";
|
|
83
87
|
import { defaultHistoryRepairTerminal } from "../plugins/defaults/history-repair.js";
|
|
84
88
|
import {
|
|
@@ -90,7 +94,7 @@ import {
|
|
|
90
94
|
import { defaultPersistenceTerminal } from "../plugins/defaults/persistence.js";
|
|
91
95
|
import { defaultTitleGenerateTerminal } from "../plugins/defaults/title-generate.js";
|
|
92
96
|
import { defaultTokenEstimateTerminal } from "../plugins/defaults/token-estimate.js";
|
|
93
|
-
import { DEFAULT_TIMEOUTS, runPipeline } from "../plugins/pipeline.js";
|
|
97
|
+
import { DEFAULT_TIMEOUTS, runHook, runPipeline } from "../plugins/pipeline.js";
|
|
94
98
|
import { getMiddlewaresFor } from "../plugins/registry.js";
|
|
95
99
|
import type {
|
|
96
100
|
CircuitBreakerArgs,
|
|
@@ -124,6 +128,7 @@ import type { Provider } from "../providers/types.js";
|
|
|
124
128
|
import { resolveActorTrust } from "../runtime/actor-trust-resolver.js";
|
|
125
129
|
import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
126
130
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
131
|
+
import { publishConversationMessagesChanged } from "../runtime/sync/resource-sync-events.js";
|
|
127
132
|
import { redactSecrets } from "../security/secret-scanner.js";
|
|
128
133
|
import { getSubagentManager } from "../subagent/index.js";
|
|
129
134
|
import type { UsageActor } from "../usage/actors.js";
|
|
@@ -202,6 +207,10 @@ import type {
|
|
|
202
207
|
} from "./message-protocol.js";
|
|
203
208
|
import type { MemoryRecalled } from "./message-types/memory.js";
|
|
204
209
|
import type { ConfirmationStateChanged } from "./message-types/messages.js";
|
|
210
|
+
import {
|
|
211
|
+
conversationMetadataSyncTag,
|
|
212
|
+
SYNC_TAGS,
|
|
213
|
+
} from "./message-types/sync.js";
|
|
205
214
|
import { parseActualTokensFromError } from "./parse-actual-tokens-from-error.js";
|
|
206
215
|
import type { TraceEmitter } from "./trace-emitter.js";
|
|
207
216
|
import type { TrustContext } from "./trust-context.js";
|
|
@@ -455,6 +464,15 @@ export interface AgentLoopConversationContext {
|
|
|
455
464
|
readonly contextWindowManager: ContextWindowManager;
|
|
456
465
|
contextCompactedMessageCount: number;
|
|
457
466
|
contextCompactedAt: number | null;
|
|
467
|
+
/**
|
|
468
|
+
* Set by `applyCompactionResult` when compaction strips runtime injections
|
|
469
|
+
* from the preserved tail. The next agent loop turn promotes this into a
|
|
470
|
+
* `compactedThisTurn` signal so NOW.md, PKB, and the v2 static block are
|
|
471
|
+
* re-injected on the first turn following `/compact` (which runs outside
|
|
472
|
+
* the agent loop and so has no other way to surface that compaction
|
|
473
|
+
* happened just before this turn).
|
|
474
|
+
*/
|
|
475
|
+
pendingPostCompactReinject: boolean;
|
|
458
476
|
/** Tracks consecutive compaction failures (summary LLM call threw). */
|
|
459
477
|
consecutiveCompactionFailures: number;
|
|
460
478
|
/** Timestamp (ms since epoch) until which the circuit breaker is open. */
|
|
@@ -767,6 +785,18 @@ export async function runAgentLoopImpl(
|
|
|
767
785
|
|
|
768
786
|
ctx.profiler.startRequest();
|
|
769
787
|
let turnStarted = false;
|
|
788
|
+
const state = createEventHandlerState();
|
|
789
|
+
let persistedErrorAssistantMessage = false;
|
|
790
|
+
|
|
791
|
+
const publishLoopMessagesChanged = (): void => {
|
|
792
|
+
if (
|
|
793
|
+
state.lastAssistantMessageId ||
|
|
794
|
+
state.persistedToolUseIds.size > 0 ||
|
|
795
|
+
persistedErrorAssistantMessage
|
|
796
|
+
) {
|
|
797
|
+
publishConversationMessagesChanged(ctx.conversationId);
|
|
798
|
+
}
|
|
799
|
+
};
|
|
770
800
|
|
|
771
801
|
// Populate Sentry scope with conversation-specific tags so any exception
|
|
772
802
|
// captured during this turn (e.g. inside agent/loop.ts) can be
|
|
@@ -871,6 +901,13 @@ export async function runAgentLoopImpl(
|
|
|
871
901
|
conversationId: ctx.conversationId,
|
|
872
902
|
title,
|
|
873
903
|
});
|
|
904
|
+
onEvent({
|
|
905
|
+
type: "sync_changed",
|
|
906
|
+
tags: [
|
|
907
|
+
SYNC_TAGS.conversationsList,
|
|
908
|
+
conversationMetadataSyncTag(ctx.conversationId),
|
|
909
|
+
],
|
|
910
|
+
});
|
|
874
911
|
},
|
|
875
912
|
};
|
|
876
913
|
setTimeout(() => {
|
|
@@ -892,8 +929,14 @@ export async function runAgentLoopImpl(
|
|
|
892
929
|
}
|
|
893
930
|
|
|
894
931
|
const isFirstMessage = ctx.messages.length === 1;
|
|
895
|
-
|
|
896
|
-
|
|
932
|
+
// Promote a pending post-compaction re-inject signal (e.g. from `/compact`)
|
|
933
|
+
// into `compactedThisTurn` so NOW.md / PKB / v2 static blocks land on this
|
|
934
|
+
// turn even when no mid-turn compaction fires. Clear the flag immediately
|
|
935
|
+
// so this fires exactly once per `/compact` event.
|
|
936
|
+
const consumedPostCompactReinject = ctx.pendingPostCompactReinject;
|
|
937
|
+
ctx.pendingPostCompactReinject = false;
|
|
938
|
+
let shouldInjectWorkspace = isFirstMessage || consumedPostCompactReinject;
|
|
939
|
+
let compactedThisTurn = consumedPostCompactReinject;
|
|
897
940
|
let slackCompactedThisTurn = false;
|
|
898
941
|
const isSlackConversation = ctx.channelCapabilities?.channel === "slack";
|
|
899
942
|
let currentSlackContextSummary =
|
|
@@ -1101,8 +1144,6 @@ export async function runAgentLoopImpl(
|
|
|
1101
1144
|
}
|
|
1102
1145
|
}
|
|
1103
1146
|
|
|
1104
|
-
const state = createEventHandlerState();
|
|
1105
|
-
|
|
1106
1147
|
// Register confirmation outcome tracker so the agent loop can link
|
|
1107
1148
|
// confirmation decisions to tool_use_ids for persistence.
|
|
1108
1149
|
ctx.onConfirmationOutcome = (
|
|
@@ -1328,6 +1369,20 @@ export async function runAgentLoopImpl(
|
|
|
1328
1369
|
}
|
|
1329
1370
|
}
|
|
1330
1371
|
|
|
1372
|
+
// Query active documents for this conversation so the injector chain
|
|
1373
|
+
// can surface them to the assistant (prevents duplicate document_create
|
|
1374
|
+
// calls when existing documents should be targeted with document_update).
|
|
1375
|
+
const conversationDocs = getDocumentsForConversation(ctx.conversationId);
|
|
1376
|
+
const activeDocuments =
|
|
1377
|
+
conversationDocs.length > 0
|
|
1378
|
+
? conversationDocs.map((d) => ({
|
|
1379
|
+
surfaceId: d.surfaceId,
|
|
1380
|
+
title: d.title,
|
|
1381
|
+
wordCount: d.wordCount,
|
|
1382
|
+
updatedAt: d.updatedAt,
|
|
1383
|
+
}))
|
|
1384
|
+
: null;
|
|
1385
|
+
|
|
1331
1386
|
ctx.refreshWorkspaceTopLevelContextIfNeeded();
|
|
1332
1387
|
|
|
1333
1388
|
// Compute fresh turn timestamp for date grounding.
|
|
@@ -1429,9 +1484,13 @@ export async function runAgentLoopImpl(
|
|
|
1429
1484
|
// are never stripped on normal turns — this preserves the cached prefix.
|
|
1430
1485
|
// PKB/NOW content is sourced from the `memoryRetrieval` pipeline above
|
|
1431
1486
|
// so plugins can override either source without touching the agent loop.
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1487
|
+
// NOW.md injection can be disabled via `memory.retrieval.scratchpadInjection.enabled`.
|
|
1488
|
+
const scratchpadInjectionEnabled =
|
|
1489
|
+
getConfig().memory.retrieval.scratchpadInjection.enabled;
|
|
1490
|
+
const currentNowContent =
|
|
1491
|
+
personalMemoryAllowed && scratchpadInjectionEnabled
|
|
1492
|
+
? memoryResult.nowContent
|
|
1493
|
+
: null;
|
|
1435
1494
|
const shouldInjectNowAndPkb = isFirstMessage || compactedThisTurn;
|
|
1436
1495
|
const nowScratchpad = shouldInjectNowAndPkb ? currentNowContent : null;
|
|
1437
1496
|
|
|
@@ -1535,6 +1594,7 @@ export async function runAgentLoopImpl(
|
|
|
1535
1594
|
const injectionOpts = {
|
|
1536
1595
|
diskPressureContext,
|
|
1537
1596
|
activeSurface,
|
|
1597
|
+
activeDocuments,
|
|
1538
1598
|
workspaceTopLevelContext: shouldInjectWorkspace
|
|
1539
1599
|
? ctx.workspaceTopLevelContext
|
|
1540
1600
|
: null,
|
|
@@ -1968,6 +2028,30 @@ export async function runAgentLoopImpl(
|
|
|
1968
2028
|
runMessages = webSearchStrip.messages;
|
|
1969
2029
|
}
|
|
1970
2030
|
|
|
2031
|
+
// user-prompt-submit hook: plugins may transform `runMessages` right
|
|
2032
|
+
// before the agent loop receives them. Fires once per user turn at
|
|
2033
|
+
// the primary `agentLoop.run` only — the re-entry / retry calls
|
|
2034
|
+
// further down in this function do not refire it (they're not new
|
|
2035
|
+
// user submissions). Plugins may mutate `ctx.latestMessages` in place
|
|
2036
|
+
// OR return a new context with a fresh array; `runHook` forwards
|
|
2037
|
+
// whichever the chain settles on. Order is plugin registration order.
|
|
2038
|
+
//
|
|
2039
|
+
// Fires BEFORE `preRunHistoryLength` is captured so the boundary
|
|
2040
|
+
// between pre-existing and hook-emitted messages — consumed by the
|
|
2041
|
+
// ordering-error retry gate, the post-run reconcile loop, and the
|
|
2042
|
+
// new-message extraction for persistence — reflects exactly what
|
|
2043
|
+
// `agentLoop.run` receives.
|
|
2044
|
+
const userPromptCtx: UserPromptSubmitContext = {
|
|
2045
|
+
conversationId: ctx.conversationId,
|
|
2046
|
+
originalMessages: ctx.messages,
|
|
2047
|
+
latestMessages: runMessages,
|
|
2048
|
+
};
|
|
2049
|
+
const finalUserPromptCtx = await runHook(
|
|
2050
|
+
HOOKS.USER_PROMPT_SUBMIT,
|
|
2051
|
+
userPromptCtx,
|
|
2052
|
+
);
|
|
2053
|
+
runMessages = finalUserPromptCtx.latestMessages;
|
|
2054
|
+
|
|
1971
2055
|
let preRunHistoryLength = runMessages.length;
|
|
1972
2056
|
|
|
1973
2057
|
const shouldGenerateTitle = isReplaceableTitle(
|
|
@@ -2408,6 +2492,64 @@ export async function runAgentLoopImpl(
|
|
|
2408
2492
|
}
|
|
2409
2493
|
}
|
|
2410
2494
|
|
|
2495
|
+
// ── Emergency mid-turn compaction ────────────────────────────
|
|
2496
|
+
// Before entering the reducer tier loop, attempt a targeted
|
|
2497
|
+
// emergency compaction: summarize everything before the last
|
|
2498
|
+
// tool_use + tool_result pair and let the agent continue with
|
|
2499
|
+
// [summary, last_tool_call, last_tool_result]. This preserves
|
|
2500
|
+
// the agent's most recent action context while aggressively
|
|
2501
|
+
// compressing history. Falls through to reducer tiers on failure.
|
|
2502
|
+
{
|
|
2503
|
+
try {
|
|
2504
|
+
const emergencyConfig = getConfig().compaction;
|
|
2505
|
+
const emergencyResult = await runEmergencyCompaction({
|
|
2506
|
+
conversationId: ctx.conversationId,
|
|
2507
|
+
messages: ctx.messages,
|
|
2508
|
+
provider: ctx.provider,
|
|
2509
|
+
systemPrompt: ctx.systemPrompt,
|
|
2510
|
+
tools: undefined,
|
|
2511
|
+
compaction: emergencyConfig,
|
|
2512
|
+
maxInputTokens: effectiveContextWindow.maxInputTokens,
|
|
2513
|
+
previousEstimatedInputTokens: estimatedTokensAtOverflow,
|
|
2514
|
+
force: true,
|
|
2515
|
+
signal: abortController.signal,
|
|
2516
|
+
overrideProfile: turnOverrideProfile ?? null,
|
|
2517
|
+
nonPersistedPrefixCount:
|
|
2518
|
+
ctx.contextWindowManager.nonPersistedPrefixCount,
|
|
2519
|
+
});
|
|
2520
|
+
if (emergencyResult.compacted) {
|
|
2521
|
+
rlog.info(
|
|
2522
|
+
{
|
|
2523
|
+
phase: "convergence",
|
|
2524
|
+
compactedMessages: emergencyResult.compactedMessages,
|
|
2525
|
+
summaryChars: emergencyResult.summaryText.length,
|
|
2526
|
+
},
|
|
2527
|
+
"Emergency mid-turn compaction succeeded — bypassing reducer tiers",
|
|
2528
|
+
);
|
|
2529
|
+
if (emergencyResult.summaryFailed !== undefined) {
|
|
2530
|
+
await trackCompactionOutcome(
|
|
2531
|
+
ctx,
|
|
2532
|
+
emergencyResult.summaryFailed,
|
|
2533
|
+
onEvent,
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
if (emergencyResult.compacted) {
|
|
2537
|
+
await applySuccessfulCompaction(emergencyResult, ctx.messages);
|
|
2538
|
+
shouldInjectWorkspace = true;
|
|
2539
|
+
}
|
|
2540
|
+
// Clear the overflow flag and re-run the agent loop with
|
|
2541
|
+
// the compacted context.
|
|
2542
|
+
state.contextTooLargeDetected = false;
|
|
2543
|
+
}
|
|
2544
|
+
} catch (err) {
|
|
2545
|
+
rlog.warn(
|
|
2546
|
+
{ phase: "convergence", err },
|
|
2547
|
+
"Emergency mid-turn compaction failed; continuing to reducer tiers",
|
|
2548
|
+
);
|
|
2549
|
+
}
|
|
2550
|
+
// If emergency compaction failed, fall through to reducer tiers.
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2411
2553
|
let convergenceAttempts = 0;
|
|
2412
2554
|
const maxAttempts = overflowRecovery.maxAttempts;
|
|
2413
2555
|
|
|
@@ -2814,6 +2956,7 @@ export async function runAgentLoopImpl(
|
|
|
2814
2956
|
buildPluginTurnContext(ctx, reqId),
|
|
2815
2957
|
DEFAULT_TIMEOUTS.persistence,
|
|
2816
2958
|
);
|
|
2959
|
+
persistedErrorAssistantMessage = true;
|
|
2817
2960
|
newMessages.push(errorAssistantMessage);
|
|
2818
2961
|
// Do NOT send assistant_text_delta here — handleProviderError already
|
|
2819
2962
|
// emitted a conversation_error event for this same error text, and the
|
|
@@ -2889,7 +3032,6 @@ export async function runAgentLoopImpl(
|
|
|
2889
3032
|
convForDisk.createdAt,
|
|
2890
3033
|
);
|
|
2891
3034
|
};
|
|
2892
|
-
|
|
2893
3035
|
// Fast-path: when the user cancelled, skip expensive post-loop work
|
|
2894
3036
|
// (attachment resolution) and emit the cancellation event immediately
|
|
2895
3037
|
// so the client can re-enable the UI without delay.
|
|
@@ -2908,6 +3050,7 @@ export async function runAgentLoopImpl(
|
|
|
2908
3050
|
type: "generation_cancelled",
|
|
2909
3051
|
conversationId: ctx.conversationId,
|
|
2910
3052
|
});
|
|
3053
|
+
publishLoopMessagesChanged();
|
|
2911
3054
|
} else {
|
|
2912
3055
|
// Resolve attachments (only when not cancelled — this is expensive async I/O)
|
|
2913
3056
|
const attachmentResult = await resolveAssistantAttachments(
|
|
@@ -2948,6 +3091,7 @@ export async function runAgentLoopImpl(
|
|
|
2948
3091
|
type: "generation_cancelled",
|
|
2949
3092
|
conversationId: ctx.conversationId,
|
|
2950
3093
|
});
|
|
3094
|
+
publishLoopMessagesChanged();
|
|
2951
3095
|
} else if (yieldedForHandoff) {
|
|
2952
3096
|
ctx.traceEmitter.emit(
|
|
2953
3097
|
"generation_handoff",
|
|
@@ -2976,6 +3120,7 @@ export async function runAgentLoopImpl(
|
|
|
2976
3120
|
? { displayMessageId: clientDisplayMessageId }
|
|
2977
3121
|
: {}),
|
|
2978
3122
|
});
|
|
3123
|
+
publishLoopMessagesChanged();
|
|
2979
3124
|
} else {
|
|
2980
3125
|
ctx.emitActivityState("idle", "message_complete", "global", reqId);
|
|
2981
3126
|
ctx.traceEmitter.emit(
|
|
@@ -3002,6 +3147,7 @@ export async function runAgentLoopImpl(
|
|
|
3002
3147
|
? { displayMessageId: clientDisplayMessageId }
|
|
3003
3148
|
: {}),
|
|
3004
3149
|
});
|
|
3150
|
+
publishLoopMessagesChanged();
|
|
3005
3151
|
|
|
3006
3152
|
// Proactive artifact: fire once when the processed turn was the 4th user message.
|
|
3007
3153
|
// Only trigger for real user-authored turns (not subagent/system messages).
|
|
@@ -3056,6 +3202,13 @@ export async function runAgentLoopImpl(
|
|
|
3056
3202
|
conversationId: ctx.conversationId,
|
|
3057
3203
|
title,
|
|
3058
3204
|
});
|
|
3205
|
+
onEvent({
|
|
3206
|
+
type: "sync_changed",
|
|
3207
|
+
tags: [
|
|
3208
|
+
SYNC_TAGS.conversationsList,
|
|
3209
|
+
conversationMetadataSyncTag(ctx.conversationId),
|
|
3210
|
+
],
|
|
3211
|
+
});
|
|
3059
3212
|
},
|
|
3060
3213
|
signal: abortController.signal,
|
|
3061
3214
|
});
|
|
@@ -3080,6 +3233,7 @@ export async function runAgentLoopImpl(
|
|
|
3080
3233
|
type: "generation_cancelled",
|
|
3081
3234
|
conversationId: ctx.conversationId,
|
|
3082
3235
|
});
|
|
3236
|
+
publishLoopMessagesChanged();
|
|
3083
3237
|
} else {
|
|
3084
3238
|
ctx.emitActivityState("idle", "error_terminal", "global", reqId);
|
|
3085
3239
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -3104,6 +3258,7 @@ export async function runAgentLoopImpl(
|
|
|
3104
3258
|
errorCategory: classified.errorCategory,
|
|
3105
3259
|
});
|
|
3106
3260
|
onEvent(buildConversationErrorMessage(ctx.conversationId, classified));
|
|
3261
|
+
publishLoopMessagesChanged();
|
|
3107
3262
|
}
|
|
3108
3263
|
} finally {
|
|
3109
3264
|
if (turnStarted) {
|
|
@@ -3234,6 +3389,7 @@ export interface CompactionApplyContext {
|
|
|
3234
3389
|
messages: Message[];
|
|
3235
3390
|
contextCompactedMessageCount: number;
|
|
3236
3391
|
contextCompactedAt: number | null;
|
|
3392
|
+
pendingPostCompactReinject: boolean;
|
|
3237
3393
|
readonly graphMemory: ConversationGraphMemory;
|
|
3238
3394
|
readonly provider: Provider;
|
|
3239
3395
|
usageStats: UsageStats;
|
|
@@ -3283,6 +3439,10 @@ export async function applyCompactionResult(
|
|
|
3283
3439
|
ctx.contextCompactedMessageCount += result.compactedPersistedMessages;
|
|
3284
3440
|
const compactedAt = Date.now();
|
|
3285
3441
|
ctx.contextCompactedAt = compactedAt;
|
|
3442
|
+
// Signal to the next agent loop turn that NOW.md / PKB / v2 static blocks
|
|
3443
|
+
// were stripped from the tail and need fresh re-injection. Consumed and
|
|
3444
|
+
// cleared at the top of the next `runAgentLoopImpl` run.
|
|
3445
|
+
ctx.pendingPostCompactReinject = true;
|
|
3286
3446
|
await ctx.graphMemory.onCompacted(result.compactedPersistedMessages);
|
|
3287
3447
|
updateConversationContextWindow(
|
|
3288
3448
|
ctx.conversationId,
|