@vellumai/assistant 0.8.7-dev.202606052232.2ddc989 → 0.8.8
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/bun.lock +2 -2
- package/docs/plugins.md +832 -0
- package/examples/plugins/echo/README.md +60 -61
- package/examples/plugins/echo/package.json +2 -1
- package/examples/plugins/echo/register.ts +143 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +6 -7
- package/openapi.yaml +5 -15
- package/package.json +2 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +56 -3
- package/src/__tests__/anthropic-provider.test.ts +1 -1
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +1 -4
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +405 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +251 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +7 -3
- package/src/__tests__/conversation-agent-loop.test.ts +39 -42
- package/src/__tests__/conversation-clean-command.test.ts +2 -5
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -4
- package/src/__tests__/conversation-runtime-assembly.test.ts +71 -140
- package/src/__tests__/conversation-runtime-workspace.test.ts +27 -108
- package/src/__tests__/conversation-starter-routes.test.ts +6 -14
- package/src/__tests__/conversation-workspace-cache-state.test.ts +16 -17
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -61
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -7
- package/src/__tests__/db-acp-history.test.ts +0 -101
- package/src/__tests__/dynamic-page-surface.test.ts +0 -31
- package/src/__tests__/file-write-tool.test.ts +0 -63
- package/src/__tests__/gateway-only-guard.test.ts +2 -12
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +4 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -1
- package/src/__tests__/heartbeat-service.test.ts +0 -1
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/injector-background-turn.test.ts +1 -1
- package/src/__tests__/injector-chain.test.ts +6 -34
- package/src/__tests__/injector-disk-pressure.test.ts +34 -77
- package/src/__tests__/injector-document-comments.test.ts +1 -1
- package/src/__tests__/list-messages-hidden-metadata.test.ts +0 -38
- package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
- package/src/__tests__/{overflow-reduction-loop.test.ts → overflow-reduce-pipeline.test.ts} +284 -64
- package/src/__tests__/pipeline-runner.test.ts +554 -0
- package/src/__tests__/plugin-api-shim.test.ts +6 -3
- package/src/__tests__/plugin-bootstrap.test.ts +23 -12
- package/src/__tests__/plugin-registry.test.ts +49 -3
- package/src/__tests__/plugin-types.test.ts +70 -0
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +1 -4
- package/src/__tests__/skill-feature-flags-integration.test.ts +0 -33
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-fork-notifications.test.ts +3 -1
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +3 -1
- package/src/__tests__/subagent-notify-parent.test.ts +3 -1
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +286 -54
- package/src/acp/__tests__/client-handler.test.ts +0 -40
- package/src/acp/__tests__/prepare-agent-env.test.ts +0 -137
- package/src/acp/__tests__/session-manager-persistence.test.ts +28 -95
- package/src/acp/agent-process.ts +1 -61
- package/src/acp/client-handler.ts +0 -31
- package/src/acp/prepare-agent-env.ts +29 -83
- package/src/acp/resolve-agent.test.ts +7 -320
- package/src/acp/resolve-agent.ts +18 -182
- package/src/acp/session-manager.ts +73 -495
- package/src/acp/types.ts +0 -8
- package/src/agent/compaction-circuit.ts +102 -60
- package/src/agent/loop.ts +59 -32
- package/src/api/responses/conversation-message.ts +1 -7
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/background-wake/next-wake.ts +0 -1
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +0 -10
- package/src/config/acp-defaults.ts +0 -6
- package/src/config/bundled-skills/acp/SKILL.md +31 -83
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +381 -224
- package/src/config/bundled-skills/app-builder/TOOLS.json +0 -29
- package/src/config/bundled-skills/document-editor/SKILL.md +23 -28
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +5 -14
- package/src/config/schemas/heartbeat.ts +0 -9
- package/src/context/strip-injections.ts +2 -8
- package/src/context/window-manager.ts +1 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +11 -0
- package/src/daemon/conversation-agent-loop.ts +279 -62
- package/src/daemon/conversation-runtime-assembly.ts +69 -106
- package/src/daemon/conversation-store.ts +90 -9
- package/src/daemon/conversation-workspace.ts +0 -17
- package/src/daemon/conversation.ts +6 -0
- package/src/daemon/external-plugins-bootstrap.ts +11 -11
- package/src/daemon/handlers/conversations.ts +1 -3
- package/src/daemon/handlers/skills.ts +1 -4
- package/src/daemon/lifecycle.ts +0 -21
- package/src/daemon/server.ts +0 -2
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -3
- package/src/heartbeat/heartbeat-run-store.ts +1 -23
- package/src/heartbeat/heartbeat-service.ts +0 -26
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -15
- package/src/ipc/skill-routes/memory.ts +2 -4
- package/src/memory/conversation-starter-checkpoints.ts +0 -1
- package/src/memory/db-init.ts +0 -2
- package/src/memory/job-handlers/conversation-starters.ts +2 -13
- package/src/memory/jobs-worker.ts +1 -1
- package/src/memory/migrations/index.ts +0 -1
- package/src/memory/schema/acp.ts +0 -4
- package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
- package/src/memory/v2/consolidation-job.ts +4 -13
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/assign.test.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/live-integration.test.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/maintain-job.test.ts +5 -5
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/orchestrate.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/reconcile.test.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/render-injection.test.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/router.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selector.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/shadow-plugin.test.ts +12 -12
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/assign.ts +5 -5
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/capabilities.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/maintain-job.ts +8 -8
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/page-content.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/provider-blocks.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/reconcile.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/render-injection.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/router.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selection-log-store.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selector.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/shadow-plugin.ts +90 -28
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/tree.ts +1 -1
- package/src/plugin-api/index.ts +5 -0
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +93 -0
- package/src/plugins/defaults/{memory-v3-shadow → circuit-breaker}/package.json +2 -2
- package/src/plugins/defaults/circuit-breaker/register.ts +39 -0
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +25 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +19 -8
- package/src/plugins/defaults/compaction/terminal.ts +73 -0
- package/src/plugins/defaults/index.ts +5 -3
- package/src/plugins/defaults/{memory-retrieval/injectors.ts → injectors/register.ts} +7 -45
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +7 -11
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +126 -0
- package/src/plugins/defaults/overflow-reduce/package.json +15 -0
- package/src/plugins/defaults/overflow-reduce/register.ts +42 -0
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +293 -6
- package/src/plugins/registry.ts +37 -9
- package/src/plugins/types.ts +336 -32
- package/src/plugins/user-loader.ts +127 -30
- package/src/proactive-artifact/aux-message-injector.ts +1 -1
- package/src/proactive-artifact/job.test.ts +1 -1
- package/src/prompts/__tests__/system-prompt.test.ts +0 -6
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +2 -4
- package/src/runtime/__tests__/agent-wake.test.ts +5 -5
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +3 -0
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +55 -283
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +4 -5
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -4
- package/src/runtime/routes/acp-routes.test.ts +25 -89
- package/src/runtime/routes/acp-routes.ts +29 -81
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +10 -6
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +2 -15
- package/src/runtime/routes/conversation-starter-routes.ts +7 -13
- package/src/runtime/routes/conversations-import-routes.ts +7 -24
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +3 -18
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/memory-v3-routes.ts +6 -16
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -4
- package/src/runtime/routes/work-items-routes.ts +4 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/signals/cancel.ts +4 -2
- package/src/subagent/manager.ts +5 -17
- package/src/tools/acp/list-agents.test.ts +1 -7
- package/src/tools/acp/spawn.test.ts +55 -158
- package/src/tools/acp/spawn.ts +72 -47
- package/src/tools/acp/steer.test.ts +8 -105
- package/src/tools/acp/steer.ts +17 -48
- package/src/tools/apps/executors.ts +8 -13
- package/src/tools/filesystem/write.ts +0 -34
- package/src/tools/subagent/spawn.ts +4 -2
- package/src/tools/ui-surface/definitions.ts +4 -25
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +5 -4
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +45 -69
- package/examples/plugins/echo/hooks/post-tool-use.ts +0 -18
- package/examples/plugins/echo/hooks/stop.ts +0 -16
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +0 -18
- package/examples/plugins/echo/src/emit.ts +0 -19
- package/src/__tests__/compaction-circuit.test.ts +0 -258
- package/src/__tests__/compaction-direct.test.ts +0 -132
- package/src/__tests__/conversations-import-system-filter.test.ts +0 -101
- package/src/acp/__tests__/agent-process.test.ts +0 -161
- package/src/acp/__tests__/helpers/acp-history-db.ts +0 -82
- package/src/acp/__tests__/helpers/exec-file-stub.ts +0 -101
- package/src/acp/__tests__/session-manager-resume.test.ts +0 -736
- package/src/acp/auto-install.test.ts +0 -196
- package/src/acp/auto-install.ts +0 -177
- package/src/acp/feature-gate.test.ts +0 -48
- package/src/acp/feature-gate.ts +0 -34
- package/src/acp/resume-hint.ts +0 -25
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +0 -48
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +0 -57
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +0 -38
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -62
- package/src/daemon/conversation-registry.ts +0 -159
- package/src/daemon/overflow-reduction-loop.ts +0 -230
- package/src/memory/migrations/272-acp-session-history-cwd.ts +0 -36
- package/src/plugins/defaults/compaction/compact.ts +0 -59
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +0 -14
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +0 -19
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +0 -75
- package/src/plugins/defaults/memory-v3-shadow/register.ts +0 -26
- package/src/tools/acp/context.ts +0 -20
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/capabilities.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/core.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/health.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/needle.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/provider-blocks.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/snapshot.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/tree.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/types.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/core.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/README.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/assignments.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/core.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/health.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/llm-retry.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/needle.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/orchestrate.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/snapshot.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/types.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/working-set.ts +0 -0
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
extractMemoryPrefixBlocks,
|
|
30
30
|
stripAllMemoryInjections,
|
|
31
31
|
} from "../memory/graph/conversation-graph-memory.js";
|
|
32
|
+
import { MEMORY_V3_BLOCK_ID } from "../memory/v3/types.js";
|
|
32
33
|
import {
|
|
33
34
|
readSlackMetadata,
|
|
34
35
|
readSlackMetadataFromMessageMetadata,
|
|
@@ -42,8 +43,8 @@ import {
|
|
|
42
43
|
renderSlackTranscriptWithProvenance,
|
|
43
44
|
} from "../messaging/providers/slack/render-transcript.js";
|
|
44
45
|
import { getInjectorChain } from "../plugins/defaults/memory-retrieval/injector-chain.js";
|
|
45
|
-
import { MEMORY_V3_BLOCK_ID } from "../plugins/defaults/memory-v3-shadow/types.js";
|
|
46
46
|
import type {
|
|
47
|
+
DiskPressureInjectionContext,
|
|
47
48
|
InjectionBlock,
|
|
48
49
|
InjectionPlacement,
|
|
49
50
|
TurnContext,
|
|
@@ -59,7 +60,6 @@ import { channelStatusToMemberStatus } from "../runtime/routes/inbound-stages/ac
|
|
|
59
60
|
import type { SubagentState } from "../subagent/types.js";
|
|
60
61
|
import { TERMINAL_STATUSES } from "../subagent/types.js";
|
|
61
62
|
import { canonicalizeInboundIdentity } from "../util/canonicalize-identity.js";
|
|
62
|
-
import { findConversationOrSubagent } from "./conversation-registry.js";
|
|
63
63
|
import type {
|
|
64
64
|
DynamicPageSurfaceData,
|
|
65
65
|
SurfaceData,
|
|
@@ -270,8 +270,8 @@ export function isGroupChatType(chatType?: string): boolean {
|
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
-
/** Context about the active workspace surface,
|
|
274
|
-
interface ActiveSurfaceContext {
|
|
273
|
+
/** Context about the active workspace surface, passed to applyRuntimeInjections. */
|
|
274
|
+
export interface ActiveSurfaceContext {
|
|
275
275
|
surfaceId: string;
|
|
276
276
|
html: string;
|
|
277
277
|
/** When set, the surface is backed by a persisted app. */
|
|
@@ -352,6 +352,24 @@ export function buildActiveDocuments(conversationId: string): Array<{
|
|
|
352
352
|
: null;
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
+
/**
|
|
356
|
+
* Resolves the `<workspace>` top-level block for the runtime injector, or
|
|
357
|
+
* `null` when the turn isn't injecting it. The refresh runs every turn so a
|
|
358
|
+
* workspace-mutating tool's `markWorkspaceTopLevelDirty` is picked up on the
|
|
359
|
+
* following turn; it is dirty-guarded, so it only rescans when the cache is
|
|
360
|
+
* stale.
|
|
361
|
+
*/
|
|
362
|
+
export function buildWorkspaceTopLevelContext(
|
|
363
|
+
ctx: {
|
|
364
|
+
refreshWorkspaceTopLevelContextIfNeeded(): void;
|
|
365
|
+
workspaceTopLevelContext: string | null;
|
|
366
|
+
},
|
|
367
|
+
shouldInject: boolean,
|
|
368
|
+
): string | null {
|
|
369
|
+
ctx.refreshWorkspaceTopLevelContextIfNeeded();
|
|
370
|
+
return shouldInject ? ctx.workspaceTopLevelContext : null;
|
|
371
|
+
}
|
|
372
|
+
|
|
355
373
|
const MAX_CONTEXT_LENGTH = 100_000;
|
|
356
374
|
|
|
357
375
|
function truncateHtml(html: string, budget: number): string {
|
|
@@ -567,7 +585,7 @@ export function buildSubagentStatusBlock(
|
|
|
567
585
|
}
|
|
568
586
|
|
|
569
587
|
// The `<active_subagents>` block is emitted by the `subagent-status` default
|
|
570
|
-
// injector (`plugins/defaults/
|
|
588
|
+
// injector (`plugins/defaults/injectors/register.ts`) as an `append-user-tail`
|
|
571
589
|
// placement. Use {@link applyRuntimeInjections} with
|
|
572
590
|
// `options.subagentStatusBlock` set, or drive the injector chain directly
|
|
573
591
|
// via `collectInjectorBlocks`.
|
|
@@ -1822,19 +1840,25 @@ function applyInjectionBlock(
|
|
|
1822
1840
|
* bag attached to the {@link TurnContext} the caller provides (or to an
|
|
1823
1841
|
* ephemeral {@link TurnContext} synthesized for test call sites). A small
|
|
1824
1842
|
* number of fields drive hardcoded branches that live outside the injector
|
|
1825
|
-
* chain — `
|
|
1826
|
-
*
|
|
1827
|
-
*
|
|
1828
|
-
*
|
|
1829
|
-
* list, the channel command context, the voice call-control prompt, and the
|
|
1830
|
-
* transport hints are not on this bag: `applyRuntimeInjections` resolves them
|
|
1831
|
-
* from the live conversation itself (its surface state, `channelCapabilities`,
|
|
1832
|
-
* the document store keyed by `conversationId`, its `commandIntent`, its
|
|
1833
|
-
* `voiceCallControlPrompt`, and its `transportHints` respectively), so the
|
|
1834
|
-
* orchestrator does not compute or thread them per turn.
|
|
1843
|
+
* chain — `activeSurface`, `channelCapabilities`, `channelCommandContext`,
|
|
1844
|
+
* `voiceCallControlPrompt`, `transportHints`, and `isNonInteractive` —
|
|
1845
|
+
* because they are orchestrator-owned content that never made sense as
|
|
1846
|
+
* plugin-overridable default injectors.
|
|
1835
1847
|
*/
|
|
1836
1848
|
export interface RuntimeInjectionOptions {
|
|
1849
|
+
diskPressureContext?: DiskPressureInjectionContext | null;
|
|
1850
|
+
/**
|
|
1851
|
+
* Active dashboard-surface context (read from `<active_workspace>`). Kept
|
|
1852
|
+
* on the options bag rather than an injector because it is a
|
|
1853
|
+
* channel-capability concern that has never been gated as a default
|
|
1854
|
+
* injector.
|
|
1855
|
+
*/
|
|
1856
|
+
activeSurface?: ActiveSurfaceContext | null;
|
|
1857
|
+
workspaceTopLevelContext?: string | null;
|
|
1858
|
+
channelCapabilities?: ChannelCapabilities | null;
|
|
1859
|
+
channelCommandContext?: ChannelCommandContext | null;
|
|
1837
1860
|
unifiedTurnContext?: string | null;
|
|
1861
|
+
voiceCallControlPrompt?: string | null;
|
|
1838
1862
|
subagentStatusBlock?: string | null;
|
|
1839
1863
|
isNonInteractive?: boolean;
|
|
1840
1864
|
/**
|
|
@@ -1844,6 +1868,7 @@ export interface RuntimeInjectionOptions {
|
|
|
1844
1868
|
* configured reminder.
|
|
1845
1869
|
*/
|
|
1846
1870
|
isBackgroundConversation?: boolean;
|
|
1871
|
+
transportHints?: string[] | null;
|
|
1847
1872
|
/**
|
|
1848
1873
|
* Pre-rendered Slack chronological transcript that replaces the
|
|
1849
1874
|
* default `runMessages` history for any Slack conversation (channels
|
|
@@ -1878,6 +1903,7 @@ export interface RuntimeInjectionOptions {
|
|
|
1878
1903
|
* `undefined` when the inbound is a top-level (non-thread) post.
|
|
1879
1904
|
*/
|
|
1880
1905
|
slackActiveThreadFocusBlock?: string | null;
|
|
1906
|
+
activeDocuments?: TurnInjectionInputs["activeDocuments"];
|
|
1881
1907
|
mode?: InjectionMode;
|
|
1882
1908
|
/**
|
|
1883
1909
|
* Per-turn {@link TurnContext} forwarded to plugin-registered
|
|
@@ -1905,35 +1931,33 @@ export interface RuntimeInjectionOptions {
|
|
|
1905
1931
|
*/
|
|
1906
1932
|
function buildTurnInjectionInputs(
|
|
1907
1933
|
options: RuntimeInjectionOptions,
|
|
1908
|
-
channelCapabilities: ChannelCapabilities | null,
|
|
1909
|
-
activeDocuments: TurnInjectionInputs["activeDocuments"],
|
|
1910
1934
|
): TurnInjectionInputs {
|
|
1911
1935
|
return {
|
|
1912
1936
|
mode: options.mode,
|
|
1937
|
+
diskPressureContext: options.diskPressureContext,
|
|
1938
|
+
workspaceTopLevelContext: options.workspaceTopLevelContext,
|
|
1913
1939
|
unifiedTurnContext: options.unifiedTurnContext,
|
|
1914
1940
|
subagentStatusBlock: options.subagentStatusBlock,
|
|
1915
|
-
channelCapabilities,
|
|
1941
|
+
channelCapabilities: options.channelCapabilities,
|
|
1916
1942
|
slackChronologicalMessages: options.slackChronologicalMessages,
|
|
1917
1943
|
slackActiveThreadFocusBlock: options.slackActiveThreadFocusBlock,
|
|
1944
|
+
activeSurface: options.activeSurface,
|
|
1945
|
+
channelCommandContext: options.channelCommandContext,
|
|
1946
|
+
voiceCallControlPrompt: options.voiceCallControlPrompt,
|
|
1947
|
+
transportHints: options.transportHints,
|
|
1918
1948
|
isNonInteractive: options.isNonInteractive,
|
|
1919
1949
|
isBackgroundConversation: options.isBackgroundConversation,
|
|
1920
|
-
activeDocuments,
|
|
1950
|
+
activeDocuments: options.activeDocuments,
|
|
1921
1951
|
};
|
|
1922
1952
|
}
|
|
1923
1953
|
|
|
1924
|
-
/**
|
|
1925
|
-
* Conversation id used for the synthetic fallback {@link TurnContext} and the
|
|
1926
|
-
* live-conversation lookup when the caller omits a context (test call sites).
|
|
1927
|
-
*/
|
|
1928
|
-
const RUNTIME_ASSEMBLY_FALLBACK_CONVERSATION_ID = "runtime-assembly-fallback";
|
|
1929
|
-
|
|
1930
1954
|
/** Minimal synthetic TurnContext used when the caller omits one. */
|
|
1931
1955
|
function synthesizeFallbackTurnContext(
|
|
1932
1956
|
inputs: TurnInjectionInputs,
|
|
1933
1957
|
): TurnContext {
|
|
1934
1958
|
return {
|
|
1935
|
-
requestId:
|
|
1936
|
-
conversationId:
|
|
1959
|
+
requestId: "runtime-assembly-fallback",
|
|
1960
|
+
conversationId: "runtime-assembly-fallback",
|
|
1937
1961
|
turnIndex: 0,
|
|
1938
1962
|
trust: {
|
|
1939
1963
|
sourceChannel: inputs.channelCapabilities?.channel
|
|
@@ -1974,9 +1998,6 @@ function synthesizeFallbackTurnContext(
|
|
|
1974
1998
|
* 6. Run the remaining hardcoded branches (`isNonInteractive`,
|
|
1975
1999
|
* `voiceCallControlPrompt`, `activeSurface`, `channelCapabilities`,
|
|
1976
2000
|
* `channelCommandContext`, `transportHints`) in their historical order.
|
|
1977
|
-
* `voiceCallControlPrompt`, `activeSurface`, `channelCapabilities`,
|
|
1978
|
-
* `channelCommandContext`, and `transportHints` are sourced from the live
|
|
1979
|
-
* conversation rather than `options`.
|
|
1980
2001
|
* 7. Finally, apply the chain's remaining blocks by placement:
|
|
1981
2002
|
* `"append-user-tail"` in ascending `order`, then `"prepend-user-tail"`
|
|
1982
2003
|
* in descending `order` so the lowest-`order` prepend lands topmost in
|
|
@@ -1991,58 +2012,14 @@ export async function applyRuntimeInjections(
|
|
|
1991
2012
|
options: RuntimeInjectionOptions,
|
|
1992
2013
|
): Promise<RuntimeInjectionResult> {
|
|
1993
2014
|
const mode = options.mode ?? "full";
|
|
1994
|
-
|
|
1995
|
-
// Source the channel capabilities from the live conversation rather than a
|
|
1996
|
-
// per-turn option computed by the orchestrator. The same value drives the
|
|
1997
|
-
// Slack-conversation gate, the `<channel_capabilities>` branch, and the
|
|
1998
|
-
// per-injector inputs the Slack injectors read.
|
|
1999
|
-
const conversationId =
|
|
2000
|
-
options.turnContext?.conversationId ??
|
|
2001
|
-
RUNTIME_ASSEMBLY_FALLBACK_CONVERSATION_ID;
|
|
2002
|
-
const channelCapabilities =
|
|
2003
|
-
findConversationOrSubagent(conversationId)?.channelCapabilities ?? null;
|
|
2004
|
-
const slackConversation = channelCapabilities?.channel === "slack";
|
|
2005
|
-
|
|
2006
|
-
// Source the active documents from the document store keyed by the same
|
|
2007
|
-
// conversation id rather than a per-turn option computed by the
|
|
2008
|
-
// orchestrator; the `active-documents` and `document-comments` injectors
|
|
2009
|
-
// read the result off their per-injector inputs.
|
|
2010
|
-
const activeDocuments = buildActiveDocuments(conversationId);
|
|
2011
|
-
|
|
2012
|
-
// Source the channel command intent (e.g. Telegram /start) from the live
|
|
2013
|
-
// conversation rather than a per-turn option. It is set on the conversation
|
|
2014
|
-
// at message-processing start and cleared at turn end, so the same value
|
|
2015
|
-
// drives the `<channel_command_context>` branch on every assembly call
|
|
2016
|
-
// within the turn.
|
|
2017
|
-
const channelCommandContext =
|
|
2018
|
-
findConversationOrSubagent(conversationId)?.commandIntent ?? null;
|
|
2019
|
-
|
|
2020
|
-
// Source the voice call-control prompt from the live conversation rather
|
|
2021
|
-
// than a per-turn option. The voice-session bridge sets it on the
|
|
2022
|
-
// conversation when a call attaches and clears it when the call ends, so
|
|
2023
|
-
// the same value drives the `<voice_call_control>` branch on every assembly
|
|
2024
|
-
// call within the turn.
|
|
2025
|
-
const voiceCallControlPrompt =
|
|
2026
|
-
findConversationOrSubagent(conversationId)?.voiceCallControlPrompt ?? null;
|
|
2027
|
-
|
|
2028
|
-
// Source the transport hints from the live conversation rather than a
|
|
2029
|
-
// per-turn option. They are set on the conversation from the inbound
|
|
2030
|
-
// message's transport when the message is processed, so the same value
|
|
2031
|
-
// drives the `<transport_hints>` branch on every assembly call within the
|
|
2032
|
-
// turn.
|
|
2033
|
-
const transportHints =
|
|
2034
|
-
findConversationOrSubagent(conversationId)?.transportHints ?? null;
|
|
2015
|
+
const slackConversation = options.channelCapabilities?.channel === "slack";
|
|
2035
2016
|
|
|
2036
2017
|
// Build the per-injector inputs and attach them to the caller's
|
|
2037
2018
|
// TurnContext (without mutating it). When the caller didn't supply one,
|
|
2038
2019
|
// synthesize a minimal fallback so the chain still runs — test call sites
|
|
2039
2020
|
// that drive injection via `options` without constructing a full context
|
|
2040
2021
|
// continue to work.
|
|
2041
|
-
const injectionInputs = buildTurnInjectionInputs(
|
|
2042
|
-
options,
|
|
2043
|
-
channelCapabilities,
|
|
2044
|
-
activeDocuments,
|
|
2045
|
-
);
|
|
2022
|
+
const injectionInputs = buildTurnInjectionInputs(options);
|
|
2046
2023
|
const turnCtx: TurnContext = options.turnContext
|
|
2047
2024
|
? { ...options.turnContext, injectionInputs }
|
|
2048
2025
|
: synthesizeFallbackTurnContext(injectionInputs);
|
|
@@ -2216,56 +2193,42 @@ export async function applyRuntimeInjections(
|
|
|
2216
2193
|
}
|
|
2217
2194
|
}
|
|
2218
2195
|
|
|
2219
|
-
if (voiceCallControlPrompt) {
|
|
2196
|
+
if (options.voiceCallControlPrompt) {
|
|
2220
2197
|
const userTail = result[result.length - 1];
|
|
2221
2198
|
if (userTail && userTail.role === "user") {
|
|
2222
2199
|
result = [
|
|
2223
2200
|
...result.slice(0, -1),
|
|
2224
|
-
injectVoiceCallControlContext(userTail, voiceCallControlPrompt),
|
|
2201
|
+
injectVoiceCallControlContext(userTail, options.voiceCallControlPrompt),
|
|
2225
2202
|
];
|
|
2226
2203
|
}
|
|
2227
2204
|
}
|
|
2228
2205
|
|
|
2229
|
-
if (mode === "full") {
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
? buildActiveSurfaceContext({
|
|
2237
|
-
currentActiveSurfaceId: surfaceConversation.currentActiveSurfaceId,
|
|
2238
|
-
currentPage: surfaceConversation.currentPage,
|
|
2239
|
-
surfaceState: surfaceConversation.surfaceState,
|
|
2240
|
-
})
|
|
2241
|
-
: null;
|
|
2242
|
-
if (activeSurface) {
|
|
2243
|
-
const userTail = result[result.length - 1];
|
|
2244
|
-
if (userTail && userTail.role === "user") {
|
|
2245
|
-
result = [
|
|
2246
|
-
...result.slice(0, -1),
|
|
2247
|
-
injectActiveSurfaceContext(userTail, activeSurface),
|
|
2248
|
-
];
|
|
2249
|
-
}
|
|
2206
|
+
if (mode === "full" && options.activeSurface) {
|
|
2207
|
+
const userTail = result[result.length - 1];
|
|
2208
|
+
if (userTail && userTail.role === "user") {
|
|
2209
|
+
result = [
|
|
2210
|
+
...result.slice(0, -1),
|
|
2211
|
+
injectActiveSurfaceContext(userTail, options.activeSurface),
|
|
2212
|
+
];
|
|
2250
2213
|
}
|
|
2251
2214
|
}
|
|
2252
2215
|
|
|
2253
|
-
if (channelCapabilities) {
|
|
2216
|
+
if (options.channelCapabilities) {
|
|
2254
2217
|
const userTail = result[result.length - 1];
|
|
2255
2218
|
if (userTail && userTail.role === "user") {
|
|
2256
2219
|
result = [
|
|
2257
2220
|
...result.slice(0, -1),
|
|
2258
|
-
injectChannelCapabilityContext(userTail, channelCapabilities),
|
|
2221
|
+
injectChannelCapabilityContext(userTail, options.channelCapabilities),
|
|
2259
2222
|
];
|
|
2260
2223
|
}
|
|
2261
2224
|
}
|
|
2262
2225
|
|
|
2263
|
-
if (mode === "full" && channelCommandContext) {
|
|
2226
|
+
if (mode === "full" && options.channelCommandContext) {
|
|
2264
2227
|
const userTail = result[result.length - 1];
|
|
2265
2228
|
if (userTail && userTail.role === "user") {
|
|
2266
2229
|
result = [
|
|
2267
2230
|
...result.slice(0, -1),
|
|
2268
|
-
injectChannelCommandContext(userTail, channelCommandContext),
|
|
2231
|
+
injectChannelCommandContext(userTail, options.channelCommandContext),
|
|
2269
2232
|
];
|
|
2270
2233
|
}
|
|
2271
2234
|
}
|
|
@@ -2279,14 +2242,14 @@ export async function applyRuntimeInjections(
|
|
|
2279
2242
|
if (
|
|
2280
2243
|
mode === "full" &&
|
|
2281
2244
|
!slackConversation &&
|
|
2282
|
-
transportHints &&
|
|
2283
|
-
transportHints.length > 0
|
|
2245
|
+
options.transportHints &&
|
|
2246
|
+
options.transportHints.length > 0
|
|
2284
2247
|
) {
|
|
2285
2248
|
const userTail = result[result.length - 1];
|
|
2286
2249
|
if (userTail && userTail.role === "user") {
|
|
2287
2250
|
result = [
|
|
2288
2251
|
...result.slice(0, -1),
|
|
2289
|
-
injectTransportHints(userTail, transportHints),
|
|
2252
|
+
injectTransportHints(userTail, options.transportHints),
|
|
2290
2253
|
];
|
|
2291
2254
|
}
|
|
2292
2255
|
}
|
|
@@ -27,18 +27,99 @@ import { ProviderNotConfiguredError } from "../util/errors.js";
|
|
|
27
27
|
import { getSandboxWorkingDir } from "../util/platform.js";
|
|
28
28
|
import { Conversation } from "./conversation.js";
|
|
29
29
|
import type { ConversationEvictor } from "./conversation-evictor.js";
|
|
30
|
-
import {
|
|
31
|
-
allConversations,
|
|
32
|
-
clearConversations,
|
|
33
|
-
conversationCount,
|
|
34
|
-
conversationIds,
|
|
35
|
-
deleteConversation,
|
|
36
|
-
findConversation,
|
|
37
|
-
setConversation,
|
|
38
|
-
} from "./conversation-registry.js";
|
|
39
30
|
import type { ConversationCreateOptions } from "./handlers/shared.js";
|
|
40
31
|
import { buildTransportHints } from "./transport-hints.js";
|
|
41
32
|
|
|
33
|
+
// ── Private store ──────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
const conversations = new Map<string, Conversation>();
|
|
36
|
+
|
|
37
|
+
// ── Read helpers ───────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
export function findConversation(
|
|
40
|
+
conversationId: string,
|
|
41
|
+
): Conversation | undefined {
|
|
42
|
+
return conversations.get(conversationId);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function findConversationBySurfaceId(
|
|
46
|
+
surfaceId: string,
|
|
47
|
+
): Conversation | undefined {
|
|
48
|
+
// Fast path: exact surfaceId match in surfaceState
|
|
49
|
+
for (const c of conversations.values()) {
|
|
50
|
+
if (c.surfaceState.has(surfaceId)) return c;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Fallback: standalone app surfaces use "app-open-{appId}" IDs that
|
|
54
|
+
// were never part of any conversation. Extract the appId and find
|
|
55
|
+
// a conversation whose surfaceState has a surface for that app.
|
|
56
|
+
const appOpenPrefix = "app-open-";
|
|
57
|
+
if (surfaceId.startsWith(appOpenPrefix)) {
|
|
58
|
+
const appId = surfaceId.slice(appOpenPrefix.length);
|
|
59
|
+
for (const c of conversations.values()) {
|
|
60
|
+
for (const [, state] of c.surfaceState.entries()) {
|
|
61
|
+
const data = state.data as unknown as Record<string, unknown>;
|
|
62
|
+
if (data?.appId === appId) {
|
|
63
|
+
// Register this surfaceId so subsequent lookups are O(1)
|
|
64
|
+
c.surfaceState.set(surfaceId, state);
|
|
65
|
+
return c;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function conversationCount(): number {
|
|
75
|
+
return conversations.size;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Iterate over all active conversations. */
|
|
79
|
+
export function allConversations(): IterableIterator<Conversation> {
|
|
80
|
+
return conversations.values();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Iterate over all [id, conversation] entries. */
|
|
84
|
+
export function conversationEntries(): IterableIterator<
|
|
85
|
+
[string, Conversation]
|
|
86
|
+
> {
|
|
87
|
+
return conversations.entries();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Iterate over all active conversation IDs. */
|
|
91
|
+
function conversationIds(): IterableIterator<string> {
|
|
92
|
+
return conversations.keys();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ── Write helpers ──────────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
export function setConversation(
|
|
98
|
+
conversationId: string,
|
|
99
|
+
conversation: Conversation,
|
|
100
|
+
): void {
|
|
101
|
+
conversations.set(conversationId, conversation);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function deleteConversation(conversationId: string): boolean {
|
|
105
|
+
return conversations.delete(conversationId);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function clearConversations(): void {
|
|
109
|
+
conversations.clear();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ── Underlying Map (for the evictor, which takes a mutable ref) ───
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Expose the raw Map for the {@link ConversationEvictor}, which needs
|
|
116
|
+
* a mutable reference to delete entries during sweeps. No other code
|
|
117
|
+
* should use this — prefer the named helpers above.
|
|
118
|
+
*/
|
|
119
|
+
export function getConversationMap(): Map<string, Conversation> {
|
|
120
|
+
return conversations;
|
|
121
|
+
}
|
|
122
|
+
|
|
42
123
|
// ── Per-conversation persistent options ────────────────────────────
|
|
43
124
|
|
|
44
125
|
const conversationOptions = new Map<string, ConversationCreateOptions>();
|
|
@@ -4,7 +4,6 @@ import { getConversation } from "../memory/conversation-crud.js";
|
|
|
4
4
|
import { resolveConversationDirectoryPaths } from "../memory/conversation-directories.js";
|
|
5
5
|
import { renderWorkspaceTopLevelContext } from "../workspace/top-level-renderer.js";
|
|
6
6
|
import { scanTopLevelDirectories } from "../workspace/top-level-scanner.js";
|
|
7
|
-
import { findConversationOrSubagent } from "./conversation-registry.js";
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Subset of Conversation state that workspace context helpers need.
|
|
@@ -26,22 +25,6 @@ export interface WorkspaceConversationContext {
|
|
|
26
25
|
hostUsername?: string;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
/**
|
|
30
|
-
* Resolve the live workspace top-level block for a conversation, refreshing
|
|
31
|
-
* the dirty-guarded cache first so a workspace-mutating tool's
|
|
32
|
-
* `markWorkspaceTopLevelDirty` from the prior turn is picked up. Returns `null`
|
|
33
|
-
* when no live conversation is found (no active conversation, or a context with
|
|
34
|
-
* no conversation id) or when the rendered context is empty.
|
|
35
|
-
*/
|
|
36
|
-
export function resolveWorkspaceTopLevelContext(
|
|
37
|
-
conversationId: string | undefined,
|
|
38
|
-
): string | null {
|
|
39
|
-
const conversation = findConversationOrSubagent(conversationId);
|
|
40
|
-
if (!conversation) return null;
|
|
41
|
-
refreshWorkspaceTopLevelContextIfNeeded(conversation);
|
|
42
|
-
return conversation.workspaceTopLevelContext;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
28
|
/** Refresh workspace top-level directory context if needed. */
|
|
46
29
|
export function refreshWorkspaceTopLevelContextIfNeeded(
|
|
47
30
|
ctx: WorkspaceConversationContext,
|
|
@@ -128,6 +128,7 @@ import {
|
|
|
128
128
|
createResolveToolsCallback,
|
|
129
129
|
createToolExecutor,
|
|
130
130
|
} from "./conversation-tool-setup.js";
|
|
131
|
+
import { refreshWorkspaceTopLevelContextIfNeeded as refreshWorkspaceImpl } from "./conversation-workspace.js";
|
|
131
132
|
import { canonicalizeTimeZone } from "./date-context.js";
|
|
132
133
|
import { HostAppControlProxy } from "./host-app-control-proxy.js";
|
|
133
134
|
import { HostCuProxy } from "./host-cu-proxy.js";
|
|
@@ -1098,6 +1099,7 @@ export class Conversation {
|
|
|
1098
1099
|
// etc.) — skip those so they don't silently reset the counter.
|
|
1099
1100
|
if (result.summaryFailed !== undefined) {
|
|
1100
1101
|
await this.agentLoop.compactionCircuit.recordOutcome(
|
|
1102
|
+
this,
|
|
1101
1103
|
result.summaryFailed,
|
|
1102
1104
|
this.sendToClient,
|
|
1103
1105
|
);
|
|
@@ -1344,6 +1346,10 @@ export class Conversation {
|
|
|
1344
1346
|
|
|
1345
1347
|
// ── Workspace ────────────────────────────────────────────────────
|
|
1346
1348
|
|
|
1349
|
+
refreshWorkspaceTopLevelContextIfNeeded(): void {
|
|
1350
|
+
refreshWorkspaceImpl(this);
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1347
1353
|
markWorkspaceTopLevelDirty(): void {
|
|
1348
1354
|
this.workspaceTopLevelDirty = true;
|
|
1349
1355
|
}
|
|
@@ -2,22 +2,21 @@
|
|
|
2
2
|
* Plugin bootstrap — runs every registered plugin's `init()` hook once during
|
|
3
3
|
* daemon startup.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* registry has been fully populated for this boot cycle. This function:
|
|
5
|
+
* Plugins register themselves via side-effect imports elsewhere in the boot
|
|
6
|
+
* sequence (first-party) or at runtime (hot-reload). By the time
|
|
7
|
+
* {@link bootstrapPlugins} runs, the registry has been fully populated for
|
|
8
|
+
* this boot cycle. This function:
|
|
10
9
|
*
|
|
11
10
|
* 1. Registers the canonical first-party default plugins via
|
|
12
|
-
* {@link registerDefaultPlugins}. Registration is
|
|
13
|
-
* calls (e.g. during integration tests) do not throw.
|
|
11
|
+
* {@link registerDefaultPlugins} (one per pipeline). Registration is
|
|
12
|
+
* idempotent so repeat calls (e.g. during integration tests) do not throw.
|
|
14
13
|
* 2. Walks {@link getRegisteredPlugins} in registration order.
|
|
15
14
|
* 3. For each plugin, consults `manifest.requiresFlag` against
|
|
16
15
|
* {@link isAssistantFeatureFlagEnabled}. If any listed flag is disabled,
|
|
17
16
|
* the plugin is skipped wholesale — no `init()`, no tool/route/skill
|
|
18
17
|
* contributions, no entry in the shutdown hook, and the plugin is also
|
|
19
|
-
* dropped from the registry via {@link unregisterPlugin} so
|
|
20
|
-
*
|
|
18
|
+
* dropped from the registry via {@link unregisterPlugin} so its middleware
|
|
19
|
+
* stops participating in pipeline runs. This is the primary mechanism for
|
|
21
20
|
* shipping experimental plugins behind a feature flag.
|
|
22
21
|
* 4. Resolves the plugin's `manifest.requiresCredential` entries via the
|
|
23
22
|
* credential store helper ({@link getSecureKeyAsync}). In Docker mode
|
|
@@ -262,8 +261,9 @@ export async function bootstrapPlugins(): Promise<void> {
|
|
|
262
261
|
// Tear down a plugin's contributions AND remove it from the registry. The
|
|
263
262
|
// two steps always move together on the bootstrap failure path: the former
|
|
264
263
|
// clears tools/routes/skills (so they stop appearing to the model/HTTP
|
|
265
|
-
// server), the latter drops the plugin's entry from the Map (so
|
|
266
|
-
// doesn't
|
|
264
|
+
// server), the latter drops the plugin's entry from the Map (so
|
|
265
|
+
// `getMiddlewaresFor` doesn't re-enter an uninitialized plugin on the next
|
|
266
|
+
// pipeline invocation).
|
|
267
267
|
// Shutdown context is identical for every plugin in this boot — construct
|
|
268
268
|
// once and reuse across the bootstrap-failure rollback and the normal
|
|
269
269
|
// shutdown hook below. Only `assistantVersion` is exposed today; future
|
|
@@ -8,11 +8,9 @@ import { createAbortReason } from "../../util/abort-reasons.js";
|
|
|
8
8
|
import { truncate } from "../../util/truncate.js";
|
|
9
9
|
import { regenerate } from "../conversation-history.js";
|
|
10
10
|
import {
|
|
11
|
+
clearAllActiveConversations,
|
|
11
12
|
conversationEntries,
|
|
12
13
|
findConversation,
|
|
13
|
-
} from "../conversation-registry.js";
|
|
14
|
-
import {
|
|
15
|
-
clearAllActiveConversations,
|
|
16
14
|
getOrCreateConversation,
|
|
17
15
|
touchConversation,
|
|
18
16
|
} from "../conversation-store.js";
|
|
@@ -31,10 +31,7 @@ import {
|
|
|
31
31
|
isTextMimeType as isTextMime,
|
|
32
32
|
MAX_INLINE_TEXT_SIZE,
|
|
33
33
|
} from "../../runtime/routes/workspace-utils.js";
|
|
34
|
-
import {
|
|
35
|
-
getCachedCatalogSync,
|
|
36
|
-
getCatalog,
|
|
37
|
-
} from "../../skills/catalog-cache.js";
|
|
34
|
+
import { getCachedCatalogSync, getCatalog } from "../../skills/catalog-cache.js";
|
|
38
35
|
import type { SkillFileEntry } from "../../skills/catalog-files.js";
|
|
39
36
|
import {
|
|
40
37
|
catalogSkillToSlim,
|
package/src/daemon/lifecycle.ts
CHANGED
|
@@ -98,7 +98,6 @@ import {
|
|
|
98
98
|
updateWorkItem,
|
|
99
99
|
} from "../work-items/work-item-store.js";
|
|
100
100
|
import { WorkspaceHeartbeatService } from "../workspace/heartbeat-service.js";
|
|
101
|
-
import { repairAdaptiveThinkingOnManagedProfiles } from "../workspace/migrations/097-enable-adaptive-thinking-managed-profiles.js";
|
|
102
101
|
import { WORKSPACE_MIGRATIONS } from "../workspace/migrations/registry.js";
|
|
103
102
|
import { runWorkspaceMigrations } from "../workspace/migrations/runner.js";
|
|
104
103
|
import {
|
|
@@ -590,26 +589,6 @@ export async function runDaemon(): Promise<void> {
|
|
|
590
589
|
);
|
|
591
590
|
}
|
|
592
591
|
|
|
593
|
-
// Re-run the adaptive thinking repair after overlay merge + profile seeding.
|
|
594
|
-
// Workspace migration 097 enables adaptive thinking on managed profiles, but
|
|
595
|
-
// it runs before mergeDefaultWorkspaceConfig() which can overwrite the fix
|
|
596
|
-
// with overlay profiles that have thinking disabled or absent. On-platform
|
|
597
|
-
// instances where the overlay supplies "balanced" / "quality-optimized"
|
|
598
|
-
// profiles without thinking enabled would be stuck permanently because the
|
|
599
|
-
// migration is already checkpointed as completed. This idempotent repair
|
|
600
|
-
// ensures thinking is enabled regardless of overlay ordering.
|
|
601
|
-
if (defaultConfigMerge.hadOverlay) {
|
|
602
|
-
try {
|
|
603
|
-
repairAdaptiveThinkingOnManagedProfiles(getWorkspaceDir());
|
|
604
|
-
log.info("Post-overlay adaptive thinking repair complete");
|
|
605
|
-
} catch (err) {
|
|
606
|
-
log.warn(
|
|
607
|
-
{ err },
|
|
608
|
-
"Post-overlay adaptive thinking repair failed — continuing startup",
|
|
609
|
-
);
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
592
|
log.info("Daemon startup: loading config");
|
|
614
593
|
const config = loadConfig();
|
|
615
594
|
|
package/src/daemon/server.ts
CHANGED
|
@@ -85,7 +85,6 @@ const stubConfig: {
|
|
|
85
85
|
activeHoursStart: number | null;
|
|
86
86
|
activeHoursEnd: number | null;
|
|
87
87
|
maxConsecutiveRuns: number | null;
|
|
88
|
-
maxDailyRuns: number | null;
|
|
89
88
|
disposition: string;
|
|
90
89
|
};
|
|
91
90
|
} = {
|
|
@@ -95,7 +94,6 @@ const stubConfig: {
|
|
|
95
94
|
activeHoursStart: null,
|
|
96
95
|
activeHoursEnd: null,
|
|
97
96
|
maxConsecutiveRuns: null,
|
|
98
|
-
maxDailyRuns: null,
|
|
99
97
|
disposition: "Default disposition text.",
|
|
100
98
|
},
|
|
101
99
|
};
|
|
@@ -197,7 +195,6 @@ mock.module("../heartbeat-run-store.js", () => ({
|
|
|
197
195
|
markStaleRunsAsMissed: () => 0,
|
|
198
196
|
markStaleRunningAsError: () => 0,
|
|
199
197
|
countCompletedHeartbeatRuns: () => 10,
|
|
200
|
-
countCompletedRunsToday: () => 0,
|
|
201
198
|
countRecentConsecutiveRuns: () => 0,
|
|
202
199
|
}));
|
|
203
200
|
|
|
@@ -24,8 +24,7 @@ export type HeartbeatSkipReason =
|
|
|
24
24
|
| "outside_active_hours"
|
|
25
25
|
| "overlap"
|
|
26
26
|
| "pre_first_user_message"
|
|
27
|
-
| "max_consecutive_runs"
|
|
28
|
-
| "max_daily_runs";
|
|
27
|
+
| "max_consecutive_runs";
|
|
29
28
|
|
|
30
29
|
export interface HeartbeatRunRecord {
|
|
31
30
|
id: string;
|
|
@@ -218,27 +217,6 @@ export function countCompletedHeartbeatRuns(): number {
|
|
|
218
217
|
return row?.count ?? 0;
|
|
219
218
|
}
|
|
220
219
|
|
|
221
|
-
/**
|
|
222
|
-
* Count heartbeat runs that completed with status `ok` today (local midnight).
|
|
223
|
-
*/
|
|
224
|
-
export function countCompletedRunsToday(): number {
|
|
225
|
-
const db = getDb();
|
|
226
|
-
const now = new Date();
|
|
227
|
-
const startOfDay = new Date(
|
|
228
|
-
now.getFullYear(),
|
|
229
|
-
now.getMonth(),
|
|
230
|
-
now.getDate(),
|
|
231
|
-
).getTime();
|
|
232
|
-
const row = db
|
|
233
|
-
.select({ count: sql<number>`count(*)` })
|
|
234
|
-
.from(heartbeatRuns)
|
|
235
|
-
.where(
|
|
236
|
-
sql`${heartbeatRuns.status} = 'ok' AND ${heartbeatRuns.scheduledFor} >= ${startOfDay}`,
|
|
237
|
-
)
|
|
238
|
-
.get();
|
|
239
|
-
return row?.count ?? 0;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
220
|
/**
|
|
243
221
|
* Count the most recent consecutive heartbeat runs with status `ok`,
|
|
244
222
|
* walking backwards from newest. Stops at the first non-`ok` status
|