@nextclaw/nextclaw-ncp-runtime-plugin-codex-sdk 0.1.0
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/LICENSE +21 -0
- package/README.md +11 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +168 -0
- package/openclaw.plugin.json +98 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NextClaw contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# @nextclaw/nextclaw-ncp-runtime-plugin-codex-sdk
|
|
2
|
+
|
|
3
|
+
Plugin package that registers the `codex` NCP session type for NextClaw.
|
|
4
|
+
|
|
5
|
+
It composes the pure runtime library from `@nextclaw/nextclaw-ncp-runtime-codex-sdk` and exposes it through the standard plugin system.
|
|
6
|
+
|
|
7
|
+
## Build
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm -C packages/extensions/nextclaw-ncp-runtime-plugin-codex-sdk build
|
|
11
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Config } from '@nextclaw/core';
|
|
2
|
+
import { NcpAgentRuntime } from '@nextclaw/ncp';
|
|
3
|
+
import { RuntimeFactoryParams } from '@nextclaw/ncp-toolkit';
|
|
4
|
+
|
|
5
|
+
type PluginApi = {
|
|
6
|
+
config: Config;
|
|
7
|
+
pluginConfig?: Record<string, unknown>;
|
|
8
|
+
registerNcpAgentRuntime: (registration: {
|
|
9
|
+
kind: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
createRuntime: (params: RuntimeFactoryParams) => NcpAgentRuntime;
|
|
12
|
+
}) => void;
|
|
13
|
+
};
|
|
14
|
+
type PluginDefinition = {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
configSchema: Record<string, unknown>;
|
|
19
|
+
register: (api: PluginApi) => void;
|
|
20
|
+
};
|
|
21
|
+
declare const plugin: PluginDefinition;
|
|
22
|
+
|
|
23
|
+
export { plugin as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getApiBase,
|
|
3
|
+
getProvider,
|
|
4
|
+
getWorkspacePath,
|
|
5
|
+
SkillsLoader
|
|
6
|
+
} from "@nextclaw/core";
|
|
7
|
+
import {
|
|
8
|
+
CodexSdkNcpAgentRuntime
|
|
9
|
+
} from "@nextclaw/nextclaw-ncp-runtime-codex-sdk";
|
|
10
|
+
const PLUGIN_ID = "nextclaw-ncp-runtime-plugin-codex-sdk";
|
|
11
|
+
const CODEX_RUNTIME_KIND = "codex";
|
|
12
|
+
function readString(value) {
|
|
13
|
+
if (typeof value !== "string") {
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
const trimmed = value.trim();
|
|
17
|
+
return trimmed || void 0;
|
|
18
|
+
}
|
|
19
|
+
function readBoolean(value) {
|
|
20
|
+
return typeof value === "boolean" ? value : void 0;
|
|
21
|
+
}
|
|
22
|
+
function readRecord(value) {
|
|
23
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
24
|
+
return void 0;
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
function readStringArray(value) {
|
|
29
|
+
if (!Array.isArray(value)) {
|
|
30
|
+
return void 0;
|
|
31
|
+
}
|
|
32
|
+
const values = value.map((entry) => readString(entry)).filter((entry) => Boolean(entry));
|
|
33
|
+
return values.length > 0 ? values : void 0;
|
|
34
|
+
}
|
|
35
|
+
function readStringRecord(value) {
|
|
36
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
const out = {};
|
|
40
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
41
|
+
if (typeof entryValue !== "string") {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const normalized = entryValue.trim();
|
|
45
|
+
if (!normalized) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
out[entryKey] = normalized;
|
|
49
|
+
}
|
|
50
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
51
|
+
}
|
|
52
|
+
function readThinkingLevel(value) {
|
|
53
|
+
if (typeof value !== "string") {
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
const normalized = value.trim().toLowerCase();
|
|
57
|
+
if (normalized === "minimal" || normalized === "low" || normalized === "medium" || normalized === "high" || normalized === "xhigh") {
|
|
58
|
+
return normalized;
|
|
59
|
+
}
|
|
60
|
+
return void 0;
|
|
61
|
+
}
|
|
62
|
+
function readRequestedSkills(metadata) {
|
|
63
|
+
const raw = metadata.requested_skills ?? metadata.requestedSkills;
|
|
64
|
+
if (!Array.isArray(raw)) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
return raw.map((entry) => readString(entry)).filter((entry) => Boolean(entry)).slice(0, 8);
|
|
68
|
+
}
|
|
69
|
+
function readUserText(input) {
|
|
70
|
+
for (let index = input.messages.length - 1; index >= 0; index -= 1) {
|
|
71
|
+
const message = input.messages[index];
|
|
72
|
+
if (message?.role !== "user") {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const text = message.parts.filter((part) => part.type === "text").map((part) => part.text).join("").trim();
|
|
76
|
+
if (text) {
|
|
77
|
+
return text;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
function buildCodexInputBuilder(workspace) {
|
|
83
|
+
const skillsLoader = new SkillsLoader(workspace);
|
|
84
|
+
return async (input) => {
|
|
85
|
+
const userText = readUserText(input);
|
|
86
|
+
const metadata = input.metadata && typeof input.metadata === "object" && !Array.isArray(input.metadata) ? input.metadata : {};
|
|
87
|
+
const requestedSkills = readRequestedSkills(metadata);
|
|
88
|
+
const requestedSkillsContent = skillsLoader.loadSkillsForContext(requestedSkills);
|
|
89
|
+
if (requestedSkillsContent.trim().length === 0) {
|
|
90
|
+
return userText;
|
|
91
|
+
}
|
|
92
|
+
return [
|
|
93
|
+
"## Requested Skills",
|
|
94
|
+
`Selected skill names: ${requestedSkills.join(", ")}`,
|
|
95
|
+
requestedSkillsContent,
|
|
96
|
+
"## User Message",
|
|
97
|
+
userText
|
|
98
|
+
].join("\n\n");
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function resolveCodexModel(params) {
|
|
102
|
+
return readString(params.sessionMetadata.preferred_model) ?? readString(params.sessionMetadata.model) ?? readString(params.pluginConfig.model) ?? params.config.agents.defaults.model;
|
|
103
|
+
}
|
|
104
|
+
const plugin = {
|
|
105
|
+
id: PLUGIN_ID,
|
|
106
|
+
name: "NextClaw Codex NCP Runtime",
|
|
107
|
+
description: "Registers NCP session type `codex` backed by OpenAI Codex SDK.",
|
|
108
|
+
configSchema: {
|
|
109
|
+
type: "object",
|
|
110
|
+
additionalProperties: true,
|
|
111
|
+
properties: {}
|
|
112
|
+
},
|
|
113
|
+
register(api) {
|
|
114
|
+
const pluginConfig = readRecord(api.pluginConfig) ?? {};
|
|
115
|
+
api.registerNcpAgentRuntime({
|
|
116
|
+
kind: CODEX_RUNTIME_KIND,
|
|
117
|
+
label: "Codex",
|
|
118
|
+
createRuntime: (runtimeParams) => {
|
|
119
|
+
const nextConfig = api.config;
|
|
120
|
+
const model = resolveCodexModel({
|
|
121
|
+
config: nextConfig,
|
|
122
|
+
pluginConfig,
|
|
123
|
+
sessionMetadata: runtimeParams.sessionMetadata
|
|
124
|
+
});
|
|
125
|
+
const provider = getProvider(nextConfig, model);
|
|
126
|
+
const apiKey = readString(pluginConfig.apiKey) ?? provider?.apiKey ?? void 0;
|
|
127
|
+
if (!apiKey) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`[codex] missing apiKey. Set plugins.entries.${PLUGIN_ID}.config.apiKey or providers.*.apiKey for model "${model}".`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
const workspace = getWorkspacePath(
|
|
133
|
+
readString(pluginConfig.workingDirectory) ?? nextConfig.agents.defaults.workspace
|
|
134
|
+
);
|
|
135
|
+
const thinkingLevel = readThinkingLevel(runtimeParams.sessionMetadata.preferred_thinking) ?? readThinkingLevel(runtimeParams.sessionMetadata.thinking) ?? void 0;
|
|
136
|
+
return new CodexSdkNcpAgentRuntime({
|
|
137
|
+
sessionId: runtimeParams.sessionId,
|
|
138
|
+
apiKey,
|
|
139
|
+
apiBase: readString(pluginConfig.apiBase) ?? getApiBase(nextConfig, model) ?? void 0,
|
|
140
|
+
model,
|
|
141
|
+
threadId: readString(runtimeParams.sessionMetadata.codex_thread_id) ?? null,
|
|
142
|
+
codexPathOverride: readString(pluginConfig.codexPathOverride),
|
|
143
|
+
env: readStringRecord(pluginConfig.env),
|
|
144
|
+
cliConfig: readRecord(pluginConfig.config),
|
|
145
|
+
sessionMetadata: runtimeParams.sessionMetadata,
|
|
146
|
+
setSessionMetadata: runtimeParams.setSessionMetadata,
|
|
147
|
+
inputBuilder: buildCodexInputBuilder(workspace),
|
|
148
|
+
threadOptions: {
|
|
149
|
+
model,
|
|
150
|
+
sandboxMode: readString(pluginConfig.sandboxMode),
|
|
151
|
+
workingDirectory: workspace,
|
|
152
|
+
skipGitRepoCheck: readBoolean(pluginConfig.skipGitRepoCheck),
|
|
153
|
+
modelReasoningEffort: thinkingLevel,
|
|
154
|
+
networkAccessEnabled: readBoolean(pluginConfig.networkAccessEnabled),
|
|
155
|
+
webSearchMode: readString(pluginConfig.webSearchMode),
|
|
156
|
+
webSearchEnabled: readBoolean(pluginConfig.webSearchEnabled),
|
|
157
|
+
approvalPolicy: readString(pluginConfig.approvalPolicy),
|
|
158
|
+
additionalDirectories: readStringArray(pluginConfig.additionalDirectories)
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
var index_default = plugin;
|
|
166
|
+
export {
|
|
167
|
+
index_default as default
|
|
168
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "nextclaw-ncp-runtime-plugin-codex-sdk",
|
|
3
|
+
"kind": "agent-runtime",
|
|
4
|
+
"name": "NextClaw Codex NCP Runtime",
|
|
5
|
+
"description": "Registers NCP session type `codex` backed by OpenAI Codex SDK.",
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"configSchema": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"additionalProperties": true,
|
|
10
|
+
"properties": {
|
|
11
|
+
"apiKey": {
|
|
12
|
+
"type": "string"
|
|
13
|
+
},
|
|
14
|
+
"apiBase": {
|
|
15
|
+
"type": "string"
|
|
16
|
+
},
|
|
17
|
+
"model": {
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"workingDirectory": {
|
|
21
|
+
"type": "string"
|
|
22
|
+
},
|
|
23
|
+
"sandboxMode": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"enum": ["read-only", "workspace-write", "danger-full-access"]
|
|
26
|
+
},
|
|
27
|
+
"skipGitRepoCheck": {
|
|
28
|
+
"type": "boolean"
|
|
29
|
+
},
|
|
30
|
+
"networkAccessEnabled": {
|
|
31
|
+
"type": "boolean"
|
|
32
|
+
},
|
|
33
|
+
"webSearchMode": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"enum": ["disabled", "cached", "live"]
|
|
36
|
+
},
|
|
37
|
+
"webSearchEnabled": {
|
|
38
|
+
"type": "boolean"
|
|
39
|
+
},
|
|
40
|
+
"approvalPolicy": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"enum": ["never", "on-request", "on-failure", "untrusted"]
|
|
43
|
+
},
|
|
44
|
+
"codexPathOverride": {
|
|
45
|
+
"type": "string"
|
|
46
|
+
},
|
|
47
|
+
"additionalDirectories": {
|
|
48
|
+
"type": "array",
|
|
49
|
+
"items": {
|
|
50
|
+
"type": "string"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"env": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"additionalProperties": {
|
|
56
|
+
"type": "string"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"config": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"additionalProperties": true
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"uiHints": {
|
|
66
|
+
"apiKey": {
|
|
67
|
+
"label": "Codex API Key",
|
|
68
|
+
"help": "Optional. Falls back to the selected provider API key when omitted.",
|
|
69
|
+
"sensitive": true
|
|
70
|
+
},
|
|
71
|
+
"apiBase": {
|
|
72
|
+
"label": "Codex API Base"
|
|
73
|
+
},
|
|
74
|
+
"model": {
|
|
75
|
+
"label": "Default Model"
|
|
76
|
+
},
|
|
77
|
+
"workingDirectory": {
|
|
78
|
+
"label": "Working Directory",
|
|
79
|
+
"advanced": true
|
|
80
|
+
},
|
|
81
|
+
"sandboxMode": {
|
|
82
|
+
"label": "Sandbox Mode",
|
|
83
|
+
"advanced": true
|
|
84
|
+
},
|
|
85
|
+
"approvalPolicy": {
|
|
86
|
+
"label": "Approval Policy",
|
|
87
|
+
"advanced": true
|
|
88
|
+
},
|
|
89
|
+
"networkAccessEnabled": {
|
|
90
|
+
"label": "Enable Network",
|
|
91
|
+
"advanced": true
|
|
92
|
+
},
|
|
93
|
+
"webSearchEnabled": {
|
|
94
|
+
"label": "Enable Web Search",
|
|
95
|
+
"advanced": true
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nextclaw/nextclaw-ncp-runtime-plugin-codex-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "NextClaw plugin that registers Codex SDK as an optional NCP runtime.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"openclaw.plugin.json",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"openclaw": {
|
|
19
|
+
"extensions": [
|
|
20
|
+
"dist/index.js"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@nextclaw/nextclaw-ncp-runtime-codex-sdk": "0.1.0",
|
|
25
|
+
"@nextclaw/ncp": "0.3.0",
|
|
26
|
+
"@nextclaw/ncp-toolkit": "0.3.0",
|
|
27
|
+
"@nextclaw/core": "0.9.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^20.17.6",
|
|
31
|
+
"tsup": "^8.3.5",
|
|
32
|
+
"typescript": "^5.6.3"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup --config tsup.config.ts",
|
|
36
|
+
"lint": "eslint .",
|
|
37
|
+
"tsc": "tsc -p tsconfig.json"
|
|
38
|
+
}
|
|
39
|
+
}
|