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.
Files changed (79) hide show
  1. package/CHANGELOG.md +139 -0
  2. package/README.md +68 -29
  3. package/dist/acp/client.d.ts +29 -1
  4. package/dist/acp/client.js +78 -4
  5. package/dist/acp/errors.d.ts +9 -1
  6. package/dist/acp/errors.js +19 -0
  7. package/dist/acp/event-normalizer.d.ts +12 -0
  8. package/dist/acp/event-normalizer.js +16 -0
  9. package/dist/acp/flight-redaction.d.ts +3 -0
  10. package/dist/acp/flight-redaction.js +3 -0
  11. package/dist/acp/permission-bridge.js +11 -5
  12. package/dist/acp/process-manager.d.ts +2 -1
  13. package/dist/acp/process-manager.js +43 -4
  14. package/dist/acp/provider-registry.js +19 -11
  15. package/dist/acp/runtime.d.ts +8 -0
  16. package/dist/acp/runtime.js +47 -4
  17. package/dist/acp/types.d.ts +3083 -55
  18. package/dist/acp/types.js +242 -5
  19. package/dist/async-job-manager.d.ts +38 -1
  20. package/dist/async-job-manager.js +287 -20
  21. package/dist/codex-json-parser.d.ts +1 -0
  22. package/dist/codex-json-parser.js +6 -0
  23. package/dist/config.d.ts +19 -0
  24. package/dist/config.js +84 -1
  25. package/dist/flight-recorder.d.ts +2 -0
  26. package/dist/flight-recorder.js +20 -0
  27. package/dist/gemini-json-parser.d.ts +2 -0
  28. package/dist/gemini-json-parser.js +45 -8
  29. package/dist/grok-json-parser.d.ts +14 -0
  30. package/dist/grok-json-parser.js +156 -0
  31. package/dist/index.d.ts +47 -2
  32. package/dist/index.js +504 -122
  33. package/dist/job-store.d.ts +119 -11
  34. package/dist/job-store.js +372 -42
  35. package/dist/model-registry.d.ts +1 -0
  36. package/dist/model-registry.js +46 -0
  37. package/dist/oauth.js +2 -2
  38. package/dist/postgres-job-store-worker.d.ts +1 -0
  39. package/dist/postgres-job-store-worker.js +444 -0
  40. package/dist/pricing.d.ts +3 -2
  41. package/dist/provider-acp-capabilities.d.ts +52 -0
  42. package/dist/provider-acp-capabilities.js +101 -0
  43. package/dist/provider-admin-tools.d.ts +100 -0
  44. package/dist/provider-admin-tools.js +572 -0
  45. package/dist/provider-capability-cache.d.ts +46 -0
  46. package/dist/provider-capability-cache.js +248 -0
  47. package/dist/provider-capability-discovery.d.ts +85 -0
  48. package/dist/provider-capability-discovery.js +461 -0
  49. package/dist/provider-capability-resolver.d.ts +29 -0
  50. package/dist/provider-capability-resolver.js +92 -0
  51. package/dist/provider-definition-assertions.d.ts +9 -0
  52. package/dist/provider-definition-assertions.js +147 -0
  53. package/dist/provider-definitions.d.ts +127 -0
  54. package/dist/provider-definitions.js +758 -0
  55. package/dist/provider-help-parser.d.ts +34 -0
  56. package/dist/provider-help-parser.js +203 -0
  57. package/dist/provider-model-discovery.d.ts +30 -0
  58. package/dist/provider-model-discovery.js +229 -0
  59. package/dist/provider-output-metadata.d.ts +7 -0
  60. package/dist/provider-output-metadata.js +68 -0
  61. package/dist/provider-schema-builder.d.ts +22 -0
  62. package/dist/provider-schema-builder.js +55 -0
  63. package/dist/provider-surface-generator.d.ts +98 -0
  64. package/dist/provider-surface-generator.js +140 -0
  65. package/dist/provider-tool-capabilities.d.ts +3 -2
  66. package/dist/provider-tool-capabilities.js +77 -62
  67. package/dist/request-helpers.d.ts +37 -4
  68. package/dist/request-helpers.js +134 -0
  69. package/dist/resources.d.ts +6 -1
  70. package/dist/resources.js +64 -192
  71. package/dist/session-manager.js +18 -11
  72. package/dist/sqlite-driver.d.ts +1 -1
  73. package/dist/sqlite-driver.js +2 -1
  74. package/dist/stream-json-parser.d.ts +1 -0
  75. package/dist/stream-json-parser.js +3 -0
  76. package/dist/upstream-contracts.d.ts +17 -1
  77. package/dist/upstream-contracts.js +209 -36
  78. package/npm-shrinkwrap.json +2 -2
  79. package/package.json +8 -3
package/dist/index.js CHANGED
@@ -10,15 +10,18 @@ import { z } from "zod/v3";
10
10
  import { executeCli, killAllProcessGroups, providerCommandName } from "./executor.js";
11
11
  import { parseStreamJson } from "./stream-json-parser.js";
12
12
  import { parseCodexJsonStream, codexDisplayText, codexFrResponse } from "./codex-json-parser.js";
13
+ import { grokDisplayText } from "./grok-json-parser.js";
14
+ import { extractProviderOutputMetadata } from "./provider-output-metadata.js";
13
15
  import { parseGeminiJson, parseGeminiStreamJson } from "./gemini-json-parser.js";
14
16
  import { parseVibeMetaJson } from "./mistral-meta-json-parser.js";
15
17
  import { homedir } from "os";
16
18
  import { CLI_TYPES, PROVIDER_TYPES, createSessionManager, callerIsRemote, remoteSafeSession, } from "./session-manager.js";
17
19
  import { createWorktree, createWorktreeSessionCleanupHook, } from "./worktree-manager.js";
18
20
  import { ResourceProvider } from "./resources.js";
21
+ import { generateResourceDescriptors, generateProviderAcpDescriptors, } from "./provider-surface-generator.js";
19
22
  import { PerformanceMetrics } from "./metrics.js";
20
23
  import { estimateTokens, optimizePrompt as optimizePromptText, optimizeResponse as optimizeResponseText, } from "./optimizer.js";
21
- import { loadConfig, loadPersistenceConfig, loadCacheAwarenessConfig, loadProvidersConfig, loadAcpConfig, loadLimitsConfig, defaultGatewayConfigPath, isXaiProviderEnabled, enabledApiProviders, minStableTokensForModel, } from "./config.js";
24
+ import { loadConfig, loadPersistenceConfig, loadCacheAwarenessConfig, loadProvidersConfig, loadAcpConfig, loadAdminConfig, loadLimitsConfig, defaultGatewayConfigPath, isXaiProviderEnabled, enabledApiProviders, minStableTokensForModel, } from "./config.js";
22
25
  import { runAcpRequest } from "./acp/runtime.js";
23
26
  import { isAcpError } from "./acp/errors.js";
24
27
  import { redactSecrets } from "./secret-redaction.js";
@@ -27,12 +30,15 @@ import { prepareApiRequest, apiProviderCatalogEntry, ApiModelNotAllowedError, }
27
30
  import { checkHealth } from "./health.js";
28
31
  import { clearModelRegistryCache, getAvailableCliInfo, getCliInfo, resolveModelAlias, } from "./model-registry.js";
29
32
  import { getProviderToolCapabilities } from "./provider-tool-capabilities.js";
33
+ import { getProviderDefinition, DEVIN_ACP_AGENT_TYPES, } from "./provider-definitions.js";
34
+ import { buildProviderDiscoveredView, peekProviderCapabilitySet, warmProviderCapabilities, } from "./provider-capability-resolver.js";
35
+ import { registerProviderAdminTools } from "./provider-admin-tools.js";
30
36
  import { AsyncJobManager, JobSaturationError, isAsyncJobInProgress, extractApiHttpStatus, extractApiErrorBody, } from "./async-job-manager.js";
31
37
  import { createJobStore } from "./job-store.js";
32
38
  import { ApprovalManager, bypassAllowedByOperator, } from "./approval-manager.js";
33
39
  import { checkReviewIntegrity } from "./review-integrity.js";
34
40
  import { buildClaudeMcpConfig, CLAUDE_MCP_SERVER_NAMES, } from "./claude-mcp-config.js";
35
- import { resolveGrokSessionArgs, resolveMistralSessionArgs, resolveCodexSessionArgs, sanitizeCliArgValues, prepareMistralRequest as buildMistralCliInvocation, GATEWAY_SESSION_PREFIX, resolveClaudePermissionFlags, resolveCodexSandboxFlags, CLAUDE_PERMISSION_MODES, GEMINI_APPROVAL_MODES, CODEX_SANDBOX_MODES, CODEX_ASK_FOR_APPROVAL_MODES, CLAUDE_EFFORT_LEVELS, prepareClaudeHighImpactFlags, validateClaudeAgentsMap, prepareCodexHighImpactFlags, prepareCodexForkRequest, CODEX_CONFIG_OVERRIDES_SCHEMA, resolveGeminiSessionPlan, GEMINI_HIGH_IMPACT_PARAMS_SCHEMA, } from "./request-helpers.js";
41
+ import { resolveGrokSessionArgs, resolveMistralSessionArgs, resolveCodexSessionArgs, sanitizeCliArgValues, prepareMistralRequest as buildMistralCliInvocation, GATEWAY_SESSION_PREFIX, resolveClaudePermissionFlags, resolveCodexSandboxFlags, CLAUDE_PERMISSION_MODES, GEMINI_APPROVAL_MODES, CODEX_SANDBOX_MODES, CODEX_ASK_FOR_APPROVAL_MODES, CODEX_LOCAL_PROVIDERS, CODEX_COLOR_MODES, CLAUDE_EFFORT_LEVELS, prepareClaudeHighImpactFlags, validateClaudeAgentsMap, prepareCodexHighImpactFlags, prepareCodexForkRequest, CODEX_CONFIG_OVERRIDES_SCHEMA, resolveGeminiSessionPlan, GEMINI_HIGH_IMPACT_PARAMS_SCHEMA, } from "./request-helpers.js";
36
42
  import { createFlightRecorder } from "./flight-recorder.js";
37
43
  import { resolvePromptInput, PromptPartsSchema, assembleClaudeCacheBlocks, } from "./prompt-parts.js";
38
44
  import { computeSessionCacheStats, computeTtlRemaining, readPersistedRequest, PERSISTED_REQUEST_DEFAULT_MAX_CHARS, } from "./cache-stats.js";
@@ -237,6 +243,7 @@ let persistenceConfig = null;
237
243
  let cacheAwarenessConfig = null;
238
244
  let providersConfig = null;
239
245
  let acpConfig = null;
246
+ let adminConfig = null;
240
247
  let limitsConfig = null;
241
248
  let jobStore = null;
242
249
  let jobStoreInitialized = false;
@@ -258,6 +265,10 @@ function getAcpConfig(runtimeLogger = logger) {
258
265
  acpConfig ??= loadAcpConfig(runtimeLogger);
259
266
  return acpConfig;
260
267
  }
268
+ function getAdminConfig(runtimeLogger = logger) {
269
+ adminConfig ??= loadAdminConfig(runtimeLogger);
270
+ return adminConfig;
271
+ }
261
272
  function getCacheAwarenessConfig(runtimeLogger = logger) {
262
273
  cacheAwarenessConfig ??= loadCacheAwarenessConfig(runtimeLogger);
263
274
  return cacheAwarenessConfig;
@@ -280,9 +291,17 @@ function getJobStore(runtimeLogger = logger) {
280
291
  return jobStore;
281
292
  }
282
293
  function newAsyncJobManager(metrics, runtimeLogger, store = getJobStore(runtimeLogger), fr = getFlightRecorder(runtimeLogger)) {
294
+ const pc = getPersistenceConfig(runtimeLogger);
283
295
  return new AsyncJobManager(runtimeLogger, (cli, durationMs, success) => {
284
296
  metrics.recordRequest(cli, durationMs, success);
285
- }, store, fr, getLimitsConfig(runtimeLogger).jobs);
297
+ }, store, fr, getLimitsConfig(runtimeLogger).jobs, true, {
298
+ instanceHeartbeatMs: pc.instanceHeartbeatMs,
299
+ instanceLeaseTtlMs: pc.instanceLeaseTtlMs,
300
+ httpJobGraceMs: pc.httpJobGraceMs,
301
+ orphanSweepIntervalMs: pc.orphanSweepIntervalMs,
302
+ instanceGcMs: pc.instanceGcMs,
303
+ role: process.argv.includes("--transport=http") ? "http" : "stdio",
304
+ });
286
305
  }
287
306
  function getAsyncJobManager(runtimeLogger = logger) {
288
307
  asyncJobManager ??= newAsyncJobManager(performanceMetrics, runtimeLogger);
@@ -299,6 +318,91 @@ function mcpServerEnum() {
299
318
  }
300
319
  const CLI_TYPE_ENUM = z.enum(CLI_TYPES);
301
320
  export const MAX_TURNS_SCHEMA = z.number().int().positive().safe().max(10_000);
321
+ const CLAUDE_PART_A_FIELDS = {
322
+ includeHookEvents: z
323
+ .boolean()
324
+ .optional()
325
+ .describe("Claude --include-hook-events: include all hook lifecycle events in the output stream. Only takes effect with outputFormat=stream-json (the default)."),
326
+ replayUserMessages: z
327
+ .boolean()
328
+ .optional()
329
+ .describe("Claude --replay-user-messages: re-emit user messages from stdin back on stdout for acknowledgment. Only works with input-format=stream-json and outputFormat=stream-json (the cacheControl path)."),
330
+ systemPromptFile: z
331
+ .string()
332
+ .min(1)
333
+ .optional()
334
+ .describe("Claude --system-prompt-file: replace the system prompt from a file path (path variant of systemPrompt)."),
335
+ appendSystemPromptFile: z
336
+ .string()
337
+ .min(1)
338
+ .optional()
339
+ .describe("Claude --append-system-prompt-file: append a system prompt from a file path (path variant of appendSystemPrompt)."),
340
+ name: z
341
+ .string()
342
+ .min(1)
343
+ .optional()
344
+ .describe("Claude --name: display name for this session (shown in pickers/titles)."),
345
+ pluginDir: z
346
+ .array(z.string())
347
+ .optional()
348
+ .describe("Claude --plugin-dir: load a plugin from a directory or .zip for this session only. One --plugin-dir instance per entry."),
349
+ pluginUrl: z
350
+ .array(z.string())
351
+ .optional()
352
+ .describe("Claude --plugin-url: load a plugin .zip from a URL for this session only. One --plugin-url instance per entry."),
353
+ safeMode: z
354
+ .boolean()
355
+ .optional()
356
+ .describe("Claude --safe-mode: start with all customizations (CLAUDE.md, skills, plugins, hooks, MCP, commands, agents) disabled for troubleshooting. Explicit opt-in."),
357
+ bare: z
358
+ .boolean()
359
+ .optional()
360
+ .describe("Claude --bare: minimal mode (skip hooks, LSP, plugin sync, attribution, auto-memory, keychain reads, CLAUDE.md auto-discovery). Explicit opt-in."),
361
+ debug: z
362
+ .union([z.string(), z.boolean()])
363
+ .optional()
364
+ .describe('Claude -d/--debug: enable debug mode. true emits a bare --debug; a string emits --debug <filter> (e.g. "api,hooks"). Debug output goes to stderr only.'),
365
+ debugFile: z
366
+ .string()
367
+ .min(1)
368
+ .optional()
369
+ .describe("Claude --debug-file: write debug logs to a specific file path (enables debug mode)."),
370
+ };
371
+ const CODEX_PART_A_FIELDS = {
372
+ enable: z
373
+ .array(z.string())
374
+ .optional()
375
+ .describe("Codex --enable <FEATURE> (repeatable): enable a feature for this run (equivalent to -c features.<name>=true). Accepted on resume."),
376
+ disable: z
377
+ .array(z.string())
378
+ .optional()
379
+ .describe("Codex --disable <FEATURE> (repeatable): disable a feature for this run (equivalent to -c features.<name>=false). Accepted on resume."),
380
+ strictConfig: z
381
+ .boolean()
382
+ .optional()
383
+ .describe("Codex --strict-config: error out when config.toml contains fields not recognized by this Codex version. New sessions only."),
384
+ oss: z
385
+ .boolean()
386
+ .optional()
387
+ .describe("Codex --oss: use the open-source provider. New sessions only."),
388
+ localProvider: z
389
+ .enum(CODEX_LOCAL_PROVIDERS)
390
+ .optional()
391
+ .describe("Codex --local-provider: local OSS provider (lmstudio|ollama), used with oss. New sessions only."),
392
+ color: z
393
+ .enum(CODEX_COLOR_MODES)
394
+ .optional()
395
+ .describe("Codex --color: output color mode (always|never|auto). New sessions only."),
396
+ outputLastMessage: z
397
+ .string()
398
+ .min(1)
399
+ .optional()
400
+ .describe("Codex -o/--output-last-message <FILE>: write the agent's last message to a file. New sessions only."),
401
+ dangerouslyBypassHookTrust: z
402
+ .boolean()
403
+ .optional()
404
+ .describe("Codex --dangerously-bypass-hook-trust: run enabled hooks without persisted hook trust for this invocation. DANGEROUS. Explicit opt-in; never defaulted on."),
405
+ };
302
406
  const GROK_GENERATED_SHAPE = deriveZodShapeFromGeneration(UPSTREAM_CLI_CONTRACTS.grok, GROK_FLAG_GENERATION);
303
407
  export const MAX_TOKENS_SCHEMA = z.number().int().positive().safe().max(100_000_000);
304
408
  export const MAX_PRICE_SCHEMA = z.number().positive().finite().min(1e-6).max(10_000);
@@ -367,7 +471,7 @@ export function resolveGatewayServerRuntime(deps = {}, options = {}) {
367
471
  sessionManager: runtimeSessionManager,
368
472
  resourceProvider: deps.resourceProvider ??
369
473
  (options.isolateState
370
- ? new ResourceProvider(runtimeSessionManager, runtimePerformanceMetrics, runtimeFlightRecorder, deps.cacheAwareness ?? getCacheAwarenessConfig(runtimeLogger), deps.providers ?? getProvidersConfig(runtimeLogger))
474
+ ? new ResourceProvider(runtimeSessionManager, runtimePerformanceMetrics, runtimeFlightRecorder, deps.cacheAwareness ?? getCacheAwarenessConfig(runtimeLogger), deps.providers ?? getProvidersConfig(runtimeLogger), undefined, deps.acpConfig ?? getAcpConfig(runtimeLogger))
371
475
  : resourceProvider),
372
476
  db: "db" in deps ? (deps.db ?? null) : db,
373
477
  performanceMetrics: runtimePerformanceMetrics,
@@ -379,6 +483,7 @@ export function resolveGatewayServerRuntime(deps = {}, options = {}) {
379
483
  cacheAwareness: deps.cacheAwareness ?? getCacheAwarenessConfig(runtimeLogger),
380
484
  providers: deps.providers ?? getProvidersConfig(runtimeLogger),
381
485
  acpConfig: deps.acpConfig ?? getAcpConfig(runtimeLogger),
486
+ adminConfig: deps.adminConfig ?? getAdminConfig(runtimeLogger),
382
487
  workspaces: deps.workspaces ?? loadWorkspaceRegistry(runtimeLogger),
383
488
  };
384
489
  }
@@ -419,12 +524,28 @@ export async function runAcpTransport(deps, params) {
419
524
  model: params.model,
420
525
  sessionId: params.sessionId,
421
526
  correlationId: corrId,
527
+ agentType: params.agentType,
422
528
  });
529
+ const stop = result.stopReason;
530
+ const normalStop = stop === null || stop === "end_turn";
531
+ let warning = null;
532
+ if (!normalStop) {
533
+ warning =
534
+ `provider ended the turn with stop_reason=${stop}` +
535
+ (result.text.trim().length === 0 ? " and produced no output" : "") +
536
+ "; the response may be partial or refused.";
537
+ }
538
+ else if (result.text.trim().length === 0) {
539
+ warning =
540
+ "provider produced no assistant output (possible no-op, guardrail, or awaited input).";
541
+ }
542
+ const banner = `[gateway] transport=acp session=${result.gatewaySessionId}` +
543
+ (warning ? `\n[gateway] warning: ${warning}` : "");
423
544
  return {
424
545
  content: [
425
546
  {
426
547
  type: "text",
427
- text: `[gateway] transport=acp session=${result.gatewaySessionId}\n${result.text}`,
548
+ text: `${banner}\n${result.text}`,
428
549
  },
429
550
  ],
430
551
  };
@@ -460,7 +581,7 @@ async function awaitJobOrDefer(cli, args, corrId, idleTimeoutMs, outputFormat, f
460
581
  }
461
582
  const deferralAvailable = runtime.persistence.backend !== "none" &&
462
583
  runtime.persistence.asyncJobsEnabled &&
463
- runtime.asyncJobManager.hasStore();
584
+ runtime.asyncJobManager.canAdmitDurableJobs();
464
585
  if (SYNC_DEADLINE_MS === 0 || !deferralAvailable) {
465
586
  const command = providerCommandName(cli);
466
587
  let slot;
@@ -549,7 +670,7 @@ async function awaitApiJobOrDefer(provider, apiRequest, corrId, runtime = resolv
549
670
  };
550
671
  const deferralAvailable = runtime.persistence.backend !== "none" &&
551
672
  runtime.persistence.asyncJobsEnabled &&
552
- runtime.asyncJobManager.hasStore();
673
+ runtime.asyncJobManager.canAdmitDurableJobs();
553
674
  if (SYNC_DEADLINE_MS === 0 || !deferralAvailable || forceInline) {
554
675
  let slot;
555
676
  try {
@@ -1153,7 +1274,7 @@ function resolveClaudeMcpConfig(operation, correlationId, requestedMcpServers, s
1153
1274
  }
1154
1275
  return { config: mcpConfig };
1155
1276
  }
1156
- function registerBaseResources(server, runtime) {
1277
+ export function registerBaseResources(server, runtime) {
1157
1278
  for (const skill of loadedSkills) {
1158
1279
  server.registerResource(`skill-${skill.name}`, `skills://${skill.name}`, {
1159
1280
  title: skill.name,
@@ -1179,96 +1300,30 @@ function registerBaseResources(server, runtime) {
1179
1300
  const contents = await runtime.resourceProvider.readResource(uri.href);
1180
1301
  return { contents: contents ? [contents] : [] };
1181
1302
  });
1182
- server.registerResource("claude-sessions", "sessions://claude", {
1183
- title: "🤖 Claude Sessions",
1184
- description: "Claude conversation sessions",
1185
- mimeType: "application/json",
1186
- }, async (uri) => {
1187
- runtime.logger.debug("Reading Claude sessions resource");
1188
- const contents = await runtime.resourceProvider.readResource(uri.href);
1189
- return { contents: contents ? [contents] : [] };
1190
- });
1191
- server.registerResource("codex-sessions", "sessions://codex", {
1192
- title: "💻 Codex Sessions",
1193
- description: "Codex conversation sessions",
1194
- mimeType: "application/json",
1195
- }, async (uri) => {
1196
- runtime.logger.debug("Reading Codex sessions resource");
1197
- const contents = await runtime.resourceProvider.readResource(uri.href);
1198
- return { contents: contents ? [contents] : [] };
1199
- });
1200
- server.registerResource("gemini-sessions", "sessions://gemini", {
1201
- title: "✨ Gemini Sessions",
1202
- description: "Gemini conversation sessions",
1203
- mimeType: "application/json",
1204
- }, async (uri) => {
1205
- runtime.logger.debug("Reading Gemini sessions resource");
1206
- const contents = await runtime.resourceProvider.readResource(uri.href);
1207
- return { contents: contents ? [contents] : [] };
1208
- });
1209
- server.registerResource("grok-sessions", "sessions://grok", {
1210
- title: "⚡ Grok Sessions",
1211
- description: "Grok conversation sessions",
1212
- mimeType: "application/json",
1213
- }, async (uri) => {
1214
- runtime.logger.debug("Reading Grok sessions resource");
1215
- const contents = await runtime.resourceProvider.readResource(uri.href);
1216
- return { contents: contents ? [contents] : [] };
1217
- });
1218
- server.registerResource("mistral-sessions", "sessions://mistral", {
1219
- title: "🌬 Mistral Sessions",
1220
- description: "Mistral Vibe conversation sessions",
1221
- mimeType: "application/json",
1222
- }, async (uri) => {
1223
- runtime.logger.debug("Reading Mistral sessions resource");
1224
- const contents = await runtime.resourceProvider.readResource(uri.href);
1225
- return { contents: contents ? [contents] : [] };
1226
- });
1227
- server.registerResource("claude-models", "models://claude", {
1228
- title: "🧠 Claude Models",
1229
- description: "Claude models and capabilities",
1230
- mimeType: "application/json",
1231
- }, async (uri) => {
1232
- runtime.logger.debug("Reading Claude models resource");
1233
- const contents = await runtime.resourceProvider.readResource(uri.href);
1234
- return { contents: contents ? [contents] : [] };
1235
- });
1236
- server.registerResource("codex-models", "models://codex", {
1237
- title: "🔧 Codex Models",
1238
- description: "Codex models and capabilities",
1239
- mimeType: "application/json",
1240
- }, async (uri) => {
1241
- runtime.logger.debug("Reading Codex models resource");
1242
- const contents = await runtime.resourceProvider.readResource(uri.href);
1243
- return { contents: contents ? [contents] : [] };
1244
- });
1245
- server.registerResource("gemini-models", "models://gemini", {
1246
- title: "🌟 Gemini Models",
1247
- description: "Gemini models and capabilities",
1248
- mimeType: "application/json",
1249
- }, async (uri) => {
1250
- runtime.logger.debug("Reading Gemini models resource");
1251
- const contents = await runtime.resourceProvider.readResource(uri.href);
1252
- return { contents: contents ? [contents] : [] };
1253
- });
1254
- server.registerResource("grok-models", "models://grok", {
1255
- title: "⚡ Grok Models",
1256
- description: "Grok models and capabilities",
1257
- mimeType: "application/json",
1258
- }, async (uri) => {
1259
- runtime.logger.debug("Reading Grok models resource");
1260
- const contents = await runtime.resourceProvider.readResource(uri.href);
1261
- return { contents: contents ? [contents] : [] };
1262
- });
1263
- server.registerResource("mistral-models", "models://mistral", {
1264
- title: "🌬 Mistral Models",
1265
- description: "Mistral Vibe models and capabilities",
1266
- mimeType: "application/json",
1267
- }, async (uri) => {
1268
- runtime.logger.debug("Reading Mistral models resource");
1269
- const contents = await runtime.resourceProvider.readResource(uri.href);
1270
- return { contents: contents ? [contents] : [] };
1271
- });
1303
+ for (const descriptor of generateResourceDescriptors()) {
1304
+ if (descriptor.exposesSessionsResource) {
1305
+ server.registerResource(`${descriptor.provider}-sessions`, descriptor.sessionsUri, {
1306
+ title: `${descriptor.icon} ${descriptor.sessionLabel}s`,
1307
+ description: `${descriptor.displayName} conversation sessions`,
1308
+ mimeType: "application/json",
1309
+ }, async (uri) => {
1310
+ runtime.logger.debug(`Reading ${descriptor.sessionsUri} resource`);
1311
+ const contents = await runtime.resourceProvider.readResource(uri.href);
1312
+ return { contents: contents ? [contents] : [] };
1313
+ });
1314
+ }
1315
+ if (descriptor.exposesModelsResource) {
1316
+ server.registerResource(`${descriptor.provider}-models`, descriptor.modelsUri, {
1317
+ title: `${descriptor.icon} ${descriptor.displayName} Models & Capabilities`,
1318
+ description: `${descriptor.displayName} models and capabilities`,
1319
+ mimeType: "application/json",
1320
+ }, async (uri) => {
1321
+ runtime.logger.debug(`Reading ${descriptor.modelsUri} resource`);
1322
+ const contents = await runtime.resourceProvider.readResource(uri.href);
1323
+ return { contents: contents ? [contents] : [] };
1324
+ });
1325
+ }
1326
+ }
1272
1327
  server.registerResource("performance-metrics", "metrics://performance", {
1273
1328
  title: "📈 Performance Metrics",
1274
1329
  description: "Request counts, latency, success/failure rates",
@@ -1380,9 +1435,30 @@ function registerBaseResources(server, runtime) {
1380
1435
  const contents = await runtime.resourceProvider.readResource(uri.href);
1381
1436
  return { contents: contents ? [contents] : [] };
1382
1437
  });
1383
- const validationReceiptStore = runtime.persistence.backend === "sqlite"
1384
- ? runtime.asyncJobManager.getValidationRunStore()
1385
- : null;
1438
+ for (const descriptor of generateProviderAcpDescriptors()) {
1439
+ server.registerResource(`${descriptor.provider}-provider-acp`, descriptor.acpUri, {
1440
+ title: `${descriptor.icon} ${descriptor.displayName} ACP Capabilities`,
1441
+ description: `Native ACP entrypoint, negotiated capabilities, supported session methods, and host-service policy for ${descriptor.displayName}`,
1442
+ mimeType: "application/json",
1443
+ }, async (uri) => {
1444
+ runtime.logger.debug(`Reading ${descriptor.acpUri} resource`);
1445
+ const contents = await runtime.resourceProvider.readResource(uri.href);
1446
+ return { contents: contents ? [contents] : [] };
1447
+ });
1448
+ }
1449
+ server.registerResource("provider-acp", new ResourceTemplate("provider-acp://{provider}", { list: undefined }), {
1450
+ title: "Provider ACP Capabilities",
1451
+ description: "Read-only negotiated ACP capability record for one provider CLI (native: false for providers with no native ACP entrypoint)",
1452
+ mimeType: "application/json",
1453
+ }, async (uri, variables) => {
1454
+ const provider = Array.isArray(variables.provider)
1455
+ ? variables.provider[0]
1456
+ : variables.provider;
1457
+ runtime.logger.debug(`Reading provider-acp://${provider}`);
1458
+ const contents = await runtime.resourceProvider.readResource(uri.href);
1459
+ return { contents: contents ? [contents] : [] };
1460
+ });
1461
+ const validationReceiptStore = runtime.asyncJobManager?.getValidationRunStore();
1386
1462
  if (validationReceiptStore) {
1387
1463
  server.registerResource("validation-receipt", new ResourceTemplate("validation-receipt://{validationId}", { list: undefined }), {
1388
1464
  title: "Validation Receipt",
@@ -1428,10 +1504,33 @@ function resolvePromptOrPartsForPrep(args) {
1428
1504
  stablePrefixTokens: resolved.stablePrefixTokens,
1429
1505
  };
1430
1506
  }
1507
+ function remoteHostPathFieldError(operation, corrId, fields) {
1508
+ const ctx = getRequestContext();
1509
+ const isRemote = ctx?.transport === "http" || ctx?.authKind === "oauth";
1510
+ if (!isRemote)
1511
+ return null;
1512
+ const present = Object.entries(fields)
1513
+ .filter(([, v]) => (Array.isArray(v) ? v.length > 0 : v !== undefined && v !== null))
1514
+ .map(([k]) => k);
1515
+ if (present.length === 0)
1516
+ return null;
1517
+ return createErrorResponse(operation, 1, `Remote HTTP/OAuth requests may not use host-path or plugin fields: ${present.join(", ")}. ` +
1518
+ `These are restricted to local callers; supply content inline or reference a registered workspace.`, corrId);
1519
+ }
1431
1520
  export function prepareClaudeRequest(params, runtime = resolveGatewayServerRuntime()) {
1432
1521
  const corrId = params.correlationId || randomUUID();
1433
1522
  const cliInfo = getCliInfo();
1434
1523
  const resolvedModel = resolveModelAlias("claude", params.model, cliInfo);
1524
+ const remoteFieldErr = remoteHostPathFieldError(params.operation, corrId, {
1525
+ settings: params.settings,
1526
+ systemPromptFile: params.systemPromptFile,
1527
+ appendSystemPromptFile: params.appendSystemPromptFile,
1528
+ pluginDir: params.pluginDir,
1529
+ pluginUrl: params.pluginUrl,
1530
+ debugFile: params.debugFile,
1531
+ });
1532
+ if (remoteFieldErr)
1533
+ return remoteFieldErr;
1435
1534
  const inputResolution = resolvePromptOrPartsForPrep({
1436
1535
  prompt: params.prompt,
1437
1536
  promptParts: params.promptParts,
@@ -1651,6 +1750,17 @@ export function prepareClaudeRequest(params, runtime = resolveGatewayServerRunti
1651
1750
  settingSources: params.settingSources,
1652
1751
  settings: params.settings,
1653
1752
  tools: params.tools,
1753
+ includeHookEvents: params.includeHookEvents,
1754
+ replayUserMessages: params.replayUserMessages,
1755
+ systemPromptFile: params.systemPromptFile,
1756
+ appendSystemPromptFile: params.appendSystemPromptFile,
1757
+ name: params.name,
1758
+ pluginDir: params.pluginDir,
1759
+ pluginUrl: params.pluginUrl,
1760
+ safeMode: params.safeMode,
1761
+ bare: params.bare,
1762
+ debug: params.debug,
1763
+ debugFile: params.debugFile,
1654
1764
  }));
1655
1765
  return {
1656
1766
  corrId,
@@ -1673,6 +1783,13 @@ export function prepareCodexRequest(params, runtime = resolveGatewayServerRuntim
1673
1783
  const corrId = params.correlationId || randomUUID();
1674
1784
  const cliInfo = getCliInfo();
1675
1785
  const resolvedModel = resolveModelAlias("codex", params.model, cliInfo);
1786
+ const remoteFieldErr = remoteHostPathFieldError(params.operation, corrId, {
1787
+ outputSchema: typeof params.outputSchema === "string" ? params.outputSchema : undefined,
1788
+ images: params.images,
1789
+ outputLastMessage: params.outputLastMessage,
1790
+ });
1791
+ if (remoteFieldErr)
1792
+ return remoteFieldErr;
1676
1793
  const inputResolution = resolvePromptOrPartsForPrep({
1677
1794
  prompt: params.prompt,
1678
1795
  promptParts: params.promptParts,
@@ -1751,6 +1868,9 @@ export function prepareCodexRequest(params, runtime = resolveGatewayServerRuntim
1751
1868
  if (params.dangerouslyBypassApprovalsAndSandbox) {
1752
1869
  args.push("--dangerously-bypass-approvals-and-sandbox");
1753
1870
  }
1871
+ if (params.dangerouslyBypassHookTrust) {
1872
+ args.push("--dangerously-bypass-hook-trust");
1873
+ }
1754
1874
  args.push("--json");
1755
1875
  args.push("--skip-git-repo-check");
1756
1876
  let highImpactCleanup;
@@ -1763,6 +1883,21 @@ export function prepareCodexRequest(params, runtime = resolveGatewayServerRuntim
1763
1883
  args.push("--add-dir", dir);
1764
1884
  }
1765
1885
  }
1886
+ if (params.oss) {
1887
+ args.push("--oss");
1888
+ }
1889
+ if (params.localProvider) {
1890
+ args.push("--local-provider", params.localProvider);
1891
+ }
1892
+ if (params.strictConfig) {
1893
+ args.push("--strict-config");
1894
+ }
1895
+ if (params.color) {
1896
+ args.push("--color", params.color);
1897
+ }
1898
+ if (params.outputLastMessage !== undefined) {
1899
+ args.push("--output-last-message", params.outputLastMessage);
1900
+ }
1766
1901
  const high = prepareCodexHighImpactFlags({
1767
1902
  outputSchema: params.outputSchema,
1768
1903
  search: params.search,
@@ -1772,6 +1907,8 @@ export function prepareCodexRequest(params, runtime = resolveGatewayServerRuntim
1772
1907
  images: params.images,
1773
1908
  ignoreUserConfig: params.ignoreUserConfig,
1774
1909
  ignoreRules: params.ignoreRules,
1910
+ enable: params.enable,
1911
+ disable: params.disable,
1775
1912
  });
1776
1913
  if (high.missingImagePath) {
1777
1914
  return createErrorResponse(params.operation, 1, "", corrId, new Error(`images: path does not exist: ${high.missingImagePath}`));
@@ -1795,6 +1932,8 @@ export function prepareCodexRequest(params, runtime = resolveGatewayServerRuntim
1795
1932
  images: params.images,
1796
1933
  ignoreUserConfig: params.ignoreUserConfig,
1797
1934
  ignoreRules: params.ignoreRules,
1935
+ enable: params.enable,
1936
+ disable: params.disable,
1798
1937
  });
1799
1938
  if (high.missingImagePath) {
1800
1939
  return createErrorResponse(params.operation, 1, "", corrId, new Error(`images: path does not exist: ${high.missingImagePath}`));
@@ -1924,6 +2063,9 @@ export function prepareGeminiRequest(params, runtime = resolveGatewayServerRunti
1924
2063
  if (params.newProject) {
1925
2064
  args.push("--new-project");
1926
2065
  }
2066
+ if (params.printTimeout !== undefined && params.printTimeout !== "") {
2067
+ args.push("--print-timeout", params.printTimeout);
2068
+ }
1927
2069
  return {
1928
2070
  corrId,
1929
2071
  effectivePrompt,
@@ -1940,6 +2082,14 @@ export function prepareGrokRequest(params, runtime = resolveGatewayServerRuntime
1940
2082
  const corrId = params.correlationId || randomUUID();
1941
2083
  const cliInfo = getCliInfo();
1942
2084
  const resolvedModel = resolveModelAlias("grok", params.model, cliInfo);
2085
+ const remoteFieldErr = remoteHostPathFieldError(params.operation, corrId, {
2086
+ promptFile: params.promptFile,
2087
+ leaderSocket: params.leaderSocket,
2088
+ rules: params.rules,
2089
+ agent: params.agent,
2090
+ });
2091
+ if (remoteFieldErr)
2092
+ return remoteFieldErr;
1943
2093
  const inputResolution = resolvePromptOrPartsForPrep({
1944
2094
  prompt: params.prompt,
1945
2095
  promptParts: params.promptParts,
@@ -2202,6 +2352,9 @@ export function buildCliResponse(cli, stdout, optimizeResponse, corrId, sessionI
2202
2352
  if (cli === "codex" && outputFormat !== "json") {
2203
2353
  finalStdout = codexDisplayText(stdout);
2204
2354
  }
2355
+ if (cli === "grok") {
2356
+ finalStdout = grokDisplayText(outputFormat, stdout);
2357
+ }
2205
2358
  if (optimizeResponse && outputFormat !== "json") {
2206
2359
  const optimized = optimizeResponseText(finalStdout);
2207
2360
  logOptimizationTokens("response", corrId, finalStdout, optimized);
@@ -2217,11 +2370,11 @@ export function buildCliResponse(cli, stdout, optimizeResponse, corrId, sessionI
2217
2370
  }
2218
2371
  const derivedWarnings = [];
2219
2372
  const extraStructured = {};
2220
- let claudeResultError = false;
2373
+ let resultError = false;
2221
2374
  if (cli === "claude") {
2222
2375
  const parsedResult = parseStreamJson(stdout);
2223
2376
  if (parsedResult.isError) {
2224
- claudeResultError = true;
2377
+ resultError = true;
2225
2378
  extraStructured.resultIsError = true;
2226
2379
  derivedWarnings.push({
2227
2380
  code: "claude_result_error",
@@ -2234,8 +2387,27 @@ export function buildCliResponse(cli, stdout, optimizeResponse, corrId, sessionI
2234
2387
  if (parsedCodex.threadId) {
2235
2388
  extraStructured.codexSessionId = parsedCodex.threadId;
2236
2389
  }
2390
+ if (parsedCodex.error) {
2391
+ resultError = true;
2392
+ extraStructured.resultIsError = true;
2393
+ derivedWarnings.push({
2394
+ code: "codex_result_error",
2395
+ message: `Codex exited 0 but reported a failed turn: ${parsedCodex.error}. The returned text may be partial.`,
2396
+ });
2397
+ }
2237
2398
  }
2238
- if (!claudeResultError && finalStdout.trim().length === 0) {
2399
+ if (cli === "gemini") {
2400
+ const parsedGemini = outputFormat === "stream-json" ? parseGeminiStreamJson(stdout) : parseGeminiJson(stdout);
2401
+ if (parsedGemini?.stopReason === "error") {
2402
+ resultError = true;
2403
+ extraStructured.resultIsError = true;
2404
+ derivedWarnings.push({
2405
+ code: "gemini_result_error",
2406
+ message: "Gemini exited 0 but the result event reported status:error. The returned text may be partial.",
2407
+ });
2408
+ }
2409
+ }
2410
+ if (!resultError && finalStdout.trim().length === 0) {
2239
2411
  extraStructured.emptyOutput = true;
2240
2412
  derivedWarnings.push({
2241
2413
  code: "empty_output",
@@ -2973,6 +3145,7 @@ export async function handleGeminiRequest(deps, params) {
2973
3145
  yolo: params.yolo,
2974
3146
  project: params.project,
2975
3147
  newProject: params.newProject,
3148
+ printTimeout: params.printTimeout,
2976
3149
  }, runtime);
2977
3150
  if (!("args" in prep))
2978
3151
  return prep;
@@ -3061,6 +3234,7 @@ export async function handleGeminiRequest(deps, params) {
3061
3234
  }
3062
3235
  }
3063
3236
  const geminiUsage = extractUsageAndCost("gemini", stdout, params.outputFormat);
3237
+ const geminiMeta = extractProviderOutputMetadata("gemini", stdout, params.outputFormat);
3064
3238
  safeFlightComplete(corrId, {
3065
3239
  response: stdout,
3066
3240
  durationMs,
@@ -3075,6 +3249,8 @@ export async function handleGeminiRequest(deps, params) {
3075
3249
  cacheReadTokens: geminiUsage.cacheReadTokens,
3076
3250
  cacheCreationTokens: geminiUsage.cacheCreationTokens,
3077
3251
  costUsd: geminiUsage.costUsd,
3252
+ providerSessionId: geminiMeta.sessionId,
3253
+ stopReason: geminiMeta.stopReason,
3078
3254
  }, runtime);
3079
3255
  return response;
3080
3256
  }
@@ -3122,6 +3298,7 @@ export async function handleGeminiRequestAsync(deps, params) {
3122
3298
  yolo: params.yolo,
3123
3299
  project: params.project,
3124
3300
  newProject: params.newProject,
3301
+ printTimeout: params.printTimeout,
3125
3302
  }, runtime);
3126
3303
  if (!("args" in prep))
3127
3304
  return prep;
@@ -3343,6 +3520,7 @@ export async function handleGrokRequest(deps, params) {
3343
3520
  first.text = formatWorktreePrefix(worktreeResolution.worktreePath) + first.text;
3344
3521
  }
3345
3522
  }
3523
+ const grokMeta = extractProviderOutputMetadata("grok", stdout, params.outputFormat);
3346
3524
  safeFlightComplete(corrId, {
3347
3525
  response: stdout,
3348
3526
  durationMs,
@@ -3352,6 +3530,8 @@ export async function handleGrokRequest(deps, params) {
3352
3530
  optimizationApplied: params.optimizePrompt || (params.optimizeResponse ?? false),
3353
3531
  exitCode: 0,
3354
3532
  status: "completed",
3533
+ providerSessionId: grokMeta.sessionId,
3534
+ stopReason: grokMeta.stopReason,
3355
3535
  }, runtime);
3356
3536
  return response;
3357
3537
  }
@@ -3506,6 +3686,14 @@ export async function handleGrokRequestAsync(deps, params) {
3506
3686
  }
3507
3687
  export function prepareDevinRequest(params, _runtime) {
3508
3688
  const corrId = params.correlationId ?? randomUUID();
3689
+ const remoteFieldErr = remoteHostPathFieldError(params.operation, corrId, {
3690
+ promptFile: params.promptFile,
3691
+ config: params.config,
3692
+ agentConfig: params.agentConfig,
3693
+ exportSession: typeof params.exportSession === "string" ? params.exportSession : undefined,
3694
+ });
3695
+ if (remoteFieldErr)
3696
+ return remoteFieldErr;
3509
3697
  let prompt = (params.prompt ?? "").trim();
3510
3698
  if (!prompt) {
3511
3699
  return createErrorResponse(params.operation, 1, "prompt is required and cannot be empty", corrId);
@@ -3520,6 +3708,21 @@ export function prepareDevinRequest(params, _runtime) {
3520
3708
  args.push("--permission-mode", params.permissionMode);
3521
3709
  if (params.promptFile)
3522
3710
  args.push("--prompt-file", params.promptFile);
3711
+ if (params.config)
3712
+ args.push("--config", params.config);
3713
+ if (params.sandbox)
3714
+ args.push("--sandbox");
3715
+ if (typeof params.exportSession === "string") {
3716
+ args.push("--export", params.exportSession);
3717
+ }
3718
+ else if (params.exportSession === true) {
3719
+ args.push("--export");
3720
+ }
3721
+ if (params.respectWorkspaceTrust !== undefined) {
3722
+ args.push("--respect-workspace-trust", params.respectWorkspaceTrust ? "true" : "false");
3723
+ }
3724
+ if (params.agentConfig)
3725
+ args.push("--agent-config", params.agentConfig);
3523
3726
  return {
3524
3727
  corrId,
3525
3728
  effectivePrompt: prompt,
@@ -3539,6 +3742,7 @@ export async function handleDevinRequest(deps, params) {
3539
3742
  model: params.model,
3540
3743
  sessionId: params.sessionId,
3541
3744
  correlationId: params.correlationId,
3745
+ agentType: params.agentType,
3542
3746
  });
3543
3747
  }
3544
3748
  const runtime = resolveHandlerRuntime(deps);
@@ -3548,6 +3752,11 @@ export async function handleDevinRequest(deps, params) {
3548
3752
  model: params.model,
3549
3753
  permissionMode: params.permissionMode,
3550
3754
  promptFile: params.promptFile,
3755
+ config: params.config,
3756
+ sandbox: params.sandbox,
3757
+ exportSession: params.exportSession,
3758
+ respectWorkspaceTrust: params.respectWorkspaceTrust,
3759
+ agentConfig: params.agentConfig,
3551
3760
  correlationId: params.correlationId,
3552
3761
  optimizePrompt: params.optimizePrompt,
3553
3762
  operation: "devin_request",
@@ -3651,6 +3860,11 @@ export async function handleDevinRequestAsync(deps, params) {
3651
3860
  model: params.model,
3652
3861
  permissionMode: params.permissionMode,
3653
3862
  promptFile: params.promptFile,
3863
+ config: params.config,
3864
+ sandbox: params.sandbox,
3865
+ exportSession: params.exportSession,
3866
+ respectWorkspaceTrust: params.respectWorkspaceTrust,
3867
+ agentConfig: params.agentConfig,
3654
3868
  correlationId: params.correlationId,
3655
3869
  optimizePrompt: params.optimizePrompt,
3656
3870
  operation: "devin_request_async",
@@ -4355,6 +4569,14 @@ export async function handleCodexRequestAsync(deps, params) {
4355
4569
  ignoreRules: params.ignoreRules,
4356
4570
  workingDir: params.workingDir,
4357
4571
  addDir: params.addDir,
4572
+ enable: params.enable,
4573
+ disable: params.disable,
4574
+ strictConfig: params.strictConfig,
4575
+ oss: params.oss,
4576
+ localProvider: params.localProvider,
4577
+ color: params.color,
4578
+ outputLastMessage: params.outputLastMessage,
4579
+ dangerouslyBypassHookTrust: params.dangerouslyBypassHookTrust,
4358
4580
  }, runtime);
4359
4581
  if (!("args" in prep))
4360
4582
  return prep;
@@ -4459,9 +4681,14 @@ export function createGatewayServer(deps = {}) {
4459
4681
  registerValidationTools(server, {
4460
4682
  asyncJobManager,
4461
4683
  apiProviders: enabledApiProviders(providers),
4462
- validationRunStore: persistence.backend === "sqlite" ? asyncJobManager.getValidationRunStore() : null,
4684
+ validationRunStore: asyncJobManager.getValidationRunStore(),
4463
4685
  });
4464
4686
  registerWorkspaceTools(server, runtime);
4687
+ registerProviderAdminTools(server, {
4688
+ approvalManager: runtime.approvalManager,
4689
+ logger: runtime.logger,
4690
+ allowMutatingCliAdminOps: runtime.adminConfig.allowMutatingCliAdminOps,
4691
+ });
4465
4692
  const apiProviderTools = registerApiProviderTools(server, runtime, providers, asyncJobsEnabled);
4466
4693
  if (apiProviderTools.length > 0) {
4467
4694
  runtime.logger.info(`Registered API provider tools: ${apiProviderTools.join(", ")}`);
@@ -4650,6 +4877,7 @@ export function createGatewayServer(deps = {}) {
4650
4877
  .array(z.string())
4651
4878
  .optional()
4652
4879
  .describe('Claude --tools: restrict the available built-in tool set (distinct from allowedTools permission gating). Pass [""] to disable all tools.'),
4880
+ ...CLAUDE_PART_A_FIELDS,
4653
4881
  workspace: providerWorkspaceAliasSchema(),
4654
4882
  worktree: WORKTREE_SCHEMA.optional(),
4655
4883
  approvalStrategy: z
@@ -4685,7 +4913,7 @@ export function createGatewayServer(deps = {}) {
4685
4913
  destructiveHint: true,
4686
4914
  idempotentHint: false,
4687
4915
  openWorldHint: true,
4688
- }, async ({ prompt, promptParts, model, outputFormat, sessionId, continueSession, createNewSession, allowedTools, disallowedTools, dangerouslySkipPermissions, permissionMode, agent, agents, forkSession, systemPrompt, appendSystemPrompt, maxBudgetUsd, maxTurns, effort, excludeDynamicSystemPromptSections, fallbackModel, jsonSchema, addDir, noSessionPersistence, settingSources, settings, tools, workspace, worktree, approvalStrategy, approvalPolicy, mcpServers, strictMcpConfig, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, }) => {
4916
+ }, async ({ prompt, promptParts, model, outputFormat, sessionId, continueSession, createNewSession, allowedTools, disallowedTools, dangerouslySkipPermissions, permissionMode, agent, agents, forkSession, systemPrompt, appendSystemPrompt, maxBudgetUsd, maxTurns, effort, excludeDynamicSystemPromptSections, fallbackModel, jsonSchema, addDir, noSessionPersistence, settingSources, settings, tools, includeHookEvents, replayUserMessages, systemPromptFile, appendSystemPromptFile, name, pluginDir, pluginUrl, safeMode, bare, debug, debugFile, workspace, worktree, approvalStrategy, approvalPolicy, mcpServers, strictMcpConfig, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, }) => {
4689
4917
  const startTime = Date.now();
4690
4918
  if (systemPrompt !== undefined && appendSystemPrompt !== undefined) {
4691
4919
  return createErrorResponse("claude", 1, "", correlationId, new Error("systemPrompt and appendSystemPrompt are mutually exclusive; use one or the other (not both)."));
@@ -4722,6 +4950,17 @@ export function createGatewayServer(deps = {}) {
4722
4950
  settingSources,
4723
4951
  settings,
4724
4952
  tools,
4953
+ includeHookEvents,
4954
+ replayUserMessages,
4955
+ systemPromptFile,
4956
+ appendSystemPromptFile,
4957
+ name,
4958
+ pluginDir,
4959
+ pluginUrl,
4960
+ safeMode,
4961
+ bare,
4962
+ debug,
4963
+ debugFile,
4725
4964
  }, runtime);
4726
4965
  if (!("args" in prep))
4727
4966
  return prep;
@@ -4849,6 +5088,8 @@ export function createGatewayServer(deps = {}) {
4849
5088
  optimizationApplied: optimizePrompt || optimizeResponse,
4850
5089
  exitCode: 0,
4851
5090
  status: "completed",
5091
+ providerSessionId: parsed.sessionId ?? undefined,
5092
+ stopReason: parsed.stopReason ?? undefined,
4852
5093
  }, runtime);
4853
5094
  const streamResponse = buildCliResponse("claude", parsed.text, optimizeResponse, corrId, effectiveSessionId, prep, durationMs, undefined, outputFormat, warnings);
4854
5095
  if (worktreeResolution.worktreePath) {
@@ -4859,6 +5100,7 @@ export function createGatewayServer(deps = {}) {
4859
5100
  }
4860
5101
  return streamResponse;
4861
5102
  }
5103
+ const claudeMeta = extractProviderOutputMetadata("claude", stdout, outputFormat);
4862
5104
  safeFlightComplete(corrId, {
4863
5105
  response: stdout,
4864
5106
  durationMs,
@@ -4867,6 +5109,8 @@ export function createGatewayServer(deps = {}) {
4867
5109
  optimizationApplied: optimizePrompt || optimizeResponse,
4868
5110
  exitCode: 0,
4869
5111
  status: "completed",
5112
+ providerSessionId: claudeMeta.sessionId,
5113
+ stopReason: claudeMeta.stopReason,
4870
5114
  }, runtime);
4871
5115
  const nonStreamResponse = buildCliResponse("claude", stdout, optimizeResponse, corrId, effectiveSessionId, prep, durationMs, undefined, outputFormat, warnings);
4872
5116
  if (worktreeResolution.worktreePath) {
@@ -5005,6 +5249,7 @@ export function createGatewayServer(deps = {}) {
5005
5249
  .optional()
5006
5250
  .describe("Codex --add-dir <DIR>: additional writable workspace directories. Emitted once per entry on new sessions only; resume inherits the original session's writable-dir policy." +
5007
5251
  LOCAL_ADD_DIR_FIELD_SUFFIX),
5252
+ ...CODEX_PART_A_FIELDS,
5008
5253
  workspace: providerWorkspaceAliasSchema(),
5009
5254
  worktree: WORKTREE_SCHEMA.optional(),
5010
5255
  }, {
@@ -5013,7 +5258,7 @@ export function createGatewayServer(deps = {}) {
5013
5258
  destructiveHint: true,
5014
5259
  idempotentHint: false,
5015
5260
  openWorldHint: true,
5016
- }, async ({ prompt, promptParts, model, fullAuto, sandboxMode, askForApproval, useLegacyFullAutoFlag, dangerouslyBypassApprovalsAndSandbox, approvalStrategy, approvalPolicy, mcpServers, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, outputFormat, outputSchema, search, profile, configOverrides, ephemeral, images, ignoreUserConfig, ignoreRules, workingDir, addDir, workspace, worktree, }) => {
5261
+ }, async ({ prompt, promptParts, model, fullAuto, sandboxMode, askForApproval, useLegacyFullAutoFlag, dangerouslyBypassApprovalsAndSandbox, approvalStrategy, approvalPolicy, mcpServers, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, outputFormat, outputSchema, search, profile, configOverrides, ephemeral, images, ignoreUserConfig, ignoreRules, workingDir, addDir, enable, disable, strictConfig, oss, localProvider, color, outputLastMessage, dangerouslyBypassHookTrust, workspace, worktree, }) => {
5017
5262
  const startTime = Date.now();
5018
5263
  const prep = prepareCodexRequest({
5019
5264
  prompt,
@@ -5044,6 +5289,14 @@ export function createGatewayServer(deps = {}) {
5044
5289
  ignoreRules,
5045
5290
  workingDir,
5046
5291
  addDir,
5292
+ enable,
5293
+ disable,
5294
+ strictConfig,
5295
+ oss,
5296
+ localProvider,
5297
+ color,
5298
+ outputLastMessage,
5299
+ dangerouslyBypassHookTrust,
5047
5300
  }, runtime);
5048
5301
  if (!("args" in prep))
5049
5302
  return prep;
@@ -5102,7 +5355,12 @@ export function createGatewayServer(deps = {}) {
5102
5355
  errorMessage: stderr || `Exit code ${code}`,
5103
5356
  status: "failed",
5104
5357
  }, runtime);
5105
- const codexErrorDetail = stderr && stderr.trim().length > 0 ? stderr : codexDisplayText(stdout);
5358
+ const parsedCodexError = parseCodexJsonStream(stdout).error;
5359
+ const codexErrorDetail = stderr && stderr.trim().length > 0
5360
+ ? stderr
5361
+ : parsedCodexError && parsedCodexError.trim().length > 0
5362
+ ? parsedCodexError
5363
+ : codexDisplayText(stdout);
5106
5364
  const codexResumeHint = sessionId &&
5107
5365
  /not found|no such|unknown session|does not exist|invalid session/i.test(codexErrorDetail)
5108
5366
  ? `\n\nSession ${sessionId} could not be resumed. Codex session IDs are UUIDs under ~/.codex/sessions/; verify the id, omit sessionId, or set createNewSession:true.`
@@ -5130,6 +5388,7 @@ export function createGatewayServer(deps = {}) {
5130
5388
  }
5131
5389
  logger.info(`[${corrId}] codex_request completed successfully in ${durationMs}ms`);
5132
5390
  const codexUsage = extractUsageAndCost("codex", stdout, outputFormat);
5391
+ const codexMeta = extractProviderOutputMetadata("codex", stdout, outputFormat);
5133
5392
  safeFlightComplete(corrId, {
5134
5393
  response: codexFrResponse(outputFormat, stdout),
5135
5394
  durationMs,
@@ -5143,6 +5402,8 @@ export function createGatewayServer(deps = {}) {
5143
5402
  cacheReadTokens: codexUsage.cacheReadTokens,
5144
5403
  cacheCreationTokens: codexUsage.cacheCreationTokens,
5145
5404
  costUsd: codexUsage.costUsd,
5405
+ providerSessionId: codexMeta.sessionId,
5406
+ stopReason: codexMeta.stopReason,
5146
5407
  }, runtime);
5147
5408
  const codexResponse = buildCliResponse("codex", stdout, optimizeResponse, corrId, effectiveSessionId, prep, durationMs, undefined, outputFormat);
5148
5409
  if (worktreeResolution.worktreePath) {
@@ -5264,7 +5525,12 @@ export function createGatewayServer(deps = {}) {
5264
5525
  const { stdout, stderr, code } = result;
5265
5526
  durationMs = Math.max(0, Date.now() - startTime);
5266
5527
  if (code !== 0) {
5267
- const codexErrorDetail = stderr && stderr.trim().length > 0 ? stderr : codexDisplayText(stdout);
5528
+ const parsedCodexError = parseCodexJsonStream(stdout).error;
5529
+ const codexErrorDetail = stderr && stderr.trim().length > 0
5530
+ ? stderr
5531
+ : parsedCodexError && parsedCodexError.trim().length > 0
5532
+ ? parsedCodexError
5533
+ : codexDisplayText(stdout);
5268
5534
  const codexResumeHint = sessionId &&
5269
5535
  /not found|no such|unknown session|does not exist|invalid session/i.test(codexErrorDetail)
5270
5536
  ? `\n\nSession ${sessionId} could not be resumed. Codex session IDs are UUIDs under ~/.codex/sessions/; verify the id, omit sessionId, or set createNewSession:true.`
@@ -5368,6 +5634,11 @@ export function createGatewayServer(deps = {}) {
5368
5634
  .boolean()
5369
5635
  .optional()
5370
5636
  .describe("Antigravity 1.0.13 --new-project: create a new project for this session. Mutually exclusive with project."),
5637
+ printTimeout: z
5638
+ .string()
5639
+ .min(1)
5640
+ .optional()
5641
+ .describe("Antigravity --print-timeout <DURATION>: print-mode wait timeout as a Go duration string (e.g. '5m0s', '30s')."),
5371
5642
  workspace: providerWorkspaceAliasSchema(),
5372
5643
  worktree: WORKTREE_SCHEMA.optional(),
5373
5644
  }, {
@@ -5376,7 +5647,7 @@ export function createGatewayServer(deps = {}) {
5376
5647
  destructiveHint: true,
5377
5648
  idempotentHint: false,
5378
5649
  openWorldHint: true,
5379
- }, async ({ prompt, promptParts, model, sessionId, resumeLatest, createNewSession, approvalMode, approvalStrategy, approvalPolicy, mcpServers, allowedTools, includeDirs, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, outputFormat, sandbox, policyFiles, adminPolicyFiles, attachments, skipTrust, yolo, project, newProject, workspace, worktree, }) => {
5650
+ }, async ({ prompt, promptParts, model, sessionId, resumeLatest, createNewSession, approvalMode, approvalStrategy, approvalPolicy, mcpServers, allowedTools, includeDirs, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, outputFormat, sandbox, policyFiles, adminPolicyFiles, attachments, skipTrust, yolo, project, newProject, printTimeout, workspace, worktree, }) => {
5380
5651
  return handleGeminiRequest({ sessionManager, logger, runtime }, {
5381
5652
  prompt,
5382
5653
  promptParts,
@@ -5404,6 +5675,7 @@ export function createGatewayServer(deps = {}) {
5404
5675
  yolo,
5405
5676
  project,
5406
5677
  newProject,
5678
+ printTimeout,
5407
5679
  workspace,
5408
5680
  worktree,
5409
5681
  });
@@ -5577,6 +5849,27 @@ export function createGatewayServer(deps = {}) {
5577
5849
  .string()
5578
5850
  .optional()
5579
5851
  .describe("Load the initial prompt from a file (--prompt-file)"),
5852
+ config: z.string().optional().describe("Config file path (Devin --config <PATH>)"),
5853
+ sandbox: z
5854
+ .boolean()
5855
+ .optional()
5856
+ .describe("Run the Devin session in a sandbox (Devin --sandbox). Safety control: never defaulted on; pass true to opt in."),
5857
+ exportSession: z
5858
+ .union([z.boolean(), z.string()])
5859
+ .optional()
5860
+ .describe("Export the session (Devin --export [<PATH>]). true emits a bare --export; a string path emits --export <path>."),
5861
+ respectWorkspaceTrust: z
5862
+ .boolean()
5863
+ .optional()
5864
+ .describe("Respect workspace trust (Devin --respect-workspace-trust <bool>). Devin defaults true for interactive and false for print mode; set explicitly to override."),
5865
+ agentConfig: z
5866
+ .string()
5867
+ .optional()
5868
+ .describe("Agent config file path (Devin --agent-config <FILE>)"),
5869
+ agentType: z
5870
+ .enum(DEVIN_ACP_AGENT_TYPES)
5871
+ .optional()
5872
+ .describe("ACP agent variant for transport=acp (`devin acp --agent-type`): 'summarizer' (no tools, text summary) or 'review' (read-only + shell code-review). Ignored for the CLI transport."),
5580
5873
  sessionId: z
5581
5874
  .string()
5582
5875
  .optional()
@@ -5606,13 +5899,19 @@ export function createGatewayServer(deps = {}) {
5606
5899
  destructiveHint: true,
5607
5900
  idempotentHint: false,
5608
5901
  openWorldHint: true,
5609
- }, async ({ prompt, model, transport, permissionMode, promptFile, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, }) => {
5902
+ }, async ({ prompt, model, transport, permissionMode, promptFile, config, sandbox, exportSession, respectWorkspaceTrust, agentConfig, agentType, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, }) => {
5610
5903
  return handleDevinRequest({ sessionManager, logger, runtime }, {
5611
5904
  prompt,
5612
5905
  model,
5613
5906
  transport,
5614
5907
  permissionMode,
5615
5908
  promptFile,
5909
+ config,
5910
+ sandbox,
5911
+ exportSession,
5912
+ respectWorkspaceTrust,
5913
+ agentConfig,
5914
+ agentType,
5616
5915
  sessionId,
5617
5916
  resumeLatest,
5618
5917
  createNewSession,
@@ -5959,6 +6258,7 @@ export function createGatewayServer(deps = {}) {
5959
6258
  .array(z.string())
5960
6259
  .optional()
5961
6260
  .describe('Claude --tools: restrict the available built-in tool set (distinct from allowedTools permission gating). Pass [""] to disable all tools.'),
6261
+ ...CLAUDE_PART_A_FIELDS,
5962
6262
  workspace: providerWorkspaceAliasSchema(),
5963
6263
  worktree: WORKTREE_SCHEMA.optional(),
5964
6264
  approvalStrategy: z
@@ -5993,7 +6293,7 @@ export function createGatewayServer(deps = {}) {
5993
6293
  destructiveHint: true,
5994
6294
  idempotentHint: false,
5995
6295
  openWorldHint: true,
5996
- }, async ({ prompt, promptParts, model, outputFormat, sessionId, continueSession, createNewSession, allowedTools, disallowedTools, dangerouslySkipPermissions, permissionMode, agent, agents, forkSession, systemPrompt, appendSystemPrompt, maxBudgetUsd, maxTurns, effort, excludeDynamicSystemPromptSections, fallbackModel, jsonSchema, addDir, noSessionPersistence, settingSources, settings, tools, workspace, worktree, approvalStrategy, approvalPolicy, mcpServers, strictMcpConfig, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, }) => {
6296
+ }, async ({ prompt, promptParts, model, outputFormat, sessionId, continueSession, createNewSession, allowedTools, disallowedTools, dangerouslySkipPermissions, permissionMode, agent, agents, forkSession, systemPrompt, appendSystemPrompt, maxBudgetUsd, maxTurns, effort, excludeDynamicSystemPromptSections, fallbackModel, jsonSchema, addDir, noSessionPersistence, settingSources, settings, tools, includeHookEvents, replayUserMessages, systemPromptFile, appendSystemPromptFile, name, pluginDir, pluginUrl, safeMode, bare, debug, debugFile, workspace, worktree, approvalStrategy, approvalPolicy, mcpServers, strictMcpConfig, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, }) => {
5997
6297
  if (systemPrompt !== undefined && appendSystemPrompt !== undefined) {
5998
6298
  return createErrorResponse("claude", 1, "", correlationId, new Error("systemPrompt and appendSystemPrompt are mutually exclusive; use one or the other (not both)."));
5999
6299
  }
@@ -6029,6 +6329,17 @@ export function createGatewayServer(deps = {}) {
6029
6329
  settingSources,
6030
6330
  settings,
6031
6331
  tools,
6332
+ includeHookEvents,
6333
+ replayUserMessages,
6334
+ systemPromptFile,
6335
+ appendSystemPromptFile,
6336
+ name,
6337
+ pluginDir,
6338
+ pluginUrl,
6339
+ safeMode,
6340
+ bare,
6341
+ debug,
6342
+ debugFile,
6032
6343
  }, runtime);
6033
6344
  if (!("args" in prep))
6034
6345
  return prep;
@@ -6216,6 +6527,7 @@ export function createGatewayServer(deps = {}) {
6216
6527
  .optional()
6217
6528
  .describe("Codex --add-dir <DIR>: additional writable workspace directories (repeat per entry). New sessions only." +
6218
6529
  LOCAL_ADD_DIR_FIELD_SUFFIX),
6530
+ ...CODEX_PART_A_FIELDS,
6219
6531
  workspace: providerWorkspaceAliasSchema(),
6220
6532
  worktree: WORKTREE_SCHEMA.optional(),
6221
6533
  }, {
@@ -6224,7 +6536,7 @@ export function createGatewayServer(deps = {}) {
6224
6536
  destructiveHint: true,
6225
6537
  idempotentHint: false,
6226
6538
  openWorldHint: true,
6227
- }, async ({ prompt, promptParts, model, fullAuto, sandboxMode, askForApproval, useLegacyFullAutoFlag, dangerouslyBypassApprovalsAndSandbox, approvalStrategy, approvalPolicy, mcpServers, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, outputFormat, outputSchema, search, profile, configOverrides, ephemeral, images, ignoreUserConfig, ignoreRules, workingDir, addDir, workspace, worktree, }) => {
6539
+ }, async ({ prompt, promptParts, model, fullAuto, sandboxMode, askForApproval, useLegacyFullAutoFlag, dangerouslyBypassApprovalsAndSandbox, approvalStrategy, approvalPolicy, mcpServers, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, outputFormat, outputSchema, search, profile, configOverrides, ephemeral, images, ignoreUserConfig, ignoreRules, workingDir, addDir, enable, disable, strictConfig, oss, localProvider, color, outputLastMessage, dangerouslyBypassHookTrust, workspace, worktree, }) => {
6228
6540
  return handleCodexRequestAsync({ sessionManager, asyncJobManager, logger, runtime }, {
6229
6541
  prompt,
6230
6542
  promptParts,
@@ -6255,6 +6567,14 @@ export function createGatewayServer(deps = {}) {
6255
6567
  ignoreRules,
6256
6568
  workingDir,
6257
6569
  addDir,
6570
+ enable,
6571
+ disable,
6572
+ strictConfig,
6573
+ oss,
6574
+ localProvider,
6575
+ color,
6576
+ outputLastMessage,
6577
+ dangerouslyBypassHookTrust,
6258
6578
  workspace,
6259
6579
  worktree,
6260
6580
  });
@@ -6343,6 +6663,11 @@ export function createGatewayServer(deps = {}) {
6343
6663
  .boolean()
6344
6664
  .optional()
6345
6665
  .describe("Antigravity 1.0.13 --new-project: create a new project for this session. Mutually exclusive with project."),
6666
+ printTimeout: z
6667
+ .string()
6668
+ .min(1)
6669
+ .optional()
6670
+ .describe("Antigravity --print-timeout <DURATION>: print-mode wait timeout as a Go duration string (e.g. '5m0s', '30s')."),
6346
6671
  workspace: providerWorkspaceAliasSchema(),
6347
6672
  worktree: WORKTREE_SCHEMA.optional(),
6348
6673
  }, {
@@ -6351,7 +6676,7 @@ export function createGatewayServer(deps = {}) {
6351
6676
  destructiveHint: true,
6352
6677
  idempotentHint: false,
6353
6678
  openWorldHint: true,
6354
- }, async ({ prompt, promptParts, model, sessionId, resumeLatest, createNewSession, approvalMode, approvalStrategy, approvalPolicy, mcpServers, allowedTools, includeDirs, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, outputFormat, sandbox, policyFiles, adminPolicyFiles, attachments, skipTrust, yolo, project, newProject, workspace, worktree, }) => {
6679
+ }, async ({ prompt, promptParts, model, sessionId, resumeLatest, createNewSession, approvalMode, approvalStrategy, approvalPolicy, mcpServers, allowedTools, includeDirs, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, outputFormat, sandbox, policyFiles, adminPolicyFiles, attachments, skipTrust, yolo, project, newProject, printTimeout, workspace, worktree, }) => {
6355
6680
  return handleGeminiRequestAsync({ sessionManager, asyncJobManager, logger, runtime }, {
6356
6681
  prompt,
6357
6682
  promptParts,
@@ -6378,6 +6703,7 @@ export function createGatewayServer(deps = {}) {
6378
6703
  yolo,
6379
6704
  project,
6380
6705
  newProject,
6706
+ printTimeout,
6381
6707
  workspace,
6382
6708
  worktree,
6383
6709
  });
@@ -6653,6 +6979,23 @@ export function createGatewayServer(deps = {}) {
6653
6979
  .string()
6654
6980
  .optional()
6655
6981
  .describe("Load the initial prompt from a file (--prompt-file)"),
6982
+ config: z.string().optional().describe("Config file path (Devin --config <PATH>)"),
6983
+ sandbox: z
6984
+ .boolean()
6985
+ .optional()
6986
+ .describe("Run the Devin session in a sandbox (Devin --sandbox). Safety control: never defaulted on; pass true to opt in."),
6987
+ exportSession: z
6988
+ .union([z.boolean(), z.string()])
6989
+ .optional()
6990
+ .describe("Export the session (Devin --export [<PATH>]). true emits a bare --export; a string path emits --export <path>."),
6991
+ respectWorkspaceTrust: z
6992
+ .boolean()
6993
+ .optional()
6994
+ .describe("Respect workspace trust (Devin --respect-workspace-trust <bool>). Devin defaults true for interactive and false for print mode; set explicitly to override."),
6995
+ agentConfig: z
6996
+ .string()
6997
+ .optional()
6998
+ .describe("Agent config file path (Devin --agent-config <FILE>)"),
6656
6999
  sessionId: z
6657
7000
  .string()
6658
7001
  .optional()
@@ -6681,12 +7024,17 @@ export function createGatewayServer(deps = {}) {
6681
7024
  destructiveHint: true,
6682
7025
  idempotentHint: false,
6683
7026
  openWorldHint: true,
6684
- }, async ({ prompt, model, permissionMode, promptFile, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, }) => {
7027
+ }, async ({ prompt, model, permissionMode, promptFile, config, sandbox, exportSession, respectWorkspaceTrust, agentConfig, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, }) => {
6685
7028
  return handleDevinRequestAsync({ sessionManager, asyncJobManager, logger, runtime }, {
6686
7029
  prompt,
6687
7030
  model,
6688
7031
  permissionMode,
6689
7032
  promptFile,
7033
+ config,
7034
+ sandbox,
7035
+ exportSession,
7036
+ respectWorkspaceTrust,
7037
+ agentConfig,
6690
7038
  sessionId,
6691
7039
  resumeLatest,
6692
7040
  createNewSession,
@@ -6989,6 +7337,18 @@ export function createGatewayServer(deps = {}) {
6989
7337
  result.stdout) {
6990
7338
  result.stdout = codexDisplayText(result.stdout);
6991
7339
  }
7340
+ if (callerIsRemote()) {
7341
+ const leakedId = result.providerSessionId;
7342
+ delete result.providerSessionId;
7343
+ if (leakedId) {
7344
+ if (result.stdout && result.stdout.includes(leakedId)) {
7345
+ result.stdout = result.stdout.split(leakedId).join("[redacted-session-id]");
7346
+ }
7347
+ if (result.stderr && result.stderr.includes(leakedId)) {
7348
+ result.stderr = result.stderr.split(leakedId).join("[redacted-session-id]");
7349
+ }
7350
+ }
7351
+ }
6992
7352
  return {
6993
7353
  content: [
6994
7354
  {
@@ -7232,10 +7592,7 @@ export function createGatewayServer(deps = {}) {
7232
7592
  .max(500)
7233
7593
  .default(50)
7234
7594
  .describe("Max number of approval records"),
7235
- cli: z
7236
- .enum(["claude", "codex", "gemini", "grok", "mistral"])
7237
- .optional()
7238
- .describe("Optional CLI filter"),
7595
+ cli: CLI_TYPE_ENUM.optional().describe("Optional CLI filter (any gateway CLI provider, derived from CLI_TYPES)"),
7239
7596
  }, {
7240
7597
  title: "Approval decisions",
7241
7598
  readOnlyHint: true,
@@ -7273,9 +7630,19 @@ export function createGatewayServer(deps = {}) {
7273
7630
  }, async ({ cli }) => {
7274
7631
  const cliInfo = getAvailableCliInfo();
7275
7632
  const apiRuntimes = enabledApiProviders(providers);
7633
+ const buildDiscoveredMap = (clis) => {
7634
+ const out = {};
7635
+ for (const c of clis) {
7636
+ out[c] = buildProviderDiscoveredView(getProviderDefinition(c), cliInfo[c], peekProviderCapabilitySet);
7637
+ }
7638
+ return out;
7639
+ };
7276
7640
  let result;
7277
7641
  if (cli && CLI_TYPES.includes(cli)) {
7278
- result = { [cli]: cliInfo[cli] };
7642
+ result = {
7643
+ [cli]: cliInfo[cli],
7644
+ discovered: buildDiscoveredMap([cli]),
7645
+ };
7279
7646
  }
7280
7647
  else if (cli) {
7281
7648
  const runtime = apiRuntimes.find(p => p.name === cli);
@@ -7283,7 +7650,11 @@ export function createGatewayServer(deps = {}) {
7283
7650
  }
7284
7651
  else {
7285
7652
  const apiProviders = apiRuntimes.map(apiProviderCatalogEntry);
7286
- result = { ...cliInfo, ...(apiProviders.length > 0 ? { apiProviders } : {}) };
7653
+ result = {
7654
+ ...cliInfo,
7655
+ discovered: buildDiscoveredMap(CLI_TYPES),
7656
+ ...(apiProviders.length > 0 ? { apiProviders } : {}),
7657
+ };
7287
7658
  }
7288
7659
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
7289
7660
  });
@@ -7330,6 +7701,7 @@ export function createGatewayServer(deps = {}) {
7330
7701
  includePaths,
7331
7702
  refresh,
7332
7703
  providersConfig: providers,
7704
+ acpConfig: runtime.acpConfig,
7333
7705
  });
7334
7706
  return { content: [{ type: "text", text: JSON.stringify(capabilities, null, 2) }] };
7335
7707
  });
@@ -7875,7 +8247,7 @@ async function initializeSessionManager() {
7875
8247
  });
7876
8248
  logger.info("File-based session manager initialized");
7877
8249
  }
7878
- resourceProvider = new ResourceProvider(sessionManager, performanceMetrics, getFlightRecorder(logger), getCacheAwarenessConfig(logger), getProvidersConfig(logger));
8250
+ resourceProvider = new ResourceProvider(sessionManager, performanceMetrics, getFlightRecorder(logger), getCacheAwarenessConfig(logger), getProvidersConfig(logger), undefined, getAcpConfig(logger));
7879
8251
  }
7880
8252
  function registerHealthResource(server) {
7881
8253
  if (db) {
@@ -7918,6 +8290,15 @@ function registerHealthResource(server) {
7918
8290
  async function shutdown(signal) {
7919
8291
  logger.info(`Received ${signal}, shutting down gracefully...`);
7920
8292
  try {
8293
+ if (asyncJobManager) {
8294
+ try {
8295
+ await asyncJobManager.dispose({ timeoutMs: 5000 });
8296
+ logger.info("Async job manager disposed");
8297
+ }
8298
+ catch (err) {
8299
+ logger.error("Async job manager dispose failed", err);
8300
+ }
8301
+ }
7921
8302
  await killAllProcessGroups();
7922
8303
  logger.info("All process groups terminated");
7923
8304
  if (activeHttpGateway) {
@@ -8331,6 +8712,7 @@ async function main() {
8331
8712
  "stdio";
8332
8713
  logger.info(`Starting llm-cli-gateway MCP server with ${transportMode} transport`);
8333
8714
  await initializeSessionManager();
8715
+ void warmProviderCapabilities({ logger }).catch(() => undefined);
8334
8716
  const serverDeps = {
8335
8717
  sessionManager,
8336
8718
  resourceProvider,