@vellumai/assistant 0.7.2 → 0.7.3
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 +16 -1
- package/docs/architecture/memory.md +5 -2
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -9
- package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
- package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
- package/openapi.yaml +449 -22
- package/package.json +1 -1
- package/src/__tests__/app-control-flow.test.ts +21 -11
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/assistant-event.test.ts +0 -10
- package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
- package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
- package/src/__tests__/call-conversation-messages.test.ts +8 -2
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
- package/src/__tests__/channel-readiness-service.test.ts +4 -2
- package/src/__tests__/config-loader-backfill.test.ts +379 -0
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
- package/src/__tests__/config-watcher.test.ts +140 -69
- package/src/__tests__/context-search-agent-runner.test.ts +61 -3
- package/src/__tests__/context-search-conversations-source.test.ts +0 -24
- package/src/__tests__/context-search-fanout.test.ts +0 -1
- package/src/__tests__/context-search-memory-source.test.ts +3 -7
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop.test.ts +454 -5
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-process-callsite.test.ts +43 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-store.test.ts +0 -18
- package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/credentials-cli.test.ts +7 -0
- package/src/__tests__/cu-unified-flow.test.ts +176 -10
- package/src/__tests__/date-context.test.ts +164 -2
- package/src/__tests__/disk-pressure-guard.test.ts +262 -0
- package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
- package/src/__tests__/disk-pressure-policy.test.ts +241 -0
- package/src/__tests__/disk-pressure-routes.test.ts +379 -0
- package/src/__tests__/disk-pressure-tools.test.ts +277 -0
- package/src/__tests__/disk-usage.test.ts +150 -0
- package/src/__tests__/events-client-registration.test.ts +52 -0
- package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
- package/src/__tests__/file-write-tool.test.ts +4 -10
- package/src/__tests__/filing-service.test.ts +3 -4
- package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
- package/src/__tests__/heartbeat-service.test.ts +260 -11
- package/src/__tests__/host-app-control-proxy.test.ts +195 -25
- package/src/__tests__/host-bash-proxy.test.ts +227 -34
- package/src/__tests__/host-bash-routes.test.ts +178 -13
- package/src/__tests__/host-cu-proxy.test.ts +210 -3
- package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
- package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
- package/src/__tests__/host-file-proxy.test.ts +268 -6
- package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
- package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
- package/src/__tests__/http-user-message-parity.test.ts +107 -1
- package/src/__tests__/injector-chain.test.ts +18 -6
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- package/src/__tests__/managed-profile-guard.test.ts +18 -0
- package/src/__tests__/mcp-abort-signal.test.ts +130 -0
- package/src/__tests__/memory-admin-recall.test.ts +3 -11
- package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
- package/src/__tests__/normalize-onboarding.test.ts +180 -0
- package/src/__tests__/oauth-connect-routes.test.ts +316 -0
- package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
- package/src/__tests__/onboarding-persona-write.test.ts +308 -0
- package/src/__tests__/openai-provider.test.ts +45 -8
- package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
- package/src/__tests__/platform-callback-registration.test.ts +21 -4
- package/src/__tests__/platform.test.ts +2 -1
- package/src/__tests__/playbook-execution.test.ts +0 -43
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
- package/src/__tests__/provider-tool-name.test.ts +23 -0
- package/src/__tests__/relay-server.test.ts +15 -4
- package/src/__tests__/runtime-events-sse.test.ts +4 -8
- package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -1
- package/src/__tests__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/twilio-validation.test.ts +2 -2
- package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
- package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
- package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
- package/src/approvals/guardian-decision-primitive.ts +13 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -17
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-conversation-messages.ts +46 -10
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
- package/src/cli/commands/bash.ts +35 -108
- package/src/cli/commands/contacts.ts +64 -25
- package/src/cli/commands/credentials.ts +56 -0
- package/src/cli/commands/memory-v2.ts +7 -6
- package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
- package/src/cli/commands/oauth/connect.ts +127 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
- package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
- package/src/cli/commands/platform/index.ts +16 -7
- package/src/cli/commands/status.ts +57 -0
- package/src/cli/program.ts +4 -2
- package/src/config/assistant-feature-flags.ts +13 -3
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
- package/src/config/env.ts +0 -8
- package/src/config/feature-flag-registry.json +27 -3
- package/src/config/loader.ts +127 -8
- package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/channels.ts +0 -5
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +2 -0
- package/src/config/schemas/memory-lifecycle.ts +13 -0
- package/src/config/schemas/memory-v2.ts +75 -11
- package/src/config/schemas/platform.ts +43 -3
- package/src/config/schemas/services.ts +28 -0
- package/src/config/seed-inference-profiles.ts +230 -33
- package/src/contacts/contact-store.ts +0 -25
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
- package/src/daemon/assistant-attachments.ts +4 -4
- package/src/daemon/config-watcher.ts +85 -57
- package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
- package/src/daemon/conversation-agent-loop.ts +170 -33
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +1 -3
- package/src/daemon/conversation-process.ts +8 -0
- package/src/daemon/conversation-runtime-assembly.ts +26 -0
- package/src/daemon/conversation-store.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +195 -15
- package/src/daemon/conversation-tool-setup.ts +57 -14
- package/src/daemon/conversation.ts +17 -22
- package/src/daemon/date-context.ts +71 -22
- package/src/daemon/disk-pressure-background-gate.ts +73 -0
- package/src/daemon/disk-pressure-guard.ts +343 -0
- package/src/daemon/disk-pressure-policy.ts +163 -0
- package/src/daemon/handlers/shared.ts +0 -1
- package/src/daemon/handlers/skills.ts +3 -4
- package/src/daemon/host-app-control-proxy.ts +137 -41
- package/src/daemon/host-bash-proxy.ts +46 -21
- package/src/daemon/host-cu-proxy.ts +49 -3
- package/src/daemon/host-file-proxy.ts +43 -7
- package/src/daemon/host-transfer-proxy.ts +95 -4
- package/src/daemon/lifecycle.ts +79 -28
- package/src/daemon/meet-host-supervisor.ts +4 -4
- package/src/daemon/meet-manifest-loader.ts +0 -1
- package/src/daemon/memory-v2-startup.ts +14 -4
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +4 -0
- package/src/daemon/message-types/disk-pressure.ts +9 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/tool-setup-types.ts +2 -2
- package/src/documents/document-store.ts +85 -0
- package/src/filing/filing-service.ts +30 -5
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
- package/src/heartbeat/heartbeat-run-store.ts +13 -0
- package/src/heartbeat/heartbeat-service.ts +205 -31
- package/src/home/feed-scheduler.ts +18 -0
- package/src/inbound/platform-callback-registration.ts +8 -15
- package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
- package/src/ipc/assistant-server.ts +56 -2
- package/src/ipc/gateway-client.ts +37 -3
- package/src/live-voice/live-voice-archive.ts +4 -4
- package/src/live-voice/protocol.ts +5 -7
- package/src/media/image-service.ts +1 -7
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
- package/src/memory/admin.ts +5 -9
- package/src/memory/context-search/agent-runner.ts +19 -2
- package/src/memory/context-search/sources/conversations.ts +2 -11
- package/src/memory/context-search/sources/memory-v2.ts +5 -4
- package/src/memory/context-search/sources/memory.ts +0 -1
- package/src/memory/context-search/types.ts +0 -1
- package/src/memory/conversation-crud.ts +4 -12
- package/src/memory/db-init.ts +2 -0
- package/src/memory/embedding-runtime-manager.ts +119 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +32 -21
- package/src/memory/graph/conversation-graph-memory.ts +42 -54
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +10 -67
- package/src/memory/graph/graph-search.ts +1 -20
- package/src/memory/graph/retriever.test.ts +6 -0
- package/src/memory/graph/retriever.ts +6 -10
- package/src/memory/indexer.ts +54 -45
- package/src/memory/job-handlers/backfill.ts +2 -11
- package/src/memory/job-handlers/cleanup.ts +43 -0
- package/src/memory/job-handlers/embedding.ts +6 -8
- package/src/memory/job-handlers/summarization.ts +2 -7
- package/src/memory/jobs-store.ts +48 -0
- package/src/memory/jobs-worker.ts +81 -43
- package/src/memory/memory-v2-activation-log-store.ts +32 -14
- package/src/memory/memory-v2-concept-frequency.ts +169 -0
- package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -0
- package/src/memory/qdrant-client.ts +0 -13
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/search/semantic.ts +6 -67
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +311 -250
- package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
- package/src/memory/v2/__tests__/injection.test.ts +157 -167
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +5 -199
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/static-context.test.ts +76 -1
- package/src/memory/v2/activation.ts +149 -156
- package/src/memory/v2/consolidation-job.ts +62 -12
- package/src/memory/v2/injection.ts +47 -60
- package/src/memory/v2/prompts/consolidation.ts +36 -1
- package/src/memory/v2/qdrant.ts +99 -0
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +10 -84
- package/src/memory/v2/skill-content.ts +4 -3
- package/src/memory/v2/skill-store.ts +82 -59
- package/src/memory/v2/static-context.ts +22 -0
- package/src/memory/v2/types.ts +10 -10
- package/src/notifications/copy-composer.ts +13 -0
- package/src/notifications/signal.ts +4 -0
- package/src/oauth/AGENTS.md +3 -1
- package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.test.ts +66 -1
- package/src/oauth/connection-resolver.ts +55 -1
- package/src/oauth/oauth-connect-state.ts +77 -0
- package/src/oauth/seed-providers.ts +58 -1
- package/src/plugins/defaults/injectors.ts +35 -2
- package/src/plugins/defaults/memory-retrieval.ts +5 -6
- package/src/plugins/types.ts +7 -0
- package/src/proactive-artifact/aux-message-injector.ts +74 -0
- package/src/proactive-artifact/decision.test.ts +226 -0
- package/src/proactive-artifact/decision.ts +165 -0
- package/src/proactive-artifact/index.ts +7 -0
- package/src/proactive-artifact/job.test.ts +867 -0
- package/src/proactive-artifact/job.ts +352 -0
- package/src/proactive-artifact/message-copy.ts +41 -0
- package/src/proactive-artifact/trigger-state.test.ts +277 -0
- package/src/proactive-artifact/trigger-state.ts +119 -0
- package/src/prompts/normalize-onboarding.ts +80 -0
- package/src/prompts/persona-resolver.ts +101 -9
- package/src/prompts/system-prompt.ts +21 -7
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/providers/__tests__/retry-callsite.test.ts +222 -1
- package/src/providers/model-intents.ts +7 -0
- package/src/providers/openrouter/client.ts +8 -0
- package/src/providers/retry.ts +50 -0
- package/src/providers/types.ts +1 -0
- package/src/runtime/__tests__/agent-wake.test.ts +456 -3
- package/src/runtime/agent-wake.ts +238 -100
- package/src/runtime/assistant-event-hub.ts +36 -6
- package/src/runtime/assistant-event.ts +0 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
- package/src/runtime/auth/route-policy.ts +14 -1
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/guardian-reply-router.ts +10 -0
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/pending-interactions.ts +8 -0
- package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/client-routes.ts +20 -2
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-routes.ts +35 -26
- package/src/runtime/routes/debug-bash-routes.ts +163 -0
- package/src/runtime/routes/disk-pressure-routes.ts +121 -0
- package/src/runtime/routes/document-pdf-renderer.ts +6 -2
- package/src/runtime/routes/documents-routes.ts +2 -75
- package/src/runtime/routes/events-routes.ts +41 -9
- package/src/runtime/routes/host-bash-routes.ts +23 -3
- package/src/runtime/routes/host-cu-routes.ts +33 -6
- package/src/runtime/routes/host-file-routes.ts +32 -6
- package/src/runtime/routes/host-transfer-routes.ts +79 -16
- package/src/runtime/routes/identity-routes.ts +7 -138
- package/src/runtime/routes/inbound-message-handler.ts +77 -12
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/memory-item-routes.test.ts +41 -15
- package/src/runtime/routes/memory-v2-routes.ts +33 -0
- package/src/runtime/routes/oauth-connect-routes.ts +153 -0
- package/src/runtime/verification-outbound-actions.ts +4 -4
- package/src/schedule/run-script.ts +37 -5
- package/src/schedule/scheduler.ts +20 -1
- package/src/security/encrypted-store.ts +2 -0
- package/src/security/secure-keys.ts +55 -0
- package/src/skills/remote-skill-policy.ts +4 -10
- package/src/subagent/index.ts +1 -7
- package/src/subagent/manager.ts +1 -15
- package/src/tasks/task-runner.ts +0 -1
- package/src/tasks/task-store.ts +0 -3
- package/src/tools/background-tool-registry.ts +17 -3
- package/src/tools/host-filesystem/edit.test.ts +151 -0
- package/src/tools/host-filesystem/edit.ts +43 -1
- package/src/tools/host-filesystem/read.test.ts +129 -0
- package/src/tools/host-filesystem/read.ts +43 -1
- package/src/tools/host-filesystem/transfer.test.ts +127 -2
- package/src/tools/host-filesystem/transfer.ts +56 -11
- package/src/tools/host-filesystem/write.test.ts +134 -0
- package/src/tools/host-filesystem/write.ts +43 -1
- package/src/tools/host-terminal/host-shell.ts +13 -6
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/register.test.ts +12 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +31 -6
- package/src/tools/types.ts +24 -2
- package/src/tts/provider-catalog.ts +3 -5
- package/src/util/disk-usage.ts +138 -0
- package/src/util/platform.ts +21 -11
- package/src/util/process-liveness.ts +26 -0
- package/src/workspace/heartbeat-service.ts +19 -0
- package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
- package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
- package/src/memory/v2/skill-qdrant.ts +0 -404
- package/src/signals/bash.ts +0 -198
|
@@ -62,7 +62,10 @@ mock.module("../platform/client.js", () => ({
|
|
|
62
62
|
// ---------------------------------------------------------------------------
|
|
63
63
|
|
|
64
64
|
import { BYOOAuthConnection } from "./byo-connection.js";
|
|
65
|
-
import {
|
|
65
|
+
import {
|
|
66
|
+
resolveEffectiveBaseUrl,
|
|
67
|
+
resolveOAuthConnection,
|
|
68
|
+
} from "./connection-resolver.js";
|
|
66
69
|
import { PlatformOAuthConnection } from "./platform-connection.js";
|
|
67
70
|
|
|
68
71
|
// ---------------------------------------------------------------------------
|
|
@@ -214,3 +217,65 @@ describe("resolveOAuthConnection", () => {
|
|
|
214
217
|
).rejects.toThrow(/No active OAuth connection found/);
|
|
215
218
|
});
|
|
216
219
|
});
|
|
220
|
+
|
|
221
|
+
describe("resolveEffectiveBaseUrl", () => {
|
|
222
|
+
const fallback = "https://login.salesforce.com";
|
|
223
|
+
|
|
224
|
+
test("uses instance_url from JSON-string metadata for Salesforce", () => {
|
|
225
|
+
const metadata = JSON.stringify({
|
|
226
|
+
instance_url: "https://acme.my.salesforce.com",
|
|
227
|
+
issued_at: "1714000000000",
|
|
228
|
+
});
|
|
229
|
+
expect(resolveEffectiveBaseUrl("salesforce", fallback, metadata)).toBe(
|
|
230
|
+
"https://acme.my.salesforce.com",
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test("uses instance_url from already-parsed object metadata", () => {
|
|
235
|
+
const metadata = { instance_url: "https://na162.salesforce.com" };
|
|
236
|
+
expect(resolveEffectiveBaseUrl("salesforce", fallback, metadata)).toBe(
|
|
237
|
+
"https://na162.salesforce.com",
|
|
238
|
+
);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("falls back to seed baseUrl when metadata is null", () => {
|
|
242
|
+
expect(resolveEffectiveBaseUrl("salesforce", fallback, null)).toBe(
|
|
243
|
+
fallback,
|
|
244
|
+
);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("falls back to seed baseUrl when instance_url is empty string", () => {
|
|
248
|
+
const metadata = JSON.stringify({ instance_url: "" });
|
|
249
|
+
expect(resolveEffectiveBaseUrl("salesforce", fallback, metadata)).toBe(
|
|
250
|
+
fallback,
|
|
251
|
+
);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("falls back to seed baseUrl when metadata is unparseable JSON", () => {
|
|
255
|
+
expect(
|
|
256
|
+
resolveEffectiveBaseUrl("salesforce", fallback, "{ not valid json"),
|
|
257
|
+
).toBe(fallback);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test("falls back to seed baseUrl when instance_url is the wrong type", () => {
|
|
261
|
+
const metadata = JSON.stringify({ instance_url: 12345 });
|
|
262
|
+
expect(resolveEffectiveBaseUrl("salesforce", fallback, metadata)).toBe(
|
|
263
|
+
fallback,
|
|
264
|
+
);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
test("ignores instance_url for non-Salesforce providers", () => {
|
|
268
|
+
// A different provider whose token response happens to include an
|
|
269
|
+
// instance_url-shaped field MUST NOT have its baseUrl rewritten.
|
|
270
|
+
const metadata = JSON.stringify({
|
|
271
|
+
instance_url: "https://attacker.example.com",
|
|
272
|
+
});
|
|
273
|
+
expect(
|
|
274
|
+
resolveEffectiveBaseUrl(
|
|
275
|
+
"google",
|
|
276
|
+
"https://gmail.googleapis.com/gmail/v1/users/me",
|
|
277
|
+
metadata,
|
|
278
|
+
),
|
|
279
|
+
).toBe("https://gmail.googleapis.com/gmail/v1/users/me");
|
|
280
|
+
});
|
|
281
|
+
});
|
|
@@ -116,11 +116,65 @@ export async function resolveOAuthConnection(
|
|
|
116
116
|
return new BYOOAuthConnection({
|
|
117
117
|
id: conn.id,
|
|
118
118
|
provider: conn.provider,
|
|
119
|
-
baseUrl,
|
|
119
|
+
baseUrl: resolveEffectiveBaseUrl(conn.provider, baseUrl, conn.metadata),
|
|
120
120
|
accountInfo: conn.accountInfo,
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Resolve the effective API base URL for a connection, preferring per-tenant
|
|
126
|
+
* values stored on the connection's `metadata` over the provider's static
|
|
127
|
+
* seed value when applicable.
|
|
128
|
+
*
|
|
129
|
+
* Salesforce is the only provider that needs this: every org has its own
|
|
130
|
+
* API instance host (``acme.my.salesforce.com``, ``na162.salesforce.com``)
|
|
131
|
+
* which is returned in the OAuth token response as ``instance_url`` and
|
|
132
|
+
* captured into ``oauth_connection.metadata`` by ``storeOAuth2Tokens``.
|
|
133
|
+
* The seed's ``baseUrl`` for Salesforce is the login domain
|
|
134
|
+
* (``https://login.salesforce.com``) — correct for the OAuth handshake but
|
|
135
|
+
* wrong for REST API calls. Pulling the per-connection ``instance_url``
|
|
136
|
+
* here avoids forcing every caller to override ``baseUrl`` per-request.
|
|
137
|
+
*
|
|
138
|
+
* For all other providers the seed value is correct (single API domain),
|
|
139
|
+
* so we return it unchanged.
|
|
140
|
+
*
|
|
141
|
+
* If a future provider needs the same treatment, generalize via a
|
|
142
|
+
* declarative ``baseUrlMetadataKey`` field on the seed entry rather than
|
|
143
|
+
* adding more provider-name branches here.
|
|
144
|
+
*/
|
|
145
|
+
export function resolveEffectiveBaseUrl(
|
|
146
|
+
provider: string,
|
|
147
|
+
fallbackBaseUrl: string,
|
|
148
|
+
rawMetadata: unknown,
|
|
149
|
+
): string {
|
|
150
|
+
if (provider !== "salesforce") return fallbackBaseUrl;
|
|
151
|
+
|
|
152
|
+
const metadata = parseConnectionMetadata(rawMetadata);
|
|
153
|
+
const instanceUrl = metadata?.instance_url;
|
|
154
|
+
if (typeof instanceUrl === "string" && instanceUrl.length > 0) {
|
|
155
|
+
return instanceUrl;
|
|
156
|
+
}
|
|
157
|
+
return fallbackBaseUrl;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function parseConnectionMetadata(
|
|
161
|
+
raw: unknown,
|
|
162
|
+
): Record<string, unknown> | undefined {
|
|
163
|
+
if (raw == null) return undefined;
|
|
164
|
+
if (typeof raw === "object") {
|
|
165
|
+
return raw as Record<string, unknown>;
|
|
166
|
+
}
|
|
167
|
+
if (typeof raw !== "string") return undefined;
|
|
168
|
+
try {
|
|
169
|
+
const parsed = JSON.parse(raw);
|
|
170
|
+
return typeof parsed === "object" && parsed !== null
|
|
171
|
+
? (parsed as Record<string, unknown>)
|
|
172
|
+
: undefined;
|
|
173
|
+
} catch {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
124
178
|
// ---------------------------------------------------------------------------
|
|
125
179
|
// Platform connection ID resolution
|
|
126
180
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory OAuth connect flow status map.
|
|
3
|
+
*
|
|
4
|
+
* Tracks the current state of daemon-owned OAuth connect flows so the CLI
|
|
5
|
+
* can poll for completion via the IPC route.
|
|
6
|
+
*/
|
|
7
|
+
type OAuthConnectState =
|
|
8
|
+
| { status: "pending"; service: string; expiresAt: number }
|
|
9
|
+
| { status: "complete"; service: string; accountInfo?: string; grantedScopes?: string[]; completedAt: number }
|
|
10
|
+
| { status: "error"; service: string; error: string; failedAt: number };
|
|
11
|
+
|
|
12
|
+
const activeOAuthConnectFlows = new Map<string, OAuthConnectState>();
|
|
13
|
+
|
|
14
|
+
const PENDING_TTL_MS = 5 * 60 * 1000; // 5 min — matches oauth-callback-registry.ts:14
|
|
15
|
+
const COMPLETION_GRACE_MS = 60 * 1000; // 60s so the polling CLI gets one final read
|
|
16
|
+
|
|
17
|
+
export function setOAuthConnectPending(state: string, service: string): void {
|
|
18
|
+
clearExpiredOAuthConnectStates();
|
|
19
|
+
activeOAuthConnectFlows.set(state, {
|
|
20
|
+
status: "pending",
|
|
21
|
+
service,
|
|
22
|
+
expiresAt: Date.now() + PENDING_TTL_MS,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function setOAuthConnectComplete(
|
|
27
|
+
state: string,
|
|
28
|
+
service: string,
|
|
29
|
+
accountInfo?: string,
|
|
30
|
+
grantedScopes?: string[],
|
|
31
|
+
): void {
|
|
32
|
+
clearExpiredOAuthConnectStates();
|
|
33
|
+
activeOAuthConnectFlows.set(state, {
|
|
34
|
+
status: "complete",
|
|
35
|
+
service,
|
|
36
|
+
accountInfo,
|
|
37
|
+
grantedScopes,
|
|
38
|
+
completedAt: Date.now(),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function setOAuthConnectError(
|
|
43
|
+
state: string,
|
|
44
|
+
service: string,
|
|
45
|
+
error: string,
|
|
46
|
+
): void {
|
|
47
|
+
clearExpiredOAuthConnectStates();
|
|
48
|
+
activeOAuthConnectFlows.set(state, {
|
|
49
|
+
status: "error",
|
|
50
|
+
service,
|
|
51
|
+
error,
|
|
52
|
+
failedAt: Date.now(),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function getOAuthConnectState(state: string): OAuthConnectState | null {
|
|
57
|
+
clearExpiredOAuthConnectStates();
|
|
58
|
+
return activeOAuthConnectFlows.get(state) ?? null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function clearExpiredOAuthConnectStates(): void {
|
|
62
|
+
const now = Date.now();
|
|
63
|
+
for (const [key, state] of activeOAuthConnectFlows) {
|
|
64
|
+
if (state.status === "pending" && now > state.expiresAt) {
|
|
65
|
+
activeOAuthConnectFlows.delete(key);
|
|
66
|
+
} else if (state.status === "complete" && now > state.completedAt + COMPLETION_GRACE_MS) {
|
|
67
|
+
activeOAuthConnectFlows.delete(key);
|
|
68
|
+
} else if (state.status === "error" && now > state.failedAt + COMPLETION_GRACE_MS) {
|
|
69
|
+
activeOAuthConnectFlows.delete(key);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Test-only helper — clears all state for test isolation. */
|
|
75
|
+
export function _clearAllOAuthConnectStates(): void {
|
|
76
|
+
activeOAuthConnectFlows.clear();
|
|
77
|
+
}
|
|
@@ -393,6 +393,7 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
393
393
|
{ scope: "project:delete", description: "Delete entire projects" },
|
|
394
394
|
],
|
|
395
395
|
loopbackPort: 17325,
|
|
396
|
+
managedServiceConfigKey: "todoist-oauth",
|
|
396
397
|
injectionTemplates: [
|
|
397
398
|
{
|
|
398
399
|
hostPattern: "api.todoist.com",
|
|
@@ -402,7 +403,7 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
402
403
|
},
|
|
403
404
|
],
|
|
404
405
|
appType: "App",
|
|
405
|
-
identityUrl: "https://api.todoist.com/
|
|
406
|
+
identityUrl: "https://api.todoist.com/api/v1/sync",
|
|
406
407
|
identityMethod: "POST",
|
|
407
408
|
identityHeaders: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
408
409
|
identityBody: "sync_token=*&resource_types=[%22user%22]",
|
|
@@ -429,6 +430,7 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
429
430
|
availableScopes:
|
|
430
431
|
"https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes",
|
|
431
432
|
loopbackPort: 17326,
|
|
433
|
+
managedServiceConfigKey: "discord-oauth",
|
|
432
434
|
injectionTemplates: [
|
|
433
435
|
{
|
|
434
436
|
hostPattern: "discord.com",
|
|
@@ -497,6 +499,7 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
497
499
|
defaultScopes: ["default"],
|
|
498
500
|
availableScopes: "https://developers.asana.com/docs/oauth-scopes",
|
|
499
501
|
loopbackPort: 17328,
|
|
502
|
+
managedServiceConfigKey: "asana-oauth",
|
|
500
503
|
injectionTemplates: [
|
|
501
504
|
{
|
|
502
505
|
hostPattern: "app.asana.com",
|
|
@@ -563,6 +566,7 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
563
566
|
availableScopes:
|
|
564
567
|
"https://developers.hubspot.com/docs/guides/apps/authentication/scopes",
|
|
565
568
|
loopbackPort: 17330,
|
|
569
|
+
managedServiceConfigKey: "hubspot-oauth",
|
|
566
570
|
injectionTemplates: [
|
|
567
571
|
{
|
|
568
572
|
hostPattern: "api.hubapi.com",
|
|
@@ -576,6 +580,59 @@ export const PROVIDER_SEED_DATA: Record<
|
|
|
576
580
|
identityResponsePaths: ["user", "hub_domain"],
|
|
577
581
|
},
|
|
578
582
|
|
|
583
|
+
salesforce: {
|
|
584
|
+
provider: "salesforce",
|
|
585
|
+
authorizeUrl: "https://login.salesforce.com/services/oauth2/authorize",
|
|
586
|
+
tokenExchangeUrl: "https://login.salesforce.com/services/oauth2/token",
|
|
587
|
+
refreshUrl: "https://login.salesforce.com/services/oauth2/token",
|
|
588
|
+
pingUrl: "https://login.salesforce.com/services/oauth2/userinfo",
|
|
589
|
+
// baseUrl points at the login domain — correct for the OAuth handshake
|
|
590
|
+
// and for ``/services/oauth2/userinfo``/``revoke`` calls. REST API calls
|
|
591
|
+
// to ``/services/data/...`` go to the per-org instance host returned in
|
|
592
|
+
// the token response as ``instance_url`` and stored on
|
|
593
|
+
// ``oauth_connection.metadata``. ``connection-resolver.ts`` substitutes
|
|
594
|
+
// that instance URL when constructing the BYO connection so callers
|
|
595
|
+
// don't need to override ``baseUrl`` per request.
|
|
596
|
+
baseUrl: "https://login.salesforce.com",
|
|
597
|
+
displayLabel: "Salesforce",
|
|
598
|
+
description: "CRM contacts, leads, and opportunities",
|
|
599
|
+
dashboardUrl:
|
|
600
|
+
"https://help.salesforce.com/s/articleView?id=sf.connected_app_create.htm&type=5",
|
|
601
|
+
clientIdPlaceholder: null,
|
|
602
|
+
logoUrl:
|
|
603
|
+
"https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/salesforce/default.svg",
|
|
604
|
+
defaultScopes: ["api", "refresh_token", "openid", "email", "profile"],
|
|
605
|
+
availableScopes:
|
|
606
|
+
"https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_tokens_scopes.htm",
|
|
607
|
+
authorizeParams: { prompt: "consent" },
|
|
608
|
+
tokenEndpointAuthMethod: "client_secret_post",
|
|
609
|
+
loopbackPort: 17336,
|
|
610
|
+
// Salesforce REST traffic goes to per-org instance hosts like
|
|
611
|
+
// ``acme.my.salesforce.com`` and ``acme.lightning.force.com``.
|
|
612
|
+
// ``matchHostPattern`` only treats ``*.<domain>`` as a wildcard match —
|
|
613
|
+
// bare ``salesforce.com`` would only match the apex. Use wildcards so
|
|
614
|
+
// ``Authorization: Bearer`` injection actually fires on tenant hosts.
|
|
615
|
+
injectionTemplates: [
|
|
616
|
+
{
|
|
617
|
+
hostPattern: "*.salesforce.com",
|
|
618
|
+
injectionType: "header",
|
|
619
|
+
headerName: "Authorization",
|
|
620
|
+
valuePrefix: "Bearer ",
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
hostPattern: "*.force.com",
|
|
624
|
+
injectionType: "header",
|
|
625
|
+
headerName: "Authorization",
|
|
626
|
+
valuePrefix: "Bearer ",
|
|
627
|
+
},
|
|
628
|
+
],
|
|
629
|
+
revokeUrl: "https://login.salesforce.com/services/oauth2/revoke",
|
|
630
|
+
revokeBodyTemplate: { token: "{access_token}" },
|
|
631
|
+
appType: "Connected App",
|
|
632
|
+
identityUrl: "https://login.salesforce.com/services/oauth2/userinfo",
|
|
633
|
+
identityResponsePaths: ["email", "preferred_username"],
|
|
634
|
+
},
|
|
635
|
+
|
|
579
636
|
figma: {
|
|
580
637
|
provider: "figma",
|
|
581
638
|
authorizeUrl: "https://www.figma.com/oauth",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* drives the per-turn injection sequence consumed by
|
|
4
4
|
* `applyRuntimeInjections`.
|
|
5
5
|
*
|
|
6
|
-
* Each
|
|
6
|
+
* Each default injector reads its per-turn inputs from
|
|
7
7
|
* `ctx.injectionInputs` (see {@link TurnInjectionInputs}), runs its gating
|
|
8
8
|
* conditions (injection mode, feature flags, channel type, null-input
|
|
9
9
|
* short-circuits), and returns an {@link InjectionBlock} with a
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* | name | order | placement |
|
|
14
14
|
* | ------------------------ | ----- | ----------------------- |
|
|
15
|
+
* | `disk-pressure-warning` | 5 | prepend-user-tail |
|
|
15
16
|
* | `workspace-context` | 10 | prepend-user-tail |
|
|
16
17
|
* | `unified-turn-context` | 20 | prepend-user-tail |
|
|
17
18
|
* | `pkb-context` | 30 | after-memory-prefix |
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
|
|
46
47
|
import { resolve } from "node:path";
|
|
47
48
|
|
|
49
|
+
import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
|
|
48
50
|
import { getConfig } from "../../config/loader.js";
|
|
49
51
|
import { getInContextPkbPaths } from "../../daemon/pkb-context-tracker.js";
|
|
50
52
|
import { buildPkbReminder } from "../../daemon/pkb-reminder-builder.js";
|
|
@@ -74,7 +76,7 @@ const PKB_HINT_THRESHOLD = 0.5;
|
|
|
74
76
|
const PKB_HINT_ARCHIVE_THRESHOLD = 0.7;
|
|
75
77
|
|
|
76
78
|
/**
|
|
77
|
-
* Fixed order values for the
|
|
79
|
+
* Fixed order values for the default injectors. Exported so tests —
|
|
78
80
|
* and any future integration code — can assert ordering without re-deriving
|
|
79
81
|
* the constants.
|
|
80
82
|
*
|
|
@@ -83,6 +85,7 @@ const PKB_HINT_ARCHIVE_THRESHOLD = 0.7;
|
|
|
83
85
|
* without renumbering the defaults.
|
|
84
86
|
*/
|
|
85
87
|
export const DEFAULT_INJECTOR_ORDER = {
|
|
88
|
+
diskPressureWarning: 5,
|
|
86
89
|
workspaceContext: 10,
|
|
87
90
|
unifiedTurnContext: 20,
|
|
88
91
|
pkbContext: 30,
|
|
@@ -98,6 +101,35 @@ function readInjectionInputs(ctx: TurnContext): TurnInjectionInputs {
|
|
|
98
101
|
return ctx.injectionInputs ?? {};
|
|
99
102
|
}
|
|
100
103
|
|
|
104
|
+
export const DISK_PRESSURE_WARNING_PROMPT = `<disk_pressure_warning>
|
|
105
|
+
Disk usage is critically low: this assistant is in storage cleanup mode because the workspace volume is at least 95% full.
|
|
106
|
+
|
|
107
|
+
In your first paragraph, warn the user that storage is critically low and that normal work is suspended until space is freed.
|
|
108
|
+
|
|
109
|
+
Then help the user clean up storage. Prefer safe inspection steps first, such as checking available space and finding large directories. Ask before deleting files or caches unless the user has already clearly approved the specific cleanup action.
|
|
110
|
+
|
|
111
|
+
Do not work on unrelated tasks until disk usage drops below the critical threshold or the user explicitly overrides the lock. Background processes and messages from trusted contacts are blocked while this cleanup mode is active.
|
|
112
|
+
</disk_pressure_warning>`;
|
|
113
|
+
|
|
114
|
+
function isSafeStorageLimitsEnabled(): boolean {
|
|
115
|
+
return isAssistantFeatureFlagEnabled("safe-storage-limits", getConfig());
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const diskPressureWarningInjector: Injector = {
|
|
119
|
+
name: "disk-pressure-warning",
|
|
120
|
+
order: DEFAULT_INJECTOR_ORDER.diskPressureWarning,
|
|
121
|
+
async produce(ctx: TurnContext): Promise<InjectionBlock | null> {
|
|
122
|
+
if (!isSafeStorageLimitsEnabled()) return null;
|
|
123
|
+
const inputs = readInjectionInputs(ctx);
|
|
124
|
+
if (!inputs.diskPressureContext?.cleanupModeActive) return null;
|
|
125
|
+
return {
|
|
126
|
+
id: "disk-pressure-warning",
|
|
127
|
+
text: DISK_PRESSURE_WARNING_PROMPT,
|
|
128
|
+
placement: "prepend-user-tail",
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
101
133
|
/**
|
|
102
134
|
* v2 read-side cutover guard. The `pkb-context` injector silences itself
|
|
103
135
|
* under v2 because the `<knowledge_base>` block surfaces PKB content the v2
|
|
@@ -520,6 +552,7 @@ export const defaultInjectorsPlugin: Plugin = {
|
|
|
520
552
|
},
|
|
521
553
|
},
|
|
522
554
|
injectors: [
|
|
555
|
+
diskPressureWarningInjector,
|
|
523
556
|
workspaceContextInjector,
|
|
524
557
|
unifiedTurnContextInjector,
|
|
525
558
|
pkbContextInjector,
|
|
@@ -72,12 +72,6 @@ export interface GraphMemoryPayload {
|
|
|
72
72
|
* Passed as a second argument to {@link runDefaultMemoryRetrieval} rather
|
|
73
73
|
* than threaded through {@link MemoryArgs} to keep the plugin-facing
|
|
74
74
|
* pipeline surface minimal.
|
|
75
|
-
*
|
|
76
|
-
* The per-turn abort signal lives on {@link MemoryArgs.signal} instead of
|
|
77
|
-
* here so the pipeline runner's `linkAbortSignal` can swap it for an
|
|
78
|
-
* internally-linked signal — that way a plugin timeout actually cancels
|
|
79
|
-
* the underlying `prepareMemory` work instead of letting it run after
|
|
80
|
-
* `Promise.race` has already rejected.
|
|
81
75
|
*/
|
|
82
76
|
export interface DefaultMemoryRetrievalDeps {
|
|
83
77
|
/** Live message list for this turn (pre-injection). */
|
|
@@ -101,6 +95,11 @@ export interface DefaultMemoryRetrievalDeps {
|
|
|
101
95
|
* trusted) or a single {@link GraphMemoryPayload} wrapping the graph
|
|
102
96
|
* retriever's full output. The agent loop narrows via
|
|
103
97
|
* {@link DEFAULT_MEMORY_GRAPH_KIND} to consume it.
|
|
98
|
+
*
|
|
99
|
+
* Memory retrieval blocks the turn — there is no soft timeout here. Memory
|
|
100
|
+
* is critical context, and silently dropping it produces a worse outcome
|
|
101
|
+
* than a slower turn. Cancellation still works via `args.signal`, which is
|
|
102
|
+
* threaded into `prepareMemory`.
|
|
104
103
|
*/
|
|
105
104
|
export async function runDefaultMemoryRetrieval(
|
|
106
105
|
args: MemoryArgs,
|
package/src/plugins/types.ts
CHANGED
|
@@ -784,6 +784,8 @@ export interface TurnInjectionInputs {
|
|
|
784
784
|
* context (unified turn context, etc.). Drives per-injector gating.
|
|
785
785
|
*/
|
|
786
786
|
readonly mode?: InjectionMode;
|
|
787
|
+
/** Disk-pressure cleanup-mode context or null to skip the warning. */
|
|
788
|
+
readonly diskPressureContext?: DiskPressureInjectionContext | null;
|
|
787
789
|
/** Workspace top-level context text (`<workspace>...`) or null to skip. */
|
|
788
790
|
readonly workspaceTopLevelContext?: string | null;
|
|
789
791
|
/** Pre-built unified-turn-context text (`<turn_context>...`) or null to skip. */
|
|
@@ -860,6 +862,11 @@ export interface TurnInjectionInputs {
|
|
|
860
862
|
readonly isNonInteractive?: boolean;
|
|
861
863
|
}
|
|
862
864
|
|
|
865
|
+
export interface DiskPressureInjectionContext {
|
|
866
|
+
/** True when the current turn is allowed to run only for storage cleanup. */
|
|
867
|
+
readonly cleanupModeActive: boolean;
|
|
868
|
+
}
|
|
869
|
+
|
|
863
870
|
/**
|
|
864
871
|
* Per-turn execution context threaded through every middleware invocation.
|
|
865
872
|
*
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auxiliary message injection for proactive artifacts.
|
|
3
|
+
*
|
|
4
|
+
* Injects an assistant message into a conversation without going through
|
|
5
|
+
* the normal agent loop. Defers injection while the conversation is
|
|
6
|
+
* actively processing to preserve chronological message ordering.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createAssistantMessage } from "../agent/message-types.js";
|
|
10
|
+
import { findConversation } from "../daemon/conversation-store.js";
|
|
11
|
+
import { addMessage } from "../memory/conversation-crud.js";
|
|
12
|
+
import type { BroadcastFn } from "../notifications/adapters/macos.js";
|
|
13
|
+
import { getLogger } from "../util/logger.js";
|
|
14
|
+
|
|
15
|
+
const log = getLogger("aux-message-injector");
|
|
16
|
+
const IDLE_POLL_MS = 200;
|
|
17
|
+
const IDLE_TIMEOUT_MS = 60_000;
|
|
18
|
+
|
|
19
|
+
async function waitForIdle(conversationId: string): Promise<boolean> {
|
|
20
|
+
const start = Date.now();
|
|
21
|
+
while (Date.now() - start < IDLE_TIMEOUT_MS) {
|
|
22
|
+
const conv = findConversation(conversationId);
|
|
23
|
+
if (!conv || !conv.processing) return true;
|
|
24
|
+
await new Promise((resolve) => setTimeout(resolve, IDLE_POLL_MS));
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function injectAuxAssistantMessage(params: {
|
|
30
|
+
conversationId: string;
|
|
31
|
+
text: string;
|
|
32
|
+
broadcastMessage: BroadcastFn;
|
|
33
|
+
}): Promise<void> {
|
|
34
|
+
const conv = findConversation(params.conversationId);
|
|
35
|
+
if (conv?.processing) {
|
|
36
|
+
const reachedIdle = await waitForIdle(params.conversationId);
|
|
37
|
+
if (!reachedIdle) {
|
|
38
|
+
log.warn(
|
|
39
|
+
{ conversationId: params.conversationId },
|
|
40
|
+
"Timed out waiting for conversation idle; injecting anyway",
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const msg = await addMessage(
|
|
46
|
+
params.conversationId,
|
|
47
|
+
"assistant",
|
|
48
|
+
JSON.stringify([{ type: "text", text: params.text }]),
|
|
49
|
+
undefined,
|
|
50
|
+
{ skipIndexing: true },
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const current = findConversation(params.conversationId);
|
|
54
|
+
if (current && !current.processing) {
|
|
55
|
+
current.getMessages().push(createAssistantMessage(params.text));
|
|
56
|
+
|
|
57
|
+
params.broadcastMessage({
|
|
58
|
+
type: "assistant_text_delta",
|
|
59
|
+
text: params.text,
|
|
60
|
+
conversationId: params.conversationId,
|
|
61
|
+
});
|
|
62
|
+
params.broadcastMessage({
|
|
63
|
+
type: "message_complete",
|
|
64
|
+
conversationId: params.conversationId,
|
|
65
|
+
messageId: msg.id,
|
|
66
|
+
source: "aux",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
params.broadcastMessage({
|
|
71
|
+
type: "conversation_list_invalidated",
|
|
72
|
+
reason: "reordered",
|
|
73
|
+
});
|
|
74
|
+
}
|