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
@@ -54,6 +54,16 @@ function ensureCacheControlTtlSecondsColumn(db) {
54
54
  db.exec("ALTER TABLE requests ADD COLUMN cache_control_ttl_seconds INTEGER");
55
55
  }
56
56
  }
57
+ function ensureMetadataProviderSessionColumns(db) {
58
+ const rows = db.prepare("PRAGMA table_info(gateway_metadata)").all();
59
+ const names = new Set(rows.map((row) => (row && typeof row.name === "string" ? row.name : "")));
60
+ if (!names.has("provider_session_id")) {
61
+ db.exec("ALTER TABLE gateway_metadata ADD COLUMN provider_session_id TEXT");
62
+ }
63
+ if (!names.has("stop_reason")) {
64
+ db.exec("ALTER TABLE gateway_metadata ADD COLUMN stop_reason TEXT");
65
+ }
66
+ }
57
67
  export function resolveFlightRecorderDbPath() {
58
68
  const configured = process.env.LLM_GATEWAY_LOGS_DB;
59
69
  if (configured !== undefined) {
@@ -147,6 +157,8 @@ export class FlightRecorder {
147
157
  http_status INTEGER,
148
158
  error_message TEXT,
149
159
  async_job_id TEXT,
160
+ provider_session_id TEXT,
161
+ stop_reason TEXT,
150
162
  status TEXT NOT NULL DEFAULT 'started'
151
163
  );
152
164
 
@@ -180,6 +192,10 @@ export class FlightRecorder {
180
192
  this.db
181
193
  .prepare("INSERT OR IGNORE INTO _migrations(version, applied_at) VALUES(6, ?)")
182
194
  .run(new Date().toISOString());
195
+ ensureMetadataProviderSessionColumns(this.db);
196
+ this.db
197
+ .prepare("INSERT OR IGNORE INTO _migrations(version, applied_at) VALUES(7, ?)")
198
+ .run(new Date().toISOString());
183
199
  if (process.platform !== "win32") {
184
200
  try {
185
201
  chmodSync(dbPath, 0o600);
@@ -240,6 +256,8 @@ export class FlightRecorder {
240
256
  exit_code = @exit_code,
241
257
  http_status = @http_status,
242
258
  error_message = @error_message,
259
+ provider_session_id = @provider_session_id,
260
+ stop_reason = @stop_reason,
243
261
  status = @status
244
262
  WHERE request_id = @id AND status = 'started'
245
263
  `);
@@ -267,6 +285,8 @@ export class FlightRecorder {
267
285
  exit_code: result.exitCode,
268
286
  http_status: result.httpStatus ?? null,
269
287
  error_message: result.errorMessage ?? null,
288
+ provider_session_id: result.providerSessionId ?? null,
289
+ stop_reason: result.stopReason ?? null,
270
290
  status: result.status,
271
291
  });
272
292
  });
@@ -6,6 +6,8 @@ export interface GeminiUsage {
6
6
  export interface GeminiJsonParseResult {
7
7
  usage?: GeminiUsage;
8
8
  response?: string;
9
+ sessionId?: string;
10
+ stopReason?: string;
9
11
  }
10
12
  export declare function parseGeminiJson(stdout: string): GeminiJsonParseResult | null;
11
13
  export declare function parseGeminiStreamJson(stdout: string): GeminiJsonParseResult | null;
@@ -1,22 +1,47 @@
1
- export function parseGeminiJson(stdout) {
2
- const trimmed = stdout.trim();
3
- if (!trimmed) {
4
- return null;
5
- }
6
- let parsed;
1
+ function parseTolerantJsonObject(text) {
7
2
  try {
8
- parsed = JSON.parse(trimmed);
3
+ const v = JSON.parse(text);
4
+ if (v && typeof v === "object")
5
+ return v;
9
6
  }
10
7
  catch {
8
+ }
9
+ const start = text.indexOf("{");
10
+ const end = text.lastIndexOf("}");
11
+ if (start >= 0 && end > start) {
12
+ try {
13
+ const v = JSON.parse(text.slice(start, end + 1));
14
+ if (v && typeof v === "object")
15
+ return v;
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ return null;
22
+ }
23
+ export function parseGeminiJson(stdout) {
24
+ const trimmed = stdout.trim();
25
+ if (!trimmed) {
11
26
  return null;
12
27
  }
13
- if (!parsed || typeof parsed !== "object") {
28
+ const parsed = parseTolerantJsonObject(trimmed);
29
+ if (!parsed) {
14
30
  return null;
15
31
  }
16
32
  const result = {};
17
33
  if (typeof parsed.response === "string") {
18
34
  result.response = parsed.response;
19
35
  }
36
+ if (typeof parsed.session_id === "string") {
37
+ result.sessionId = parsed.session_id;
38
+ }
39
+ else if (typeof parsed.sessionId === "string") {
40
+ result.sessionId = parsed.sessionId;
41
+ }
42
+ if (typeof parsed.status === "string") {
43
+ result.stopReason = parsed.status;
44
+ }
20
45
  const meta = parsed.usageMetadata;
21
46
  if (meta && typeof meta === "object") {
22
47
  const input = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : undefined;
@@ -56,12 +81,24 @@ export function parseGeminiStreamJson(stdout) {
56
81
  if (!event || typeof event !== "object")
57
82
  continue;
58
83
  sawAnyLine = true;
84
+ if (event.type === "init" && typeof event.session_id === "string") {
85
+ result.sessionId = event.session_id;
86
+ continue;
87
+ }
59
88
  if (event.type === "message" &&
60
89
  event.role === "assistant" &&
61
90
  typeof event.content === "string") {
91
+ if (event.delta === false || event.is_delta === false) {
92
+ assistantChunks.length = 0;
93
+ }
62
94
  assistantChunks.push(event.content);
63
95
  continue;
64
96
  }
97
+ if (event.type === "result") {
98
+ if (typeof event.status === "string") {
99
+ result.stopReason = event.status;
100
+ }
101
+ }
65
102
  if (event.type === "result" && event.stats && typeof event.stats === "object") {
66
103
  const stats = event.stats;
67
104
  const input = typeof stats.input_tokens === "number" ? stats.input_tokens : undefined;
@@ -0,0 +1,14 @@
1
+ export interface GrokJsonParseResult {
2
+ text?: string;
3
+ stopReason?: string;
4
+ sessionId?: string;
5
+ requestId?: string;
6
+ thought?: string;
7
+ error?: string;
8
+ sawEvent?: boolean;
9
+ usageAbsent: true;
10
+ }
11
+ export declare function parseGrokJson(stdout: string): GrokJsonParseResult | null;
12
+ export declare function parseGrokStreamingJson(stdout: string): GrokJsonParseResult | null;
13
+ export declare function parseGrokOutput(outputFormat: string | undefined, stdout: string): GrokJsonParseResult | null;
14
+ export declare function grokDisplayText(outputFormat: string | undefined, stdout: string): string;
@@ -0,0 +1,156 @@
1
+ function str(value) {
2
+ return typeof value === "string" ? value : undefined;
3
+ }
4
+ function deltaText(event) {
5
+ return str(event.data) ?? str(event.text) ?? str(event.content) ?? str(event.delta);
6
+ }
7
+ function deltaThought(event) {
8
+ return (str(event.data) ??
9
+ str(event.thought) ??
10
+ str(event.text) ??
11
+ str(event.content) ??
12
+ str(event.delta));
13
+ }
14
+ function parseTolerantGrokObject(text) {
15
+ try {
16
+ const v = JSON.parse(text);
17
+ if (v && typeof v === "object" && !Array.isArray(v))
18
+ return v;
19
+ }
20
+ catch {
21
+ }
22
+ const start = text.indexOf("{");
23
+ const end = text.lastIndexOf("}");
24
+ if (start >= 0 && end > start) {
25
+ try {
26
+ const v = JSON.parse(text.slice(start, end + 1));
27
+ if (v && typeof v === "object" && !Array.isArray(v))
28
+ return v;
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ return null;
35
+ }
36
+ export function parseGrokJson(stdout) {
37
+ const trimmed = stdout.trim();
38
+ if (!trimmed) {
39
+ return null;
40
+ }
41
+ const parsed = parseTolerantGrokObject(trimmed);
42
+ if (!parsed) {
43
+ return null;
44
+ }
45
+ const result = { sawEvent: true, usageAbsent: true };
46
+ const text = str(parsed.text);
47
+ if (text !== undefined)
48
+ result.text = text;
49
+ const stopReason = str(parsed.stopReason);
50
+ if (stopReason !== undefined)
51
+ result.stopReason = stopReason;
52
+ const sessionId = str(parsed.sessionId);
53
+ if (sessionId !== undefined)
54
+ result.sessionId = sessionId;
55
+ const requestId = str(parsed.requestId);
56
+ if (requestId !== undefined)
57
+ result.requestId = requestId;
58
+ const thought = str(parsed.thought);
59
+ if (thought !== undefined)
60
+ result.thought = thought;
61
+ const error = str(parsed.error);
62
+ if (error !== undefined)
63
+ result.error = error;
64
+ return result;
65
+ }
66
+ export function parseGrokStreamingJson(stdout) {
67
+ if (!stdout) {
68
+ return null;
69
+ }
70
+ const lines = stdout.split(/\r?\n/);
71
+ const result = { usageAbsent: true };
72
+ const textChunks = [];
73
+ const thoughtChunks = [];
74
+ let sawAnyLine = false;
75
+ for (const line of lines) {
76
+ const trimmed = line.trim();
77
+ if (!trimmed)
78
+ continue;
79
+ let event;
80
+ try {
81
+ event = JSON.parse(trimmed);
82
+ }
83
+ catch {
84
+ continue;
85
+ }
86
+ if (!event || typeof event !== "object" || Array.isArray(event))
87
+ continue;
88
+ sawAnyLine = true;
89
+ switch (str(event.type)) {
90
+ case "text": {
91
+ const t = deltaText(event);
92
+ if (t !== undefined)
93
+ textChunks.push(t);
94
+ break;
95
+ }
96
+ case "thought": {
97
+ const t = deltaThought(event);
98
+ if (t !== undefined)
99
+ thoughtChunks.push(t);
100
+ break;
101
+ }
102
+ case "end": {
103
+ const stopReason = str(event.stopReason);
104
+ if (stopReason !== undefined)
105
+ result.stopReason = stopReason;
106
+ const sessionId = str(event.sessionId);
107
+ if (sessionId !== undefined)
108
+ result.sessionId = sessionId;
109
+ const requestId = str(event.requestId);
110
+ if (requestId !== undefined)
111
+ result.requestId = requestId;
112
+ break;
113
+ }
114
+ case "error": {
115
+ const error = str(event.error) ?? str(event.message);
116
+ if (error !== undefined)
117
+ result.error = error;
118
+ break;
119
+ }
120
+ default:
121
+ break;
122
+ }
123
+ }
124
+ if (!sawAnyLine) {
125
+ return null;
126
+ }
127
+ result.sawEvent = true;
128
+ if (textChunks.length > 0)
129
+ result.text = textChunks.join("");
130
+ if (thoughtChunks.length > 0)
131
+ result.thought = thoughtChunks.join("");
132
+ return result;
133
+ }
134
+ export function parseGrokOutput(outputFormat, stdout) {
135
+ if (outputFormat === "json")
136
+ return parseGrokJson(stdout);
137
+ if (outputFormat === "streaming-json")
138
+ return parseGrokStreamingJson(stdout);
139
+ return null;
140
+ }
141
+ export function grokDisplayText(outputFormat, stdout) {
142
+ if (outputFormat === "json") {
143
+ return stdout;
144
+ }
145
+ if (outputFormat === "streaming-json") {
146
+ const parsed = parseGrokStreamingJson(stdout);
147
+ if (!parsed)
148
+ return stdout;
149
+ if (parsed.text !== undefined)
150
+ return parsed.text;
151
+ if (parsed.error !== undefined)
152
+ return parsed.error;
153
+ return "";
154
+ }
155
+ return stdout;
156
+ }
package/dist/index.d.ts CHANGED
@@ -4,13 +4,14 @@ import { z } from "zod/v3";
4
4
  import { ISessionManager, type CliType, type ProviderType } from "./session-manager.js";
5
5
  import { ResourceProvider } from "./resources.js";
6
6
  import { PerformanceMetrics } from "./metrics.js";
7
- import { type PersistenceConfig, type CacheAwarenessConfig, type ProvidersConfig, type ApiProviderRuntime, type AcpConfig } from "./config.js";
7
+ import { type PersistenceConfig, type CacheAwarenessConfig, type ProvidersConfig, type ApiProviderRuntime, type AcpConfig, type AdminConfig } from "./config.js";
8
8
  import { DatabaseConnection } from "./db.js";
9
+ import { type DevinAcpAgentType } from "./provider-definitions.js";
9
10
  import { AsyncJobManager } from "./async-job-manager.js";
10
11
  import { ApprovalManager, ApprovalPolicy, ApprovalRecord } from "./approval-manager.js";
11
12
  import { ReviewIntegrityResult } from "./review-integrity.js";
12
13
  import { ClaudeMcpConfigResult, ClaudeMcpServerName } from "./claude-mcp-config.js";
13
- import { type MistralAgentMode, type ClaudePermissionMode, type CodexSandboxMode, type CodexAskForApproval, type ClaudeEffortLevel } from "./request-helpers.js";
14
+ import { type MistralAgentMode, type ClaudePermissionMode, type CodexSandboxMode, type CodexAskForApproval, type CodexLocalProvider, type CodexColorMode, type ClaudeEffortLevel } from "./request-helpers.js";
14
15
  import { FlightRecorderLike } from "./flight-recorder.js";
15
16
  import { type PromptParts } from "./prompt-parts.js";
16
17
  import { type WorkspaceRegistry } from "./workspace-registry.js";
@@ -77,6 +78,7 @@ export interface GatewayServerDeps {
77
78
  cacheAwareness?: CacheAwarenessConfig;
78
79
  providers?: ProvidersConfig;
79
80
  acpConfig?: AcpConfig;
81
+ adminConfig?: AdminConfig;
80
82
  workspaces?: WorkspaceRegistry;
81
83
  }
82
84
  export interface GatewayServerRuntime {
@@ -92,6 +94,7 @@ export interface GatewayServerRuntime {
92
94
  cacheAwareness: CacheAwarenessConfig;
93
95
  providers: ProvidersConfig;
94
96
  acpConfig: AcpConfig;
97
+ adminConfig: AdminConfig;
95
98
  workspaces: WorkspaceRegistry;
96
99
  }
97
100
  export declare function resolveGatewayServerRuntime(deps?: GatewayServerDeps, options?: {
@@ -104,6 +107,7 @@ export declare function runAcpTransport(deps: HandlerDeps, params: {
104
107
  model?: string;
105
108
  sessionId?: string;
106
109
  correlationId?: string;
110
+ agentType?: string;
107
111
  }): Promise<ExtendedToolResponse>;
108
112
  export interface ResolvedWorktree {
109
113
  cwd?: string;
@@ -165,6 +169,7 @@ export declare function extractUsageAndCost(cli: CliType, output: string, output
165
169
  cacheCreationTokens?: number;
166
170
  costUsd?: number;
167
171
  };
172
+ export declare function registerBaseResources(server: McpServer, runtime: GatewayServerRuntime): void;
168
173
  interface CliRequestPrep {
169
174
  corrId: string;
170
175
  effectivePrompt: string;
@@ -213,6 +218,17 @@ export declare function prepareClaudeRequest(params: {
213
218
  settingSources?: string;
214
219
  settings?: string;
215
220
  tools?: string[];
221
+ includeHookEvents?: boolean;
222
+ replayUserMessages?: boolean;
223
+ systemPromptFile?: string;
224
+ appendSystemPromptFile?: string;
225
+ name?: string;
226
+ pluginDir?: string[];
227
+ pluginUrl?: string[];
228
+ safeMode?: boolean;
229
+ bare?: boolean;
230
+ debug?: string | boolean;
231
+ debugFile?: string;
216
232
  }, runtime?: GatewayServerRuntime): CliRequestPrep | ExtendedToolResponse;
217
233
  export interface CodexRequestPrep extends CliRequestPrep {
218
234
  cleanup?: () => void;
@@ -246,6 +262,14 @@ export declare function prepareCodexRequest(params: {
246
262
  ignoreRules?: boolean;
247
263
  workingDir?: string;
248
264
  addDir?: string[];
265
+ enable?: string[];
266
+ disable?: string[];
267
+ strictConfig?: boolean;
268
+ oss?: boolean;
269
+ localProvider?: CodexLocalProvider;
270
+ color?: CodexColorMode;
271
+ outputLastMessage?: string;
272
+ dangerouslyBypassHookTrust?: boolean;
249
273
  }, runtime?: GatewayServerRuntime): CodexRequestPrep | ExtendedToolResponse;
250
274
  export declare function prepareGeminiRequest(params: {
251
275
  prompt?: string;
@@ -269,6 +293,7 @@ export declare function prepareGeminiRequest(params: {
269
293
  yolo?: boolean;
270
294
  project?: string;
271
295
  newProject?: boolean;
296
+ printTimeout?: string;
272
297
  }, runtime?: GatewayServerRuntime): CliRequestPrep | ExtendedToolResponse;
273
298
  export declare function prepareGrokRequest(params: {
274
299
  prompt?: string;
@@ -413,6 +438,7 @@ export interface GeminiRequestParams {
413
438
  yolo?: boolean;
414
439
  project?: string;
415
440
  newProject?: boolean;
441
+ printTimeout?: string;
416
442
  workspace?: string;
417
443
  worktree?: boolean | {
418
444
  name?: string;
@@ -502,6 +528,12 @@ export interface DevinRequestParams {
502
528
  model?: string;
503
529
  permissionMode?: "auto" | "smart" | "dangerous";
504
530
  promptFile?: string;
531
+ config?: string;
532
+ sandbox?: boolean;
533
+ exportSession?: boolean | string;
534
+ respectWorkspaceTrust?: boolean;
535
+ agentConfig?: string;
536
+ agentType?: DevinAcpAgentType;
505
537
  transport?: "cli" | "acp";
506
538
  sessionId?: string;
507
539
  resumeLatest?: boolean;
@@ -517,6 +549,11 @@ export declare function prepareDevinRequest(params: {
517
549
  model?: string;
518
550
  permissionMode?: DevinRequestParams["permissionMode"];
519
551
  promptFile?: string;
552
+ config?: string;
553
+ sandbox?: boolean;
554
+ exportSession?: boolean | string;
555
+ respectWorkspaceTrust?: boolean;
556
+ agentConfig?: string;
520
557
  correlationId?: string;
521
558
  optimizePrompt: boolean;
522
559
  operation: string;
@@ -629,6 +666,14 @@ export declare function handleCodexRequestAsync(deps: AsyncHandlerDeps, params:
629
666
  ignoreRules?: boolean;
630
667
  workingDir?: string;
631
668
  addDir?: string[];
669
+ enable?: string[];
670
+ disable?: string[];
671
+ strictConfig?: boolean;
672
+ oss?: boolean;
673
+ localProvider?: CodexLocalProvider;
674
+ color?: CodexColorMode;
675
+ outputLastMessage?: string;
676
+ dangerouslyBypassHookTrust?: boolean;
632
677
  workspace?: string;
633
678
  worktree?: boolean | {
634
679
  name?: string;