llm-cli-gateway 2.13.2 → 2.14.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +97 -0
- package/README.md +53 -26
- 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 +2 -0
- package/dist/async-job-manager.js +11 -0
- package/dist/codex-json-parser.d.ts +1 -0
- package/dist/codex-json-parser.js +6 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +47 -0
- 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 +484 -119
- package/dist/job-store.d.ts +45 -7
- package/dist/job-store.js +138 -17
- 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 +327 -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/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/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;
|
|
@@ -299,6 +310,91 @@ function mcpServerEnum() {
|
|
|
299
310
|
}
|
|
300
311
|
const CLI_TYPE_ENUM = z.enum(CLI_TYPES);
|
|
301
312
|
export const MAX_TURNS_SCHEMA = z.number().int().positive().safe().max(10_000);
|
|
313
|
+
const CLAUDE_PART_A_FIELDS = {
|
|
314
|
+
includeHookEvents: z
|
|
315
|
+
.boolean()
|
|
316
|
+
.optional()
|
|
317
|
+
.describe("Claude --include-hook-events: include all hook lifecycle events in the output stream. Only takes effect with outputFormat=stream-json (the default)."),
|
|
318
|
+
replayUserMessages: z
|
|
319
|
+
.boolean()
|
|
320
|
+
.optional()
|
|
321
|
+
.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)."),
|
|
322
|
+
systemPromptFile: z
|
|
323
|
+
.string()
|
|
324
|
+
.min(1)
|
|
325
|
+
.optional()
|
|
326
|
+
.describe("Claude --system-prompt-file: replace the system prompt from a file path (path variant of systemPrompt)."),
|
|
327
|
+
appendSystemPromptFile: z
|
|
328
|
+
.string()
|
|
329
|
+
.min(1)
|
|
330
|
+
.optional()
|
|
331
|
+
.describe("Claude --append-system-prompt-file: append a system prompt from a file path (path variant of appendSystemPrompt)."),
|
|
332
|
+
name: z
|
|
333
|
+
.string()
|
|
334
|
+
.min(1)
|
|
335
|
+
.optional()
|
|
336
|
+
.describe("Claude --name: display name for this session (shown in pickers/titles)."),
|
|
337
|
+
pluginDir: z
|
|
338
|
+
.array(z.string())
|
|
339
|
+
.optional()
|
|
340
|
+
.describe("Claude --plugin-dir: load a plugin from a directory or .zip for this session only. One --plugin-dir instance per entry."),
|
|
341
|
+
pluginUrl: z
|
|
342
|
+
.array(z.string())
|
|
343
|
+
.optional()
|
|
344
|
+
.describe("Claude --plugin-url: load a plugin .zip from a URL for this session only. One --plugin-url instance per entry."),
|
|
345
|
+
safeMode: z
|
|
346
|
+
.boolean()
|
|
347
|
+
.optional()
|
|
348
|
+
.describe("Claude --safe-mode: start with all customizations (CLAUDE.md, skills, plugins, hooks, MCP, commands, agents) disabled for troubleshooting. Explicit opt-in."),
|
|
349
|
+
bare: z
|
|
350
|
+
.boolean()
|
|
351
|
+
.optional()
|
|
352
|
+
.describe("Claude --bare: minimal mode (skip hooks, LSP, plugin sync, attribution, auto-memory, keychain reads, CLAUDE.md auto-discovery). Explicit opt-in."),
|
|
353
|
+
debug: z
|
|
354
|
+
.union([z.string(), z.boolean()])
|
|
355
|
+
.optional()
|
|
356
|
+
.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.'),
|
|
357
|
+
debugFile: z
|
|
358
|
+
.string()
|
|
359
|
+
.min(1)
|
|
360
|
+
.optional()
|
|
361
|
+
.describe("Claude --debug-file: write debug logs to a specific file path (enables debug mode)."),
|
|
362
|
+
};
|
|
363
|
+
const CODEX_PART_A_FIELDS = {
|
|
364
|
+
enable: z
|
|
365
|
+
.array(z.string())
|
|
366
|
+
.optional()
|
|
367
|
+
.describe("Codex --enable <FEATURE> (repeatable): enable a feature for this run (equivalent to -c features.<name>=true). Accepted on resume."),
|
|
368
|
+
disable: z
|
|
369
|
+
.array(z.string())
|
|
370
|
+
.optional()
|
|
371
|
+
.describe("Codex --disable <FEATURE> (repeatable): disable a feature for this run (equivalent to -c features.<name>=false). Accepted on resume."),
|
|
372
|
+
strictConfig: z
|
|
373
|
+
.boolean()
|
|
374
|
+
.optional()
|
|
375
|
+
.describe("Codex --strict-config: error out when config.toml contains fields not recognized by this Codex version. New sessions only."),
|
|
376
|
+
oss: z
|
|
377
|
+
.boolean()
|
|
378
|
+
.optional()
|
|
379
|
+
.describe("Codex --oss: use the open-source provider. New sessions only."),
|
|
380
|
+
localProvider: z
|
|
381
|
+
.enum(CODEX_LOCAL_PROVIDERS)
|
|
382
|
+
.optional()
|
|
383
|
+
.describe("Codex --local-provider: local OSS provider (lmstudio|ollama), used with oss. New sessions only."),
|
|
384
|
+
color: z
|
|
385
|
+
.enum(CODEX_COLOR_MODES)
|
|
386
|
+
.optional()
|
|
387
|
+
.describe("Codex --color: output color mode (always|never|auto). New sessions only."),
|
|
388
|
+
outputLastMessage: z
|
|
389
|
+
.string()
|
|
390
|
+
.min(1)
|
|
391
|
+
.optional()
|
|
392
|
+
.describe("Codex -o/--output-last-message <FILE>: write the agent's last message to a file. New sessions only."),
|
|
393
|
+
dangerouslyBypassHookTrust: z
|
|
394
|
+
.boolean()
|
|
395
|
+
.optional()
|
|
396
|
+
.describe("Codex --dangerously-bypass-hook-trust: run enabled hooks without persisted hook trust for this invocation. DANGEROUS. Explicit opt-in; never defaulted on."),
|
|
397
|
+
};
|
|
302
398
|
const GROK_GENERATED_SHAPE = deriveZodShapeFromGeneration(UPSTREAM_CLI_CONTRACTS.grok, GROK_FLAG_GENERATION);
|
|
303
399
|
export const MAX_TOKENS_SCHEMA = z.number().int().positive().safe().max(100_000_000);
|
|
304
400
|
export const MAX_PRICE_SCHEMA = z.number().positive().finite().min(1e-6).max(10_000);
|
|
@@ -367,7 +463,7 @@ export function resolveGatewayServerRuntime(deps = {}, options = {}) {
|
|
|
367
463
|
sessionManager: runtimeSessionManager,
|
|
368
464
|
resourceProvider: deps.resourceProvider ??
|
|
369
465
|
(options.isolateState
|
|
370
|
-
? new ResourceProvider(runtimeSessionManager, runtimePerformanceMetrics, runtimeFlightRecorder, deps.cacheAwareness ?? getCacheAwarenessConfig(runtimeLogger), deps.providers ?? getProvidersConfig(runtimeLogger))
|
|
466
|
+
? new ResourceProvider(runtimeSessionManager, runtimePerformanceMetrics, runtimeFlightRecorder, deps.cacheAwareness ?? getCacheAwarenessConfig(runtimeLogger), deps.providers ?? getProvidersConfig(runtimeLogger), undefined, deps.acpConfig ?? getAcpConfig(runtimeLogger))
|
|
371
467
|
: resourceProvider),
|
|
372
468
|
db: "db" in deps ? (deps.db ?? null) : db,
|
|
373
469
|
performanceMetrics: runtimePerformanceMetrics,
|
|
@@ -379,6 +475,7 @@ export function resolveGatewayServerRuntime(deps = {}, options = {}) {
|
|
|
379
475
|
cacheAwareness: deps.cacheAwareness ?? getCacheAwarenessConfig(runtimeLogger),
|
|
380
476
|
providers: deps.providers ?? getProvidersConfig(runtimeLogger),
|
|
381
477
|
acpConfig: deps.acpConfig ?? getAcpConfig(runtimeLogger),
|
|
478
|
+
adminConfig: deps.adminConfig ?? getAdminConfig(runtimeLogger),
|
|
382
479
|
workspaces: deps.workspaces ?? loadWorkspaceRegistry(runtimeLogger),
|
|
383
480
|
};
|
|
384
481
|
}
|
|
@@ -419,12 +516,28 @@ export async function runAcpTransport(deps, params) {
|
|
|
419
516
|
model: params.model,
|
|
420
517
|
sessionId: params.sessionId,
|
|
421
518
|
correlationId: corrId,
|
|
519
|
+
agentType: params.agentType,
|
|
422
520
|
});
|
|
521
|
+
const stop = result.stopReason;
|
|
522
|
+
const normalStop = stop === null || stop === "end_turn";
|
|
523
|
+
let warning = null;
|
|
524
|
+
if (!normalStop) {
|
|
525
|
+
warning =
|
|
526
|
+
`provider ended the turn with stop_reason=${stop}` +
|
|
527
|
+
(result.text.trim().length === 0 ? " and produced no output" : "") +
|
|
528
|
+
"; the response may be partial or refused.";
|
|
529
|
+
}
|
|
530
|
+
else if (result.text.trim().length === 0) {
|
|
531
|
+
warning =
|
|
532
|
+
"provider produced no assistant output (possible no-op, guardrail, or awaited input).";
|
|
533
|
+
}
|
|
534
|
+
const banner = `[gateway] transport=acp session=${result.gatewaySessionId}` +
|
|
535
|
+
(warning ? `\n[gateway] warning: ${warning}` : "");
|
|
423
536
|
return {
|
|
424
537
|
content: [
|
|
425
538
|
{
|
|
426
539
|
type: "text",
|
|
427
|
-
text:
|
|
540
|
+
text: `${banner}\n${result.text}`,
|
|
428
541
|
},
|
|
429
542
|
],
|
|
430
543
|
};
|
|
@@ -1153,7 +1266,7 @@ function resolveClaudeMcpConfig(operation, correlationId, requestedMcpServers, s
|
|
|
1153
1266
|
}
|
|
1154
1267
|
return { config: mcpConfig };
|
|
1155
1268
|
}
|
|
1156
|
-
function registerBaseResources(server, runtime) {
|
|
1269
|
+
export function registerBaseResources(server, runtime) {
|
|
1157
1270
|
for (const skill of loadedSkills) {
|
|
1158
1271
|
server.registerResource(`skill-${skill.name}`, `skills://${skill.name}`, {
|
|
1159
1272
|
title: skill.name,
|
|
@@ -1179,96 +1292,30 @@ function registerBaseResources(server, runtime) {
|
|
|
1179
1292
|
const contents = await runtime.resourceProvider.readResource(uri.href);
|
|
1180
1293
|
return { contents: contents ? [contents] : [] };
|
|
1181
1294
|
});
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
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
|
-
});
|
|
1295
|
+
for (const descriptor of generateResourceDescriptors()) {
|
|
1296
|
+
if (descriptor.exposesSessionsResource) {
|
|
1297
|
+
server.registerResource(`${descriptor.provider}-sessions`, descriptor.sessionsUri, {
|
|
1298
|
+
title: `${descriptor.icon} ${descriptor.sessionLabel}s`,
|
|
1299
|
+
description: `${descriptor.displayName} conversation sessions`,
|
|
1300
|
+
mimeType: "application/json",
|
|
1301
|
+
}, async (uri) => {
|
|
1302
|
+
runtime.logger.debug(`Reading ${descriptor.sessionsUri} resource`);
|
|
1303
|
+
const contents = await runtime.resourceProvider.readResource(uri.href);
|
|
1304
|
+
return { contents: contents ? [contents] : [] };
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
if (descriptor.exposesModelsResource) {
|
|
1308
|
+
server.registerResource(`${descriptor.provider}-models`, descriptor.modelsUri, {
|
|
1309
|
+
title: `${descriptor.icon} ${descriptor.displayName} Models & Capabilities`,
|
|
1310
|
+
description: `${descriptor.displayName} models and capabilities`,
|
|
1311
|
+
mimeType: "application/json",
|
|
1312
|
+
}, async (uri) => {
|
|
1313
|
+
runtime.logger.debug(`Reading ${descriptor.modelsUri} resource`);
|
|
1314
|
+
const contents = await runtime.resourceProvider.readResource(uri.href);
|
|
1315
|
+
return { contents: contents ? [contents] : [] };
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1272
1319
|
server.registerResource("performance-metrics", "metrics://performance", {
|
|
1273
1320
|
title: "📈 Performance Metrics",
|
|
1274
1321
|
description: "Request counts, latency, success/failure rates",
|
|
@@ -1380,9 +1427,30 @@ function registerBaseResources(server, runtime) {
|
|
|
1380
1427
|
const contents = await runtime.resourceProvider.readResource(uri.href);
|
|
1381
1428
|
return { contents: contents ? [contents] : [] };
|
|
1382
1429
|
});
|
|
1383
|
-
const
|
|
1384
|
-
|
|
1385
|
-
|
|
1430
|
+
for (const descriptor of generateProviderAcpDescriptors()) {
|
|
1431
|
+
server.registerResource(`${descriptor.provider}-provider-acp`, descriptor.acpUri, {
|
|
1432
|
+
title: `${descriptor.icon} ${descriptor.displayName} ACP Capabilities`,
|
|
1433
|
+
description: `Native ACP entrypoint, negotiated capabilities, supported session methods, and host-service policy for ${descriptor.displayName}`,
|
|
1434
|
+
mimeType: "application/json",
|
|
1435
|
+
}, async (uri) => {
|
|
1436
|
+
runtime.logger.debug(`Reading ${descriptor.acpUri} resource`);
|
|
1437
|
+
const contents = await runtime.resourceProvider.readResource(uri.href);
|
|
1438
|
+
return { contents: contents ? [contents] : [] };
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
server.registerResource("provider-acp", new ResourceTemplate("provider-acp://{provider}", { list: undefined }), {
|
|
1442
|
+
title: "Provider ACP Capabilities",
|
|
1443
|
+
description: "Read-only negotiated ACP capability record for one provider CLI (native: false for providers with no native ACP entrypoint)",
|
|
1444
|
+
mimeType: "application/json",
|
|
1445
|
+
}, async (uri, variables) => {
|
|
1446
|
+
const provider = Array.isArray(variables.provider)
|
|
1447
|
+
? variables.provider[0]
|
|
1448
|
+
: variables.provider;
|
|
1449
|
+
runtime.logger.debug(`Reading provider-acp://${provider}`);
|
|
1450
|
+
const contents = await runtime.resourceProvider.readResource(uri.href);
|
|
1451
|
+
return { contents: contents ? [contents] : [] };
|
|
1452
|
+
});
|
|
1453
|
+
const validationReceiptStore = runtime.asyncJobManager?.getValidationRunStore();
|
|
1386
1454
|
if (validationReceiptStore) {
|
|
1387
1455
|
server.registerResource("validation-receipt", new ResourceTemplate("validation-receipt://{validationId}", { list: undefined }), {
|
|
1388
1456
|
title: "Validation Receipt",
|
|
@@ -1428,10 +1496,33 @@ function resolvePromptOrPartsForPrep(args) {
|
|
|
1428
1496
|
stablePrefixTokens: resolved.stablePrefixTokens,
|
|
1429
1497
|
};
|
|
1430
1498
|
}
|
|
1499
|
+
function remoteHostPathFieldError(operation, corrId, fields) {
|
|
1500
|
+
const ctx = getRequestContext();
|
|
1501
|
+
const isRemote = ctx?.transport === "http" || ctx?.authKind === "oauth";
|
|
1502
|
+
if (!isRemote)
|
|
1503
|
+
return null;
|
|
1504
|
+
const present = Object.entries(fields)
|
|
1505
|
+
.filter(([, v]) => (Array.isArray(v) ? v.length > 0 : v !== undefined && v !== null))
|
|
1506
|
+
.map(([k]) => k);
|
|
1507
|
+
if (present.length === 0)
|
|
1508
|
+
return null;
|
|
1509
|
+
return createErrorResponse(operation, 1, `Remote HTTP/OAuth requests may not use host-path or plugin fields: ${present.join(", ")}. ` +
|
|
1510
|
+
`These are restricted to local callers; supply content inline or reference a registered workspace.`, corrId);
|
|
1511
|
+
}
|
|
1431
1512
|
export function prepareClaudeRequest(params, runtime = resolveGatewayServerRuntime()) {
|
|
1432
1513
|
const corrId = params.correlationId || randomUUID();
|
|
1433
1514
|
const cliInfo = getCliInfo();
|
|
1434
1515
|
const resolvedModel = resolveModelAlias("claude", params.model, cliInfo);
|
|
1516
|
+
const remoteFieldErr = remoteHostPathFieldError(params.operation, corrId, {
|
|
1517
|
+
settings: params.settings,
|
|
1518
|
+
systemPromptFile: params.systemPromptFile,
|
|
1519
|
+
appendSystemPromptFile: params.appendSystemPromptFile,
|
|
1520
|
+
pluginDir: params.pluginDir,
|
|
1521
|
+
pluginUrl: params.pluginUrl,
|
|
1522
|
+
debugFile: params.debugFile,
|
|
1523
|
+
});
|
|
1524
|
+
if (remoteFieldErr)
|
|
1525
|
+
return remoteFieldErr;
|
|
1435
1526
|
const inputResolution = resolvePromptOrPartsForPrep({
|
|
1436
1527
|
prompt: params.prompt,
|
|
1437
1528
|
promptParts: params.promptParts,
|
|
@@ -1651,6 +1742,17 @@ export function prepareClaudeRequest(params, runtime = resolveGatewayServerRunti
|
|
|
1651
1742
|
settingSources: params.settingSources,
|
|
1652
1743
|
settings: params.settings,
|
|
1653
1744
|
tools: params.tools,
|
|
1745
|
+
includeHookEvents: params.includeHookEvents,
|
|
1746
|
+
replayUserMessages: params.replayUserMessages,
|
|
1747
|
+
systemPromptFile: params.systemPromptFile,
|
|
1748
|
+
appendSystemPromptFile: params.appendSystemPromptFile,
|
|
1749
|
+
name: params.name,
|
|
1750
|
+
pluginDir: params.pluginDir,
|
|
1751
|
+
pluginUrl: params.pluginUrl,
|
|
1752
|
+
safeMode: params.safeMode,
|
|
1753
|
+
bare: params.bare,
|
|
1754
|
+
debug: params.debug,
|
|
1755
|
+
debugFile: params.debugFile,
|
|
1654
1756
|
}));
|
|
1655
1757
|
return {
|
|
1656
1758
|
corrId,
|
|
@@ -1673,6 +1775,13 @@ export function prepareCodexRequest(params, runtime = resolveGatewayServerRuntim
|
|
|
1673
1775
|
const corrId = params.correlationId || randomUUID();
|
|
1674
1776
|
const cliInfo = getCliInfo();
|
|
1675
1777
|
const resolvedModel = resolveModelAlias("codex", params.model, cliInfo);
|
|
1778
|
+
const remoteFieldErr = remoteHostPathFieldError(params.operation, corrId, {
|
|
1779
|
+
outputSchema: typeof params.outputSchema === "string" ? params.outputSchema : undefined,
|
|
1780
|
+
images: params.images,
|
|
1781
|
+
outputLastMessage: params.outputLastMessage,
|
|
1782
|
+
});
|
|
1783
|
+
if (remoteFieldErr)
|
|
1784
|
+
return remoteFieldErr;
|
|
1676
1785
|
const inputResolution = resolvePromptOrPartsForPrep({
|
|
1677
1786
|
prompt: params.prompt,
|
|
1678
1787
|
promptParts: params.promptParts,
|
|
@@ -1751,6 +1860,9 @@ export function prepareCodexRequest(params, runtime = resolveGatewayServerRuntim
|
|
|
1751
1860
|
if (params.dangerouslyBypassApprovalsAndSandbox) {
|
|
1752
1861
|
args.push("--dangerously-bypass-approvals-and-sandbox");
|
|
1753
1862
|
}
|
|
1863
|
+
if (params.dangerouslyBypassHookTrust) {
|
|
1864
|
+
args.push("--dangerously-bypass-hook-trust");
|
|
1865
|
+
}
|
|
1754
1866
|
args.push("--json");
|
|
1755
1867
|
args.push("--skip-git-repo-check");
|
|
1756
1868
|
let highImpactCleanup;
|
|
@@ -1763,6 +1875,21 @@ export function prepareCodexRequest(params, runtime = resolveGatewayServerRuntim
|
|
|
1763
1875
|
args.push("--add-dir", dir);
|
|
1764
1876
|
}
|
|
1765
1877
|
}
|
|
1878
|
+
if (params.oss) {
|
|
1879
|
+
args.push("--oss");
|
|
1880
|
+
}
|
|
1881
|
+
if (params.localProvider) {
|
|
1882
|
+
args.push("--local-provider", params.localProvider);
|
|
1883
|
+
}
|
|
1884
|
+
if (params.strictConfig) {
|
|
1885
|
+
args.push("--strict-config");
|
|
1886
|
+
}
|
|
1887
|
+
if (params.color) {
|
|
1888
|
+
args.push("--color", params.color);
|
|
1889
|
+
}
|
|
1890
|
+
if (params.outputLastMessage !== undefined) {
|
|
1891
|
+
args.push("--output-last-message", params.outputLastMessage);
|
|
1892
|
+
}
|
|
1766
1893
|
const high = prepareCodexHighImpactFlags({
|
|
1767
1894
|
outputSchema: params.outputSchema,
|
|
1768
1895
|
search: params.search,
|
|
@@ -1772,6 +1899,8 @@ export function prepareCodexRequest(params, runtime = resolveGatewayServerRuntim
|
|
|
1772
1899
|
images: params.images,
|
|
1773
1900
|
ignoreUserConfig: params.ignoreUserConfig,
|
|
1774
1901
|
ignoreRules: params.ignoreRules,
|
|
1902
|
+
enable: params.enable,
|
|
1903
|
+
disable: params.disable,
|
|
1775
1904
|
});
|
|
1776
1905
|
if (high.missingImagePath) {
|
|
1777
1906
|
return createErrorResponse(params.operation, 1, "", corrId, new Error(`images: path does not exist: ${high.missingImagePath}`));
|
|
@@ -1795,6 +1924,8 @@ export function prepareCodexRequest(params, runtime = resolveGatewayServerRuntim
|
|
|
1795
1924
|
images: params.images,
|
|
1796
1925
|
ignoreUserConfig: params.ignoreUserConfig,
|
|
1797
1926
|
ignoreRules: params.ignoreRules,
|
|
1927
|
+
enable: params.enable,
|
|
1928
|
+
disable: params.disable,
|
|
1798
1929
|
});
|
|
1799
1930
|
if (high.missingImagePath) {
|
|
1800
1931
|
return createErrorResponse(params.operation, 1, "", corrId, new Error(`images: path does not exist: ${high.missingImagePath}`));
|
|
@@ -1924,6 +2055,9 @@ export function prepareGeminiRequest(params, runtime = resolveGatewayServerRunti
|
|
|
1924
2055
|
if (params.newProject) {
|
|
1925
2056
|
args.push("--new-project");
|
|
1926
2057
|
}
|
|
2058
|
+
if (params.printTimeout !== undefined && params.printTimeout !== "") {
|
|
2059
|
+
args.push("--print-timeout", params.printTimeout);
|
|
2060
|
+
}
|
|
1927
2061
|
return {
|
|
1928
2062
|
corrId,
|
|
1929
2063
|
effectivePrompt,
|
|
@@ -1940,6 +2074,14 @@ export function prepareGrokRequest(params, runtime = resolveGatewayServerRuntime
|
|
|
1940
2074
|
const corrId = params.correlationId || randomUUID();
|
|
1941
2075
|
const cliInfo = getCliInfo();
|
|
1942
2076
|
const resolvedModel = resolveModelAlias("grok", params.model, cliInfo);
|
|
2077
|
+
const remoteFieldErr = remoteHostPathFieldError(params.operation, corrId, {
|
|
2078
|
+
promptFile: params.promptFile,
|
|
2079
|
+
leaderSocket: params.leaderSocket,
|
|
2080
|
+
rules: params.rules,
|
|
2081
|
+
agent: params.agent,
|
|
2082
|
+
});
|
|
2083
|
+
if (remoteFieldErr)
|
|
2084
|
+
return remoteFieldErr;
|
|
1943
2085
|
const inputResolution = resolvePromptOrPartsForPrep({
|
|
1944
2086
|
prompt: params.prompt,
|
|
1945
2087
|
promptParts: params.promptParts,
|
|
@@ -2202,6 +2344,9 @@ export function buildCliResponse(cli, stdout, optimizeResponse, corrId, sessionI
|
|
|
2202
2344
|
if (cli === "codex" && outputFormat !== "json") {
|
|
2203
2345
|
finalStdout = codexDisplayText(stdout);
|
|
2204
2346
|
}
|
|
2347
|
+
if (cli === "grok") {
|
|
2348
|
+
finalStdout = grokDisplayText(outputFormat, stdout);
|
|
2349
|
+
}
|
|
2205
2350
|
if (optimizeResponse && outputFormat !== "json") {
|
|
2206
2351
|
const optimized = optimizeResponseText(finalStdout);
|
|
2207
2352
|
logOptimizationTokens("response", corrId, finalStdout, optimized);
|
|
@@ -2217,11 +2362,11 @@ export function buildCliResponse(cli, stdout, optimizeResponse, corrId, sessionI
|
|
|
2217
2362
|
}
|
|
2218
2363
|
const derivedWarnings = [];
|
|
2219
2364
|
const extraStructured = {};
|
|
2220
|
-
let
|
|
2365
|
+
let resultError = false;
|
|
2221
2366
|
if (cli === "claude") {
|
|
2222
2367
|
const parsedResult = parseStreamJson(stdout);
|
|
2223
2368
|
if (parsedResult.isError) {
|
|
2224
|
-
|
|
2369
|
+
resultError = true;
|
|
2225
2370
|
extraStructured.resultIsError = true;
|
|
2226
2371
|
derivedWarnings.push({
|
|
2227
2372
|
code: "claude_result_error",
|
|
@@ -2234,8 +2379,27 @@ export function buildCliResponse(cli, stdout, optimizeResponse, corrId, sessionI
|
|
|
2234
2379
|
if (parsedCodex.threadId) {
|
|
2235
2380
|
extraStructured.codexSessionId = parsedCodex.threadId;
|
|
2236
2381
|
}
|
|
2382
|
+
if (parsedCodex.error) {
|
|
2383
|
+
resultError = true;
|
|
2384
|
+
extraStructured.resultIsError = true;
|
|
2385
|
+
derivedWarnings.push({
|
|
2386
|
+
code: "codex_result_error",
|
|
2387
|
+
message: `Codex exited 0 but reported a failed turn: ${parsedCodex.error}. The returned text may be partial.`,
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2237
2390
|
}
|
|
2238
|
-
if (
|
|
2391
|
+
if (cli === "gemini") {
|
|
2392
|
+
const parsedGemini = outputFormat === "stream-json" ? parseGeminiStreamJson(stdout) : parseGeminiJson(stdout);
|
|
2393
|
+
if (parsedGemini?.stopReason === "error") {
|
|
2394
|
+
resultError = true;
|
|
2395
|
+
extraStructured.resultIsError = true;
|
|
2396
|
+
derivedWarnings.push({
|
|
2397
|
+
code: "gemini_result_error",
|
|
2398
|
+
message: "Gemini exited 0 but the result event reported status:error. The returned text may be partial.",
|
|
2399
|
+
});
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
if (!resultError && finalStdout.trim().length === 0) {
|
|
2239
2403
|
extraStructured.emptyOutput = true;
|
|
2240
2404
|
derivedWarnings.push({
|
|
2241
2405
|
code: "empty_output",
|
|
@@ -2973,6 +3137,7 @@ export async function handleGeminiRequest(deps, params) {
|
|
|
2973
3137
|
yolo: params.yolo,
|
|
2974
3138
|
project: params.project,
|
|
2975
3139
|
newProject: params.newProject,
|
|
3140
|
+
printTimeout: params.printTimeout,
|
|
2976
3141
|
}, runtime);
|
|
2977
3142
|
if (!("args" in prep))
|
|
2978
3143
|
return prep;
|
|
@@ -3061,6 +3226,7 @@ export async function handleGeminiRequest(deps, params) {
|
|
|
3061
3226
|
}
|
|
3062
3227
|
}
|
|
3063
3228
|
const geminiUsage = extractUsageAndCost("gemini", stdout, params.outputFormat);
|
|
3229
|
+
const geminiMeta = extractProviderOutputMetadata("gemini", stdout, params.outputFormat);
|
|
3064
3230
|
safeFlightComplete(corrId, {
|
|
3065
3231
|
response: stdout,
|
|
3066
3232
|
durationMs,
|
|
@@ -3075,6 +3241,8 @@ export async function handleGeminiRequest(deps, params) {
|
|
|
3075
3241
|
cacheReadTokens: geminiUsage.cacheReadTokens,
|
|
3076
3242
|
cacheCreationTokens: geminiUsage.cacheCreationTokens,
|
|
3077
3243
|
costUsd: geminiUsage.costUsd,
|
|
3244
|
+
providerSessionId: geminiMeta.sessionId,
|
|
3245
|
+
stopReason: geminiMeta.stopReason,
|
|
3078
3246
|
}, runtime);
|
|
3079
3247
|
return response;
|
|
3080
3248
|
}
|
|
@@ -3122,6 +3290,7 @@ export async function handleGeminiRequestAsync(deps, params) {
|
|
|
3122
3290
|
yolo: params.yolo,
|
|
3123
3291
|
project: params.project,
|
|
3124
3292
|
newProject: params.newProject,
|
|
3293
|
+
printTimeout: params.printTimeout,
|
|
3125
3294
|
}, runtime);
|
|
3126
3295
|
if (!("args" in prep))
|
|
3127
3296
|
return prep;
|
|
@@ -3343,6 +3512,7 @@ export async function handleGrokRequest(deps, params) {
|
|
|
3343
3512
|
first.text = formatWorktreePrefix(worktreeResolution.worktreePath) + first.text;
|
|
3344
3513
|
}
|
|
3345
3514
|
}
|
|
3515
|
+
const grokMeta = extractProviderOutputMetadata("grok", stdout, params.outputFormat);
|
|
3346
3516
|
safeFlightComplete(corrId, {
|
|
3347
3517
|
response: stdout,
|
|
3348
3518
|
durationMs,
|
|
@@ -3352,6 +3522,8 @@ export async function handleGrokRequest(deps, params) {
|
|
|
3352
3522
|
optimizationApplied: params.optimizePrompt || (params.optimizeResponse ?? false),
|
|
3353
3523
|
exitCode: 0,
|
|
3354
3524
|
status: "completed",
|
|
3525
|
+
providerSessionId: grokMeta.sessionId,
|
|
3526
|
+
stopReason: grokMeta.stopReason,
|
|
3355
3527
|
}, runtime);
|
|
3356
3528
|
return response;
|
|
3357
3529
|
}
|
|
@@ -3506,6 +3678,14 @@ export async function handleGrokRequestAsync(deps, params) {
|
|
|
3506
3678
|
}
|
|
3507
3679
|
export function prepareDevinRequest(params, _runtime) {
|
|
3508
3680
|
const corrId = params.correlationId ?? randomUUID();
|
|
3681
|
+
const remoteFieldErr = remoteHostPathFieldError(params.operation, corrId, {
|
|
3682
|
+
promptFile: params.promptFile,
|
|
3683
|
+
config: params.config,
|
|
3684
|
+
agentConfig: params.agentConfig,
|
|
3685
|
+
exportSession: typeof params.exportSession === "string" ? params.exportSession : undefined,
|
|
3686
|
+
});
|
|
3687
|
+
if (remoteFieldErr)
|
|
3688
|
+
return remoteFieldErr;
|
|
3509
3689
|
let prompt = (params.prompt ?? "").trim();
|
|
3510
3690
|
if (!prompt) {
|
|
3511
3691
|
return createErrorResponse(params.operation, 1, "prompt is required and cannot be empty", corrId);
|
|
@@ -3520,6 +3700,21 @@ export function prepareDevinRequest(params, _runtime) {
|
|
|
3520
3700
|
args.push("--permission-mode", params.permissionMode);
|
|
3521
3701
|
if (params.promptFile)
|
|
3522
3702
|
args.push("--prompt-file", params.promptFile);
|
|
3703
|
+
if (params.config)
|
|
3704
|
+
args.push("--config", params.config);
|
|
3705
|
+
if (params.sandbox)
|
|
3706
|
+
args.push("--sandbox");
|
|
3707
|
+
if (typeof params.exportSession === "string") {
|
|
3708
|
+
args.push("--export", params.exportSession);
|
|
3709
|
+
}
|
|
3710
|
+
else if (params.exportSession === true) {
|
|
3711
|
+
args.push("--export");
|
|
3712
|
+
}
|
|
3713
|
+
if (params.respectWorkspaceTrust !== undefined) {
|
|
3714
|
+
args.push("--respect-workspace-trust", params.respectWorkspaceTrust ? "true" : "false");
|
|
3715
|
+
}
|
|
3716
|
+
if (params.agentConfig)
|
|
3717
|
+
args.push("--agent-config", params.agentConfig);
|
|
3523
3718
|
return {
|
|
3524
3719
|
corrId,
|
|
3525
3720
|
effectivePrompt: prompt,
|
|
@@ -3539,6 +3734,7 @@ export async function handleDevinRequest(deps, params) {
|
|
|
3539
3734
|
model: params.model,
|
|
3540
3735
|
sessionId: params.sessionId,
|
|
3541
3736
|
correlationId: params.correlationId,
|
|
3737
|
+
agentType: params.agentType,
|
|
3542
3738
|
});
|
|
3543
3739
|
}
|
|
3544
3740
|
const runtime = resolveHandlerRuntime(deps);
|
|
@@ -3548,6 +3744,11 @@ export async function handleDevinRequest(deps, params) {
|
|
|
3548
3744
|
model: params.model,
|
|
3549
3745
|
permissionMode: params.permissionMode,
|
|
3550
3746
|
promptFile: params.promptFile,
|
|
3747
|
+
config: params.config,
|
|
3748
|
+
sandbox: params.sandbox,
|
|
3749
|
+
exportSession: params.exportSession,
|
|
3750
|
+
respectWorkspaceTrust: params.respectWorkspaceTrust,
|
|
3751
|
+
agentConfig: params.agentConfig,
|
|
3551
3752
|
correlationId: params.correlationId,
|
|
3552
3753
|
optimizePrompt: params.optimizePrompt,
|
|
3553
3754
|
operation: "devin_request",
|
|
@@ -3651,6 +3852,11 @@ export async function handleDevinRequestAsync(deps, params) {
|
|
|
3651
3852
|
model: params.model,
|
|
3652
3853
|
permissionMode: params.permissionMode,
|
|
3653
3854
|
promptFile: params.promptFile,
|
|
3855
|
+
config: params.config,
|
|
3856
|
+
sandbox: params.sandbox,
|
|
3857
|
+
exportSession: params.exportSession,
|
|
3858
|
+
respectWorkspaceTrust: params.respectWorkspaceTrust,
|
|
3859
|
+
agentConfig: params.agentConfig,
|
|
3654
3860
|
correlationId: params.correlationId,
|
|
3655
3861
|
optimizePrompt: params.optimizePrompt,
|
|
3656
3862
|
operation: "devin_request_async",
|
|
@@ -4355,6 +4561,14 @@ export async function handleCodexRequestAsync(deps, params) {
|
|
|
4355
4561
|
ignoreRules: params.ignoreRules,
|
|
4356
4562
|
workingDir: params.workingDir,
|
|
4357
4563
|
addDir: params.addDir,
|
|
4564
|
+
enable: params.enable,
|
|
4565
|
+
disable: params.disable,
|
|
4566
|
+
strictConfig: params.strictConfig,
|
|
4567
|
+
oss: params.oss,
|
|
4568
|
+
localProvider: params.localProvider,
|
|
4569
|
+
color: params.color,
|
|
4570
|
+
outputLastMessage: params.outputLastMessage,
|
|
4571
|
+
dangerouslyBypassHookTrust: params.dangerouslyBypassHookTrust,
|
|
4358
4572
|
}, runtime);
|
|
4359
4573
|
if (!("args" in prep))
|
|
4360
4574
|
return prep;
|
|
@@ -4459,9 +4673,14 @@ export function createGatewayServer(deps = {}) {
|
|
|
4459
4673
|
registerValidationTools(server, {
|
|
4460
4674
|
asyncJobManager,
|
|
4461
4675
|
apiProviders: enabledApiProviders(providers),
|
|
4462
|
-
validationRunStore:
|
|
4676
|
+
validationRunStore: asyncJobManager.getValidationRunStore(),
|
|
4463
4677
|
});
|
|
4464
4678
|
registerWorkspaceTools(server, runtime);
|
|
4679
|
+
registerProviderAdminTools(server, {
|
|
4680
|
+
approvalManager: runtime.approvalManager,
|
|
4681
|
+
logger: runtime.logger,
|
|
4682
|
+
allowMutatingCliAdminOps: runtime.adminConfig.allowMutatingCliAdminOps,
|
|
4683
|
+
});
|
|
4465
4684
|
const apiProviderTools = registerApiProviderTools(server, runtime, providers, asyncJobsEnabled);
|
|
4466
4685
|
if (apiProviderTools.length > 0) {
|
|
4467
4686
|
runtime.logger.info(`Registered API provider tools: ${apiProviderTools.join(", ")}`);
|
|
@@ -4650,6 +4869,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
4650
4869
|
.array(z.string())
|
|
4651
4870
|
.optional()
|
|
4652
4871
|
.describe('Claude --tools: restrict the available built-in tool set (distinct from allowedTools permission gating). Pass [""] to disable all tools.'),
|
|
4872
|
+
...CLAUDE_PART_A_FIELDS,
|
|
4653
4873
|
workspace: providerWorkspaceAliasSchema(),
|
|
4654
4874
|
worktree: WORKTREE_SCHEMA.optional(),
|
|
4655
4875
|
approvalStrategy: z
|
|
@@ -4685,7 +4905,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
4685
4905
|
destructiveHint: true,
|
|
4686
4906
|
idempotentHint: false,
|
|
4687
4907
|
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, }) => {
|
|
4908
|
+
}, 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
4909
|
const startTime = Date.now();
|
|
4690
4910
|
if (systemPrompt !== undefined && appendSystemPrompt !== undefined) {
|
|
4691
4911
|
return createErrorResponse("claude", 1, "", correlationId, new Error("systemPrompt and appendSystemPrompt are mutually exclusive; use one or the other (not both)."));
|
|
@@ -4722,6 +4942,17 @@ export function createGatewayServer(deps = {}) {
|
|
|
4722
4942
|
settingSources,
|
|
4723
4943
|
settings,
|
|
4724
4944
|
tools,
|
|
4945
|
+
includeHookEvents,
|
|
4946
|
+
replayUserMessages,
|
|
4947
|
+
systemPromptFile,
|
|
4948
|
+
appendSystemPromptFile,
|
|
4949
|
+
name,
|
|
4950
|
+
pluginDir,
|
|
4951
|
+
pluginUrl,
|
|
4952
|
+
safeMode,
|
|
4953
|
+
bare,
|
|
4954
|
+
debug,
|
|
4955
|
+
debugFile,
|
|
4725
4956
|
}, runtime);
|
|
4726
4957
|
if (!("args" in prep))
|
|
4727
4958
|
return prep;
|
|
@@ -4849,6 +5080,8 @@ export function createGatewayServer(deps = {}) {
|
|
|
4849
5080
|
optimizationApplied: optimizePrompt || optimizeResponse,
|
|
4850
5081
|
exitCode: 0,
|
|
4851
5082
|
status: "completed",
|
|
5083
|
+
providerSessionId: parsed.sessionId ?? undefined,
|
|
5084
|
+
stopReason: parsed.stopReason ?? undefined,
|
|
4852
5085
|
}, runtime);
|
|
4853
5086
|
const streamResponse = buildCliResponse("claude", parsed.text, optimizeResponse, corrId, effectiveSessionId, prep, durationMs, undefined, outputFormat, warnings);
|
|
4854
5087
|
if (worktreeResolution.worktreePath) {
|
|
@@ -4859,6 +5092,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
4859
5092
|
}
|
|
4860
5093
|
return streamResponse;
|
|
4861
5094
|
}
|
|
5095
|
+
const claudeMeta = extractProviderOutputMetadata("claude", stdout, outputFormat);
|
|
4862
5096
|
safeFlightComplete(corrId, {
|
|
4863
5097
|
response: stdout,
|
|
4864
5098
|
durationMs,
|
|
@@ -4867,6 +5101,8 @@ export function createGatewayServer(deps = {}) {
|
|
|
4867
5101
|
optimizationApplied: optimizePrompt || optimizeResponse,
|
|
4868
5102
|
exitCode: 0,
|
|
4869
5103
|
status: "completed",
|
|
5104
|
+
providerSessionId: claudeMeta.sessionId,
|
|
5105
|
+
stopReason: claudeMeta.stopReason,
|
|
4870
5106
|
}, runtime);
|
|
4871
5107
|
const nonStreamResponse = buildCliResponse("claude", stdout, optimizeResponse, corrId, effectiveSessionId, prep, durationMs, undefined, outputFormat, warnings);
|
|
4872
5108
|
if (worktreeResolution.worktreePath) {
|
|
@@ -5005,6 +5241,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
5005
5241
|
.optional()
|
|
5006
5242
|
.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
5243
|
LOCAL_ADD_DIR_FIELD_SUFFIX),
|
|
5244
|
+
...CODEX_PART_A_FIELDS,
|
|
5008
5245
|
workspace: providerWorkspaceAliasSchema(),
|
|
5009
5246
|
worktree: WORKTREE_SCHEMA.optional(),
|
|
5010
5247
|
}, {
|
|
@@ -5013,7 +5250,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
5013
5250
|
destructiveHint: true,
|
|
5014
5251
|
idempotentHint: false,
|
|
5015
5252
|
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, }) => {
|
|
5253
|
+
}, 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
5254
|
const startTime = Date.now();
|
|
5018
5255
|
const prep = prepareCodexRequest({
|
|
5019
5256
|
prompt,
|
|
@@ -5044,6 +5281,14 @@ export function createGatewayServer(deps = {}) {
|
|
|
5044
5281
|
ignoreRules,
|
|
5045
5282
|
workingDir,
|
|
5046
5283
|
addDir,
|
|
5284
|
+
enable,
|
|
5285
|
+
disable,
|
|
5286
|
+
strictConfig,
|
|
5287
|
+
oss,
|
|
5288
|
+
localProvider,
|
|
5289
|
+
color,
|
|
5290
|
+
outputLastMessage,
|
|
5291
|
+
dangerouslyBypassHookTrust,
|
|
5047
5292
|
}, runtime);
|
|
5048
5293
|
if (!("args" in prep))
|
|
5049
5294
|
return prep;
|
|
@@ -5102,7 +5347,12 @@ export function createGatewayServer(deps = {}) {
|
|
|
5102
5347
|
errorMessage: stderr || `Exit code ${code}`,
|
|
5103
5348
|
status: "failed",
|
|
5104
5349
|
}, runtime);
|
|
5105
|
-
const
|
|
5350
|
+
const parsedCodexError = parseCodexJsonStream(stdout).error;
|
|
5351
|
+
const codexErrorDetail = stderr && stderr.trim().length > 0
|
|
5352
|
+
? stderr
|
|
5353
|
+
: parsedCodexError && parsedCodexError.trim().length > 0
|
|
5354
|
+
? parsedCodexError
|
|
5355
|
+
: codexDisplayText(stdout);
|
|
5106
5356
|
const codexResumeHint = sessionId &&
|
|
5107
5357
|
/not found|no such|unknown session|does not exist|invalid session/i.test(codexErrorDetail)
|
|
5108
5358
|
? `\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 +5380,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
5130
5380
|
}
|
|
5131
5381
|
logger.info(`[${corrId}] codex_request completed successfully in ${durationMs}ms`);
|
|
5132
5382
|
const codexUsage = extractUsageAndCost("codex", stdout, outputFormat);
|
|
5383
|
+
const codexMeta = extractProviderOutputMetadata("codex", stdout, outputFormat);
|
|
5133
5384
|
safeFlightComplete(corrId, {
|
|
5134
5385
|
response: codexFrResponse(outputFormat, stdout),
|
|
5135
5386
|
durationMs,
|
|
@@ -5143,6 +5394,8 @@ export function createGatewayServer(deps = {}) {
|
|
|
5143
5394
|
cacheReadTokens: codexUsage.cacheReadTokens,
|
|
5144
5395
|
cacheCreationTokens: codexUsage.cacheCreationTokens,
|
|
5145
5396
|
costUsd: codexUsage.costUsd,
|
|
5397
|
+
providerSessionId: codexMeta.sessionId,
|
|
5398
|
+
stopReason: codexMeta.stopReason,
|
|
5146
5399
|
}, runtime);
|
|
5147
5400
|
const codexResponse = buildCliResponse("codex", stdout, optimizeResponse, corrId, effectiveSessionId, prep, durationMs, undefined, outputFormat);
|
|
5148
5401
|
if (worktreeResolution.worktreePath) {
|
|
@@ -5264,7 +5517,12 @@ export function createGatewayServer(deps = {}) {
|
|
|
5264
5517
|
const { stdout, stderr, code } = result;
|
|
5265
5518
|
durationMs = Math.max(0, Date.now() - startTime);
|
|
5266
5519
|
if (code !== 0) {
|
|
5267
|
-
const
|
|
5520
|
+
const parsedCodexError = parseCodexJsonStream(stdout).error;
|
|
5521
|
+
const codexErrorDetail = stderr && stderr.trim().length > 0
|
|
5522
|
+
? stderr
|
|
5523
|
+
: parsedCodexError && parsedCodexError.trim().length > 0
|
|
5524
|
+
? parsedCodexError
|
|
5525
|
+
: codexDisplayText(stdout);
|
|
5268
5526
|
const codexResumeHint = sessionId &&
|
|
5269
5527
|
/not found|no such|unknown session|does not exist|invalid session/i.test(codexErrorDetail)
|
|
5270
5528
|
? `\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 +5626,11 @@ export function createGatewayServer(deps = {}) {
|
|
|
5368
5626
|
.boolean()
|
|
5369
5627
|
.optional()
|
|
5370
5628
|
.describe("Antigravity 1.0.13 --new-project: create a new project for this session. Mutually exclusive with project."),
|
|
5629
|
+
printTimeout: z
|
|
5630
|
+
.string()
|
|
5631
|
+
.min(1)
|
|
5632
|
+
.optional()
|
|
5633
|
+
.describe("Antigravity --print-timeout <DURATION>: print-mode wait timeout as a Go duration string (e.g. '5m0s', '30s')."),
|
|
5371
5634
|
workspace: providerWorkspaceAliasSchema(),
|
|
5372
5635
|
worktree: WORKTREE_SCHEMA.optional(),
|
|
5373
5636
|
}, {
|
|
@@ -5376,7 +5639,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
5376
5639
|
destructiveHint: true,
|
|
5377
5640
|
idempotentHint: false,
|
|
5378
5641
|
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, }) => {
|
|
5642
|
+
}, 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
5643
|
return handleGeminiRequest({ sessionManager, logger, runtime }, {
|
|
5381
5644
|
prompt,
|
|
5382
5645
|
promptParts,
|
|
@@ -5404,6 +5667,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
5404
5667
|
yolo,
|
|
5405
5668
|
project,
|
|
5406
5669
|
newProject,
|
|
5670
|
+
printTimeout,
|
|
5407
5671
|
workspace,
|
|
5408
5672
|
worktree,
|
|
5409
5673
|
});
|
|
@@ -5577,6 +5841,27 @@ export function createGatewayServer(deps = {}) {
|
|
|
5577
5841
|
.string()
|
|
5578
5842
|
.optional()
|
|
5579
5843
|
.describe("Load the initial prompt from a file (--prompt-file)"),
|
|
5844
|
+
config: z.string().optional().describe("Config file path (Devin --config <PATH>)"),
|
|
5845
|
+
sandbox: z
|
|
5846
|
+
.boolean()
|
|
5847
|
+
.optional()
|
|
5848
|
+
.describe("Run the Devin session in a sandbox (Devin --sandbox). Safety control: never defaulted on; pass true to opt in."),
|
|
5849
|
+
exportSession: z
|
|
5850
|
+
.union([z.boolean(), z.string()])
|
|
5851
|
+
.optional()
|
|
5852
|
+
.describe("Export the session (Devin --export [<PATH>]). true emits a bare --export; a string path emits --export <path>."),
|
|
5853
|
+
respectWorkspaceTrust: z
|
|
5854
|
+
.boolean()
|
|
5855
|
+
.optional()
|
|
5856
|
+
.describe("Respect workspace trust (Devin --respect-workspace-trust <bool>). Devin defaults true for interactive and false for print mode; set explicitly to override."),
|
|
5857
|
+
agentConfig: z
|
|
5858
|
+
.string()
|
|
5859
|
+
.optional()
|
|
5860
|
+
.describe("Agent config file path (Devin --agent-config <FILE>)"),
|
|
5861
|
+
agentType: z
|
|
5862
|
+
.enum(DEVIN_ACP_AGENT_TYPES)
|
|
5863
|
+
.optional()
|
|
5864
|
+
.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
5865
|
sessionId: z
|
|
5581
5866
|
.string()
|
|
5582
5867
|
.optional()
|
|
@@ -5606,13 +5891,19 @@ export function createGatewayServer(deps = {}) {
|
|
|
5606
5891
|
destructiveHint: true,
|
|
5607
5892
|
idempotentHint: false,
|
|
5608
5893
|
openWorldHint: true,
|
|
5609
|
-
}, async ({ prompt, model, transport, permissionMode, promptFile, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, }) => {
|
|
5894
|
+
}, async ({ prompt, model, transport, permissionMode, promptFile, config, sandbox, exportSession, respectWorkspaceTrust, agentConfig, agentType, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, optimizeResponse, idleTimeoutMs, forceRefresh, }) => {
|
|
5610
5895
|
return handleDevinRequest({ sessionManager, logger, runtime }, {
|
|
5611
5896
|
prompt,
|
|
5612
5897
|
model,
|
|
5613
5898
|
transport,
|
|
5614
5899
|
permissionMode,
|
|
5615
5900
|
promptFile,
|
|
5901
|
+
config,
|
|
5902
|
+
sandbox,
|
|
5903
|
+
exportSession,
|
|
5904
|
+
respectWorkspaceTrust,
|
|
5905
|
+
agentConfig,
|
|
5906
|
+
agentType,
|
|
5616
5907
|
sessionId,
|
|
5617
5908
|
resumeLatest,
|
|
5618
5909
|
createNewSession,
|
|
@@ -5959,6 +6250,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
5959
6250
|
.array(z.string())
|
|
5960
6251
|
.optional()
|
|
5961
6252
|
.describe('Claude --tools: restrict the available built-in tool set (distinct from allowedTools permission gating). Pass [""] to disable all tools.'),
|
|
6253
|
+
...CLAUDE_PART_A_FIELDS,
|
|
5962
6254
|
workspace: providerWorkspaceAliasSchema(),
|
|
5963
6255
|
worktree: WORKTREE_SCHEMA.optional(),
|
|
5964
6256
|
approvalStrategy: z
|
|
@@ -5993,7 +6285,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
5993
6285
|
destructiveHint: true,
|
|
5994
6286
|
idempotentHint: false,
|
|
5995
6287
|
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, }) => {
|
|
6288
|
+
}, 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
6289
|
if (systemPrompt !== undefined && appendSystemPrompt !== undefined) {
|
|
5998
6290
|
return createErrorResponse("claude", 1, "", correlationId, new Error("systemPrompt and appendSystemPrompt are mutually exclusive; use one or the other (not both)."));
|
|
5999
6291
|
}
|
|
@@ -6029,6 +6321,17 @@ export function createGatewayServer(deps = {}) {
|
|
|
6029
6321
|
settingSources,
|
|
6030
6322
|
settings,
|
|
6031
6323
|
tools,
|
|
6324
|
+
includeHookEvents,
|
|
6325
|
+
replayUserMessages,
|
|
6326
|
+
systemPromptFile,
|
|
6327
|
+
appendSystemPromptFile,
|
|
6328
|
+
name,
|
|
6329
|
+
pluginDir,
|
|
6330
|
+
pluginUrl,
|
|
6331
|
+
safeMode,
|
|
6332
|
+
bare,
|
|
6333
|
+
debug,
|
|
6334
|
+
debugFile,
|
|
6032
6335
|
}, runtime);
|
|
6033
6336
|
if (!("args" in prep))
|
|
6034
6337
|
return prep;
|
|
@@ -6216,6 +6519,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
6216
6519
|
.optional()
|
|
6217
6520
|
.describe("Codex --add-dir <DIR>: additional writable workspace directories (repeat per entry). New sessions only." +
|
|
6218
6521
|
LOCAL_ADD_DIR_FIELD_SUFFIX),
|
|
6522
|
+
...CODEX_PART_A_FIELDS,
|
|
6219
6523
|
workspace: providerWorkspaceAliasSchema(),
|
|
6220
6524
|
worktree: WORKTREE_SCHEMA.optional(),
|
|
6221
6525
|
}, {
|
|
@@ -6224,7 +6528,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
6224
6528
|
destructiveHint: true,
|
|
6225
6529
|
idempotentHint: false,
|
|
6226
6530
|
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, }) => {
|
|
6531
|
+
}, 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
6532
|
return handleCodexRequestAsync({ sessionManager, asyncJobManager, logger, runtime }, {
|
|
6229
6533
|
prompt,
|
|
6230
6534
|
promptParts,
|
|
@@ -6255,6 +6559,14 @@ export function createGatewayServer(deps = {}) {
|
|
|
6255
6559
|
ignoreRules,
|
|
6256
6560
|
workingDir,
|
|
6257
6561
|
addDir,
|
|
6562
|
+
enable,
|
|
6563
|
+
disable,
|
|
6564
|
+
strictConfig,
|
|
6565
|
+
oss,
|
|
6566
|
+
localProvider,
|
|
6567
|
+
color,
|
|
6568
|
+
outputLastMessage,
|
|
6569
|
+
dangerouslyBypassHookTrust,
|
|
6258
6570
|
workspace,
|
|
6259
6571
|
worktree,
|
|
6260
6572
|
});
|
|
@@ -6343,6 +6655,11 @@ export function createGatewayServer(deps = {}) {
|
|
|
6343
6655
|
.boolean()
|
|
6344
6656
|
.optional()
|
|
6345
6657
|
.describe("Antigravity 1.0.13 --new-project: create a new project for this session. Mutually exclusive with project."),
|
|
6658
|
+
printTimeout: z
|
|
6659
|
+
.string()
|
|
6660
|
+
.min(1)
|
|
6661
|
+
.optional()
|
|
6662
|
+
.describe("Antigravity --print-timeout <DURATION>: print-mode wait timeout as a Go duration string (e.g. '5m0s', '30s')."),
|
|
6346
6663
|
workspace: providerWorkspaceAliasSchema(),
|
|
6347
6664
|
worktree: WORKTREE_SCHEMA.optional(),
|
|
6348
6665
|
}, {
|
|
@@ -6351,7 +6668,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
6351
6668
|
destructiveHint: true,
|
|
6352
6669
|
idempotentHint: false,
|
|
6353
6670
|
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, }) => {
|
|
6671
|
+
}, 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
6672
|
return handleGeminiRequestAsync({ sessionManager, asyncJobManager, logger, runtime }, {
|
|
6356
6673
|
prompt,
|
|
6357
6674
|
promptParts,
|
|
@@ -6378,6 +6695,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
6378
6695
|
yolo,
|
|
6379
6696
|
project,
|
|
6380
6697
|
newProject,
|
|
6698
|
+
printTimeout,
|
|
6381
6699
|
workspace,
|
|
6382
6700
|
worktree,
|
|
6383
6701
|
});
|
|
@@ -6653,6 +6971,23 @@ export function createGatewayServer(deps = {}) {
|
|
|
6653
6971
|
.string()
|
|
6654
6972
|
.optional()
|
|
6655
6973
|
.describe("Load the initial prompt from a file (--prompt-file)"),
|
|
6974
|
+
config: z.string().optional().describe("Config file path (Devin --config <PATH>)"),
|
|
6975
|
+
sandbox: z
|
|
6976
|
+
.boolean()
|
|
6977
|
+
.optional()
|
|
6978
|
+
.describe("Run the Devin session in a sandbox (Devin --sandbox). Safety control: never defaulted on; pass true to opt in."),
|
|
6979
|
+
exportSession: z
|
|
6980
|
+
.union([z.boolean(), z.string()])
|
|
6981
|
+
.optional()
|
|
6982
|
+
.describe("Export the session (Devin --export [<PATH>]). true emits a bare --export; a string path emits --export <path>."),
|
|
6983
|
+
respectWorkspaceTrust: z
|
|
6984
|
+
.boolean()
|
|
6985
|
+
.optional()
|
|
6986
|
+
.describe("Respect workspace trust (Devin --respect-workspace-trust <bool>). Devin defaults true for interactive and false for print mode; set explicitly to override."),
|
|
6987
|
+
agentConfig: z
|
|
6988
|
+
.string()
|
|
6989
|
+
.optional()
|
|
6990
|
+
.describe("Agent config file path (Devin --agent-config <FILE>)"),
|
|
6656
6991
|
sessionId: z
|
|
6657
6992
|
.string()
|
|
6658
6993
|
.optional()
|
|
@@ -6681,12 +7016,17 @@ export function createGatewayServer(deps = {}) {
|
|
|
6681
7016
|
destructiveHint: true,
|
|
6682
7017
|
idempotentHint: false,
|
|
6683
7018
|
openWorldHint: true,
|
|
6684
|
-
}, async ({ prompt, model, permissionMode, promptFile, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, }) => {
|
|
7019
|
+
}, async ({ prompt, model, permissionMode, promptFile, config, sandbox, exportSession, respectWorkspaceTrust, agentConfig, sessionId, resumeLatest, createNewSession, correlationId, optimizePrompt, idleTimeoutMs, forceRefresh, }) => {
|
|
6685
7020
|
return handleDevinRequestAsync({ sessionManager, asyncJobManager, logger, runtime }, {
|
|
6686
7021
|
prompt,
|
|
6687
7022
|
model,
|
|
6688
7023
|
permissionMode,
|
|
6689
7024
|
promptFile,
|
|
7025
|
+
config,
|
|
7026
|
+
sandbox,
|
|
7027
|
+
exportSession,
|
|
7028
|
+
respectWorkspaceTrust,
|
|
7029
|
+
agentConfig,
|
|
6690
7030
|
sessionId,
|
|
6691
7031
|
resumeLatest,
|
|
6692
7032
|
createNewSession,
|
|
@@ -6989,6 +7329,18 @@ export function createGatewayServer(deps = {}) {
|
|
|
6989
7329
|
result.stdout) {
|
|
6990
7330
|
result.stdout = codexDisplayText(result.stdout);
|
|
6991
7331
|
}
|
|
7332
|
+
if (callerIsRemote()) {
|
|
7333
|
+
const leakedId = result.providerSessionId;
|
|
7334
|
+
delete result.providerSessionId;
|
|
7335
|
+
if (leakedId) {
|
|
7336
|
+
if (result.stdout && result.stdout.includes(leakedId)) {
|
|
7337
|
+
result.stdout = result.stdout.split(leakedId).join("[redacted-session-id]");
|
|
7338
|
+
}
|
|
7339
|
+
if (result.stderr && result.stderr.includes(leakedId)) {
|
|
7340
|
+
result.stderr = result.stderr.split(leakedId).join("[redacted-session-id]");
|
|
7341
|
+
}
|
|
7342
|
+
}
|
|
7343
|
+
}
|
|
6992
7344
|
return {
|
|
6993
7345
|
content: [
|
|
6994
7346
|
{
|
|
@@ -7232,10 +7584,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
7232
7584
|
.max(500)
|
|
7233
7585
|
.default(50)
|
|
7234
7586
|
.describe("Max number of approval records"),
|
|
7235
|
-
cli:
|
|
7236
|
-
.enum(["claude", "codex", "gemini", "grok", "mistral"])
|
|
7237
|
-
.optional()
|
|
7238
|
-
.describe("Optional CLI filter"),
|
|
7587
|
+
cli: CLI_TYPE_ENUM.optional().describe("Optional CLI filter (any gateway CLI provider, derived from CLI_TYPES)"),
|
|
7239
7588
|
}, {
|
|
7240
7589
|
title: "Approval decisions",
|
|
7241
7590
|
readOnlyHint: true,
|
|
@@ -7273,9 +7622,19 @@ export function createGatewayServer(deps = {}) {
|
|
|
7273
7622
|
}, async ({ cli }) => {
|
|
7274
7623
|
const cliInfo = getAvailableCliInfo();
|
|
7275
7624
|
const apiRuntimes = enabledApiProviders(providers);
|
|
7625
|
+
const buildDiscoveredMap = (clis) => {
|
|
7626
|
+
const out = {};
|
|
7627
|
+
for (const c of clis) {
|
|
7628
|
+
out[c] = buildProviderDiscoveredView(getProviderDefinition(c), cliInfo[c], peekProviderCapabilitySet);
|
|
7629
|
+
}
|
|
7630
|
+
return out;
|
|
7631
|
+
};
|
|
7276
7632
|
let result;
|
|
7277
7633
|
if (cli && CLI_TYPES.includes(cli)) {
|
|
7278
|
-
result = {
|
|
7634
|
+
result = {
|
|
7635
|
+
[cli]: cliInfo[cli],
|
|
7636
|
+
discovered: buildDiscoveredMap([cli]),
|
|
7637
|
+
};
|
|
7279
7638
|
}
|
|
7280
7639
|
else if (cli) {
|
|
7281
7640
|
const runtime = apiRuntimes.find(p => p.name === cli);
|
|
@@ -7283,7 +7642,11 @@ export function createGatewayServer(deps = {}) {
|
|
|
7283
7642
|
}
|
|
7284
7643
|
else {
|
|
7285
7644
|
const apiProviders = apiRuntimes.map(apiProviderCatalogEntry);
|
|
7286
|
-
result = {
|
|
7645
|
+
result = {
|
|
7646
|
+
...cliInfo,
|
|
7647
|
+
discovered: buildDiscoveredMap(CLI_TYPES),
|
|
7648
|
+
...(apiProviders.length > 0 ? { apiProviders } : {}),
|
|
7649
|
+
};
|
|
7287
7650
|
}
|
|
7288
7651
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
7289
7652
|
});
|
|
@@ -7330,6 +7693,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
7330
7693
|
includePaths,
|
|
7331
7694
|
refresh,
|
|
7332
7695
|
providersConfig: providers,
|
|
7696
|
+
acpConfig: runtime.acpConfig,
|
|
7333
7697
|
});
|
|
7334
7698
|
return { content: [{ type: "text", text: JSON.stringify(capabilities, null, 2) }] };
|
|
7335
7699
|
});
|
|
@@ -7875,7 +8239,7 @@ async function initializeSessionManager() {
|
|
|
7875
8239
|
});
|
|
7876
8240
|
logger.info("File-based session manager initialized");
|
|
7877
8241
|
}
|
|
7878
|
-
resourceProvider = new ResourceProvider(sessionManager, performanceMetrics, getFlightRecorder(logger), getCacheAwarenessConfig(logger), getProvidersConfig(logger));
|
|
8242
|
+
resourceProvider = new ResourceProvider(sessionManager, performanceMetrics, getFlightRecorder(logger), getCacheAwarenessConfig(logger), getProvidersConfig(logger), undefined, getAcpConfig(logger));
|
|
7879
8243
|
}
|
|
7880
8244
|
function registerHealthResource(server) {
|
|
7881
8245
|
if (db) {
|
|
@@ -8331,6 +8695,7 @@ async function main() {
|
|
|
8331
8695
|
"stdio";
|
|
8332
8696
|
logger.info(`Starting llm-cli-gateway MCP server with ${transportMode} transport`);
|
|
8333
8697
|
await initializeSessionManager();
|
|
8698
|
+
void warmProviderCapabilities({ logger }).catch(() => undefined);
|
|
8334
8699
|
const serverDeps = {
|
|
8335
8700
|
sessionManager,
|
|
8336
8701
|
resourceProvider,
|