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/acp/types.js
CHANGED
|
@@ -57,10 +57,60 @@ export const InitializeRequestSchema = z
|
|
|
57
57
|
_meta: MetaSchema,
|
|
58
58
|
})
|
|
59
59
|
.passthrough();
|
|
60
|
+
const SessionSubCapabilitySchema = z.object({ _meta: MetaSchema }).passthrough().nullish();
|
|
61
|
+
export const PromptCapabilitiesSchema = z
|
|
62
|
+
.object({
|
|
63
|
+
image: z.boolean().optional(),
|
|
64
|
+
audio: z.boolean().optional(),
|
|
65
|
+
embeddedContext: z.boolean().optional(),
|
|
66
|
+
_meta: MetaSchema,
|
|
67
|
+
})
|
|
68
|
+
.passthrough();
|
|
69
|
+
export const McpCapabilitiesSchema = z
|
|
70
|
+
.object({
|
|
71
|
+
http: z.boolean().optional(),
|
|
72
|
+
sse: z.boolean().optional(),
|
|
73
|
+
_meta: MetaSchema,
|
|
74
|
+
})
|
|
75
|
+
.passthrough();
|
|
76
|
+
export const SessionCapabilitiesSchema = z
|
|
77
|
+
.object({
|
|
78
|
+
resume: SessionSubCapabilitySchema,
|
|
79
|
+
list: SessionSubCapabilitySchema,
|
|
80
|
+
close: SessionSubCapabilitySchema,
|
|
81
|
+
delete: SessionSubCapabilitySchema,
|
|
82
|
+
additionalDirectories: SessionSubCapabilitySchema,
|
|
83
|
+
_meta: MetaSchema,
|
|
84
|
+
})
|
|
85
|
+
.passthrough();
|
|
86
|
+
export const AgentAuthCapabilitiesSchema = z
|
|
87
|
+
.object({
|
|
88
|
+
logout: z.object({ _meta: MetaSchema }).passthrough().nullish(),
|
|
89
|
+
_meta: MetaSchema,
|
|
90
|
+
})
|
|
91
|
+
.passthrough();
|
|
92
|
+
export const AgentCapabilitiesSchema = z
|
|
93
|
+
.object({
|
|
94
|
+
loadSession: z.boolean().optional(),
|
|
95
|
+
promptCapabilities: PromptCapabilitiesSchema.optional(),
|
|
96
|
+
mcpCapabilities: McpCapabilitiesSchema.optional(),
|
|
97
|
+
sessionCapabilities: SessionCapabilitiesSchema.optional(),
|
|
98
|
+
auth: AgentAuthCapabilitiesSchema.optional(),
|
|
99
|
+
_meta: MetaSchema,
|
|
100
|
+
})
|
|
101
|
+
.passthrough();
|
|
102
|
+
export const AuthMethodSchema = z
|
|
103
|
+
.object({
|
|
104
|
+
id: z.string().optional(),
|
|
105
|
+
name: z.string().optional(),
|
|
106
|
+
description: z.string().nullish(),
|
|
107
|
+
_meta: MetaSchema,
|
|
108
|
+
})
|
|
109
|
+
.passthrough();
|
|
60
110
|
export const InitializeResponseSchema = z
|
|
61
111
|
.object({
|
|
62
112
|
protocolVersion: ProtocolVersionSchema,
|
|
63
|
-
agentCapabilities:
|
|
113
|
+
agentCapabilities: AgentCapabilitiesSchema.optional(),
|
|
64
114
|
agentInfo: z
|
|
65
115
|
.object({
|
|
66
116
|
name: z.string().optional(),
|
|
@@ -68,10 +118,51 @@ export const InitializeResponseSchema = z
|
|
|
68
118
|
})
|
|
69
119
|
.passthrough()
|
|
70
120
|
.optional(),
|
|
71
|
-
authMethods: z.array(
|
|
121
|
+
authMethods: z.array(AuthMethodSchema).optional(),
|
|
72
122
|
_meta: MetaSchema,
|
|
73
123
|
})
|
|
74
124
|
.passthrough();
|
|
125
|
+
export const BASELINE_ACP_METHODS = [
|
|
126
|
+
"session/new",
|
|
127
|
+
"session/prompt",
|
|
128
|
+
"session/cancel",
|
|
129
|
+
"session/update",
|
|
130
|
+
];
|
|
131
|
+
function subCapabilityPresent(value) {
|
|
132
|
+
return value !== null && value !== undefined && typeof value === "object";
|
|
133
|
+
}
|
|
134
|
+
export function deriveAcpMethodAvailability(init) {
|
|
135
|
+
const methods = new Set(BASELINE_ACP_METHODS);
|
|
136
|
+
const caps = init.agentCapabilities;
|
|
137
|
+
if (caps?.loadSession === true) {
|
|
138
|
+
methods.add("session/load");
|
|
139
|
+
}
|
|
140
|
+
const sc = caps?.sessionCapabilities;
|
|
141
|
+
if (sc) {
|
|
142
|
+
if (subCapabilityPresent(sc.resume))
|
|
143
|
+
methods.add("session/resume");
|
|
144
|
+
if (subCapabilityPresent(sc.list))
|
|
145
|
+
methods.add("session/list");
|
|
146
|
+
if (subCapabilityPresent(sc.close))
|
|
147
|
+
methods.add("session/close");
|
|
148
|
+
if (subCapabilityPresent(sc.delete))
|
|
149
|
+
methods.add("session/delete");
|
|
150
|
+
}
|
|
151
|
+
if (Array.isArray(init.authMethods) && init.authMethods.length > 0) {
|
|
152
|
+
methods.add("authenticate");
|
|
153
|
+
}
|
|
154
|
+
return methods;
|
|
155
|
+
}
|
|
156
|
+
export function sessionResponseMethods(response) {
|
|
157
|
+
const methods = new Set();
|
|
158
|
+
if (response.modes !== null && response.modes !== undefined) {
|
|
159
|
+
methods.add("session/set_mode");
|
|
160
|
+
}
|
|
161
|
+
if (response.configOptions !== null && response.configOptions !== undefined) {
|
|
162
|
+
methods.add("session/set_config_option");
|
|
163
|
+
}
|
|
164
|
+
return methods;
|
|
165
|
+
}
|
|
75
166
|
export const McpServerSchema = z.record(z.unknown());
|
|
76
167
|
export const SessionNewRequestSchema = z
|
|
77
168
|
.object({
|
|
@@ -83,7 +174,8 @@ export const SessionNewRequestSchema = z
|
|
|
83
174
|
export const SessionNewResponseSchema = z
|
|
84
175
|
.object({
|
|
85
176
|
sessionId: SessionIdSchema,
|
|
86
|
-
modes: z.record(z.unknown()).
|
|
177
|
+
modes: z.record(z.unknown()).nullish(),
|
|
178
|
+
configOptions: z.array(z.record(z.unknown())).nullish(),
|
|
87
179
|
_meta: MetaSchema,
|
|
88
180
|
})
|
|
89
181
|
.passthrough();
|
|
@@ -97,7 +189,124 @@ export const SessionLoadRequestSchema = z
|
|
|
97
189
|
.passthrough();
|
|
98
190
|
export const SessionLoadResponseSchema = z
|
|
99
191
|
.object({
|
|
100
|
-
modes: z.record(z.unknown()).
|
|
192
|
+
modes: z.record(z.unknown()).nullish(),
|
|
193
|
+
configOptions: z.array(z.record(z.unknown())).nullish(),
|
|
194
|
+
_meta: MetaSchema,
|
|
195
|
+
})
|
|
196
|
+
.passthrough();
|
|
197
|
+
export const SessionResumeRequestSchema = z
|
|
198
|
+
.object({
|
|
199
|
+
sessionId: SessionIdSchema,
|
|
200
|
+
cwd: z.string().min(1),
|
|
201
|
+
mcpServers: z.array(McpServerSchema).default([]),
|
|
202
|
+
_meta: MetaSchema,
|
|
203
|
+
})
|
|
204
|
+
.passthrough();
|
|
205
|
+
export const SessionResumeResponseSchema = z
|
|
206
|
+
.object({
|
|
207
|
+
modes: z.record(z.unknown()).nullish(),
|
|
208
|
+
configOptions: z.array(z.record(z.unknown())).nullish(),
|
|
209
|
+
_meta: MetaSchema,
|
|
210
|
+
})
|
|
211
|
+
.passthrough();
|
|
212
|
+
export const SessionModeSchema = z
|
|
213
|
+
.object({
|
|
214
|
+
id: z.string().min(1),
|
|
215
|
+
name: z.string().min(1),
|
|
216
|
+
description: z.string().nullish(),
|
|
217
|
+
_meta: MetaSchema,
|
|
218
|
+
})
|
|
219
|
+
.passthrough();
|
|
220
|
+
export const SessionModeStateSchema = z
|
|
221
|
+
.object({
|
|
222
|
+
currentModeId: z.string().min(1),
|
|
223
|
+
availableModes: z.array(SessionModeSchema),
|
|
224
|
+
_meta: MetaSchema,
|
|
225
|
+
})
|
|
226
|
+
.passthrough();
|
|
227
|
+
export const SessionConfigSelectValueSchema = z
|
|
228
|
+
.object({
|
|
229
|
+
value: z.string().min(1),
|
|
230
|
+
label: z.string().nullish(),
|
|
231
|
+
description: z.string().nullish(),
|
|
232
|
+
_meta: MetaSchema,
|
|
233
|
+
})
|
|
234
|
+
.passthrough();
|
|
235
|
+
export const SessionConfigOptionSchema = z.discriminatedUnion("type", [
|
|
236
|
+
z
|
|
237
|
+
.object({
|
|
238
|
+
type: z.literal("select"),
|
|
239
|
+
id: z.string().min(1),
|
|
240
|
+
name: z.string().min(1),
|
|
241
|
+
description: z.string().nullish(),
|
|
242
|
+
category: z.string().nullish(),
|
|
243
|
+
currentValue: z.string().min(1),
|
|
244
|
+
options: z.array(SessionConfigSelectValueSchema),
|
|
245
|
+
_meta: MetaSchema,
|
|
246
|
+
})
|
|
247
|
+
.passthrough(),
|
|
248
|
+
z
|
|
249
|
+
.object({
|
|
250
|
+
type: z.literal("boolean"),
|
|
251
|
+
id: z.string().min(1),
|
|
252
|
+
name: z.string().min(1),
|
|
253
|
+
description: z.string().nullish(),
|
|
254
|
+
category: z.string().nullish(),
|
|
255
|
+
currentValue: z.boolean(),
|
|
256
|
+
_meta: MetaSchema,
|
|
257
|
+
})
|
|
258
|
+
.passthrough(),
|
|
259
|
+
]);
|
|
260
|
+
export const SessionInfoSchema = z
|
|
261
|
+
.object({
|
|
262
|
+
sessionId: SessionIdSchema,
|
|
263
|
+
cwd: z.string().min(1),
|
|
264
|
+
additionalDirectories: z.array(z.string()).optional(),
|
|
265
|
+
title: z.string().nullish(),
|
|
266
|
+
updatedAt: z.string().nullish(),
|
|
267
|
+
_meta: MetaSchema,
|
|
268
|
+
})
|
|
269
|
+
.passthrough();
|
|
270
|
+
export const ListSessionsRequestSchema = z
|
|
271
|
+
.object({
|
|
272
|
+
cursor: z.string().nullish(),
|
|
273
|
+
_meta: MetaSchema,
|
|
274
|
+
})
|
|
275
|
+
.passthrough();
|
|
276
|
+
export const ListSessionsResponseSchema = z
|
|
277
|
+
.object({
|
|
278
|
+
sessions: z.array(SessionInfoSchema),
|
|
279
|
+
nextCursor: z.string().nullish(),
|
|
280
|
+
_meta: MetaSchema,
|
|
281
|
+
})
|
|
282
|
+
.passthrough();
|
|
283
|
+
export const CloseSessionRequestSchema = z
|
|
284
|
+
.object({ sessionId: SessionIdSchema, _meta: MetaSchema })
|
|
285
|
+
.passthrough();
|
|
286
|
+
export const CloseSessionResponseSchema = z.object({ _meta: MetaSchema }).passthrough();
|
|
287
|
+
export const DeleteSessionRequestSchema = z
|
|
288
|
+
.object({ sessionId: SessionIdSchema, _meta: MetaSchema })
|
|
289
|
+
.passthrough();
|
|
290
|
+
export const DeleteSessionResponseSchema = z.object({ _meta: MetaSchema }).passthrough();
|
|
291
|
+
export const SetSessionModeRequestSchema = z
|
|
292
|
+
.object({
|
|
293
|
+
sessionId: SessionIdSchema,
|
|
294
|
+
modeId: z.string().min(1),
|
|
295
|
+
_meta: MetaSchema,
|
|
296
|
+
})
|
|
297
|
+
.passthrough();
|
|
298
|
+
export const SetSessionModeResponseSchema = z.object({ _meta: MetaSchema }).passthrough();
|
|
299
|
+
export const SetSessionConfigOptionRequestSchema = z
|
|
300
|
+
.object({
|
|
301
|
+
sessionId: SessionIdSchema,
|
|
302
|
+
configId: z.string().min(1),
|
|
303
|
+
value: z.string().min(1),
|
|
304
|
+
_meta: MetaSchema,
|
|
305
|
+
})
|
|
306
|
+
.passthrough();
|
|
307
|
+
export const SetSessionConfigOptionResponseSchema = z
|
|
308
|
+
.object({
|
|
309
|
+
configOptions: z.array(SessionConfigOptionSchema),
|
|
101
310
|
_meta: MetaSchema,
|
|
102
311
|
})
|
|
103
312
|
.passthrough();
|
|
@@ -184,6 +393,13 @@ const UsageUpdate = z
|
|
|
184
393
|
_meta: MetaSchema,
|
|
185
394
|
})
|
|
186
395
|
.passthrough();
|
|
396
|
+
const ConfigOptionUpdate = z
|
|
397
|
+
.object({
|
|
398
|
+
sessionUpdate: z.literal("config_option_update"),
|
|
399
|
+
configOptions: z.array(SessionConfigOptionSchema),
|
|
400
|
+
_meta: MetaSchema,
|
|
401
|
+
})
|
|
402
|
+
.passthrough();
|
|
187
403
|
const KNOWN_UPDATE_SCHEMAS = {
|
|
188
404
|
user_message_chunk: MessageChunkUpdate("user_message_chunk"),
|
|
189
405
|
agent_message_chunk: MessageChunkUpdate("agent_message_chunk"),
|
|
@@ -193,6 +409,7 @@ const KNOWN_UPDATE_SCHEMAS = {
|
|
|
193
409
|
plan: PlanUpdate,
|
|
194
410
|
available_commands_update: AvailableCommandsUpdate,
|
|
195
411
|
current_mode_update: CurrentModeUpdate,
|
|
412
|
+
config_option_update: ConfigOptionUpdate,
|
|
196
413
|
usage_update: UsageUpdate,
|
|
197
414
|
};
|
|
198
415
|
export const SessionUpdateSchema = z
|
|
@@ -227,7 +444,6 @@ export const KNOWN_SESSION_UPDATE_VARIANTS = [
|
|
|
227
444
|
"available_commands_update",
|
|
228
445
|
"current_mode_update",
|
|
229
446
|
"config_option_update",
|
|
230
|
-
"session_info_update",
|
|
231
447
|
"usage_update",
|
|
232
448
|
];
|
|
233
449
|
export function isUnknownSessionUpdate(update) {
|
|
@@ -333,3 +549,24 @@ export function parseWriteTextFileRequest(value, provider) {
|
|
|
333
549
|
provider,
|
|
334
550
|
});
|
|
335
551
|
}
|
|
552
|
+
export function parseSessionResumeResponse(value, provider) {
|
|
553
|
+
return parseAcp(SessionResumeResponseSchema, value, { method: "session/resume", provider });
|
|
554
|
+
}
|
|
555
|
+
export function parseListSessionsResponse(value, provider) {
|
|
556
|
+
return parseAcp(ListSessionsResponseSchema, value, { method: "session/list", provider });
|
|
557
|
+
}
|
|
558
|
+
export function parseCloseSessionResponse(value, provider) {
|
|
559
|
+
return parseAcp(CloseSessionResponseSchema, value, { method: "session/close", provider });
|
|
560
|
+
}
|
|
561
|
+
export function parseDeleteSessionResponse(value, provider) {
|
|
562
|
+
return parseAcp(DeleteSessionResponseSchema, value, { method: "session/delete", provider });
|
|
563
|
+
}
|
|
564
|
+
export function parseSetSessionModeResponse(value, provider) {
|
|
565
|
+
return parseAcp(SetSessionModeResponseSchema, value, { method: "session/set_mode", provider });
|
|
566
|
+
}
|
|
567
|
+
export function parseSetSessionConfigOptionResponse(value, provider) {
|
|
568
|
+
return parseAcp(SetSessionConfigOptionResponseSchema, value, {
|
|
569
|
+
method: "session/set_config_option",
|
|
570
|
+
provider,
|
|
571
|
+
});
|
|
572
|
+
}
|
|
@@ -5,6 +5,7 @@ import { ProcessMonitor } from "./process-monitor.js";
|
|
|
5
5
|
import { computeRequestKey, isValidationRunStore } from "./job-store.js";
|
|
6
6
|
import { NoopFlightRecorder, } from "./flight-recorder.js";
|
|
7
7
|
import { codexFrResponse } from "./codex-json-parser.js";
|
|
8
|
+
import { extractProviderOutputMetadata } from "./provider-output-metadata.js";
|
|
8
9
|
import { getRequestContext, resolveOwnerPrincipal, principalCanAccess } from "./request-context.js";
|
|
9
10
|
import { runApiRequest, ApiHttpError, } from "./api-provider.js";
|
|
10
11
|
export function extractApiHttpStatus(error) {
|
|
@@ -681,6 +682,9 @@ export class AsyncJobManager {
|
|
|
681
682
|
const errorMessage = isFailure
|
|
682
683
|
? (overrideErrorMessage ?? job.error ?? job.stderr ?? `Exit code ${exitCode}`)
|
|
683
684
|
: undefined;
|
|
685
|
+
const providerMeta = finalStatus === "completed" && job.transport === "process"
|
|
686
|
+
? extractProviderOutputMetadata(job.cli, job.stdout, job.outputFormat)
|
|
687
|
+
: undefined;
|
|
684
688
|
try {
|
|
685
689
|
this.flightRecorder.logComplete(job.correlationId, {
|
|
686
690
|
response,
|
|
@@ -697,6 +701,8 @@ export class AsyncJobManager {
|
|
|
697
701
|
cacheReadTokens: usage.cacheReadTokens,
|
|
698
702
|
cacheCreationTokens: usage.cacheCreationTokens,
|
|
699
703
|
costUsd: usage.costUsd,
|
|
704
|
+
providerSessionId: providerMeta?.sessionId,
|
|
705
|
+
stopReason: providerMeta?.stopReason,
|
|
700
706
|
});
|
|
701
707
|
job.flightRecorderComplete = true;
|
|
702
708
|
job.flightRecorderEntry = undefined;
|
|
@@ -1136,12 +1142,17 @@ export class AsyncJobManager {
|
|
|
1136
1142
|
}
|
|
1137
1143
|
const stdout = truncateText(job.stdout, maxChars);
|
|
1138
1144
|
const stderr = truncateText(job.stderr, maxChars);
|
|
1145
|
+
const providerMeta = job.transport === "process" && job.status === "completed"
|
|
1146
|
+
? extractProviderOutputMetadata(job.cli, job.stdout, job.outputFormat)
|
|
1147
|
+
: undefined;
|
|
1139
1148
|
return {
|
|
1140
1149
|
...this.snapshot(job),
|
|
1141
1150
|
stdout: stdout.text,
|
|
1142
1151
|
stderr: stderr.text,
|
|
1143
1152
|
stdoutTruncated: stdout.truncated,
|
|
1144
1153
|
stderrTruncated: stderr.truncated,
|
|
1154
|
+
...(providerMeta?.sessionId ? { providerSessionId: providerMeta.sessionId } : {}),
|
|
1155
|
+
...(providerMeta?.stopReason ? { stopReason: providerMeta.stopReason } : {}),
|
|
1145
1156
|
...(job.transport === "http"
|
|
1146
1157
|
? {
|
|
1147
1158
|
apiUsage: job.apiUsage,
|
|
@@ -47,6 +47,12 @@ export function parseCodexJsonStream(stdout) {
|
|
|
47
47
|
}
|
|
48
48
|
result.usage = usage;
|
|
49
49
|
}
|
|
50
|
+
if (typeof parsed.stop_reason === "string") {
|
|
51
|
+
result.stopReason = parsed.stop_reason;
|
|
52
|
+
}
|
|
53
|
+
else if (typeof parsed.reason === "string") {
|
|
54
|
+
result.stopReason = parsed.reason;
|
|
55
|
+
}
|
|
50
56
|
break;
|
|
51
57
|
}
|
|
52
58
|
case "turn.failed": {
|
package/dist/config.d.ts
CHANGED
|
@@ -155,6 +155,7 @@ export interface AcpConfig {
|
|
|
155
155
|
promptTimeoutMs: number;
|
|
156
156
|
allowWriteHostServices: boolean;
|
|
157
157
|
allowTerminalHostServices: boolean;
|
|
158
|
+
allowMutatingSessionOps: boolean;
|
|
158
159
|
fallbackToCliWhenUnhealthy: boolean;
|
|
159
160
|
providers: Record<string, AcpProviderConfig>;
|
|
160
161
|
sources: {
|
|
@@ -162,6 +163,13 @@ export interface AcpConfig {
|
|
|
162
163
|
};
|
|
163
164
|
}
|
|
164
165
|
export declare function loadAcpConfig(logger?: Logger): AcpConfig;
|
|
166
|
+
export interface AdminConfig {
|
|
167
|
+
allowMutatingCliAdminOps: boolean;
|
|
168
|
+
sources: {
|
|
169
|
+
configFile: string | null;
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
export declare function loadAdminConfig(logger?: Logger): AdminConfig;
|
|
165
173
|
export type RemoteOAuthConfigStatus = "absent" | "disabled" | "enabled" | "malformed";
|
|
166
174
|
export interface RemoteOAuthConfigDiagnostics {
|
|
167
175
|
config: RemoteOAuthConfig;
|
package/dist/config.js
CHANGED
|
@@ -537,6 +537,7 @@ const AcpConfigSchema = z
|
|
|
537
537
|
prompt_timeout_ms: z.number().int().positive().default(DEFAULT_ACP_PROMPT_TIMEOUT_MS),
|
|
538
538
|
allow_write_host_services: z.boolean().default(false),
|
|
539
539
|
allow_terminal_host_services: z.boolean().default(false),
|
|
540
|
+
allow_mutating_session_ops: z.boolean().default(false),
|
|
540
541
|
fallback_to_cli_when_unhealthy: z.boolean().default(true),
|
|
541
542
|
providers: z.record(z.string(), AcpProviderSchema).default({}),
|
|
542
543
|
})
|
|
@@ -552,6 +553,7 @@ function defaultAcpConfig(sourcePath) {
|
|
|
552
553
|
promptTimeoutMs: DEFAULT_ACP_PROMPT_TIMEOUT_MS,
|
|
553
554
|
allowWriteHostServices: false,
|
|
554
555
|
allowTerminalHostServices: false,
|
|
556
|
+
allowMutatingSessionOps: false,
|
|
555
557
|
fallbackToCliWhenUnhealthy: true,
|
|
556
558
|
providers: {},
|
|
557
559
|
sources: { configFile: sourcePath },
|
|
@@ -608,11 +610,56 @@ export function loadAcpConfig(logger = noopLogger) {
|
|
|
608
610
|
promptTimeoutMs: parsed.prompt_timeout_ms,
|
|
609
611
|
allowWriteHostServices: parsed.allow_write_host_services,
|
|
610
612
|
allowTerminalHostServices: parsed.allow_terminal_host_services,
|
|
613
|
+
allowMutatingSessionOps: parsed.allow_mutating_session_ops,
|
|
611
614
|
fallbackToCliWhenUnhealthy: parsed.fallback_to_cli_when_unhealthy,
|
|
612
615
|
providers,
|
|
613
616
|
sources: { configFile: sourcePath },
|
|
614
617
|
};
|
|
615
618
|
}
|
|
619
|
+
const AdminConfigSchema = z
|
|
620
|
+
.object({
|
|
621
|
+
allow_mutating_cli_admin_ops: z.boolean().default(false),
|
|
622
|
+
})
|
|
623
|
+
.strict();
|
|
624
|
+
function defaultAdminConfig(sourcePath) {
|
|
625
|
+
return { allowMutatingCliAdminOps: false, sources: { configFile: sourcePath } };
|
|
626
|
+
}
|
|
627
|
+
function readAdminFile(configPath, logger) {
|
|
628
|
+
if (!existsSync(configPath)) {
|
|
629
|
+
return { raw: undefined, sourcePath: null };
|
|
630
|
+
}
|
|
631
|
+
try {
|
|
632
|
+
const require = createRequire(import.meta.url);
|
|
633
|
+
const TOML = require("smol-toml");
|
|
634
|
+
const text = readFileSync(configPath, "utf-8");
|
|
635
|
+
const parsed = TOML.parse(text);
|
|
636
|
+
return { raw: parsed?.admin, sourcePath: configPath };
|
|
637
|
+
}
|
|
638
|
+
catch (err) {
|
|
639
|
+
logger.error(`Failed to parse gateway config at ${configPath}; using admin defaults`, err);
|
|
640
|
+
return { raw: undefined, sourcePath: null };
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
export function loadAdminConfig(logger = noopLogger) {
|
|
644
|
+
const configPath = defaultGatewayConfigPath();
|
|
645
|
+
const { raw, sourcePath } = readAdminFile(configPath, logger);
|
|
646
|
+
if (raw === undefined) {
|
|
647
|
+
return defaultAdminConfig(sourcePath);
|
|
648
|
+
}
|
|
649
|
+
let parsed;
|
|
650
|
+
try {
|
|
651
|
+
parsed = AdminConfigSchema.parse(raw);
|
|
652
|
+
}
|
|
653
|
+
catch (err) {
|
|
654
|
+
throw new Error(`Invalid [admin] config: ${err instanceof Error ? err.message : String(err)}`, {
|
|
655
|
+
cause: err,
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
return {
|
|
659
|
+
allowMutatingCliAdminOps: parsed.allow_mutating_cli_admin_ops,
|
|
660
|
+
sources: { configFile: sourcePath },
|
|
661
|
+
};
|
|
662
|
+
}
|
|
616
663
|
const OAuthRegistrationPolicySchema = z.enum(["static_clients", "shared_secret", "open_dev"]);
|
|
617
664
|
const OAuthClientSchema = z
|
|
618
665
|
.object({
|
package/dist/flight-recorder.js
CHANGED
|
@@ -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
|
-
|
|
2
|
-
const trimmed = stdout.trim();
|
|
3
|
-
if (!trimmed) {
|
|
4
|
-
return null;
|
|
5
|
-
}
|
|
6
|
-
let parsed;
|
|
1
|
+
function parseTolerantJsonObject(text) {
|
|
7
2
|
try {
|
|
8
|
-
|
|
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
|
-
|
|
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;
|