llm-cli-gateway 2.13.2 → 2.14.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 +139 -0
- package/README.md +68 -29
- package/dist/acp/client.d.ts +29 -1
- package/dist/acp/client.js +78 -4
- package/dist/acp/errors.d.ts +9 -1
- package/dist/acp/errors.js +19 -0
- package/dist/acp/event-normalizer.d.ts +12 -0
- package/dist/acp/event-normalizer.js +16 -0
- package/dist/acp/flight-redaction.d.ts +3 -0
- package/dist/acp/flight-redaction.js +3 -0
- package/dist/acp/permission-bridge.js +11 -5
- package/dist/acp/process-manager.d.ts +2 -1
- package/dist/acp/process-manager.js +43 -4
- package/dist/acp/provider-registry.js +19 -11
- package/dist/acp/runtime.d.ts +8 -0
- package/dist/acp/runtime.js +47 -4
- package/dist/acp/types.d.ts +3083 -55
- package/dist/acp/types.js +242 -5
- package/dist/async-job-manager.d.ts +38 -1
- package/dist/async-job-manager.js +287 -20
- package/dist/codex-json-parser.d.ts +1 -0
- package/dist/codex-json-parser.js +6 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.js +84 -1
- package/dist/flight-recorder.d.ts +2 -0
- package/dist/flight-recorder.js +20 -0
- package/dist/gemini-json-parser.d.ts +2 -0
- package/dist/gemini-json-parser.js +45 -8
- package/dist/grok-json-parser.d.ts +14 -0
- package/dist/grok-json-parser.js +156 -0
- package/dist/index.d.ts +47 -2
- package/dist/index.js +504 -122
- package/dist/job-store.d.ts +119 -11
- package/dist/job-store.js +372 -42
- package/dist/model-registry.d.ts +1 -0
- package/dist/model-registry.js +46 -0
- package/dist/oauth.js +2 -2
- package/dist/postgres-job-store-worker.d.ts +1 -0
- package/dist/postgres-job-store-worker.js +444 -0
- package/dist/pricing.d.ts +3 -2
- package/dist/provider-acp-capabilities.d.ts +52 -0
- package/dist/provider-acp-capabilities.js +101 -0
- package/dist/provider-admin-tools.d.ts +100 -0
- package/dist/provider-admin-tools.js +572 -0
- package/dist/provider-capability-cache.d.ts +46 -0
- package/dist/provider-capability-cache.js +248 -0
- package/dist/provider-capability-discovery.d.ts +85 -0
- package/dist/provider-capability-discovery.js +461 -0
- package/dist/provider-capability-resolver.d.ts +29 -0
- package/dist/provider-capability-resolver.js +92 -0
- package/dist/provider-definition-assertions.d.ts +9 -0
- package/dist/provider-definition-assertions.js +147 -0
- package/dist/provider-definitions.d.ts +127 -0
- package/dist/provider-definitions.js +758 -0
- package/dist/provider-help-parser.d.ts +34 -0
- package/dist/provider-help-parser.js +203 -0
- package/dist/provider-model-discovery.d.ts +30 -0
- package/dist/provider-model-discovery.js +229 -0
- package/dist/provider-output-metadata.d.ts +7 -0
- package/dist/provider-output-metadata.js +68 -0
- package/dist/provider-schema-builder.d.ts +22 -0
- package/dist/provider-schema-builder.js +55 -0
- package/dist/provider-surface-generator.d.ts +98 -0
- package/dist/provider-surface-generator.js +140 -0
- package/dist/provider-tool-capabilities.d.ts +3 -2
- package/dist/provider-tool-capabilities.js +77 -62
- package/dist/request-helpers.d.ts +37 -4
- package/dist/request-helpers.js +134 -0
- package/dist/resources.d.ts +6 -1
- package/dist/resources.js +64 -192
- package/dist/session-manager.js +18 -11
- package/dist/sqlite-driver.d.ts +1 -1
- package/dist/sqlite-driver.js +2 -1
- package/dist/stream-json-parser.d.ts +1 -0
- package/dist/stream-json-parser.js +3 -0
- package/dist/upstream-contracts.d.ts +17 -1
- package/dist/upstream-contracts.js +209 -36
- package/npm-shrinkwrap.json +2 -2
- package/package.json +8 -3
package/dist/acp/errors.js
CHANGED
|
@@ -2,6 +2,9 @@ export function redactAcpMessage(input) {
|
|
|
2
2
|
let out = redactJsonLikeBodies(input);
|
|
3
3
|
out = out.replace(/\b(bearer|token|api[_-]?key|secret)\b\s*[:=]?\s*\S+/gi, "$1 <redacted>");
|
|
4
4
|
out = out.replace(/\b(sk|xai|gsk|key)-[A-Za-z0-9_-]{8,}\b/gi, "<redacted-token>");
|
|
5
|
+
out = out.replace(/\bAIza[A-Za-z0-9_-]{10,}/g, "<redacted-token>");
|
|
6
|
+
out = out.replace(/\bgh[pousr]_[A-Za-z0-9]{20,}\b/g, "<redacted-token>");
|
|
7
|
+
out = out.replace(/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/gi, "<redacted-token>");
|
|
5
8
|
out = out.replace(/(^|[^A-Za-z0-9._~\\/-])[A-Za-z]:\\[^\s"')\]}>]*/g, "$1<redacted-path>");
|
|
6
9
|
out = out.replace(/(^|[^A-Za-z0-9._~\\/-])\\\\[^\s"')\]}>]+/g, "$1<redacted-path>");
|
|
7
10
|
out = out.replace(/(^|[^A-Za-z0-9._~/-])~\/[^\s"')\]}>]+/g, "$1<redacted-path>");
|
|
@@ -150,6 +153,22 @@ export class ProviderUnavailableError extends AcpError {
|
|
|
150
153
|
this.name = "ProviderUnavailableError";
|
|
151
154
|
}
|
|
152
155
|
}
|
|
156
|
+
export class AcpMethodUnsupportedError extends AcpError {
|
|
157
|
+
method;
|
|
158
|
+
constructor(provider, method, debug) {
|
|
159
|
+
super("method_unsupported", `ACP method ${method} is not advertised by provider ${provider}'s capability set; the agent did not declare support for it.`, { provider, debug: { method, ...(debug ?? {}) } });
|
|
160
|
+
this.name = "AcpMethodUnsupportedError";
|
|
161
|
+
this.method = method;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
export class AcpMutatingDisabledError extends AcpError {
|
|
165
|
+
method;
|
|
166
|
+
constructor(provider, method, debug) {
|
|
167
|
+
super("mutating_disabled", `ACP mutating session op ${method} is disabled. Set allow_mutating_session_ops=true under [acp] to permit state-mutating ACP admin ops.`, { provider, debug: { method, ...(debug ?? {}) } });
|
|
168
|
+
this.name = "AcpMutatingDisabledError";
|
|
169
|
+
this.method = method;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
153
172
|
export class AcpProtocolError extends AcpError {
|
|
154
173
|
code;
|
|
155
174
|
constructor(userMessage, options) {
|
|
@@ -29,6 +29,12 @@ export type AcpProgressEvent = {
|
|
|
29
29
|
readonly kind: "usage";
|
|
30
30
|
readonly size: number;
|
|
31
31
|
readonly used: number;
|
|
32
|
+
} | {
|
|
33
|
+
readonly kind: "session_complete";
|
|
34
|
+
readonly stopReason: string;
|
|
35
|
+
} | {
|
|
36
|
+
readonly kind: "error";
|
|
37
|
+
readonly message: string;
|
|
32
38
|
} | {
|
|
33
39
|
readonly kind: "other";
|
|
34
40
|
readonly sessionUpdate: string;
|
|
@@ -37,6 +43,12 @@ export declare function summarizeContentBlock(block: ContentBlock): string;
|
|
|
37
43
|
export declare function normalizeSessionUpdate(notification: SessionUpdateNotification): AcpProgressEvent;
|
|
38
44
|
export declare class AcpEventNormalizer {
|
|
39
45
|
private text;
|
|
46
|
+
private stopReasonValue;
|
|
47
|
+
private errorValue;
|
|
40
48
|
handle(notification: SessionUpdateNotification): AcpProgressEvent;
|
|
49
|
+
completeWith(stopReason: string): AcpProgressEvent;
|
|
50
|
+
error(message: string): AcpProgressEvent;
|
|
41
51
|
get finalText(): string;
|
|
52
|
+
get stopReason(): string | undefined;
|
|
53
|
+
get errorMessage(): string | undefined;
|
|
42
54
|
}
|
|
@@ -58,6 +58,8 @@ export function normalizeSessionUpdate(notification) {
|
|
|
58
58
|
}
|
|
59
59
|
export class AcpEventNormalizer {
|
|
60
60
|
text = "";
|
|
61
|
+
stopReasonValue;
|
|
62
|
+
errorValue;
|
|
61
63
|
handle(notification) {
|
|
62
64
|
const event = normalizeSessionUpdate(notification);
|
|
63
65
|
if (event.kind === "agent_message") {
|
|
@@ -65,7 +67,21 @@ export class AcpEventNormalizer {
|
|
|
65
67
|
}
|
|
66
68
|
return event;
|
|
67
69
|
}
|
|
70
|
+
completeWith(stopReason) {
|
|
71
|
+
this.stopReasonValue = stopReason;
|
|
72
|
+
return { kind: "session_complete", stopReason };
|
|
73
|
+
}
|
|
74
|
+
error(message) {
|
|
75
|
+
this.errorValue = message;
|
|
76
|
+
return { kind: "error", message };
|
|
77
|
+
}
|
|
68
78
|
get finalText() {
|
|
69
79
|
return this.text;
|
|
70
80
|
}
|
|
81
|
+
get stopReason() {
|
|
82
|
+
return this.stopReasonValue;
|
|
83
|
+
}
|
|
84
|
+
get errorMessage() {
|
|
85
|
+
return this.errorValue;
|
|
86
|
+
}
|
|
71
87
|
}
|
|
@@ -20,6 +20,9 @@ export interface AcpFlightResultParams {
|
|
|
20
20
|
readonly exitCode: number;
|
|
21
21
|
readonly inputTokens?: number;
|
|
22
22
|
readonly outputTokens?: number;
|
|
23
|
+
readonly cacheReadTokens?: number;
|
|
23
24
|
readonly errorMessage?: string;
|
|
25
|
+
readonly providerSessionId?: string;
|
|
26
|
+
readonly stopReason?: string;
|
|
24
27
|
}
|
|
25
28
|
export declare function buildAcpFlightResult(params: AcpFlightResultParams): FlightLogResult;
|
|
@@ -35,6 +35,9 @@ export function buildAcpFlightResult(params) {
|
|
|
35
35
|
optimizationApplied: false,
|
|
36
36
|
inputTokens: params.inputTokens,
|
|
37
37
|
outputTokens: params.outputTokens,
|
|
38
|
+
cacheReadTokens: params.cacheReadTokens,
|
|
38
39
|
errorMessage: params.errorMessage !== undefined ? redactAcpTextForFlight(params.errorMessage) : undefined,
|
|
40
|
+
providerSessionId: params.providerSessionId,
|
|
41
|
+
stopReason: params.stopReason,
|
|
39
42
|
};
|
|
40
43
|
}
|
|
@@ -12,9 +12,15 @@ export function categorizeToolCall(toolCall) {
|
|
|
12
12
|
return "read";
|
|
13
13
|
return "other";
|
|
14
14
|
}
|
|
15
|
-
function
|
|
16
|
-
const
|
|
17
|
-
|
|
15
|
+
function selectSingleUseAllow(options) {
|
|
16
|
+
const kindOf = (o) => typeof o.kind === "string" ? o.kind.toLowerCase() : "";
|
|
17
|
+
const allowOnce = options.find(o => kindOf(o) === "allow_once");
|
|
18
|
+
if (allowOnce)
|
|
19
|
+
return allowOnce;
|
|
20
|
+
return options.find(o => {
|
|
21
|
+
const kind = kindOf(o);
|
|
22
|
+
return kind.startsWith("allow") && !kind.includes("always");
|
|
23
|
+
});
|
|
18
24
|
}
|
|
19
25
|
const CANCELLED = { outcome: { outcome: "cancelled" } };
|
|
20
26
|
export function createAcpPermissionDecider(deps) {
|
|
@@ -75,12 +81,12 @@ export function createAcpPermissionDecider(deps) {
|
|
|
75
81
|
});
|
|
76
82
|
return CANCELLED;
|
|
77
83
|
}
|
|
78
|
-
const allow = request.options
|
|
84
|
+
const allow = selectSingleUseAllow(request.options);
|
|
79
85
|
if (!allow) {
|
|
80
86
|
logger.info("acp.permission.denied", {
|
|
81
87
|
provider: deps.provider,
|
|
82
88
|
category,
|
|
83
|
-
reason: "
|
|
89
|
+
reason: "no_single_use_allow_option",
|
|
84
90
|
});
|
|
85
91
|
return CANCELLED;
|
|
86
92
|
}
|
|
@@ -36,6 +36,7 @@ export interface StartProviderOptions {
|
|
|
36
36
|
readonly hostServices: HostServices;
|
|
37
37
|
readonly callbacks?: AcpClientCallbacks;
|
|
38
38
|
readonly idleTimeoutMs?: number;
|
|
39
|
+
readonly extraArgs?: readonly string[];
|
|
39
40
|
}
|
|
40
41
|
export interface ManagedAcpProcess {
|
|
41
42
|
readonly provider: CliType;
|
|
@@ -51,7 +52,7 @@ export interface ManagedAcpProcess {
|
|
|
51
52
|
isHealthy(): boolean;
|
|
52
53
|
}
|
|
53
54
|
export declare function buildProviderEnv(provider: CliType, providerConfig: AcpProviderConfig, baseEnv: ProcessEnv): ProcessEnv;
|
|
54
|
-
export declare function resolveProviderSpawn(provider: CliType, config: AcpConfig, baseEnv: ProcessEnv, cwd?: string): ResolvedAcpSpawn;
|
|
55
|
+
export declare function resolveProviderSpawn(provider: CliType, config: AcpConfig, baseEnv: ProcessEnv, cwd?: string, extraArgs?: readonly string[]): ResolvedAcpSpawn;
|
|
55
56
|
export declare const defaultSpawn: AcpSpawnFn;
|
|
56
57
|
export declare class AcpProcessManager {
|
|
57
58
|
private readonly config;
|
|
@@ -7,6 +7,7 @@ import { JsonRpcStdioTransport, } from "./json-rpc-stdio.js";
|
|
|
7
7
|
import { getAcpProviderEntry } from "./provider-registry.js";
|
|
8
8
|
import { envWithExtendedPath, getExtendedPath } from "../executor.js";
|
|
9
9
|
import { noopLogger } from "../logger.js";
|
|
10
|
+
const SHUTDOWN_KILL_GRACE_MS = 5000;
|
|
10
11
|
const SHELL_METACHARACTERS = /[\s|&;<>(){}$`"'\\*?[\]~#! ]/;
|
|
11
12
|
function assertSafeExecutable(command, provider) {
|
|
12
13
|
if (command.length === 0 || SHELL_METACHARACTERS.test(command)) {
|
|
@@ -22,7 +23,7 @@ export function buildProviderEnv(provider, providerConfig, baseEnv) {
|
|
|
22
23
|
}
|
|
23
24
|
return env;
|
|
24
25
|
}
|
|
25
|
-
export function resolveProviderSpawn(provider, config, baseEnv, cwd) {
|
|
26
|
+
export function resolveProviderSpawn(provider, config, baseEnv, cwd, extraArgs = []) {
|
|
26
27
|
const providerConfig = config.providers[provider];
|
|
27
28
|
const registryEntry = getAcpProviderEntry(provider);
|
|
28
29
|
let command;
|
|
@@ -38,8 +39,9 @@ export function resolveProviderSpawn(provider, config, baseEnv, cwd) {
|
|
|
38
39
|
else {
|
|
39
40
|
throw new ProviderUnavailableError(provider, "no ACP entrypoint configured and provider has no native ACP entrypoint", { provider });
|
|
40
41
|
}
|
|
42
|
+
const combinedArgs = [...args, ...extraArgs];
|
|
41
43
|
assertSafeExecutable(command, provider);
|
|
42
|
-
for (const arg of
|
|
44
|
+
for (const arg of combinedArgs) {
|
|
43
45
|
if (typeof arg !== "string") {
|
|
44
46
|
throw new ProviderUnavailableError(provider, "ACP args must be strings", { provider });
|
|
45
47
|
}
|
|
@@ -53,7 +55,7 @@ export function resolveProviderSpawn(provider, config, baseEnv, cwd) {
|
|
|
53
55
|
};
|
|
54
56
|
return {
|
|
55
57
|
command,
|
|
56
|
-
args: [...
|
|
58
|
+
args: [...combinedArgs],
|
|
57
59
|
cwd: cwd ?? `${tmpdir()}/llm-gateway-acp-${provider}`,
|
|
58
60
|
env: buildProviderEnv(provider, effectiveConfig, baseEnv),
|
|
59
61
|
};
|
|
@@ -82,7 +84,7 @@ export class AcpProcessManager {
|
|
|
82
84
|
this.baseEnv = options.baseEnv ?? process.env;
|
|
83
85
|
}
|
|
84
86
|
async start(options) {
|
|
85
|
-
const resolved = resolveProviderSpawn(options.provider, this.config, this.baseEnv, options.cwd);
|
|
87
|
+
const resolved = resolveProviderSpawn(options.provider, this.config, this.baseEnv, options.cwd, options.extraArgs);
|
|
86
88
|
let child;
|
|
87
89
|
try {
|
|
88
90
|
child = this.spawnFn(resolved);
|
|
@@ -119,6 +121,7 @@ export class AcpProcessManager {
|
|
|
119
121
|
initializeTimeoutMs: this.config.initializeTimeoutMs,
|
|
120
122
|
sessionNewTimeoutMs: this.config.sessionNewTimeoutMs,
|
|
121
123
|
promptTimeoutMs: this.config.promptTimeoutMs,
|
|
124
|
+
allowMutatingSessionOps: this.config.allowMutatingSessionOps,
|
|
122
125
|
onTerminal: m => this.live.delete(m),
|
|
123
126
|
});
|
|
124
127
|
this.live.add(managed);
|
|
@@ -162,6 +165,7 @@ class ManagedProcessImpl {
|
|
|
162
165
|
_signal = null;
|
|
163
166
|
_terminalError = null;
|
|
164
167
|
idleTimer = null;
|
|
168
|
+
killTimer = null;
|
|
165
169
|
constructor(options) {
|
|
166
170
|
this.provider = options.provider;
|
|
167
171
|
this.child = options.child;
|
|
@@ -199,6 +203,7 @@ class ManagedProcessImpl {
|
|
|
199
203
|
sessionNewMs: options.sessionNewTimeoutMs,
|
|
200
204
|
promptMs: options.promptTimeoutMs,
|
|
201
205
|
},
|
|
206
|
+
allowMutatingSessionOps: options.allowMutatingSessionOps ?? false,
|
|
202
207
|
});
|
|
203
208
|
options.child.on("exit", (code, signal) => this.handleExit(code, signal));
|
|
204
209
|
options.child.on("error", err => this.handleSpawnError(err));
|
|
@@ -259,7 +264,37 @@ class ManagedProcessImpl {
|
|
|
259
264
|
this.idleTimer = null;
|
|
260
265
|
}
|
|
261
266
|
}
|
|
267
|
+
armKillTimer() {
|
|
268
|
+
if (this.killTimer || SHUTDOWN_KILL_GRACE_MS <= 0) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
this.killTimer = setTimeout(() => {
|
|
272
|
+
this.killTimer = null;
|
|
273
|
+
try {
|
|
274
|
+
this.child.kill("SIGKILL");
|
|
275
|
+
this.logger.info("acp.process.force_killed", {
|
|
276
|
+
provider: this.provider,
|
|
277
|
+
pid: this.pid,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
this.logger.error("acp.process.kill_failed", {
|
|
282
|
+
provider: this.provider,
|
|
283
|
+
pid: this.pid,
|
|
284
|
+
errorClass: err instanceof Error ? err.name : "unknown",
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}, SHUTDOWN_KILL_GRACE_MS);
|
|
288
|
+
this.killTimer.unref?.();
|
|
289
|
+
}
|
|
290
|
+
clearKillTimer() {
|
|
291
|
+
if (this.killTimer) {
|
|
292
|
+
clearTimeout(this.killTimer);
|
|
293
|
+
this.killTimer = null;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
262
296
|
handleExit(code, signal) {
|
|
297
|
+
this.clearKillTimer();
|
|
263
298
|
if (this._state === "exited" || this._state === "quarantined") {
|
|
264
299
|
this._exitCode = code;
|
|
265
300
|
this._signal = signal;
|
|
@@ -322,6 +357,7 @@ class ManagedProcessImpl {
|
|
|
322
357
|
this.client.notifyProcessExit(error);
|
|
323
358
|
try {
|
|
324
359
|
this.child.kill("SIGTERM");
|
|
360
|
+
this.armKillTimer();
|
|
325
361
|
}
|
|
326
362
|
catch (err) {
|
|
327
363
|
this.logger.error("acp.process.kill_failed", {
|
|
@@ -348,6 +384,9 @@ class ManagedProcessImpl {
|
|
|
348
384
|
if (wasRunning) {
|
|
349
385
|
try {
|
|
350
386
|
this.child.kill(signal);
|
|
387
|
+
if (signal !== "SIGKILL") {
|
|
388
|
+
this.armKillTimer();
|
|
389
|
+
}
|
|
351
390
|
}
|
|
352
391
|
catch (err) {
|
|
353
392
|
this.logger.error("acp.process.kill_failed", {
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import { getProviderDefinition } from "../provider-definitions.js";
|
|
2
|
+
function acpEntrypointFromDefinition(provider) {
|
|
3
|
+
const entry = getProviderDefinition(provider).acp.entrypoint;
|
|
4
|
+
if (!entry) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return Object.freeze({ command: entry.command, args: Object.freeze([...entry.args]) });
|
|
8
|
+
}
|
|
1
9
|
const ACP_PROVIDER_REGISTRY = Object.freeze({
|
|
2
10
|
mistral: Object.freeze({
|
|
3
11
|
provider: "mistral",
|
|
4
12
|
displayName: "Mistral Vibe",
|
|
5
13
|
status: "native_smoke_passed",
|
|
6
14
|
supportKind: "native",
|
|
7
|
-
targetVersion: "vibe 2.
|
|
8
|
-
entrypoint:
|
|
15
|
+
targetVersion: "vibe 2.18.3",
|
|
16
|
+
entrypoint: acpEntrypointFromDefinition("mistral"),
|
|
9
17
|
runtimeEnabledDefault: false,
|
|
10
18
|
shipRuntimePilot: true,
|
|
11
19
|
runtimePriority: 1,
|
|
@@ -17,8 +25,8 @@ const ACP_PROVIDER_REGISTRY = Object.freeze({
|
|
|
17
25
|
displayName: "xAI Grok CLI",
|
|
18
26
|
status: "native_smoke_passed",
|
|
19
27
|
supportKind: "native",
|
|
20
|
-
targetVersion: "grok 0.2.
|
|
21
|
-
entrypoint:
|
|
28
|
+
targetVersion: "grok 0.2.77 (44e77bec3a)",
|
|
29
|
+
entrypoint: acpEntrypointFromDefinition("grok"),
|
|
22
30
|
runtimeEnabledDefault: false,
|
|
23
31
|
shipRuntimePilot: true,
|
|
24
32
|
runtimePriority: 2,
|
|
@@ -31,7 +39,7 @@ const ACP_PROVIDER_REGISTRY = Object.freeze({
|
|
|
31
39
|
status: "adapter_mediated_deferred",
|
|
32
40
|
supportKind: "adapter_mediated",
|
|
33
41
|
targetVersion: "codex-cli 0.142.4",
|
|
34
|
-
entrypoint:
|
|
42
|
+
entrypoint: acpEntrypointFromDefinition("codex"),
|
|
35
43
|
runtimeEnabledDefault: false,
|
|
36
44
|
shipRuntimePilot: false,
|
|
37
45
|
runtimePriority: 0,
|
|
@@ -43,8 +51,8 @@ const ACP_PROVIDER_REGISTRY = Object.freeze({
|
|
|
43
51
|
displayName: "Anthropic Claude Code",
|
|
44
52
|
status: "adapter_mediated_deferred",
|
|
45
53
|
supportKind: "adapter_mediated",
|
|
46
|
-
targetVersion: "claude 2.1.
|
|
47
|
-
entrypoint:
|
|
54
|
+
targetVersion: "claude 2.1.198",
|
|
55
|
+
entrypoint: acpEntrypointFromDefinition("claude"),
|
|
48
56
|
runtimeEnabledDefault: false,
|
|
49
57
|
shipRuntimePilot: false,
|
|
50
58
|
runtimePriority: 0,
|
|
@@ -56,8 +64,8 @@ const ACP_PROVIDER_REGISTRY = Object.freeze({
|
|
|
56
64
|
displayName: "Google Antigravity",
|
|
57
65
|
status: "absent_watchlist",
|
|
58
66
|
supportKind: "none",
|
|
59
|
-
targetVersion: "agy 1.0.
|
|
60
|
-
entrypoint:
|
|
67
|
+
targetVersion: "agy 1.0.14",
|
|
68
|
+
entrypoint: acpEntrypointFromDefinition("gemini"),
|
|
61
69
|
runtimeEnabledDefault: false,
|
|
62
70
|
shipRuntimePilot: false,
|
|
63
71
|
runtimePriority: 0,
|
|
@@ -70,7 +78,7 @@ const ACP_PROVIDER_REGISTRY = Object.freeze({
|
|
|
70
78
|
status: "native_smoke_passed",
|
|
71
79
|
supportKind: "native",
|
|
72
80
|
targetVersion: "devin 2026.8.18 (16737566)",
|
|
73
|
-
entrypoint:
|
|
81
|
+
entrypoint: acpEntrypointFromDefinition("devin"),
|
|
74
82
|
runtimeEnabledDefault: false,
|
|
75
83
|
shipRuntimePilot: true,
|
|
76
84
|
runtimePriority: 3,
|
|
@@ -83,7 +91,7 @@ const ACP_PROVIDER_REGISTRY = Object.freeze({
|
|
|
83
91
|
status: "native_smoke_passed",
|
|
84
92
|
supportKind: "native",
|
|
85
93
|
targetVersion: "cursor-agent 2026.06.29-2ad2186",
|
|
86
|
-
entrypoint:
|
|
94
|
+
entrypoint: acpEntrypointFromDefinition("cursor"),
|
|
87
95
|
runtimeEnabledDefault: false,
|
|
88
96
|
shipRuntimePilot: true,
|
|
89
97
|
runtimePriority: 4,
|
package/dist/acp/runtime.d.ts
CHANGED
|
@@ -25,11 +25,19 @@ export interface AcpRunRequest {
|
|
|
25
25
|
readonly sessionId?: string;
|
|
26
26
|
readonly cwd?: string;
|
|
27
27
|
readonly correlationId: string;
|
|
28
|
+
readonly agentType?: string;
|
|
28
29
|
}
|
|
29
30
|
export interface AcpRunResult {
|
|
30
31
|
readonly text: string;
|
|
31
32
|
readonly gatewaySessionId: string;
|
|
32
33
|
readonly protocolVersion: number | null;
|
|
33
34
|
readonly durationMs: number;
|
|
35
|
+
readonly stopReason: string | null;
|
|
34
36
|
}
|
|
37
|
+
export interface AcpPromptUsage {
|
|
38
|
+
inputTokens?: number;
|
|
39
|
+
outputTokens?: number;
|
|
40
|
+
cacheReadTokens?: number;
|
|
41
|
+
}
|
|
42
|
+
export declare function extractAcpPromptUsage(meta: unknown): AcpPromptUsage;
|
|
35
43
|
export declare function runAcpRequest(deps: AcpRuntimeDeps, req: AcpRunRequest): Promise<AcpRunResult>;
|
package/dist/acp/runtime.js
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
import { AcpEventNormalizer } from "./event-normalizer.js";
|
|
2
|
-
import { AcpDisabledError, AcpError, AcpProtocolError, ProviderRuntimeDisabledError, isAcpError, } from "./errors.js";
|
|
2
|
+
import { AcpDisabledError, AcpError, AcpProtocolError, ProviderAcpDisabledError, ProviderRuntimeDisabledError, isAcpError, } from "./errors.js";
|
|
3
3
|
import { buildAcpFlightResult, buildAcpFlightStart } from "./flight-redaction.js";
|
|
4
4
|
import { GatewayHostServices } from "./host-services.js";
|
|
5
5
|
import { createAcpPermissionDecider } from "./permission-bridge.js";
|
|
6
6
|
import { AcpProcessManager } from "./process-manager.js";
|
|
7
7
|
import { createAcpSession, recordAcpSessionInfo, resolveAcpResume } from "./session-map.js";
|
|
8
|
+
import { DEVIN_ACP_AGENT_TYPES } from "../provider-definitions.js";
|
|
8
9
|
import { noopLogger } from "../logger.js";
|
|
10
|
+
export function extractAcpPromptUsage(meta) {
|
|
11
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta))
|
|
12
|
+
return {};
|
|
13
|
+
const record = meta;
|
|
14
|
+
const num = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
15
|
+
const usage = {};
|
|
16
|
+
const inputTokens = num(record.inputTokens);
|
|
17
|
+
if (inputTokens !== undefined)
|
|
18
|
+
usage.inputTokens = inputTokens;
|
|
19
|
+
const outputTokens = num(record.outputTokens);
|
|
20
|
+
if (outputTokens !== undefined)
|
|
21
|
+
usage.outputTokens = outputTokens;
|
|
22
|
+
const cacheReadTokens = num(record.cachedReadTokens);
|
|
23
|
+
if (cacheReadTokens !== undefined)
|
|
24
|
+
usage.cacheReadTokens = cacheReadTokens;
|
|
25
|
+
return usage;
|
|
26
|
+
}
|
|
9
27
|
export async function runAcpRequest(deps, req) {
|
|
10
28
|
const logger = deps.logger ?? noopLogger;
|
|
11
29
|
const now = deps.now ?? Date.now;
|
|
@@ -15,7 +33,10 @@ export async function runAcpRequest(deps, req) {
|
|
|
15
33
|
throw new AcpDisabledError({ provider: req.provider });
|
|
16
34
|
}
|
|
17
35
|
const providerConfig = deps.config.providers[req.provider];
|
|
18
|
-
if (
|
|
36
|
+
if (providerConfig?.enabled !== true) {
|
|
37
|
+
throw new ProviderAcpDisabledError(req.provider, { provider: req.provider });
|
|
38
|
+
}
|
|
39
|
+
if (providerConfig?.runtimeEnabled !== true) {
|
|
19
40
|
throw new ProviderRuntimeDisabledError(req.provider, { provider: req.provider });
|
|
20
41
|
}
|
|
21
42
|
const permissionDecider = createAcpPermissionDecider({
|
|
@@ -60,6 +81,11 @@ export async function runAcpRequest(deps, req) {
|
|
|
60
81
|
prompt: promptBlocks,
|
|
61
82
|
gatewaySessionId,
|
|
62
83
|
}));
|
|
84
|
+
const extraArgs = req.provider === "devin" &&
|
|
85
|
+
req.agentType !== undefined &&
|
|
86
|
+
DEVIN_ACP_AGENT_TYPES.includes(req.agentType)
|
|
87
|
+
? ["--agent-type", req.agentType]
|
|
88
|
+
: [];
|
|
63
89
|
let proc = null;
|
|
64
90
|
try {
|
|
65
91
|
proc = await manager.start({
|
|
@@ -67,6 +93,7 @@ export async function runAcpRequest(deps, req) {
|
|
|
67
93
|
cwd: req.cwd,
|
|
68
94
|
hostServices,
|
|
69
95
|
callbacks: { onSessionUpdate: update => normalizer.handle(update) },
|
|
96
|
+
extraArgs,
|
|
70
97
|
});
|
|
71
98
|
const cwd = proc.resolved.cwd;
|
|
72
99
|
const init = proc.client.agentInfo;
|
|
@@ -85,16 +112,32 @@ export async function runAcpRequest(deps, req) {
|
|
|
85
112
|
agentVersion: init?.agentInfo?.version,
|
|
86
113
|
});
|
|
87
114
|
}
|
|
88
|
-
await proc.client.prompt({
|
|
115
|
+
const promptResult = await proc.client.prompt({
|
|
116
|
+
sessionId: providerSessionId,
|
|
117
|
+
prompt: promptBlocks,
|
|
118
|
+
});
|
|
119
|
+
normalizer.completeWith(promptResult.stopReason);
|
|
89
120
|
const text = normalizer.finalText;
|
|
90
121
|
const durationMs = elapsed();
|
|
91
|
-
|
|
122
|
+
const usage = extractAcpPromptUsage(promptResult._meta);
|
|
123
|
+
deps.flightRecorder?.logComplete(req.correlationId, buildAcpFlightResult({
|
|
124
|
+
responseText: text,
|
|
125
|
+
durationMs,
|
|
126
|
+
status: "completed",
|
|
127
|
+
exitCode: 0,
|
|
128
|
+
providerSessionId,
|
|
129
|
+
stopReason: normalizer.stopReason,
|
|
130
|
+
inputTokens: usage.inputTokens,
|
|
131
|
+
outputTokens: usage.outputTokens,
|
|
132
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
133
|
+
}));
|
|
92
134
|
logger.info("acp.request.success", { provider: req.provider, durationMs });
|
|
93
135
|
return {
|
|
94
136
|
text,
|
|
95
137
|
gatewaySessionId,
|
|
96
138
|
protocolVersion: init?.protocolVersion ?? null,
|
|
97
139
|
durationMs,
|
|
140
|
+
stopReason: normalizer.stopReason ?? null,
|
|
98
141
|
};
|
|
99
142
|
}
|
|
100
143
|
catch (err) {
|