@nextclaw/nextclaw-ncp-runtime-plugin-codex-sdk 0.1.21 → 0.1.22

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/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ // src/index.ts
1
2
  import {
2
3
  findProviderByModel,
3
4
  findProviderByName,
@@ -7,20 +8,1102 @@ import {
7
8
  import {
8
9
  CodexSdkNcpAgentRuntime
9
10
  } from "@nextclaw/nextclaw-ncp-runtime-codex-sdk";
11
+
12
+ // src/codex-model-provider.ts
13
+ function readOptionalString(value) {
14
+ if (typeof value !== "string") {
15
+ return void 0;
16
+ }
17
+ const trimmed = value.trim();
18
+ return trimmed || void 0;
19
+ }
20
+ function isValidExternalModelProvider(value) {
21
+ return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(value);
22
+ }
23
+ function resolveExternalModelProvider(params) {
24
+ const explicitModelProvider = readOptionalString(params.explicitModelProvider);
25
+ if (explicitModelProvider) {
26
+ return explicitModelProvider;
27
+ }
28
+ const providerName = readOptionalString(params.providerName);
29
+ if (providerName && !providerName.startsWith("custom-")) {
30
+ return providerName;
31
+ }
32
+ const providerDisplayName = readOptionalString(params.providerDisplayName);
33
+ if (providerDisplayName && isValidExternalModelProvider(providerDisplayName)) {
34
+ return providerDisplayName;
35
+ }
36
+ throw new Error(
37
+ `[codex] custom provider "${providerName ?? "unknown"}" requires an external model provider id. Set plugins.entries.${params.pluginId}.config.modelProvider or use a provider display name with only letters, numbers, ".", "_" or "-".`
38
+ );
39
+ }
40
+ function buildUserFacingModelRoute(params) {
41
+ const providerLocalModel = params.providerLocalModel.trim();
42
+ if (!providerLocalModel) {
43
+ return params.resolvedModel.trim();
44
+ }
45
+ return `${params.externalModelProvider}/${providerLocalModel}`;
46
+ }
47
+ function buildCodexBridgeModelProviderId(externalModelProvider) {
48
+ const normalized = externalModelProvider.trim();
49
+ if (!normalized) {
50
+ return "nextclaw-codex-bridge";
51
+ }
52
+ return `nextclaw-codex-bridge-${normalized}`;
53
+ }
54
+
55
+ // src/codex-access-mode.ts
56
+ var DEFAULT_CODEX_ACCESS_MODE = "full-access";
57
+ var CODEX_ACCESS_MODES = ["read-only", "workspace-write", "full-access"];
58
+ var LEGACY_CODEX_SANDBOX_MODES = ["read-only", "workspace-write", "danger-full-access"];
59
+ var CODEX_APPROVAL_POLICY = "never";
60
+ function readEnumString(value, allowedValues) {
61
+ if (typeof value !== "string") {
62
+ return void 0;
63
+ }
64
+ const normalized = value.trim();
65
+ return allowedValues.includes(normalized) ? normalized : void 0;
66
+ }
67
+ function mapLegacySandboxModeToAccessMode(sandboxMode) {
68
+ switch (sandboxMode) {
69
+ case "read-only":
70
+ return "read-only";
71
+ case "workspace-write":
72
+ return "workspace-write";
73
+ case "danger-full-access":
74
+ return "full-access";
75
+ }
76
+ }
77
+ function mapAccessModeToSandboxMode(accessMode) {
78
+ switch (accessMode) {
79
+ case "read-only":
80
+ return "read-only";
81
+ case "workspace-write":
82
+ return "workspace-write";
83
+ case "full-access":
84
+ return "danger-full-access";
85
+ }
86
+ }
87
+ function resolveCodexAccessMode(pluginConfig) {
88
+ const explicitAccessMode = readEnumString(pluginConfig.accessMode, CODEX_ACCESS_MODES);
89
+ if (explicitAccessMode) {
90
+ return explicitAccessMode;
91
+ }
92
+ const legacySandboxMode = readEnumString(pluginConfig.sandboxMode, LEGACY_CODEX_SANDBOX_MODES);
93
+ if (legacySandboxMode) {
94
+ return mapLegacySandboxModeToAccessMode(legacySandboxMode);
95
+ }
96
+ return DEFAULT_CODEX_ACCESS_MODE;
97
+ }
98
+
99
+ // src/codex-input-builder.ts
10
100
  import {
11
- buildUserFacingModelRoute,
12
- buildCodexBridgeModelProviderId,
13
- resolveExternalModelProvider
14
- } from "./codex-model-provider.js";
15
- import { buildCodexInputBuilder } from "./codex-input-builder.js";
16
- import { ensureCodexOpenAiResponsesBridge } from "./codex-openai-responses-bridge.js";
17
- import { resolveCodexResponsesApiSupport } from "./codex-responses-capability.js";
18
- import {
19
- createDescribeCodexSessionType
20
- } from "./codex-session-type.js";
21
- const PLUGIN_ID = "nextclaw-ncp-runtime-plugin-codex-sdk";
22
- const CODEX_RUNTIME_KIND = "codex";
23
- class DeferredCodexSdkNcpAgentRuntime {
101
+ buildRequestedSkillsUserPrompt,
102
+ SkillsLoader
103
+ } from "@nextclaw/core";
104
+ function readString(value) {
105
+ if (typeof value !== "string") {
106
+ return void 0;
107
+ }
108
+ const trimmed = value.trim();
109
+ return trimmed || void 0;
110
+ }
111
+ function readRequestedSkills(metadata) {
112
+ const raw = metadata.requested_skills ?? metadata.requestedSkills;
113
+ if (!Array.isArray(raw)) {
114
+ return [];
115
+ }
116
+ return raw.map((entry) => readString(entry)).filter((entry) => Boolean(entry)).slice(0, 8);
117
+ }
118
+ function readUserText(input) {
119
+ for (let index = input.messages.length - 1; index >= 0; index -= 1) {
120
+ const message = input.messages[index];
121
+ if (message?.role !== "user") {
122
+ continue;
123
+ }
124
+ const text = message.parts.filter((part) => part.type === "text").map((part) => part.text).join("").trim();
125
+ if (text) {
126
+ return text;
127
+ }
128
+ }
129
+ return "";
130
+ }
131
+ function buildCodexInputBuilder(workspace) {
132
+ const skillsLoader = new SkillsLoader(workspace);
133
+ return async (input) => {
134
+ const userText = readUserText(input);
135
+ const metadata = input.metadata && typeof input.metadata === "object" && !Array.isArray(input.metadata) ? input.metadata : {};
136
+ const requestedSkills = readRequestedSkills(metadata);
137
+ return buildRequestedSkillsUserPrompt(skillsLoader, requestedSkills, userText);
138
+ };
139
+ }
140
+
141
+ // src/codex-openai-responses-bridge.ts
142
+ import { randomUUID } from "crypto";
143
+ import { createServer } from "http";
144
+
145
+ // src/codex-openai-responses-bridge-shared.ts
146
+ function readString2(value) {
147
+ if (typeof value !== "string") {
148
+ return void 0;
149
+ }
150
+ const trimmed = value.trim();
151
+ return trimmed || void 0;
152
+ }
153
+ function readBoolean(value) {
154
+ return typeof value === "boolean" ? value : void 0;
155
+ }
156
+ function readNumber(value) {
157
+ if (typeof value !== "number" || !Number.isFinite(value)) {
158
+ return void 0;
159
+ }
160
+ return value;
161
+ }
162
+ function readRecord(value) {
163
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
164
+ return void 0;
165
+ }
166
+ return value;
167
+ }
168
+ function readArray(value) {
169
+ return Array.isArray(value) ? value : [];
170
+ }
171
+ function withTrailingSlash(value) {
172
+ return value.endsWith("/") ? value : `${value}/`;
173
+ }
174
+ function writeSseEvent(response, eventType, payload) {
175
+ response.write(`event: ${eventType}
176
+ `);
177
+ response.write(`data: ${JSON.stringify(payload)}
178
+
179
+ `);
180
+ }
181
+ function nextSequenceNumber(state) {
182
+ const nextValue = state.value;
183
+ state.value += 1;
184
+ return nextValue;
185
+ }
186
+
187
+ // src/codex-openai-responses-bridge-request.ts
188
+ function stripModelPrefix(model, prefixes) {
189
+ const normalizedModel = model.trim();
190
+ for (const prefix of prefixes) {
191
+ const normalizedPrefix = prefix.trim().toLowerCase();
192
+ if (!normalizedPrefix) {
193
+ continue;
194
+ }
195
+ const candidatePrefix = `${normalizedPrefix}/`;
196
+ if (normalizedModel.toLowerCase().startsWith(candidatePrefix)) {
197
+ return normalizedModel.slice(candidatePrefix.length);
198
+ }
199
+ }
200
+ return normalizedModel;
201
+ }
202
+ function resolveUpstreamModel(requestedModel, config) {
203
+ const prefixes = (config.modelPrefixes ?? []).filter((value) => value.trim().length > 0);
204
+ const model = stripModelPrefix(readString2(requestedModel) ?? "", prefixes) || stripModelPrefix(config.defaultModel ?? "", prefixes);
205
+ if (!model) {
206
+ throw new Error("Codex bridge could not resolve an upstream model.");
207
+ }
208
+ return model;
209
+ }
210
+ function normalizeTextPart(value) {
211
+ const record = readRecord(value);
212
+ if (!record) {
213
+ return "";
214
+ }
215
+ const type = readString2(record.type);
216
+ if (type !== "input_text" && type !== "output_text") {
217
+ return "";
218
+ }
219
+ return readString2(record.text) ?? "";
220
+ }
221
+ function normalizeImageUrl(value) {
222
+ const record = readRecord(value);
223
+ if (!record || readString2(record.type) !== "input_image") {
224
+ return null;
225
+ }
226
+ const source = readRecord(record.source);
227
+ if (!source) {
228
+ return null;
229
+ }
230
+ if (readString2(source.type) === "url") {
231
+ return readString2(source.url) ?? null;
232
+ }
233
+ if (readString2(source.type) === "base64") {
234
+ const mediaType = readString2(source.media_type) ?? "application/octet-stream";
235
+ const data = readString2(source.data);
236
+ if (!data) {
237
+ return null;
238
+ }
239
+ return `data:${mediaType};base64,${data}`;
240
+ }
241
+ return null;
242
+ }
243
+ function normalizeToolOutput(value) {
244
+ if (typeof value === "string") {
245
+ return value;
246
+ }
247
+ if (Array.isArray(value)) {
248
+ const text = value.map((entry) => normalizeTextPart(entry)).filter(Boolean).join("");
249
+ if (text) {
250
+ return text;
251
+ }
252
+ }
253
+ try {
254
+ return JSON.stringify(value ?? "");
255
+ } catch {
256
+ return String(value ?? "");
257
+ }
258
+ }
259
+ function buildChatContent(content) {
260
+ if (typeof content === "string") {
261
+ return content;
262
+ }
263
+ if (!Array.isArray(content)) {
264
+ return null;
265
+ }
266
+ const chatContent = [];
267
+ for (const entry of content) {
268
+ const text = normalizeTextPart(entry);
269
+ if (text) {
270
+ chatContent.push({
271
+ type: "text",
272
+ text
273
+ });
274
+ continue;
275
+ }
276
+ const imageUrl = normalizeImageUrl(entry);
277
+ if (imageUrl) {
278
+ chatContent.push({
279
+ type: "image_url",
280
+ image_url: {
281
+ url: imageUrl
282
+ }
283
+ });
284
+ }
285
+ }
286
+ if (chatContent.length === 0) {
287
+ return null;
288
+ }
289
+ const textOnly = chatContent.every((entry) => entry.type === "text");
290
+ if (textOnly) {
291
+ return chatContent.map((entry) => readString2(entry.text) ?? "").join("\n");
292
+ }
293
+ return chatContent;
294
+ }
295
+ function readAssistantMessageText(content) {
296
+ if (typeof content === "string") {
297
+ return content;
298
+ }
299
+ if (!Array.isArray(content)) {
300
+ return "";
301
+ }
302
+ return content.filter((entry) => entry.type === "text").map((entry) => readString2(entry.text) ?? "").join("\n");
303
+ }
304
+ function appendMessageInputItem(params) {
305
+ const role = readString2(params.item.role);
306
+ const content = buildChatContent(params.item.content);
307
+ if (role === "assistant") {
308
+ const text = readAssistantMessageText(content);
309
+ if (text.trim()) {
310
+ params.assistantTextParts.push(text);
311
+ }
312
+ return;
313
+ }
314
+ params.flushAssistant();
315
+ const normalizedRole = role === "developer" ? "system" : role;
316
+ if ((normalizedRole === "system" || normalizedRole === "user") && content !== null) {
317
+ params.messages.push({
318
+ role: normalizedRole,
319
+ content
320
+ });
321
+ }
322
+ }
323
+ function appendFunctionCallItem(params) {
324
+ const name = readString2(params.item.name);
325
+ const argumentsText = readString2(params.item.arguments) ?? "{}";
326
+ if (!name) {
327
+ return;
328
+ }
329
+ const callId = readString2(params.item.call_id) ?? readString2(params.item.id) ?? `call_${params.assistantToolCalls.length}`;
330
+ params.assistantToolCalls.push({
331
+ id: callId,
332
+ type: "function",
333
+ function: {
334
+ name,
335
+ arguments: argumentsText
336
+ }
337
+ });
338
+ }
339
+ function appendFunctionCallOutputItem(params) {
340
+ params.flushAssistant();
341
+ const callId = readString2(params.item.call_id);
342
+ if (!callId) {
343
+ return;
344
+ }
345
+ params.messages.push({
346
+ role: "tool",
347
+ tool_call_id: callId,
348
+ content: normalizeToolOutput(params.item.output)
349
+ });
350
+ }
351
+ function buildOpenAiMessages(input, instructions) {
352
+ const messages = [];
353
+ const instructionText = readString2(instructions);
354
+ if (instructionText) {
355
+ messages.push({
356
+ role: "system",
357
+ content: instructionText
358
+ });
359
+ }
360
+ if (typeof input === "string") {
361
+ return [
362
+ ...messages,
363
+ {
364
+ role: "user",
365
+ content: input
366
+ }
367
+ ];
368
+ }
369
+ const assistantTextParts = [];
370
+ const assistantToolCalls = [];
371
+ const flushAssistant = () => {
372
+ if (assistantTextParts.length === 0 && assistantToolCalls.length === 0) {
373
+ return;
374
+ }
375
+ messages.push({
376
+ role: "assistant",
377
+ content: assistantTextParts.join("\n").trim() || null,
378
+ ...assistantToolCalls.length > 0 ? {
379
+ tool_calls: structuredClone(assistantToolCalls)
380
+ } : {}
381
+ });
382
+ assistantTextParts.length = 0;
383
+ assistantToolCalls.length = 0;
384
+ };
385
+ for (const rawItem of readArray(input)) {
386
+ const item = readRecord(rawItem);
387
+ if (!item) {
388
+ continue;
389
+ }
390
+ const type = readString2(item.type);
391
+ if (type === "message") {
392
+ appendMessageInputItem({
393
+ messages,
394
+ assistantTextParts,
395
+ assistantToolCalls,
396
+ item,
397
+ flushAssistant
398
+ });
399
+ continue;
400
+ }
401
+ if (type === "function_call") {
402
+ appendFunctionCallItem({
403
+ assistantToolCalls,
404
+ item
405
+ });
406
+ continue;
407
+ }
408
+ if (type === "function_call_output") {
409
+ appendFunctionCallOutputItem({
410
+ messages,
411
+ item,
412
+ flushAssistant
413
+ });
414
+ }
415
+ }
416
+ flushAssistant();
417
+ return messages;
418
+ }
419
+ function toOpenAiTools(value) {
420
+ const tools = [];
421
+ for (const entry of readArray(value)) {
422
+ const tool = readRecord(entry);
423
+ const type = readString2(tool?.type);
424
+ const fn = readRecord(tool?.function);
425
+ const name = readString2(fn?.name) ?? readString2(tool?.name);
426
+ if (type !== "function" || !name) {
427
+ continue;
428
+ }
429
+ const description = (fn ? readString2(fn.description) : void 0) ?? readString2(tool?.description);
430
+ const parameters = (fn ? readRecord(fn.parameters) : void 0) ?? readRecord(tool?.parameters);
431
+ const strict = (fn ? readBoolean(fn.strict) : void 0) ?? readBoolean(tool?.strict);
432
+ tools.push({
433
+ type: "function",
434
+ function: {
435
+ name,
436
+ ...description ? { description } : {},
437
+ parameters: parameters ?? {
438
+ type: "object",
439
+ properties: {}
440
+ },
441
+ ...strict !== void 0 ? { strict } : {}
442
+ }
443
+ });
444
+ }
445
+ return tools.length > 0 ? tools : void 0;
446
+ }
447
+ function toOpenAiToolChoice(value) {
448
+ if (value === "auto" || value === "none" || value === "required") {
449
+ return value;
450
+ }
451
+ const record = readRecord(value);
452
+ const fn = readRecord(record?.function);
453
+ const name = readString2(fn?.name) ?? readString2(record?.name);
454
+ if (readString2(record?.type) === "function" && name) {
455
+ return {
456
+ type: "function",
457
+ function: {
458
+ name
459
+ }
460
+ };
461
+ }
462
+ return void 0;
463
+ }
464
+ async function callOpenAiCompatibleUpstream(params) {
465
+ const model = resolveUpstreamModel(params.body.model, params.config);
466
+ const upstreamUrl = new URL(
467
+ "chat/completions",
468
+ withTrailingSlash(params.config.upstreamApiBase)
469
+ );
470
+ const tools = toOpenAiTools(params.body.tools);
471
+ const toolChoice = toOpenAiToolChoice(params.body.tool_choice);
472
+ const upstreamResponse = await fetch(upstreamUrl.toString(), {
473
+ method: "POST",
474
+ headers: {
475
+ "Content-Type": "application/json",
476
+ ...params.config.upstreamApiKey ? {
477
+ Authorization: `Bearer ${params.config.upstreamApiKey}`
478
+ } : {},
479
+ ...params.config.upstreamExtraHeaders ?? {}
480
+ },
481
+ body: JSON.stringify({
482
+ model,
483
+ messages: buildOpenAiMessages(params.body.input, params.body.instructions),
484
+ ...tools ? { tools } : {},
485
+ ...toolChoice ? { tool_choice: toolChoice } : {},
486
+ ...typeof params.body.max_output_tokens === "number" ? {
487
+ max_tokens: Math.max(
488
+ 1,
489
+ Math.trunc(readNumber(params.body.max_output_tokens) ?? 1)
490
+ )
491
+ } : {}
492
+ })
493
+ });
494
+ const rawText = await upstreamResponse.text();
495
+ let parsed;
496
+ try {
497
+ parsed = JSON.parse(rawText);
498
+ } catch {
499
+ throw new Error(`Bridge upstream returned invalid JSON: ${rawText.slice(0, 240)}`);
500
+ }
501
+ if (!upstreamResponse.ok) {
502
+ throw new Error(
503
+ readString2(parsed.error?.message) ?? rawText.slice(0, 240) ?? `HTTP ${upstreamResponse.status}`
504
+ );
505
+ }
506
+ return {
507
+ model,
508
+ response: parsed
509
+ };
510
+ }
511
+
512
+ // src/codex-openai-responses-bridge-stream.ts
513
+ function extractAssistantText(content) {
514
+ if (typeof content === "string") {
515
+ return content;
516
+ }
517
+ if (!Array.isArray(content)) {
518
+ return "";
519
+ }
520
+ return content.map((entry) => {
521
+ const record = readRecord(entry);
522
+ if (!record) {
523
+ return "";
524
+ }
525
+ const type = readString2(record.type);
526
+ if (type === "text" || type === "output_text") {
527
+ return readString2(record.text) ?? "";
528
+ }
529
+ return "";
530
+ }).filter(Boolean).join("");
531
+ }
532
+ function buildOpenResponsesOutputItems(response, responseId) {
533
+ const message = response.choices?.[0]?.message;
534
+ if (!message) {
535
+ return [];
536
+ }
537
+ const outputItems = [];
538
+ const text = extractAssistantText(message.content).trim();
539
+ if (text) {
540
+ outputItems.push({
541
+ type: "message",
542
+ id: `${responseId}:message:0`,
543
+ role: "assistant",
544
+ status: "completed",
545
+ content: [
546
+ {
547
+ type: "output_text",
548
+ text,
549
+ annotations: []
550
+ }
551
+ ]
552
+ });
553
+ }
554
+ const toolCalls = readArray(message.tool_calls);
555
+ toolCalls.forEach((entry, index) => {
556
+ const toolCall = readRecord(entry);
557
+ const fn = readRecord(toolCall?.function);
558
+ const name = readString2(fn?.name);
559
+ const argumentsText = readString2(fn?.arguments) ?? "{}";
560
+ if (!name) {
561
+ return;
562
+ }
563
+ const callId = readString2(toolCall?.id) ?? `${responseId}:call:${index}`;
564
+ outputItems.push({
565
+ type: "function_call",
566
+ id: `${responseId}:function:${index}`,
567
+ call_id: callId,
568
+ name,
569
+ arguments: argumentsText,
570
+ status: "completed"
571
+ });
572
+ });
573
+ return outputItems;
574
+ }
575
+ function buildUsage(response) {
576
+ const promptTokens = Math.max(0, Math.trunc(readNumber(response.usage?.prompt_tokens) ?? 0));
577
+ const completionTokens = Math.max(
578
+ 0,
579
+ Math.trunc(readNumber(response.usage?.completion_tokens) ?? 0)
580
+ );
581
+ const totalTokens = Math.max(
582
+ 0,
583
+ Math.trunc(readNumber(response.usage?.total_tokens) ?? promptTokens + completionTokens)
584
+ );
585
+ return {
586
+ input_tokens: promptTokens,
587
+ input_tokens_details: null,
588
+ output_tokens: completionTokens,
589
+ output_tokens_details: null,
590
+ total_tokens: totalTokens
591
+ };
592
+ }
593
+ function buildResponseResource(params) {
594
+ return {
595
+ id: params.responseId,
596
+ object: "response",
597
+ created_at: Math.floor(Date.now() / 1e3),
598
+ status: params.status ?? "completed",
599
+ model: params.model,
600
+ output: params.outputItems,
601
+ usage: params.usage,
602
+ error: null
603
+ };
604
+ }
605
+ function cloneRecord(value) {
606
+ return structuredClone(value);
607
+ }
608
+ function buildInProgressOutputItem(item) {
609
+ const type = readString2(item.type);
610
+ if (type === "message") {
611
+ return {
612
+ ...cloneRecord(item),
613
+ status: "in_progress",
614
+ content: []
615
+ };
616
+ }
617
+ if (type === "function_call") {
618
+ return {
619
+ ...cloneRecord(item),
620
+ status: "in_progress",
621
+ arguments: ""
622
+ };
623
+ }
624
+ return cloneRecord(item);
625
+ }
626
+ function writeMessageOutputItemEvents(params) {
627
+ const itemId = readString2(params.item.id);
628
+ const content = readArray(params.item.content);
629
+ const textPart = content.find((entry) => readString2(readRecord(entry)?.type) === "output_text");
630
+ const text = readString2(readRecord(textPart)?.text) ?? "";
631
+ writeSseEvent(params.response, "response.output_item.added", {
632
+ type: "response.output_item.added",
633
+ sequence_number: nextSequenceNumber(params.sequenceState),
634
+ output_index: params.outputIndex,
635
+ item: buildInProgressOutputItem(params.item)
636
+ });
637
+ if (itemId) {
638
+ writeSseEvent(params.response, "response.content_part.added", {
639
+ type: "response.content_part.added",
640
+ sequence_number: nextSequenceNumber(params.sequenceState),
641
+ output_index: params.outputIndex,
642
+ item_id: itemId,
643
+ content_index: 0,
644
+ part: {
645
+ type: "output_text",
646
+ text: "",
647
+ annotations: []
648
+ }
649
+ });
650
+ if (text) {
651
+ writeSseEvent(params.response, "response.output_text.delta", {
652
+ type: "response.output_text.delta",
653
+ sequence_number: nextSequenceNumber(params.sequenceState),
654
+ output_index: params.outputIndex,
655
+ item_id: itemId,
656
+ content_index: 0,
657
+ delta: text
658
+ });
659
+ }
660
+ writeSseEvent(params.response, "response.output_text.done", {
661
+ type: "response.output_text.done",
662
+ sequence_number: nextSequenceNumber(params.sequenceState),
663
+ output_index: params.outputIndex,
664
+ item_id: itemId,
665
+ content_index: 0,
666
+ text
667
+ });
668
+ writeSseEvent(params.response, "response.content_part.done", {
669
+ type: "response.content_part.done",
670
+ sequence_number: nextSequenceNumber(params.sequenceState),
671
+ output_index: params.outputIndex,
672
+ item_id: itemId,
673
+ content_index: 0,
674
+ part: {
675
+ type: "output_text",
676
+ text,
677
+ annotations: []
678
+ }
679
+ });
680
+ }
681
+ writeSseEvent(params.response, "response.output_item.done", {
682
+ type: "response.output_item.done",
683
+ sequence_number: nextSequenceNumber(params.sequenceState),
684
+ output_index: params.outputIndex,
685
+ item: params.item
686
+ });
687
+ }
688
+ function writeFunctionCallOutputItemEvents(params) {
689
+ const itemId = readString2(params.item.id);
690
+ const argumentsText = readString2(params.item.arguments) ?? "";
691
+ writeSseEvent(params.response, "response.output_item.added", {
692
+ type: "response.output_item.added",
693
+ sequence_number: nextSequenceNumber(params.sequenceState),
694
+ output_index: params.outputIndex,
695
+ item: buildInProgressOutputItem(params.item)
696
+ });
697
+ if (itemId && argumentsText) {
698
+ writeSseEvent(params.response, "response.function_call_arguments.delta", {
699
+ type: "response.function_call_arguments.delta",
700
+ sequence_number: nextSequenceNumber(params.sequenceState),
701
+ output_index: params.outputIndex,
702
+ item_id: itemId,
703
+ delta: argumentsText
704
+ });
705
+ }
706
+ if (itemId) {
707
+ writeSseEvent(params.response, "response.function_call_arguments.done", {
708
+ type: "response.function_call_arguments.done",
709
+ sequence_number: nextSequenceNumber(params.sequenceState),
710
+ output_index: params.outputIndex,
711
+ item_id: itemId,
712
+ arguments: argumentsText
713
+ });
714
+ }
715
+ writeSseEvent(params.response, "response.output_item.done", {
716
+ type: "response.output_item.done",
717
+ sequence_number: nextSequenceNumber(params.sequenceState),
718
+ output_index: params.outputIndex,
719
+ item: params.item
720
+ });
721
+ }
722
+ function writeResponseOutputItemEvents(params) {
723
+ params.outputItems.forEach((item, outputIndex) => {
724
+ const type = readString2(item.type);
725
+ if (type === "message") {
726
+ writeMessageOutputItemEvents({
727
+ response: params.response,
728
+ item,
729
+ outputIndex,
730
+ sequenceState: params.sequenceState
731
+ });
732
+ return;
733
+ }
734
+ if (type === "function_call") {
735
+ writeFunctionCallOutputItemEvents({
736
+ response: params.response,
737
+ item,
738
+ outputIndex,
739
+ sequenceState: params.sequenceState
740
+ });
741
+ return;
742
+ }
743
+ writeSseEvent(params.response, "response.output_item.done", {
744
+ type: "response.output_item.done",
745
+ sequence_number: nextSequenceNumber(params.sequenceState),
746
+ output_index: outputIndex,
747
+ item
748
+ });
749
+ });
750
+ }
751
+ function writeStreamError(response, message) {
752
+ response.statusCode = 200;
753
+ response.setHeader("content-type", "text/event-stream; charset=utf-8");
754
+ response.setHeader("cache-control", "no-cache, no-transform");
755
+ response.setHeader("connection", "keep-alive");
756
+ writeSseEvent(response, "error", {
757
+ type: "error",
758
+ error: {
759
+ code: "invalid_request_error",
760
+ message
761
+ }
762
+ });
763
+ response.end();
764
+ }
765
+ function buildBridgeResponsePayload(params) {
766
+ const outputItems = buildOpenResponsesOutputItems(params.response, params.responseId);
767
+ const usage = buildUsage(params.response);
768
+ return {
769
+ outputItems,
770
+ usage,
771
+ responseResource: buildResponseResource({
772
+ responseId: params.responseId,
773
+ model: params.model,
774
+ outputItems,
775
+ usage
776
+ })
777
+ };
778
+ }
779
+ function writeResponsesStream(params) {
780
+ const sequenceState = {
781
+ value: 0
782
+ };
783
+ params.response.statusCode = 200;
784
+ params.response.setHeader("content-type", "text/event-stream; charset=utf-8");
785
+ params.response.setHeader("cache-control", "no-cache, no-transform");
786
+ params.response.setHeader("connection", "keep-alive");
787
+ writeSseEvent(params.response, "response.created", {
788
+ type: "response.created",
789
+ sequence_number: nextSequenceNumber(sequenceState),
790
+ response: buildResponseResource({
791
+ responseId: params.responseId,
792
+ model: params.model,
793
+ outputItems: [],
794
+ usage: buildUsage({
795
+ usage: {}
796
+ }),
797
+ status: "in_progress"
798
+ })
799
+ });
800
+ writeResponseOutputItemEvents({
801
+ response: params.response,
802
+ outputItems: params.outputItems,
803
+ sequenceState
804
+ });
805
+ writeSseEvent(params.response, "response.completed", {
806
+ type: "response.completed",
807
+ sequence_number: nextSequenceNumber(sequenceState),
808
+ response: params.responseResource
809
+ });
810
+ params.response.end();
811
+ }
812
+
813
+ // src/codex-openai-responses-bridge.ts
814
+ var bridgeCache = /* @__PURE__ */ new Map();
815
+ function toBridgeCacheKey(config) {
816
+ return JSON.stringify({
817
+ upstreamApiBase: config.upstreamApiBase,
818
+ upstreamApiKey: config.upstreamApiKey ?? "",
819
+ upstreamExtraHeaders: config.upstreamExtraHeaders ?? {},
820
+ defaultModel: config.defaultModel ?? "",
821
+ modelPrefixes: (config.modelPrefixes ?? []).map((prefix) => prefix.trim().toLowerCase())
822
+ });
823
+ }
824
+ async function readJsonBody(request) {
825
+ const chunks = [];
826
+ for await (const chunk of request) {
827
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
828
+ }
829
+ const rawText = Buffer.concat(chunks).toString("utf8").trim();
830
+ if (!rawText) {
831
+ return {};
832
+ }
833
+ try {
834
+ return readRecord(JSON.parse(rawText)) ?? null;
835
+ } catch {
836
+ return null;
837
+ }
838
+ }
839
+ async function handleResponsesRequest(request, response, config) {
840
+ const body = await readJsonBody(request);
841
+ if (!body) {
842
+ response.statusCode = 400;
843
+ response.setHeader("content-type", "application/json");
844
+ response.end(
845
+ JSON.stringify({
846
+ error: {
847
+ message: "Invalid JSON payload."
848
+ }
849
+ })
850
+ );
851
+ return;
852
+ }
853
+ try {
854
+ const upstream = await callOpenAiCompatibleUpstream({
855
+ config,
856
+ body
857
+ });
858
+ const responseId = randomUUID();
859
+ const { outputItems, responseResource } = buildBridgeResponsePayload({
860
+ responseId,
861
+ model: upstream.model,
862
+ response: upstream.response
863
+ });
864
+ const wantsStream = readBoolean(body.stream) !== false;
865
+ if (wantsStream) {
866
+ writeResponsesStream({
867
+ response,
868
+ responseId,
869
+ model: upstream.model,
870
+ outputItems,
871
+ responseResource
872
+ });
873
+ return;
874
+ }
875
+ response.statusCode = 200;
876
+ response.setHeader("content-type", "application/json");
877
+ response.end(JSON.stringify(responseResource));
878
+ } catch (error) {
879
+ const message = error instanceof Error ? error.message : "Codex OpenAI bridge request failed.";
880
+ if (readBoolean(body.stream) !== false) {
881
+ writeStreamError(response, message);
882
+ return;
883
+ }
884
+ response.statusCode = 400;
885
+ response.setHeader("content-type", "application/json");
886
+ response.end(
887
+ JSON.stringify({
888
+ error: {
889
+ message
890
+ }
891
+ })
892
+ );
893
+ }
894
+ }
895
+ async function createCodexOpenAiResponsesBridge(config) {
896
+ const server = createServer((request, response) => {
897
+ const pathname = request.url ? new URL(request.url, "http://127.0.0.1").pathname : "/";
898
+ if (request.method === "POST" && (pathname === "/responses" || pathname === "/v1/responses")) {
899
+ void handleResponsesRequest(request, response, config);
900
+ return;
901
+ }
902
+ response.statusCode = 404;
903
+ response.setHeader("content-type", "application/json");
904
+ response.end(
905
+ JSON.stringify({
906
+ error: {
907
+ message: `Unsupported Codex bridge path: ${pathname}`
908
+ }
909
+ })
910
+ );
911
+ });
912
+ await new Promise((resolve, reject) => {
913
+ server.once("error", reject);
914
+ server.listen(0, "127.0.0.1", () => resolve());
915
+ });
916
+ const address = server.address();
917
+ if (!address || typeof address === "string") {
918
+ throw new Error("Codex bridge failed to bind a loopback port.");
919
+ }
920
+ return {
921
+ baseUrl: `http://127.0.0.1:${address.port}`
922
+ };
923
+ }
924
+ async function ensureCodexOpenAiResponsesBridge(config) {
925
+ const key = toBridgeCacheKey(config);
926
+ const existing = bridgeCache.get(key);
927
+ if (existing) {
928
+ return await existing.promise;
929
+ }
930
+ const promise = createCodexOpenAiResponsesBridge(config);
931
+ bridgeCache.set(key, { promise });
932
+ try {
933
+ return await promise;
934
+ } catch (error) {
935
+ bridgeCache.delete(key);
936
+ throw error;
937
+ }
938
+ }
939
+
940
+ // src/codex-responses-capability.ts
941
+ var codexResponsesProbeCache = /* @__PURE__ */ new Map();
942
+ function normalizeApiBase(value) {
943
+ return value.endsWith("/") ? value : `${value}/`;
944
+ }
945
+ function readErrorMessage(value) {
946
+ if (typeof value === "string") {
947
+ return value.trim();
948
+ }
949
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
950
+ return "";
951
+ }
952
+ const record = value;
953
+ return readString2(record.message) ?? readString2(record.error) ?? "";
954
+ }
955
+ function shouldTreatResponsesProbeFailureAsUnsupported(params) {
956
+ const normalizedMessage = params.message.trim().toLowerCase();
957
+ if (params.status === 404 || params.status === 405 || params.status === 501) {
958
+ return true;
959
+ }
960
+ if (params.status >= 500) {
961
+ return false;
962
+ }
963
+ return [
964
+ "unsupported model",
965
+ "not support",
966
+ "not supported",
967
+ "unsupported endpoint",
968
+ "unknown url",
969
+ "no route matched",
970
+ "responses api"
971
+ ].some((token) => normalizedMessage.includes(token));
972
+ }
973
+ async function probeCodexResponsesApiSupport(params) {
974
+ const cacheKey = JSON.stringify({
975
+ apiBase: params.apiBase,
976
+ apiKey: params.apiKey,
977
+ extraHeaders: params.extraHeaders ?? {},
978
+ model: params.model
979
+ });
980
+ const existing = codexResponsesProbeCache.get(cacheKey);
981
+ if (existing) {
982
+ return await existing;
983
+ }
984
+ const probePromise = (async () => {
985
+ const response = await fetch(new URL("responses", normalizeApiBase(params.apiBase)), {
986
+ method: "POST",
987
+ headers: {
988
+ "Content-Type": "application/json",
989
+ Authorization: `Bearer ${params.apiKey}`,
990
+ ...params.extraHeaders ?? {}
991
+ },
992
+ body: JSON.stringify({
993
+ model: params.model,
994
+ input: "ping",
995
+ max_output_tokens: 1,
996
+ stream: false
997
+ })
998
+ });
999
+ const rawText = await response.text();
1000
+ let parsed = null;
1001
+ try {
1002
+ parsed = JSON.parse(rawText);
1003
+ } catch {
1004
+ parsed = null;
1005
+ }
1006
+ const parsedRecord = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
1007
+ const message = readErrorMessage(parsedRecord?.error) || readErrorMessage(parsed) || rawText.slice(0, 240);
1008
+ const responseFailed = readString2(parsedRecord?.status)?.toLowerCase() === "failed" || Boolean(parsedRecord?.error);
1009
+ if (response.ok && !responseFailed) {
1010
+ return true;
1011
+ }
1012
+ return !shouldTreatResponsesProbeFailureAsUnsupported({
1013
+ status: response.status,
1014
+ message
1015
+ });
1016
+ })();
1017
+ codexResponsesProbeCache.set(cacheKey, probePromise);
1018
+ try {
1019
+ return await probePromise;
1020
+ } catch (error) {
1021
+ codexResponsesProbeCache.delete(cacheKey);
1022
+ throw error;
1023
+ }
1024
+ }
1025
+ async function resolveCodexResponsesApiSupport(params) {
1026
+ if (params.capabilitySpec?.supportsResponsesApi === true) {
1027
+ return true;
1028
+ }
1029
+ if (params.capabilitySpec?.supportsResponsesApi === false) {
1030
+ return false;
1031
+ }
1032
+ const explicitWireApi = readString2(params.wireApi)?.toLowerCase();
1033
+ if (explicitWireApi === "chat") {
1034
+ return false;
1035
+ }
1036
+ if (explicitWireApi === "responses") {
1037
+ return true;
1038
+ }
1039
+ return await probeCodexResponsesApiSupport({
1040
+ apiBase: params.apiBase,
1041
+ apiKey: params.apiKey,
1042
+ extraHeaders: params.extraHeaders,
1043
+ model: params.model
1044
+ });
1045
+ }
1046
+
1047
+ // src/codex-session-type.ts
1048
+ function readString3(value) {
1049
+ if (typeof value !== "string") {
1050
+ return void 0;
1051
+ }
1052
+ const trimmed = value.trim();
1053
+ return trimmed || void 0;
1054
+ }
1055
+ function readStringArray(value) {
1056
+ if (!Array.isArray(value)) {
1057
+ return void 0;
1058
+ }
1059
+ const values = value.map((entry) => readString3(entry)).filter((entry) => Boolean(entry));
1060
+ return values.length > 0 ? values : void 0;
1061
+ }
1062
+ function dedupeStrings(values) {
1063
+ return Array.from(new Set(values));
1064
+ }
1065
+ function resolveConfiguredCodexModels(params) {
1066
+ const explicitSupportedModels = readStringArray(params.pluginConfig.supportedModels);
1067
+ if (explicitSupportedModels) {
1068
+ return dedupeStrings(explicitSupportedModels);
1069
+ }
1070
+ const configuredProviders = params.config.providers && typeof params.config.providers === "object" && !Array.isArray(params.config.providers) ? params.config.providers : {};
1071
+ const configuredModels = Object.entries(configuredProviders).flatMap(
1072
+ ([providerName, provider]) => (provider.models ?? []).map((modelName) => readString3(modelName)).filter((modelName) => Boolean(modelName)).map((modelName) => `${providerName}/${modelName}`)
1073
+ );
1074
+ const fallbackModel = readString3(params.pluginConfig.model) ?? params.config.agents.defaults.model;
1075
+ const fallbackModels = fallbackModel ? [fallbackModel] : [];
1076
+ return dedupeStrings(configuredModels.length > 0 ? configuredModels : fallbackModels);
1077
+ }
1078
+ function resolveRecommendedCodexModel(params) {
1079
+ const configuredModel = readString3(params.pluginConfig.model) ?? params.config.agents.defaults.model;
1080
+ if (params.supportedModels.includes(configuredModel)) {
1081
+ return configuredModel;
1082
+ }
1083
+ return params.supportedModels[0] ?? configuredModel ?? null;
1084
+ }
1085
+ function createDescribeCodexSessionType(params) {
1086
+ return () => {
1087
+ const supportedModels = resolveConfiguredCodexModels(params);
1088
+ return {
1089
+ ready: true,
1090
+ reason: null,
1091
+ reasonMessage: null,
1092
+ supportedModels,
1093
+ recommendedModel: resolveRecommendedCodexModel({
1094
+ config: params.config,
1095
+ pluginConfig: params.pluginConfig,
1096
+ supportedModels
1097
+ }),
1098
+ cta: null
1099
+ };
1100
+ };
1101
+ }
1102
+
1103
+ // src/index.ts
1104
+ var PLUGIN_ID = "nextclaw-ncp-runtime-plugin-codex-sdk";
1105
+ var CODEX_RUNTIME_KIND = "codex";
1106
+ var DeferredCodexSdkNcpAgentRuntime = class {
24
1107
  constructor(createRuntime) {
25
1108
  this.createRuntime = createRuntime;
26
1109
  }
@@ -38,28 +1121,28 @@ class DeferredCodexSdkNcpAgentRuntime {
38
1121
  }.bind(this);
39
1122
  return stream();
40
1123
  }
41
- }
42
- function readString(value) {
1124
+ };
1125
+ function readString4(value) {
43
1126
  if (typeof value !== "string") {
44
1127
  return void 0;
45
1128
  }
46
1129
  const trimmed = value.trim();
47
1130
  return trimmed || void 0;
48
1131
  }
49
- function readBoolean(value) {
1132
+ function readBoolean2(value) {
50
1133
  return typeof value === "boolean" ? value : void 0;
51
1134
  }
52
- function readRecord(value) {
1135
+ function readRecord2(value) {
53
1136
  if (!value || typeof value !== "object" || Array.isArray(value)) {
54
1137
  return void 0;
55
1138
  }
56
1139
  return value;
57
1140
  }
58
- function readStringArray(value) {
1141
+ function readStringArray2(value) {
59
1142
  if (!Array.isArray(value)) {
60
1143
  return void 0;
61
1144
  }
62
- const values = value.map((entry) => readString(entry)).filter((entry) => Boolean(entry));
1145
+ const values = value.map((entry) => readString4(entry)).filter((entry) => Boolean(entry));
63
1146
  return values.length > 0 ? values : void 0;
64
1147
  }
65
1148
  function resolveCodexCapabilitySpec(params) {
@@ -95,25 +1178,25 @@ function readThinkingLevel(value) {
95
1178
  return void 0;
96
1179
  }
97
1180
  function resolveCodexExecutionOptions(params) {
98
- const configuredWorkingDirectory = readString(params.pluginConfig.workingDirectory);
1181
+ const configuredWorkingDirectory = readString4(params.pluginConfig.workingDirectory);
99
1182
  const workspace = getWorkspacePath(
100
1183
  configuredWorkingDirectory ?? params.config.agents.defaults.workspace
101
1184
  );
102
1185
  return {
103
1186
  workingDirectory: workspace,
104
- skipGitRepoCheck: readBoolean(params.pluginConfig.skipGitRepoCheck) ?? true
1187
+ skipGitRepoCheck: readBoolean2(params.pluginConfig.skipGitRepoCheck) ?? true
105
1188
  };
106
1189
  }
107
1190
  function resolveCodexCliConfig(params) {
108
- const explicitConfig = readRecord(params.pluginConfig.config);
109
- const modelProvider = readString(params.modelProviderOverride) ?? resolveExternalModelProvider({
1191
+ const explicitConfig = readRecord2(params.pluginConfig.config);
1192
+ const modelProvider = readString4(params.modelProviderOverride) ?? resolveExternalModelProvider({
110
1193
  explicitModelProvider: params.pluginConfig.modelProvider,
111
1194
  providerName: params.providerName,
112
1195
  providerDisplayName: params.providerDisplayName,
113
1196
  pluginId: PLUGIN_ID
114
1197
  });
115
- const preferredAuthMethod = readString(params.pluginConfig.preferredAuthMethod) ?? "apikey";
116
- const apiBase = readString(params.pluginConfig.apiBase) ?? readString(params.apiBase);
1198
+ const preferredAuthMethod = readString4(params.pluginConfig.preferredAuthMethod) ?? "apikey";
1199
+ const apiBase = readString4(params.pluginConfig.apiBase) ?? readString4(params.apiBase);
117
1200
  const config = {
118
1201
  model_provider: modelProvider,
119
1202
  preferred_auth_method: preferredAuthMethod
@@ -134,9 +1217,9 @@ function resolveCodexCliConfig(params) {
134
1217
  };
135
1218
  }
136
1219
  function resolveCodexModel(params) {
137
- return readString(params.sessionMetadata.preferred_model) ?? readString(params.sessionMetadata.model) ?? readString(params.pluginConfig.model) ?? params.config.agents.defaults.model;
1220
+ return readString4(params.sessionMetadata.preferred_model) ?? readString4(params.sessionMetadata.model) ?? readString4(params.pluginConfig.model) ?? params.config.agents.defaults.model;
138
1221
  }
139
- const plugin = {
1222
+ var plugin = {
140
1223
  id: PLUGIN_ID,
141
1224
  name: "NextClaw Codex NCP Runtime",
142
1225
  description: "Registers NCP session type `codex` backed by OpenAI Codex SDK.",
@@ -146,7 +1229,7 @@ const plugin = {
146
1229
  properties: {}
147
1230
  },
148
1231
  register(api) {
149
- const pluginConfig = readRecord(api.pluginConfig) ?? {};
1232
+ const pluginConfig = readRecord2(api.pluginConfig) ?? {};
150
1233
  const describeCodexSessionType = createDescribeCodexSessionType({
151
1234
  config: api.config,
152
1235
  pluginConfig
@@ -180,8 +1263,8 @@ const plugin = {
180
1263
  providerLocalModel: resolvedProviderRuntime.providerLocalModel,
181
1264
  resolvedModel: resolvedProviderRuntime.resolvedModel
182
1265
  });
183
- const upstreamApiBase = readString(pluginConfig.apiBase) ?? resolvedProviderRuntime.apiBase ?? void 0;
184
- const apiKey = readString(pluginConfig.apiKey) ?? resolvedProviderRuntime.apiKey ?? void 0;
1266
+ const upstreamApiBase = readString4(pluginConfig.apiBase) ?? resolvedProviderRuntime.apiBase ?? void 0;
1267
+ const apiKey = readString4(pluginConfig.apiKey) ?? resolvedProviderRuntime.apiKey ?? void 0;
185
1268
  if (!apiKey) {
186
1269
  throw new Error(
187
1270
  `[codex] missing apiKey. Set plugins.entries.${PLUGIN_ID}.config.apiKey or providers.*.apiKey for model "${userFacingModelRoute}".`
@@ -196,7 +1279,7 @@ const plugin = {
196
1279
  let codexModelProviderOverride;
197
1280
  const supportsResponsesApi = await resolveCodexResponsesApiSupport({
198
1281
  capabilitySpec,
199
- wireApi: readString(resolvedProviderRuntime.provider?.wireApi),
1282
+ wireApi: readString4(resolvedProviderRuntime.provider?.wireApi),
200
1283
  apiBase: upstreamApiBase,
201
1284
  apiKey,
202
1285
  extraHeaders: resolvedProviderRuntime.provider?.extraHeaders ?? null,
@@ -223,14 +1306,15 @@ const plugin = {
223
1306
  config: nextConfig,
224
1307
  pluginConfig
225
1308
  });
1309
+ const accessMode = resolveCodexAccessMode(pluginConfig);
226
1310
  const thinkingLevel = readThinkingLevel(runtimeParams.sessionMetadata.preferred_thinking) ?? readThinkingLevel(runtimeParams.sessionMetadata.thinking) ?? void 0;
227
1311
  return new CodexSdkNcpAgentRuntime({
228
1312
  sessionId: runtimeParams.sessionId,
229
1313
  apiKey,
230
1314
  apiBase: codexApiBase,
231
1315
  model: resolvedProviderRuntime.providerLocalModel,
232
- threadId: readString(runtimeParams.sessionMetadata.codex_thread_id) ?? null,
233
- codexPathOverride: readString(pluginConfig.codexPathOverride),
1316
+ threadId: readString4(runtimeParams.sessionMetadata.codex_thread_id) ?? null,
1317
+ codexPathOverride: readString4(pluginConfig.codexPathOverride),
234
1318
  env: readStringRecord(pluginConfig.env),
235
1319
  cliConfig: resolveCodexCliConfig({
236
1320
  pluginConfig,
@@ -245,15 +1329,15 @@ const plugin = {
245
1329
  inputBuilder: buildCodexInputBuilder(executionOptions.workingDirectory),
246
1330
  threadOptions: {
247
1331
  model,
248
- sandboxMode: readString(pluginConfig.sandboxMode),
1332
+ sandboxMode: mapAccessModeToSandboxMode(accessMode),
249
1333
  workingDirectory: executionOptions.workingDirectory,
250
1334
  skipGitRepoCheck: executionOptions.skipGitRepoCheck,
251
1335
  modelReasoningEffort: thinkingLevel,
252
- networkAccessEnabled: readBoolean(pluginConfig.networkAccessEnabled),
253
- webSearchMode: readString(pluginConfig.webSearchMode),
254
- webSearchEnabled: readBoolean(pluginConfig.webSearchEnabled),
255
- approvalPolicy: readString(pluginConfig.approvalPolicy),
256
- additionalDirectories: readStringArray(pluginConfig.additionalDirectories)
1336
+ networkAccessEnabled: readBoolean2(pluginConfig.networkAccessEnabled),
1337
+ webSearchMode: readString4(pluginConfig.webSearchMode),
1338
+ webSearchEnabled: readBoolean2(pluginConfig.webSearchEnabled),
1339
+ approvalPolicy: CODEX_APPROVAL_POLICY,
1340
+ additionalDirectories: readStringArray2(pluginConfig.additionalDirectories)
257
1341
  }
258
1342
  });
259
1343
  });