@nextclaw/nextclaw-ncp-runtime-plugin-codex-sdk 0.1.19 → 0.1.21
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.js +45 -6
- package/dist/index.js +2 -8
- package/openclaw.plugin.json +12 -6
- package/package.json +3 -3
|
@@ -2,6 +2,9 @@ import {
|
|
|
2
2
|
buildRequestedSkillsUserPrompt,
|
|
3
3
|
SkillsLoader
|
|
4
4
|
} from "@nextclaw/core";
|
|
5
|
+
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { join } from "node:path";
|
|
5
8
|
function readString(value) {
|
|
6
9
|
if (typeof value !== "string") {
|
|
7
10
|
return void 0;
|
|
@@ -17,25 +20,61 @@ function readRequestedSkills(metadata) {
|
|
|
17
20
|
return raw.map((entry) => readString(entry)).filter((entry) => Boolean(entry)).slice(0, 8);
|
|
18
21
|
}
|
|
19
22
|
function readUserText(input) {
|
|
23
|
+
const message = readLatestUserMessage(input);
|
|
24
|
+
if (!message) {
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
return message.parts.filter((part) => part.type === "text").map((part) => part.text).join("").trim();
|
|
28
|
+
}
|
|
29
|
+
function readLatestUserMessage(input) {
|
|
20
30
|
for (let index = input.messages.length - 1; index >= 0; index -= 1) {
|
|
21
31
|
const message = input.messages[index];
|
|
22
32
|
if (message?.role !== "user") {
|
|
23
33
|
continue;
|
|
24
34
|
}
|
|
25
|
-
|
|
26
|
-
if (text) {
|
|
27
|
-
return text;
|
|
28
|
-
}
|
|
35
|
+
return message;
|
|
29
36
|
}
|
|
30
|
-
return
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
function sanitizeFileName(name) {
|
|
40
|
+
const sanitized = name.trim().replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
41
|
+
return sanitized || "attachment";
|
|
42
|
+
}
|
|
43
|
+
function buildAttachmentPrompt(message) {
|
|
44
|
+
if (!message) {
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
const fileParts = message.parts.filter((part) => part.type === "file");
|
|
48
|
+
if (fileParts.length === 0) {
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
const tempDir = mkdtempSync(join(tmpdir(), "nextclaw-codex-files-"));
|
|
52
|
+
const lines = fileParts.map((part, index) => {
|
|
53
|
+
const rawName = readString(part.name) ?? `attachment-${index + 1}`;
|
|
54
|
+
const fileName = sanitizeFileName(rawName);
|
|
55
|
+
const mimeSegment = readString(part.mimeType) ? ` (${part.mimeType})` : "";
|
|
56
|
+
const contentBase64 = readString(part.contentBase64);
|
|
57
|
+
if (contentBase64) {
|
|
58
|
+
const filePath = join(tempDir, fileName);
|
|
59
|
+
writeFileSync(filePath, Buffer.from(contentBase64.replace(/\s+/g, ""), "base64"));
|
|
60
|
+
return `- ${fileName}${mimeSegment} -> local file: ${filePath}`;
|
|
61
|
+
}
|
|
62
|
+
if (readString(part.url)) {
|
|
63
|
+
return `- ${fileName}${mimeSegment} -> remote url: ${part.url}`;
|
|
64
|
+
}
|
|
65
|
+
return `- ${fileName}${mimeSegment}`;
|
|
66
|
+
});
|
|
67
|
+
return ["Attached files for this turn:", ...lines].join("\n");
|
|
31
68
|
}
|
|
32
69
|
function buildCodexInputBuilder(workspace) {
|
|
33
70
|
const skillsLoader = new SkillsLoader(workspace);
|
|
34
71
|
return async (input) => {
|
|
35
72
|
const userText = readUserText(input);
|
|
73
|
+
const attachmentPrompt = buildAttachmentPrompt(readLatestUserMessage(input));
|
|
74
|
+
const promptBody = [userText || (attachmentPrompt ? "Please inspect the attached file(s) and respond." : ""), attachmentPrompt].filter(Boolean).join("\n\n");
|
|
36
75
|
const metadata = input.metadata && typeof input.metadata === "object" && !Array.isArray(input.metadata) ? input.metadata : {};
|
|
37
76
|
const requestedSkills = readRequestedSkills(metadata);
|
|
38
|
-
return buildRequestedSkillsUserPrompt(skillsLoader, requestedSkills,
|
|
77
|
+
return buildRequestedSkillsUserPrompt(skillsLoader, requestedSkills, promptBody);
|
|
39
78
|
};
|
|
40
79
|
}
|
|
41
80
|
export {
|
package/dist/index.js
CHANGED
|
@@ -12,11 +12,6 @@ import {
|
|
|
12
12
|
buildCodexBridgeModelProviderId,
|
|
13
13
|
resolveExternalModelProvider
|
|
14
14
|
} from "./codex-model-provider.js";
|
|
15
|
-
import {
|
|
16
|
-
CODEX_APPROVAL_POLICY,
|
|
17
|
-
mapAccessModeToSandboxMode,
|
|
18
|
-
resolveCodexAccessMode
|
|
19
|
-
} from "./codex-access-mode.js";
|
|
20
15
|
import { buildCodexInputBuilder } from "./codex-input-builder.js";
|
|
21
16
|
import { ensureCodexOpenAiResponsesBridge } from "./codex-openai-responses-bridge.js";
|
|
22
17
|
import { resolveCodexResponsesApiSupport } from "./codex-responses-capability.js";
|
|
@@ -228,7 +223,6 @@ const plugin = {
|
|
|
228
223
|
config: nextConfig,
|
|
229
224
|
pluginConfig
|
|
230
225
|
});
|
|
231
|
-
const accessMode = resolveCodexAccessMode(pluginConfig);
|
|
232
226
|
const thinkingLevel = readThinkingLevel(runtimeParams.sessionMetadata.preferred_thinking) ?? readThinkingLevel(runtimeParams.sessionMetadata.thinking) ?? void 0;
|
|
233
227
|
return new CodexSdkNcpAgentRuntime({
|
|
234
228
|
sessionId: runtimeParams.sessionId,
|
|
@@ -251,14 +245,14 @@ const plugin = {
|
|
|
251
245
|
inputBuilder: buildCodexInputBuilder(executionOptions.workingDirectory),
|
|
252
246
|
threadOptions: {
|
|
253
247
|
model,
|
|
254
|
-
sandboxMode:
|
|
248
|
+
sandboxMode: readString(pluginConfig.sandboxMode),
|
|
255
249
|
workingDirectory: executionOptions.workingDirectory,
|
|
256
250
|
skipGitRepoCheck: executionOptions.skipGitRepoCheck,
|
|
257
251
|
modelReasoningEffort: thinkingLevel,
|
|
258
252
|
networkAccessEnabled: readBoolean(pluginConfig.networkAccessEnabled),
|
|
259
253
|
webSearchMode: readString(pluginConfig.webSearchMode),
|
|
260
254
|
webSearchEnabled: readBoolean(pluginConfig.webSearchEnabled),
|
|
261
|
-
approvalPolicy:
|
|
255
|
+
approvalPolicy: readString(pluginConfig.approvalPolicy),
|
|
262
256
|
additionalDirectories: readStringArray(pluginConfig.additionalDirectories)
|
|
263
257
|
}
|
|
264
258
|
});
|
package/openclaw.plugin.json
CHANGED
|
@@ -23,10 +23,9 @@
|
|
|
23
23
|
"workingDirectory": {
|
|
24
24
|
"type": "string"
|
|
25
25
|
},
|
|
26
|
-
"
|
|
26
|
+
"sandboxMode": {
|
|
27
27
|
"type": "string",
|
|
28
|
-
"enum": ["read-only", "workspace-write", "full-access"]
|
|
29
|
-
"default": "full-access"
|
|
28
|
+
"enum": ["read-only", "workspace-write", "danger-full-access"]
|
|
30
29
|
},
|
|
31
30
|
"skipGitRepoCheck": {
|
|
32
31
|
"type": "boolean"
|
|
@@ -41,6 +40,10 @@
|
|
|
41
40
|
"webSearchEnabled": {
|
|
42
41
|
"type": "boolean"
|
|
43
42
|
},
|
|
43
|
+
"approvalPolicy": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"enum": ["never", "on-request", "on-failure", "untrusted"]
|
|
46
|
+
},
|
|
44
47
|
"codexPathOverride": {
|
|
45
48
|
"type": "string"
|
|
46
49
|
},
|
|
@@ -83,9 +86,12 @@
|
|
|
83
86
|
"label": "Working Directory",
|
|
84
87
|
"advanced": true
|
|
85
88
|
},
|
|
86
|
-
"
|
|
87
|
-
"label": "
|
|
88
|
-
"
|
|
89
|
+
"sandboxMode": {
|
|
90
|
+
"label": "Sandbox Mode",
|
|
91
|
+
"advanced": true
|
|
92
|
+
},
|
|
93
|
+
"approvalPolicy": {
|
|
94
|
+
"label": "Approval Policy",
|
|
89
95
|
"advanced": true
|
|
90
96
|
},
|
|
91
97
|
"networkAccessEnabled": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/nextclaw-ncp-runtime-plugin-codex-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "NextClaw plugin that registers Codex SDK as an optional NCP runtime.",
|
|
6
6
|
"type": "module",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@nextclaw/core": "0.11.0",
|
|
25
25
|
"@nextclaw/nextclaw-ncp-runtime-codex-sdk": "0.1.3",
|
|
26
|
-
"@nextclaw/ncp
|
|
27
|
-
"@nextclaw/ncp": "0.
|
|
26
|
+
"@nextclaw/ncp": "0.3.2",
|
|
27
|
+
"@nextclaw/ncp-toolkit": "0.4.2"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "^20.17.6",
|