@openma/common 0.0.0-stage → 0.9.1
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/LICENSE +202 -0
- package/README.md +391 -2
- package/dist/acp-artifacts/binary.d.ts +35 -0
- package/dist/acp-artifacts/binary.d.ts.map +1 -0
- package/dist/acp-artifacts/binary.js +120 -0
- package/dist/acp-artifacts/binary.js.map +1 -0
- package/dist/acp-artifacts/index.d.ts +7 -0
- package/dist/acp-artifacts/index.d.ts.map +1 -0
- package/dist/acp-artifacts/index.js +7 -0
- package/dist/acp-artifacts/index.js.map +1 -0
- package/dist/acp-artifacts/node-abi.d.ts +3 -0
- package/dist/acp-artifacts/node-abi.d.ts.map +1 -0
- package/dist/acp-artifacts/node-abi.js +17 -0
- package/dist/acp-artifacts/node-abi.js.map +1 -0
- package/dist/acp-artifacts/npm-cli.d.ts +3 -0
- package/dist/acp-artifacts/npm-cli.d.ts.map +1 -0
- package/dist/acp-artifacts/npm-cli.js +9 -0
- package/dist/acp-artifacts/npm-cli.js.map +1 -0
- package/dist/acp-artifacts/npm.d.ts +37 -0
- package/dist/acp-artifacts/npm.d.ts.map +1 -0
- package/dist/acp-artifacts/npm.js +167 -0
- package/dist/acp-artifacts/npm.js.map +1 -0
- package/dist/acp-artifacts/registry.d.ts +45 -0
- package/dist/acp-artifacts/registry.d.ts.map +1 -0
- package/dist/acp-artifacts/registry.js +206 -0
- package/dist/acp-artifacts/registry.js.map +1 -0
- package/dist/acp-artifacts/shared.d.ts +45 -0
- package/dist/acp-artifacts/shared.d.ts.map +1 -0
- package/dist/acp-artifacts/shared.js +157 -0
- package/dist/acp-artifacts/shared.js.map +1 -0
- package/dist/acp-artifacts/uvx.d.ts +32 -0
- package/dist/acp-artifacts/uvx.d.ts.map +1 -0
- package/dist/acp-artifacts/uvx.js +95 -0
- package/dist/acp-artifacts/uvx.js.map +1 -0
- package/dist/acp-fork/index.d.ts +51 -0
- package/dist/acp-fork/index.d.ts.map +1 -0
- package/dist/acp-fork/index.js +116 -0
- package/dist/acp-fork/index.js.map +1 -0
- package/dist/acp-harnesses/agent-setup.d.ts +118 -0
- package/dist/acp-harnesses/agent-setup.d.ts.map +1 -0
- package/dist/acp-harnesses/agent-setup.js +717 -0
- package/dist/acp-harnesses/agent-setup.js.map +1 -0
- package/dist/acp-harnesses/custom-agents.d.ts +81 -0
- package/dist/acp-harnesses/custom-agents.d.ts.map +1 -0
- package/dist/acp-harnesses/custom-agents.js +361 -0
- package/dist/acp-harnesses/custom-agents.js.map +1 -0
- package/dist/acp-harnesses/headless-launch.d.ts +34 -0
- package/dist/acp-harnesses/headless-launch.d.ts.map +1 -0
- package/dist/acp-harnesses/headless-launch.js +67 -0
- package/dist/acp-harnesses/headless-launch.js.map +1 -0
- package/dist/acp-harnesses/index.d.ts +18 -0
- package/dist/acp-harnesses/index.d.ts.map +1 -0
- package/dist/acp-harnesses/index.js +58 -0
- package/dist/acp-harnesses/index.js.map +1 -0
- package/dist/acp-harnesses/install-state.d.ts +86 -0
- package/dist/acp-harnesses/install-state.d.ts.map +1 -0
- package/dist/acp-harnesses/install-state.js +322 -0
- package/dist/acp-harnesses/install-state.js.map +1 -0
- package/dist/acp-harnesses/installer.d.ts +145 -0
- package/dist/acp-harnesses/installer.d.ts.map +1 -0
- package/dist/acp-harnesses/installer.js +716 -0
- package/dist/acp-harnesses/installer.js.map +1 -0
- package/dist/acp-harnesses/known-agents.d.ts +154 -0
- package/dist/acp-harnesses/known-agents.d.ts.map +1 -0
- package/dist/acp-harnesses/known-agents.js +240 -0
- package/dist/acp-harnesses/known-agents.js.map +1 -0
- package/dist/acp-harnesses/launcher.d.ts +27 -0
- package/dist/acp-harnesses/launcher.d.ts.map +1 -0
- package/dist/acp-harnesses/launcher.js +64 -0
- package/dist/acp-harnesses/launcher.js.map +1 -0
- package/dist/acp-harnesses/registry-fetch.d.ts +42 -0
- package/dist/acp-harnesses/registry-fetch.d.ts.map +1 -0
- package/dist/acp-harnesses/registry-fetch.js +132 -0
- package/dist/acp-harnesses/registry-fetch.js.map +1 -0
- package/dist/acp-harnesses/registry.d.ts +36 -0
- package/dist/acp-harnesses/registry.d.ts.map +1 -0
- package/dist/acp-harnesses/registry.js +307 -0
- package/dist/acp-harnesses/registry.js.map +1 -0
- package/dist/acp-runtime/errors.d.ts +7 -0
- package/dist/acp-runtime/errors.d.ts.map +1 -0
- package/dist/acp-runtime/errors.js +17 -0
- package/dist/acp-runtime/errors.js.map +1 -0
- package/dist/acp-runtime/fork-support.d.ts +8 -0
- package/dist/acp-runtime/fork-support.d.ts.map +1 -0
- package/dist/acp-runtime/fork-support.js +20 -0
- package/dist/acp-runtime/fork-support.js.map +1 -0
- package/dist/acp-runtime/index.d.ts +11 -0
- package/dist/acp-runtime/index.d.ts.map +1 -0
- package/dist/acp-runtime/index.js +6 -0
- package/dist/acp-runtime/index.js.map +1 -0
- package/dist/acp-runtime/probe.d.ts +103 -0
- package/dist/acp-runtime/probe.d.ts.map +1 -0
- package/dist/acp-runtime/probe.js +881 -0
- package/dist/acp-runtime/probe.js.map +1 -0
- package/dist/acp-runtime/runtime.d.ts +7 -0
- package/dist/acp-runtime/runtime.d.ts.map +1 -0
- package/dist/acp-runtime/runtime.js +26 -0
- package/dist/acp-runtime/runtime.js.map +1 -0
- package/dist/acp-runtime/session.d.ts +87 -0
- package/dist/acp-runtime/session.d.ts.map +1 -0
- package/dist/acp-runtime/session.js +1071 -0
- package/dist/acp-runtime/session.js.map +1 -0
- package/dist/acp-runtime/spawners/node.d.ts +5 -0
- package/dist/acp-runtime/spawners/node.d.ts.map +1 -0
- package/dist/acp-runtime/spawners/node.js +244 -0
- package/dist/acp-runtime/spawners/node.js.map +1 -0
- package/dist/acp-runtime/types.d.ts +180 -0
- package/dist/acp-runtime/types.d.ts.map +1 -0
- package/dist/acp-runtime/types.js +2 -0
- package/dist/acp-runtime/types.js.map +1 -0
- package/dist/agent-contract/acp.d.ts +4 -0
- package/dist/agent-contract/acp.d.ts.map +1 -0
- package/dist/agent-contract/acp.js +273 -0
- package/dist/agent-contract/acp.js.map +1 -0
- package/dist/agent-contract/index.d.ts +125 -0
- package/dist/agent-contract/index.d.ts.map +1 -0
- package/dist/agent-contract/index.js +102 -0
- package/dist/agent-contract/index.js.map +1 -0
- package/dist/agent-contract/managed.d.ts +5 -0
- package/dist/agent-contract/managed.d.ts.map +1 -0
- package/dist/agent-contract/managed.js +242 -0
- package/dist/agent-contract/managed.js.map +1 -0
- package/dist/agent-ui/index.d.ts +170 -0
- package/dist/agent-ui/index.d.ts.map +1 -0
- package/dist/agent-ui/index.js +853 -0
- package/dist/agent-ui/index.js.map +1 -0
- package/dist/agent-ui/presentation.d.ts +30 -0
- package/dist/agent-ui/presentation.d.ts.map +1 -0
- package/dist/agent-ui/presentation.js +79 -0
- package/dist/agent-ui/presentation.js.map +1 -0
- package/dist/agent-ui/react.d.ts +50 -0
- package/dist/agent-ui/react.d.ts.map +1 -0
- package/dist/agent-ui/react.js +334 -0
- package/dist/agent-ui/react.js.map +1 -0
- package/dist/brand/index.d.ts +17 -0
- package/dist/brand/index.d.ts.map +1 -0
- package/dist/brand/index.js +119 -0
- package/dist/brand/index.js.map +1 -0
- package/dist/brand/openma-logo-mark.svg +7 -0
- package/dist/brand/tokens.css +77 -0
- package/dist/brand/website.css +67 -0
- package/dist/chat-ui/acp.d.ts +26 -0
- package/dist/chat-ui/acp.d.ts.map +1 -0
- package/dist/chat-ui/acp.js +166 -0
- package/dist/chat-ui/acp.js.map +1 -0
- package/dist/chat-ui/components.d.ts +230 -0
- package/dist/chat-ui/components.d.ts.map +1 -0
- package/dist/chat-ui/components.js +561 -0
- package/dist/chat-ui/components.js.map +1 -0
- package/dist/chat-ui/composer-drafts.d.ts +21 -0
- package/dist/chat-ui/composer-drafts.d.ts.map +1 -0
- package/dist/chat-ui/composer-drafts.js +58 -0
- package/dist/chat-ui/composer-drafts.js.map +1 -0
- package/dist/chat-ui/controller.d.ts +61 -0
- package/dist/chat-ui/controller.d.ts.map +1 -0
- package/dist/chat-ui/controller.js +218 -0
- package/dist/chat-ui/controller.js.map +1 -0
- package/dist/chat-ui/index.d.ts +8 -0
- package/dist/chat-ui/index.d.ts.map +1 -0
- package/dist/chat-ui/index.js +8 -0
- package/dist/chat-ui/index.js.map +1 -0
- package/dist/chat-ui/markdown.d.ts +37 -0
- package/dist/chat-ui/markdown.d.ts.map +1 -0
- package/dist/chat-ui/markdown.js +33 -0
- package/dist/chat-ui/markdown.js.map +1 -0
- package/dist/chat-ui/presentation.d.ts +34 -0
- package/dist/chat-ui/presentation.d.ts.map +1 -0
- package/dist/chat-ui/presentation.js +191 -0
- package/dist/chat-ui/presentation.js.map +1 -0
- package/dist/chat-ui/styles.css +815 -0
- package/dist/chat-ui/utils.d.ts +14 -0
- package/dist/chat-ui/utils.d.ts.map +1 -0
- package/dist/chat-ui/utils.js +71 -0
- package/dist/chat-ui/utils.js.map +1 -0
- package/dist/local-runtime/checkpoint.d.ts +28 -0
- package/dist/local-runtime/checkpoint.d.ts.map +1 -0
- package/dist/local-runtime/checkpoint.js +2 -0
- package/dist/local-runtime/checkpoint.js.map +1 -0
- package/dist/local-runtime/daemon-connection.d.ts +27 -0
- package/dist/local-runtime/daemon-connection.d.ts.map +1 -0
- package/dist/local-runtime/daemon-connection.js +161 -0
- package/dist/local-runtime/daemon-connection.js.map +1 -0
- package/dist/local-runtime/daemon-host.d.ts +39 -0
- package/dist/local-runtime/daemon-host.d.ts.map +1 -0
- package/dist/local-runtime/daemon-host.js +88 -0
- package/dist/local-runtime/daemon-host.js.map +1 -0
- package/dist/local-runtime/index.d.ts +6 -0
- package/dist/local-runtime/index.d.ts.map +1 -0
- package/dist/local-runtime/index.js +5 -0
- package/dist/local-runtime/index.js.map +1 -0
- package/dist/local-runtime/runtime.d.ts +36 -0
- package/dist/local-runtime/runtime.d.ts.map +1 -0
- package/dist/local-runtime/runtime.js +82 -0
- package/dist/local-runtime/runtime.js.map +1 -0
- package/dist/local-runtime/session-host.d.ts +62 -0
- package/dist/local-runtime/session-host.d.ts.map +1 -0
- package/dist/local-runtime/session-host.js +477 -0
- package/dist/local-runtime/session-host.js.map +1 -0
- package/dist/managed-runtime/acp-subagents.d.ts +14 -0
- package/dist/managed-runtime/acp-subagents.d.ts.map +1 -0
- package/dist/managed-runtime/acp-subagents.js +67 -0
- package/dist/managed-runtime/acp-subagents.js.map +1 -0
- package/dist/managed-runtime/claimed-environment-work.d.ts +61 -0
- package/dist/managed-runtime/claimed-environment-work.d.ts.map +1 -0
- package/dist/managed-runtime/claimed-environment-work.js +170 -0
- package/dist/managed-runtime/claimed-environment-work.js.map +1 -0
- package/dist/managed-runtime/contracts.d.ts +31 -0
- package/dist/managed-runtime/contracts.d.ts.map +1 -0
- package/dist/managed-runtime/contracts.js +2 -0
- package/dist/managed-runtime/contracts.js.map +1 -0
- package/dist/managed-runtime/http-control.d.ts +67 -0
- package/dist/managed-runtime/http-control.d.ts.map +1 -0
- package/dist/managed-runtime/http-control.js +465 -0
- package/dist/managed-runtime/http-control.js.map +1 -0
- package/dist/managed-runtime/index.d.ts +89 -0
- package/dist/managed-runtime/index.d.ts.map +1 -0
- package/dist/managed-runtime/index.js +215 -0
- package/dist/managed-runtime/index.js.map +1 -0
- package/dist/managed-runtime/input-identity.d.ts +2 -0
- package/dist/managed-runtime/input-identity.d.ts.map +1 -0
- package/dist/managed-runtime/input-identity.js +2 -0
- package/dist/managed-runtime/input-identity.js.map +1 -0
- package/dist/managed-runtime/managed-event-projector.d.ts +24 -0
- package/dist/managed-runtime/managed-event-projector.d.ts.map +1 -0
- package/dist/managed-runtime/managed-event-projector.js +333 -0
- package/dist/managed-runtime/managed-event-projector.js.map +1 -0
- package/dist/managed-runtime/semantic-recovery.d.ts +61 -0
- package/dist/managed-runtime/semantic-recovery.d.ts.map +1 -0
- package/dist/managed-runtime/semantic-recovery.js +167 -0
- package/dist/managed-runtime/semantic-recovery.js.map +1 -0
- package/dist/project-ui/CreateProjectDialog.d.ts +15 -0
- package/dist/project-ui/CreateProjectDialog.d.ts.map +1 -0
- package/dist/project-ui/CreateProjectDialog.js +87 -0
- package/dist/project-ui/CreateProjectDialog.js.map +1 -0
- package/dist/project-ui/ProjectComposer.d.ts +13 -0
- package/dist/project-ui/ProjectComposer.d.ts.map +1 -0
- package/dist/project-ui/ProjectComposer.js +70 -0
- package/dist/project-ui/ProjectComposer.js.map +1 -0
- package/dist/project-ui/ProjectConversation.d.ts +10 -0
- package/dist/project-ui/ProjectConversation.d.ts.map +1 -0
- package/dist/project-ui/ProjectConversation.js +28 -0
- package/dist/project-ui/ProjectConversation.js.map +1 -0
- package/dist/project-ui/ProjectMessageAttachments.d.ts +4 -0
- package/dist/project-ui/ProjectMessageAttachments.d.ts.map +1 -0
- package/dist/project-ui/ProjectMessageAttachments.js +28 -0
- package/dist/project-ui/ProjectMessageAttachments.js.map +1 -0
- package/dist/project-ui/ProjectSettings.d.ts +8 -0
- package/dist/project-ui/ProjectSettings.d.ts.map +1 -0
- package/dist/project-ui/ProjectSettings.js +65 -0
- package/dist/project-ui/ProjectSettings.js.map +1 -0
- package/dist/project-ui/Projects.d.ts +18 -0
- package/dist/project-ui/Projects.d.ts.map +1 -0
- package/dist/project-ui/Projects.js +377 -0
- package/dist/project-ui/Projects.js.map +1 -0
- package/dist/project-ui/client.d.ts +234 -0
- package/dist/project-ui/client.d.ts.map +1 -0
- package/dist/project-ui/client.js +42 -0
- package/dist/project-ui/client.js.map +1 -0
- package/dist/project-ui/controls.d.ts +15 -0
- package/dist/project-ui/controls.d.ts.map +1 -0
- package/dist/project-ui/controls.js +17 -0
- package/dist/project-ui/controls.js.map +1 -0
- package/dist/project-ui/index.d.ts +20 -0
- package/dist/project-ui/index.d.ts.map +1 -0
- package/dist/project-ui/index.js +17 -0
- package/dist/project-ui/index.js.map +1 -0
- package/dist/project-ui/project-coordinator.d.ts +3 -0
- package/dist/project-ui/project-coordinator.d.ts.map +1 -0
- package/dist/project-ui/project-coordinator.js +12 -0
- package/dist/project-ui/project-coordinator.js.map +1 -0
- package/dist/project-ui/project-goals.d.ts +48 -0
- package/dist/project-ui/project-goals.d.ts.map +1 -0
- package/dist/project-ui/project-goals.js +169 -0
- package/dist/project-ui/project-goals.js.map +1 -0
- package/dist/project-ui/projects-query.d.ts +19 -0
- package/dist/project-ui/projects-query.d.ts.map +1 -0
- package/dist/project-ui/projects-query.js +132 -0
- package/dist/project-ui/projects-query.js.map +1 -0
- package/dist/project-ui/styles.css +847 -0
- package/dist/protocol/acp/index.d.ts +52 -0
- package/dist/protocol/acp/index.d.ts.map +1 -0
- package/dist/protocol/acp/index.js +1056 -0
- package/dist/protocol/acp/index.js.map +1 -0
- package/dist/protocol/cursor-cloud/index.d.ts +74 -0
- package/dist/protocol/cursor-cloud/index.d.ts.map +1 -0
- package/dist/protocol/cursor-cloud/index.js +249 -0
- package/dist/protocol/cursor-cloud/index.js.map +1 -0
- package/dist/protocol/managed/index.d.ts +32 -0
- package/dist/protocol/managed/index.d.ts.map +1 -0
- package/dist/protocol/managed/index.js +646 -0
- package/dist/protocol/managed/index.js.map +1 -0
- package/dist/protocol/managed/input-identity.d.ts +3 -0
- package/dist/protocol/managed/input-identity.d.ts.map +1 -0
- package/dist/protocol/managed/input-identity.js +6 -0
- package/dist/protocol/managed/input-identity.js.map +1 -0
- package/dist/protocol/openai-agents/index.d.ts +102 -0
- package/dist/protocol/openai-agents/index.d.ts.map +1 -0
- package/dist/protocol/openai-agents/index.js +142 -0
- package/dist/protocol/openai-agents/index.js.map +1 -0
- package/dist/session-events/acp-system-notices.d.ts +10 -0
- package/dist/session-events/acp-system-notices.d.ts.map +1 -0
- package/dist/session-events/acp-system-notices.js +46 -0
- package/dist/session-events/acp-system-notices.js.map +1 -0
- package/dist/session-events/acp.d.ts +214 -0
- package/dist/session-events/acp.d.ts.map +1 -0
- package/dist/session-events/acp.js +956 -0
- package/dist/session-events/acp.js.map +1 -0
- package/dist/session-events/managed.d.ts +141 -0
- package/dist/session-events/managed.d.ts.map +1 -0
- package/dist/session-events/managed.js +324 -0
- package/dist/session-events/managed.js.map +1 -0
- package/dist/session-events/openma.d.ts +304 -0
- package/dist/session-events/openma.d.ts.map +1 -0
- package/dist/session-events/openma.js +438 -0
- package/dist/session-events/openma.js.map +1 -0
- package/dist/session-kernel/index.d.ts +118 -0
- package/dist/session-kernel/index.d.ts.map +1 -0
- package/dist/session-kernel/index.js +215 -0
- package/dist/session-kernel/index.js.map +1 -0
- package/dist/session-orchestrator/index.d.ts +71 -0
- package/dist/session-orchestrator/index.d.ts.map +1 -0
- package/dist/session-orchestrator/index.js +177 -0
- package/dist/session-orchestrator/index.js.map +1 -0
- package/dist/session-ui/index.d.ts +96 -0
- package/dist/session-ui/index.d.ts.map +1 -0
- package/dist/session-ui/index.js +277 -0
- package/dist/session-ui/index.js.map +1 -0
- package/package.json +222 -4
|
@@ -0,0 +1,1071 @@
|
|
|
1
|
+
import { ClientSideConnection, RequestError, ndJsonStream, } from "@agentclientprotocol/sdk";
|
|
2
|
+
import { preserveAcpNotificationContext } from "../session-events/acp.js";
|
|
3
|
+
import { isAuthenticationRequiredError } from "./errors.js";
|
|
4
|
+
import { acpForkRequestMeta, forkSupport as forkSupportOf, } from "./fork-support.js";
|
|
5
|
+
export { acpForkRequestMeta } from "./fork-support.js";
|
|
6
|
+
const LEGACY_MODEL_META_KEY = "openma.dev/legacy-model-state";
|
|
7
|
+
export class AcpSessionImpl {
|
|
8
|
+
id;
|
|
9
|
+
options;
|
|
10
|
+
#child;
|
|
11
|
+
#stdout;
|
|
12
|
+
#childExit = null;
|
|
13
|
+
#agent;
|
|
14
|
+
#legacyModels = null;
|
|
15
|
+
#disposePromise;
|
|
16
|
+
#sessionId;
|
|
17
|
+
#disposed = false;
|
|
18
|
+
#acceptOutOfBandUpdates = false;
|
|
19
|
+
#activePromptCount = 0;
|
|
20
|
+
#pendingEvents = [];
|
|
21
|
+
#waiters = [];
|
|
22
|
+
#authMethods = [];
|
|
23
|
+
#protocolVersion = null;
|
|
24
|
+
#agentInfo = null;
|
|
25
|
+
#agentCapabilities = {};
|
|
26
|
+
#initializeMeta = null;
|
|
27
|
+
#sessionSetupMeta = null;
|
|
28
|
+
#configOptions = [];
|
|
29
|
+
#modes = null;
|
|
30
|
+
#promptCapabilities = {};
|
|
31
|
+
#supportsSessionFork = false;
|
|
32
|
+
#supportsSessionList = false;
|
|
33
|
+
#supportsSessionDelete = false;
|
|
34
|
+
#supportsSessionResume = false;
|
|
35
|
+
#supportsSessionClose = false;
|
|
36
|
+
#supportsAdditionalDirectories = false;
|
|
37
|
+
#supportsLogout = false;
|
|
38
|
+
#supportsProviders = false;
|
|
39
|
+
#supportsNes = false;
|
|
40
|
+
#nesCapabilities = null;
|
|
41
|
+
#positionEncoding = null;
|
|
42
|
+
#supportsSteering = false;
|
|
43
|
+
#nextClientRequestId = 1;
|
|
44
|
+
#outstandingUrlElicitations = new Set();
|
|
45
|
+
constructor(deps) {
|
|
46
|
+
this.id = deps.id;
|
|
47
|
+
this.options = deps.options;
|
|
48
|
+
this.#child = deps.child;
|
|
49
|
+
this.#stdout = observeLegacyModels(deps.child.stdout, (models) => {
|
|
50
|
+
if (this.#legacyModels === null)
|
|
51
|
+
this.#legacyModels = models;
|
|
52
|
+
});
|
|
53
|
+
void deps.child.exited.then((result) => {
|
|
54
|
+
this.#childExit = result;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
get acpSessionId() {
|
|
58
|
+
return this.#sessionId ?? "";
|
|
59
|
+
}
|
|
60
|
+
get authMethods() {
|
|
61
|
+
return this.#authMethods;
|
|
62
|
+
}
|
|
63
|
+
get protocolVersion() {
|
|
64
|
+
return this.#protocolVersion;
|
|
65
|
+
}
|
|
66
|
+
get agentInfo() {
|
|
67
|
+
return this.#agentInfo;
|
|
68
|
+
}
|
|
69
|
+
get agentCapabilities() {
|
|
70
|
+
return this.#agentCapabilities;
|
|
71
|
+
}
|
|
72
|
+
get initializeMeta() {
|
|
73
|
+
return this.#initializeMeta;
|
|
74
|
+
}
|
|
75
|
+
get sessionSetupMeta() {
|
|
76
|
+
return this.#sessionSetupMeta;
|
|
77
|
+
}
|
|
78
|
+
get configOptions() {
|
|
79
|
+
return this.#configOptions;
|
|
80
|
+
}
|
|
81
|
+
get legacyModels() {
|
|
82
|
+
return this.#legacyModels;
|
|
83
|
+
}
|
|
84
|
+
get modes() {
|
|
85
|
+
return this.#modes;
|
|
86
|
+
}
|
|
87
|
+
get promptCapabilities() {
|
|
88
|
+
return this.#promptCapabilities;
|
|
89
|
+
}
|
|
90
|
+
get supportsSessionFork() {
|
|
91
|
+
return this.#supportsSessionFork;
|
|
92
|
+
}
|
|
93
|
+
get forkSupport() {
|
|
94
|
+
return forkSupportOf(this);
|
|
95
|
+
}
|
|
96
|
+
get supportsSessionList() {
|
|
97
|
+
return this.#supportsSessionList;
|
|
98
|
+
}
|
|
99
|
+
get supportsSessionDelete() {
|
|
100
|
+
return this.#supportsSessionDelete;
|
|
101
|
+
}
|
|
102
|
+
get supportsSessionResume() {
|
|
103
|
+
return this.#supportsSessionResume;
|
|
104
|
+
}
|
|
105
|
+
get supportsSessionClose() {
|
|
106
|
+
return this.#supportsSessionClose;
|
|
107
|
+
}
|
|
108
|
+
get supportsAdditionalDirectories() {
|
|
109
|
+
return this.#supportsAdditionalDirectories;
|
|
110
|
+
}
|
|
111
|
+
get supportsLogout() {
|
|
112
|
+
return this.#supportsLogout;
|
|
113
|
+
}
|
|
114
|
+
get supportsProviders() {
|
|
115
|
+
return this.#supportsProviders;
|
|
116
|
+
}
|
|
117
|
+
get supportsNes() {
|
|
118
|
+
return this.#supportsNes;
|
|
119
|
+
}
|
|
120
|
+
get nesCapabilities() {
|
|
121
|
+
return this.#nesCapabilities;
|
|
122
|
+
}
|
|
123
|
+
get positionEncoding() {
|
|
124
|
+
return this.#positionEncoding;
|
|
125
|
+
}
|
|
126
|
+
get supportsSteering() {
|
|
127
|
+
return this.#supportsSteering;
|
|
128
|
+
}
|
|
129
|
+
async init() {
|
|
130
|
+
const initStartedAt = Date.now();
|
|
131
|
+
const callbacks = this.options.clientCallbacks ?? {};
|
|
132
|
+
const requestedElicitationCapabilities = this.options.clientElicitationCapabilities
|
|
133
|
+
?? (callbacks.createElicitation
|
|
134
|
+
? {
|
|
135
|
+
form: {},
|
|
136
|
+
...(callbacks.completeElicitation ? { url: {} } : {}),
|
|
137
|
+
}
|
|
138
|
+
: undefined);
|
|
139
|
+
const elicitationCapabilities = callbacks.createElicitation
|
|
140
|
+
&& requestedElicitationCapabilities
|
|
141
|
+
&& (requestedElicitationCapabilities.form != null
|
|
142
|
+
|| requestedElicitationCapabilities.url != null)
|
|
143
|
+
? requestedElicitationCapabilities
|
|
144
|
+
: undefined;
|
|
145
|
+
const connection = new ClientSideConnection(() => this.#createClient(callbacks, elicitationCapabilities?.url != null), ndJsonStream(this.#child.stdin, this.#stdout));
|
|
146
|
+
this.#agent = connection;
|
|
147
|
+
if (this.options.forkPoint && !this.options.forkFromAcpSessionId) {
|
|
148
|
+
throw new Error("forkPoint can only be used together with forkFromAcpSessionId");
|
|
149
|
+
}
|
|
150
|
+
const clientCapabilities = {
|
|
151
|
+
// The existing OpenMA controls render both boolean config options and
|
|
152
|
+
// structured/markdown plans. Advertising these capabilities prevents
|
|
153
|
+
// agents such as codex-acp from degrading them to plain transcript
|
|
154
|
+
// text even though the canonical event and GUI projections exist.
|
|
155
|
+
session: {
|
|
156
|
+
configOptions: {
|
|
157
|
+
boolean: {},
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
plan: {},
|
|
161
|
+
// Claude Agent ACP uses this ACP-reserved extension capability to
|
|
162
|
+
// forward nested subagent text, thinking, and tool updates. It is
|
|
163
|
+
// harmless for agents that do not implement the extension: ACP
|
|
164
|
+
// clients and agents must treat unknown `_meta` keys as optional.
|
|
165
|
+
_meta: {
|
|
166
|
+
"subagent-transcript": true,
|
|
167
|
+
// claude-agent-acp and codex-acp use this negotiated extension to
|
|
168
|
+
// send terminal snapshots instead of forcing clients to reconstruct
|
|
169
|
+
// them from provider-specific delta notifications.
|
|
170
|
+
terminal_output: true,
|
|
171
|
+
},
|
|
172
|
+
fs: {
|
|
173
|
+
readTextFile: Boolean(callbacks.readTextFile),
|
|
174
|
+
writeTextFile: Boolean(callbacks.writeTextFile),
|
|
175
|
+
},
|
|
176
|
+
terminal: Boolean(callbacks.createTerminal),
|
|
177
|
+
...(elicitationCapabilities
|
|
178
|
+
? { elicitation: elicitationCapabilities }
|
|
179
|
+
: {}),
|
|
180
|
+
...(this.options.clientNesCapabilities
|
|
181
|
+
? { nes: this.options.clientNesCapabilities }
|
|
182
|
+
: {}),
|
|
183
|
+
...(this.options.positionEncodings?.length
|
|
184
|
+
? { positionEncodings: this.options.positionEncodings }
|
|
185
|
+
: {}),
|
|
186
|
+
};
|
|
187
|
+
const overlay = this.options.clientCapabilityOverlay;
|
|
188
|
+
const initialized = await this.#agent.initialize({
|
|
189
|
+
protocolVersion: 1,
|
|
190
|
+
clientCapabilities: overlay
|
|
191
|
+
? mergeClientCapabilities(clientCapabilities, overlay)
|
|
192
|
+
: clientCapabilities,
|
|
193
|
+
});
|
|
194
|
+
const initializedAt = Date.now();
|
|
195
|
+
this.#authMethods = initialized.authMethods ?? [];
|
|
196
|
+
this.#protocolVersion = initialized.protocolVersion;
|
|
197
|
+
this.#agentInfo = initialized.agentInfo ?? null;
|
|
198
|
+
this.#agentCapabilities = initialized.agentCapabilities ?? {};
|
|
199
|
+
this.#initializeMeta = initialized._meta ?? null;
|
|
200
|
+
this.#promptCapabilities = this.#agentCapabilities.promptCapabilities ?? {};
|
|
201
|
+
this.#supportsSessionFork =
|
|
202
|
+
initialized.agentCapabilities?.sessionCapabilities?.fork != null;
|
|
203
|
+
this.#supportsSessionList =
|
|
204
|
+
initialized.agentCapabilities?.sessionCapabilities?.list != null;
|
|
205
|
+
this.#supportsSessionDelete =
|
|
206
|
+
initialized.agentCapabilities?.sessionCapabilities?.delete != null;
|
|
207
|
+
this.#supportsSessionResume =
|
|
208
|
+
initialized.agentCapabilities?.sessionCapabilities?.resume != null;
|
|
209
|
+
this.#supportsSessionClose =
|
|
210
|
+
initialized.agentCapabilities?.sessionCapabilities?.close != null;
|
|
211
|
+
this.#supportsAdditionalDirectories =
|
|
212
|
+
initialized.agentCapabilities?.sessionCapabilities?.additionalDirectories != null;
|
|
213
|
+
this.#supportsLogout = initialized.agentCapabilities?.auth?.logout != null;
|
|
214
|
+
this.#supportsProviders = initialized.agentCapabilities?.providers != null;
|
|
215
|
+
this.#nesCapabilities = initialized.agentCapabilities?.nes ?? null;
|
|
216
|
+
this.#supportsNes = this.#nesCapabilities != null;
|
|
217
|
+
this.#positionEncoding = initialized.agentCapabilities?.positionEncoding ?? null;
|
|
218
|
+
this.#supportsSteering =
|
|
219
|
+
initialized._meta
|
|
220
|
+
?.steering?.supported === true;
|
|
221
|
+
const cwd = this.options.agent.cwd ?? process.cwd();
|
|
222
|
+
const mcpCapabilities = this.#agentCapabilities.mcpCapabilities;
|
|
223
|
+
const mcpServers = (this.options.mcpServers ?? []).filter((server) => {
|
|
224
|
+
const transport = server.type;
|
|
225
|
+
if (transport === "http")
|
|
226
|
+
return mcpCapabilities?.http === true;
|
|
227
|
+
if (transport === "sse")
|
|
228
|
+
return mcpCapabilities?.sse === true;
|
|
229
|
+
return true;
|
|
230
|
+
});
|
|
231
|
+
const requestedAdditionalDirectories = this.options.additionalDirectories ?? [];
|
|
232
|
+
if (requestedAdditionalDirectories.length > 0 &&
|
|
233
|
+
!this.#supportsAdditionalDirectories) {
|
|
234
|
+
throw new Error("ACP agent does not support additional workspace directories");
|
|
235
|
+
}
|
|
236
|
+
const additionalDirectories = requestedAdditionalDirectories;
|
|
237
|
+
const requestMeta = this.options.sessionRequestMeta;
|
|
238
|
+
if (this.options.forkFromAcpSessionId) {
|
|
239
|
+
const support = forkSupportOf(initialized);
|
|
240
|
+
const wantsMessageFork = this.options.forkPoint != null
|
|
241
|
+
|| sessionRequestDeclaresAirFork(requestMeta);
|
|
242
|
+
if (wantsMessageFork && support.level !== "message") {
|
|
243
|
+
throw new Error(`ACP agent does not support message-level fork (${support.reason}): ${support.message}`);
|
|
244
|
+
}
|
|
245
|
+
if (!this.#supportsSessionFork || !this.#agent.unstable_forkSession) {
|
|
246
|
+
throw new Error("ACP agent does not support unstable session/fork");
|
|
247
|
+
}
|
|
248
|
+
const forkRequestMeta = this.options.forkPoint
|
|
249
|
+
? mergeSessionRequestMeta(requestMeta, acpForkRequestMeta(this.options.forkPoint))
|
|
250
|
+
: requestMeta;
|
|
251
|
+
const forked = await this.#agent.unstable_forkSession({
|
|
252
|
+
sessionId: this.options.forkFromAcpSessionId,
|
|
253
|
+
cwd,
|
|
254
|
+
mcpServers,
|
|
255
|
+
...(additionalDirectories.length > 0 ? { additionalDirectories } : {}),
|
|
256
|
+
...(forkRequestMeta ? { _meta: forkRequestMeta } : {}),
|
|
257
|
+
});
|
|
258
|
+
this.#sessionId = forked.sessionId;
|
|
259
|
+
this.#configOptions = forked.configOptions ?? [];
|
|
260
|
+
this.#modes = forked.modes ?? null;
|
|
261
|
+
this.#sessionSetupMeta = forked._meta ?? null;
|
|
262
|
+
this.#acceptOutOfBandUpdates = true;
|
|
263
|
+
this.#logInit("fork", initStartedAt, initializedAt);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (this.options.resumeAcpSessionId &&
|
|
267
|
+
this.#supportsSessionResume &&
|
|
268
|
+
this.#agent.resumeSession) {
|
|
269
|
+
try {
|
|
270
|
+
const resumed = await this.#withAuthenticationRetry(() => this.#agent.resumeSession({
|
|
271
|
+
sessionId: this.options.resumeAcpSessionId,
|
|
272
|
+
cwd,
|
|
273
|
+
mcpServers,
|
|
274
|
+
...(additionalDirectories.length > 0 ? { additionalDirectories } : {}),
|
|
275
|
+
...(requestMeta ? { _meta: requestMeta } : {}),
|
|
276
|
+
}));
|
|
277
|
+
this.#sessionId = this.options.resumeAcpSessionId;
|
|
278
|
+
this.#configOptions = resumed.configOptions ?? [];
|
|
279
|
+
this.#modes = resumed.modes ?? null;
|
|
280
|
+
this.#sessionSetupMeta = resumed._meta ?? null;
|
|
281
|
+
this.#acceptOutOfBandUpdates = true;
|
|
282
|
+
this.#logInit("resume", initStartedAt, initializedAt);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
console.error(`[acp] session/resume(${this.options.resumeAcpSessionId}) failed, falling back to load/new:`, error);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (this.options.resumeAcpSessionId &&
|
|
290
|
+
initialized.agentCapabilities?.loadSession === true &&
|
|
291
|
+
this.#agent.loadSession) {
|
|
292
|
+
try {
|
|
293
|
+
const loaded = await this.#withAuthenticationRetry(() => this.#agent.loadSession({
|
|
294
|
+
sessionId: this.options.resumeAcpSessionId,
|
|
295
|
+
cwd,
|
|
296
|
+
mcpServers,
|
|
297
|
+
...(additionalDirectories.length > 0 ? { additionalDirectories } : {}),
|
|
298
|
+
...(requestMeta ? { _meta: requestMeta } : {}),
|
|
299
|
+
}));
|
|
300
|
+
this.#sessionId = this.options.resumeAcpSessionId;
|
|
301
|
+
this.#configOptions = loaded?.configOptions ?? [];
|
|
302
|
+
this.#modes = loaded?.modes ?? null;
|
|
303
|
+
this.#sessionSetupMeta = loaded?._meta ?? null;
|
|
304
|
+
this.#acceptOutOfBandUpdates = true;
|
|
305
|
+
this.#logInit("load", initStartedAt, initializedAt);
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
console.error(`[acp] session/load(${this.options.resumeAcpSessionId}) failed, falling back to new:`, error);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const created = await this.#withAuthenticationRetry(() => this.#agent.newSession({
|
|
313
|
+
cwd,
|
|
314
|
+
mcpServers,
|
|
315
|
+
...(additionalDirectories.length > 0 ? { additionalDirectories } : {}),
|
|
316
|
+
...(requestMeta ? { _meta: requestMeta } : {}),
|
|
317
|
+
}));
|
|
318
|
+
this.#sessionId = created.sessionId;
|
|
319
|
+
this.#configOptions = created.configOptions ?? [];
|
|
320
|
+
this.#modes = created.modes ?? null;
|
|
321
|
+
this.#sessionSetupMeta = created._meta ?? null;
|
|
322
|
+
this.#acceptOutOfBandUpdates = true;
|
|
323
|
+
this.#logInit("new", initStartedAt, initializedAt);
|
|
324
|
+
}
|
|
325
|
+
#createClient(callbacks, supportsUrlElicitation) {
|
|
326
|
+
return {
|
|
327
|
+
sessionUpdate: async (params) => {
|
|
328
|
+
const update = preserveAcpNotificationContext(params);
|
|
329
|
+
this.#receiveInboundEvent(update, isIdleSessionUpdate(update));
|
|
330
|
+
},
|
|
331
|
+
requestPermission: async (params) => {
|
|
332
|
+
return this.#runClientRequest("session/request_permission", params, async () => {
|
|
333
|
+
if (!callbacks.requestPermission) {
|
|
334
|
+
return { outcome: { outcome: "cancelled" } };
|
|
335
|
+
}
|
|
336
|
+
try {
|
|
337
|
+
return await callbacks.requestPermission(params);
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
this.#pushEvent({ type: "requestPermissionError", error: String(error) });
|
|
341
|
+
return { outcome: { outcome: "cancelled" } };
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
},
|
|
345
|
+
readTextFile: callbacks.readTextFile
|
|
346
|
+
? async (params) => this.#runClientRequest("fs/read_text_file", params, () => callbacks.readTextFile(params))
|
|
347
|
+
: undefined,
|
|
348
|
+
writeTextFile: callbacks.writeTextFile
|
|
349
|
+
? async (params) => this.#runClientRequest("fs/write_text_file", params, () => callbacks.writeTextFile(params))
|
|
350
|
+
: undefined,
|
|
351
|
+
createTerminal: callbacks.createTerminal
|
|
352
|
+
? async (params) => this.#runClientRequest("terminal/create", params, () => callbacks.createTerminal(params))
|
|
353
|
+
: undefined,
|
|
354
|
+
terminalOutput: callbacks.terminalOutput
|
|
355
|
+
? async (params) => this.#runClientRequest("terminal/output", params, () => callbacks.terminalOutput(params))
|
|
356
|
+
: undefined,
|
|
357
|
+
releaseTerminal: callbacks.releaseTerminal
|
|
358
|
+
? async (params) => this.#runClientRequest("terminal/release", params, () => callbacks.releaseTerminal(params))
|
|
359
|
+
: undefined,
|
|
360
|
+
waitForTerminalExit: callbacks.waitForTerminalExit
|
|
361
|
+
? async (params) => this.#runClientRequest("terminal/wait_for_exit", params, () => callbacks.waitForTerminalExit(params))
|
|
362
|
+
: undefined,
|
|
363
|
+
killTerminal: callbacks.killTerminal
|
|
364
|
+
? async (params) => this.#runClientRequest("terminal/kill", params, () => callbacks.killTerminal(params))
|
|
365
|
+
: undefined,
|
|
366
|
+
unstable_createElicitation: callbacks.createElicitation
|
|
367
|
+
? async (params) => {
|
|
368
|
+
const response = await this.#runClientRequest("elicitation/create", params, () => callbacks.createElicitation(params));
|
|
369
|
+
if (params.mode === "url"
|
|
370
|
+
&& response.action === "accept"
|
|
371
|
+
&& typeof params.elicitationId === "string") {
|
|
372
|
+
this.#outstandingUrlElicitations.add(params.elicitationId);
|
|
373
|
+
}
|
|
374
|
+
return response;
|
|
375
|
+
}
|
|
376
|
+
: undefined,
|
|
377
|
+
unstable_completeElicitation: supportsUrlElicitation
|
|
378
|
+
? async (params) => {
|
|
379
|
+
if (!this.#outstandingUrlElicitations.delete(params.elicitationId))
|
|
380
|
+
return;
|
|
381
|
+
this.#receiveClientNotification("elicitation/complete", params);
|
|
382
|
+
await callbacks.completeElicitation?.(params);
|
|
383
|
+
this.#receiveInboundEvent({
|
|
384
|
+
type: "acp.elicitation_complete",
|
|
385
|
+
method: "elicitation/complete",
|
|
386
|
+
params,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
: undefined,
|
|
390
|
+
extMethod: async (method, params) => this.#runClientRequest(method, params, async () => {
|
|
391
|
+
if (method === "mcp/connect" && callbacks.connectMcp) {
|
|
392
|
+
return callbacks.connectMcp(params);
|
|
393
|
+
}
|
|
394
|
+
if (method === "mcp/message" && callbacks.messageMcp) {
|
|
395
|
+
return await callbacks.messageMcp(params);
|
|
396
|
+
}
|
|
397
|
+
if (method === "mcp/disconnect" && callbacks.disconnectMcp) {
|
|
398
|
+
return (await callbacks.disconnectMcp(params)) ?? {};
|
|
399
|
+
}
|
|
400
|
+
this.#receiveInboundEvent({
|
|
401
|
+
type: "acp.extension_request",
|
|
402
|
+
method,
|
|
403
|
+
params,
|
|
404
|
+
});
|
|
405
|
+
if (callbacks.extensionRequest) {
|
|
406
|
+
return callbacks.extensionRequest(method, params);
|
|
407
|
+
}
|
|
408
|
+
throw RequestError.methodNotFound(method);
|
|
409
|
+
}),
|
|
410
|
+
extNotification: async (method, params) => {
|
|
411
|
+
this.#receiveClientNotification(method, params);
|
|
412
|
+
try {
|
|
413
|
+
if (method === "mcp/message" && callbacks.notifyMcp) {
|
|
414
|
+
await callbacks.notifyMcp(params);
|
|
415
|
+
this.#receiveInboundEvent({
|
|
416
|
+
type: "acp.mcp_notification",
|
|
417
|
+
method,
|
|
418
|
+
params,
|
|
419
|
+
});
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
await callbacks.extensionNotification?.(method, params);
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
console.error("[acp] extension notification callback failed:", error);
|
|
426
|
+
}
|
|
427
|
+
this.#receiveInboundEvent({
|
|
428
|
+
type: "acp.extension_notification",
|
|
429
|
+
method,
|
|
430
|
+
params,
|
|
431
|
+
});
|
|
432
|
+
},
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
async #runClientRequest(method, params, invoke) {
|
|
436
|
+
const requestId = `client-request-${this.#nextClientRequestId++}`;
|
|
437
|
+
this.#receiveInboundEvent({
|
|
438
|
+
type: "acp.client_request",
|
|
439
|
+
requestId,
|
|
440
|
+
method,
|
|
441
|
+
params,
|
|
442
|
+
});
|
|
443
|
+
try {
|
|
444
|
+
const result = await invoke();
|
|
445
|
+
this.#receiveInboundEvent({
|
|
446
|
+
type: "acp.client_response",
|
|
447
|
+
requestId,
|
|
448
|
+
method,
|
|
449
|
+
result,
|
|
450
|
+
});
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
catch (error) {
|
|
454
|
+
this.#receiveInboundEvent({
|
|
455
|
+
type: "acp.client_error",
|
|
456
|
+
requestId,
|
|
457
|
+
method,
|
|
458
|
+
error: clientCallbackError(error),
|
|
459
|
+
});
|
|
460
|
+
throw error;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
#receiveClientNotification(method, params) {
|
|
464
|
+
this.#receiveInboundEvent({
|
|
465
|
+
type: "acp.client_notification",
|
|
466
|
+
method,
|
|
467
|
+
params,
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
#receiveInboundEvent(event, allowedBeforeSessionReady = false) {
|
|
471
|
+
this.#applySessionStateUpdate(event);
|
|
472
|
+
if (this.#activePromptCount === 0) {
|
|
473
|
+
if (!this.#acceptOutOfBandUpdates && !allowedBeforeSessionReady)
|
|
474
|
+
return;
|
|
475
|
+
if (this.#acceptOutOfBandUpdates && this.options.onOutOfBandSessionUpdate) {
|
|
476
|
+
try {
|
|
477
|
+
this.options.onOutOfBandSessionUpdate(event);
|
|
478
|
+
}
|
|
479
|
+
catch (error) {
|
|
480
|
+
console.error("[acp] out-of-band session update callback failed:", error);
|
|
481
|
+
}
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
this.#pushEvent(event);
|
|
486
|
+
}
|
|
487
|
+
#applySessionStateUpdate(event) {
|
|
488
|
+
if (!event || typeof event !== "object")
|
|
489
|
+
return;
|
|
490
|
+
const update = event;
|
|
491
|
+
if (update.sessionUpdate === "config_option_update"
|
|
492
|
+
&& Array.isArray(update.configOptions)) {
|
|
493
|
+
this.#configOptions = update.configOptions;
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
if (update.sessionUpdate === "current_mode_update"
|
|
497
|
+
&& typeof update.currentModeId === "string"
|
|
498
|
+
&& this.#modes) {
|
|
499
|
+
this.#modes = { ...this.#modes, currentModeId: update.currentModeId };
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
#logInit(mode, startedAt, initializedAt) {
|
|
503
|
+
if (process.env.NODE_ENV === "test")
|
|
504
|
+
return;
|
|
505
|
+
const completedAt = Date.now();
|
|
506
|
+
process.stderr.write(`[acp-init] id=${this.id} mode=${mode} initialize_ms=${initializedAt - startedAt} session_open_ms=${completedAt - initializedAt} total_ms=${completedAt - startedAt}\n`);
|
|
507
|
+
}
|
|
508
|
+
async #withAuthenticationRetry(open) {
|
|
509
|
+
try {
|
|
510
|
+
return await open();
|
|
511
|
+
}
|
|
512
|
+
catch (error) {
|
|
513
|
+
if (!isAuthenticationRequiredError(error))
|
|
514
|
+
throw error;
|
|
515
|
+
const method = this.#authMethods.find((candidate) => authMethodType(candidate) === "agent");
|
|
516
|
+
if (!method)
|
|
517
|
+
throw error;
|
|
518
|
+
await this.#agent.authenticate({ methodId: method.id });
|
|
519
|
+
return await open();
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
async authenticate(methodId) {
|
|
523
|
+
if (!this.#agent)
|
|
524
|
+
throw new Error("AcpSession not initialized");
|
|
525
|
+
await this.#agent.authenticate({ methodId });
|
|
526
|
+
}
|
|
527
|
+
async setMode(modeId) {
|
|
528
|
+
if (!this.#agent || !this.#sessionId)
|
|
529
|
+
throw new Error("AcpSession not initialized");
|
|
530
|
+
const setSessionMode = this.#agent.setSessionMode;
|
|
531
|
+
if (typeof setSessionMode !== "function")
|
|
532
|
+
return;
|
|
533
|
+
try {
|
|
534
|
+
await setSessionMode.call(this.#agent, { sessionId: this.#sessionId, modeId });
|
|
535
|
+
if (this.#modes)
|
|
536
|
+
this.#modes = { ...this.#modes, currentModeId: modeId };
|
|
537
|
+
}
|
|
538
|
+
catch (error) {
|
|
539
|
+
console.warn(`[acp] setSessionMode("${modeId}") failed:`, error);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
async setConfigOption(configId, value) {
|
|
543
|
+
if (!this.#agent || !this.#sessionId)
|
|
544
|
+
throw new Error("AcpSession not initialized");
|
|
545
|
+
const setSessionConfigOption = this.#agent.setSessionConfigOption;
|
|
546
|
+
if (typeof setSessionConfigOption !== "function") {
|
|
547
|
+
throw new Error("ACP agent does not support session config options");
|
|
548
|
+
}
|
|
549
|
+
const response = await setSessionConfigOption.call(this.#agent, {
|
|
550
|
+
sessionId: this.#sessionId,
|
|
551
|
+
configId,
|
|
552
|
+
...(typeof value === "boolean" ? { type: "boolean", value } : { value }),
|
|
553
|
+
});
|
|
554
|
+
this.#configOptions = response.configOptions ?? [];
|
|
555
|
+
return this.#configOptions;
|
|
556
|
+
}
|
|
557
|
+
async listSessions(params = {}) {
|
|
558
|
+
if (!this.#supportsSessionList || !this.#agent?.listSessions) {
|
|
559
|
+
throw new Error("ACP agent does not support session/list");
|
|
560
|
+
}
|
|
561
|
+
return this.#agent.listSessions(params);
|
|
562
|
+
}
|
|
563
|
+
async deleteSession(sessionId) {
|
|
564
|
+
if (!this.#supportsSessionDelete || !this.#agent?.deleteSession) {
|
|
565
|
+
throw new Error("ACP agent does not support session/delete");
|
|
566
|
+
}
|
|
567
|
+
await this.#agent.deleteSession({ sessionId });
|
|
568
|
+
}
|
|
569
|
+
async logout() {
|
|
570
|
+
if (!this.#supportsLogout || !this.#agent?.logout) {
|
|
571
|
+
throw new Error("ACP agent does not support logout");
|
|
572
|
+
}
|
|
573
|
+
await this.#agent.logout({});
|
|
574
|
+
}
|
|
575
|
+
async listProviders() {
|
|
576
|
+
if (!this.#supportsProviders || !this.#agent?.unstable_listProviders) {
|
|
577
|
+
throw new Error("ACP agent does not support providers/list");
|
|
578
|
+
}
|
|
579
|
+
return this.#agent.unstable_listProviders({});
|
|
580
|
+
}
|
|
581
|
+
async setProvider(params) {
|
|
582
|
+
if (!this.#supportsProviders || !this.#agent?.unstable_setProvider) {
|
|
583
|
+
throw new Error("ACP agent does not support providers/set");
|
|
584
|
+
}
|
|
585
|
+
await this.#agent.unstable_setProvider(params);
|
|
586
|
+
}
|
|
587
|
+
async disableProvider(providerId) {
|
|
588
|
+
if (!this.#supportsProviders || !this.#agent?.unstable_disableProvider) {
|
|
589
|
+
throw new Error("ACP agent does not support providers/disable");
|
|
590
|
+
}
|
|
591
|
+
await this.#agent.unstable_disableProvider({ providerId });
|
|
592
|
+
}
|
|
593
|
+
async requestExtension(method, params = {}) {
|
|
594
|
+
if (!this.#agent?.extMethod) {
|
|
595
|
+
throw new Error("ACP connection does not support extension requests");
|
|
596
|
+
}
|
|
597
|
+
return this.#agent.extMethod(method, params);
|
|
598
|
+
}
|
|
599
|
+
async notifyExtension(method, params = {}) {
|
|
600
|
+
if (!this.#agent?.extNotification) {
|
|
601
|
+
throw new Error("ACP connection does not support extension notifications");
|
|
602
|
+
}
|
|
603
|
+
await this.#agent.extNotification(method, params);
|
|
604
|
+
}
|
|
605
|
+
async startNes(params) {
|
|
606
|
+
this.#assertNesMethod(this.#agent?.unstable_startNes, "nes/start");
|
|
607
|
+
return this.#agent.unstable_startNes(params);
|
|
608
|
+
}
|
|
609
|
+
async suggestNes(params) {
|
|
610
|
+
this.#assertNesMethod(this.#agent?.unstable_suggestNes, "nes/suggest");
|
|
611
|
+
return this.#agent.unstable_suggestNes(params);
|
|
612
|
+
}
|
|
613
|
+
async closeNes(params) {
|
|
614
|
+
this.#assertNesMethod(this.#agent?.unstable_closeNes, "nes/close");
|
|
615
|
+
return this.#agent.unstable_closeNes(params);
|
|
616
|
+
}
|
|
617
|
+
async didOpenDocument(params) {
|
|
618
|
+
this.#assertNesDocumentEvent("didOpen", this.#agent?.unstable_didOpenDocument);
|
|
619
|
+
await this.#agent.unstable_didOpenDocument(params);
|
|
620
|
+
}
|
|
621
|
+
async didChangeDocument(params) {
|
|
622
|
+
this.#assertNesDocumentEvent("didChange", this.#agent?.unstable_didChangeDocument);
|
|
623
|
+
await this.#agent.unstable_didChangeDocument(params);
|
|
624
|
+
}
|
|
625
|
+
async didCloseDocument(params) {
|
|
626
|
+
this.#assertNesDocumentEvent("didClose", this.#agent?.unstable_didCloseDocument);
|
|
627
|
+
await this.#agent.unstable_didCloseDocument(params);
|
|
628
|
+
}
|
|
629
|
+
async didSaveDocument(params) {
|
|
630
|
+
this.#assertNesDocumentEvent("didSave", this.#agent?.unstable_didSaveDocument);
|
|
631
|
+
await this.#agent.unstable_didSaveDocument(params);
|
|
632
|
+
}
|
|
633
|
+
async didFocusDocument(params) {
|
|
634
|
+
this.#assertNesDocumentEvent("didFocus", this.#agent?.unstable_didFocusDocument);
|
|
635
|
+
await this.#agent.unstable_didFocusDocument(params);
|
|
636
|
+
}
|
|
637
|
+
async acceptNes(params) {
|
|
638
|
+
this.#assertNesMethod(this.#agent?.unstable_acceptNes, "nes/accept");
|
|
639
|
+
await this.#agent.unstable_acceptNes(params);
|
|
640
|
+
}
|
|
641
|
+
async rejectNes(params) {
|
|
642
|
+
this.#assertNesMethod(this.#agent?.unstable_rejectNes, "nes/reject");
|
|
643
|
+
await this.#agent.unstable_rejectNes(params);
|
|
644
|
+
}
|
|
645
|
+
#assertNesMethod(method, name) {
|
|
646
|
+
if (!this.#supportsNes || typeof method !== "function") {
|
|
647
|
+
throw new Error(`ACP agent does not support ${name}`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
#assertNesDocumentEvent(event, method) {
|
|
651
|
+
const capability = this.#nesCapabilities?.events?.document?.[event];
|
|
652
|
+
if (capability == null || typeof method !== "function") {
|
|
653
|
+
throw new Error(`ACP agent does not support document/${event}`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
prompt(input, options) {
|
|
657
|
+
if (this.#disposed)
|
|
658
|
+
throw new Error(`AcpSession ${this.id} is disposed`);
|
|
659
|
+
return this.#guardPrompt(this.#prompt(input, options));
|
|
660
|
+
}
|
|
661
|
+
async *#guardPrompt(stream) {
|
|
662
|
+
try {
|
|
663
|
+
yield* stream;
|
|
664
|
+
}
|
|
665
|
+
catch (error) {
|
|
666
|
+
const exit = this.#childExit ?? await settledChildExit(this.#child.exited);
|
|
667
|
+
if (exit || isBrokenPipe(error)) {
|
|
668
|
+
throw agentProcessExitError(this.options.agent.command, exit, error);
|
|
669
|
+
}
|
|
670
|
+
throw error;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
async steer(input) {
|
|
674
|
+
if (!this.#agent || !this.#sessionId)
|
|
675
|
+
throw new Error("AcpSession not initialized");
|
|
676
|
+
if (!this.#supportsSteering) {
|
|
677
|
+
throw new Error("ACP agent did not negotiate _session/steering");
|
|
678
|
+
}
|
|
679
|
+
if (!this.#agent.extMethod)
|
|
680
|
+
throw new Error("ACP connection does not support extensions");
|
|
681
|
+
const prompt = typeof input === "string"
|
|
682
|
+
? [{ type: "text", text: input }]
|
|
683
|
+
: [...input];
|
|
684
|
+
const response = await this.#agent.extMethod("_session/steering", {
|
|
685
|
+
sessionId: this.#sessionId,
|
|
686
|
+
prompt,
|
|
687
|
+
_meta: { steering: { idleBehavior: "promptRequired" } },
|
|
688
|
+
});
|
|
689
|
+
const outcome = response.outcome;
|
|
690
|
+
if (outcome !== "injected"
|
|
691
|
+
&& outcome !== "promptRequired"
|
|
692
|
+
&& outcome !== "startedNewTurn"
|
|
693
|
+
&& outcome !== "failed") {
|
|
694
|
+
throw new Error(`Invalid _session/steering outcome: ${String(outcome)}`);
|
|
695
|
+
}
|
|
696
|
+
return outcome;
|
|
697
|
+
}
|
|
698
|
+
async cancelCurrentTurn() {
|
|
699
|
+
if (!this.#agent || !this.#sessionId)
|
|
700
|
+
throw new Error("AcpSession not initialized");
|
|
701
|
+
await this.#agent.cancel({ sessionId: this.#sessionId });
|
|
702
|
+
}
|
|
703
|
+
async provideToolResult(toolCallId, result) {
|
|
704
|
+
void toolCallId;
|
|
705
|
+
void result;
|
|
706
|
+
throw new Error("provideToolResult not implemented; ACP tools use client callbacks");
|
|
707
|
+
}
|
|
708
|
+
drainPendingEvents() {
|
|
709
|
+
return this.#pendingEvents.splice(0);
|
|
710
|
+
}
|
|
711
|
+
async *#prompt(input, options) {
|
|
712
|
+
const turnAbort = new AbortController();
|
|
713
|
+
const onAbort = () => {
|
|
714
|
+
Promise.resolve(this.#agent.cancel({ sessionId: this.#sessionId }))
|
|
715
|
+
.catch(() => { });
|
|
716
|
+
};
|
|
717
|
+
const abortTurn = () => turnAbort.abort();
|
|
718
|
+
const timeoutMs = this.options.perTurnTimeoutMs;
|
|
719
|
+
let timer;
|
|
720
|
+
let turnFinished = false;
|
|
721
|
+
const finishTurn = () => {
|
|
722
|
+
if (turnFinished)
|
|
723
|
+
return;
|
|
724
|
+
turnFinished = true;
|
|
725
|
+
this.#activePromptCount = Math.max(0, this.#activePromptCount - 1);
|
|
726
|
+
if (timer)
|
|
727
|
+
clearTimeout(timer);
|
|
728
|
+
options?.abortSignal?.removeEventListener("abort", abortTurn);
|
|
729
|
+
};
|
|
730
|
+
options?.abortSignal?.addEventListener("abort", abortTurn, { once: true });
|
|
731
|
+
turnAbort.signal.addEventListener("abort", onAbort, { once: true });
|
|
732
|
+
if (options?.abortSignal?.aborted)
|
|
733
|
+
turnAbort.abort();
|
|
734
|
+
this.#activePromptCount += 1;
|
|
735
|
+
const prompt = typeof input === "string" ? [{ type: "text", text: input }] : [...input];
|
|
736
|
+
const done = Promise.resolve(this.#agent.prompt({ sessionId: this.#sessionId, prompt }))
|
|
737
|
+
.finally(finishTurn);
|
|
738
|
+
let ended = false;
|
|
739
|
+
let timedOut = false;
|
|
740
|
+
if (timeoutMs) {
|
|
741
|
+
timer = setTimeout(() => {
|
|
742
|
+
if (ended)
|
|
743
|
+
return;
|
|
744
|
+
timedOut = true;
|
|
745
|
+
ended = true;
|
|
746
|
+
turnAbort.abort();
|
|
747
|
+
const message = `ACP prompt timed out after ${timeoutMs}ms`;
|
|
748
|
+
this.#pushEvent({
|
|
749
|
+
type: "promptError",
|
|
750
|
+
error: `Error: ${message}`,
|
|
751
|
+
errorDetails: { message },
|
|
752
|
+
});
|
|
753
|
+
this.#endStream();
|
|
754
|
+
finishTurn();
|
|
755
|
+
}, timeoutMs);
|
|
756
|
+
}
|
|
757
|
+
void done.then((response) => {
|
|
758
|
+
if (timedOut || ended)
|
|
759
|
+
return;
|
|
760
|
+
ended = true;
|
|
761
|
+
this.#pushEvent({ type: "promptComplete", response });
|
|
762
|
+
this.#endStream();
|
|
763
|
+
}, (error) => {
|
|
764
|
+
if (timedOut || ended)
|
|
765
|
+
return;
|
|
766
|
+
ended = true;
|
|
767
|
+
// Keep the legacy display string, but retain the JSON-RPC evidence
|
|
768
|
+
// so hosts can classify failures without interpreting message text.
|
|
769
|
+
const rpcError = error !== null && typeof error === "object"
|
|
770
|
+
? error
|
|
771
|
+
: undefined;
|
|
772
|
+
this.#pushEvent({
|
|
773
|
+
type: "promptError",
|
|
774
|
+
error: String(error),
|
|
775
|
+
errorDetails: {
|
|
776
|
+
message: typeof rpcError?.message === "string"
|
|
777
|
+
? rpcError.message
|
|
778
|
+
: String(error),
|
|
779
|
+
...(typeof rpcError?.code === "number" ? { code: rpcError.code } : {}),
|
|
780
|
+
...(rpcError?.data !== undefined ? { data: rpcError.data } : {}),
|
|
781
|
+
},
|
|
782
|
+
});
|
|
783
|
+
this.#endStream();
|
|
784
|
+
});
|
|
785
|
+
while (true) {
|
|
786
|
+
if (this.#pendingEvents.length > 0) {
|
|
787
|
+
yield this.#pendingEvents.shift();
|
|
788
|
+
}
|
|
789
|
+
else if (ended) {
|
|
790
|
+
break;
|
|
791
|
+
}
|
|
792
|
+
else {
|
|
793
|
+
await new Promise((resolve) => {
|
|
794
|
+
this.#waiters.push(() => resolve());
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
if (!timedOut)
|
|
799
|
+
await done;
|
|
800
|
+
}
|
|
801
|
+
isAlive() {
|
|
802
|
+
return !this.#disposed && this.#childExit === null;
|
|
803
|
+
}
|
|
804
|
+
dispose() {
|
|
805
|
+
this.#disposePromise ??= this.#disposeOnce();
|
|
806
|
+
return this.#disposePromise;
|
|
807
|
+
}
|
|
808
|
+
async #disposeOnce() {
|
|
809
|
+
if (this.#supportsSessionClose && this.#sessionId && this.#agent?.closeSession) {
|
|
810
|
+
try {
|
|
811
|
+
await this.#agent.closeSession({ sessionId: this.#sessionId });
|
|
812
|
+
}
|
|
813
|
+
catch (error) {
|
|
814
|
+
console.warn(`[acp] session/close(${this.#sessionId}) failed:`, error);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
this.#disposed = true;
|
|
818
|
+
this.#outstandingUrlElicitations.clear();
|
|
819
|
+
this.#endStream();
|
|
820
|
+
await this.#child.kill("SIGTERM").catch(() => { });
|
|
821
|
+
}
|
|
822
|
+
#pushEvent(event) {
|
|
823
|
+
this.#pendingEvents.push(event);
|
|
824
|
+
this.#waiters.shift()?.({ value: undefined, done: false });
|
|
825
|
+
}
|
|
826
|
+
#endStream() {
|
|
827
|
+
while (this.#waiters.length > 0) {
|
|
828
|
+
this.#waiters.shift()?.({ value: undefined, done: true });
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
async function settledChildExit(exited) {
|
|
833
|
+
let timer;
|
|
834
|
+
try {
|
|
835
|
+
return await Promise.race([
|
|
836
|
+
exited,
|
|
837
|
+
new Promise((resolve) => {
|
|
838
|
+
timer = setTimeout(() => resolve(null), 25);
|
|
839
|
+
timer.unref?.();
|
|
840
|
+
}),
|
|
841
|
+
]);
|
|
842
|
+
}
|
|
843
|
+
finally {
|
|
844
|
+
if (timer)
|
|
845
|
+
clearTimeout(timer);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
function isBrokenPipe(error) {
|
|
849
|
+
const code = error && typeof error === "object" && "code" in error
|
|
850
|
+
? String(error.code ?? "")
|
|
851
|
+
: "";
|
|
852
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
853
|
+
return (code === "EPIPE"
|
|
854
|
+
|| code === "ERR_STREAM_DESTROYED"
|
|
855
|
+
|| /\bEPIPE\b|broken pipe|stream (?:is )?(?:closed|destroyed)/i.test(message));
|
|
856
|
+
}
|
|
857
|
+
function agentProcessExitError(command, exit, cause) {
|
|
858
|
+
const status = exit?.signal
|
|
859
|
+
? `signal ${exit.signal}`
|
|
860
|
+
: exit?.code != null
|
|
861
|
+
? `exit code ${exit.code}`
|
|
862
|
+
: "no exit status";
|
|
863
|
+
return new Error(`The agent process exited before it could accept the prompt (${command}, ${status}). `
|
|
864
|
+
+ "Reopen the task to restart it, or check this agent's setup and sign-in.", { cause });
|
|
865
|
+
}
|
|
866
|
+
function clientCallbackError(error) {
|
|
867
|
+
const code = error !== null
|
|
868
|
+
&& typeof error === "object"
|
|
869
|
+
&& typeof error.code === "number"
|
|
870
|
+
? error.code
|
|
871
|
+
: undefined;
|
|
872
|
+
const message = code === -32601
|
|
873
|
+
? "Method not found"
|
|
874
|
+
: error instanceof Error
|
|
875
|
+
? error.message
|
|
876
|
+
: String(error);
|
|
877
|
+
return {
|
|
878
|
+
message,
|
|
879
|
+
...(code !== undefined ? { code } : {}),
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
const IDLE_SESSION_UPDATES = new Set([
|
|
883
|
+
"available_commands_update",
|
|
884
|
+
"current_mode_update",
|
|
885
|
+
"config_option_update",
|
|
886
|
+
"session_info_update",
|
|
887
|
+
]);
|
|
888
|
+
function isIdleSessionUpdate(update) {
|
|
889
|
+
const tag = update?.sessionUpdate;
|
|
890
|
+
return typeof tag === "string" && IDLE_SESSION_UPDATES.has(tag);
|
|
891
|
+
}
|
|
892
|
+
function authMethodType(method) {
|
|
893
|
+
return typeof method.type === "string" && method.type.length > 0 ? method.type : "agent";
|
|
894
|
+
}
|
|
895
|
+
function sessionRequestDeclaresAirFork(meta) {
|
|
896
|
+
if (!meta || !isPlainRecord(meta.jetbrains) || !isPlainRecord(meta.jetbrains.air))
|
|
897
|
+
return false;
|
|
898
|
+
return Object.hasOwn(meta.jetbrains.air, "fork");
|
|
899
|
+
}
|
|
900
|
+
function mergeSessionRequestMeta(base, extra) {
|
|
901
|
+
const merged = { ...(base ?? {}) };
|
|
902
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
903
|
+
const current = merged[key];
|
|
904
|
+
if (isPlainRecord(current) && isPlainRecord(value)) {
|
|
905
|
+
merged[key] = mergeSessionRequestMeta(current, value);
|
|
906
|
+
}
|
|
907
|
+
else {
|
|
908
|
+
merged[key] = value;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return merged;
|
|
912
|
+
}
|
|
913
|
+
function isPlainRecord(value) {
|
|
914
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
915
|
+
}
|
|
916
|
+
/** Clone `configOptions` from a session-setup response. When the response
|
|
917
|
+
* still carries the retired `models` catalog and no option already has
|
|
918
|
+
* category or id `model`, append a select marked as legacy model state. */
|
|
919
|
+
export function sessionConfigOptionsFromResponse(value) {
|
|
920
|
+
const responseConfigOptions = value && typeof value === "object"
|
|
921
|
+
? value.configOptions
|
|
922
|
+
: undefined;
|
|
923
|
+
const configOptions = Array.isArray(responseConfigOptions)
|
|
924
|
+
? responseConfigOptions.map((option) => structuredClone(option))
|
|
925
|
+
: [];
|
|
926
|
+
const legacyModels = legacyModelStateFromResponse(value);
|
|
927
|
+
if (legacyModels && !configOptions.some(isModelConfigOption)) {
|
|
928
|
+
configOptions.push(legacyModelConfigOption(legacyModels));
|
|
929
|
+
}
|
|
930
|
+
return configOptions;
|
|
931
|
+
}
|
|
932
|
+
function legacyModelStateFromResponse(value) {
|
|
933
|
+
if (!value || typeof value !== "object")
|
|
934
|
+
return null;
|
|
935
|
+
const models = value.models;
|
|
936
|
+
if (!models || typeof models !== "object")
|
|
937
|
+
return null;
|
|
938
|
+
const currentModelId = models.currentModelId;
|
|
939
|
+
const availableModels = models.availableModels;
|
|
940
|
+
if (typeof currentModelId !== "string" || !Array.isArray(availableModels))
|
|
941
|
+
return null;
|
|
942
|
+
const normalized = availableModels.flatMap((model) => {
|
|
943
|
+
if (!model || typeof model !== "object")
|
|
944
|
+
return [];
|
|
945
|
+
const candidate = model;
|
|
946
|
+
if (typeof candidate.modelId !== "string" || typeof candidate.name !== "string")
|
|
947
|
+
return [];
|
|
948
|
+
return [{
|
|
949
|
+
modelId: candidate.modelId,
|
|
950
|
+
name: candidate.name,
|
|
951
|
+
...(typeof candidate.description === "string"
|
|
952
|
+
? { description: candidate.description }
|
|
953
|
+
: {}),
|
|
954
|
+
}];
|
|
955
|
+
});
|
|
956
|
+
if (normalized.length === 0)
|
|
957
|
+
return null;
|
|
958
|
+
return { currentModelId, availableModels: normalized };
|
|
959
|
+
}
|
|
960
|
+
function isModelConfigOption(option) {
|
|
961
|
+
return option?.category === "model" || option?.id === "model";
|
|
962
|
+
}
|
|
963
|
+
function legacyModelConfigOption(state) {
|
|
964
|
+
return {
|
|
965
|
+
id: "model",
|
|
966
|
+
name: "Model",
|
|
967
|
+
category: "model",
|
|
968
|
+
type: "select",
|
|
969
|
+
currentValue: state.currentModelId,
|
|
970
|
+
options: state.availableModels.map((model) => ({
|
|
971
|
+
value: model.modelId,
|
|
972
|
+
name: model.name,
|
|
973
|
+
...(model.description ? { description: model.description } : {}),
|
|
974
|
+
})),
|
|
975
|
+
_meta: { [LEGACY_MODEL_META_KEY]: true },
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
/** Merge a host capability overlay into the runtime's initialize advertisement.
|
|
979
|
+
* `fs` and `session.configOptions` merge one level. `auth._meta` and top-level
|
|
980
|
+
* `_meta` merge key by key. Overlay values win. */
|
|
981
|
+
export function mergeClientCapabilities(base, extra) {
|
|
982
|
+
const left = base ?? {};
|
|
983
|
+
const leftSession = left.session;
|
|
984
|
+
const rightSession = extra.session;
|
|
985
|
+
const leftAuth = left.auth;
|
|
986
|
+
const rightAuth = extra.auth;
|
|
987
|
+
return {
|
|
988
|
+
...left,
|
|
989
|
+
...extra,
|
|
990
|
+
...(left.fs || extra.fs ? { fs: { ...left.fs, ...extra.fs } } : {}),
|
|
991
|
+
...(leftSession || rightSession
|
|
992
|
+
? {
|
|
993
|
+
session: {
|
|
994
|
+
...(leftSession ?? {}),
|
|
995
|
+
...(rightSession ?? {}),
|
|
996
|
+
...(leftSession?.configOptions || rightSession?.configOptions
|
|
997
|
+
? {
|
|
998
|
+
configOptions: {
|
|
999
|
+
...(leftSession?.configOptions ?? {}),
|
|
1000
|
+
...(rightSession?.configOptions ?? {}),
|
|
1001
|
+
},
|
|
1002
|
+
}
|
|
1003
|
+
: {}),
|
|
1004
|
+
},
|
|
1005
|
+
}
|
|
1006
|
+
: {}),
|
|
1007
|
+
...(leftAuth || rightAuth
|
|
1008
|
+
? {
|
|
1009
|
+
auth: {
|
|
1010
|
+
...(leftAuth ?? {}),
|
|
1011
|
+
...(rightAuth ?? {}),
|
|
1012
|
+
...(leftAuth?._meta || rightAuth?._meta
|
|
1013
|
+
? { _meta: { ...(leftAuth?._meta ?? {}), ...(rightAuth?._meta ?? {}) } }
|
|
1014
|
+
: {}),
|
|
1015
|
+
},
|
|
1016
|
+
}
|
|
1017
|
+
: {}),
|
|
1018
|
+
...(left._meta || extra._meta
|
|
1019
|
+
? { _meta: { ...(left._meta ?? {}), ...(extra._meta ?? {}) } }
|
|
1020
|
+
: {}),
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
function observeLegacyModels(source, onModels) {
|
|
1024
|
+
const decoder = new TextDecoder();
|
|
1025
|
+
let pending = "";
|
|
1026
|
+
let found = false;
|
|
1027
|
+
return source.pipeThrough(new TransformStream({
|
|
1028
|
+
transform(chunk, controller) {
|
|
1029
|
+
if (!found) {
|
|
1030
|
+
pending += decoder.decode(chunk, { stream: true });
|
|
1031
|
+
let end = pending.indexOf("\n");
|
|
1032
|
+
while (end >= 0) {
|
|
1033
|
+
const line = pending.slice(0, end);
|
|
1034
|
+
pending = pending.slice(end + 1);
|
|
1035
|
+
const models = legacyModelsFromLine(line);
|
|
1036
|
+
if (models) {
|
|
1037
|
+
found = true;
|
|
1038
|
+
onModels(models);
|
|
1039
|
+
break;
|
|
1040
|
+
}
|
|
1041
|
+
end = pending.indexOf("\n");
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
controller.enqueue(chunk);
|
|
1045
|
+
},
|
|
1046
|
+
}));
|
|
1047
|
+
}
|
|
1048
|
+
function legacyModelsFromLine(line) {
|
|
1049
|
+
try {
|
|
1050
|
+
const models = JSON.parse(line)?.result?.models;
|
|
1051
|
+
if (!models
|
|
1052
|
+
|| typeof models.currentModelId !== "string"
|
|
1053
|
+
|| !Array.isArray(models.availableModels)) {
|
|
1054
|
+
return null;
|
|
1055
|
+
}
|
|
1056
|
+
const availableModels = [];
|
|
1057
|
+
for (const model of models.availableModels) {
|
|
1058
|
+
if (!model
|
|
1059
|
+
|| typeof model.modelId !== "string"
|
|
1060
|
+
|| typeof model.name !== "string") {
|
|
1061
|
+
return null;
|
|
1062
|
+
}
|
|
1063
|
+
availableModels.push({ modelId: model.modelId, name: model.name });
|
|
1064
|
+
}
|
|
1065
|
+
return { currentModelId: models.currentModelId, availableModels };
|
|
1066
|
+
}
|
|
1067
|
+
catch {
|
|
1068
|
+
return null;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
//# sourceMappingURL=session.js.map
|