@nextclaw/nextclaw-ncp-runtime-plugin-codex-sdk 0.1.23 → 0.1.25

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.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { Config } from '@nextclaw/core';
2
1
  import { NcpAgentRuntime } from '@nextclaw/ncp';
3
2
  import { RuntimeFactoryParams } from '@nextclaw/ncp-toolkit';
4
3
 
@@ -15,9 +14,45 @@ type SessionTypeDescriptor = {
15
14
  } | null;
16
15
  };
17
16
 
17
+ type ResolvedProviderSpec = {
18
+ isGateway?: boolean;
19
+ isLocal?: boolean;
20
+ supportsResponsesApi?: boolean;
21
+ };
22
+ type ResolvedProviderConfig = {
23
+ wireApi?: string | null;
24
+ extraHeaders?: Record<string, string> | null;
25
+ };
26
+ type ResolvedProviderRuntime = {
27
+ resolvedModel: string;
28
+ providerLocalModel: string;
29
+ provider: ResolvedProviderConfig | null;
30
+ providerName: string | null;
31
+ providerDisplayName: string | null;
32
+ providerSpec: ResolvedProviderSpec | null;
33
+ apiKey: string | null;
34
+ apiBase: string | null;
35
+ };
36
+ type AgentRuntimeApi = {
37
+ defaults: {
38
+ workspace?: string;
39
+ model?: string;
40
+ };
41
+ resolveWorkspacePath: (workspace?: string) => string;
42
+ resolveProviderRuntime: (model?: string) => ResolvedProviderRuntime;
43
+ buildRuntimeUserPrompt: (params: {
44
+ workspace?: string;
45
+ sessionKey?: string;
46
+ metadata?: Record<string, unknown>;
47
+ userMessage: string;
48
+ }) => string;
49
+ };
18
50
  type PluginApi = {
19
- config: Config;
51
+ config?: Record<string, unknown>;
20
52
  pluginConfig?: Record<string, unknown>;
53
+ runtime: {
54
+ agent: AgentRuntimeApi;
55
+ };
21
56
  registerNcpAgentRuntime: (registration: {
22
57
  kind: string;
23
58
  label?: string;
package/dist/index.js CHANGED
@@ -1,10 +1,4 @@
1
1
  // src/index.ts
2
- import {
3
- findProviderByModel,
4
- findProviderByName,
5
- resolveProviderRuntime,
6
- getWorkspacePath
7
- } from "@nextclaw/core";
8
2
  import {
9
3
  CodexSdkNcpAgentRuntime
10
4
  } from "@nextclaw/nextclaw-ncp-runtime-codex-sdk";
@@ -97,24 +91,6 @@ function resolveCodexAccessMode(pluginConfig) {
97
91
  }
98
92
 
99
93
  // src/codex-input-builder.ts
100
- import {
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
94
  function readUserText(input) {
119
95
  for (let index = input.messages.length - 1; index >= 0; index -= 1) {
120
96
  const message = input.messages[index];
@@ -128,13 +104,16 @@ function readUserText(input) {
128
104
  }
129
105
  return "";
130
106
  }
131
- function buildCodexInputBuilder(workspace) {
132
- const skillsLoader = new SkillsLoader(workspace);
107
+ function buildCodexInputBuilder(runtimeAgent, workspace) {
133
108
  return async (input) => {
134
109
  const userText = readUserText(input);
135
110
  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);
111
+ return runtimeAgent.buildRuntimeUserPrompt({
112
+ workspace,
113
+ sessionKey: input.sessionId,
114
+ metadata,
115
+ userMessage: userText
116
+ });
138
117
  };
139
118
  }
140
119
 
@@ -143,7 +122,7 @@ import { randomUUID } from "crypto";
143
122
  import { createServer } from "http";
144
123
 
145
124
  // src/codex-openai-responses-bridge-shared.ts
146
- function readString2(value) {
125
+ function readString(value) {
147
126
  if (typeof value !== "string") {
148
127
  return void 0;
149
128
  }
@@ -201,7 +180,7 @@ function stripModelPrefix(model, prefixes) {
201
180
  }
202
181
  function resolveUpstreamModel(requestedModel, config) {
203
182
  const prefixes = (config.modelPrefixes ?? []).filter((value) => value.trim().length > 0);
204
- const model = stripModelPrefix(readString2(requestedModel) ?? "", prefixes) || stripModelPrefix(config.defaultModel ?? "", prefixes);
183
+ const model = stripModelPrefix(readString(requestedModel) ?? "", prefixes) || stripModelPrefix(config.defaultModel ?? "", prefixes);
205
184
  if (!model) {
206
185
  throw new Error("Codex bridge could not resolve an upstream model.");
207
186
  }
@@ -212,27 +191,27 @@ function normalizeTextPart(value) {
212
191
  if (!record) {
213
192
  return "";
214
193
  }
215
- const type = readString2(record.type);
194
+ const type = readString(record.type);
216
195
  if (type !== "input_text" && type !== "output_text") {
217
196
  return "";
218
197
  }
219
- return readString2(record.text) ?? "";
198
+ return readString(record.text) ?? "";
220
199
  }
221
200
  function normalizeImageUrl(value) {
222
201
  const record = readRecord(value);
223
- if (!record || readString2(record.type) !== "input_image") {
202
+ if (!record || readString(record.type) !== "input_image") {
224
203
  return null;
225
204
  }
226
205
  const source = readRecord(record.source);
227
206
  if (!source) {
228
207
  return null;
229
208
  }
230
- if (readString2(source.type) === "url") {
231
- return readString2(source.url) ?? null;
209
+ if (readString(source.type) === "url") {
210
+ return readString(source.url) ?? null;
232
211
  }
233
- if (readString2(source.type) === "base64") {
234
- const mediaType = readString2(source.media_type) ?? "application/octet-stream";
235
- const data = readString2(source.data);
212
+ if (readString(source.type) === "base64") {
213
+ const mediaType = readString(source.media_type) ?? "application/octet-stream";
214
+ const data = readString(source.data);
236
215
  if (!data) {
237
216
  return null;
238
217
  }
@@ -288,7 +267,7 @@ function buildChatContent(content) {
288
267
  }
289
268
  const textOnly = chatContent.every((entry) => entry.type === "text");
290
269
  if (textOnly) {
291
- return chatContent.map((entry) => readString2(entry.text) ?? "").join("\n");
270
+ return chatContent.map((entry) => readString(entry.text) ?? "").join("\n");
292
271
  }
293
272
  return chatContent;
294
273
  }
@@ -299,10 +278,10 @@ function readAssistantMessageText(content) {
299
278
  if (!Array.isArray(content)) {
300
279
  return "";
301
280
  }
302
- return content.filter((entry) => entry.type === "text").map((entry) => readString2(entry.text) ?? "").join("\n");
281
+ return content.filter((entry) => entry.type === "text").map((entry) => readString(entry.text) ?? "").join("\n");
303
282
  }
304
283
  function appendMessageInputItem(params) {
305
- const role = readString2(params.item.role);
284
+ const role = readString(params.item.role);
306
285
  const content = buildChatContent(params.item.content);
307
286
  if (role === "assistant") {
308
287
  const text = readAssistantMessageText(content);
@@ -321,12 +300,12 @@ function appendMessageInputItem(params) {
321
300
  }
322
301
  }
323
302
  function appendFunctionCallItem(params) {
324
- const name = readString2(params.item.name);
325
- const argumentsText = readString2(params.item.arguments) ?? "{}";
303
+ const name = readString(params.item.name);
304
+ const argumentsText = readString(params.item.arguments) ?? "{}";
326
305
  if (!name) {
327
306
  return;
328
307
  }
329
- const callId = readString2(params.item.call_id) ?? readString2(params.item.id) ?? `call_${params.assistantToolCalls.length}`;
308
+ const callId = readString(params.item.call_id) ?? readString(params.item.id) ?? `call_${params.assistantToolCalls.length}`;
330
309
  params.assistantToolCalls.push({
331
310
  id: callId,
332
311
  type: "function",
@@ -338,7 +317,7 @@ function appendFunctionCallItem(params) {
338
317
  }
339
318
  function appendFunctionCallOutputItem(params) {
340
319
  params.flushAssistant();
341
- const callId = readString2(params.item.call_id);
320
+ const callId = readString(params.item.call_id);
342
321
  if (!callId) {
343
322
  return;
344
323
  }
@@ -350,7 +329,7 @@ function appendFunctionCallOutputItem(params) {
350
329
  }
351
330
  function buildOpenAiMessages(input, instructions) {
352
331
  const messages = [];
353
- const instructionText = readString2(instructions);
332
+ const instructionText = readString(instructions);
354
333
  if (instructionText) {
355
334
  messages.push({
356
335
  role: "system",
@@ -387,7 +366,7 @@ function buildOpenAiMessages(input, instructions) {
387
366
  if (!item) {
388
367
  continue;
389
368
  }
390
- const type = readString2(item.type);
369
+ const type = readString(item.type);
391
370
  if (type === "message") {
392
371
  appendMessageInputItem({
393
372
  messages,
@@ -420,13 +399,13 @@ function toOpenAiTools(value) {
420
399
  const tools = [];
421
400
  for (const entry of readArray(value)) {
422
401
  const tool = readRecord(entry);
423
- const type = readString2(tool?.type);
402
+ const type = readString(tool?.type);
424
403
  const fn = readRecord(tool?.function);
425
- const name = readString2(fn?.name) ?? readString2(tool?.name);
404
+ const name = readString(fn?.name) ?? readString(tool?.name);
426
405
  if (type !== "function" || !name) {
427
406
  continue;
428
407
  }
429
- const description = (fn ? readString2(fn.description) : void 0) ?? readString2(tool?.description);
408
+ const description = (fn ? readString(fn.description) : void 0) ?? readString(tool?.description);
430
409
  const parameters = (fn ? readRecord(fn.parameters) : void 0) ?? readRecord(tool?.parameters);
431
410
  const strict = (fn ? readBoolean(fn.strict) : void 0) ?? readBoolean(tool?.strict);
432
411
  tools.push({
@@ -450,8 +429,8 @@ function toOpenAiToolChoice(value) {
450
429
  }
451
430
  const record = readRecord(value);
452
431
  const fn = readRecord(record?.function);
453
- const name = readString2(fn?.name) ?? readString2(record?.name);
454
- if (readString2(record?.type) === "function" && name) {
432
+ const name = readString(fn?.name) ?? readString(record?.name);
433
+ if (readString(record?.type) === "function" && name) {
455
434
  return {
456
435
  type: "function",
457
436
  function: {
@@ -500,7 +479,7 @@ async function callOpenAiCompatibleUpstream(params) {
500
479
  }
501
480
  if (!upstreamResponse.ok) {
502
481
  throw new Error(
503
- readString2(parsed.error?.message) ?? rawText.slice(0, 240) ?? `HTTP ${upstreamResponse.status}`
482
+ readString(parsed.error?.message) ?? rawText.slice(0, 240) ?? `HTTP ${upstreamResponse.status}`
504
483
  );
505
484
  }
506
485
  return {
@@ -522,9 +501,9 @@ function extractAssistantText(content) {
522
501
  if (!record) {
523
502
  return "";
524
503
  }
525
- const type = readString2(record.type);
504
+ const type = readString(record.type);
526
505
  if (type === "text" || type === "output_text") {
527
- return readString2(record.text) ?? "";
506
+ return readString(record.text) ?? "";
528
507
  }
529
508
  return "";
530
509
  }).filter(Boolean).join("");
@@ -555,12 +534,12 @@ function buildOpenResponsesOutputItems(response, responseId) {
555
534
  toolCalls.forEach((entry, index) => {
556
535
  const toolCall = readRecord(entry);
557
536
  const fn = readRecord(toolCall?.function);
558
- const name = readString2(fn?.name);
559
- const argumentsText = readString2(fn?.arguments) ?? "{}";
537
+ const name = readString(fn?.name);
538
+ const argumentsText = readString(fn?.arguments) ?? "{}";
560
539
  if (!name) {
561
540
  return;
562
541
  }
563
- const callId = readString2(toolCall?.id) ?? `${responseId}:call:${index}`;
542
+ const callId = readString(toolCall?.id) ?? `${responseId}:call:${index}`;
564
543
  outputItems.push({
565
544
  type: "function_call",
566
545
  id: `${responseId}:function:${index}`,
@@ -606,7 +585,7 @@ function cloneRecord(value) {
606
585
  return structuredClone(value);
607
586
  }
608
587
  function buildInProgressOutputItem(item) {
609
- const type = readString2(item.type);
588
+ const type = readString(item.type);
610
589
  if (type === "message") {
611
590
  return {
612
591
  ...cloneRecord(item),
@@ -624,10 +603,10 @@ function buildInProgressOutputItem(item) {
624
603
  return cloneRecord(item);
625
604
  }
626
605
  function writeMessageOutputItemEvents(params) {
627
- const itemId = readString2(params.item.id);
606
+ const itemId = readString(params.item.id);
628
607
  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) ?? "";
608
+ const textPart = content.find((entry) => readString(readRecord(entry)?.type) === "output_text");
609
+ const text = readString(readRecord(textPart)?.text) ?? "";
631
610
  writeSseEvent(params.response, "response.output_item.added", {
632
611
  type: "response.output_item.added",
633
612
  sequence_number: nextSequenceNumber(params.sequenceState),
@@ -686,8 +665,8 @@ function writeMessageOutputItemEvents(params) {
686
665
  });
687
666
  }
688
667
  function writeFunctionCallOutputItemEvents(params) {
689
- const itemId = readString2(params.item.id);
690
- const argumentsText = readString2(params.item.arguments) ?? "";
668
+ const itemId = readString(params.item.id);
669
+ const argumentsText = readString(params.item.arguments) ?? "";
691
670
  writeSseEvent(params.response, "response.output_item.added", {
692
671
  type: "response.output_item.added",
693
672
  sequence_number: nextSequenceNumber(params.sequenceState),
@@ -721,7 +700,7 @@ function writeFunctionCallOutputItemEvents(params) {
721
700
  }
722
701
  function writeResponseOutputItemEvents(params) {
723
702
  params.outputItems.forEach((item, outputIndex) => {
724
- const type = readString2(item.type);
703
+ const type = readString(item.type);
725
704
  if (type === "message") {
726
705
  writeMessageOutputItemEvents({
727
706
  response: params.response,
@@ -950,7 +929,7 @@ function readErrorMessage(value) {
950
929
  return "";
951
930
  }
952
931
  const record = value;
953
- return readString2(record.message) ?? readString2(record.error) ?? "";
932
+ return readString(record.message) ?? readString(record.error) ?? "";
954
933
  }
955
934
  function shouldTreatResponsesProbeFailureAsUnsupported(params) {
956
935
  const normalizedMessage = params.message.trim().toLowerCase();
@@ -1005,7 +984,7 @@ async function probeCodexResponsesApiSupport(params) {
1005
984
  }
1006
985
  const parsedRecord = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
1007
986
  const message = readErrorMessage(parsedRecord?.error) || readErrorMessage(parsed) || rawText.slice(0, 240);
1008
- const responseFailed = readString2(parsedRecord?.status)?.toLowerCase() === "failed" || Boolean(parsedRecord?.error);
987
+ const responseFailed = readString(parsedRecord?.status)?.toLowerCase() === "failed" || Boolean(parsedRecord?.error);
1009
988
  if (response.ok && !responseFailed) {
1010
989
  return true;
1011
990
  }
@@ -1029,7 +1008,7 @@ async function resolveCodexResponsesApiSupport(params) {
1029
1008
  if (params.capabilitySpec?.supportsResponsesApi === false) {
1030
1009
  return false;
1031
1010
  }
1032
- const explicitWireApi = readString2(params.wireApi)?.toLowerCase();
1011
+ const explicitWireApi = readString(params.wireApi)?.toLowerCase();
1033
1012
  if (explicitWireApi === "chat") {
1034
1013
  return false;
1035
1014
  }
@@ -1045,7 +1024,7 @@ async function resolveCodexResponsesApiSupport(params) {
1045
1024
  }
1046
1025
 
1047
1026
  // src/codex-session-type.ts
1048
- function readString3(value) {
1027
+ function readString2(value) {
1049
1028
  if (typeof value !== "string") {
1050
1029
  return void 0;
1051
1030
  }
@@ -1056,47 +1035,51 @@ function readStringArray(value) {
1056
1035
  if (!Array.isArray(value)) {
1057
1036
  return void 0;
1058
1037
  }
1059
- const values = value.map((entry) => readString3(entry)).filter((entry) => Boolean(entry));
1038
+ const values = value.map((entry) => readString2(entry)).filter((entry) => Boolean(entry));
1060
1039
  return values.length > 0 ? values : void 0;
1061
1040
  }
1062
1041
  function dedupeStrings(values) {
1063
1042
  return Array.from(new Set(values));
1064
1043
  }
1065
- function resolveConfiguredCodexModels(params) {
1066
- const explicitSupportedModels = readStringArray(params.pluginConfig.supportedModels);
1067
- if (explicitSupportedModels) {
1068
- return dedupeStrings(explicitSupportedModels);
1044
+ function resolveConfiguredCodexModels(pluginConfig) {
1045
+ const explicitSupportedModels = readStringArray(pluginConfig.supportedModels);
1046
+ if (!explicitSupportedModels) {
1047
+ return void 0;
1069
1048
  }
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);
1049
+ const normalizedModels = dedupeStrings(explicitSupportedModels);
1050
+ if (normalizedModels.includes("*")) {
1051
+ return void 0;
1052
+ }
1053
+ return normalizedModels;
1077
1054
  }
1078
1055
  function resolveRecommendedCodexModel(params) {
1079
- const configuredModel = readString3(params.pluginConfig.model) ?? params.config.agents.defaults.model;
1080
- if (params.supportedModels.includes(configuredModel)) {
1056
+ const configuredModel = readString2(params.pluginConfig.model) ?? params.defaultModel;
1057
+ if (!configuredModel) {
1058
+ return params.supportedModels?.[0] ?? null;
1059
+ }
1060
+ if (!params.supportedModels || params.supportedModels.includes(configuredModel)) {
1081
1061
  return configuredModel;
1082
1062
  }
1083
1063
  return params.supportedModels[0] ?? configuredModel ?? null;
1084
1064
  }
1085
1065
  function createDescribeCodexSessionType(params) {
1086
1066
  return () => {
1087
- const supportedModels = resolveConfiguredCodexModels(params);
1088
- return {
1067
+ const supportedModels = resolveConfiguredCodexModels(params.pluginConfig);
1068
+ const descriptor = {
1089
1069
  ready: true,
1090
1070
  reason: null,
1091
1071
  reasonMessage: null,
1092
- supportedModels,
1093
1072
  recommendedModel: resolveRecommendedCodexModel({
1094
- config: params.config,
1073
+ defaultModel: params.defaultModel,
1095
1074
  pluginConfig: params.pluginConfig,
1096
1075
  supportedModels
1097
1076
  }),
1098
1077
  cta: null
1099
1078
  };
1079
+ if (supportedModels) {
1080
+ descriptor.supportedModels = supportedModels;
1081
+ }
1082
+ return descriptor;
1100
1083
  };
1101
1084
  }
1102
1085
 
@@ -1122,7 +1105,7 @@ var DeferredCodexSdkNcpAgentRuntime = class {
1122
1105
  return stream();
1123
1106
  }
1124
1107
  };
1125
- function readString4(value) {
1108
+ function readString3(value) {
1126
1109
  if (typeof value !== "string") {
1127
1110
  return void 0;
1128
1111
  }
@@ -1142,14 +1125,9 @@ function readStringArray2(value) {
1142
1125
  if (!Array.isArray(value)) {
1143
1126
  return void 0;
1144
1127
  }
1145
- const values = value.map((entry) => readString4(entry)).filter((entry) => Boolean(entry));
1128
+ const values = value.map((entry) => readString3(entry)).filter((entry) => Boolean(entry));
1146
1129
  return values.length > 0 ? values : void 0;
1147
1130
  }
1148
- function resolveCodexCapabilitySpec(params) {
1149
- const providerSpec = params.providerName ? findProviderByName(params.providerName) : void 0;
1150
- const modelSpec = params.model ? findProviderByModel(params.model) : void 0;
1151
- return providerSpec?.isGateway ? modelSpec ?? providerSpec : providerSpec ?? modelSpec;
1152
- }
1153
1131
  function readStringRecord(value) {
1154
1132
  if (!value || typeof value !== "object" || Array.isArray(value)) {
1155
1133
  return void 0;
@@ -1178,9 +1156,9 @@ function readThinkingLevel(value) {
1178
1156
  return void 0;
1179
1157
  }
1180
1158
  function resolveCodexExecutionOptions(params) {
1181
- const configuredWorkingDirectory = readString4(params.pluginConfig.workingDirectory);
1182
- const workspace = getWorkspacePath(
1183
- configuredWorkingDirectory ?? params.config.agents.defaults.workspace
1159
+ const configuredWorkingDirectory = readString3(params.pluginConfig.workingDirectory);
1160
+ const workspace = params.runtimeAgent.resolveWorkspacePath(
1161
+ configuredWorkingDirectory ?? params.runtimeAgent.defaults.workspace
1184
1162
  );
1185
1163
  return {
1186
1164
  workingDirectory: workspace,
@@ -1189,14 +1167,14 @@ function resolveCodexExecutionOptions(params) {
1189
1167
  }
1190
1168
  function resolveCodexCliConfig(params) {
1191
1169
  const explicitConfig = readRecord2(params.pluginConfig.config);
1192
- const modelProvider = readString4(params.modelProviderOverride) ?? resolveExternalModelProvider({
1170
+ const modelProvider = readString3(params.modelProviderOverride) ?? resolveExternalModelProvider({
1193
1171
  explicitModelProvider: params.pluginConfig.modelProvider,
1194
1172
  providerName: params.providerName,
1195
1173
  providerDisplayName: params.providerDisplayName,
1196
1174
  pluginId: PLUGIN_ID
1197
1175
  });
1198
- const preferredAuthMethod = readString4(params.pluginConfig.preferredAuthMethod) ?? "apikey";
1199
- const apiBase = readString4(params.pluginConfig.apiBase) ?? readString4(params.apiBase);
1176
+ const preferredAuthMethod = readString3(params.pluginConfig.preferredAuthMethod) ?? "apikey";
1177
+ const apiBase = readString3(params.pluginConfig.apiBase) ?? readString3(params.apiBase);
1200
1178
  const config = {
1201
1179
  model_provider: modelProvider,
1202
1180
  preferred_auth_method: preferredAuthMethod
@@ -1217,7 +1195,7 @@ function resolveCodexCliConfig(params) {
1217
1195
  };
1218
1196
  }
1219
1197
  function resolveCodexModel(params) {
1220
- return readString4(params.sessionMetadata.preferred_model) ?? readString4(params.sessionMetadata.model) ?? readString4(params.pluginConfig.model) ?? params.config.agents.defaults.model;
1198
+ return readString3(params.sessionMetadata.preferred_model) ?? readString3(params.sessionMetadata.model) ?? readString3(params.pluginConfig.model) ?? params.runtimeAgent.defaults.model ?? "";
1221
1199
  }
1222
1200
  var plugin = {
1223
1201
  id: PLUGIN_ID,
@@ -1231,7 +1209,7 @@ var plugin = {
1231
1209
  register(api) {
1232
1210
  const pluginConfig = readRecord2(api.pluginConfig) ?? {};
1233
1211
  const describeCodexSessionType = createDescribeCodexSessionType({
1234
- config: api.config,
1212
+ defaultModel: readString3(api.runtime.agent.defaults.model),
1235
1213
  pluginConfig
1236
1214
  });
1237
1215
  api.registerNcpAgentRuntime({
@@ -1240,22 +1218,19 @@ var plugin = {
1240
1218
  describeSessionType: describeCodexSessionType,
1241
1219
  createRuntime: (runtimeParams) => {
1242
1220
  return new DeferredCodexSdkNcpAgentRuntime(async () => {
1243
- const nextConfig = api.config;
1244
1221
  const model = resolveCodexModel({
1245
- config: nextConfig,
1222
+ runtimeAgent: api.runtime.agent,
1246
1223
  pluginConfig,
1247
1224
  sessionMetadata: runtimeParams.sessionMetadata
1248
1225
  });
1249
- const resolvedProviderRuntime = resolveProviderRuntime(nextConfig, model);
1226
+ const resolvedProviderRuntime = api.runtime.agent.resolveProviderRuntime(model);
1250
1227
  const providerName = resolvedProviderRuntime.providerName;
1251
- const capabilitySpec = resolveCodexCapabilitySpec({
1252
- model,
1253
- providerName
1254
- });
1228
+ const capabilitySpec = resolvedProviderRuntime.providerSpec ?? null;
1229
+ const providerDisplayName = resolvedProviderRuntime.providerDisplayName;
1255
1230
  const externalModelProvider = resolveExternalModelProvider({
1256
1231
  explicitModelProvider: pluginConfig.modelProvider,
1257
1232
  providerName,
1258
- providerDisplayName: resolvedProviderRuntime.providerDisplayName,
1233
+ providerDisplayName,
1259
1234
  pluginId: PLUGIN_ID
1260
1235
  });
1261
1236
  const userFacingModelRoute = buildUserFacingModelRoute({
@@ -1263,8 +1238,8 @@ var plugin = {
1263
1238
  providerLocalModel: resolvedProviderRuntime.providerLocalModel,
1264
1239
  resolvedModel: resolvedProviderRuntime.resolvedModel
1265
1240
  });
1266
- const upstreamApiBase = readString4(pluginConfig.apiBase) ?? resolvedProviderRuntime.apiBase ?? void 0;
1267
- const apiKey = readString4(pluginConfig.apiKey) ?? resolvedProviderRuntime.apiKey ?? void 0;
1241
+ const upstreamApiBase = readString3(pluginConfig.apiBase) ?? resolvedProviderRuntime.apiBase ?? void 0;
1242
+ const apiKey = readString3(pluginConfig.apiKey) ?? resolvedProviderRuntime.apiKey ?? void 0;
1268
1243
  if (!apiKey) {
1269
1244
  throw new Error(
1270
1245
  `[codex] missing apiKey. Set plugins.entries.${PLUGIN_ID}.config.apiKey or providers.*.apiKey for model "${userFacingModelRoute}".`
@@ -1279,7 +1254,7 @@ var plugin = {
1279
1254
  let codexModelProviderOverride;
1280
1255
  const supportsResponsesApi = await resolveCodexResponsesApiSupport({
1281
1256
  capabilitySpec,
1282
- wireApi: readString4(resolvedProviderRuntime.provider?.wireApi),
1257
+ wireApi: readString3(resolvedProviderRuntime.provider?.wireApi),
1283
1258
  apiBase: upstreamApiBase,
1284
1259
  apiKey,
1285
1260
  extraHeaders: resolvedProviderRuntime.provider?.extraHeaders ?? null,
@@ -1303,7 +1278,7 @@ var plugin = {
1303
1278
  );
1304
1279
  }
1305
1280
  const executionOptions = resolveCodexExecutionOptions({
1306
- config: nextConfig,
1281
+ runtimeAgent: api.runtime.agent,
1307
1282
  pluginConfig
1308
1283
  });
1309
1284
  const accessMode = resolveCodexAccessMode(pluginConfig);
@@ -1313,20 +1288,23 @@ var plugin = {
1313
1288
  apiKey,
1314
1289
  apiBase: codexApiBase,
1315
1290
  model: resolvedProviderRuntime.providerLocalModel,
1316
- threadId: readString4(runtimeParams.sessionMetadata.codex_thread_id) ?? null,
1317
- codexPathOverride: readString4(pluginConfig.codexPathOverride),
1291
+ threadId: readString3(runtimeParams.sessionMetadata.codex_thread_id) ?? null,
1292
+ codexPathOverride: readString3(pluginConfig.codexPathOverride),
1318
1293
  env: readStringRecord(pluginConfig.env),
1319
1294
  cliConfig: resolveCodexCliConfig({
1320
1295
  pluginConfig,
1321
1296
  providerName,
1322
- providerDisplayName: resolvedProviderRuntime.providerDisplayName,
1297
+ providerDisplayName,
1323
1298
  apiBase: codexApiBase,
1324
1299
  modelProviderOverride: codexModelProviderOverride
1325
1300
  }),
1326
1301
  stateManager: runtimeParams.stateManager,
1327
1302
  sessionMetadata: runtimeParams.sessionMetadata,
1328
1303
  setSessionMetadata: runtimeParams.setSessionMetadata,
1329
- inputBuilder: buildCodexInputBuilder(executionOptions.workingDirectory),
1304
+ inputBuilder: buildCodexInputBuilder(
1305
+ api.runtime.agent,
1306
+ executionOptions.workingDirectory
1307
+ ),
1330
1308
  threadOptions: {
1331
1309
  model,
1332
1310
  sandboxMode: mapAccessModeToSandboxMode(accessMode),
@@ -1334,7 +1312,7 @@ var plugin = {
1334
1312
  skipGitRepoCheck: executionOptions.skipGitRepoCheck,
1335
1313
  modelReasoningEffort: thinkingLevel,
1336
1314
  networkAccessEnabled: readBoolean2(pluginConfig.networkAccessEnabled),
1337
- webSearchMode: readString4(pluginConfig.webSearchMode),
1315
+ webSearchMode: readString3(pluginConfig.webSearchMode),
1338
1316
  webSearchEnabled: readBoolean2(pluginConfig.webSearchEnabled),
1339
1317
  approvalPolicy: CODEX_APPROVAL_POLICY,
1340
1318
  additionalDirectories: readStringArray2(pluginConfig.additionalDirectories)
@@ -17,6 +17,12 @@
17
17
  "model": {
18
18
  "type": "string"
19
19
  },
20
+ "supportedModels": {
21
+ "type": "array",
22
+ "items": {
23
+ "type": "string"
24
+ }
25
+ },
20
26
  "modelProvider": {
21
27
  "type": "string"
22
28
  },
@@ -74,6 +80,11 @@
74
80
  "model": {
75
81
  "label": "Default Model"
76
82
  },
83
+ "supportedModels": {
84
+ "label": "Supported Models",
85
+ "help": "Optional advanced allowlist. Leave empty for no model restriction. Use [\"*\"] to explicitly allow any model.",
86
+ "advanced": true
87
+ },
77
88
  "modelProvider": {
78
89
  "label": "External Model Provider",
79
90
  "help": "Optional override for the provider id exposed to Codex SDK. Recommended for custom providers whose display name is not the actual upstream provider id.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/nextclaw-ncp-runtime-plugin-codex-sdk",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "private": false,
5
5
  "description": "NextClaw plugin that registers Codex SDK as an optional NCP runtime.",
6
6
  "type": "module",
@@ -21,10 +21,9 @@
21
21
  ]
22
22
  },
23
23
  "dependencies": {
24
- "@nextclaw/core": "0.11.2",
25
- "@nextclaw/ncp": "0.3.3",
26
- "@nextclaw/ncp-toolkit": "0.4.3",
27
- "@nextclaw/nextclaw-ncp-runtime-codex-sdk": "0.1.4"
24
+ "@nextclaw/ncp": "0.4.0",
25
+ "@nextclaw/ncp-toolkit": "0.4.4",
26
+ "@nextclaw/nextclaw-ncp-runtime-codex-sdk": "0.1.5"
28
27
  },
29
28
  "devDependencies": {
30
29
  "@types/node": "^20.17.6",