@nyssance/codex-acp-v2 0.5.0 → 0.7.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.
- package/CHANGELOG.md +23 -0
- package/dist/index.js +599 -171
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3190,13 +3190,13 @@ var require_ril = __commonJS(function(exports) {
|
|
|
3190
3190
|
var util_1 = __require("util");
|
|
3191
3191
|
var api_1 = require_api();
|
|
3192
3192
|
|
|
3193
|
-
class
|
|
3193
|
+
class MessageBuffer2 extends api_1.AbstractMessageBuffer {
|
|
3194
3194
|
static emptyBuffer = Buffer.allocUnsafe(0);
|
|
3195
3195
|
constructor(encoding = "utf-8") {
|
|
3196
3196
|
super(encoding);
|
|
3197
3197
|
}
|
|
3198
3198
|
emptyBuffer() {
|
|
3199
|
-
return
|
|
3199
|
+
return MessageBuffer2.emptyBuffer;
|
|
3200
3200
|
}
|
|
3201
3201
|
fromString(value, encoding) {
|
|
3202
3202
|
return Buffer.from(value, encoding);
|
|
@@ -3282,7 +3282,7 @@ var require_ril = __commonJS(function(exports) {
|
|
|
3282
3282
|
}
|
|
3283
3283
|
var _ril = Object.freeze({
|
|
3284
3284
|
messageBuffer: Object.freeze({
|
|
3285
|
-
create: (encoding) => new
|
|
3285
|
+
create: (encoding) => new MessageBuffer2(encoding)
|
|
3286
3286
|
}),
|
|
3287
3287
|
applicationJson: Object.freeze({
|
|
3288
3288
|
encoder: Object.freeze({
|
|
@@ -15886,7 +15886,9 @@ var zSetSessionConfigOptionResponse = object({
|
|
|
15886
15886
|
return;
|
|
15887
15887
|
})
|
|
15888
15888
|
});
|
|
15889
|
+
var zMessageId = string2();
|
|
15889
15890
|
var zPromptResponse = object({
|
|
15891
|
+
messageId: zMessageId,
|
|
15890
15892
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
15891
15893
|
return;
|
|
15892
15894
|
})
|
|
@@ -16044,7 +16046,6 @@ var zAgentResponse = union([
|
|
|
16044
16046
|
error: zError
|
|
16045
16047
|
})
|
|
16046
16048
|
]);
|
|
16047
|
-
var zMessageId = string2();
|
|
16048
16049
|
var zContentChunk = object({
|
|
16049
16050
|
messageId: zMessageId,
|
|
16050
16051
|
content: zContentBlock,
|
|
@@ -16324,6 +16325,22 @@ var zUsageUpdate = object({
|
|
|
16324
16325
|
return;
|
|
16325
16326
|
})
|
|
16326
16327
|
});
|
|
16328
|
+
var zNoticeSeverity = union([
|
|
16329
|
+
literal("info"),
|
|
16330
|
+
literal("warning"),
|
|
16331
|
+
literal("error"),
|
|
16332
|
+
string2()
|
|
16333
|
+
]);
|
|
16334
|
+
var zNotice = object({
|
|
16335
|
+
severity: zNoticeSeverity,
|
|
16336
|
+
title: string2().min(1),
|
|
16337
|
+
description: defaultOnError(string2().nullish(), () => {
|
|
16338
|
+
return;
|
|
16339
|
+
}),
|
|
16340
|
+
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
16341
|
+
return;
|
|
16342
|
+
})
|
|
16343
|
+
});
|
|
16327
16344
|
var zCompactionId = string2();
|
|
16328
16345
|
var zCompactionStatus = union([
|
|
16329
16346
|
literal("in_progress"),
|
|
@@ -16404,6 +16421,9 @@ var zSessionUpdate = preserveCustomPayload(union([
|
|
|
16404
16421
|
zUsageUpdate.and(object({
|
|
16405
16422
|
sessionUpdate: literal("usage_update")
|
|
16406
16423
|
})),
|
|
16424
|
+
zNotice.and(object({
|
|
16425
|
+
sessionUpdate: literal("notice")
|
|
16426
|
+
})),
|
|
16407
16427
|
zCompactionUpdate.and(object({
|
|
16408
16428
|
sessionUpdate: literal("compaction_update")
|
|
16409
16429
|
})),
|
|
@@ -16421,6 +16441,7 @@ var zSessionUpdate = preserveCustomPayload(union([
|
|
|
16421
16441
|
"compaction_summary_chunk",
|
|
16422
16442
|
"compaction_update",
|
|
16423
16443
|
"config_option_update",
|
|
16444
|
+
"notice",
|
|
16424
16445
|
"plan_removed",
|
|
16425
16446
|
"plan_update",
|
|
16426
16447
|
"session_info_update",
|
|
@@ -16442,6 +16463,7 @@ var zSessionUpdate = preserveCustomPayload(union([
|
|
|
16442
16463
|
"compaction_summary_chunk",
|
|
16443
16464
|
"compaction_update",
|
|
16444
16465
|
"config_option_update",
|
|
16466
|
+
"notice",
|
|
16445
16467
|
"plan_removed",
|
|
16446
16468
|
"plan_update",
|
|
16447
16469
|
"session_info_update",
|
|
@@ -17148,6 +17170,7 @@ var zGuardSessionUpdateAvailableCommandsUpdate = zAvailableCommandsUpdate.and(ob
|
|
|
17148
17170
|
var zGuardSessionUpdateConfigOptionUpdate = zConfigOptionUpdate.and(object({ sessionUpdate: literal("config_option_update") }));
|
|
17149
17171
|
var zGuardSessionUpdateSessionInfoUpdate = zSessionInfoUpdate.and(object({ sessionUpdate: literal("session_info_update") }));
|
|
17150
17172
|
var zGuardSessionUpdateUsageUpdate = zUsageUpdate.and(object({ sessionUpdate: literal("usage_update") }));
|
|
17173
|
+
var zGuardSessionUpdateNotice = zNotice.and(object({ sessionUpdate: literal("notice") }));
|
|
17151
17174
|
var zGuardSessionUpdateCompactionUpdate = zCompactionUpdate.and(object({ sessionUpdate: literal("compaction_update") }));
|
|
17152
17175
|
var zGuardSessionUpdateCompactionSummaryChunk = zCompactionSummaryChunk.and(object({ sessionUpdate: literal("compaction_summary_chunk") }));
|
|
17153
17176
|
var zGuardStateUpdateRunning = zRunningStateUpdate.and(object({ state: literal("running") }));
|
|
@@ -17258,6 +17281,9 @@ var SessionUpdate = {
|
|
|
17258
17281
|
isUsageUpdate(value) {
|
|
17259
17282
|
return tagOf(value, "sessionUpdate") === "usage_update" && zGuardSessionUpdateUsageUpdate.safeParse(value).success;
|
|
17260
17283
|
},
|
|
17284
|
+
isNotice(value) {
|
|
17285
|
+
return tagOf(value, "sessionUpdate") === "notice" && zGuardSessionUpdateNotice.safeParse(value).success;
|
|
17286
|
+
},
|
|
17261
17287
|
isCompactionUpdate(value) {
|
|
17262
17288
|
return tagOf(value, "sessionUpdate") === "compaction_update" && zGuardSessionUpdateCompactionUpdate.safeParse(value).success;
|
|
17263
17289
|
},
|
|
@@ -17275,6 +17301,7 @@ var SessionUpdate = {
|
|
|
17275
17301
|
"compaction_summary_chunk",
|
|
17276
17302
|
"compaction_update",
|
|
17277
17303
|
"config_option_update",
|
|
17304
|
+
"notice",
|
|
17278
17305
|
"plan_removed",
|
|
17279
17306
|
"plan_update",
|
|
17280
17307
|
"session_info_update",
|
|
@@ -18106,53 +18133,124 @@ function protocolErrorResponse(error40) {
|
|
|
18106
18133
|
};
|
|
18107
18134
|
}
|
|
18108
18135
|
|
|
18136
|
+
// node_modules/@agentclientprotocol/sdk/dist/stream-limits.js
|
|
18137
|
+
var DEFAULT_MAX_MESSAGE_BYTES = 32 * 1024 * 1024;
|
|
18138
|
+
|
|
18139
|
+
class MessageTooLargeError extends Error {
|
|
18140
|
+
maxMessageBytes;
|
|
18141
|
+
constructor(maxMessageBytes) {
|
|
18142
|
+
super(`Incoming ACP data exceeds the configured ${maxMessageBytes} byte limit`);
|
|
18143
|
+
this.maxMessageBytes = maxMessageBytes;
|
|
18144
|
+
this.name = "MessageTooLargeError";
|
|
18145
|
+
}
|
|
18146
|
+
}
|
|
18147
|
+
function resolveMaxMessageBytes(value) {
|
|
18148
|
+
const maxMessageBytes = value ?? DEFAULT_MAX_MESSAGE_BYTES;
|
|
18149
|
+
if (!Number.isSafeInteger(maxMessageBytes) || maxMessageBytes <= 0) {
|
|
18150
|
+
throw new RangeError("maxMessageBytes must be a positive safe integer");
|
|
18151
|
+
}
|
|
18152
|
+
return maxMessageBytes;
|
|
18153
|
+
}
|
|
18154
|
+
|
|
18155
|
+
class MessageBuffer {
|
|
18156
|
+
#buffer = new Uint8Array(0);
|
|
18157
|
+
#length = 0;
|
|
18158
|
+
#maxMessageBytes;
|
|
18159
|
+
constructor(maxMessageBytes) {
|
|
18160
|
+
this.#maxMessageBytes = resolveMaxMessageBytes(maxMessageBytes);
|
|
18161
|
+
}
|
|
18162
|
+
get byteLength() {
|
|
18163
|
+
return this.#length;
|
|
18164
|
+
}
|
|
18165
|
+
get lastByte() {
|
|
18166
|
+
return this.#buffer[this.#length - 1];
|
|
18167
|
+
}
|
|
18168
|
+
#checkAppend(byteLength) {
|
|
18169
|
+
if (byteLength > this.#maxMessageBytes - this.#length) {
|
|
18170
|
+
this.clear();
|
|
18171
|
+
throw new MessageTooLargeError(this.#maxMessageBytes);
|
|
18172
|
+
}
|
|
18173
|
+
}
|
|
18174
|
+
append(bytes) {
|
|
18175
|
+
this.#checkAppend(bytes.byteLength);
|
|
18176
|
+
const length = this.#length + bytes.byteLength;
|
|
18177
|
+
if (length > this.#buffer.byteLength) {
|
|
18178
|
+
const capacity = Math.min(this.#maxMessageBytes, Math.max(length, this.#buffer.byteLength * 2, 1024));
|
|
18179
|
+
const buffer = new Uint8Array(capacity);
|
|
18180
|
+
buffer.set(this.#buffer.subarray(0, this.#length));
|
|
18181
|
+
this.#buffer = buffer;
|
|
18182
|
+
}
|
|
18183
|
+
this.#buffer.set(bytes, this.#length);
|
|
18184
|
+
this.#length = length;
|
|
18185
|
+
}
|
|
18186
|
+
take() {
|
|
18187
|
+
const bytes = this.#buffer.subarray(0, this.#length);
|
|
18188
|
+
this.clear();
|
|
18189
|
+
return bytes;
|
|
18190
|
+
}
|
|
18191
|
+
clear() {
|
|
18192
|
+
this.#buffer = new Uint8Array(0);
|
|
18193
|
+
this.#length = 0;
|
|
18194
|
+
}
|
|
18195
|
+
}
|
|
18196
|
+
|
|
18109
18197
|
// node_modules/@agentclientprotocol/sdk/dist/line-buffer.js
|
|
18110
18198
|
var newline = 10;
|
|
18111
18199
|
|
|
18112
18200
|
class LineBuffer {
|
|
18113
|
-
#pending
|
|
18114
|
-
|
|
18115
|
-
|
|
18201
|
+
#pending;
|
|
18202
|
+
#maxMessageBytes;
|
|
18203
|
+
constructor(maxMessageBytes) {
|
|
18204
|
+
this.#maxMessageBytes = resolveMaxMessageBytes(maxMessageBytes);
|
|
18205
|
+
this.#pending = new MessageBuffer(Math.min(Number.MAX_SAFE_INTEGER, this.#maxMessageBytes + 1));
|
|
18206
|
+
}
|
|
18207
|
+
*push(chunk) {
|
|
18116
18208
|
let start = 0;
|
|
18117
18209
|
let newlineIndex = chunk.indexOf(newline, start);
|
|
18118
18210
|
while (newlineIndex !== -1) {
|
|
18119
|
-
|
|
18211
|
+
yield this.#takeLine(chunk.subarray(start, newlineIndex));
|
|
18120
18212
|
start = newlineIndex + 1;
|
|
18121
18213
|
newlineIndex = chunk.indexOf(newline, start);
|
|
18122
18214
|
}
|
|
18123
18215
|
if (start < chunk.byteLength) {
|
|
18124
|
-
|
|
18216
|
+
const tail = chunk.subarray(start);
|
|
18217
|
+
this.#checkLine(tail);
|
|
18218
|
+
this.#pending.append(tail);
|
|
18125
18219
|
}
|
|
18126
|
-
return lines;
|
|
18127
18220
|
}
|
|
18128
18221
|
flush() {
|
|
18129
|
-
if (this.#pending.
|
|
18222
|
+
if (this.#pending.byteLength === 0) {
|
|
18130
18223
|
return;
|
|
18131
18224
|
}
|
|
18132
|
-
return this.#
|
|
18225
|
+
return stripCarriageReturn(this.#pending.take());
|
|
18226
|
+
}
|
|
18227
|
+
clear() {
|
|
18228
|
+
this.#pending.clear();
|
|
18133
18229
|
}
|
|
18134
18230
|
#takeLine(tail) {
|
|
18135
|
-
|
|
18136
|
-
|
|
18231
|
+
this.#checkLine(tail);
|
|
18232
|
+
if (this.#pending.byteLength === 0) {
|
|
18233
|
+
return stripCarriageReturn(tail);
|
|
18137
18234
|
}
|
|
18138
|
-
|
|
18139
|
-
|
|
18140
|
-
|
|
18141
|
-
|
|
18142
|
-
const
|
|
18143
|
-
|
|
18144
|
-
|
|
18145
|
-
|
|
18146
|
-
|
|
18235
|
+
this.#pending.append(tail);
|
|
18236
|
+
return stripCarriageReturn(this.#pending.take());
|
|
18237
|
+
}
|
|
18238
|
+
#checkLine(tail) {
|
|
18239
|
+
const lastByte = tail.byteLength > 0 ? tail[tail.byteLength - 1] : this.#pending.lastByte;
|
|
18240
|
+
const byteLength = this.#pending.byteLength + tail.byteLength - (lastByte === 13 ? 1 : 0);
|
|
18241
|
+
if (byteLength > this.#maxMessageBytes) {
|
|
18242
|
+
this.clear();
|
|
18243
|
+
throw new MessageTooLargeError(this.#maxMessageBytes);
|
|
18147
18244
|
}
|
|
18148
|
-
line.set(tail, offset);
|
|
18149
|
-
this.#pending = [];
|
|
18150
|
-
return line;
|
|
18151
18245
|
}
|
|
18152
18246
|
}
|
|
18247
|
+
function stripCarriageReturn(line) {
|
|
18248
|
+
return line[line.byteLength - 1] === 13 ? line.subarray(0, -1) : line;
|
|
18249
|
+
}
|
|
18153
18250
|
|
|
18154
18251
|
// node_modules/@agentclientprotocol/sdk/dist/stream.js
|
|
18155
|
-
function ndJsonStream(output, input) {
|
|
18252
|
+
function ndJsonStream(output, input, options = {}) {
|
|
18253
|
+
const maxMessageBytes = resolveMaxMessageBytes(options.maxMessageBytes);
|
|
18156
18254
|
const textEncoder = new TextEncoder;
|
|
18157
18255
|
const textDecoder = new TextDecoder;
|
|
18158
18256
|
let cancelled = false;
|
|
@@ -18174,7 +18272,7 @@ function ndJsonStream(output, input) {
|
|
|
18174
18272
|
};
|
|
18175
18273
|
const readable = new ReadableStream({
|
|
18176
18274
|
async start(controller) {
|
|
18177
|
-
const lines = new LineBuffer;
|
|
18275
|
+
const lines = new LineBuffer(maxMessageBytes);
|
|
18178
18276
|
const enqueueLine = async (lineBytes) => {
|
|
18179
18277
|
const trimmedLine = textDecoder.decode(lineBytes).trim();
|
|
18180
18278
|
if (!trimmedLine) {
|
|
@@ -18226,8 +18324,10 @@ function ndJsonStream(output, input) {
|
|
|
18226
18324
|
return;
|
|
18227
18325
|
}
|
|
18228
18326
|
controller.error(err);
|
|
18327
|
+
reader.cancel(err).catch(() => {});
|
|
18229
18328
|
return;
|
|
18230
18329
|
} finally {
|
|
18330
|
+
lines.clear();
|
|
18231
18331
|
if (inputReader === reader) {
|
|
18232
18332
|
inputReader = undefined;
|
|
18233
18333
|
}
|
|
@@ -19711,6 +19811,22 @@ var zUsageUpdate2 = object({
|
|
|
19711
19811
|
return;
|
|
19712
19812
|
})
|
|
19713
19813
|
});
|
|
19814
|
+
var zNoticeSeverity2 = union([
|
|
19815
|
+
literal("info"),
|
|
19816
|
+
literal("warning"),
|
|
19817
|
+
literal("error"),
|
|
19818
|
+
string2()
|
|
19819
|
+
]);
|
|
19820
|
+
var zNotice2 = object({
|
|
19821
|
+
severity: zNoticeSeverity2,
|
|
19822
|
+
title: string2().min(1),
|
|
19823
|
+
description: defaultOnError(string2().nullish(), () => {
|
|
19824
|
+
return;
|
|
19825
|
+
}),
|
|
19826
|
+
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
19827
|
+
return;
|
|
19828
|
+
})
|
|
19829
|
+
});
|
|
19714
19830
|
var zCompactionId2 = string2();
|
|
19715
19831
|
var zCompactionStatus2 = union([
|
|
19716
19832
|
literal("in_progress"),
|
|
@@ -19779,6 +19895,9 @@ var zSessionUpdate2 = union([
|
|
|
19779
19895
|
zUsageUpdate2.and(object({
|
|
19780
19896
|
sessionUpdate: literal("usage_update")
|
|
19781
19897
|
})),
|
|
19898
|
+
zNotice2.and(object({
|
|
19899
|
+
sessionUpdate: literal("notice")
|
|
19900
|
+
})),
|
|
19782
19901
|
zCompactionUpdate2.and(object({
|
|
19783
19902
|
sessionUpdate: literal("compaction_update")
|
|
19784
19903
|
})),
|
|
@@ -19840,6 +19959,7 @@ var zSessionConfigOptionsCapabilities = object({
|
|
|
19840
19959
|
return;
|
|
19841
19960
|
})
|
|
19842
19961
|
});
|
|
19962
|
+
var zNoticeCapabilities = record(string2(), unknown());
|
|
19843
19963
|
var zClientSessionCapabilities = object({
|
|
19844
19964
|
compaction: defaultOnError(zCompactionCapabilities.nullish(), () => {
|
|
19845
19965
|
return;
|
|
@@ -19847,6 +19967,9 @@ var zClientSessionCapabilities = object({
|
|
|
19847
19967
|
configOptions: defaultOnError(zSessionConfigOptionsCapabilities.nullish(), () => {
|
|
19848
19968
|
return;
|
|
19849
19969
|
}),
|
|
19970
|
+
notices: defaultOnError(zNoticeCapabilities.nullish(), () => {
|
|
19971
|
+
return;
|
|
19972
|
+
}),
|
|
19850
19973
|
_meta: defaultOnError(record(string2(), unknown()).nullish(), () => {
|
|
19851
19974
|
return;
|
|
19852
19975
|
})
|
|
@@ -20522,8 +20645,8 @@ var zCancelRequestNotification2 = object({
|
|
|
20522
20645
|
})
|
|
20523
20646
|
});
|
|
20524
20647
|
// node_modules/@agentclientprotocol/sdk/dist/v2/acp.js
|
|
20525
|
-
function ndJsonStream2(output, input) {
|
|
20526
|
-
return ndJsonStream(output, input);
|
|
20648
|
+
function ndJsonStream2(output, input, options) {
|
|
20649
|
+
return ndJsonStream(output, input, options);
|
|
20527
20650
|
}
|
|
20528
20651
|
function emptyObjectResponse(response) {
|
|
20529
20652
|
return response ?? {};
|
|
@@ -21367,7 +21490,7 @@ var agentRequestSpecs = {
|
|
|
21367
21490
|
unstable_disableProvider: requestSpec(AGENT_METHODS.providers_disable, zDisableProviderRequest, zDisableProviderResponse, emptyObjectResponse),
|
|
21368
21491
|
newSession: requestSpec(AGENT_METHODS.session_new, zNewSessionRequest, zNewSessionResponse),
|
|
21369
21492
|
setSessionConfigOption: requestSpec(AGENT_METHODS.session_set_config_option, zSetSessionConfigOptionRequest, zSetSessionConfigOptionResponse),
|
|
21370
|
-
prompt: requestSpec(AGENT_METHODS.session_prompt, zPromptRequest, zPromptResponse
|
|
21493
|
+
prompt: requestSpec(AGENT_METHODS.session_prompt, zPromptRequest, zPromptResponse),
|
|
21371
21494
|
unstable_messageMcp: requestSpec(AGENT_METHODS.mcp_message, zMessageMcpRequest, zMessageMcpResponse),
|
|
21372
21495
|
listSessions: requestSpec(AGENT_METHODS.session_list, zListSessionsRequest, zListSessionsResponse),
|
|
21373
21496
|
deleteSession: requestSpec(AGENT_METHODS.session_delete, zDeleteSessionRequest, zDeleteSessionResponse, emptyObjectResponse),
|
|
@@ -21721,7 +21844,7 @@ var package_default = {
|
|
|
21721
21844
|
publishConfig: {
|
|
21722
21845
|
access: "public"
|
|
21723
21846
|
},
|
|
21724
|
-
version: "0.
|
|
21847
|
+
version: "0.7.0",
|
|
21725
21848
|
description: "Native ACP v2 agent for the OpenAI Codex app-server",
|
|
21726
21849
|
packageManager: "bun@1.4.0",
|
|
21727
21850
|
engines: {
|
|
@@ -21755,7 +21878,7 @@ var package_default = {
|
|
|
21755
21878
|
"package:win-x64": "cd dist/bin && zip codex-acp-v2-x64-windows.zip codex-acp-v2-x64-windows.exe",
|
|
21756
21879
|
"package:win-arm64": "cd dist/bin && zip codex-acp-v2-arm64-windows.zip codex-acp-v2-arm64-windows.exe",
|
|
21757
21880
|
start: "bun src/index.ts",
|
|
21758
|
-
"generate-types": "codex app-server generate-ts --out src/app-server",
|
|
21881
|
+
"generate-types": "codex app-server generate-ts --experimental --out src/app-server",
|
|
21759
21882
|
test: "vitest run --exclude src/__tests__/e2e.test.ts",
|
|
21760
21883
|
"test:watch": "vitest",
|
|
21761
21884
|
typecheck: "tsc --noEmit",
|
|
@@ -21787,7 +21910,7 @@ var package_default = {
|
|
|
21787
21910
|
vitest: "^4.1.11"
|
|
21788
21911
|
},
|
|
21789
21912
|
dependencies: {
|
|
21790
|
-
"@agentclientprotocol/sdk": "^1.
|
|
21913
|
+
"@agentclientprotocol/sdk": "^1.5.1",
|
|
21791
21914
|
diff: "^9.0.0",
|
|
21792
21915
|
open: "^11.0.2",
|
|
21793
21916
|
"vscode-jsonrpc": "^9.0.2"
|
|
@@ -21797,43 +21920,182 @@ var package_default = {
|
|
|
21797
21920
|
}
|
|
21798
21921
|
};
|
|
21799
21922
|
|
|
21923
|
+
// src/util/abort.ts
|
|
21924
|
+
function abortable(operation, signal) {
|
|
21925
|
+
if (signal.aborted) {
|
|
21926
|
+
operation.catch(() => {});
|
|
21927
|
+
return Promise.reject(signal.reason);
|
|
21928
|
+
}
|
|
21929
|
+
return new Promise((resolve, reject) => {
|
|
21930
|
+
const abort = () => {
|
|
21931
|
+
cleanup();
|
|
21932
|
+
reject(signal.reason);
|
|
21933
|
+
};
|
|
21934
|
+
const cleanup = () => signal.removeEventListener("abort", abort);
|
|
21935
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
21936
|
+
operation.then((value) => {
|
|
21937
|
+
cleanup();
|
|
21938
|
+
resolve(value);
|
|
21939
|
+
}, (error40) => {
|
|
21940
|
+
cleanup();
|
|
21941
|
+
reject(error40);
|
|
21942
|
+
});
|
|
21943
|
+
});
|
|
21944
|
+
}
|
|
21945
|
+
|
|
21946
|
+
// src/agent/clientTools.ts
|
|
21947
|
+
var PREFIX = "alwith_client_";
|
|
21948
|
+
var MAX_RESULT_BYTES = 16 * 1024 * 1024;
|
|
21949
|
+
function record2(value) {
|
|
21950
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
21951
|
+
}
|
|
21952
|
+
function clientToolsOf(meta) {
|
|
21953
|
+
if (!record2(meta) || !record2(meta["alwith"]) || meta["alwith"]["tools"] === undefined)
|
|
21954
|
+
return;
|
|
21955
|
+
const value = meta["alwith"]["tools"];
|
|
21956
|
+
if (!record2(value) || value["version"] !== 1 || typeof value["revision"] !== "string" || !value["revision"].trim() || !Array.isArray(value["definitions"]) || value["definitions"].length > 128) {
|
|
21957
|
+
throw RequestError.invalidParams(undefined, "Expected a version 1 client tool set with revision and definitions");
|
|
21958
|
+
}
|
|
21959
|
+
const names = new Set;
|
|
21960
|
+
const definitions = value["definitions"].map((tool) => {
|
|
21961
|
+
if (!record2(tool) || typeof tool["name"] !== "string" || !/^[a-zA-Z][a-zA-Z0-9_]{0,49}$/.test(tool["name"]) || names.has(tool["name"]) || typeof tool["description"] !== "string" || !record2(tool["inputSchema"]) || tool["inputSchema"]["type"] !== "object") {
|
|
21962
|
+
throw RequestError.invalidParams(undefined, "Client tools require unique names, descriptions and object input schemas");
|
|
21963
|
+
}
|
|
21964
|
+
names.add(tool["name"]);
|
|
21965
|
+
return { name: tool["name"], description: tool["description"], inputSchema: structuredClone(tool["inputSchema"]) };
|
|
21966
|
+
});
|
|
21967
|
+
return { version: 1, revision: value["revision"], definitions };
|
|
21968
|
+
}
|
|
21969
|
+
function dynamicTools(set2) {
|
|
21970
|
+
return set2.definitions.map((tool) => ({ type: "function", ...tool, name: PREFIX + tool["name"], deferLoading: false }));
|
|
21971
|
+
}
|
|
21972
|
+
function failure(message) {
|
|
21973
|
+
return { success: false, contentItems: [{ type: "inputText", text: message }] };
|
|
21974
|
+
}
|
|
21975
|
+
function toolResponse(value) {
|
|
21976
|
+
if (!record2(value) || typeof value["success"] !== "boolean" || !Array.isArray(value["contentItems"]) || Buffer.byteLength(JSON.stringify(value)) > MAX_RESULT_BYTES) {
|
|
21977
|
+
throw new Error("Invalid or oversized client tool result");
|
|
21978
|
+
}
|
|
21979
|
+
const contentItems = value["contentItems"].map((item) => {
|
|
21980
|
+
if (!record2(item))
|
|
21981
|
+
throw new Error("Invalid client tool content");
|
|
21982
|
+
if (item["type"] === "text" && typeof item["text"] === "string")
|
|
21983
|
+
return { type: "inputText", text: item["text"] };
|
|
21984
|
+
if ((item["type"] === "image" || item["type"] === "audio") && typeof item["data"] === "string" && typeof item["mimeType"] === "string" && /^[A-Za-z0-9+/]*={0,2}$/.test(item["data"])) {
|
|
21985
|
+
const supported = item["type"] === "image" ? /^image\/(png|jpeg|webp|gif)$/ : /^audio\/(wav|mpeg|mp3|ogg|flac|mp4)$/;
|
|
21986
|
+
if (!supported.test(item["mimeType"]))
|
|
21987
|
+
throw new Error("Unsupported client tool media type");
|
|
21988
|
+
const url2 = `data:${item["mimeType"]};base64,${item["data"]}`;
|
|
21989
|
+
return item["type"] === "image" ? { type: "inputImage", imageUrl: url2 } : { type: "inputAudio", audioUrl: url2 };
|
|
21990
|
+
}
|
|
21991
|
+
throw new Error("Client tool content must be text or bounded inline media");
|
|
21992
|
+
});
|
|
21993
|
+
return { success: value["success"], contentItems };
|
|
21994
|
+
}
|
|
21995
|
+
|
|
21996
|
+
class ClientTools {
|
|
21997
|
+
session;
|
|
21998
|
+
client;
|
|
21999
|
+
lifetime;
|
|
22000
|
+
calls = new WeakMap;
|
|
22001
|
+
constructor(session, client, lifetime) {
|
|
22002
|
+
this.session = session;
|
|
22003
|
+
this.client = client;
|
|
22004
|
+
this.lifetime = lifetime;
|
|
22005
|
+
}
|
|
22006
|
+
call(params) {
|
|
22007
|
+
const turn = this.session.activeTurn;
|
|
22008
|
+
const set2 = this.session.clientTools;
|
|
22009
|
+
if (!turn || !set2 || this.session.closed || this.lifetime.aborted || turn.abort.signal.aborted || params.threadId !== this.session.id || params.namespace !== null || turn.turnId !== null && params.turnId !== turn.turnId)
|
|
22010
|
+
return Promise.resolve(failure("Client tool turn is no longer active"));
|
|
22011
|
+
const tool = set2.definitions.find((tool2) => PREFIX + tool2["name"] === params.tool);
|
|
22012
|
+
if (!tool)
|
|
22013
|
+
return Promise.resolve(failure("Client tool was not declared for this session"));
|
|
22014
|
+
let calls = this.calls.get(turn);
|
|
22015
|
+
if (!calls) {
|
|
22016
|
+
calls = new Map;
|
|
22017
|
+
this.calls.set(turn, calls);
|
|
22018
|
+
}
|
|
22019
|
+
const fingerprint = JSON.stringify([params.tool, params.arguments, set2.revision]);
|
|
22020
|
+
const previous = calls.get(params.callId);
|
|
22021
|
+
if (previous)
|
|
22022
|
+
return previous.fingerprint === fingerprint ? previous.response : Promise.resolve(failure("Client tool call ID was reused with different arguments"));
|
|
22023
|
+
const response = this.execute(turn, set2, tool, params);
|
|
22024
|
+
calls.set(params.callId, { fingerprint, response });
|
|
22025
|
+
return response;
|
|
22026
|
+
}
|
|
22027
|
+
async execute(turn, set2, tool, params) {
|
|
22028
|
+
const signal = AbortSignal.any([this.lifetime, this.client.signal, turn.abort.signal, turn.stop.signal]);
|
|
22029
|
+
try {
|
|
22030
|
+
signal.throwIfAborted();
|
|
22031
|
+
const turnId = turn.turnId ?? await abortable(turn.started, signal);
|
|
22032
|
+
if (turnId !== params.turnId || this.session.activeTurn !== turn)
|
|
22033
|
+
return failure("Client tool turn is no longer active");
|
|
22034
|
+
if (this.session.mode.approvalPolicy !== "never") {
|
|
22035
|
+
const permission = await this.client.requestPermission({
|
|
22036
|
+
title: `Run ${tool["name"]}?`,
|
|
22037
|
+
subject: { type: "tool_call", toolCall: { toolCallId: params.callId, name: tool["name"], title: tool["description"], kind: "other", status: "pending" } },
|
|
22038
|
+
options: [{ optionId: "allow_once", name: "Allow", kind: "allow_once" }, { optionId: "reject_once", name: "Reject", kind: "reject_once" }]
|
|
22039
|
+
}, signal);
|
|
22040
|
+
if (permission.outcome.outcome !== "selected" || permission.outcome.optionId !== "allow_once")
|
|
22041
|
+
return failure("Client tool permission was denied");
|
|
22042
|
+
}
|
|
22043
|
+
signal.throwIfAborted();
|
|
22044
|
+
const value = await abortable(this.client.requestTool({
|
|
22045
|
+
sessionId: this.session.id,
|
|
22046
|
+
turnId: params.turnId,
|
|
22047
|
+
toolCallId: params.callId,
|
|
22048
|
+
name: tool["name"],
|
|
22049
|
+
arguments: params.arguments,
|
|
22050
|
+
toolSetRevision: set2.revision
|
|
22051
|
+
}, signal), signal);
|
|
22052
|
+
if (this.session.activeTurn !== turn)
|
|
22053
|
+
return failure("Client tool turn is no longer active");
|
|
22054
|
+
signal.throwIfAborted();
|
|
22055
|
+
return toolResponse(value);
|
|
22056
|
+
} catch {
|
|
22057
|
+
return failure(signal.aborted ? "Client tool call was cancelled" : "Client tool call failed");
|
|
22058
|
+
}
|
|
22059
|
+
}
|
|
22060
|
+
}
|
|
22061
|
+
|
|
21800
22062
|
// src/agent/turnErrors.ts
|
|
21801
22063
|
function classifyTurnError(info) {
|
|
21802
|
-
const
|
|
22064
|
+
const failure2 = (category, retryable = false, stopReason = "_error") => ({ category, retryable, stopReason });
|
|
21803
22065
|
if (info === null)
|
|
21804
|
-
return
|
|
22066
|
+
return failure2("unknown");
|
|
21805
22067
|
if (typeof info === "object") {
|
|
21806
22068
|
if ("activeTurnNotSteerable" in info)
|
|
21807
|
-
return
|
|
22069
|
+
return failure2("turn_not_steerable");
|
|
21808
22070
|
const status = "httpConnectionFailed" in info ? info.httpConnectionFailed.httpStatusCode : ("responseStreamConnectionFailed" in info) ? info.responseStreamConnectionFailed.httpStatusCode : ("responseStreamDisconnected" in info) ? info.responseStreamDisconnected.httpStatusCode : info.responseTooManyFailedAttempts.httpStatusCode;
|
|
21809
|
-
return
|
|
22071
|
+
return failure2("connection", status === null || status === 408 || status === 429 || status >= 500);
|
|
21810
22072
|
}
|
|
21811
22073
|
switch (info) {
|
|
21812
22074
|
case "contextWindowExceeded":
|
|
21813
|
-
return
|
|
22075
|
+
return failure2("context_window", false, "max_tokens");
|
|
21814
22076
|
case "cyberPolicy":
|
|
21815
22077
|
case "misalignmentPolicyViolation":
|
|
21816
|
-
return
|
|
22078
|
+
return failure2("policy", false, "refusal");
|
|
21817
22079
|
case "sessionBudgetExceeded":
|
|
21818
|
-
return
|
|
22080
|
+
return failure2("budget");
|
|
21819
22081
|
case "usageLimitExceeded":
|
|
21820
|
-
return
|
|
22082
|
+
return failure2("usage_limit");
|
|
21821
22083
|
case "rateLimitExceeded":
|
|
21822
|
-
return
|
|
22084
|
+
return failure2("rate_limit", true);
|
|
21823
22085
|
case "serverOverloaded":
|
|
21824
|
-
return
|
|
22086
|
+
return failure2("overloaded", true);
|
|
21825
22087
|
case "internalServerError":
|
|
21826
|
-
return
|
|
22088
|
+
return failure2("internal", true);
|
|
21827
22089
|
case "unauthorized":
|
|
21828
|
-
return
|
|
22090
|
+
return failure2("authentication");
|
|
21829
22091
|
case "badRequest":
|
|
21830
|
-
return
|
|
22092
|
+
return failure2("invalid_request");
|
|
21831
22093
|
case "threadRollbackFailed":
|
|
21832
|
-
return
|
|
22094
|
+
return failure2("rollback");
|
|
21833
22095
|
case "sandboxError":
|
|
21834
|
-
return
|
|
22096
|
+
return failure2("sandbox");
|
|
21835
22097
|
case "other":
|
|
21836
|
-
return
|
|
22098
|
+
return failure2("unknown");
|
|
21837
22099
|
}
|
|
21838
22100
|
}
|
|
21839
22101
|
|
|
@@ -23344,7 +23606,7 @@ function itemSnapshot(item) {
|
|
|
23344
23606
|
switch (item.type) {
|
|
23345
23607
|
case "userMessage": {
|
|
23346
23608
|
const content = item.content.flatMap(fromUserInput);
|
|
23347
|
-
return content.length > 0 ? [{ sessionUpdate: "user_message", messageId: item.id, content }] : [];
|
|
23609
|
+
return content.length > 0 ? [{ sessionUpdate: "user_message", messageId: item.clientId ?? item.id, content }] : [];
|
|
23348
23610
|
}
|
|
23349
23611
|
case "agentMessage":
|
|
23350
23612
|
return item.text.length > 0 ? [{
|
|
@@ -23701,7 +23963,7 @@ ${details}` : summary)];
|
|
|
23701
23963
|
return [compactionUpdate(item.id, "in_progress")];
|
|
23702
23964
|
case "userMessage": {
|
|
23703
23965
|
const content = item.content.flatMap(fromUserInput);
|
|
23704
|
-
return content.length > 0 ? [{ sessionUpdate: "user_message", messageId: item.id, content }] : [];
|
|
23966
|
+
return content.length > 0 ? [{ sessionUpdate: "user_message", messageId: item.clientId ?? item.id, content }] : [];
|
|
23705
23967
|
}
|
|
23706
23968
|
case "hookPrompt":
|
|
23707
23969
|
case "functionCallOutput":
|
|
@@ -23982,7 +24244,7 @@ function modelLacksReasoning(model) {
|
|
|
23982
24244
|
const options = supportedEfforts(model);
|
|
23983
24245
|
return options.length > 0 && options.every((option) => option.reasoningEffort === "none");
|
|
23984
24246
|
}
|
|
23985
|
-
function modelConfigOption(catalog, current,
|
|
24247
|
+
function modelConfigOption(catalog, current, gatewayGroups = []) {
|
|
23986
24248
|
const visible = catalog.filter((model) => !model.hidden || model.id === current);
|
|
23987
24249
|
const options = visible.map((model) => ({
|
|
23988
24250
|
value: model.id,
|
|
@@ -24000,16 +24262,18 @@ function modelConfigOption(catalog, current, gatewayGroup = null) {
|
|
|
24000
24262
|
type: "select",
|
|
24001
24263
|
currentValue: current
|
|
24002
24264
|
};
|
|
24003
|
-
if (
|
|
24265
|
+
if (gatewayGroups.length === 0)
|
|
24004
24266
|
return { ...base, options };
|
|
24005
|
-
const
|
|
24006
|
-
const
|
|
24007
|
-
|
|
24267
|
+
const owner = new Map;
|
|
24268
|
+
for (const group of gatewayGroups)
|
|
24269
|
+
for (const id of group.modelIds)
|
|
24270
|
+
owner.set(id, group.id);
|
|
24271
|
+
const native = options.filter((option) => !owner.has(option.value));
|
|
24008
24272
|
return {
|
|
24009
24273
|
...base,
|
|
24010
24274
|
options: [
|
|
24011
24275
|
{ groupId: "codex", name: "Codex", options: native },
|
|
24012
|
-
{ groupId:
|
|
24276
|
+
...gatewayGroups.map((group) => ({ groupId: group.id, name: group.name, options: options.filter((option) => owner.get(option.value) === group.id) }))
|
|
24013
24277
|
]
|
|
24014
24278
|
};
|
|
24015
24279
|
}
|
|
@@ -24900,29 +25164,6 @@ class TurnContext {
|
|
|
24900
25164
|
}
|
|
24901
25165
|
}
|
|
24902
25166
|
|
|
24903
|
-
// src/util/abort.ts
|
|
24904
|
-
function abortable(operation, signal) {
|
|
24905
|
-
if (signal.aborted) {
|
|
24906
|
-
operation.catch(() => {});
|
|
24907
|
-
return Promise.reject(signal.reason);
|
|
24908
|
-
}
|
|
24909
|
-
return new Promise((resolve, reject) => {
|
|
24910
|
-
const abort = () => {
|
|
24911
|
-
cleanup();
|
|
24912
|
-
reject(signal.reason);
|
|
24913
|
-
};
|
|
24914
|
-
const cleanup = () => signal.removeEventListener("abort", abort);
|
|
24915
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
24916
|
-
operation.then((value) => {
|
|
24917
|
-
cleanup();
|
|
24918
|
-
resolve(value);
|
|
24919
|
-
}, (error40) => {
|
|
24920
|
-
cleanup();
|
|
24921
|
-
reject(error40);
|
|
24922
|
-
});
|
|
24923
|
-
});
|
|
24924
|
-
}
|
|
24925
|
-
|
|
24926
25167
|
// node_modules/open/index.js
|
|
24927
25168
|
import process10 from "process";
|
|
24928
25169
|
import path5 from "path";
|
|
@@ -25740,6 +25981,9 @@ class ClientSession {
|
|
|
25740
25981
|
return signal ? abortable(pending, signal) : pending;
|
|
25741
25982
|
}, signal);
|
|
25742
25983
|
}
|
|
25984
|
+
async requestTool(params, signal) {
|
|
25985
|
+
return await this.link.request("_alwith/tool/call", params, { cancellationSignal: signal });
|
|
25986
|
+
}
|
|
25743
25987
|
async createElicitation(request, signal) {
|
|
25744
25988
|
signal = signal ? AbortSignal.any([signal, this.output.signal]) : this.output.signal;
|
|
25745
25989
|
signal.throwIfAborted();
|
|
@@ -25966,7 +26210,7 @@ function sessionConfigOptions(session) {
|
|
|
25966
26210
|
const model = findModel(session.catalog, session.model.model);
|
|
25967
26211
|
const options = [
|
|
25968
26212
|
modeConfigOption(session.mode),
|
|
25969
|
-
modelConfigOption(session.catalog, session.model.model, session.
|
|
26213
|
+
modelConfigOption(session.catalog, session.model.model, session.gatewayGroups),
|
|
25970
26214
|
effortConfigOption(supportedEfforts(model), session.model.effort),
|
|
25971
26215
|
collaborationModeConfigOption(session.collaborationMode)
|
|
25972
26216
|
];
|
|
@@ -26019,7 +26263,7 @@ async function applyConfigOption(session, codex, request) {
|
|
|
26019
26263
|
threadId: session.id,
|
|
26020
26264
|
collaborationMode: {
|
|
26021
26265
|
mode,
|
|
26022
|
-
settings: { model: session.model.model, reasoning_effort: session.model.effort, developer_instructions: null }
|
|
26266
|
+
settings: { model: findModel(session.catalog, session.model.model)?.model ?? session.model.model, reasoning_effort: session.model.effort, developer_instructions: null }
|
|
26023
26267
|
}
|
|
26024
26268
|
});
|
|
26025
26269
|
session.collaborationMode = mode;
|
|
@@ -26074,31 +26318,44 @@ import path6 from "path";
|
|
|
26074
26318
|
var OPENAI_PROVIDER_ID = "openai";
|
|
26075
26319
|
var GATEWAY_MODEL_PROVIDER = "custom-gateway";
|
|
26076
26320
|
var DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
26321
|
+
var GATEWAY_ID_PATTERN = /^[a-z0-9-]+$/;
|
|
26322
|
+
function gatewayModelId(connectionId, modelId) {
|
|
26323
|
+
return `gateway:${encodeURIComponent(connectionId)}:${encodeURIComponent(modelId)}`;
|
|
26324
|
+
}
|
|
26325
|
+
|
|
26077
26326
|
class ProviderRouting {
|
|
26078
26327
|
baseConfig;
|
|
26079
26328
|
configuredProvider;
|
|
26080
|
-
|
|
26329
|
+
gateways = new Map;
|
|
26081
26330
|
constructor(baseConfig, configuredProvider) {
|
|
26082
26331
|
this.baseConfig = baseConfig;
|
|
26083
26332
|
this.configuredProvider = configuredProvider;
|
|
26084
26333
|
}
|
|
26085
26334
|
copy() {
|
|
26086
26335
|
const copy = new ProviderRouting(this.baseConfig, this.configuredProvider);
|
|
26087
|
-
copy.
|
|
26336
|
+
copy.gateways = new Map(this.gateways);
|
|
26088
26337
|
return copy;
|
|
26089
26338
|
}
|
|
26090
26339
|
get active() {
|
|
26091
|
-
return this.
|
|
26340
|
+
return this.gateways.values().next().value ?? null;
|
|
26341
|
+
}
|
|
26342
|
+
gateway(id) {
|
|
26343
|
+
return id === null ? null : this.gateways.get(id) ?? null;
|
|
26344
|
+
}
|
|
26345
|
+
hasGateway(id) {
|
|
26346
|
+
return id !== null && this.gateways.has(id);
|
|
26092
26347
|
}
|
|
26093
26348
|
list() {
|
|
26094
|
-
const
|
|
26349
|
+
const first = this.active;
|
|
26350
|
+
const routed = first !== null && first.mode === "route";
|
|
26351
|
+
const summary = (gateway) => ({ id: gateway.id, name: gateway.name, baseUrl: gateway.baseUrl, models: gateway.models.map((model) => model.id) });
|
|
26095
26352
|
return {
|
|
26096
26353
|
providers: [{
|
|
26097
26354
|
providerId: OPENAI_PROVIDER_ID,
|
|
26098
26355
|
supported: ["openai"],
|
|
26099
26356
|
required: false,
|
|
26100
|
-
current: routed &&
|
|
26101
|
-
...
|
|
26357
|
+
current: routed && first ? { apiType: "openai", baseUrl: first.baseUrl } : { apiType: "openai", baseUrl: this.nativeBaseUrl() },
|
|
26358
|
+
...first && !routed ? { _meta: { codex: { mode: "catalog", gateway: summary(first), gateways: [...this.gateways.values()].map(summary) } } } : {}
|
|
26102
26359
|
}]
|
|
26103
26360
|
};
|
|
26104
26361
|
}
|
|
@@ -26114,7 +26371,13 @@ class ProviderRouting {
|
|
|
26114
26371
|
throw RequestError.invalidParams({ baseUrl: request.baseUrl }, "baseUrl must be an http(s) URL");
|
|
26115
26372
|
}
|
|
26116
26373
|
const hints = readHints(request._meta);
|
|
26117
|
-
this.
|
|
26374
|
+
if (hints.id === OPENAI_PROVIDER_ID || hints.id === this.configuredProvider) {
|
|
26375
|
+
throw RequestError.invalidParams({ id: hints.id }, `_meta.codex.id "${hints.id}" is Codex's own provider; pick another gateway id`);
|
|
26376
|
+
}
|
|
26377
|
+
if (hints.mode === "route" || this.mode !== hints.mode)
|
|
26378
|
+
this.gateways.clear();
|
|
26379
|
+
this.gateways.set(hints.id, {
|
|
26380
|
+
id: hints.id,
|
|
26118
26381
|
baseUrl,
|
|
26119
26382
|
headers: { ...request.headers ?? {} },
|
|
26120
26383
|
name: hints.name ?? "Client-configured gateway",
|
|
@@ -26124,41 +26387,77 @@ class ProviderRouting {
|
|
|
26124
26387
|
config: hints.config,
|
|
26125
26388
|
mode: hints.mode,
|
|
26126
26389
|
catalogEntries: hints.catalogEntries
|
|
26127
|
-
};
|
|
26390
|
+
});
|
|
26128
26391
|
}
|
|
26129
26392
|
get mode() {
|
|
26130
|
-
return this.
|
|
26393
|
+
return this.active?.mode ?? "route";
|
|
26394
|
+
}
|
|
26395
|
+
gatewayFor(modelId) {
|
|
26396
|
+
for (const gateway of this.gateways.values()) {
|
|
26397
|
+
if (gateway.models.some((model) => (this.mode === "catalog" ? gatewayModelId(gateway.id, model.id) : model.id) === modelId))
|
|
26398
|
+
return gateway;
|
|
26399
|
+
}
|
|
26400
|
+
return null;
|
|
26401
|
+
}
|
|
26402
|
+
gatewayIdFor(modelId) {
|
|
26403
|
+
return this.gatewayFor(modelId)?.id ?? null;
|
|
26131
26404
|
}
|
|
26132
26405
|
isGatewayModel(modelId) {
|
|
26133
|
-
return this.
|
|
26406
|
+
return this.gatewayFor(modelId) !== null;
|
|
26134
26407
|
}
|
|
26135
|
-
|
|
26136
|
-
if (
|
|
26137
|
-
return
|
|
26138
|
-
return { name:
|
|
26408
|
+
gatewayGroups() {
|
|
26409
|
+
if (this.mode !== "catalog")
|
|
26410
|
+
return [];
|
|
26411
|
+
return [...this.gateways.values()].filter((gateway) => gateway.models.length > 0).map((gateway) => ({ id: gateway.id, name: gateway.name, modelIds: gateway.models.map((model) => gatewayModelId(gateway.id, model.id)) }));
|
|
26412
|
+
}
|
|
26413
|
+
selectionId(modelId, provider) {
|
|
26414
|
+
return modelId !== null && this.mode === "catalog" && this.hasGateway(provider) ? gatewayModelId(provider, modelId) : modelId;
|
|
26415
|
+
}
|
|
26416
|
+
upstreamModel(selectionId) {
|
|
26417
|
+
if (selectionId === null || !selectionId.startsWith("gateway:"))
|
|
26418
|
+
return selectionId;
|
|
26419
|
+
const gateway = this.gatewayFor(selectionId);
|
|
26420
|
+
const model = gateway?.models.find((model2) => gatewayModelId(gateway.id, model2.id) === selectionId);
|
|
26421
|
+
if (!model)
|
|
26422
|
+
throw RequestError.invalidParams({ model: selectionId }, "The selected provider connection or model is unavailable");
|
|
26423
|
+
return model.id;
|
|
26139
26424
|
}
|
|
26140
26425
|
disable(request) {
|
|
26141
|
-
if (request.providerId
|
|
26142
|
-
|
|
26426
|
+
if (request.providerId !== OPENAI_PROVIDER_ID)
|
|
26427
|
+
return;
|
|
26428
|
+
const id = readGatewayId(request._meta);
|
|
26429
|
+
if (id === null)
|
|
26430
|
+
this.gateways.clear();
|
|
26431
|
+
else
|
|
26432
|
+
this.gateways.delete(id);
|
|
26143
26433
|
}
|
|
26144
26434
|
modelProvider() {
|
|
26145
|
-
return this.
|
|
26435
|
+
return this.defaultGatewayId() ?? this.configuredProvider;
|
|
26146
26436
|
}
|
|
26147
26437
|
routesByDefault() {
|
|
26148
|
-
return this.
|
|
26438
|
+
return this.defaultGatewayId() !== null;
|
|
26439
|
+
}
|
|
26440
|
+
defaultGatewayId() {
|
|
26441
|
+
const first = this.active;
|
|
26442
|
+
return first !== null && first.mode === "route" ? first.id : null;
|
|
26149
26443
|
}
|
|
26150
|
-
threadConfig(
|
|
26151
|
-
|
|
26444
|
+
threadConfig(gatewayId = this.defaultGatewayId()) {
|
|
26445
|
+
const gateway = this.gateway(gatewayId);
|
|
26446
|
+
if (!gateway)
|
|
26152
26447
|
return this.baseConfig;
|
|
26153
|
-
return this.applyGateway(this.baseConfig,
|
|
26448
|
+
return this.applyGateway(this.baseConfig, gateway);
|
|
26154
26449
|
}
|
|
26155
|
-
routeConfig(config2,
|
|
26156
|
-
return this.rebind(config2, this,
|
|
26450
|
+
routeConfig(config2, gatewayId) {
|
|
26451
|
+
return this.rebind(config2, this, gatewayId);
|
|
26157
26452
|
}
|
|
26158
26453
|
overrideKeys() {
|
|
26159
|
-
|
|
26454
|
+
const keys = new Set;
|
|
26455
|
+
for (const gateway of this.gateways.values())
|
|
26456
|
+
for (const key of Object.keys(gateway.config))
|
|
26457
|
+
keys.add(key);
|
|
26458
|
+
return [...keys];
|
|
26160
26459
|
}
|
|
26161
|
-
rebind(config2, previous,
|
|
26460
|
+
rebind(config2, previous, gatewayId = this.defaultGatewayId()) {
|
|
26162
26461
|
const next = { ...config2 };
|
|
26163
26462
|
for (const key of previous.overrideKeys()) {
|
|
26164
26463
|
if (key in this.baseConfig)
|
|
@@ -26166,13 +26465,11 @@ class ProviderRouting {
|
|
|
26166
26465
|
else
|
|
26167
26466
|
delete next[key];
|
|
26168
26467
|
}
|
|
26169
|
-
|
|
26170
|
-
|
|
26171
|
-
|
|
26172
|
-
|
|
26173
|
-
|
|
26174
|
-
}
|
|
26175
|
-
return this.applyGateway(next, this.gateway);
|
|
26468
|
+
delete next["model_providers"];
|
|
26469
|
+
if (isRecord2(this.baseConfig["model_providers"]))
|
|
26470
|
+
next["model_providers"] = this.baseConfig["model_providers"];
|
|
26471
|
+
const gateway = this.gateway(gatewayId);
|
|
26472
|
+
return gateway ? this.applyGateway(next, gateway) : next;
|
|
26176
26473
|
}
|
|
26177
26474
|
applyGateway(config2, gateway) {
|
|
26178
26475
|
const existing = isRecord2(config2["model_providers"]) ? config2["model_providers"] : {};
|
|
@@ -26187,15 +26484,24 @@ class ProviderRouting {
|
|
|
26187
26484
|
return {
|
|
26188
26485
|
...config2,
|
|
26189
26486
|
...gateway.config,
|
|
26190
|
-
model_providers: { ...existing, [
|
|
26487
|
+
model_providers: { ...existing, [gateway.id]: entry }
|
|
26191
26488
|
};
|
|
26192
26489
|
}
|
|
26193
26490
|
catalog(codexCatalog) {
|
|
26194
|
-
|
|
26491
|
+
const first = this.active;
|
|
26492
|
+
if (first === null)
|
|
26195
26493
|
return codexCatalog;
|
|
26196
|
-
|
|
26197
|
-
|
|
26198
|
-
|
|
26494
|
+
if (first.mode === "route") {
|
|
26495
|
+
if (first.models.length === 0)
|
|
26496
|
+
return codexCatalog;
|
|
26497
|
+
return first.models.map((model, index) => gatewayModel(model, index === 0, codexCatalog[0], first.catalogEntries.get(model.id)));
|
|
26498
|
+
}
|
|
26499
|
+
const own = [];
|
|
26500
|
+
for (const gateway of this.gateways.values()) {
|
|
26501
|
+
for (const model of gateway.models)
|
|
26502
|
+
own.push({ ...gatewayModel(model, false, codexCatalog[0], gateway.catalogEntries.get(model.id)), id: gatewayModelId(gateway.id, model.id) });
|
|
26503
|
+
}
|
|
26504
|
+
return [...codexCatalog, ...own];
|
|
26199
26505
|
}
|
|
26200
26506
|
nativeBaseUrl() {
|
|
26201
26507
|
const providers = this.baseConfig["model_providers"];
|
|
@@ -26212,6 +26518,7 @@ function readHints(meta) {
|
|
|
26212
26518
|
const root = isRecord2(meta) ? meta : {};
|
|
26213
26519
|
const alwith = isRecord2(root["alwith"]) ? root["alwith"] : {};
|
|
26214
26520
|
const codex = isRecord2(root["codex"]) ? root["codex"] : {};
|
|
26521
|
+
const id = readGatewayId(meta) ?? GATEWAY_MODEL_PROVIDER;
|
|
26215
26522
|
const models = [];
|
|
26216
26523
|
if (Array.isArray(alwith["models"])) {
|
|
26217
26524
|
for (const entry of alwith["models"]) {
|
|
@@ -26249,7 +26556,18 @@ function readHints(meta) {
|
|
|
26249
26556
|
}
|
|
26250
26557
|
const catalogPath = config2["model_catalog_json"];
|
|
26251
26558
|
const catalogEntries = typeof catalogPath === "string" ? readCatalogFile(catalogPath) : new Map;
|
|
26252
|
-
return { models, model, name, bearerToken, config: config2, mode, catalogEntries };
|
|
26559
|
+
return { id, models, model, name, bearerToken, config: config2, mode, catalogEntries };
|
|
26560
|
+
}
|
|
26561
|
+
function readGatewayId(meta) {
|
|
26562
|
+
const root = isRecord2(meta) ? meta : {};
|
|
26563
|
+
const codex = isRecord2(root["codex"]) ? root["codex"] : {};
|
|
26564
|
+
const raw = codex["id"];
|
|
26565
|
+
if (raw === undefined)
|
|
26566
|
+
return null;
|
|
26567
|
+
if (typeof raw !== "string" || !GATEWAY_ID_PATTERN.test(raw)) {
|
|
26568
|
+
throw RequestError.invalidParams({ id: raw }, "_meta.codex.id must match [a-z0-9-]+");
|
|
26569
|
+
}
|
|
26570
|
+
return raw;
|
|
26253
26571
|
}
|
|
26254
26572
|
function readCatalogFile(catalogPath) {
|
|
26255
26573
|
const resolved = catalogPath.startsWith("~/") ? path6.join(os2.homedir(), catalogPath.slice(2)) : catalogPath;
|
|
@@ -26310,7 +26628,7 @@ function gatewayModel(model, isDefault, template, entry) {
|
|
|
26310
26628
|
}
|
|
26311
26629
|
|
|
26312
26630
|
// src/agent/session.ts
|
|
26313
|
-
function createActiveTurn(threadId) {
|
|
26631
|
+
function createActiveTurn(threadId, clientUserMessageId = null) {
|
|
26314
26632
|
let resolveStarted = () => {};
|
|
26315
26633
|
let resolveFinished = () => {};
|
|
26316
26634
|
let started = new Promise((resolve) => {
|
|
@@ -26324,6 +26642,7 @@ function createActiveTurn(threadId) {
|
|
|
26324
26642
|
return {
|
|
26325
26643
|
turnId: null,
|
|
26326
26644
|
threadId,
|
|
26645
|
+
clientUserMessageId,
|
|
26327
26646
|
abort: new AbortController,
|
|
26328
26647
|
stop: new AbortController,
|
|
26329
26648
|
interrupts: new Map,
|
|
@@ -26406,6 +26725,12 @@ class CodexAgent {
|
|
|
26406
26725
|
}
|
|
26407
26726
|
if (notification.method === "account/updated")
|
|
26408
26727
|
this.refreshAccounts().catch((error40) => logger.error("refreshing account failed", error40));
|
|
26728
|
+
if (notification.method === "account/rateLimits/updated")
|
|
26729
|
+
this.forward("_codex/rate_limits_updated", notification.params);
|
|
26730
|
+
if (notification.method === "fuzzyFileSearch/sessionUpdated")
|
|
26731
|
+
this.forward("_codex/fuzzy_file_search_updated", notification.params);
|
|
26732
|
+
if (notification.method === "fuzzyFileSearch/sessionCompleted")
|
|
26733
|
+
this.forward("_codex/fuzzy_file_search_completed", notification.params);
|
|
26409
26734
|
});
|
|
26410
26735
|
this.codex.disconnectSignal.addEventListener("abort", stopObserving, { once: true });
|
|
26411
26736
|
}
|
|
@@ -26442,7 +26767,7 @@ class CodexAgent {
|
|
|
26442
26767
|
additionalDirectories: {}
|
|
26443
26768
|
},
|
|
26444
26769
|
providers: {},
|
|
26445
|
-
_meta: { codex: { archive: true, seedHistory: true, skills: true, plugins: true, providerCatalog: true } }
|
|
26770
|
+
_meta: { alwith: { tools: { version: 1 } }, codex: { archive: true, seedHistory: true, skills: true, plugins: true, providerCatalog: true, rename: true, account: true, fuzzyFileSearch: true } }
|
|
26446
26771
|
},
|
|
26447
26772
|
authMethods: authMethods(this.capabilities, this.env)
|
|
26448
26773
|
};
|
|
@@ -26529,8 +26854,15 @@ class CodexAgent {
|
|
|
26529
26854
|
const catalog = await this.withCodex(() => this.codex.allModels(true));
|
|
26530
26855
|
const nativeProvider = await this.resolveModelProvider(candidate);
|
|
26531
26856
|
const wholesale = this.providers.active !== null && this.providers.mode === "route" || candidate.active !== null && candidate.mode === "route";
|
|
26532
|
-
const
|
|
26533
|
-
const
|
|
26857
|
+
const unavailable = new Set([...this.sessions.values()].filter((runtime) => this.providers.mode === "catalog" && this.providers.hasGateway(runtime.modelProvider) && !candidate.hasGateway(runtime.modelProvider)));
|
|
26858
|
+
const moving = [...this.sessions.values()].filter((runtime) => !unavailable.has(runtime) && (wholesale || this.providers.hasGateway(runtime.modelProvider) && candidate.gateway(runtime.modelProvider) !== this.providers.gateway(runtime.modelProvider)));
|
|
26859
|
+
const targets = new Map(moving.map((runtime) => {
|
|
26860
|
+
if (candidate.active === null)
|
|
26861
|
+
return [runtime, null];
|
|
26862
|
+
if (candidate.mode === "route")
|
|
26863
|
+
return [runtime, candidate.defaultGatewayId()];
|
|
26864
|
+
return [runtime, candidate.hasGateway(runtime.modelProvider) ? runtime.modelProvider : null];
|
|
26865
|
+
}));
|
|
26534
26866
|
for (const runtime of moving) {
|
|
26535
26867
|
try {
|
|
26536
26868
|
await this.codex.threadTurnsList({ threadId: runtime.session.id, limit: 1, itemsView: "notLoaded" });
|
|
@@ -26543,10 +26875,10 @@ class CodexAgent {
|
|
|
26543
26875
|
}
|
|
26544
26876
|
const nextCatalog = candidate.catalog(catalog);
|
|
26545
26877
|
for (const runtime of moving) {
|
|
26546
|
-
const
|
|
26547
|
-
const config2 = candidate.rebind(runtime.config, this.providers,
|
|
26548
|
-
const modelProvider =
|
|
26549
|
-
const keep = findModel(nextCatalog, runtime.session.model.model) && candidate.
|
|
26878
|
+
const target = targets.get(runtime) ?? null;
|
|
26879
|
+
const config2 = candidate.rebind(runtime.config, this.providers, target);
|
|
26880
|
+
const modelProvider = target ?? nativeProvider;
|
|
26881
|
+
const keep = findModel(nextCatalog, runtime.session.model.model) && candidate.gatewayIdFor(runtime.session.model.model) === target;
|
|
26550
26882
|
const requestedModel = candidate.mode === "route" ? candidate.active?.model ?? (keep ? runtime.session.model.model : null) : keep ? runtime.session.model.model : null;
|
|
26551
26883
|
const selection = resolveModelSelection(nextCatalog, requestedModel, requestedModel === runtime.session.model.model ? runtime.session.model.effort : null);
|
|
26552
26884
|
attempted.push(runtime);
|
|
@@ -26556,23 +26888,25 @@ class CodexAgent {
|
|
|
26556
26888
|
cwd: runtime.session.cwd,
|
|
26557
26889
|
config: config2,
|
|
26558
26890
|
modelProvider,
|
|
26559
|
-
model: selection.model,
|
|
26891
|
+
model: candidate.upstreamModel(selection.model),
|
|
26560
26892
|
excludeTurns: true
|
|
26561
26893
|
}));
|
|
26562
|
-
staged.set(runtime, { config: config2, catalog: nextCatalog, model: resolveModelSelection(nextCatalog, requestedModel ?? thread.model, thread.reasoningEffort) });
|
|
26894
|
+
staged.set(runtime, { config: config2, catalog: nextCatalog, model: resolveModelSelection(nextCatalog, requestedModel ?? candidate.selectionId(thread.model, modelProvider), thread.reasoningEffort) });
|
|
26563
26895
|
}
|
|
26896
|
+
for (const runtime of unavailable)
|
|
26897
|
+
runtime.config = candidate.rebind(runtime.config, this.providers, null);
|
|
26564
26898
|
this.providers = candidate;
|
|
26565
26899
|
for (const runtime of this.sessions.values()) {
|
|
26566
26900
|
const next = staged.get(runtime);
|
|
26567
26901
|
if (next) {
|
|
26568
26902
|
runtime.config = next.config;
|
|
26569
|
-
runtime.modelProvider = targets.get(runtime)
|
|
26903
|
+
runtime.modelProvider = targets.get(runtime) ?? nativeProvider;
|
|
26570
26904
|
runtime.session.model = next.model;
|
|
26571
26905
|
runtime.stale = false;
|
|
26572
26906
|
}
|
|
26573
26907
|
runtime.session.catalog = nextCatalog;
|
|
26574
|
-
runtime.session.
|
|
26575
|
-
if (!next)
|
|
26908
|
+
runtime.session.gatewayGroups = candidate.gatewayGroups();
|
|
26909
|
+
if (!next && !unavailable.has(runtime))
|
|
26576
26910
|
runtime.session.model = resolveModelSelection(nextCatalog, findModel(nextCatalog, runtime.session.model.model) ? runtime.session.model.model : null, runtime.session.model.effort);
|
|
26577
26911
|
runtime.client.update({ sessionUpdate: "config_option_update", configOptions: sessionConfigOptions(runtime.session), _meta: { codex: { routing: { stale: false } } } }).catch((error40) => logger.error("Provider config notification failed", error40));
|
|
26578
26912
|
}
|
|
@@ -26588,7 +26922,7 @@ class CodexAgent {
|
|
|
26588
26922
|
cwd: runtime.session.cwd,
|
|
26589
26923
|
config: runtime.config,
|
|
26590
26924
|
modelProvider: runtime.modelProvider,
|
|
26591
|
-
model: runtime.session.model.model,
|
|
26925
|
+
model: this.providers.upstreamModel(runtime.session.model.model),
|
|
26592
26926
|
excludeTurns: true
|
|
26593
26927
|
});
|
|
26594
26928
|
} catch (rollbackError) {
|
|
@@ -26662,36 +26996,51 @@ class CodexAgent {
|
|
|
26662
26996
|
this.assertUnsubscribeSettled(open2.request.sessionId);
|
|
26663
26997
|
}
|
|
26664
26998
|
const mcpServers = request.mcpServers ?? [];
|
|
26999
|
+
const clientTools = clientToolsOf(request._meta);
|
|
27000
|
+
const host = hostSessionOptions(request._meta);
|
|
27001
|
+
const mode = host.mode ?? initialAgentMode(this.env);
|
|
27002
|
+
const hostThreadOptions = {
|
|
27003
|
+
...host.instructions === undefined ? {} : { developerInstructions: host.instructions },
|
|
27004
|
+
...host.mode ? { approvalPolicy: mode.approvalPolicy, approvalsReviewer: mode.approvalsReviewer, sandbox: mode.sandboxMode } : {}
|
|
27005
|
+
};
|
|
26665
27006
|
const requestedModel = requestedModelOf(request._meta);
|
|
26666
|
-
let
|
|
27007
|
+
let gatewayId = this.providers.defaultGatewayId();
|
|
26667
27008
|
if (this.providers.active !== null && this.providers.mode === "catalog") {
|
|
26668
27009
|
if (requestedModel !== null)
|
|
26669
|
-
|
|
27010
|
+
gatewayId = this.providers.gatewayIdFor(requestedModel);
|
|
26670
27011
|
else if (open2.kind === "resume") {
|
|
26671
27012
|
const known = await this.withCodex(() => this.codex.threadRead({ threadId: open2.request.sessionId, includeTurns: false }));
|
|
26672
|
-
|
|
27013
|
+
gatewayId = this.providers.hasGateway(known.thread.modelProvider) ? known.thread.modelProvider : null;
|
|
26673
27014
|
}
|
|
26674
27015
|
}
|
|
27016
|
+
const onGateway = gatewayId !== null;
|
|
26675
27017
|
let accountVersion = this.accountGeneration;
|
|
26676
27018
|
const account = await this.withCodex(() => this.codex.accountRead({ refreshToken: false }));
|
|
26677
27019
|
if (!onGateway && account.requiresOpenaiAuth && account.account === null) {
|
|
26678
27020
|
throw RequestError.authRequired(undefined, "Log in to Codex first (auth/login)");
|
|
26679
27021
|
}
|
|
26680
27022
|
const existingMcp = mcpServers.length > 0 ? await this.withCodex(() => this.configuredMcpServerNames(request.cwd)) : new Set;
|
|
26681
|
-
const config2 = buildThreadConfig(this.providers.threadConfig(
|
|
27023
|
+
const config2 = buildThreadConfig(this.providers.threadConfig(gatewayId), request.cwd, additionalDirectories, mcpServers, existingMcp);
|
|
26682
27024
|
const mcpStartupGeneration = this.codex.mcpStartupGeneration;
|
|
26683
|
-
const modelProvider =
|
|
26684
|
-
const startModel = onGateway ? requestedModel ?? this.providers.
|
|
27025
|
+
const modelProvider = gatewayId ?? await this.withCodex(() => this.resolveModelProvider());
|
|
27026
|
+
const startModel = this.providers.upstreamModel(onGateway ? requestedModel ?? this.providers.gateway(gatewayId)?.model ?? null : requestedModel);
|
|
26685
27027
|
let readOnly = false;
|
|
26686
27028
|
const { thread, skills } = await this.withSkillsContext(request.cwd, additionalDirectories, async (skills2) => ({ skills: skills2, thread: await this.withCodex(async () => {
|
|
26687
27029
|
if (signal?.aborted)
|
|
26688
27030
|
throw RequestError.requestCancelled(undefined, "Session opening was cancelled");
|
|
26689
27031
|
switch (open2.kind) {
|
|
26690
27032
|
case "new":
|
|
26691
|
-
return await this.codex.threadStart({
|
|
27033
|
+
return await this.codex.threadStart({
|
|
27034
|
+
...hostThreadOptions,
|
|
27035
|
+
config: config2,
|
|
27036
|
+
cwd: request.cwd,
|
|
27037
|
+
modelProvider,
|
|
27038
|
+
model: startModel,
|
|
27039
|
+
...clientTools ? { dynamicTools: dynamicTools(clientTools) } : {}
|
|
27040
|
+
});
|
|
26692
27041
|
case "resume":
|
|
26693
27042
|
try {
|
|
26694
|
-
return await this.codex.threadResume({ threadId: open2.request.sessionId, config: config2, cwd: request.cwd, modelProvider, model: startModel, excludeTurns: true });
|
|
27043
|
+
return await this.codex.threadResume({ ...hostThreadOptions, threadId: open2.request.sessionId, config: config2, cwd: request.cwd, modelProvider, model: startModel, excludeTurns: true });
|
|
26695
27044
|
} catch (error40) {
|
|
26696
27045
|
if (!errorMessage(error40).includes("already has an active writer"))
|
|
26697
27046
|
throw error40;
|
|
@@ -26699,7 +27048,7 @@ class CodexAgent {
|
|
|
26699
27048
|
return readOnlyThread((await this.codex.threadRead({ threadId: open2.request.sessionId, includeTurns: false })).thread, request.cwd);
|
|
26700
27049
|
}
|
|
26701
27050
|
case "fork":
|
|
26702
|
-
return await this.codex.threadFork({ threadId: open2.request.sessionId, config: config2, cwd: request.cwd, modelProvider, model: startModel, excludeTurns: true });
|
|
27051
|
+
return await this.codex.threadFork({ ...hostThreadOptions, threadId: open2.request.sessionId, config: config2, cwd: request.cwd, modelProvider, model: startModel, excludeTurns: true });
|
|
26703
27052
|
}
|
|
26704
27053
|
}) }));
|
|
26705
27054
|
const sessionId = thread.thread.id;
|
|
@@ -26728,16 +27077,17 @@ class CodexAgent {
|
|
|
26728
27077
|
openedAccount = (await this.withCodex(() => this.codex.accountRead({ refreshToken: false }))).account;
|
|
26729
27078
|
}
|
|
26730
27079
|
const catalog = this.providers.catalog(codexCatalog);
|
|
26731
|
-
const model = resolveModelSelection(catalog, startModel ?? thread.model, thread.reasoningEffort);
|
|
27080
|
+
const model = resolveModelSelection(catalog, this.providers.selectionId(startModel ?? thread.model, gatewayId ?? thread.modelProvider), thread.reasoningEffort);
|
|
26732
27081
|
const session = {
|
|
27082
|
+
...clientTools ? { clientTools } : {},
|
|
26733
27083
|
id: sessionId,
|
|
26734
27084
|
cwd: request.cwd,
|
|
26735
27085
|
additionalDirectories,
|
|
26736
27086
|
mcpServerNames: mcpServerNames(mcpServers).filter((name) => !existingMcp.has(name)),
|
|
26737
27087
|
catalog,
|
|
26738
|
-
|
|
27088
|
+
gatewayGroups: this.providers.gatewayGroups(),
|
|
26739
27089
|
model,
|
|
26740
|
-
mode
|
|
27090
|
+
mode,
|
|
26741
27091
|
collaborationMode: DEFAULT_COLLABORATION_MODE,
|
|
26742
27092
|
fastMode: thread.serviceTier === FAST_SERVICE_TIER,
|
|
26743
27093
|
account: openedAccount,
|
|
@@ -26748,7 +27098,7 @@ class CodexAgent {
|
|
|
26748
27098
|
contextWindow: null,
|
|
26749
27099
|
closed: false
|
|
26750
27100
|
};
|
|
26751
|
-
const runtime = this.installRuntime(session, capabilities, config2,
|
|
27101
|
+
const runtime = this.installRuntime(session, capabilities, config2, gatewayId ?? thread.modelProvider, readOnly);
|
|
26752
27102
|
const cancelOpening = () => {
|
|
26753
27103
|
runtime.session.closed = true;
|
|
26754
27104
|
runtime.lifetime.abort();
|
|
@@ -26806,11 +27156,13 @@ class CodexAgent {
|
|
|
26806
27156
|
const approval = new CodexApprovalHandler(client, turnContext, signal);
|
|
26807
27157
|
const elicitation = new CodexElicitationHandler(client, turnContext, signal);
|
|
26808
27158
|
const runtime = { config: config2, modelProvider, stale: false, readOnly, session, client, bridge, turnContext, elicitation, lifetime: new AbortController, queue: Promise.resolve() };
|
|
27159
|
+
const tools = new ClientTools(session, client, AbortSignal.any([runtime.lifetime.signal, this.codex.disconnectSignal]));
|
|
26809
27160
|
const drained = (operation) => async (params) => {
|
|
26810
27161
|
await abortable(this.drain(runtime), this.codex.disconnectSignal);
|
|
26811
27162
|
return await operation(params);
|
|
26812
27163
|
};
|
|
26813
27164
|
this.codex.attachThread(session.id, {
|
|
27165
|
+
tool: (params) => tools.call(params),
|
|
26814
27166
|
notification: (notification) => this.enqueue(runtime, notification),
|
|
26815
27167
|
approval: {
|
|
26816
27168
|
handleCommandExecution: drained((params) => approval.handleCommandExecution(params)),
|
|
@@ -26914,8 +27266,8 @@ class CodexAgent {
|
|
|
26914
27266
|
const result = await this.codex.awaitMcpStartup(runtime.session.mcpServerNames, afterGeneration, runtime.lifetime.signal, runtime.session.id);
|
|
26915
27267
|
if (runtime.session.closed)
|
|
26916
27268
|
return;
|
|
26917
|
-
for (const
|
|
26918
|
-
await runtime.client.update(mcpStartupFailed(
|
|
27269
|
+
for (const failure2 of result.failed) {
|
|
27270
|
+
await runtime.client.update(mcpStartupFailed(failure2.server, `MCP server "${failure2.server}" failed to start: ${failure2.error}`));
|
|
26919
27271
|
}
|
|
26920
27272
|
for (const server of result.cancelled) {
|
|
26921
27273
|
await runtime.client.update(mcpStartupFailed(server, `MCP server "${server}" startup was cancelled.`));
|
|
@@ -27046,6 +27398,27 @@ class CodexAgent {
|
|
|
27046
27398
|
notifySkillsChanged() {
|
|
27047
27399
|
this.link.notify("_codex/skills_changed", {}).catch((error40) => logger.error("skills change notification failed", error40));
|
|
27048
27400
|
}
|
|
27401
|
+
forward(method, params) {
|
|
27402
|
+
this.link.notify(method, params).catch((error40) => logger.error(`${method} notification failed`, error40));
|
|
27403
|
+
}
|
|
27404
|
+
async sessionRename(params) {
|
|
27405
|
+
this.requireInitialized("_codex/session_rename");
|
|
27406
|
+
await this.withCodex(() => this.codex.threadSetName({ threadId: params.sessionId, name: params.name }));
|
|
27407
|
+
return {};
|
|
27408
|
+
}
|
|
27409
|
+
async accountRead() {
|
|
27410
|
+
this.requireInitialized("_codex/account_read");
|
|
27411
|
+
return await this.withCodex(() => this.codex.accountRead({ refreshToken: false }));
|
|
27412
|
+
}
|
|
27413
|
+
async rateLimits() {
|
|
27414
|
+
this.requireInitialized("_codex/rate_limits");
|
|
27415
|
+
return await this.withCodex(() => this.codex.accountRateLimitsRead());
|
|
27416
|
+
}
|
|
27417
|
+
async fuzzyFileSearch(params) {
|
|
27418
|
+
this.requireInitialized("_codex/fuzzy_file_search");
|
|
27419
|
+
const request = { query: params.query, roots: params.roots, cancellationToken: params.cancellationToken };
|
|
27420
|
+
return await this.withCodex(() => this.codex.fuzzyFileSearch(request));
|
|
27421
|
+
}
|
|
27049
27422
|
async closeRuntime(sessionId) {
|
|
27050
27423
|
const deadline = performance.now() + this.closeGraceMs;
|
|
27051
27424
|
const runtime = this.sessions.get(sessionId);
|
|
@@ -27102,17 +27475,19 @@ class CodexAgent {
|
|
|
27102
27475
|
async setSessionConfigOptionInternal(params) {
|
|
27103
27476
|
const runtime = this.runtime(params.sessionId, "session/set_config_option");
|
|
27104
27477
|
assertWritable(runtime);
|
|
27105
|
-
if (params.configId === MODEL_CONFIG_ID && this.providers.mode === "catalog" && typeof params.value === "string") {
|
|
27106
|
-
|
|
27107
|
-
|
|
27108
|
-
|
|
27478
|
+
if (params.configId === MODEL_CONFIG_ID && (this.providers.mode === "catalog" || runtime.session.model.model.startsWith("gateway:")) && typeof params.value === "string") {
|
|
27479
|
+
this.providers.upstreamModel(params.value);
|
|
27480
|
+
const target = this.providers.gatewayIdFor(params.value);
|
|
27481
|
+
const destination = target ?? await this.withCodex(() => this.resolveModelProvider());
|
|
27482
|
+
if (destination !== runtime.modelProvider)
|
|
27483
|
+
await this.rerouteSession(runtime, target, params.value);
|
|
27109
27484
|
}
|
|
27110
27485
|
await this.withCodex(() => applyConfigOption(runtime.session, this.codex, params));
|
|
27111
27486
|
const configOptions = sessionConfigOptions(runtime.session);
|
|
27112
27487
|
await runtime.client.update({ sessionUpdate: "config_option_update", configOptions });
|
|
27113
27488
|
return { configOptions };
|
|
27114
27489
|
}
|
|
27115
|
-
async rerouteSession(runtime,
|
|
27490
|
+
async rerouteSession(runtime, gatewayId, modelId) {
|
|
27116
27491
|
const { session } = runtime;
|
|
27117
27492
|
this.assertRoutingAvailable();
|
|
27118
27493
|
if (session.activeTurn !== null) {
|
|
@@ -27123,19 +27498,19 @@ class CodexAgent {
|
|
|
27123
27498
|
} catch {
|
|
27124
27499
|
await this.withCodex(() => this.codex.threadInjectItems({ threadId: session.id, items: [providerChangeNote()] }));
|
|
27125
27500
|
}
|
|
27126
|
-
const config2 = this.providers.routeConfig(runtime.config,
|
|
27127
|
-
const modelProvider =
|
|
27501
|
+
const config2 = this.providers.routeConfig(runtime.config, gatewayId);
|
|
27502
|
+
const modelProvider = gatewayId ?? await this.withCodex(() => this.resolveModelProvider());
|
|
27128
27503
|
await this.codex.threadUnsubscribe({ threadId: session.id });
|
|
27129
27504
|
try {
|
|
27130
|
-
await this.withCodex(() => this.codex.threadResume({ threadId: session.id, cwd: session.cwd, config: config2, modelProvider, model: modelId, excludeTurns: true }));
|
|
27505
|
+
await this.withCodex(() => this.codex.threadResume({ threadId: session.id, cwd: session.cwd, config: config2, modelProvider, model: this.providers.upstreamModel(modelId), excludeTurns: true }));
|
|
27131
27506
|
} catch (error40) {
|
|
27132
27507
|
try {
|
|
27133
|
-
await this.codex.threadResume({ threadId: session.id, cwd: session.cwd, config: runtime.config, modelProvider: runtime.modelProvider, model: session.model.model, excludeTurns: true });
|
|
27508
|
+
await this.codex.threadResume({ threadId: session.id, cwd: session.cwd, config: runtime.config, modelProvider: runtime.modelProvider, model: this.providers.upstreamModel(session.model.model), excludeTurns: true });
|
|
27134
27509
|
} catch (rollbackError) {
|
|
27135
27510
|
runtime.stale = true;
|
|
27136
27511
|
logger.error("Provider rollback failed", rollbackError, { sessionId: session.id });
|
|
27137
27512
|
}
|
|
27138
|
-
throw RequestError.internalError({ sessionId: session.id, stale: runtime.stale }, `Could not move the session to ${
|
|
27513
|
+
throw RequestError.internalError({ sessionId: session.id, stale: runtime.stale }, `Could not move the session to ${gatewayId !== null ? `gateway "${gatewayId}"` : "Codex's provider"}: ${errorMessage(error40)}`);
|
|
27139
27514
|
}
|
|
27140
27515
|
runtime.config = config2;
|
|
27141
27516
|
runtime.modelProvider = modelProvider;
|
|
@@ -27149,9 +27524,9 @@ class CodexAgent {
|
|
|
27149
27524
|
return runtime;
|
|
27150
27525
|
}
|
|
27151
27526
|
async prompt(params) {
|
|
27152
|
-
return await this.promptInternal(params);
|
|
27527
|
+
return await this.promptInternal(params, false, crypto.randomUUID());
|
|
27153
27528
|
}
|
|
27154
|
-
async promptInternal(params, allowReentry
|
|
27529
|
+
async promptInternal(params, allowReentry, messageId) {
|
|
27155
27530
|
this.assertRoutingAvailable();
|
|
27156
27531
|
if (!allowReentry && this.sessionMutations.has(params.sessionId))
|
|
27157
27532
|
throw RequestError.invalidRequest({ sessionId: params.sessionId }, "Session lifecycle or configuration work is in progress; retry when it finishes");
|
|
@@ -27163,31 +27538,32 @@ class CodexAgent {
|
|
|
27163
27538
|
throw RequestError.invalidParams(undefined, "prompt must contain at least one content block");
|
|
27164
27539
|
}
|
|
27165
27540
|
const { session } = runtime;
|
|
27541
|
+
this.providers.upstreamModel(session.model.model);
|
|
27166
27542
|
const model = findModel(session.catalog, session.model.model);
|
|
27167
27543
|
if (!modelSupportsImages(model) && params.prompt.some((block) => block.type === "image")) {
|
|
27168
27544
|
throw RequestError.invalidParams({ model: session.model.model }, "The current model does not support image input");
|
|
27169
27545
|
}
|
|
27170
27546
|
if (session.activeTurn) {
|
|
27171
|
-
return await this.steerActiveTurn(runtime, session.activeTurn, params);
|
|
27547
|
+
return await this.steerActiveTurn(runtime, session.activeTurn, params, messageId);
|
|
27172
27548
|
}
|
|
27173
|
-
const turn = createActiveTurn(session.id);
|
|
27549
|
+
const turn = createActiveTurn(session.id, messageId);
|
|
27174
27550
|
session.activeTurn = turn;
|
|
27175
27551
|
runtime.client.reportRunning();
|
|
27176
27552
|
this.runPrompt(runtime, turn, params);
|
|
27177
|
-
return {};
|
|
27553
|
+
return { messageId };
|
|
27178
27554
|
}
|
|
27179
|
-
async steerActiveTurn(runtime, turn, params) {
|
|
27555
|
+
async steerActiveTurn(runtime, turn, params, messageId) {
|
|
27180
27556
|
const turnId = turn.turnId ?? await turn.started;
|
|
27181
27557
|
if (turnId === null || turn.threadId !== runtime.session.id) {
|
|
27182
27558
|
throw RequestError.invalidRequest({ sessionId: params.sessionId }, "A turn is already running; wait for it to finish or cancel it");
|
|
27183
27559
|
}
|
|
27184
27560
|
try {
|
|
27185
|
-
await this.codex.turnSteer({ threadId: runtime.session.id, expectedTurnId: turnId, input: toUserInput(params.prompt) });
|
|
27186
|
-
return { _meta: { codex: { steered: turnId } } };
|
|
27561
|
+
await this.codex.turnSteer({ threadId: runtime.session.id, expectedTurnId: turnId, clientUserMessageId: messageId, input: toUserInput(params.prompt) });
|
|
27562
|
+
return { messageId, _meta: { codex: { steered: turnId } } };
|
|
27187
27563
|
} catch (error40) {
|
|
27188
27564
|
if (this.completedTurns.get(turn) === turnId || runtime.session.activeTurn !== turn) {
|
|
27189
27565
|
await turn.finished;
|
|
27190
|
-
return await this.promptInternal(params, true);
|
|
27566
|
+
return await this.promptInternal(params, true, messageId);
|
|
27191
27567
|
}
|
|
27192
27568
|
throw RequestError.invalidRequest({ sessionId: params.sessionId, turnId }, `Could not steer the running turn: ${errorMessage(error40)}`);
|
|
27193
27569
|
}
|
|
@@ -27292,11 +27668,12 @@ class CodexAgent {
|
|
|
27292
27668
|
startSent = true;
|
|
27293
27669
|
const completed = this.withCodex(() => this.codex.runTurn({
|
|
27294
27670
|
threadId: session.id,
|
|
27671
|
+
clientUserMessageId: turn.clientUserMessageId,
|
|
27295
27672
|
input: toUserInput(prompt),
|
|
27296
27673
|
approvalPolicy: session.mode.approvalPolicy,
|
|
27297
27674
|
approvalsReviewer: session.mode.approvalsReviewer,
|
|
27298
27675
|
sandboxPolicy: withWritableRoots(session.mode.sandboxPolicy, session.additionalDirectories),
|
|
27299
|
-
model: session.model.model,
|
|
27676
|
+
model: this.providers.upstreamModel(session.model.model),
|
|
27300
27677
|
effort: session.model.effort,
|
|
27301
27678
|
summary: disableSummary ? "none" : "auto",
|
|
27302
27679
|
serviceTier: session.fastMode ? FAST_SERVICE_TIER : null
|
|
@@ -27592,6 +27969,28 @@ function interruptedTurn(threadId) {
|
|
|
27592
27969
|
turn: { id: "", items: [], itemsView: "notLoaded", status: "interrupted", error: null, startedAt: null, completedAt: null, durationMs: null }
|
|
27593
27970
|
};
|
|
27594
27971
|
}
|
|
27972
|
+
function parseSessionRenameParams(raw) {
|
|
27973
|
+
const params = objectParams()(raw);
|
|
27974
|
+
if (typeof params.sessionId !== "string" || params.sessionId.length === 0) {
|
|
27975
|
+
throw RequestError.invalidParams({ sessionId: params.sessionId }, "sessionId must be a non-empty string");
|
|
27976
|
+
}
|
|
27977
|
+
if (typeof params.name !== "string")
|
|
27978
|
+
throw RequestError.invalidParams({ name: params.name }, "name must be a string");
|
|
27979
|
+
return { sessionId: params.sessionId, name: params.name };
|
|
27980
|
+
}
|
|
27981
|
+
function parseFuzzyFileSearchParams(raw) {
|
|
27982
|
+
const params = objectParams()(raw);
|
|
27983
|
+
if (typeof params.query !== "string")
|
|
27984
|
+
throw RequestError.invalidParams({ query: params.query }, "query must be a string");
|
|
27985
|
+
if (!Array.isArray(params.roots) || !params.roots.every((root) => typeof root === "string")) {
|
|
27986
|
+
throw RequestError.invalidParams({ roots: params.roots }, "roots must be an array of directory paths");
|
|
27987
|
+
}
|
|
27988
|
+
const token = params.cancellationToken;
|
|
27989
|
+
if (token !== undefined && token !== null && typeof token !== "string") {
|
|
27990
|
+
throw RequestError.invalidParams({ cancellationToken: token }, "cancellationToken must be a string when given");
|
|
27991
|
+
}
|
|
27992
|
+
return { query: params.query, roots: params.roots, cancellationToken: typeof token === "string" ? token : null };
|
|
27993
|
+
}
|
|
27595
27994
|
function objectParams() {
|
|
27596
27995
|
return (raw) => {
|
|
27597
27996
|
if (raw === undefined || raw === null)
|
|
@@ -27637,6 +28036,17 @@ function readOnlyThread(thread, cwd) {
|
|
|
27637
28036
|
itemsBackwardsCursor: null
|
|
27638
28037
|
};
|
|
27639
28038
|
}
|
|
28039
|
+
function hostSessionOptions(meta) {
|
|
28040
|
+
const instructions = meta?.alwith?.appendSystemPrompt;
|
|
28041
|
+
if (instructions !== undefined && typeof instructions !== "string") {
|
|
28042
|
+
throw RequestError.invalidParams(undefined, "appendSystemPrompt must be a string");
|
|
28043
|
+
}
|
|
28044
|
+
const modeId = meta?.codex?.mode;
|
|
28045
|
+
const mode = typeof modeId === "string" ? findAgentMode(modeId) : undefined;
|
|
28046
|
+
if (modeId !== undefined && !mode)
|
|
28047
|
+
throw RequestError.invalidParams(undefined, "Unknown Codex session mode");
|
|
28048
|
+
return { instructions, mode };
|
|
28049
|
+
}
|
|
27640
28050
|
function requestedModelOf(meta) {
|
|
27641
28051
|
const raw = meta?.alwith?.model;
|
|
27642
28052
|
return typeof raw === "string" && raw.length > 0 ? raw : null;
|
|
@@ -27687,7 +28097,7 @@ function createAgentApp(options) {
|
|
|
27687
28097
|
};
|
|
27688
28098
|
return agent({ name: options.info.name }).onConnect((connection) => {
|
|
27689
28099
|
agent2 = new CodexAgent(connection.client, options);
|
|
27690
|
-
}).onRequest(methods.agent.initialize, (ctx) => current().initialize(ctx.params)).onRequest(methods.agent.auth.login, (ctx) => current().login(ctx.params, ctx.requestId)).onRequest(methods.agent.auth.logout, (ctx) => current().logout(ctx.params)).onRequest(methods.agent.providers.list, (ctx) => current().listProviders(ctx.params)).onRequest(methods.agent.providers.set, (ctx) => current().setProvider(ctx.params)).onRequest(methods.agent.providers.disable, (ctx) => current().disableProvider(ctx.params)).onRequest(methods.agent.session.new, (ctx) => current().newSession(ctx.params, ctx.signal)).onRequest(methods.agent.session.resume, (ctx) => current().resumeSession(ctx.params, ctx.signal)).onRequest(methods.agent.session.fork, (ctx) => current().forkSession(ctx.params, ctx.signal)).onRequest(methods.agent.session.list, (ctx) => current().listSessions(ctx.params)).onRequest(methods.agent.session.close, (ctx) => current().closeSession(ctx.params)).onRequest(methods.agent.session.delete, (ctx) => current().deleteSession(ctx.params)).onRequest("_codex/session_archive", { parse: parseSessionIdParams }, (ctx) => current().archiveSession(ctx.params)).onRequest("_codex/session_unarchive", { parse: parseSessionIdParams }, (ctx) => current().unarchiveSession(ctx.params)).onRequest("_codex/skills_list", { parse: objectParams() }, (ctx) => current().skillsList(ctx.params)).onRequest("_codex/skills_config_write", { parse: objectParams() }, (ctx) => current().skillsConfigWrite(ctx.params)).onRequest("_codex/plugin_list", { parse: objectParams() }, (ctx) => current().pluginList(ctx.params)).onRequest("_codex/plugin_installed", { parse: objectParams() }, (ctx) => current().pluginInstalled(ctx.params)).onRequest("_codex/plugin_install", { parse: objectParams() }, (ctx) => current().pluginInstall(ctx.params)).onRequest("_codex/plugin_uninstall", { parse: objectParams() }, (ctx) => current().pluginUninstall(ctx.params)).onRequest("_codex/plugin_read", { parse: objectParams() }, (ctx) => current().pluginRead(ctx.params)).onRequest("_codex/marketplace_add", { parse: objectParams() }, (ctx) => current().marketplaceAdd(ctx.params)).onRequest("_codex/marketplace_remove", { parse: objectParams() }, (ctx) => current().marketplaceRemove(ctx.params)).onRequest("_codex/marketplace_upgrade", { parse: objectParams() }, (ctx) => current().marketplaceUpgrade(ctx.params)).onRequest(methods.agent.session.setConfigOption, (ctx) => current().setSessionConfigOption(ctx.params)).onRequest(methods.agent.session.prompt, (ctx) => current().prompt(ctx.params)).onNotification(methods.agent.session.cancel, (ctx) => current().cancel(ctx.params));
|
|
28100
|
+
}).onRequest(methods.agent.initialize, (ctx) => current().initialize(ctx.params)).onRequest(methods.agent.auth.login, (ctx) => current().login(ctx.params, ctx.requestId)).onRequest(methods.agent.auth.logout, (ctx) => current().logout(ctx.params)).onRequest(methods.agent.providers.list, (ctx) => current().listProviders(ctx.params)).onRequest(methods.agent.providers.set, (ctx) => current().setProvider(ctx.params)).onRequest(methods.agent.providers.disable, (ctx) => current().disableProvider(ctx.params)).onRequest(methods.agent.session.new, (ctx) => current().newSession(ctx.params, ctx.signal)).onRequest(methods.agent.session.resume, (ctx) => current().resumeSession(ctx.params, ctx.signal)).onRequest(methods.agent.session.fork, (ctx) => current().forkSession(ctx.params, ctx.signal)).onRequest(methods.agent.session.list, (ctx) => current().listSessions(ctx.params)).onRequest(methods.agent.session.close, (ctx) => current().closeSession(ctx.params)).onRequest(methods.agent.session.delete, (ctx) => current().deleteSession(ctx.params)).onRequest("_codex/session_archive", { parse: parseSessionIdParams }, (ctx) => current().archiveSession(ctx.params)).onRequest("_codex/session_unarchive", { parse: parseSessionIdParams }, (ctx) => current().unarchiveSession(ctx.params)).onRequest("_codex/skills_list", { parse: objectParams() }, (ctx) => current().skillsList(ctx.params)).onRequest("_codex/skills_config_write", { parse: objectParams() }, (ctx) => current().skillsConfigWrite(ctx.params)).onRequest("_codex/plugin_list", { parse: objectParams() }, (ctx) => current().pluginList(ctx.params)).onRequest("_codex/plugin_installed", { parse: objectParams() }, (ctx) => current().pluginInstalled(ctx.params)).onRequest("_codex/plugin_install", { parse: objectParams() }, (ctx) => current().pluginInstall(ctx.params)).onRequest("_codex/plugin_uninstall", { parse: objectParams() }, (ctx) => current().pluginUninstall(ctx.params)).onRequest("_codex/plugin_read", { parse: objectParams() }, (ctx) => current().pluginRead(ctx.params)).onRequest("_codex/marketplace_add", { parse: objectParams() }, (ctx) => current().marketplaceAdd(ctx.params)).onRequest("_codex/marketplace_remove", { parse: objectParams() }, (ctx) => current().marketplaceRemove(ctx.params)).onRequest("_codex/marketplace_upgrade", { parse: objectParams() }, (ctx) => current().marketplaceUpgrade(ctx.params)).onRequest("_codex/session_rename", { parse: parseSessionRenameParams }, (ctx) => current().sessionRename(ctx.params)).onRequest("_codex/account_read", { parse: objectParams() }, () => current().accountRead()).onRequest("_codex/rate_limits", { parse: objectParams() }, () => current().rateLimits()).onRequest("_codex/fuzzy_file_search", { parse: parseFuzzyFileSearchParams }, (ctx) => current().fuzzyFileSearch(ctx.params)).onRequest(methods.agent.session.setConfigOption, (ctx) => current().setSessionConfigOption(ctx.params)).onRequest(methods.agent.session.prompt, (ctx) => current().prompt(ctx.params)).onNotification(methods.agent.session.cancel, (ctx) => current().cancel(ctx.params));
|
|
27691
28101
|
}
|
|
27692
28102
|
|
|
27693
28103
|
// src/codex/AppServerClient.ts
|
|
@@ -27697,12 +28107,14 @@ var FileChangeApprovalRequest = new import_node.RequestType("item/fileChange/req
|
|
|
27697
28107
|
var PermissionsApprovalRequest = new import_node.RequestType("item/permissions/requestApproval");
|
|
27698
28108
|
var McpServerElicitationRequest = new import_node.RequestType("mcpServer/elicitation/request");
|
|
27699
28109
|
var ToolRequestUserInputRequest = new import_node.RequestType("item/tool/requestUserInput");
|
|
28110
|
+
var DynamicToolCallRequest = new import_node.RequestType("item/tool/call");
|
|
27700
28111
|
|
|
27701
28112
|
class AppServerClient {
|
|
27702
28113
|
connection;
|
|
27703
28114
|
threadHandlers = new Map;
|
|
27704
28115
|
approvalHandlers = new Map;
|
|
27705
28116
|
elicitationHandlers = new Map;
|
|
28117
|
+
dynamicToolHandlers = new Map;
|
|
27706
28118
|
turnCompletionWaiters = new Map;
|
|
27707
28119
|
earlyTurnCompletions = new Map;
|
|
27708
28120
|
startingThreads = new Map;
|
|
@@ -27715,6 +28127,10 @@ class AppServerClient {
|
|
|
27715
28127
|
disconnected = new AbortController;
|
|
27716
28128
|
constructor(connection) {
|
|
27717
28129
|
this.connection = connection;
|
|
28130
|
+
connection.onRequest(DynamicToolCallRequest, async (params) => {
|
|
28131
|
+
const handler = this.dynamicToolHandlers.get(params.threadId);
|
|
28132
|
+
return handler ? await handler(params) : { success: false, contentItems: [{ type: "inputText", text: "Client tools are unavailable for this thread" }] };
|
|
28133
|
+
});
|
|
27718
28134
|
connection.onClose(() => this.disconnected.abort(new Error("Connection to Codex was lost")));
|
|
27719
28135
|
connection.onDispose(() => this.disconnected.abort(new Error("Connection to Codex was lost")));
|
|
27720
28136
|
connection.onUnhandledNotification((message) => {
|
|
@@ -27748,11 +28164,14 @@ class AppServerClient {
|
|
|
27748
28164
|
this.threadHandlers.set(threadId, handlers.notification);
|
|
27749
28165
|
this.approvalHandlers.set(threadId, handlers.approval);
|
|
27750
28166
|
this.elicitationHandlers.set(threadId, handlers.elicitation);
|
|
28167
|
+
if (handlers.tool)
|
|
28168
|
+
this.dynamicToolHandlers.set(threadId, handlers.tool);
|
|
27751
28169
|
}
|
|
27752
28170
|
detachThread(threadId) {
|
|
27753
28171
|
this.threadHandlers.delete(threadId);
|
|
27754
28172
|
this.approvalHandlers.delete(threadId);
|
|
27755
28173
|
this.elicitationHandlers.delete(threadId);
|
|
28174
|
+
this.dynamicToolHandlers.delete(threadId);
|
|
27756
28175
|
for (const key of this.mcpStartupStates.keys()) {
|
|
27757
28176
|
if (key.startsWith(`${threadId}\x00`))
|
|
27758
28177
|
this.mcpStartupStates.delete(key);
|
|
@@ -28100,6 +28519,15 @@ class AppServerClient {
|
|
|
28100
28519
|
accountRead(params) {
|
|
28101
28520
|
return this.send({ method: "account/read", params });
|
|
28102
28521
|
}
|
|
28522
|
+
accountRateLimitsRead() {
|
|
28523
|
+
return this.send({ method: "account/rateLimits/read", params: undefined });
|
|
28524
|
+
}
|
|
28525
|
+
threadSetName(params) {
|
|
28526
|
+
return this.send({ method: "thread/name/set", params });
|
|
28527
|
+
}
|
|
28528
|
+
fuzzyFileSearch(params) {
|
|
28529
|
+
return this.send({ method: "fuzzyFileSearch", params });
|
|
28530
|
+
}
|
|
28103
28531
|
accountLogin(params) {
|
|
28104
28532
|
return this.send({ method: "account/login/start", params });
|
|
28105
28533
|
}
|