@nextclaw/nextclaw-ncp-runtime-plugin-codex-sdk 0.1.15 → 0.1.16
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/codex-input-builder.d.ts +5 -0
- package/dist/codex-input-builder.js +43 -0
- package/dist/codex-model-provider.d.ts +2 -1
- package/dist/codex-model-provider.js +8 -0
- package/dist/codex-openai-responses-bridge-request.d.ts +11 -0
- package/dist/codex-openai-responses-bridge-request.js +334 -0
- package/dist/codex-openai-responses-bridge-shared.d.ts +47 -0
- package/dist/codex-openai-responses-bridge-shared.js +50 -0
- package/dist/codex-openai-responses-bridge-stream.d.ts +22 -0
- package/dist/codex-openai-responses-bridge-stream.js +312 -0
- package/dist/codex-openai-responses-bridge.d.ts +5 -0
- package/dist/codex-openai-responses-bridge.js +140 -0
- package/dist/codex-responses-capability.d.ts +12 -0
- package/dist/codex-responses-capability.js +109 -0
- package/dist/codex-session-type.d.ts +20 -0
- package/dist/codex-session-type.js +57 -0
- package/dist/index.d.ts +1 -13
- package/dist/index.js +121 -100
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,23 +1,44 @@
|
|
|
1
1
|
import {
|
|
2
2
|
findProviderByModel,
|
|
3
3
|
findProviderByName,
|
|
4
|
-
buildRequestedSkillsUserPrompt,
|
|
5
4
|
resolveProviderRuntime,
|
|
6
|
-
getWorkspacePath
|
|
7
|
-
SkillsLoader
|
|
5
|
+
getWorkspacePath
|
|
8
6
|
} from "@nextclaw/core";
|
|
9
7
|
import {
|
|
10
8
|
CodexSdkNcpAgentRuntime
|
|
11
9
|
} from "@nextclaw/nextclaw-ncp-runtime-codex-sdk";
|
|
12
10
|
import {
|
|
13
11
|
buildUserFacingModelRoute,
|
|
12
|
+
buildCodexBridgeModelProviderId,
|
|
14
13
|
resolveExternalModelProvider
|
|
15
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";
|
|
16
18
|
import {
|
|
17
19
|
createDescribeCodexSessionType
|
|
18
20
|
} from "./codex-session-type.js";
|
|
19
21
|
const PLUGIN_ID = "nextclaw-ncp-runtime-plugin-codex-sdk";
|
|
20
22
|
const CODEX_RUNTIME_KIND = "codex";
|
|
23
|
+
class DeferredCodexSdkNcpAgentRuntime {
|
|
24
|
+
constructor(createRuntime) {
|
|
25
|
+
this.createRuntime = createRuntime;
|
|
26
|
+
}
|
|
27
|
+
runtimePromise = null;
|
|
28
|
+
run(input, options) {
|
|
29
|
+
const resolveRuntime = async () => {
|
|
30
|
+
if (!this.runtimePromise) {
|
|
31
|
+
this.runtimePromise = this.createRuntime();
|
|
32
|
+
}
|
|
33
|
+
return await this.runtimePromise;
|
|
34
|
+
};
|
|
35
|
+
const stream = async function* () {
|
|
36
|
+
const runtime = await resolveRuntime();
|
|
37
|
+
yield* runtime.run(input, options);
|
|
38
|
+
}.bind(this);
|
|
39
|
+
return stream();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
21
42
|
function readString(value) {
|
|
22
43
|
if (typeof value !== "string") {
|
|
23
44
|
return void 0;
|
|
@@ -85,7 +106,7 @@ function resolveCodexExecutionOptions(params) {
|
|
|
85
106
|
}
|
|
86
107
|
function resolveCodexCliConfig(params) {
|
|
87
108
|
const explicitConfig = readRecord(params.pluginConfig.config);
|
|
88
|
-
const modelProvider = resolveExternalModelProvider({
|
|
109
|
+
const modelProvider = readString(params.modelProviderOverride) ?? resolveExternalModelProvider({
|
|
89
110
|
explicitModelProvider: params.pluginConfig.modelProvider,
|
|
90
111
|
providerName: params.providerName,
|
|
91
112
|
providerDisplayName: params.providerDisplayName,
|
|
@@ -112,35 +133,6 @@ function resolveCodexCliConfig(params) {
|
|
|
112
133
|
...explicitConfig ?? {}
|
|
113
134
|
};
|
|
114
135
|
}
|
|
115
|
-
function readRequestedSkills(metadata) {
|
|
116
|
-
const raw = metadata.requested_skills ?? metadata.requestedSkills;
|
|
117
|
-
if (!Array.isArray(raw)) {
|
|
118
|
-
return [];
|
|
119
|
-
}
|
|
120
|
-
return raw.map((entry) => readString(entry)).filter((entry) => Boolean(entry)).slice(0, 8);
|
|
121
|
-
}
|
|
122
|
-
function readUserText(input) {
|
|
123
|
-
for (let index = input.messages.length - 1; index >= 0; index -= 1) {
|
|
124
|
-
const message = input.messages[index];
|
|
125
|
-
if (message?.role !== "user") {
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
const text = message.parts.filter((part) => part.type === "text").map((part) => part.text).join("").trim();
|
|
129
|
-
if (text) {
|
|
130
|
-
return text;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return "";
|
|
134
|
-
}
|
|
135
|
-
function buildCodexInputBuilder(workspace) {
|
|
136
|
-
const skillsLoader = new SkillsLoader(workspace);
|
|
137
|
-
return async (input) => {
|
|
138
|
-
const userText = readUserText(input);
|
|
139
|
-
const metadata = input.metadata && typeof input.metadata === "object" && !Array.isArray(input.metadata) ? input.metadata : {};
|
|
140
|
-
const requestedSkills = readRequestedSkills(metadata);
|
|
141
|
-
return buildRequestedSkillsUserPrompt(skillsLoader, requestedSkills, userText);
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
136
|
function resolveCodexModel(params) {
|
|
145
137
|
return readString(params.sessionMetadata.preferred_model) ?? readString(params.sessionMetadata.model) ?? readString(params.pluginConfig.model) ?? params.config.agents.defaults.model;
|
|
146
138
|
}
|
|
@@ -164,77 +156,106 @@ const plugin = {
|
|
|
164
156
|
label: "Codex",
|
|
165
157
|
describeSessionType: describeCodexSessionType,
|
|
166
158
|
createRuntime: (runtimeParams) => {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
sessionMetadata: runtimeParams.sessionMetadata
|
|
172
|
-
});
|
|
173
|
-
const resolvedProviderRuntime = resolveProviderRuntime(nextConfig, model);
|
|
174
|
-
const providerName = resolvedProviderRuntime.providerName;
|
|
175
|
-
const capabilitySpec = resolveCodexCapabilitySpec({
|
|
176
|
-
model,
|
|
177
|
-
providerName
|
|
178
|
-
});
|
|
179
|
-
const externalModelProvider = resolveExternalModelProvider({
|
|
180
|
-
explicitModelProvider: pluginConfig.modelProvider,
|
|
181
|
-
providerName,
|
|
182
|
-
providerDisplayName: resolvedProviderRuntime.providerDisplayName,
|
|
183
|
-
pluginId: PLUGIN_ID
|
|
184
|
-
});
|
|
185
|
-
const userFacingModelRoute = buildUserFacingModelRoute({
|
|
186
|
-
externalModelProvider,
|
|
187
|
-
providerLocalModel: resolvedProviderRuntime.providerLocalModel,
|
|
188
|
-
resolvedModel: resolvedProviderRuntime.resolvedModel
|
|
189
|
-
});
|
|
190
|
-
const apiBase = readString(pluginConfig.apiBase) ?? resolvedProviderRuntime.apiBase ?? void 0;
|
|
191
|
-
const apiKey = readString(pluginConfig.apiKey) ?? resolvedProviderRuntime.apiKey ?? void 0;
|
|
192
|
-
if (!apiKey) {
|
|
193
|
-
throw new Error(
|
|
194
|
-
`[codex] missing apiKey. Set plugins.entries.${PLUGIN_ID}.config.apiKey or providers.*.apiKey for model "${userFacingModelRoute}".`
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
if (capabilitySpec?.supportsResponsesApi === false) {
|
|
198
|
-
const capabilityProviderName = capabilitySpec.displayName ?? capabilitySpec.name ?? resolvedProviderRuntime.providerDisplayName ?? externalModelProvider;
|
|
199
|
-
throw new Error(
|
|
200
|
-
`[codex] model "${userFacingModelRoute}" is routed through "${capabilityProviderName}", which does not support the Responses API. Codex SDK currently only supports models available through the Responses API.`
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
const executionOptions = resolveCodexExecutionOptions({
|
|
204
|
-
config: nextConfig,
|
|
205
|
-
pluginConfig
|
|
206
|
-
});
|
|
207
|
-
const thinkingLevel = readThinkingLevel(runtimeParams.sessionMetadata.preferred_thinking) ?? readThinkingLevel(runtimeParams.sessionMetadata.thinking) ?? void 0;
|
|
208
|
-
return new CodexSdkNcpAgentRuntime({
|
|
209
|
-
sessionId: runtimeParams.sessionId,
|
|
210
|
-
apiKey,
|
|
211
|
-
apiBase,
|
|
212
|
-
model: resolvedProviderRuntime.providerLocalModel,
|
|
213
|
-
threadId: readString(runtimeParams.sessionMetadata.codex_thread_id) ?? null,
|
|
214
|
-
codexPathOverride: readString(pluginConfig.codexPathOverride),
|
|
215
|
-
env: readStringRecord(pluginConfig.env),
|
|
216
|
-
cliConfig: resolveCodexCliConfig({
|
|
159
|
+
return new DeferredCodexSdkNcpAgentRuntime(async () => {
|
|
160
|
+
const nextConfig = api.config;
|
|
161
|
+
const model = resolveCodexModel({
|
|
162
|
+
config: nextConfig,
|
|
217
163
|
pluginConfig,
|
|
164
|
+
sessionMetadata: runtimeParams.sessionMetadata
|
|
165
|
+
});
|
|
166
|
+
const resolvedProviderRuntime = resolveProviderRuntime(nextConfig, model);
|
|
167
|
+
const providerName = resolvedProviderRuntime.providerName;
|
|
168
|
+
const capabilitySpec = resolveCodexCapabilitySpec({
|
|
169
|
+
model,
|
|
170
|
+
providerName
|
|
171
|
+
});
|
|
172
|
+
const externalModelProvider = resolveExternalModelProvider({
|
|
173
|
+
explicitModelProvider: pluginConfig.modelProvider,
|
|
218
174
|
providerName,
|
|
219
175
|
providerDisplayName: resolvedProviderRuntime.providerDisplayName,
|
|
220
|
-
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
176
|
+
pluginId: PLUGIN_ID
|
|
177
|
+
});
|
|
178
|
+
const userFacingModelRoute = buildUserFacingModelRoute({
|
|
179
|
+
externalModelProvider,
|
|
180
|
+
providerLocalModel: resolvedProviderRuntime.providerLocalModel,
|
|
181
|
+
resolvedModel: resolvedProviderRuntime.resolvedModel
|
|
182
|
+
});
|
|
183
|
+
const upstreamApiBase = readString(pluginConfig.apiBase) ?? resolvedProviderRuntime.apiBase ?? void 0;
|
|
184
|
+
const apiKey = readString(pluginConfig.apiKey) ?? resolvedProviderRuntime.apiKey ?? void 0;
|
|
185
|
+
if (!apiKey) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`[codex] missing apiKey. Set plugins.entries.${PLUGIN_ID}.config.apiKey or providers.*.apiKey for model "${userFacingModelRoute}".`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
if (!upstreamApiBase) {
|
|
191
|
+
throw new Error(
|
|
192
|
+
`[codex] missing apiBase for model "${userFacingModelRoute}". Configure plugins.entries.${PLUGIN_ID}.config.apiBase or providers.*.apiBase.`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
let codexApiBase = upstreamApiBase;
|
|
196
|
+
let codexModelProviderOverride;
|
|
197
|
+
const supportsResponsesApi = await resolveCodexResponsesApiSupport({
|
|
198
|
+
capabilitySpec,
|
|
199
|
+
wireApi: readString(resolvedProviderRuntime.provider?.wireApi),
|
|
200
|
+
apiBase: upstreamApiBase,
|
|
201
|
+
apiKey,
|
|
202
|
+
extraHeaders: resolvedProviderRuntime.provider?.extraHeaders ?? null,
|
|
203
|
+
model: resolvedProviderRuntime.providerLocalModel
|
|
204
|
+
});
|
|
205
|
+
if (!supportsResponsesApi) {
|
|
206
|
+
const bridge = await ensureCodexOpenAiResponsesBridge({
|
|
207
|
+
upstreamApiBase,
|
|
208
|
+
upstreamApiKey: apiKey,
|
|
209
|
+
upstreamExtraHeaders: resolvedProviderRuntime.provider?.extraHeaders ?? void 0,
|
|
210
|
+
defaultModel: resolvedProviderRuntime.providerLocalModel,
|
|
211
|
+
modelPrefixes: [
|
|
212
|
+
providerName ?? "",
|
|
213
|
+
externalModelProvider,
|
|
214
|
+
resolvedProviderRuntime.providerDisplayName ?? ""
|
|
215
|
+
]
|
|
216
|
+
});
|
|
217
|
+
codexApiBase = bridge.baseUrl;
|
|
218
|
+
codexModelProviderOverride = buildCodexBridgeModelProviderId(
|
|
219
|
+
externalModelProvider
|
|
220
|
+
);
|
|
237
221
|
}
|
|
222
|
+
const executionOptions = resolveCodexExecutionOptions({
|
|
223
|
+
config: nextConfig,
|
|
224
|
+
pluginConfig
|
|
225
|
+
});
|
|
226
|
+
const thinkingLevel = readThinkingLevel(runtimeParams.sessionMetadata.preferred_thinking) ?? readThinkingLevel(runtimeParams.sessionMetadata.thinking) ?? void 0;
|
|
227
|
+
return new CodexSdkNcpAgentRuntime({
|
|
228
|
+
sessionId: runtimeParams.sessionId,
|
|
229
|
+
apiKey,
|
|
230
|
+
apiBase: codexApiBase,
|
|
231
|
+
model: resolvedProviderRuntime.providerLocalModel,
|
|
232
|
+
threadId: readString(runtimeParams.sessionMetadata.codex_thread_id) ?? null,
|
|
233
|
+
codexPathOverride: readString(pluginConfig.codexPathOverride),
|
|
234
|
+
env: readStringRecord(pluginConfig.env),
|
|
235
|
+
cliConfig: resolveCodexCliConfig({
|
|
236
|
+
pluginConfig,
|
|
237
|
+
providerName,
|
|
238
|
+
providerDisplayName: resolvedProviderRuntime.providerDisplayName,
|
|
239
|
+
apiBase: codexApiBase,
|
|
240
|
+
modelProviderOverride: codexModelProviderOverride
|
|
241
|
+
}),
|
|
242
|
+
stateManager: runtimeParams.stateManager,
|
|
243
|
+
sessionMetadata: runtimeParams.sessionMetadata,
|
|
244
|
+
setSessionMetadata: runtimeParams.setSessionMetadata,
|
|
245
|
+
inputBuilder: buildCodexInputBuilder(executionOptions.workingDirectory),
|
|
246
|
+
threadOptions: {
|
|
247
|
+
model,
|
|
248
|
+
sandboxMode: readString(pluginConfig.sandboxMode),
|
|
249
|
+
workingDirectory: executionOptions.workingDirectory,
|
|
250
|
+
skipGitRepoCheck: executionOptions.skipGitRepoCheck,
|
|
251
|
+
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)
|
|
257
|
+
}
|
|
258
|
+
});
|
|
238
259
|
});
|
|
239
260
|
}
|
|
240
261
|
});
|