@gajae-code/coding-agent 0.14.2 → 0.15.0
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/CHANGELOG.md +120 -1
- package/dist/types/async/job-manager.d.ts +4 -1
- package/dist/types/autoresearch/dashboard.d.ts +29 -4
- package/dist/types/autoresearch/data-context.d.ts +25 -0
- package/dist/types/autoresearch/git.d.ts +65 -7
- package/dist/types/autoresearch/harness.d.ts +58 -0
- package/dist/types/autoresearch/prompts.d.ts +51 -0
- package/dist/types/autoresearch/runs.d.ts +173 -0
- package/dist/types/autoresearch/types.d.ts +9 -139
- package/dist/types/capability/types.d.ts +20 -0
- package/dist/types/cli/accounts-cli.d.ts +1 -0
- package/dist/types/commands/{rlm.d.ts → autoresearch.d.ts} +2 -4
- package/dist/types/config/autorouting-contract.d.ts +146 -0
- package/dist/types/config/autorouting-generator.d.ts +40 -0
- package/dist/types/config/autorouting-tier-map.d.ts +16844 -0
- package/dist/types/config/autorouting.d.ts +35 -0
- package/dist/types/config/model-discovery-manager.d.ts +8 -1
- package/dist/types/config/model-registry.d.ts +30 -1
- package/dist/types/config/provider-selection-policy.d.ts +23 -0
- package/dist/types/config/settings-schema.d.ts +61 -3
- package/dist/types/config/settings.d.ts +3 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/coordinator-mcp/durability.d.ts +29 -0
- package/dist/types/coordinator-mcp/event-webhook.d.ts +50 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +1 -1
- package/dist/types/coordinator-mcp/server.d.ts +14 -0
- package/dist/types/crash/index-store.d.ts +3 -0
- package/dist/types/crash/record-loader.d.ts +2 -0
- package/dist/types/crash/upstream/relay.d.ts +5 -3
- package/dist/types/cursor.d.ts +12 -0
- package/dist/types/defaults/gjc-defaults.d.ts +35 -1
- package/dist/types/defaults/gjc-skills.generated.d.ts +1 -1
- package/dist/types/discovery/helpers.d.ts +1 -1
- package/dist/types/edit/index.d.ts +2 -1
- package/dist/types/eval/py/executor.d.ts +2 -0
- package/dist/types/extensibility/extensions/loader.d.ts +32 -0
- package/dist/types/extensibility/gjc-plugins/types.d.ts +1 -1
- package/dist/types/extensibility/skills.d.ts +2 -0
- package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +194 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/psmux-detect.d.ts +1 -1
- package/dist/types/gjc-runtime/python-transcript.d.ts +19 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +2 -8
- package/dist/types/gjc-runtime/session-layout.d.ts +6 -3
- package/dist/types/gjc-runtime/state-renderer.d.ts +0 -22
- package/dist/types/gjc-runtime/state-schema.d.ts +7 -7
- package/dist/types/gjc-runtime/tmux-common.d.ts +2 -2
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +38 -1
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +2 -24
- package/dist/types/gjc-runtime/ultragoal-validation-policy.d.ts +73 -0
- package/dist/types/gjc-runtime/workflow-recovery-projection.d.ts +100 -0
- package/dist/types/hooks/skill-keywords.d.ts +1 -1
- package/dist/types/main.d.ts +0 -10
- package/dist/types/modes/acp/acp-agent.d.ts +13 -6
- package/dist/types/modes/components/model-selector.d.ts +14 -0
- package/dist/types/modes/components/skill-hud/render.d.ts +6 -1
- package/dist/types/modes/components/smart-routing-panel.d.ts +82 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +14 -0
- package/dist/types/modes/interactive-mode.d.ts +3 -0
- package/dist/types/modes/types.d.ts +9 -0
- package/dist/types/rlm/artifacts.d.ts +4 -4
- package/dist/types/runtime/optional-runtime-services.d.ts +2 -1
- package/dist/types/runtime/workspace-tree-service.d.ts +5 -1
- package/dist/types/runtime-mcp/config.d.ts +6 -0
- package/dist/types/runtime-mcp/manager.d.ts +10 -0
- package/dist/types/sdk/acp/adapter.d.ts +0 -4
- package/dist/types/sdk/broker/broker.d.ts +1 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +57 -2
- package/dist/types/sdk/broker/session-index.d.ts +15 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +6 -0
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/index.d.ts +8 -0
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -2
- package/dist/types/sdk/client/client.d.ts +39 -4
- package/dist/types/sdk/host/host.d.ts +1 -0
- package/dist/types/sdk/host/internal-autorouting-state.d.ts +3 -0
- package/dist/types/sdk/host/model-pin.d.ts +29 -0
- package/dist/types/sdk/host/session-runtime.d.ts +2 -1
- package/dist/types/sdk/lifecycle-session.d.ts +13 -0
- package/dist/types/sdk/router/session-router.d.ts +27 -1
- package/dist/types/sdk/session.d.ts +11 -1
- package/dist/types/session/agent-session.d.ts +36 -6
- package/dist/types/session/artifacts.d.ts +16 -1
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -0
- package/dist/types/session/session-manager.d.ts +84 -2
- package/dist/types/session/session-staging-paths.d.ts +3 -0
- package/dist/types/skill-state/canonical-skills.d.ts +1 -1
- package/dist/types/skill-state/workflow-hud.d.ts +12 -21
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +1 -0
- package/dist/types/slash-commands/helpers/autorouting-status.d.ts +8 -0
- package/dist/types/system-prompt.d.ts +23 -0
- package/dist/types/task/executor.d.ts +35 -4
- package/dist/types/task/index.d.ts +17 -3
- package/dist/types/task/receipt.d.ts +3 -1
- package/dist/types/task/types.d.ts +144 -0
- package/dist/types/tools/atomic-file-write.d.ts +72 -0
- package/dist/types/tools/descriptors.d.ts +1 -0
- package/dist/types/tools/index.d.ts +36 -1
- package/dist/types/tools/move-session.d.ts +40 -0
- package/dist/types/tools/python.d.ts +12 -0
- package/dist/types/tools/resource-gc.d.ts +0 -3
- package/dist/types/tools/search.d.ts +8 -1
- package/dist/types/tools/skill.d.ts +9 -4
- package/dist/types/tools/subagent.d.ts +33 -3
- package/dist/types/utils/xml-escape.d.ts +2 -0
- package/dist/types/workflow/workflow-intent-diff.d.ts +2 -2
- package/dist/types/workflow/workflow-intent-report-consumer.d.ts +1 -1
- package/package.json +11 -12
- package/scripts/build-sdk-package-smoke.ts +7 -5
- package/scripts/check-autorouting-tier-map.ts +183 -0
- package/scripts/generate-sdk-operation-inventory.ts +12 -0
- package/scripts/generate-tool-catalog.ts +40 -5
- package/src/async/job-manager.ts +5 -2
- package/src/autoresearch/dashboard.ts +134 -314
- package/src/autoresearch/data-context.ts +35 -0
- package/src/autoresearch/git.ts +186 -26
- package/src/autoresearch/{helpers.ts → harness.ts} +65 -40
- package/src/autoresearch/{prompt-setup.md → prompts/prompt-setup.md} +7 -7
- package/src/autoresearch/prompts/prompt.md +103 -0
- package/src/autoresearch/prompts.ts +126 -0
- package/src/autoresearch/runs.ts +708 -0
- package/src/autoresearch/types.ts +9 -150
- package/src/capability/index.ts +4 -4
- package/src/capability/types.ts +20 -0
- package/src/cli/accounts-cli.ts +21 -5
- package/src/cli/config-cli.ts +25 -1
- package/src/cli/fast-help.ts +1 -2
- package/src/cli/list-models.ts +5 -8
- package/src/cli/setup-cli.ts +8 -0
- package/src/cli.ts +2 -21
- package/src/commands/autoresearch.ts +33 -0
- package/src/commands/coordinator.ts +15 -0
- package/src/commands/launch.ts +2 -4
- package/src/commands/quick-lane.ts +1 -1
- package/src/commands/sdk.ts +24 -0
- package/src/commands/state.ts +1 -1
- package/src/config/autorouting-contract.ts +474 -0
- package/src/config/autorouting-generator.ts +238 -0
- package/src/config/autorouting-tier-map.ts +6108 -0
- package/src/config/autorouting.ts +120 -0
- package/src/config/model-discovery-manager.ts +42 -11
- package/src/config/model-registry.ts +348 -68
- package/src/config/provider-selection-policy.ts +60 -9
- package/src/config/settings-schema.ts +195 -6
- package/src/config/settings.ts +62 -1
- package/src/config.ts +2 -3
- package/src/coordinator/contract.ts +0 -1
- package/src/coordinator-mcp/codex-handoff.ts +68 -42
- package/src/coordinator-mcp/durability.ts +200 -0
- package/src/coordinator-mcp/event-webhook.ts +278 -0
- package/src/coordinator-mcp/question-state.ts +109 -46
- package/src/coordinator-mcp/server.ts +932 -504
- package/src/crash/index-store.ts +126 -22
- package/src/crash/record-loader.ts +7 -0
- package/src/crash/upstream/relay.ts +82 -34
- package/src/cursor.ts +84 -1
- package/src/debug/index.ts +26 -0
- package/src/defaults/gjc/skills/autoresearch/SKILL.md +116 -0
- package/src/defaults/gjc/skills/autoresearch/auto-critic.md +46 -0
- package/src/defaults/gjc/skills/autoresearch/auto-iterate.md +42 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +17 -37
- package/src/defaults/gjc/skills/ralplan/SKILL.md +21 -18
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +6 -17
- package/src/defaults/gjc/skills/ultragoal/ai-slop-cleaner.md +2 -2
- package/src/defaults/gjc-defaults.ts +89 -2
- package/src/defaults/gjc-skills.generated.ts +24 -17
- package/src/discovery/builtin.ts +18 -5
- package/src/discovery/helpers.ts +6 -6
- package/src/edit/index.ts +5 -2
- package/src/eval/py/executor.ts +8 -0
- package/src/extensibility/extensions/loader.ts +135 -13
- package/src/extensibility/extensions/wrapper.ts +1 -2
- package/src/extensibility/gjc-plugins/schema.ts +1 -1
- package/src/extensibility/runtime-skill-discovery.ts +2 -2
- package/src/extensibility/skill-management.ts +2 -3
- package/src/extensibility/skills.ts +16 -8
- package/src/gjc-runtime/autoresearch-runtime.ts +1509 -0
- package/src/gjc-runtime/gc-render.ts +0 -1
- package/src/gjc-runtime/gc-runtime.ts +1 -11
- package/src/gjc-runtime/launch-tmux.ts +3 -3
- package/src/gjc-runtime/psmux-detect.ts +2 -2
- package/src/gjc-runtime/python-transcript.ts +58 -0
- package/src/gjc-runtime/ralplan-runtime.ts +6 -18
- package/src/gjc-runtime/session-layout.ts +18 -7
- package/src/gjc-runtime/session-state-sidecar.ts +58 -9
- package/src/gjc-runtime/state-renderer.ts +0 -38
- package/src/gjc-runtime/state-runtime.ts +43 -22
- package/src/gjc-runtime/state-schema.ts +1 -1
- package/src/gjc-runtime/tmux-common.ts +7 -7
- package/src/gjc-runtime/ultragoal-change-set.ts +232 -11
- package/src/gjc-runtime/ultragoal-runtime.ts +309 -114
- package/src/gjc-runtime/ultragoal-validation-policy.ts +247 -0
- package/src/gjc-runtime/workflow-command-ref.ts +15 -11
- package/src/gjc-runtime/workflow-manifest.generated.json +413 -532
- package/src/gjc-runtime/workflow-manifest.ts +43 -83
- package/src/gjc-runtime/workflow-recovery-projection.ts +616 -0
- package/src/hooks/skill-keywords.ts +3 -3
- package/src/hooks/skill-state.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +26 -24
- package/src/lsp/index.ts +25 -5
- package/src/main.ts +2 -27
- package/src/modes/acp/acp-agent.ts +200 -75
- package/src/modes/components/model-selector.ts +216 -13
- package/src/modes/components/oauth-selector.ts +5 -5
- package/src/modes/components/skill-hud/render.ts +173 -35
- package/src/modes/components/smart-routing-panel.ts +531 -0
- package/src/modes/components/tool-status-header.ts +6 -3
- package/src/modes/controllers/command-controller.ts +17 -7
- package/src/modes/controllers/input-controller.ts +44 -9
- package/src/modes/controllers/runtime-mcp-command-controller.ts +4 -0
- package/src/modes/controllers/selector-controller.ts +298 -65
- package/src/modes/interactive-mode.ts +8 -1
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +1 -1
- package/src/modes/types.ts +9 -1
- package/src/prompts/agents/planner.md +1 -1
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/prompts/system/volatile-project-context.md +2 -1
- package/src/prompts/tools/move-session.md +15 -0
- package/src/prompts/tools/python.md +12 -0
- package/src/prompts/tools/skill-discovery.md +1 -1
- package/src/prompts/tools/skill.md +2 -2
- package/src/prompts/tools/task-summary.md +1 -0
- package/src/prompts/tools/task.md +6 -0
- package/src/rlm/artifacts.ts +12 -10
- package/src/runtime/optional-runtime-services.ts +3 -2
- package/src/runtime/workspace-tree-service.ts +11 -3
- package/src/runtime-mcp/config.ts +8 -1
- package/src/runtime-mcp/manager.ts +33 -0
- package/src/sdk/acp/adapter.ts +48 -1
- package/src/sdk/broker/broker.ts +30 -2
- package/src/sdk/broker/discovery.ts +217 -2
- package/src/sdk/broker/lifecycle.ts +385 -59
- package/src/sdk/broker/session-index.ts +243 -48
- package/src/sdk/broker/transport.ts +1 -0
- package/src/sdk/bus/chat-daemon-control.ts +8 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +5 -0
- package/src/sdk/bus/index.ts +208 -11
- package/src/sdk/bus/kind-aware-reconciliation.ts +16 -0
- package/src/sdk/bus/reconciliation-store.ts +27 -5
- package/src/sdk/bus/telegram-daemon-contract.ts +12 -2
- package/src/sdk/client/client.ts +204 -22
- package/src/sdk/host/host.ts +16 -0
- package/src/sdk/host/internal-autorouting-state.ts +13 -0
- package/src/sdk/host/model-pin.ts +101 -0
- package/src/sdk/host/reverse-leases.ts +2 -1
- package/src/sdk/host/session-runtime.test.ts +224 -1
- package/src/sdk/host/session-runtime.ts +125 -37
- package/src/sdk/lifecycle/service.ts +3 -1
- package/src/sdk/lifecycle-session.ts +42 -1
- package/src/sdk/protocol/operation-inventory.generated.json +66 -0
- package/src/sdk/router/session-router.ts +375 -36
- package/src/sdk/session.ts +547 -47
- package/src/session/account-inventory.ts +1 -1
- package/src/session/agent-session.ts +765 -189
- package/src/session/artifacts.ts +234 -4
- package/src/session/internal/managed-session-storage.ts +91 -4
- package/src/session/provider-safety-stop-hint.ts +3 -2
- package/src/session/session-manager.ts +775 -16
- package/src/session/session-staging-paths.ts +8 -0
- package/src/setup/hermes/templates/operator-instructions.v1.md +0 -1
- package/src/setup/host-plugin-setup.ts +2 -2
- package/src/skill-state/active-state.ts +2 -2
- package/src/skill-state/canonical-skills.ts +1 -1
- package/src/skill-state/initial-phase.ts +1 -1
- package/src/skill-state/workflow-hud.ts +41 -41
- package/src/skill-state/workflow-mutation-guard.ts +26 -7
- package/src/slash-commands/builtin-registry.ts +77 -0
- package/src/slash-commands/helpers/autorouting-status.ts +55 -0
- package/src/system-prompt.ts +102 -5
- package/src/task/discovery.ts +2 -3
- package/src/task/executor.ts +617 -43
- package/src/task/index.ts +262 -15
- package/src/task/receipt.ts +30 -0
- package/src/task/render.ts +11 -1
- package/src/task/types.ts +316 -0
- package/src/tools/atomic-file-write.ts +594 -0
- package/src/tools/bisect.ts +3 -2
- package/src/tools/descriptors.test.ts +3 -0
- package/src/tools/descriptors.ts +24 -0
- package/src/tools/image-gen.ts +5 -1
- package/src/tools/index.ts +62 -5
- package/src/tools/move-session.ts +107 -0
- package/src/tools/python.ts +205 -0
- package/src/tools/read.ts +88 -15
- package/src/tools/renderers.ts +2 -0
- package/src/tools/resource-gc.ts +8 -177
- package/src/tools/search.ts +30 -6
- package/src/tools/skill-discovery.ts +1 -0
- package/src/tools/skill.ts +37 -7
- package/src/tools/subagent-render.ts +119 -13
- package/src/tools/subagent.ts +91 -74
- package/src/tools/tool-catalog.generated.ts +64 -2
- package/src/tools/write.ts +16 -12
- package/src/utils/xml-escape.ts +14 -0
- package/src/web/search/providers/codex.ts +2 -2
- package/src/workflow/workflow-intent-diff.ts +13 -12
- package/src/workflow/workflow-intent-report-consumer.ts +6 -6
- package/dist/types/autoresearch/helpers.d.ts +0 -24
- package/dist/types/autoresearch/index.d.ts +0 -2
- package/dist/types/autoresearch/state.d.ts +0 -17
- package/dist/types/autoresearch/storage.d.ts +0 -142
- package/dist/types/autoresearch/tools/init-experiment.d.ts +0 -31
- package/dist/types/autoresearch/tools/log-experiment.d.ts +0 -23
- package/dist/types/autoresearch/tools/run-experiment.d.ts +0 -8
- package/dist/types/autoresearch/tools/update-notes.d.ts +0 -12
- package/dist/types/commands/team.d.ts +0 -24
- package/dist/types/gjc-runtime/team-gc.d.ts +0 -7
- package/dist/types/gjc-runtime/team-launch.d.ts +0 -61
- package/dist/types/gjc-runtime/team-notify.d.ts +0 -45
- package/dist/types/gjc-runtime/team-runtime.d.ts +0 -336
- package/dist/types/gjc-runtime/team-store.d.ts +0 -168
- package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +0 -43
- package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +0 -92
- package/dist/types/gjc-runtime/team-workers.d.ts +0 -83
- package/dist/types/rlm/index.d.ts +0 -47
- package/dist/types/rlm/preset.d.ts +0 -23
- package/dist/types/rlm/python-tool.d.ts +0 -16
- package/src/autoresearch/command-resume.md +0 -14
- package/src/autoresearch/index.ts +0 -536
- package/src/autoresearch/prompt.md +0 -103
- package/src/autoresearch/resume-message.md +0 -10
- package/src/autoresearch/state.ts +0 -273
- package/src/autoresearch/storage.ts +0 -699
- package/src/autoresearch/tools/init-experiment.ts +0 -272
- package/src/autoresearch/tools/log-experiment.ts +0 -524
- package/src/autoresearch/tools/run-experiment.ts +0 -475
- package/src/autoresearch/tools/update-notes.ts +0 -109
- package/src/commands/rlm.ts +0 -19
- package/src/commands/team.ts +0 -238
- package/src/defaults/gjc/skills/deep-interview/auto-research-greenfield.md +0 -42
- package/src/defaults/gjc/skills/team/SKILL.md +0 -467
- package/src/gjc-runtime/team-gc.ts +0 -49
- package/src/gjc-runtime/team-launch.ts +0 -404
- package/src/gjc-runtime/team-notify.ts +0 -326
- package/src/gjc-runtime/team-runtime.ts +0 -5923
- package/src/gjc-runtime/team-store.ts +0 -878
- package/src/gjc-runtime/team-worker-heartbeat.ts +0 -149
- package/src/gjc-runtime/team-worker-memory-guard.ts +0 -363
- package/src/gjc-runtime/team-workers.ts +0 -1123
- package/src/prompts/system/rlm-report-command.md +0 -1
- package/src/prompts/system/rlm-research.md +0 -23
- package/src/rlm/index.ts +0 -365
- package/src/rlm/preset.ts +0 -76
- package/src/rlm/python-tool.ts +0 -68
package/src/lsp/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { BunFile } from "bun";
|
|
|
6
6
|
import { type Theme, theme } from "../modes/theme/theme";
|
|
7
7
|
import lspDescription from "../prompts/tools/lsp.md" with { type: "text" };
|
|
8
8
|
import type { ToolSession } from "../tools";
|
|
9
|
+
import { FileWriteNotPublishedError, writeFileAtomically } from "../tools/atomic-file-write";
|
|
9
10
|
import { formatPathRelativeToCwd, resolveToCwd } from "../tools/path-utils";
|
|
10
11
|
import { ToolAbortError, ToolError, throwIfAborted } from "../tools/tool-errors";
|
|
11
12
|
import { clampTimeout } from "../tools/tool-timeouts";
|
|
@@ -745,11 +746,11 @@ export async function writethroughNoop(
|
|
|
745
746
|
_batch?: LspWritethroughBatchRequest,
|
|
746
747
|
_getDeferred?: (dst: string) => WritethroughDeferredHandle | undefined,
|
|
747
748
|
): Promise<FileDiagnosticsResult | undefined> {
|
|
748
|
-
if (file) {
|
|
749
|
+
if (file !== undefined) {
|
|
749
750
|
await file.write(content);
|
|
750
|
-
|
|
751
|
-
await Bun.write(dst, content);
|
|
751
|
+
return undefined;
|
|
752
752
|
}
|
|
753
|
+
await writeFileAtomically(dst, content);
|
|
753
754
|
return undefined;
|
|
754
755
|
}
|
|
755
756
|
|
|
@@ -921,7 +922,25 @@ async function runLspWritethrough(
|
|
|
921
922
|
const { lspServers, customLinterServers } = splitServers(servers);
|
|
922
923
|
|
|
923
924
|
let finalContent = content;
|
|
924
|
-
|
|
925
|
+
let publishedContent = false;
|
|
926
|
+
const writeContent = async (value: string) => {
|
|
927
|
+
try {
|
|
928
|
+
if (file !== undefined) await file.write(value);
|
|
929
|
+
else await writeFileAtomically(dst, value);
|
|
930
|
+
publishedContent = true;
|
|
931
|
+
} catch (error) {
|
|
932
|
+
if (error instanceof FileWriteNotPublishedError) {
|
|
933
|
+
if (publishedContent) {
|
|
934
|
+
throw new FileWriteNotPublishedError(dst, error.cause, {
|
|
935
|
+
destUnchanged: false,
|
|
936
|
+
publicationState: "published",
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
throw error;
|
|
940
|
+
}
|
|
941
|
+
throw error;
|
|
942
|
+
}
|
|
943
|
+
};
|
|
925
944
|
const getWritePromise = once(() => writeContent(finalContent));
|
|
926
945
|
const useCustomFormatter = enableFormat && customLinterServers.length > 0;
|
|
927
946
|
|
|
@@ -986,7 +1005,8 @@ async function runLspWritethrough(
|
|
|
986
1005
|
});
|
|
987
1006
|
}
|
|
988
1007
|
});
|
|
989
|
-
} catch {
|
|
1008
|
+
} catch (error) {
|
|
1009
|
+
if (error instanceof FileWriteNotPublishedError) throw error;
|
|
990
1010
|
if (timedOut) {
|
|
991
1011
|
formatter = undefined;
|
|
992
1012
|
diagnostics = undefined;
|
package/src/main.ts
CHANGED
|
@@ -173,6 +173,8 @@ const ACP_DEFAULTED_SETTING_PATHS: SettingPath[] = [
|
|
|
173
173
|
"task.maxRecursionDepth",
|
|
174
174
|
"task.disabledAgents",
|
|
175
175
|
"task.agentModelOverrides",
|
|
176
|
+
"task.autorouting.enabled",
|
|
177
|
+
"task.autorouting.tiers",
|
|
176
178
|
// Memory subsystems are off-by-default for embedded (ACP) hosts; embedders
|
|
177
179
|
// that want memory should opt in explicitly through their own settings layer.
|
|
178
180
|
"memory.backend",
|
|
@@ -1234,16 +1236,6 @@ async function buildSessionOptions(
|
|
|
1234
1236
|
return { options };
|
|
1235
1237
|
}
|
|
1236
1238
|
|
|
1237
|
-
/**
|
|
1238
|
-
* Research-mode (RLM) preset hook. Lets `gjc rlm` augment the session options
|
|
1239
|
-
* (system prompt, restricted toolset, custom python tool) and assert the tool
|
|
1240
|
-
* boundary once the session's tool registry is fully assembled.
|
|
1241
|
-
*/
|
|
1242
|
-
export interface RlmPreset {
|
|
1243
|
-
applyOptions: (options: CreateAgentSessionOptions, settings: Settings) => void;
|
|
1244
|
-
onSessionCreated?: (session: AgentSession) => void | Promise<void>;
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
1239
|
type RunPrintMode = (session: AgentSession, options: PrintModeOptions) => Promise<void>;
|
|
1248
1240
|
|
|
1249
1241
|
export interface RunRootCommandDependencies {
|
|
@@ -1252,7 +1244,6 @@ export interface RunRootCommandDependencies {
|
|
|
1252
1244
|
discoverAuthStorage?: typeof discoverAuthStorage;
|
|
1253
1245
|
runAcpMode?: (options?: { agentDir?: string }) => Promise<void>;
|
|
1254
1246
|
settings?: Settings;
|
|
1255
|
-
rlmPreset?: RlmPreset;
|
|
1256
1247
|
suppressProcessExit?: boolean;
|
|
1257
1248
|
startupUpdate?: { check: () => Promise<string | undefined> };
|
|
1258
1249
|
initTheme?: typeof initTheme;
|
|
@@ -1685,8 +1676,6 @@ export async function runRootCommand(
|
|
|
1685
1676
|
const deferMemoryBackendStartup = hasRootStartupProfile && !(parsedArgs.authBootstrap === true && isInteractive);
|
|
1686
1677
|
sessionOptions.deferMemoryBackendStartup = deferMemoryBackendStartup;
|
|
1687
1678
|
|
|
1688
|
-
// Research-mode (RLM) preset: augment session options before session creation.
|
|
1689
|
-
deps.rlmPreset?.applyOptions(sessionOptions, settingsInstance);
|
|
1690
1679
|
const acpStartupOptions = mode === "acp" ? resolveAcpStartupOptions(parsedArgs, sessionOptions) : undefined;
|
|
1691
1680
|
|
|
1692
1681
|
// Handle CLI credential selection and --api-key as runtime overrides (not persisted).
|
|
@@ -1822,20 +1811,6 @@ export async function runRootCommand(
|
|
|
1822
1811
|
// Herdr integration: report gjc lifecycle state when running in a Herdr pane.
|
|
1823
1812
|
installHerdrReporter(listener => session.subscribe(listener));
|
|
1824
1813
|
|
|
1825
|
-
// Research-mode (RLM) preset: hard tool-boundary assertion after the registry is assembled.
|
|
1826
|
-
if (deps.rlmPreset?.onSessionCreated) {
|
|
1827
|
-
try {
|
|
1828
|
-
await deps.rlmPreset.onSessionCreated(session);
|
|
1829
|
-
} catch (error) {
|
|
1830
|
-
try {
|
|
1831
|
-
await session.dispose();
|
|
1832
|
-
} catch {
|
|
1833
|
-
logger.warn("Failed to dispose session after RLM post-create error");
|
|
1834
|
-
}
|
|
1835
|
-
throw error;
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1839
1814
|
let startDeferredModelProfiles: DeferredModelProfileStartup | undefined;
|
|
1840
1815
|
if (!(parsedArgs.authBootstrap === true && isInteractive)) {
|
|
1841
1816
|
const profileArgs = {
|
|
@@ -165,6 +165,8 @@ type SessionRecord = {
|
|
|
165
165
|
/** Bounded set of correlations already settled; they stay closed for publication. */
|
|
166
166
|
settledPromptCorrelations: PromptCorrelation[];
|
|
167
167
|
authFailure?: string;
|
|
168
|
+
/** Replayable startup notice captured before ACP bootstrap; emitted once after the session id is known. */
|
|
169
|
+
routingInactiveNotice?: string;
|
|
168
170
|
activePrompt?: PromptWaiter;
|
|
169
171
|
/** Set by `session/cancel` so an in-flight prompt settles as `cancelled`, never as an error. */
|
|
170
172
|
cancelRequested?: boolean;
|
|
@@ -830,23 +832,43 @@ export async function collectActiveProviderIds(
|
|
|
830
832
|
const MAX_MODEL_CATALOG_PAGES = 100;
|
|
831
833
|
|
|
832
834
|
/**
|
|
833
|
-
*
|
|
834
|
-
*
|
|
835
|
-
*
|
|
836
|
-
*
|
|
837
|
-
* `{ result: { page: { items } } }` envelope `pageItems` consumes.
|
|
835
|
+
* Validate one `models.list/current` response and return its page. The SDK pages
|
|
836
|
+
* Q10 at a fixed byte target (256 KiB), which a fully configured catalog can
|
|
837
|
+
* exceed, so every page shape failure fails closed instead of silently dropping
|
|
838
|
+
* models the active-provider filter would need.
|
|
838
839
|
*/
|
|
839
|
-
|
|
840
|
+
interface ModelCatalogPage {
|
|
841
|
+
items: unknown[];
|
|
842
|
+
complete?: unknown;
|
|
843
|
+
continuationCursor?: unknown;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function requireCatalogPage(response: unknown): ModelCatalogPage {
|
|
847
|
+
const page = queryPage(response);
|
|
848
|
+
if (!page) throw new AcpSdkAdapterError("protocol_error", "models.list/current returned no page.");
|
|
849
|
+
if (!Array.isArray(page.items))
|
|
850
|
+
throw new AcpSdkAdapterError("protocol_error", "models.list/current returned a malformed page.");
|
|
851
|
+
return page as ModelCatalogPage;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
async function collectModelCatalogContinuation(
|
|
855
|
+
adapter: Pick<AcpSdkAdapter, "query">,
|
|
856
|
+
firstPage: ModelCatalogPage,
|
|
857
|
+
): Promise<unknown[]> {
|
|
858
|
+
if (firstPage.complete === true) return [];
|
|
859
|
+
if (typeof firstPage.continuationCursor !== "string")
|
|
860
|
+
throw new AcpSdkAdapterError(
|
|
861
|
+
"protocol_error",
|
|
862
|
+
"models.list/current page is incomplete without a continuation cursor.",
|
|
863
|
+
);
|
|
864
|
+
let cursor: string | undefined = firstPage.continuationCursor;
|
|
840
865
|
const items: unknown[] = [];
|
|
841
|
-
|
|
842
|
-
for (let pageCount =
|
|
866
|
+
// Page 1 was already consumed by the caller, so the remaining budget is one shorter.
|
|
867
|
+
for (let pageCount = 1; pageCount < MAX_MODEL_CATALOG_PAGES; pageCount++) {
|
|
843
868
|
const response = await adapter.query("models.list/current", {}, cursor);
|
|
844
|
-
const page =
|
|
845
|
-
if (!page) throw new AcpSdkAdapterError("protocol_error", "models.list/current returned no page.");
|
|
846
|
-
if (!Array.isArray(page.items))
|
|
847
|
-
throw new AcpSdkAdapterError("protocol_error", "models.list/current returned a malformed page.");
|
|
869
|
+
const page = requireCatalogPage(response);
|
|
848
870
|
items.push(...page.items);
|
|
849
|
-
if (page.complete === true) return
|
|
871
|
+
if (page.complete === true) return items;
|
|
850
872
|
if (typeof page.continuationCursor !== "string")
|
|
851
873
|
throw new AcpSdkAdapterError(
|
|
852
874
|
"protocol_error",
|
|
@@ -857,6 +879,32 @@ export async function collectModelCatalog(adapter: Pick<AcpSdkAdapter, "query">)
|
|
|
857
879
|
throw new AcpSdkAdapterError("protocol_error", "models.list/current exceeded the page budget.");
|
|
858
880
|
}
|
|
859
881
|
|
|
882
|
+
/**
|
|
883
|
+
* Collect the model catalog (Q10) and the active-provider set (Q29) under one
|
|
884
|
+
* credential ordering. Assembling the first Q10 page is what finalizes host-side
|
|
885
|
+
* credential state — expired or invalid OAuth credentials are refreshed or
|
|
886
|
+
* disabled while that snapshot is built, and continuation pages replay the
|
|
887
|
+
* frozen revision without further side effects — so Q29 must not start until
|
|
888
|
+
* page 1 has resolved. Starting both together would let Q29 snapshot pre-refresh
|
|
889
|
+
* credential state and mix catalog rows and provider availability from different
|
|
890
|
+
* credential states. After page 1, the provider walk overlaps the remaining
|
|
891
|
+
* catalog pages instead of adding its latency after them.
|
|
892
|
+
*/
|
|
893
|
+
export async function collectModelCatalogAndActiveProviders(
|
|
894
|
+
adapter: Pick<AcpSdkAdapter, "query">,
|
|
895
|
+
): Promise<{ modelCatalog: unknown; activeProviders: ReadonlySet<string> | undefined }> {
|
|
896
|
+
const firstResponse = await adapter.query("models.list/current");
|
|
897
|
+
const firstPage = requireCatalogPage(firstResponse);
|
|
898
|
+
const [remaining, activeProviders] = await Promise.all([
|
|
899
|
+
collectModelCatalogContinuation(adapter, firstPage),
|
|
900
|
+
collectActiveProviderIds(adapter),
|
|
901
|
+
]);
|
|
902
|
+
return {
|
|
903
|
+
modelCatalog: { result: { page: { items: [...firstPage.items, ...remaining] } } },
|
|
904
|
+
activeProviders,
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
|
|
860
908
|
const THINKING_CONFIG_OPTIONS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"].map(value => ({
|
|
861
909
|
value,
|
|
862
910
|
name: value,
|
|
@@ -1133,13 +1181,23 @@ export class AcpAgent implements Agent {
|
|
|
1133
1181
|
readonly #attaching = new Map<string, PendingAttachment>();
|
|
1134
1182
|
readonly #resolvingExisting = new Map<string, PendingAttachment>();
|
|
1135
1183
|
readonly #knownSessionCwds = new Map<string, string>();
|
|
1184
|
+
/**
|
|
1185
|
+
* Sessions this connection actually owns, i.e. ones it created or attached to.
|
|
1186
|
+
* Destructive lifecycle control gates on this set, never on `#knownSessionCwds`.
|
|
1187
|
+
*
|
|
1188
|
+
* `session/list` legitimately populates `#knownSessionCwds` for every session a
|
|
1189
|
+
* shared broker reports, so treating that map as ownership let a second ACP
|
|
1190
|
+
* connection enumerate another connection's sessions and then close or delete
|
|
1191
|
+
* them. Knowing a session's cwd is not authority over its lifecycle.
|
|
1192
|
+
*/
|
|
1193
|
+
readonly #ownedSessionIds = new Set<string>();
|
|
1136
1194
|
readonly #knownSessionMcpServers = new Map<string, SessionLifecycleMcpServer[]>();
|
|
1137
1195
|
readonly #knownSessionMetadata = new Map<string, { title?: string; updatedAt?: string }>();
|
|
1138
1196
|
readonly #pendingDeleteLocators = new Map<string, { cwd: string; path: string }>();
|
|
1139
1197
|
readonly #pendingCloseIdempotencyKeys = new Map<string, string>();
|
|
1140
1198
|
readonly #sessionEpochs = new Map<string, number>();
|
|
1141
1199
|
readonly #tearingDown = new Map<string, number>();
|
|
1142
|
-
readonly #
|
|
1200
|
+
readonly #lifecycleOperations = new Map<string, Promise<void>>();
|
|
1143
1201
|
#clientCapabilities: ClientCapabilities | undefined;
|
|
1144
1202
|
#broker: Promise<BrokerConnection> | undefined;
|
|
1145
1203
|
readonly #startupOptions: AcpStartupOptions | undefined;
|
|
@@ -1276,6 +1334,7 @@ export class AcpAgent implements Agent {
|
|
|
1276
1334
|
);
|
|
1277
1335
|
const id = sessionId(result);
|
|
1278
1336
|
this.#knownSessionCwds.set(id, params.cwd);
|
|
1337
|
+
this.#ownedSessionIds.add(id);
|
|
1279
1338
|
this.#knownSessionMcpServers.set(id, mcpServers);
|
|
1280
1339
|
try {
|
|
1281
1340
|
await this.#attach(id, params.cwd, undefined, result);
|
|
@@ -1331,6 +1390,7 @@ export class AcpAgent implements Agent {
|
|
|
1331
1390
|
);
|
|
1332
1391
|
const id = sessionId(result);
|
|
1333
1392
|
this.#knownSessionCwds.set(id, params.cwd);
|
|
1393
|
+
this.#ownedSessionIds.add(id);
|
|
1334
1394
|
this.#knownSessionMcpServers.set(id, mcpServers);
|
|
1335
1395
|
try {
|
|
1336
1396
|
await this.#attach(id, params.cwd, undefined, result);
|
|
@@ -1381,70 +1441,83 @@ export class AcpAgent implements Agent {
|
|
|
1381
1441
|
|
|
1382
1442
|
closeSession(params: CloseSessionRequest): Promise<CloseSessionResponse> {
|
|
1383
1443
|
const record = this.#sessions.get(params.sessionId);
|
|
1384
|
-
const cwd = record?.cwd ?? this.#knownSessionCwds.get(params.sessionId);
|
|
1385
1444
|
// ACP close has no cwd. Only connection-owned sessions may reach broker lifecycle control.
|
|
1445
|
+
if (!this.#ownedSessionIds.has(params.sessionId)) return Promise.resolve({});
|
|
1446
|
+
const cwd = record?.cwd ?? this.#knownSessionCwds.get(params.sessionId);
|
|
1386
1447
|
if (!cwd) return Promise.resolve({});
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
void this.#closeOwnedSession(params.sessionId).then(deferred.resolve, deferred.reject);
|
|
1392
|
-
const cleanup = deferred.promise.finally(() => {
|
|
1393
|
-
if (this.#closing.get(params.sessionId) === deferred.promise) this.#closing.delete(params.sessionId);
|
|
1448
|
+
return this.#enqueueLifecycleOperation(params.sessionId, async () => {
|
|
1449
|
+
// A preceding delete in the same lifecycle chain already completed the terminal operation.
|
|
1450
|
+
if (!this.#ownedSessionIds.has(params.sessionId) && !this.#sessions.has(params.sessionId)) return {};
|
|
1451
|
+
return this.#closeOwnedSession(params.sessionId);
|
|
1394
1452
|
});
|
|
1395
|
-
void cleanup.catch(() => undefined);
|
|
1396
|
-
return deferred.promise;
|
|
1397
1453
|
}
|
|
1398
1454
|
|
|
1399
1455
|
async deleteSession(params: DeleteSessionRequest): Promise<DeleteSessionResponse> {
|
|
1400
1456
|
const record = this.#sessions.get(params.sessionId);
|
|
1401
1457
|
const pendingLocator = this.#pendingDeleteLocators.get(params.sessionId);
|
|
1458
|
+
// Capture authority before joining the lifecycle chain: an admitted delete must
|
|
1459
|
+
// remain authorized when a preceding close retires connection ownership.
|
|
1460
|
+
if (!this.#ownedSessionIds.has(params.sessionId) && pendingLocator === undefined) return {};
|
|
1402
1461
|
const cwd = record?.cwd ?? this.#knownSessionCwds.get(params.sessionId) ?? pendingLocator?.cwd;
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1462
|
+
return this.#enqueueLifecycleOperation(params.sessionId, async () => {
|
|
1463
|
+
// ACP's delete request has no cwd. Unknown ids remain the protocol no-op,
|
|
1464
|
+
// while the broker can reconstruct an authenticated pending locator from its durable ledger.
|
|
1465
|
+
if (!cwd) {
|
|
1466
|
+
await (await this.#brokerAdapter()).global(
|
|
1467
|
+
"session.delete",
|
|
1468
|
+
{ sessionId: params.sessionId },
|
|
1469
|
+
this.#lifecycleIdempotencyKey(params.sessionId, "session.delete"),
|
|
1470
|
+
);
|
|
1471
|
+
return {};
|
|
1472
|
+
}
|
|
1473
|
+
this.#beginTeardown(params.sessionId);
|
|
1474
|
+
try {
|
|
1475
|
+
// A preceding close in the lifecycle chain already completed process teardown.
|
|
1476
|
+
// Continue with durable deletion instead of re-closing an already-dead process.
|
|
1477
|
+
const teardownCompleted =
|
|
1478
|
+
!this.#ownedSessionIds.has(params.sessionId) && !this.#sessions.has(params.sessionId);
|
|
1479
|
+
if (!teardownCompleted) {
|
|
1480
|
+
// A retained delete locator proves the prior attempt already completed
|
|
1481
|
+
// connection/process teardown and reached durable artifact cleanup. Re-closing
|
|
1482
|
+
// that terminal session can only replace the authoritative cleanup_pending
|
|
1483
|
+
// result with unrelated close uncertainty, so retries resume deletion directly.
|
|
1484
|
+
await this.#teardownSession(
|
|
1485
|
+
params.sessionId,
|
|
1486
|
+
"deleted",
|
|
1487
|
+
pendingLocator === undefined || record !== undefined,
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
let saved = pendingLocator?.cwd === cwd ? pendingLocator.path : undefined;
|
|
1491
|
+
if (!saved) {
|
|
1492
|
+
try {
|
|
1493
|
+
saved = await this.#resolveSavedSession(params.sessionId, cwd);
|
|
1494
|
+
} catch (error) {
|
|
1495
|
+
if (error instanceof AcpSdkAdapterError && error.code === "not_found") {
|
|
1496
|
+
this.#knownSessionCwds.delete(params.sessionId);
|
|
1497
|
+
this.#ownedSessionIds.delete(params.sessionId);
|
|
1498
|
+
this.#knownSessionMcpServers.delete(params.sessionId);
|
|
1499
|
+
this.#knownSessionMetadata.delete(params.sessionId);
|
|
1500
|
+
return {};
|
|
1501
|
+
}
|
|
1502
|
+
throw error;
|
|
1430
1503
|
}
|
|
1431
|
-
throw error;
|
|
1432
1504
|
}
|
|
1505
|
+
this.#pendingDeleteLocators.set(params.sessionId, { cwd, path: saved });
|
|
1506
|
+
await (await this.#brokerAdapter()).global(
|
|
1507
|
+
"session.delete",
|
|
1508
|
+
{ sessionId: params.sessionId, sessionPath: saved, cwd, target: { path: cwd } },
|
|
1509
|
+
this.#lifecycleIdempotencyKey(params.sessionId, "session.delete"),
|
|
1510
|
+
);
|
|
1511
|
+
this.#knownSessionCwds.delete(params.sessionId);
|
|
1512
|
+
this.#ownedSessionIds.delete(params.sessionId);
|
|
1513
|
+
this.#knownSessionMcpServers.delete(params.sessionId);
|
|
1514
|
+
this.#knownSessionMetadata.delete(params.sessionId);
|
|
1515
|
+
this.#pendingDeleteLocators.delete(params.sessionId);
|
|
1516
|
+
return {};
|
|
1517
|
+
} finally {
|
|
1518
|
+
this.#finishTeardown(params.sessionId);
|
|
1433
1519
|
}
|
|
1434
|
-
|
|
1435
|
-
await (await this.#brokerAdapter()).global(
|
|
1436
|
-
"session.delete",
|
|
1437
|
-
{ sessionId: params.sessionId, sessionPath: saved, cwd, target: { path: cwd } },
|
|
1438
|
-
this.#lifecycleIdempotencyKey(params.sessionId, "session.delete"),
|
|
1439
|
-
);
|
|
1440
|
-
this.#knownSessionCwds.delete(params.sessionId);
|
|
1441
|
-
this.#knownSessionMcpServers.delete(params.sessionId);
|
|
1442
|
-
this.#knownSessionMetadata.delete(params.sessionId);
|
|
1443
|
-
this.#pendingDeleteLocators.delete(params.sessionId);
|
|
1444
|
-
return {};
|
|
1445
|
-
} finally {
|
|
1446
|
-
this.#finishTeardown(params.sessionId);
|
|
1447
|
-
}
|
|
1520
|
+
});
|
|
1448
1521
|
}
|
|
1449
1522
|
|
|
1450
1523
|
async setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse> {
|
|
@@ -1911,6 +1984,20 @@ export class AcpAgent implements Agent {
|
|
|
1911
1984
|
else this.#tearingDown.delete(id);
|
|
1912
1985
|
}
|
|
1913
1986
|
|
|
1987
|
+
#enqueueLifecycleOperation<T>(id: string, operation: () => Promise<T>): Promise<T> {
|
|
1988
|
+
const previous = this.#lifecycleOperations.get(id) ?? Promise.resolve();
|
|
1989
|
+
const result = previous.catch(() => undefined).then(operation);
|
|
1990
|
+
const settled = result.then(
|
|
1991
|
+
() => undefined,
|
|
1992
|
+
() => undefined,
|
|
1993
|
+
);
|
|
1994
|
+
this.#lifecycleOperations.set(id, settled);
|
|
1995
|
+
void settled.finally(() => {
|
|
1996
|
+
if (this.#lifecycleOperations.get(id) === settled) this.#lifecycleOperations.delete(id);
|
|
1997
|
+
});
|
|
1998
|
+
return result;
|
|
1999
|
+
}
|
|
2000
|
+
|
|
1914
2001
|
#lifecycleIdempotencyKey(id: string, operation: "session.close" | "session.delete"): string {
|
|
1915
2002
|
return `acp:${operation}:${id}`;
|
|
1916
2003
|
}
|
|
@@ -2135,6 +2222,7 @@ export class AcpAgent implements Agent {
|
|
|
2135
2222
|
this.#pendingRouterAdapters.delete(id);
|
|
2136
2223
|
this.#pendingRouterFrames.delete(id);
|
|
2137
2224
|
this.#knownSessionCwds.set(id, cwd);
|
|
2225
|
+
this.#ownedSessionIds.add(id);
|
|
2138
2226
|
await applyAcpPermissionMode(adapter, this.#clientCapabilities);
|
|
2139
2227
|
this.#assertSessionEpoch(id, epoch);
|
|
2140
2228
|
// A successful attachment establishes a new live-owner epoch. Any locator
|
|
@@ -2151,6 +2239,7 @@ export class AcpAgent implements Agent {
|
|
|
2151
2239
|
await this.#teardownSession(id, "attachment failed", false);
|
|
2152
2240
|
} finally {
|
|
2153
2241
|
this.#knownSessionCwds.delete(id);
|
|
2242
|
+
this.#ownedSessionIds.delete(id);
|
|
2154
2243
|
this.#knownSessionMcpServers.delete(id);
|
|
2155
2244
|
}
|
|
2156
2245
|
} else if (adapter) {
|
|
@@ -2216,6 +2305,7 @@ export class AcpAgent implements Agent {
|
|
|
2216
2305
|
async #discardNewSession(id: string): Promise<void> {
|
|
2217
2306
|
await this.#teardownSession(id, "discarded", true);
|
|
2218
2307
|
this.#knownSessionCwds.delete(id);
|
|
2308
|
+
this.#ownedSessionIds.delete(id);
|
|
2219
2309
|
this.#knownSessionMcpServers.delete(id);
|
|
2220
2310
|
this.#knownSessionMetadata.delete(id);
|
|
2221
2311
|
}
|
|
@@ -2229,6 +2319,7 @@ export class AcpAgent implements Agent {
|
|
|
2229
2319
|
if (attaching) await Promise.allSettled([attaching.task]);
|
|
2230
2320
|
await this.#teardownSession(id, "closed", true);
|
|
2231
2321
|
this.#knownSessionCwds.delete(id);
|
|
2322
|
+
this.#ownedSessionIds.delete(id);
|
|
2232
2323
|
this.#knownSessionMcpServers.delete(id);
|
|
2233
2324
|
this.#knownSessionMetadata.delete(id);
|
|
2234
2325
|
return {};
|
|
@@ -2244,7 +2335,7 @@ export class AcpAgent implements Agent {
|
|
|
2244
2335
|
*/
|
|
2245
2336
|
async #teardownSession(id: string, reason: string, closeRemote: boolean): Promise<void> {
|
|
2246
2337
|
const record = this.#sessions.get(id);
|
|
2247
|
-
const ownershipBound = record !== undefined || this.#
|
|
2338
|
+
const ownershipBound = record !== undefined || this.#ownedSessionIds.has(id);
|
|
2248
2339
|
this.#beginTeardown(id);
|
|
2249
2340
|
try {
|
|
2250
2341
|
this.#advanceSessionEpoch(id);
|
|
@@ -2537,6 +2628,10 @@ export class AcpAgent implements Agent {
|
|
|
2537
2628
|
if (!received) return;
|
|
2538
2629
|
const { event, wirePayload } = received;
|
|
2539
2630
|
const isTerminal = event.type === "agent_end" || event.type === "agent_failed";
|
|
2631
|
+
if (event.type === "notice" && event.source === "autorouting" && typeof event.message === "string") {
|
|
2632
|
+
record.routingInactiveNotice = event.message;
|
|
2633
|
+
return;
|
|
2634
|
+
}
|
|
2540
2635
|
const derivedCorrelation = sdkFrameCorrelation(frame, event);
|
|
2541
2636
|
const correlation = derivedCorrelation ?? {};
|
|
2542
2637
|
const activePrompt = record.activePrompt;
|
|
@@ -2848,15 +2943,26 @@ export class AcpAgent implements Agent {
|
|
|
2848
2943
|
const record = this.#sessions.get(id);
|
|
2849
2944
|
if (!record) throw new AcpSdkAdapterError("not_found", `Unknown session, not found: ${id}`);
|
|
2850
2945
|
const modelPreset = this.#startupOptions?.modelPreset;
|
|
2851
|
-
const [config,
|
|
2946
|
+
const [config, sessionCatalog] = await Promise.all([
|
|
2852
2947
|
record.adapter.query("config.list/get"),
|
|
2853
|
-
modelPreset === undefined
|
|
2948
|
+
modelPreset === undefined
|
|
2949
|
+
? collectModelCatalogAndActiveProviders(record.adapter)
|
|
2950
|
+
: record.adapter
|
|
2951
|
+
.query("models.profiles.list")
|
|
2952
|
+
.then((profiles): { modelCatalog: unknown; activeProviders: undefined } => ({
|
|
2953
|
+
modelCatalog: profiles,
|
|
2954
|
+
activeProviders: undefined,
|
|
2955
|
+
})),
|
|
2854
2956
|
]);
|
|
2855
|
-
//
|
|
2856
|
-
//
|
|
2857
|
-
//
|
|
2858
|
-
//
|
|
2859
|
-
|
|
2957
|
+
// The active-provider walk overlaps the catalog inside the batch above, but
|
|
2958
|
+
// only after the first models.list/current page has finalized host-side
|
|
2959
|
+
// credential state, so catalog rows and provider availability never mix
|
|
2960
|
+
// pre- and post-refresh credential snapshots. Only an older session host
|
|
2961
|
+
// that rejects `providers.list/active` with `operation_not_session_owned`
|
|
2962
|
+
// falls back to the full catalog; operational failures fail closed so the
|
|
2963
|
+
// active-provider contract is not silently widened.
|
|
2964
|
+
const modelCatalog = sessionCatalog.modelCatalog;
|
|
2965
|
+
const activeProviders = sessionCatalog.activeProviders;
|
|
2860
2966
|
record.authFailure = undefined;
|
|
2861
2967
|
if (modelPreset !== undefined) {
|
|
2862
2968
|
const activePreset = configValues(config).get(MODEL_PRESET_CONFIG_KEY);
|
|
@@ -3341,6 +3447,24 @@ export class AcpAgent implements Agent {
|
|
|
3341
3447
|
record.adapter,
|
|
3342
3448
|
);
|
|
3343
3449
|
}
|
|
3450
|
+
// Not consumed on publish: this mirrors authFailure's lifecycle, where a
|
|
3451
|
+
// later load/resume legitimately re-announces the condition. Clearing here
|
|
3452
|
+
// would also lose the warning outright if the publish below rejected, since
|
|
3453
|
+
// the enclosing bootstrap task swallows failures.
|
|
3454
|
+
if (record.routingInactiveNotice) {
|
|
3455
|
+
const message = record.routingInactiveNotice;
|
|
3456
|
+
await this.#publishSessionUpdate(
|
|
3457
|
+
id,
|
|
3458
|
+
{
|
|
3459
|
+
sessionId: id,
|
|
3460
|
+
update: {
|
|
3461
|
+
sessionUpdate: "agent_thought_chunk",
|
|
3462
|
+
content: { type: "text", text: `[warning:autorouting] ${message}\n` },
|
|
3463
|
+
},
|
|
3464
|
+
},
|
|
3465
|
+
record.adapter,
|
|
3466
|
+
);
|
|
3467
|
+
}
|
|
3344
3468
|
await this.#publishSessionUpdate(
|
|
3345
3469
|
id,
|
|
3346
3470
|
{
|
|
@@ -3507,11 +3631,12 @@ export class AcpAgent implements Agent {
|
|
|
3507
3631
|
this.#attaching.clear();
|
|
3508
3632
|
this.#resolvingExisting.clear();
|
|
3509
3633
|
this.#knownSessionCwds.clear();
|
|
3634
|
+
this.#ownedSessionIds.clear();
|
|
3510
3635
|
this.#knownSessionMcpServers.clear();
|
|
3511
3636
|
this.#knownSessionMetadata.clear();
|
|
3512
3637
|
this.#pendingDeleteLocators.clear();
|
|
3513
3638
|
this.#pendingCloseIdempotencyKeys.clear();
|
|
3514
|
-
if (this.#
|
|
3639
|
+
if (this.#lifecycleOperations.size === 0) this.#lifecycleOperations.clear();
|
|
3515
3640
|
this.#tearingDown.clear();
|
|
3516
3641
|
if (this.#broker) {
|
|
3517
3642
|
const broker = this.#broker;
|