llm-cli-gateway 2.6.3 → 2.8.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.
@@ -0,0 +1,335 @@
1
+ import { z } from "zod/v3";
2
+ import { AcpProtocolError } from "./errors.js";
3
+ export const ProtocolVersionSchema = z.number().int().nonnegative();
4
+ export const SessionIdSchema = z.string().min(1);
5
+ const MetaSchema = z.record(z.unknown()).optional();
6
+ const KNOWN_CONTENT_BLOCK_TYPES = new Set(["text", "image", "audio", "resource_link", "resource"]);
7
+ export const ContentBlockSchema = z.lazy(() => z.union([
8
+ z.object({ type: z.literal("text"), text: z.string(), _meta: MetaSchema }).passthrough(),
9
+ z
10
+ .object({
11
+ type: z.literal("image"),
12
+ data: z.string(),
13
+ mimeType: z.string(),
14
+ _meta: MetaSchema,
15
+ })
16
+ .passthrough(),
17
+ z
18
+ .object({
19
+ type: z.literal("audio"),
20
+ data: z.string(),
21
+ mimeType: z.string(),
22
+ _meta: MetaSchema,
23
+ })
24
+ .passthrough(),
25
+ z
26
+ .object({
27
+ type: z.literal("resource_link"),
28
+ uri: z.string(),
29
+ _meta: MetaSchema,
30
+ })
31
+ .passthrough(),
32
+ z.object({ type: z.literal("resource"), _meta: MetaSchema }).passthrough(),
33
+ z
34
+ .object({
35
+ type: z.string().refine(t => !KNOWN_CONTENT_BLOCK_TYPES.has(t), {
36
+ message: "known content block type missing required fields",
37
+ }),
38
+ })
39
+ .passthrough(),
40
+ ]));
41
+ export const ClientFsCapabilitiesSchema = z
42
+ .object({
43
+ readTextFile: z.boolean().optional(),
44
+ writeTextFile: z.boolean().optional(),
45
+ })
46
+ .passthrough();
47
+ export const ClientCapabilitiesSchema = z
48
+ .object({
49
+ fs: ClientFsCapabilitiesSchema.optional(),
50
+ terminal: z.boolean().optional(),
51
+ })
52
+ .passthrough();
53
+ export const InitializeRequestSchema = z
54
+ .object({
55
+ protocolVersion: ProtocolVersionSchema,
56
+ clientCapabilities: ClientCapabilitiesSchema.optional(),
57
+ _meta: MetaSchema,
58
+ })
59
+ .passthrough();
60
+ export const InitializeResponseSchema = z
61
+ .object({
62
+ protocolVersion: ProtocolVersionSchema,
63
+ agentCapabilities: z.record(z.unknown()).optional(),
64
+ agentInfo: z
65
+ .object({
66
+ name: z.string().optional(),
67
+ version: z.string().optional(),
68
+ })
69
+ .passthrough()
70
+ .optional(),
71
+ authMethods: z.array(z.record(z.unknown())).optional(),
72
+ _meta: MetaSchema,
73
+ })
74
+ .passthrough();
75
+ export const McpServerSchema = z.record(z.unknown());
76
+ export const SessionNewRequestSchema = z
77
+ .object({
78
+ cwd: z.string().min(1),
79
+ mcpServers: z.array(McpServerSchema).default([]),
80
+ _meta: MetaSchema,
81
+ })
82
+ .passthrough();
83
+ export const SessionNewResponseSchema = z
84
+ .object({
85
+ sessionId: SessionIdSchema,
86
+ modes: z.record(z.unknown()).optional(),
87
+ _meta: MetaSchema,
88
+ })
89
+ .passthrough();
90
+ export const SessionLoadRequestSchema = z
91
+ .object({
92
+ sessionId: SessionIdSchema,
93
+ cwd: z.string().min(1),
94
+ mcpServers: z.array(McpServerSchema).default([]),
95
+ _meta: MetaSchema,
96
+ })
97
+ .passthrough();
98
+ export const SessionLoadResponseSchema = z
99
+ .object({
100
+ modes: z.record(z.unknown()).optional(),
101
+ _meta: MetaSchema,
102
+ })
103
+ .passthrough();
104
+ export const SessionPromptRequestSchema = z
105
+ .object({
106
+ sessionId: SessionIdSchema,
107
+ prompt: z.array(ContentBlockSchema).min(1),
108
+ _meta: MetaSchema,
109
+ })
110
+ .passthrough();
111
+ export const STOP_REASONS = [
112
+ "end_turn",
113
+ "max_tokens",
114
+ "max_turn_requests",
115
+ "refusal",
116
+ "cancelled",
117
+ ];
118
+ export const SessionPromptResponseSchema = z
119
+ .object({
120
+ stopReason: z.string().min(1),
121
+ _meta: MetaSchema,
122
+ })
123
+ .passthrough();
124
+ export const SessionCancelNotificationSchema = z
125
+ .object({
126
+ sessionId: SessionIdSchema,
127
+ _meta: MetaSchema,
128
+ })
129
+ .passthrough();
130
+ const MessageChunkUpdate = (variant) => z
131
+ .object({
132
+ sessionUpdate: z.literal(variant),
133
+ content: ContentBlockSchema,
134
+ messageId: z.string().nullish(),
135
+ _meta: MetaSchema,
136
+ })
137
+ .passthrough();
138
+ const ToolCallUpdate = z
139
+ .object({
140
+ sessionUpdate: z.literal("tool_call"),
141
+ toolCallId: z.string().min(1),
142
+ title: z.string(),
143
+ status: z.string().optional(),
144
+ kind: z.string().optional(),
145
+ _meta: MetaSchema,
146
+ })
147
+ .passthrough();
148
+ const ToolCallUpdateUpdate = z
149
+ .object({
150
+ sessionUpdate: z.literal("tool_call_update"),
151
+ toolCallId: z.string().min(1),
152
+ status: z.string().nullish(),
153
+ title: z.string().nullish(),
154
+ _meta: MetaSchema,
155
+ })
156
+ .passthrough();
157
+ const PlanUpdate = z
158
+ .object({
159
+ sessionUpdate: z.literal("plan"),
160
+ entries: z.array(z.record(z.unknown())),
161
+ _meta: MetaSchema,
162
+ })
163
+ .passthrough();
164
+ const AvailableCommandsUpdate = z
165
+ .object({
166
+ sessionUpdate: z.literal("available_commands_update"),
167
+ availableCommands: z.array(z.record(z.unknown())),
168
+ _meta: MetaSchema,
169
+ })
170
+ .passthrough();
171
+ const CurrentModeUpdate = z
172
+ .object({
173
+ sessionUpdate: z.literal("current_mode_update"),
174
+ currentModeId: z.string().min(1),
175
+ _meta: MetaSchema,
176
+ })
177
+ .passthrough();
178
+ const UsageUpdate = z
179
+ .object({
180
+ sessionUpdate: z.literal("usage_update"),
181
+ size: z.number().int().nonnegative(),
182
+ used: z.number().int().nonnegative(),
183
+ cost: z.record(z.unknown()).nullish(),
184
+ _meta: MetaSchema,
185
+ })
186
+ .passthrough();
187
+ const KNOWN_UPDATE_SCHEMAS = {
188
+ user_message_chunk: MessageChunkUpdate("user_message_chunk"),
189
+ agent_message_chunk: MessageChunkUpdate("agent_message_chunk"),
190
+ agent_thought_chunk: MessageChunkUpdate("agent_thought_chunk"),
191
+ tool_call: ToolCallUpdate,
192
+ tool_call_update: ToolCallUpdateUpdate,
193
+ plan: PlanUpdate,
194
+ available_commands_update: AvailableCommandsUpdate,
195
+ current_mode_update: CurrentModeUpdate,
196
+ usage_update: UsageUpdate,
197
+ };
198
+ export const SessionUpdateSchema = z
199
+ .object({ sessionUpdate: z.string().min(1) })
200
+ .passthrough()
201
+ .superRefine((value, ctx) => {
202
+ const known = KNOWN_UPDATE_SCHEMAS[value.sessionUpdate];
203
+ if (!known) {
204
+ return;
205
+ }
206
+ const result = known.safeParse(value);
207
+ if (!result.success) {
208
+ for (const issue of result.error.issues) {
209
+ ctx.addIssue(issue);
210
+ }
211
+ }
212
+ });
213
+ export const SessionUpdateNotificationSchema = z
214
+ .object({
215
+ sessionId: SessionIdSchema,
216
+ update: SessionUpdateSchema,
217
+ _meta: MetaSchema,
218
+ })
219
+ .passthrough();
220
+ export const KNOWN_SESSION_UPDATE_VARIANTS = [
221
+ "user_message_chunk",
222
+ "agent_message_chunk",
223
+ "agent_thought_chunk",
224
+ "tool_call",
225
+ "tool_call_update",
226
+ "plan",
227
+ "available_commands_update",
228
+ "current_mode_update",
229
+ "config_option_update",
230
+ "session_info_update",
231
+ "usage_update",
232
+ ];
233
+ export function isUnknownSessionUpdate(update) {
234
+ return !KNOWN_SESSION_UPDATE_VARIANTS.includes(update.sessionUpdate);
235
+ }
236
+ export const PermissionOptionSchema = z
237
+ .object({
238
+ optionId: z.string().min(1),
239
+ name: z.string(),
240
+ kind: z.string().optional(),
241
+ _meta: MetaSchema,
242
+ })
243
+ .passthrough();
244
+ export const RequestPermissionRequestSchema = z
245
+ .object({
246
+ sessionId: SessionIdSchema,
247
+ options: z.array(PermissionOptionSchema).min(1),
248
+ toolCall: z.record(z.unknown()),
249
+ _meta: MetaSchema,
250
+ })
251
+ .passthrough();
252
+ export const RequestPermissionOutcomeSchema = z.union([
253
+ z.object({ outcome: z.literal("cancelled") }).passthrough(),
254
+ z.object({ outcome: z.literal("selected"), optionId: z.string().min(1) }).passthrough(),
255
+ ]);
256
+ export const RequestPermissionResponseSchema = z
257
+ .object({
258
+ outcome: RequestPermissionOutcomeSchema,
259
+ _meta: MetaSchema,
260
+ })
261
+ .passthrough();
262
+ export const ReadTextFileRequestSchema = z
263
+ .object({
264
+ sessionId: SessionIdSchema,
265
+ path: z.string().min(1),
266
+ line: z.number().int().nonnegative().nullish(),
267
+ limit: z.number().int().nonnegative().nullish(),
268
+ _meta: MetaSchema,
269
+ })
270
+ .passthrough();
271
+ export const ReadTextFileResponseSchema = z
272
+ .object({
273
+ content: z.string(),
274
+ _meta: MetaSchema,
275
+ })
276
+ .passthrough();
277
+ export const WriteTextFileRequestSchema = z
278
+ .object({
279
+ sessionId: SessionIdSchema,
280
+ path: z.string().min(1),
281
+ content: z.string(),
282
+ _meta: MetaSchema,
283
+ })
284
+ .passthrough();
285
+ export const WriteTextFileResponseSchema = z.object({ _meta: MetaSchema }).passthrough();
286
+ export function parseAcp(schema, value, context) {
287
+ const result = schema.safeParse(value);
288
+ if (result.success) {
289
+ return result.data;
290
+ }
291
+ const issuePaths = result.error.issues.map(issue => ({
292
+ path: issue.path.join("."),
293
+ code: issue.code,
294
+ }));
295
+ throw new AcpProtocolError(`Malformed ACP ${context.method} payload`, {
296
+ provider: context.provider,
297
+ debug: { method: context.method, issues: issuePaths },
298
+ });
299
+ }
300
+ export function parseInitializeResponse(value, provider) {
301
+ return parseAcp(InitializeResponseSchema, value, { method: "initialize", provider });
302
+ }
303
+ export function parseSessionNewResponse(value, provider) {
304
+ return parseAcp(SessionNewResponseSchema, value, { method: "session/new", provider });
305
+ }
306
+ export function parseSessionLoadResponse(value, provider) {
307
+ return parseAcp(SessionLoadResponseSchema, value, { method: "session/load", provider });
308
+ }
309
+ export function parseSessionPromptResponse(value, provider) {
310
+ return parseAcp(SessionPromptResponseSchema, value, { method: "session/prompt", provider });
311
+ }
312
+ export function parseSessionUpdateNotification(value, provider) {
313
+ return parseAcp(SessionUpdateNotificationSchema, value, {
314
+ method: "session/update",
315
+ provider,
316
+ });
317
+ }
318
+ export function parseRequestPermissionRequest(value, provider) {
319
+ return parseAcp(RequestPermissionRequestSchema, value, {
320
+ method: "session/request_permission",
321
+ provider,
322
+ });
323
+ }
324
+ export function parseReadTextFileRequest(value, provider) {
325
+ return parseAcp(ReadTextFileRequestSchema, value, {
326
+ method: "fs/read_text_file",
327
+ provider,
328
+ });
329
+ }
330
+ export function parseWriteTextFileRequest(value, provider) {
331
+ return parseAcp(WriteTextFileRequestSchema, value, {
332
+ method: "fs/write_text_file",
333
+ provider,
334
+ });
335
+ }
@@ -67,6 +67,7 @@ export declare class AsyncJobManager {
67
67
  private store;
68
68
  private flightRecorder;
69
69
  constructor(logger?: Logger, onJobComplete?: ((cli: LlmCli, durationMs: number, success: boolean) => void) | undefined, store?: JobStore | null, flightRecorder?: FlightRecorderLike);
70
+ private buildOrphanFlightResult;
70
71
  checkStalledJobs(now?: number): void;
71
72
  hasStore(): boolean;
72
73
  private emitMetrics;
@@ -103,6 +104,7 @@ export declare class AsyncJobManager {
103
104
  jobs: JobHealth[];
104
105
  };
105
106
  getJobOutputFormat(jobId: string): string | undefined;
107
+ getJobCli(jobId: string): LlmCli | undefined;
106
108
  private snapshot;
107
109
  private appendOutput;
108
110
  }
@@ -3,7 +3,8 @@ import { envWithExtendedPath, getExtendedPath, killProcessGroup, providerCommand
3
3
  import { noopLogger, logWarn } from "./logger.js";
4
4
  import { ProcessMonitor } from "./process-monitor.js";
5
5
  import { computeRequestKey } from "./job-store.js";
6
- import { NoopFlightRecorder } from "./flight-recorder.js";
6
+ import { NoopFlightRecorder, } from "./flight-recorder.js";
7
+ import { codexFrResponse } from "./codex-json-parser.js";
7
8
  const MAX_OUTPUT_SIZE = 50 * 1024 * 1024;
8
9
  const JOB_TTL_MS = 60 * 60 * 1000;
9
10
  const EVICTION_INTERVAL_MS = 5 * 60 * 1000;
@@ -75,17 +76,7 @@ export class AsyncJobManager {
75
76
  }
76
77
  for (const orphan of orphaned) {
77
78
  try {
78
- const durationMs = Math.max(0, Date.now() - new Date(orphan.startedAt).getTime());
79
- this.flightRecorder.logComplete(orphan.correlationId, {
80
- response: orphan.stderr || orphan.stdout,
81
- durationMs,
82
- retryCount: 0,
83
- circuitBreakerState: "closed",
84
- optimizationApplied: false,
85
- exitCode: orphan.exitCode ?? 1,
86
- errorMessage: "orphaned after gateway restart",
87
- status: "failed",
88
- });
79
+ this.flightRecorder.logComplete(orphan.correlationId, this.buildOrphanFlightResult(orphan));
89
80
  }
90
81
  catch (err) {
91
82
  this.logger.error(`Async-path FR logComplete for orphaned job ${orphan.id} failed`, err);
@@ -105,6 +96,33 @@ export class AsyncJobManager {
105
96
  this.stallTimer.unref();
106
97
  }
107
98
  }
99
+ buildOrphanFlightResult(orphan) {
100
+ const durationMs = Math.max(0, Date.now() - new Date(orphan.startedAt).getTime());
101
+ const hasCapturedStdout = orphan.stdout.length > 0;
102
+ const hasKnownSuccessfulExit = orphan.exitCode === 0;
103
+ const hasCapturedResponseWithoutFailure = orphan.exitCode === null && hasCapturedStdout;
104
+ if (hasKnownSuccessfulExit || hasCapturedResponseWithoutFailure) {
105
+ return {
106
+ response: orphan.stdout,
107
+ durationMs,
108
+ retryCount: 0,
109
+ circuitBreakerState: "closed",
110
+ optimizationApplied: false,
111
+ exitCode: 0,
112
+ status: "completed",
113
+ };
114
+ }
115
+ return {
116
+ response: orphan.stderr || orphan.stdout,
117
+ durationMs,
118
+ retryCount: 0,
119
+ circuitBreakerState: "closed",
120
+ optimizationApplied: false,
121
+ exitCode: orphan.exitCode ?? 1,
122
+ errorMessage: "orphaned after gateway restart",
123
+ status: "failed",
124
+ };
125
+ }
108
126
  checkStalledJobs(now = Date.now()) {
109
127
  for (const job of this.jobs.values()) {
110
128
  if (job.status !== "running")
@@ -218,10 +236,11 @@ export class AsyncJobManager {
218
236
  }
219
237
  }
220
238
  }
221
- buildRequestKey(cli, args, env, stdin, cwd) {
239
+ buildRequestKey(cli, args, env, stdin, cwd, outputFormat) {
222
240
  const extraEnv = canonicaliseEnvForKey(env);
223
241
  const withStdin = stdin === undefined ? extraEnv : `${extraEnv}|stdin:${stdin}`;
224
- const extra = cwd === undefined ? withStdin : `${withStdin}|cwd:${cwd}`;
242
+ const withCwd = cwd === undefined ? withStdin : `${withStdin}|cwd:${cwd}`;
243
+ const extra = cli === "codex" ? `${withCwd}|fmt:${outputFormat ?? "text"}` : withCwd;
225
244
  return computeRequestKey(cli, args, extra);
226
245
  }
227
246
  fireOnComplete(job) {
@@ -247,7 +266,14 @@ export class AsyncJobManager {
247
266
  const durationMs = Math.max(0, Date.now() - new Date(job.startedAt).getTime());
248
267
  const usage = finalStatus === "completed" && job.extractUsage ? this.safeExtractUsage(job) : {};
249
268
  const isFailure = finalStatus === "failed";
250
- const response = isFailure ? job.stderr || job.stdout : job.stdout;
269
+ let response;
270
+ if (job.cli === "codex") {
271
+ const codexText = codexFrResponse(job.outputFormat, job.stdout);
272
+ response = isFailure ? job.stderr || codexText : codexText;
273
+ }
274
+ else {
275
+ response = isFailure ? job.stderr || job.stdout : job.stdout;
276
+ }
251
277
  const exitCode = job.exitCode ?? (finalStatus === "completed" ? 0 : 1);
252
278
  const errorMessage = isFailure
253
279
  ? (overrideErrorMessage ?? job.error ?? job.stderr ?? `Exit code ${exitCode}`)
@@ -402,7 +428,7 @@ export class AsyncJobManager {
402
428
  }
403
429
  startJobWithDedup(cli, args, correlationId, opts = {}) {
404
430
  const { cwd, idleTimeoutMs, outputFormat, forceRefresh, env: extraEnv, stdin, onComplete, flightRecorderEntry, extractUsage, writeFlightStart, } = opts;
405
- const requestKey = this.buildRequestKey(cli, args, extraEnv, stdin, cwd);
431
+ const requestKey = this.buildRequestKey(cli, args, extraEnv, stdin, cwd, outputFormat);
406
432
  if (!forceRefresh && this.store) {
407
433
  try {
408
434
  const existing = this.store.findByRequestKey(requestKey);
@@ -713,6 +739,9 @@ export class AsyncJobManager {
713
739
  getJobOutputFormat(jobId) {
714
740
  return this.jobs.get(jobId)?.outputFormat;
715
741
  }
742
+ getJobCli(jobId) {
743
+ return this.jobs.get(jobId)?.cli;
744
+ }
716
745
  snapshot(job) {
717
746
  return {
718
747
  id: job.id,
@@ -5,6 +5,11 @@ function safeNum(n) {
5
5
  function isCacheStatsCli(s) {
6
6
  return s === "claude" || s === "codex" || s === "gemini" || s === "grok" || s === "mistral";
7
7
  }
8
+ function normalizeCacheStatsCli(s) {
9
+ if (s === "grok-api")
10
+ return "grok";
11
+ return isCacheStatsCli(s) ? s : null;
12
+ }
8
13
  export function computeSessionCacheStats(db, sessionId) {
9
14
  const rows = db.queryRequests(`SELECT cli, model,
10
15
  COALESCE(cache_read_tokens, 0) AS cache_read_tokens,
@@ -34,10 +39,11 @@ export function computeSessionCacheStats(db, sessionId) {
34
39
  prefixSet.add(row.stable_prefix_hash);
35
40
  if (!lastAt || row.datetime_utc > lastAt)
36
41
  lastAt = row.datetime_utc;
37
- if (cli === null && isCacheStatsCli(row.cli))
38
- cli = row.cli;
39
- if (isCacheStatsCli(row.cli)) {
40
- estimatedSavingsUsd += estimateCacheSavingsUsd(row.cli, row.model, reads);
42
+ const rowCli = normalizeCacheStatsCli(row.cli);
43
+ if (cli === null && rowCli !== null)
44
+ cli = rowCli;
45
+ if (rowCli !== null) {
46
+ estimatedSavingsUsd += estimateCacheSavingsUsd(rowCli, row.model, reads);
41
47
  }
42
48
  }
43
49
  const requestCount = rows.length;
@@ -102,15 +108,16 @@ export function computePrefixCacheStats(db, stablePrefixHash) {
102
108
  if (!firstAt)
103
109
  firstAt = row.datetime_utc;
104
110
  lastAt = row.datetime_utc;
105
- if (isCacheStatsCli(row.cli)) {
106
- estimatedSavingsUsd += estimateCacheSavingsUsd(row.cli, row.model, reads);
107
- const key = `${row.cli}::${row.model}`;
111
+ const rowCli = normalizeCacheStatsCli(row.cli);
112
+ if (rowCli !== null) {
113
+ estimatedSavingsUsd += estimateCacheSavingsUsd(rowCli, row.model, reads);
114
+ const key = `${rowCli}::${row.model}`;
108
115
  const entry = cliMap.get(key);
109
116
  if (entry) {
110
117
  entry.count += 1;
111
118
  }
112
119
  else {
113
- cliMap.set(key, { cli: row.cli, model: row.model, count: 1 });
120
+ cliMap.set(key, { cli: rowCli, model: row.model, count: 1 });
114
121
  }
115
122
  }
116
123
  }
@@ -180,9 +187,9 @@ export function computeGlobalCacheStats(db, opts = {}) {
180
187
  arr.push({ datetime_utc: row.datetime_utc, cache_creation_tokens: creation });
181
188
  perPrefix.set(row.stable_prefix_hash, arr);
182
189
  }
183
- if (!isCacheStatsCli(row.cli))
190
+ const cli = normalizeCacheStatsCli(row.cli);
191
+ if (cli === null)
184
192
  continue;
185
- const cli = row.cli;
186
193
  const savings = estimateCacheSavingsUsd(cli, row.model, reads);
187
194
  totalSavings += savings;
188
195
  const agg = perCliMap.get(cli) ?? {
@@ -10,5 +10,8 @@ export interface CodexJsonParseResult {
10
10
  error?: string;
11
11
  threadId?: string;
12
12
  finalMessage?: string;
13
+ sawEvent?: boolean;
13
14
  }
14
15
  export declare function parseCodexJsonStream(stdout: string): CodexJsonParseResult;
16
+ export declare function codexDisplayText(stdout: string): string;
17
+ export declare function codexFrResponse(outputFormat: string | undefined, stdout: string): string;
@@ -13,6 +13,7 @@ export function parseCodexJsonStream(stdout) {
13
13
  if (!parsed || typeof parsed !== "object") {
14
14
  continue;
15
15
  }
16
+ result.sawEvent = true;
16
17
  switch (parsed.type) {
17
18
  case "thread.started":
18
19
  if (typeof parsed.thread_id === "string") {
@@ -85,3 +86,19 @@ export function parseCodexJsonStream(stdout) {
85
86
  }
86
87
  return result;
87
88
  }
89
+ export function codexDisplayText(stdout) {
90
+ const parsed = parseCodexJsonStream(stdout);
91
+ if (parsed.finalMessage !== undefined) {
92
+ return parsed.finalMessage;
93
+ }
94
+ if (parsed.error !== undefined) {
95
+ return parsed.error;
96
+ }
97
+ if (parsed.sawEvent) {
98
+ return "";
99
+ }
100
+ return stdout;
101
+ }
102
+ export function codexFrResponse(outputFormat, stdout) {
103
+ return outputFormat === "json" ? stdout : codexDisplayText(stdout);
104
+ }
package/dist/config.d.ts CHANGED
@@ -76,4 +76,34 @@ export interface ProvidersConfig {
76
76
  }
77
77
  export declare function loadProvidersConfig(logger?: Logger): ProvidersConfig;
78
78
  export declare function isXaiProviderEnabled(config: ProvidersConfig, env?: NodeJS.ProcessEnv): boolean;
79
+ export declare const ACP_TRANSPORTS: readonly ["cli", "acp"];
80
+ export type AcpTransport = (typeof ACP_TRANSPORTS)[number];
81
+ export declare const DEFAULT_ACP_PROCESS_IDLE_TIMEOUT_MS = 600000;
82
+ export declare const DEFAULT_ACP_INITIALIZE_TIMEOUT_MS = 10000;
83
+ export declare const DEFAULT_ACP_SESSION_NEW_TIMEOUT_MS = 10000;
84
+ export declare const DEFAULT_ACP_PROMPT_TIMEOUT_MS = 600000;
85
+ export interface AcpProviderConfig {
86
+ enabled: boolean;
87
+ command: string;
88
+ args: string[];
89
+ runtimeEnabled: boolean;
90
+ isolatedLeaderSocket: boolean;
91
+ }
92
+ export interface AcpConfig {
93
+ enabled: boolean;
94
+ defaultTransport: AcpTransport;
95
+ smokeOnStartup: boolean;
96
+ processIdleTimeoutMs: number;
97
+ initializeTimeoutMs: number;
98
+ sessionNewTimeoutMs: number;
99
+ promptTimeoutMs: number;
100
+ allowWriteHostServices: boolean;
101
+ allowTerminalHostServices: boolean;
102
+ fallbackToCliWhenUnhealthy: boolean;
103
+ providers: Record<string, AcpProviderConfig>;
104
+ sources: {
105
+ configFile: string | null;
106
+ };
107
+ }
108
+ export declare function loadAcpConfig(logger?: Logger): AcpConfig;
79
109
  export declare function loadRemoteOAuthConfig(logger?: Logger, env?: NodeJS.ProcessEnv): RemoteOAuthConfig;