@nyssance/codex-acp-v2 0.6.0 → 0.7.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 +19 -0
- package/README.md +1 -1
- package/dist/index.js +427 -119
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.1 — 2026-09-29
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Generated against Codex 0.158.0 (`@openai/codex` `^0.158.0`); the version floor follows.
|
|
8
|
+
- MCP `openai/userVerification` elicitations (signed device challenges) are declined with
|
|
9
|
+
`cancelled`: ACP has no surface for them and enrollment stays inside Codex.
|
|
10
|
+
- `codexErrorInfo` `flexUnavailable` classifies as `flex_unavailable`, retryable.
|
|
11
|
+
- Replayed `image` user input renders `image:<fileId>` when Codex stored an uploaded file
|
|
12
|
+
instead of a URL.
|
|
13
|
+
|
|
14
|
+
## 0.7.0 — 2026-09-29
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- `session/prompt` returns `{messageId}` (ACP v2, sdk 1.5.1). The id is passed to Codex as
|
|
19
|
+
`clientUserMessageId`; `user_message` echoes and replays report it as `messageId`
|
|
20
|
+
(`userMessage.clientId ?? id`). Steering returns `{messageId, _meta.codex.steered}`.
|
|
21
|
+
|
|
3
22
|
## 0.6.0 — 2026-09-11
|
|
4
23
|
|
|
5
24
|
### Added
|
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ See [`docs/protocol.md`](docs/protocol.md) for the exact wire contract.
|
|
|
59
59
|
|
|
60
60
|
## Requirements
|
|
61
61
|
|
|
62
|
-
- Codex CLI **0.
|
|
62
|
+
- Codex CLI **0.158.0 or newer** — the app-server types under `src/app-server` are generated
|
|
63
63
|
from the `@openai/codex` release named in `optionalDependencies`, and the agent checks
|
|
64
64
|
`codex --version` before starting the server; an older Codex fails at startup with an
|
|
65
65
|
upgrade hint.
|
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.1",
|
|
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,53 +21910,194 @@ 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"
|
|
21794
21917
|
},
|
|
21795
21918
|
optionalDependencies: {
|
|
21796
|
-
"@openai/codex": "^0.
|
|
21919
|
+
"@openai/codex": "^0.158.0"
|
|
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);
|
|
22087
|
+
case "flexUnavailable":
|
|
22088
|
+
return failure2("flex_unavailable", true);
|
|
21825
22089
|
case "internalServerError":
|
|
21826
|
-
return
|
|
22090
|
+
return failure2("internal", true);
|
|
21827
22091
|
case "unauthorized":
|
|
21828
|
-
return
|
|
22092
|
+
return failure2("authentication");
|
|
21829
22093
|
case "badRequest":
|
|
21830
|
-
return
|
|
22094
|
+
return failure2("invalid_request");
|
|
21831
22095
|
case "threadRollbackFailed":
|
|
21832
|
-
return
|
|
22096
|
+
return failure2("rollback");
|
|
21833
22097
|
case "sandboxError":
|
|
21834
|
-
return
|
|
22098
|
+
return failure2("sandbox");
|
|
21835
22099
|
case "other":
|
|
21836
|
-
return
|
|
22100
|
+
return failure2("unknown");
|
|
21837
22101
|
}
|
|
21838
22102
|
}
|
|
21839
22103
|
|
|
@@ -23294,7 +23558,7 @@ function fromUserInput(input) {
|
|
|
23294
23558
|
case "text":
|
|
23295
23559
|
return input.text.length > 0 ? [{ type: "text", text: input.text }] : [];
|
|
23296
23560
|
case "image":
|
|
23297
|
-
return [{ type: "text", text: formatUriAsLink("image", input.url) }];
|
|
23561
|
+
return [{ type: "text", text: "url" in input ? formatUriAsLink("image", input.url) : `image:${input.fileId}` }];
|
|
23298
23562
|
case "localImage":
|
|
23299
23563
|
return [{ type: "text", text: formatUriAsLink(null, toFileUri(input.path)) }];
|
|
23300
23564
|
case "skill":
|
|
@@ -23344,7 +23608,7 @@ function itemSnapshot(item) {
|
|
|
23344
23608
|
switch (item.type) {
|
|
23345
23609
|
case "userMessage": {
|
|
23346
23610
|
const content = item.content.flatMap(fromUserInput);
|
|
23347
|
-
return content.length > 0 ? [{ sessionUpdate: "user_message", messageId: item.id, content }] : [];
|
|
23611
|
+
return content.length > 0 ? [{ sessionUpdate: "user_message", messageId: item.clientId ?? item.id, content }] : [];
|
|
23348
23612
|
}
|
|
23349
23613
|
case "agentMessage":
|
|
23350
23614
|
return item.text.length > 0 ? [{
|
|
@@ -23642,6 +23906,8 @@ ${details}` : summary)];
|
|
|
23642
23906
|
case "mcpServer/event/stream/notification":
|
|
23643
23907
|
case "account/updated":
|
|
23644
23908
|
case "account/login/completed":
|
|
23909
|
+
case "account/gatewayOAuth/changed":
|
|
23910
|
+
case "thread/attachment/updated":
|
|
23645
23911
|
case "app/list/updated":
|
|
23646
23912
|
case "remoteControl/status/changed":
|
|
23647
23913
|
case "externalAgentConfig/import/progress":
|
|
@@ -23701,7 +23967,7 @@ ${details}` : summary)];
|
|
|
23701
23967
|
return [compactionUpdate(item.id, "in_progress")];
|
|
23702
23968
|
case "userMessage": {
|
|
23703
23969
|
const content = item.content.flatMap(fromUserInput);
|
|
23704
|
-
return content.length > 0 ? [{ sessionUpdate: "user_message", messageId: item.id, content }] : [];
|
|
23970
|
+
return content.length > 0 ? [{ sessionUpdate: "user_message", messageId: item.clientId ?? item.id, content }] : [];
|
|
23705
23971
|
}
|
|
23706
23972
|
case "hookPrompt":
|
|
23707
23973
|
case "functionCallOutput":
|
|
@@ -24630,6 +24896,10 @@ class CodexElicitationHandler {
|
|
|
24630
24896
|
}
|
|
24631
24897
|
async handleElicitation(params) {
|
|
24632
24898
|
try {
|
|
24899
|
+
if (params.mode === "openai/userVerification") {
|
|
24900
|
+
logger.log("MCP user verification is not supported over ACP", { server: params.serverName });
|
|
24901
|
+
return cancelled();
|
|
24902
|
+
}
|
|
24633
24903
|
const context = this.mcpContext(params);
|
|
24634
24904
|
const messageOnly = isMessageOnlyForm(params);
|
|
24635
24905
|
if (!messageOnly && this.useAcpElicitation(params)) {
|
|
@@ -24902,29 +25172,6 @@ class TurnContext {
|
|
|
24902
25172
|
}
|
|
24903
25173
|
}
|
|
24904
25174
|
|
|
24905
|
-
// src/util/abort.ts
|
|
24906
|
-
function abortable(operation, signal) {
|
|
24907
|
-
if (signal.aborted) {
|
|
24908
|
-
operation.catch(() => {});
|
|
24909
|
-
return Promise.reject(signal.reason);
|
|
24910
|
-
}
|
|
24911
|
-
return new Promise((resolve, reject) => {
|
|
24912
|
-
const abort = () => {
|
|
24913
|
-
cleanup();
|
|
24914
|
-
reject(signal.reason);
|
|
24915
|
-
};
|
|
24916
|
-
const cleanup = () => signal.removeEventListener("abort", abort);
|
|
24917
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
24918
|
-
operation.then((value) => {
|
|
24919
|
-
cleanup();
|
|
24920
|
-
resolve(value);
|
|
24921
|
-
}, (error40) => {
|
|
24922
|
-
cleanup();
|
|
24923
|
-
reject(error40);
|
|
24924
|
-
});
|
|
24925
|
-
});
|
|
24926
|
-
}
|
|
24927
|
-
|
|
24928
25175
|
// node_modules/open/index.js
|
|
24929
25176
|
import process10 from "process";
|
|
24930
25177
|
import path5 from "path";
|
|
@@ -25742,6 +25989,9 @@ class ClientSession {
|
|
|
25742
25989
|
return signal ? abortable(pending, signal) : pending;
|
|
25743
25990
|
}, signal);
|
|
25744
25991
|
}
|
|
25992
|
+
async requestTool(params, signal) {
|
|
25993
|
+
return await this.link.request("_alwith/tool/call", params, { cancellationSignal: signal });
|
|
25994
|
+
}
|
|
25745
25995
|
async createElicitation(request, signal) {
|
|
25746
25996
|
signal = signal ? AbortSignal.any([signal, this.output.signal]) : this.output.signal;
|
|
25747
25997
|
signal.throwIfAborted();
|
|
@@ -26021,7 +26271,7 @@ async function applyConfigOption(session, codex, request) {
|
|
|
26021
26271
|
threadId: session.id,
|
|
26022
26272
|
collaborationMode: {
|
|
26023
26273
|
mode,
|
|
26024
|
-
settings: { model: session.model.model, reasoning_effort: session.model.effort, developer_instructions: null }
|
|
26274
|
+
settings: { model: findModel(session.catalog, session.model.model)?.model ?? session.model.model, reasoning_effort: session.model.effort, developer_instructions: null }
|
|
26025
26275
|
}
|
|
26026
26276
|
});
|
|
26027
26277
|
session.collaborationMode = mode;
|
|
@@ -26077,6 +26327,9 @@ var OPENAI_PROVIDER_ID = "openai";
|
|
|
26077
26327
|
var GATEWAY_MODEL_PROVIDER = "custom-gateway";
|
|
26078
26328
|
var DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
26079
26329
|
var GATEWAY_ID_PATTERN = /^[a-z0-9-]+$/;
|
|
26330
|
+
function gatewayModelId(connectionId, modelId) {
|
|
26331
|
+
return `gateway:${encodeURIComponent(connectionId)}:${encodeURIComponent(modelId)}`;
|
|
26332
|
+
}
|
|
26080
26333
|
|
|
26081
26334
|
class ProviderRouting {
|
|
26082
26335
|
baseConfig;
|
|
@@ -26131,14 +26384,6 @@ class ProviderRouting {
|
|
|
26131
26384
|
}
|
|
26132
26385
|
if (hints.mode === "route" || this.mode !== hints.mode)
|
|
26133
26386
|
this.gateways.clear();
|
|
26134
|
-
for (const other of this.gateways.values()) {
|
|
26135
|
-
if (other.id === hints.id)
|
|
26136
|
-
continue;
|
|
26137
|
-
const duplicate = hints.models.find((model) => other.models.some((candidate) => candidate.id === model.id));
|
|
26138
|
-
if (duplicate) {
|
|
26139
|
-
throw RequestError.invalidParams({ id: hints.id, model: duplicate.id }, `Model "${duplicate.id}" is already served by gateway "${other.id}"; model ids must be unique across gateways`);
|
|
26140
|
-
}
|
|
26141
|
-
}
|
|
26142
26387
|
this.gateways.set(hints.id, {
|
|
26143
26388
|
id: hints.id,
|
|
26144
26389
|
baseUrl,
|
|
@@ -26157,7 +26402,7 @@ class ProviderRouting {
|
|
|
26157
26402
|
}
|
|
26158
26403
|
gatewayFor(modelId) {
|
|
26159
26404
|
for (const gateway of this.gateways.values()) {
|
|
26160
|
-
if (gateway.models.some((model) => model.id === modelId))
|
|
26405
|
+
if (gateway.models.some((model) => (this.mode === "catalog" ? gatewayModelId(gateway.id, model.id) : model.id) === modelId))
|
|
26161
26406
|
return gateway;
|
|
26162
26407
|
}
|
|
26163
26408
|
return null;
|
|
@@ -26171,7 +26416,19 @@ class ProviderRouting {
|
|
|
26171
26416
|
gatewayGroups() {
|
|
26172
26417
|
if (this.mode !== "catalog")
|
|
26173
26418
|
return [];
|
|
26174
|
-
return [...this.gateways.values()].filter((gateway) => gateway.models.length > 0).map((gateway) => ({ id: gateway.id, name: gateway.name, modelIds: gateway.models.map((model) => model.id) }));
|
|
26419
|
+
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)) }));
|
|
26420
|
+
}
|
|
26421
|
+
selectionId(modelId, provider) {
|
|
26422
|
+
return modelId !== null && this.mode === "catalog" && this.hasGateway(provider) ? gatewayModelId(provider, modelId) : modelId;
|
|
26423
|
+
}
|
|
26424
|
+
upstreamModel(selectionId) {
|
|
26425
|
+
if (selectionId === null || !selectionId.startsWith("gateway:"))
|
|
26426
|
+
return selectionId;
|
|
26427
|
+
const gateway = this.gatewayFor(selectionId);
|
|
26428
|
+
const model = gateway?.models.find((model2) => gatewayModelId(gateway.id, model2.id) === selectionId);
|
|
26429
|
+
if (!model)
|
|
26430
|
+
throw RequestError.invalidParams({ model: selectionId }, "The selected provider connection or model is unavailable");
|
|
26431
|
+
return model.id;
|
|
26175
26432
|
}
|
|
26176
26433
|
disable(request) {
|
|
26177
26434
|
if (request.providerId !== OPENAI_PROVIDER_ID)
|
|
@@ -26250,7 +26507,7 @@ class ProviderRouting {
|
|
|
26250
26507
|
const own = [];
|
|
26251
26508
|
for (const gateway of this.gateways.values()) {
|
|
26252
26509
|
for (const model of gateway.models)
|
|
26253
|
-
own.push(gatewayModel(model, false, codexCatalog[0], gateway.catalogEntries.get(model.id)));
|
|
26510
|
+
own.push({ ...gatewayModel(model, false, codexCatalog[0], gateway.catalogEntries.get(model.id)), id: gatewayModelId(gateway.id, model.id) });
|
|
26254
26511
|
}
|
|
26255
26512
|
return [...codexCatalog, ...own];
|
|
26256
26513
|
}
|
|
@@ -26374,12 +26631,13 @@ function gatewayModel(model, isDefault, template, entry) {
|
|
|
26374
26631
|
additionalSpeedTiers: [],
|
|
26375
26632
|
serviceTiers: [],
|
|
26376
26633
|
defaultServiceTier: null,
|
|
26634
|
+
availableAccessPrograms: null,
|
|
26377
26635
|
isDefault
|
|
26378
26636
|
};
|
|
26379
26637
|
}
|
|
26380
26638
|
|
|
26381
26639
|
// src/agent/session.ts
|
|
26382
|
-
function createActiveTurn(threadId) {
|
|
26640
|
+
function createActiveTurn(threadId, clientUserMessageId = null) {
|
|
26383
26641
|
let resolveStarted = () => {};
|
|
26384
26642
|
let resolveFinished = () => {};
|
|
26385
26643
|
let started = new Promise((resolve) => {
|
|
@@ -26393,6 +26651,7 @@ function createActiveTurn(threadId) {
|
|
|
26393
26651
|
return {
|
|
26394
26652
|
turnId: null,
|
|
26395
26653
|
threadId,
|
|
26654
|
+
clientUserMessageId,
|
|
26396
26655
|
abort: new AbortController,
|
|
26397
26656
|
stop: new AbortController,
|
|
26398
26657
|
interrupts: new Map,
|
|
@@ -26517,7 +26776,7 @@ class CodexAgent {
|
|
|
26517
26776
|
additionalDirectories: {}
|
|
26518
26777
|
},
|
|
26519
26778
|
providers: {},
|
|
26520
|
-
_meta: { codex: { archive: true, seedHistory: true, skills: true, plugins: true, providerCatalog: true, rename: true, account: true, fuzzyFileSearch: true } }
|
|
26779
|
+
_meta: { alwith: { tools: { version: 1 } }, codex: { archive: true, seedHistory: true, skills: true, plugins: true, providerCatalog: true, rename: true, account: true, fuzzyFileSearch: true } }
|
|
26521
26780
|
},
|
|
26522
26781
|
authMethods: authMethods(this.capabilities, this.env)
|
|
26523
26782
|
};
|
|
@@ -26604,7 +26863,8 @@ class CodexAgent {
|
|
|
26604
26863
|
const catalog = await this.withCodex(() => this.codex.allModels(true));
|
|
26605
26864
|
const nativeProvider = await this.resolveModelProvider(candidate);
|
|
26606
26865
|
const wholesale = this.providers.active !== null && this.providers.mode === "route" || candidate.active !== null && candidate.mode === "route";
|
|
26607
|
-
const
|
|
26866
|
+
const unavailable = new Set([...this.sessions.values()].filter((runtime) => this.providers.mode === "catalog" && this.providers.hasGateway(runtime.modelProvider) && !candidate.hasGateway(runtime.modelProvider)));
|
|
26867
|
+
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)));
|
|
26608
26868
|
const targets = new Map(moving.map((runtime) => {
|
|
26609
26869
|
if (candidate.active === null)
|
|
26610
26870
|
return [runtime, null];
|
|
@@ -26637,11 +26897,13 @@ class CodexAgent {
|
|
|
26637
26897
|
cwd: runtime.session.cwd,
|
|
26638
26898
|
config: config2,
|
|
26639
26899
|
modelProvider,
|
|
26640
|
-
model: selection.model,
|
|
26900
|
+
model: candidate.upstreamModel(selection.model),
|
|
26641
26901
|
excludeTurns: true
|
|
26642
26902
|
}));
|
|
26643
|
-
staged.set(runtime, { config: config2, catalog: nextCatalog, model: resolveModelSelection(nextCatalog, requestedModel ?? thread.model, thread.reasoningEffort) });
|
|
26903
|
+
staged.set(runtime, { config: config2, catalog: nextCatalog, model: resolveModelSelection(nextCatalog, requestedModel ?? candidate.selectionId(thread.model, modelProvider), thread.reasoningEffort) });
|
|
26644
26904
|
}
|
|
26905
|
+
for (const runtime of unavailable)
|
|
26906
|
+
runtime.config = candidate.rebind(runtime.config, this.providers, null);
|
|
26645
26907
|
this.providers = candidate;
|
|
26646
26908
|
for (const runtime of this.sessions.values()) {
|
|
26647
26909
|
const next = staged.get(runtime);
|
|
@@ -26653,7 +26915,7 @@ class CodexAgent {
|
|
|
26653
26915
|
}
|
|
26654
26916
|
runtime.session.catalog = nextCatalog;
|
|
26655
26917
|
runtime.session.gatewayGroups = candidate.gatewayGroups();
|
|
26656
|
-
if (!next)
|
|
26918
|
+
if (!next && !unavailable.has(runtime))
|
|
26657
26919
|
runtime.session.model = resolveModelSelection(nextCatalog, findModel(nextCatalog, runtime.session.model.model) ? runtime.session.model.model : null, runtime.session.model.effort);
|
|
26658
26920
|
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));
|
|
26659
26921
|
}
|
|
@@ -26669,7 +26931,7 @@ class CodexAgent {
|
|
|
26669
26931
|
cwd: runtime.session.cwd,
|
|
26670
26932
|
config: runtime.config,
|
|
26671
26933
|
modelProvider: runtime.modelProvider,
|
|
26672
|
-
model: runtime.session.model.model,
|
|
26934
|
+
model: this.providers.upstreamModel(runtime.session.model.model),
|
|
26673
26935
|
excludeTurns: true
|
|
26674
26936
|
});
|
|
26675
26937
|
} catch (rollbackError) {
|
|
@@ -26743,6 +27005,13 @@ class CodexAgent {
|
|
|
26743
27005
|
this.assertUnsubscribeSettled(open2.request.sessionId);
|
|
26744
27006
|
}
|
|
26745
27007
|
const mcpServers = request.mcpServers ?? [];
|
|
27008
|
+
const clientTools = clientToolsOf(request._meta);
|
|
27009
|
+
const host = hostSessionOptions(request._meta);
|
|
27010
|
+
const mode = host.mode ?? initialAgentMode(this.env);
|
|
27011
|
+
const hostThreadOptions = {
|
|
27012
|
+
...host.instructions === undefined ? {} : { developerInstructions: host.instructions },
|
|
27013
|
+
...host.mode ? { approvalPolicy: mode.approvalPolicy, approvalsReviewer: mode.approvalsReviewer, sandbox: mode.sandboxMode } : {}
|
|
27014
|
+
};
|
|
26746
27015
|
const requestedModel = requestedModelOf(request._meta);
|
|
26747
27016
|
let gatewayId = this.providers.defaultGatewayId();
|
|
26748
27017
|
if (this.providers.active !== null && this.providers.mode === "catalog") {
|
|
@@ -26763,17 +27032,24 @@ class CodexAgent {
|
|
|
26763
27032
|
const config2 = buildThreadConfig(this.providers.threadConfig(gatewayId), request.cwd, additionalDirectories, mcpServers, existingMcp);
|
|
26764
27033
|
const mcpStartupGeneration = this.codex.mcpStartupGeneration;
|
|
26765
27034
|
const modelProvider = gatewayId ?? await this.withCodex(() => this.resolveModelProvider());
|
|
26766
|
-
const startModel = onGateway ? requestedModel ?? this.providers.gateway(gatewayId)?.model ?? null : requestedModel;
|
|
27035
|
+
const startModel = this.providers.upstreamModel(onGateway ? requestedModel ?? this.providers.gateway(gatewayId)?.model ?? null : requestedModel);
|
|
26767
27036
|
let readOnly = false;
|
|
26768
27037
|
const { thread, skills } = await this.withSkillsContext(request.cwd, additionalDirectories, async (skills2) => ({ skills: skills2, thread: await this.withCodex(async () => {
|
|
26769
27038
|
if (signal?.aborted)
|
|
26770
27039
|
throw RequestError.requestCancelled(undefined, "Session opening was cancelled");
|
|
26771
27040
|
switch (open2.kind) {
|
|
26772
27041
|
case "new":
|
|
26773
|
-
return await this.codex.threadStart({
|
|
27042
|
+
return await this.codex.threadStart({
|
|
27043
|
+
...hostThreadOptions,
|
|
27044
|
+
config: config2,
|
|
27045
|
+
cwd: request.cwd,
|
|
27046
|
+
modelProvider,
|
|
27047
|
+
model: startModel,
|
|
27048
|
+
...clientTools ? { dynamicTools: dynamicTools(clientTools) } : {}
|
|
27049
|
+
});
|
|
26774
27050
|
case "resume":
|
|
26775
27051
|
try {
|
|
26776
|
-
return await this.codex.threadResume({ threadId: open2.request.sessionId, config: config2, cwd: request.cwd, modelProvider, model: startModel, excludeTurns: true });
|
|
27052
|
+
return await this.codex.threadResume({ ...hostThreadOptions, threadId: open2.request.sessionId, config: config2, cwd: request.cwd, modelProvider, model: startModel, excludeTurns: true });
|
|
26777
27053
|
} catch (error40) {
|
|
26778
27054
|
if (!errorMessage(error40).includes("already has an active writer"))
|
|
26779
27055
|
throw error40;
|
|
@@ -26781,7 +27057,7 @@ class CodexAgent {
|
|
|
26781
27057
|
return readOnlyThread((await this.codex.threadRead({ threadId: open2.request.sessionId, includeTurns: false })).thread, request.cwd);
|
|
26782
27058
|
}
|
|
26783
27059
|
case "fork":
|
|
26784
|
-
return await this.codex.threadFork({ threadId: open2.request.sessionId, config: config2, cwd: request.cwd, modelProvider, model: startModel, excludeTurns: true });
|
|
27060
|
+
return await this.codex.threadFork({ ...hostThreadOptions, threadId: open2.request.sessionId, config: config2, cwd: request.cwd, modelProvider, model: startModel, excludeTurns: true });
|
|
26785
27061
|
}
|
|
26786
27062
|
}) }));
|
|
26787
27063
|
const sessionId = thread.thread.id;
|
|
@@ -26810,8 +27086,9 @@ class CodexAgent {
|
|
|
26810
27086
|
openedAccount = (await this.withCodex(() => this.codex.accountRead({ refreshToken: false }))).account;
|
|
26811
27087
|
}
|
|
26812
27088
|
const catalog = this.providers.catalog(codexCatalog);
|
|
26813
|
-
const model = resolveModelSelection(catalog, startModel ?? thread.model, thread.reasoningEffort);
|
|
27089
|
+
const model = resolveModelSelection(catalog, this.providers.selectionId(startModel ?? thread.model, gatewayId ?? thread.modelProvider), thread.reasoningEffort);
|
|
26814
27090
|
const session = {
|
|
27091
|
+
...clientTools ? { clientTools } : {},
|
|
26815
27092
|
id: sessionId,
|
|
26816
27093
|
cwd: request.cwd,
|
|
26817
27094
|
additionalDirectories,
|
|
@@ -26819,7 +27096,7 @@ class CodexAgent {
|
|
|
26819
27096
|
catalog,
|
|
26820
27097
|
gatewayGroups: this.providers.gatewayGroups(),
|
|
26821
27098
|
model,
|
|
26822
|
-
mode
|
|
27099
|
+
mode,
|
|
26823
27100
|
collaborationMode: DEFAULT_COLLABORATION_MODE,
|
|
26824
27101
|
fastMode: thread.serviceTier === FAST_SERVICE_TIER,
|
|
26825
27102
|
account: openedAccount,
|
|
@@ -26888,11 +27165,13 @@ class CodexAgent {
|
|
|
26888
27165
|
const approval = new CodexApprovalHandler(client, turnContext, signal);
|
|
26889
27166
|
const elicitation = new CodexElicitationHandler(client, turnContext, signal);
|
|
26890
27167
|
const runtime = { config: config2, modelProvider, stale: false, readOnly, session, client, bridge, turnContext, elicitation, lifetime: new AbortController, queue: Promise.resolve() };
|
|
27168
|
+
const tools = new ClientTools(session, client, AbortSignal.any([runtime.lifetime.signal, this.codex.disconnectSignal]));
|
|
26891
27169
|
const drained = (operation) => async (params) => {
|
|
26892
27170
|
await abortable(this.drain(runtime), this.codex.disconnectSignal);
|
|
26893
27171
|
return await operation(params);
|
|
26894
27172
|
};
|
|
26895
27173
|
this.codex.attachThread(session.id, {
|
|
27174
|
+
tool: (params) => tools.call(params),
|
|
26896
27175
|
notification: (notification) => this.enqueue(runtime, notification),
|
|
26897
27176
|
approval: {
|
|
26898
27177
|
handleCommandExecution: drained((params) => approval.handleCommandExecution(params)),
|
|
@@ -26996,8 +27275,8 @@ class CodexAgent {
|
|
|
26996
27275
|
const result = await this.codex.awaitMcpStartup(runtime.session.mcpServerNames, afterGeneration, runtime.lifetime.signal, runtime.session.id);
|
|
26997
27276
|
if (runtime.session.closed)
|
|
26998
27277
|
return;
|
|
26999
|
-
for (const
|
|
27000
|
-
await runtime.client.update(mcpStartupFailed(
|
|
27278
|
+
for (const failure2 of result.failed) {
|
|
27279
|
+
await runtime.client.update(mcpStartupFailed(failure2.server, `MCP server "${failure2.server}" failed to start: ${failure2.error}`));
|
|
27001
27280
|
}
|
|
27002
27281
|
for (const server of result.cancelled) {
|
|
27003
27282
|
await runtime.client.update(mcpStartupFailed(server, `MCP server "${server}" startup was cancelled.`));
|
|
@@ -27205,10 +27484,11 @@ class CodexAgent {
|
|
|
27205
27484
|
async setSessionConfigOptionInternal(params) {
|
|
27206
27485
|
const runtime = this.runtime(params.sessionId, "session/set_config_option");
|
|
27207
27486
|
assertWritable(runtime);
|
|
27208
|
-
if (params.configId === MODEL_CONFIG_ID && this.providers.mode === "catalog" && typeof params.value === "string") {
|
|
27487
|
+
if (params.configId === MODEL_CONFIG_ID && (this.providers.mode === "catalog" || runtime.session.model.model.startsWith("gateway:")) && typeof params.value === "string") {
|
|
27488
|
+
this.providers.upstreamModel(params.value);
|
|
27209
27489
|
const target = this.providers.gatewayIdFor(params.value);
|
|
27210
|
-
const
|
|
27211
|
-
if (
|
|
27490
|
+
const destination = target ?? await this.withCodex(() => this.resolveModelProvider());
|
|
27491
|
+
if (destination !== runtime.modelProvider)
|
|
27212
27492
|
await this.rerouteSession(runtime, target, params.value);
|
|
27213
27493
|
}
|
|
27214
27494
|
await this.withCodex(() => applyConfigOption(runtime.session, this.codex, params));
|
|
@@ -27231,10 +27511,10 @@ class CodexAgent {
|
|
|
27231
27511
|
const modelProvider = gatewayId ?? await this.withCodex(() => this.resolveModelProvider());
|
|
27232
27512
|
await this.codex.threadUnsubscribe({ threadId: session.id });
|
|
27233
27513
|
try {
|
|
27234
|
-
await this.withCodex(() => this.codex.threadResume({ threadId: session.id, cwd: session.cwd, config: config2, modelProvider, model: modelId, excludeTurns: true }));
|
|
27514
|
+
await this.withCodex(() => this.codex.threadResume({ threadId: session.id, cwd: session.cwd, config: config2, modelProvider, model: this.providers.upstreamModel(modelId), excludeTurns: true }));
|
|
27235
27515
|
} catch (error40) {
|
|
27236
27516
|
try {
|
|
27237
|
-
await this.codex.threadResume({ threadId: session.id, cwd: session.cwd, config: runtime.config, modelProvider: runtime.modelProvider, model: session.model.model, excludeTurns: true });
|
|
27517
|
+
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 });
|
|
27238
27518
|
} catch (rollbackError) {
|
|
27239
27519
|
runtime.stale = true;
|
|
27240
27520
|
logger.error("Provider rollback failed", rollbackError, { sessionId: session.id });
|
|
@@ -27253,9 +27533,9 @@ class CodexAgent {
|
|
|
27253
27533
|
return runtime;
|
|
27254
27534
|
}
|
|
27255
27535
|
async prompt(params) {
|
|
27256
|
-
return await this.promptInternal(params);
|
|
27536
|
+
return await this.promptInternal(params, false, crypto.randomUUID());
|
|
27257
27537
|
}
|
|
27258
|
-
async promptInternal(params, allowReentry
|
|
27538
|
+
async promptInternal(params, allowReentry, messageId) {
|
|
27259
27539
|
this.assertRoutingAvailable();
|
|
27260
27540
|
if (!allowReentry && this.sessionMutations.has(params.sessionId))
|
|
27261
27541
|
throw RequestError.invalidRequest({ sessionId: params.sessionId }, "Session lifecycle or configuration work is in progress; retry when it finishes");
|
|
@@ -27267,31 +27547,32 @@ class CodexAgent {
|
|
|
27267
27547
|
throw RequestError.invalidParams(undefined, "prompt must contain at least one content block");
|
|
27268
27548
|
}
|
|
27269
27549
|
const { session } = runtime;
|
|
27550
|
+
this.providers.upstreamModel(session.model.model);
|
|
27270
27551
|
const model = findModel(session.catalog, session.model.model);
|
|
27271
27552
|
if (!modelSupportsImages(model) && params.prompt.some((block) => block.type === "image")) {
|
|
27272
27553
|
throw RequestError.invalidParams({ model: session.model.model }, "The current model does not support image input");
|
|
27273
27554
|
}
|
|
27274
27555
|
if (session.activeTurn) {
|
|
27275
|
-
return await this.steerActiveTurn(runtime, session.activeTurn, params);
|
|
27556
|
+
return await this.steerActiveTurn(runtime, session.activeTurn, params, messageId);
|
|
27276
27557
|
}
|
|
27277
|
-
const turn = createActiveTurn(session.id);
|
|
27558
|
+
const turn = createActiveTurn(session.id, messageId);
|
|
27278
27559
|
session.activeTurn = turn;
|
|
27279
27560
|
runtime.client.reportRunning();
|
|
27280
27561
|
this.runPrompt(runtime, turn, params);
|
|
27281
|
-
return {};
|
|
27562
|
+
return { messageId };
|
|
27282
27563
|
}
|
|
27283
|
-
async steerActiveTurn(runtime, turn, params) {
|
|
27564
|
+
async steerActiveTurn(runtime, turn, params, messageId) {
|
|
27284
27565
|
const turnId = turn.turnId ?? await turn.started;
|
|
27285
27566
|
if (turnId === null || turn.threadId !== runtime.session.id) {
|
|
27286
27567
|
throw RequestError.invalidRequest({ sessionId: params.sessionId }, "A turn is already running; wait for it to finish or cancel it");
|
|
27287
27568
|
}
|
|
27288
27569
|
try {
|
|
27289
|
-
await this.codex.turnSteer({ threadId: runtime.session.id, expectedTurnId: turnId, input: toUserInput(params.prompt) });
|
|
27290
|
-
return { _meta: { codex: { steered: turnId } } };
|
|
27570
|
+
await this.codex.turnSteer({ threadId: runtime.session.id, expectedTurnId: turnId, clientUserMessageId: messageId, input: toUserInput(params.prompt) });
|
|
27571
|
+
return { messageId, _meta: { codex: { steered: turnId } } };
|
|
27291
27572
|
} catch (error40) {
|
|
27292
27573
|
if (this.completedTurns.get(turn) === turnId || runtime.session.activeTurn !== turn) {
|
|
27293
27574
|
await turn.finished;
|
|
27294
|
-
return await this.promptInternal(params, true);
|
|
27575
|
+
return await this.promptInternal(params, true, messageId);
|
|
27295
27576
|
}
|
|
27296
27577
|
throw RequestError.invalidRequest({ sessionId: params.sessionId, turnId }, `Could not steer the running turn: ${errorMessage(error40)}`);
|
|
27297
27578
|
}
|
|
@@ -27396,11 +27677,12 @@ class CodexAgent {
|
|
|
27396
27677
|
startSent = true;
|
|
27397
27678
|
const completed = this.withCodex(() => this.codex.runTurn({
|
|
27398
27679
|
threadId: session.id,
|
|
27680
|
+
clientUserMessageId: turn.clientUserMessageId,
|
|
27399
27681
|
input: toUserInput(prompt),
|
|
27400
27682
|
approvalPolicy: session.mode.approvalPolicy,
|
|
27401
27683
|
approvalsReviewer: session.mode.approvalsReviewer,
|
|
27402
27684
|
sandboxPolicy: withWritableRoots(session.mode.sandboxPolicy, session.additionalDirectories),
|
|
27403
|
-
model: session.model.model,
|
|
27685
|
+
model: this.providers.upstreamModel(session.model.model),
|
|
27404
27686
|
effort: session.model.effort,
|
|
27405
27687
|
summary: disableSummary ? "none" : "auto",
|
|
27406
27688
|
serviceTier: session.fastMode ? FAST_SERVICE_TIER : null
|
|
@@ -27753,16 +28035,33 @@ function readOnlyThread(thread, cwd) {
|
|
|
27753
28035
|
model: thread.model ?? "",
|
|
27754
28036
|
modelProvider: thread.modelProvider,
|
|
27755
28037
|
serviceTier: null,
|
|
28038
|
+
disabledPluginIds: [],
|
|
27756
28039
|
cwd,
|
|
28040
|
+
runtimeWorkspaceRoots: [],
|
|
27757
28041
|
instructionSources: [],
|
|
27758
28042
|
approvalPolicy: "on-request",
|
|
27759
28043
|
approvalsReviewer: "user",
|
|
27760
28044
|
sandbox: { type: "readOnly", networkAccess: false },
|
|
28045
|
+
activePermissionProfile: null,
|
|
27761
28046
|
reasoningEffort: thread.reasoningEffort,
|
|
28047
|
+
collaborationMode: null,
|
|
28048
|
+
multiAgentMode: "explicitRequestOnly",
|
|
28049
|
+
initialTurnsPage: null,
|
|
27762
28050
|
turnsBackwardsCursor: null,
|
|
27763
28051
|
itemsBackwardsCursor: null
|
|
27764
28052
|
};
|
|
27765
28053
|
}
|
|
28054
|
+
function hostSessionOptions(meta) {
|
|
28055
|
+
const instructions = meta?.alwith?.appendSystemPrompt;
|
|
28056
|
+
if (instructions !== undefined && typeof instructions !== "string") {
|
|
28057
|
+
throw RequestError.invalidParams(undefined, "appendSystemPrompt must be a string");
|
|
28058
|
+
}
|
|
28059
|
+
const modeId = meta?.codex?.mode;
|
|
28060
|
+
const mode = typeof modeId === "string" ? findAgentMode(modeId) : undefined;
|
|
28061
|
+
if (modeId !== undefined && !mode)
|
|
28062
|
+
throw RequestError.invalidParams(undefined, "Unknown Codex session mode");
|
|
28063
|
+
return { instructions, mode };
|
|
28064
|
+
}
|
|
27766
28065
|
function requestedModelOf(meta) {
|
|
27767
28066
|
const raw = meta?.alwith?.model;
|
|
27768
28067
|
return typeof raw === "string" && raw.length > 0 ? raw : null;
|
|
@@ -27823,12 +28122,14 @@ var FileChangeApprovalRequest = new import_node.RequestType("item/fileChange/req
|
|
|
27823
28122
|
var PermissionsApprovalRequest = new import_node.RequestType("item/permissions/requestApproval");
|
|
27824
28123
|
var McpServerElicitationRequest = new import_node.RequestType("mcpServer/elicitation/request");
|
|
27825
28124
|
var ToolRequestUserInputRequest = new import_node.RequestType("item/tool/requestUserInput");
|
|
28125
|
+
var DynamicToolCallRequest = new import_node.RequestType("item/tool/call");
|
|
27826
28126
|
|
|
27827
28127
|
class AppServerClient {
|
|
27828
28128
|
connection;
|
|
27829
28129
|
threadHandlers = new Map;
|
|
27830
28130
|
approvalHandlers = new Map;
|
|
27831
28131
|
elicitationHandlers = new Map;
|
|
28132
|
+
dynamicToolHandlers = new Map;
|
|
27832
28133
|
turnCompletionWaiters = new Map;
|
|
27833
28134
|
earlyTurnCompletions = new Map;
|
|
27834
28135
|
startingThreads = new Map;
|
|
@@ -27841,6 +28142,10 @@ class AppServerClient {
|
|
|
27841
28142
|
disconnected = new AbortController;
|
|
27842
28143
|
constructor(connection) {
|
|
27843
28144
|
this.connection = connection;
|
|
28145
|
+
connection.onRequest(DynamicToolCallRequest, async (params) => {
|
|
28146
|
+
const handler = this.dynamicToolHandlers.get(params.threadId);
|
|
28147
|
+
return handler ? await handler(params) : { success: false, contentItems: [{ type: "inputText", text: "Client tools are unavailable for this thread" }] };
|
|
28148
|
+
});
|
|
27844
28149
|
connection.onClose(() => this.disconnected.abort(new Error("Connection to Codex was lost")));
|
|
27845
28150
|
connection.onDispose(() => this.disconnected.abort(new Error("Connection to Codex was lost")));
|
|
27846
28151
|
connection.onUnhandledNotification((message) => {
|
|
@@ -27874,11 +28179,14 @@ class AppServerClient {
|
|
|
27874
28179
|
this.threadHandlers.set(threadId, handlers.notification);
|
|
27875
28180
|
this.approvalHandlers.set(threadId, handlers.approval);
|
|
27876
28181
|
this.elicitationHandlers.set(threadId, handlers.elicitation);
|
|
28182
|
+
if (handlers.tool)
|
|
28183
|
+
this.dynamicToolHandlers.set(threadId, handlers.tool);
|
|
27877
28184
|
}
|
|
27878
28185
|
detachThread(threadId) {
|
|
27879
28186
|
this.threadHandlers.delete(threadId);
|
|
27880
28187
|
this.approvalHandlers.delete(threadId);
|
|
27881
28188
|
this.elicitationHandlers.delete(threadId);
|
|
28189
|
+
this.dynamicToolHandlers.delete(threadId);
|
|
27882
28190
|
for (const key of this.mcpStartupStates.keys()) {
|
|
27883
28191
|
if (key.startsWith(`${threadId}\x00`))
|
|
27884
28192
|
this.mcpStartupStates.delete(key);
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.7.1",
|
|
7
7
|
"description": "Native ACP v2 agent for the OpenAI Codex app-server",
|
|
8
8
|
"packageManager": "bun@1.4.0",
|
|
9
9
|
"engines": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"package:win-x64": "cd dist/bin && zip codex-acp-v2-x64-windows.zip codex-acp-v2-x64-windows.exe",
|
|
38
38
|
"package:win-arm64": "cd dist/bin && zip codex-acp-v2-arm64-windows.zip codex-acp-v2-arm64-windows.exe",
|
|
39
39
|
"start": "bun src/index.ts",
|
|
40
|
-
"generate-types": "codex app-server generate-ts --out src/app-server",
|
|
40
|
+
"generate-types": "codex app-server generate-ts --experimental --out src/app-server",
|
|
41
41
|
"test": "vitest run --exclude src/__tests__/e2e.test.ts",
|
|
42
42
|
"test:watch": "vitest",
|
|
43
43
|
"typecheck": "tsc --noEmit",
|
|
@@ -69,12 +69,12 @@
|
|
|
69
69
|
"vitest": "^4.1.11"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@agentclientprotocol/sdk": "^1.
|
|
72
|
+
"@agentclientprotocol/sdk": "^1.5.1",
|
|
73
73
|
"diff": "^9.0.0",
|
|
74
74
|
"open": "^11.0.2",
|
|
75
75
|
"vscode-jsonrpc": "^9.0.2"
|
|
76
76
|
},
|
|
77
77
|
"optionalDependencies": {
|
|
78
|
-
"@openai/codex": "^0.
|
|
78
|
+
"@openai/codex": "^0.158.0"
|
|
79
79
|
}
|
|
80
80
|
}
|