@nextclaw/nextclaw-ncp-runtime-codex-sdk 0.1.54 → 0.1.55-beta.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/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -5
- package/dist/index.js.map +1 -1
- package/dist/services/codex-app-server-client.service.js +242 -0
- package/dist/services/codex-app-server-client.service.js.map +1 -0
- package/dist/services/codex-app-server-ncp-agent-runtime.service.d.ts +30 -0
- package/dist/services/codex-app-server-ncp-agent-runtime.service.d.ts.map +1 -0
- package/dist/services/codex-app-server-ncp-agent-runtime.service.js +389 -0
- package/dist/services/codex-app-server-ncp-agent-runtime.service.js.map +1 -0
- package/dist/types/codex-app-server-runtime.types.d.ts +24 -0
- package/dist/types/codex-app-server-runtime.types.d.ts.map +1 -0
- package/dist/utils/codex-app-server-item-mapper.utils.js +67 -0
- package/dist/utils/codex-app-server-item-mapper.utils.js.map +1 -0
- package/dist/utils/codex-app-server-request.utils.js +49 -0
- package/dist/utils/codex-app-server-request.utils.js.map +1 -0
- package/dist/{codex-openai-responses-bridge-assistant-output.utils.js → utils/codex-openai-responses-bridge-assistant-output.utils.js} +2 -2
- package/dist/utils/codex-openai-responses-bridge-assistant-output.utils.js.map +1 -0
- package/dist/utils/codex-openai-responses-bridge-request.utils.js.map +1 -1
- package/dist/utils/codex-openai-responses-bridge-stream.utils.js +1 -1
- package/dist/utils/codex-openai-responses-bridge-stream.utils.js.map +1 -1
- package/dist/utils/codex-openai-responses-bridge.utils.js.map +1 -1
- package/dist/utils/codex-openai-responses-stream-writer.utils.d.ts.map +1 -1
- package/dist/utils/codex-openai-responses-stream-writer.utils.js +2 -9
- package/dist/utils/codex-openai-responses-stream-writer.utils.js.map +1 -1
- package/dist/utils/codex-openai-sse-chunks.utils.js.map +1 -1
- package/package.json +4 -3
- package/dist/codex-openai-responses-bridge-assistant-output.utils.js.map +0 -1
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { CodexNcpRunEventEmitter } from "./codex-ncp-run-event-emitter.service.js";
|
|
2
|
+
import { buildCodexTurnInputFromRunInput } from "../codex-input.utils.js";
|
|
3
|
+
import { isAppServerToolLikeItem, readAppServerReasoningText, readAppServerToolArgs, readAppServerToolName, readAppServerToolResult, stringifyAppServerToolArgs } from "../utils/codex-app-server-item-mapper.utils.js";
|
|
4
|
+
import { compactObject, normalizeSandbox, splitModelRoute, toAppServerInput } from "../utils/codex-app-server-request.utils.js";
|
|
5
|
+
import { CodexAppServerClient } from "./codex-app-server-client.service.js";
|
|
6
|
+
import { NcpEventType } from "@nextclaw/ncp";
|
|
7
|
+
//#region src/services/codex-app-server-ncp-agent-runtime.service.ts
|
|
8
|
+
var CodexAppServerNcpAgentRuntime = class {
|
|
9
|
+
eventEmitter;
|
|
10
|
+
sessionMetadata;
|
|
11
|
+
clientPromise = null;
|
|
12
|
+
threadId;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.eventEmitter = new CodexNcpRunEventEmitter(config.stateManager);
|
|
16
|
+
this.threadId = config.threadId?.trim() || null;
|
|
17
|
+
this.sessionMetadata = { ...config.sessionMetadata ? structuredClone(config.sessionMetadata) : {} };
|
|
18
|
+
}
|
|
19
|
+
run = async function* (input, options) {
|
|
20
|
+
const signal = options?.signal;
|
|
21
|
+
const messageId = createId("codex-message");
|
|
22
|
+
const runId = input.runId ?? createId("codex-run");
|
|
23
|
+
const textState = /* @__PURE__ */ new Set();
|
|
24
|
+
const textDeltaState = /* @__PURE__ */ new Set();
|
|
25
|
+
const reasoningState = /* @__PURE__ */ new Set();
|
|
26
|
+
const reasoningDeltaState = /* @__PURE__ */ new Set();
|
|
27
|
+
const toolState = /* @__PURE__ */ new Set();
|
|
28
|
+
yield* this.eventEmitter.emitRunStarted(input.sessionId, messageId, runId);
|
|
29
|
+
yield* this.eventEmitter.emitReadyMetadata(input.sessionId, messageId, runId);
|
|
30
|
+
const client = await this.resolveClient();
|
|
31
|
+
await this.resolveThread(client);
|
|
32
|
+
const turnInput = await this.buildTurnInput(input);
|
|
33
|
+
const turnId = readString((await client.request("turn/start", {
|
|
34
|
+
threadId: this.threadId ?? "",
|
|
35
|
+
input: toAppServerInput(turnInput),
|
|
36
|
+
...this.buildTurnOverrides()
|
|
37
|
+
})).turn?.id);
|
|
38
|
+
const abortListener = () => {
|
|
39
|
+
if (turnId && this.threadId) client.request("turn/interrupt", {
|
|
40
|
+
threadId: this.threadId,
|
|
41
|
+
turnId
|
|
42
|
+
}, 5e3).catch(() => {
|
|
43
|
+
client.dispose();
|
|
44
|
+
});
|
|
45
|
+
else client.dispose();
|
|
46
|
+
};
|
|
47
|
+
signal?.addEventListener("abort", abortListener, { once: true });
|
|
48
|
+
try {
|
|
49
|
+
while (true) {
|
|
50
|
+
if (signal?.aborted) throw toAbortError(signal.reason);
|
|
51
|
+
const next = await client.nextNotification();
|
|
52
|
+
if (next.done) return;
|
|
53
|
+
if (yield* this.handleNotification({
|
|
54
|
+
notification: next.value,
|
|
55
|
+
sessionId: input.sessionId,
|
|
56
|
+
messageId,
|
|
57
|
+
runId,
|
|
58
|
+
textState,
|
|
59
|
+
textDeltaState,
|
|
60
|
+
reasoningState,
|
|
61
|
+
reasoningDeltaState,
|
|
62
|
+
toolState
|
|
63
|
+
})) return;
|
|
64
|
+
}
|
|
65
|
+
} finally {
|
|
66
|
+
signal?.removeEventListener("abort", abortListener);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
resolveClient = async () => {
|
|
70
|
+
if (!this.clientPromise) {
|
|
71
|
+
const client = new CodexAppServerClient(this.config);
|
|
72
|
+
this.clientPromise = client.initialize().then(() => client);
|
|
73
|
+
}
|
|
74
|
+
return this.clientPromise;
|
|
75
|
+
};
|
|
76
|
+
resolveThread = async (client) => {
|
|
77
|
+
if (this.threadId) {
|
|
78
|
+
const response = await client.request("thread/resume", {
|
|
79
|
+
threadId: this.threadId,
|
|
80
|
+
...this.buildThreadOverrides()
|
|
81
|
+
});
|
|
82
|
+
await this.updateThreadId(readString(response.thread?.id) ?? this.threadId);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const nextThreadId = readString((await client.request("thread/start", { ...this.buildThreadOverrides() })).thread?.id);
|
|
86
|
+
if (nextThreadId) await this.updateThreadId(nextThreadId);
|
|
87
|
+
};
|
|
88
|
+
buildThreadOverrides = () => {
|
|
89
|
+
const threadOptions = this.config.threadOptions;
|
|
90
|
+
const route = splitModelRoute(threadOptions?.model ?? this.config.model);
|
|
91
|
+
return compactObject({
|
|
92
|
+
cwd: threadOptions?.workingDirectory,
|
|
93
|
+
model: route.model,
|
|
94
|
+
modelProvider: route.modelProvider,
|
|
95
|
+
approvalPolicy: threadOptions?.approvalPolicy,
|
|
96
|
+
sandbox: normalizeSandbox(threadOptions?.sandboxMode),
|
|
97
|
+
config: this.config.cliConfig
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
buildTurnOverrides = () => {
|
|
101
|
+
const threadOptions = this.config.threadOptions;
|
|
102
|
+
const route = splitModelRoute(threadOptions?.model ?? this.config.model);
|
|
103
|
+
return compactObject({
|
|
104
|
+
cwd: threadOptions?.workingDirectory,
|
|
105
|
+
model: route.model,
|
|
106
|
+
effort: threadOptions?.modelReasoningEffort,
|
|
107
|
+
sandboxPolicy: normalizeSandbox(threadOptions?.sandboxMode),
|
|
108
|
+
approvalPolicy: threadOptions?.approvalPolicy
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
buildTurnInput = async (input) => {
|
|
112
|
+
if (this.config.inputBuilder) return await this.config.inputBuilder(input);
|
|
113
|
+
return await buildCodexTurnInputFromRunInput(input, { resolveAssetContentPath: this.config.resolveAssetContentPath });
|
|
114
|
+
};
|
|
115
|
+
handleNotification = async function* (params) {
|
|
116
|
+
const { messageId, notification, reasoningDeltaState, reasoningState, runId, sessionId, textDeltaState, textState, toolState } = params;
|
|
117
|
+
if (notification.method === "thread/started") {
|
|
118
|
+
await this.handleThreadStarted(notification.params);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
if (notification.method === "item/agentMessage/delta") {
|
|
122
|
+
yield* this.emitTextDelta({
|
|
123
|
+
messageId,
|
|
124
|
+
params: notification.params,
|
|
125
|
+
sessionId,
|
|
126
|
+
textDeltaState,
|
|
127
|
+
textState
|
|
128
|
+
});
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
if (notification.method === "item/reasoning/textDelta" || notification.method === "item/reasoning/summaryTextDelta") {
|
|
132
|
+
yield* this.emitReasoningDelta({
|
|
133
|
+
messageId,
|
|
134
|
+
params: notification.params,
|
|
135
|
+
reasoningDeltaState,
|
|
136
|
+
reasoningState,
|
|
137
|
+
sessionId
|
|
138
|
+
});
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
if (notification.method === "item/started" || notification.method === "item/completed") {
|
|
142
|
+
const item = notification.params.item;
|
|
143
|
+
if (item) yield* this.handleItemLifecycle({
|
|
144
|
+
item,
|
|
145
|
+
eventType: notification.method,
|
|
146
|
+
sessionId,
|
|
147
|
+
messageId,
|
|
148
|
+
reasoningDeltaState,
|
|
149
|
+
textState,
|
|
150
|
+
textDeltaState,
|
|
151
|
+
reasoningState,
|
|
152
|
+
toolState
|
|
153
|
+
});
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
if (notification.method === "turn/completed") {
|
|
157
|
+
yield* this.eventEmitter.emitRunCompleted(sessionId, messageId, runId);
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
if (notification.method === "turn/failed") {
|
|
161
|
+
yield* this.eventEmitter.emitRunError(sessionId, messageId, runId, readString(notification.params.error) ?? "Codex turn failed.");
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
return false;
|
|
165
|
+
};
|
|
166
|
+
handleThreadStarted = async (params) => {
|
|
167
|
+
const threadId = readString(params.thread?.id);
|
|
168
|
+
if (threadId) await this.updateThreadId(threadId);
|
|
169
|
+
};
|
|
170
|
+
emitTextDelta = async function* (params) {
|
|
171
|
+
const { messageId, sessionId, textDeltaState, textState } = params;
|
|
172
|
+
const itemId = readString(params.params.itemId) ?? "agent-message";
|
|
173
|
+
if (!textState.has(itemId)) {
|
|
174
|
+
textState.add(itemId);
|
|
175
|
+
yield* this.eventEmitter.emitEvent({
|
|
176
|
+
type: NcpEventType.MessageTextStart,
|
|
177
|
+
payload: {
|
|
178
|
+
sessionId,
|
|
179
|
+
messageId
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
textDeltaState.add(itemId);
|
|
184
|
+
yield* this.eventEmitter.emitEvent({
|
|
185
|
+
type: NcpEventType.MessageTextDelta,
|
|
186
|
+
payload: {
|
|
187
|
+
sessionId,
|
|
188
|
+
messageId,
|
|
189
|
+
delta: readRawString(params.params.delta) ?? ""
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
emitReasoningDelta = async function* (params) {
|
|
194
|
+
const { messageId, reasoningDeltaState, reasoningState, sessionId } = params;
|
|
195
|
+
const itemId = readString(params.params.itemId) ?? "reasoning";
|
|
196
|
+
if (!reasoningState.has(itemId)) {
|
|
197
|
+
reasoningState.add(itemId);
|
|
198
|
+
yield* this.eventEmitter.emitEvent({
|
|
199
|
+
type: NcpEventType.MessageReasoningStart,
|
|
200
|
+
payload: {
|
|
201
|
+
sessionId,
|
|
202
|
+
messageId
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
reasoningDeltaState.add(itemId);
|
|
207
|
+
yield* this.eventEmitter.emitEvent({
|
|
208
|
+
type: NcpEventType.MessageReasoningDelta,
|
|
209
|
+
payload: {
|
|
210
|
+
sessionId,
|
|
211
|
+
messageId,
|
|
212
|
+
delta: readRawString(params.params.delta) ?? ""
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
handleItemLifecycle = async function* (params) {
|
|
217
|
+
const { eventType, item, messageId, reasoningDeltaState, reasoningState, sessionId, textDeltaState, textState, toolState } = params;
|
|
218
|
+
const itemId = readString(item.id) ?? createId("codex-item");
|
|
219
|
+
if (item.type === "agentMessage") {
|
|
220
|
+
yield* this.handleAgentMessageItem({
|
|
221
|
+
eventType,
|
|
222
|
+
item,
|
|
223
|
+
itemId,
|
|
224
|
+
messageId,
|
|
225
|
+
sessionId,
|
|
226
|
+
textDeltaState,
|
|
227
|
+
textState
|
|
228
|
+
});
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (item.type === "reasoning") {
|
|
232
|
+
yield* this.handleReasoningItem({
|
|
233
|
+
eventType,
|
|
234
|
+
item,
|
|
235
|
+
itemId,
|
|
236
|
+
messageId,
|
|
237
|
+
reasoningDeltaState,
|
|
238
|
+
reasoningState,
|
|
239
|
+
sessionId
|
|
240
|
+
});
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (!isAppServerToolLikeItem(item.type)) return;
|
|
244
|
+
yield* this.handleToolItem({
|
|
245
|
+
eventType,
|
|
246
|
+
item,
|
|
247
|
+
itemId,
|
|
248
|
+
messageId,
|
|
249
|
+
sessionId,
|
|
250
|
+
toolState
|
|
251
|
+
});
|
|
252
|
+
};
|
|
253
|
+
handleAgentMessageItem = async function* (params) {
|
|
254
|
+
const { eventType, item, itemId, messageId, sessionId, textDeltaState, textState } = params;
|
|
255
|
+
if (!textState.has(itemId)) {
|
|
256
|
+
textState.add(itemId);
|
|
257
|
+
yield* this.eventEmitter.emitEvent({
|
|
258
|
+
type: NcpEventType.MessageTextStart,
|
|
259
|
+
payload: {
|
|
260
|
+
sessionId,
|
|
261
|
+
messageId
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
const text = readRawString(item.text);
|
|
266
|
+
if (text && !textDeltaState.has(itemId)) yield* this.eventEmitter.emitEvent({
|
|
267
|
+
type: NcpEventType.MessageTextDelta,
|
|
268
|
+
payload: {
|
|
269
|
+
sessionId,
|
|
270
|
+
messageId,
|
|
271
|
+
delta: text
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
if (eventType === "item/completed") yield* this.eventEmitter.emitEvent({
|
|
275
|
+
type: NcpEventType.MessageTextEnd,
|
|
276
|
+
payload: {
|
|
277
|
+
sessionId,
|
|
278
|
+
messageId
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
handleReasoningItem = async function* (params) {
|
|
283
|
+
const { eventType, item, itemId, messageId, reasoningDeltaState, reasoningState, sessionId } = params;
|
|
284
|
+
const reasoningText = readAppServerReasoningText(item);
|
|
285
|
+
if (!reasoningState.has(itemId) && (eventType === "item/started" || reasoningText)) {
|
|
286
|
+
reasoningState.add(itemId);
|
|
287
|
+
yield* this.eventEmitter.emitEvent({
|
|
288
|
+
type: NcpEventType.MessageReasoningStart,
|
|
289
|
+
payload: {
|
|
290
|
+
sessionId,
|
|
291
|
+
messageId
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
if (!reasoningDeltaState.has(itemId) && reasoningText) yield* this.eventEmitter.emitEvent({
|
|
296
|
+
type: NcpEventType.MessageReasoningDelta,
|
|
297
|
+
payload: {
|
|
298
|
+
sessionId,
|
|
299
|
+
messageId,
|
|
300
|
+
delta: reasoningText
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
if (eventType === "item/completed" && reasoningState.has(itemId)) yield* this.eventEmitter.emitEvent({
|
|
304
|
+
type: NcpEventType.MessageReasoningEnd,
|
|
305
|
+
payload: {
|
|
306
|
+
sessionId,
|
|
307
|
+
messageId
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
};
|
|
311
|
+
handleToolItem = async function* (params) {
|
|
312
|
+
const { eventType, item, itemId, messageId, sessionId, toolState } = params;
|
|
313
|
+
if (!toolState.has(itemId)) {
|
|
314
|
+
toolState.add(itemId);
|
|
315
|
+
yield* this.eventEmitter.emitEvent({
|
|
316
|
+
type: NcpEventType.MessageToolCallStart,
|
|
317
|
+
payload: {
|
|
318
|
+
sessionId,
|
|
319
|
+
messageId,
|
|
320
|
+
toolCallId: itemId,
|
|
321
|
+
toolName: readAppServerToolName(item)
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
yield* this.eventEmitter.emitEvent({
|
|
325
|
+
type: NcpEventType.MessageToolCallArgs,
|
|
326
|
+
payload: {
|
|
327
|
+
sessionId,
|
|
328
|
+
toolCallId: itemId,
|
|
329
|
+
args: stringifyAppServerToolArgs(readAppServerToolArgs(item))
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
yield* this.eventEmitter.emitEvent({
|
|
333
|
+
type: NcpEventType.MessageToolCallEnd,
|
|
334
|
+
payload: {
|
|
335
|
+
sessionId,
|
|
336
|
+
toolCallId: itemId
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
if (eventType === "item/completed") yield* this.eventEmitter.emitEvent({
|
|
341
|
+
type: NcpEventType.MessageToolCallResult,
|
|
342
|
+
payload: {
|
|
343
|
+
sessionId,
|
|
344
|
+
toolCallId: itemId,
|
|
345
|
+
content: readAppServerToolResult(item)
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
};
|
|
349
|
+
updateThreadId = async (nextThreadId) => {
|
|
350
|
+
const normalizedThreadId = nextThreadId.trim();
|
|
351
|
+
if (!normalizedThreadId || normalizedThreadId === this.threadId) return;
|
|
352
|
+
this.threadId = normalizedThreadId;
|
|
353
|
+
const nextMetadata = {
|
|
354
|
+
...this.sessionMetadata,
|
|
355
|
+
session_type: "codex",
|
|
356
|
+
codex_thread_id: normalizedThreadId,
|
|
357
|
+
codex_thread_model: buildThreadModelScope(this.config)
|
|
358
|
+
};
|
|
359
|
+
this.sessionMetadata.codex_thread_id = normalizedThreadId;
|
|
360
|
+
this.sessionMetadata.codex_thread_model = nextMetadata.codex_thread_model;
|
|
361
|
+
this.sessionMetadata.session_type = "codex";
|
|
362
|
+
await this.config.setSessionMetadata?.(nextMetadata);
|
|
363
|
+
};
|
|
364
|
+
};
|
|
365
|
+
function createId(prefix) {
|
|
366
|
+
return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
367
|
+
}
|
|
368
|
+
function readString(value) {
|
|
369
|
+
if (typeof value !== "string") return;
|
|
370
|
+
const trimmed = value.trim();
|
|
371
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
372
|
+
}
|
|
373
|
+
function readRawString(value) {
|
|
374
|
+
return typeof value === "string" ? value : void 0;
|
|
375
|
+
}
|
|
376
|
+
function buildThreadModelScope(config) {
|
|
377
|
+
return readString(config.threadOptions?.model) ?? readString(config.model) ?? "__nextclaw_runtime_default__";
|
|
378
|
+
}
|
|
379
|
+
function toAbortError(reason) {
|
|
380
|
+
if (reason instanceof Error) return reason;
|
|
381
|
+
const message = typeof reason === "string" && reason.trim() ? reason.trim() : "operation aborted";
|
|
382
|
+
const error = new Error(message);
|
|
383
|
+
error.name = "AbortError";
|
|
384
|
+
return error;
|
|
385
|
+
}
|
|
386
|
+
//#endregion
|
|
387
|
+
export { CodexAppServerNcpAgentRuntime };
|
|
388
|
+
|
|
389
|
+
//# sourceMappingURL=codex-app-server-ncp-agent-runtime.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-app-server-ncp-agent-runtime.service.js","names":[],"sources":["../../src/services/codex-app-server-ncp-agent-runtime.service.ts"],"sourcesContent":["import {\n type NcpAgentRunInput,\n type NcpAgentRunOptions,\n type NcpAgentRuntime,\n type NcpEndpointEvent,\n NcpEventType,\n} from \"@nextclaw/ncp\";\nimport {\n buildCodexTurnInputFromRunInput,\n type CodexThreadInput,\n} from \"@/codex-input.utils.js\";\nimport {\n isAppServerToolLikeItem,\n readAppServerReasoningText,\n readAppServerToolArgs,\n readAppServerToolName,\n readAppServerToolResult,\n stringifyAppServerToolArgs,\n} from \"@/utils/codex-app-server-item-mapper.utils.js\";\nimport {\n compactObject,\n normalizeSandbox,\n splitModelRoute,\n toAppServerInput,\n} from \"@/utils/codex-app-server-request.utils.js\";\nimport { CodexAppServerClient } from \"./codex-app-server-client.service.js\";\nimport type {\n AppServerNotification,\n AppServerThreadItem,\n CodexAppServerNcpAgentRuntimeConfig,\n JsonObject,\n} from \"@/types/codex-app-server-runtime.types.js\";\nimport { CodexNcpRunEventEmitter } from \"./codex-ncp-run-event-emitter.service.js\";\n\nexport class CodexAppServerNcpAgentRuntime implements NcpAgentRuntime {\n private readonly eventEmitter: CodexNcpRunEventEmitter;\n private readonly sessionMetadata: Record<string, unknown>;\n private clientPromise: Promise<CodexAppServerClient> | null = null;\n private threadId: string | null;\n\n constructor(private readonly config: CodexAppServerNcpAgentRuntimeConfig) {\n this.eventEmitter = new CodexNcpRunEventEmitter(config.stateManager);\n this.threadId = config.threadId?.trim() || null;\n this.sessionMetadata = {\n ...(config.sessionMetadata ? structuredClone(config.sessionMetadata) : {}),\n };\n }\n\n run = async function* (\n this: CodexAppServerNcpAgentRuntime,\n input: NcpAgentRunInput,\n options?: NcpAgentRunOptions,\n ): AsyncGenerator<NcpEndpointEvent> {\n const signal = options?.signal;\n const messageId = createId(\"codex-message\");\n const runId = (input as NcpAgentRunInput & { runId?: string }).runId ?? createId(\"codex-run\");\n const textState = new Set<string>();\n const textDeltaState = new Set<string>();\n const reasoningState = new Set<string>();\n const reasoningDeltaState = new Set<string>();\n const toolState = new Set<string>();\n\n yield* this.eventEmitter.emitRunStarted(input.sessionId, messageId, runId);\n yield* this.eventEmitter.emitReadyMetadata(input.sessionId, messageId, runId);\n\n const client = await this.resolveClient();\n await this.resolveThread(client);\n const turnInput = await this.buildTurnInput(input);\n const turn = await client.request<{ turn?: { id?: string } }>(\"turn/start\", {\n threadId: this.threadId ?? \"\",\n input: toAppServerInput(turnInput),\n ...this.buildTurnOverrides(),\n });\n const turnId = readString(turn.turn?.id);\n const abortListener = (): void => {\n if (turnId && this.threadId) {\n void client.request(\"turn/interrupt\", { threadId: this.threadId, turnId }, 5000).catch(() => {\n client.dispose();\n });\n } else {\n client.dispose();\n }\n };\n signal?.addEventListener(\"abort\", abortListener, { once: true });\n try {\n while (true) {\n if (signal?.aborted) {\n throw toAbortError(signal.reason);\n }\n const next = await client.nextNotification();\n if (next.done) {\n return;\n }\n const shouldFinish = yield* this.handleNotification({\n notification: next.value,\n sessionId: input.sessionId,\n messageId,\n runId,\n textState,\n textDeltaState,\n reasoningState,\n reasoningDeltaState,\n toolState,\n });\n if (shouldFinish) {\n return;\n }\n }\n } finally {\n signal?.removeEventListener(\"abort\", abortListener);\n }\n };\n\n private resolveClient = async (): Promise<CodexAppServerClient> => {\n if (!this.clientPromise) {\n const client = new CodexAppServerClient(this.config);\n this.clientPromise = client.initialize().then(() => client);\n }\n return this.clientPromise;\n };\n\n private resolveThread = async (client: CodexAppServerClient): Promise<void> => {\n if (this.threadId) {\n const response = await client.request<{ thread?: { id?: string } }>(\"thread/resume\", {\n threadId: this.threadId,\n ...this.buildThreadOverrides(),\n });\n await this.updateThreadId(readString(response.thread?.id) ?? this.threadId);\n return;\n }\n const response = await client.request<{ thread?: { id?: string } }>(\"thread/start\", {\n ...this.buildThreadOverrides(),\n });\n const nextThreadId = readString(response.thread?.id);\n if (nextThreadId) {\n await this.updateThreadId(nextThreadId);\n }\n };\n\n private buildThreadOverrides = (): JsonObject => {\n const threadOptions = this.config.threadOptions;\n const route = splitModelRoute(threadOptions?.model ?? this.config.model);\n return compactObject({\n cwd: threadOptions?.workingDirectory,\n model: route.model,\n modelProvider: route.modelProvider,\n approvalPolicy: threadOptions?.approvalPolicy,\n sandbox: normalizeSandbox(threadOptions?.sandboxMode),\n config: this.config.cliConfig,\n });\n };\n\n private buildTurnOverrides = (): JsonObject => {\n const threadOptions = this.config.threadOptions;\n const route = splitModelRoute(threadOptions?.model ?? this.config.model);\n return compactObject({\n cwd: threadOptions?.workingDirectory,\n model: route.model,\n effort: threadOptions?.modelReasoningEffort,\n sandboxPolicy: normalizeSandbox(threadOptions?.sandboxMode),\n approvalPolicy: threadOptions?.approvalPolicy,\n });\n };\n\n private buildTurnInput = async (input: NcpAgentRunInput): Promise<CodexThreadInput> => {\n if (this.config.inputBuilder) {\n return await this.config.inputBuilder(input);\n }\n return await buildCodexTurnInputFromRunInput(input, {\n resolveAssetContentPath: this.config.resolveAssetContentPath,\n });\n };\n\n private handleNotification = async function* (\n this: CodexAppServerNcpAgentRuntime,\n params: {\n notification: AppServerNotification;\n sessionId: string;\n messageId: string;\n runId: string;\n textState: Set<string>;\n textDeltaState: Set<string>;\n reasoningState: Set<string>;\n reasoningDeltaState: Set<string>;\n toolState: Set<string>;\n },\n ): AsyncGenerator<NcpEndpointEvent, boolean> {\n const {\n messageId,\n notification,\n reasoningDeltaState,\n reasoningState,\n runId,\n sessionId,\n textDeltaState,\n textState,\n toolState,\n } = params;\n if (notification.method === \"thread/started\") {\n await this.handleThreadStarted(notification.params);\n return false;\n }\n if (notification.method === \"item/agentMessage/delta\") {\n yield* this.emitTextDelta({\n messageId,\n params: notification.params,\n sessionId,\n textDeltaState,\n textState,\n });\n return false;\n }\n if (\n notification.method === \"item/reasoning/textDelta\" ||\n notification.method === \"item/reasoning/summaryTextDelta\"\n ) {\n yield* this.emitReasoningDelta({\n messageId,\n params: notification.params,\n reasoningDeltaState,\n reasoningState,\n sessionId,\n });\n return false;\n }\n if (notification.method === \"item/started\" || notification.method === \"item/completed\") {\n const item = notification.params.item as AppServerThreadItem | undefined;\n if (item) {\n yield* this.handleItemLifecycle({\n item,\n eventType: notification.method,\n sessionId,\n messageId,\n reasoningDeltaState,\n textState,\n textDeltaState,\n reasoningState,\n toolState,\n });\n }\n return false;\n }\n if (notification.method === \"turn/completed\") {\n yield* this.eventEmitter.emitRunCompleted(sessionId, messageId, runId);\n return true;\n }\n if (notification.method === \"turn/failed\") {\n yield* this.eventEmitter.emitRunError(\n sessionId,\n messageId,\n runId,\n readString(notification.params.error) ?? \"Codex turn failed.\",\n );\n return true;\n }\n return false;\n };\n\n private handleThreadStarted = async (params: JsonObject): Promise<void> => {\n const threadId = readString((params.thread as JsonObject | undefined)?.id);\n if (threadId) {\n await this.updateThreadId(threadId);\n }\n };\n\n private emitTextDelta = async function* (\n this: CodexAppServerNcpAgentRuntime,\n params: {\n params: JsonObject;\n sessionId: string;\n messageId: string;\n textState: Set<string>;\n textDeltaState: Set<string>;\n },\n ): AsyncGenerator<NcpEndpointEvent> {\n const { messageId, sessionId, textDeltaState, textState } = params;\n const itemId = readString(params.params.itemId) ?? \"agent-message\";\n if (!textState.has(itemId)) {\n textState.add(itemId);\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageTextStart,\n payload: { sessionId, messageId },\n });\n }\n textDeltaState.add(itemId);\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageTextDelta,\n payload: { sessionId, messageId, delta: readRawString(params.params.delta) ?? \"\" },\n });\n };\n\n private emitReasoningDelta = async function* (\n this: CodexAppServerNcpAgentRuntime,\n params: {\n params: JsonObject;\n sessionId: string;\n messageId: string;\n reasoningState: Set<string>;\n reasoningDeltaState: Set<string>;\n },\n ): AsyncGenerator<NcpEndpointEvent> {\n const { messageId, reasoningDeltaState, reasoningState, sessionId } = params;\n const itemId = readString(params.params.itemId) ?? \"reasoning\";\n if (!reasoningState.has(itemId)) {\n reasoningState.add(itemId);\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageReasoningStart,\n payload: { sessionId, messageId },\n });\n }\n reasoningDeltaState.add(itemId);\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageReasoningDelta,\n payload: { sessionId, messageId, delta: readRawString(params.params.delta) ?? \"\" },\n });\n };\n\n private handleItemLifecycle = async function* (\n this: CodexAppServerNcpAgentRuntime,\n params: {\n item: AppServerThreadItem;\n eventType: \"item/started\" | \"item/completed\";\n sessionId: string;\n messageId: string;\n textState: Set<string>;\n textDeltaState: Set<string>;\n reasoningState: Set<string>;\n reasoningDeltaState: Set<string>;\n toolState: Set<string>;\n },\n ): AsyncGenerator<NcpEndpointEvent> {\n const {\n eventType,\n item,\n messageId,\n reasoningDeltaState,\n reasoningState,\n sessionId,\n textDeltaState,\n textState,\n toolState,\n } = params;\n const itemId = readString(item.id) ?? createId(\"codex-item\");\n if (item.type === \"agentMessage\") {\n yield* this.handleAgentMessageItem({\n eventType,\n item,\n itemId,\n messageId,\n sessionId,\n textDeltaState,\n textState,\n });\n return;\n }\n if (item.type === \"reasoning\") {\n yield* this.handleReasoningItem({\n eventType,\n item,\n itemId,\n messageId,\n reasoningDeltaState,\n reasoningState,\n sessionId,\n });\n return;\n }\n if (!isAppServerToolLikeItem(item.type)) {\n return;\n }\n yield* this.handleToolItem({ eventType, item, itemId, messageId, sessionId, toolState });\n };\n\n private handleAgentMessageItem = async function* (\n this: CodexAppServerNcpAgentRuntime,\n params: {\n item: AppServerThreadItem;\n itemId: string;\n eventType: \"item/started\" | \"item/completed\";\n sessionId: string;\n messageId: string;\n textState: Set<string>;\n textDeltaState: Set<string>;\n },\n ): AsyncGenerator<NcpEndpointEvent> {\n const { eventType, item, itemId, messageId, sessionId, textDeltaState, textState } = params;\n if (!textState.has(itemId)) {\n textState.add(itemId);\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageTextStart,\n payload: { sessionId, messageId },\n });\n }\n const text = readRawString(item.text);\n if (text && !textDeltaState.has(itemId)) {\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageTextDelta,\n payload: { sessionId, messageId, delta: text },\n });\n }\n if (eventType === \"item/completed\") {\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageTextEnd,\n payload: { sessionId, messageId },\n });\n }\n };\n\n private handleReasoningItem = async function* (\n this: CodexAppServerNcpAgentRuntime,\n params: {\n item: AppServerThreadItem;\n itemId: string;\n eventType: \"item/started\" | \"item/completed\";\n sessionId: string;\n messageId: string;\n reasoningState: Set<string>;\n reasoningDeltaState: Set<string>;\n },\n ): AsyncGenerator<NcpEndpointEvent> {\n const { eventType, item, itemId, messageId, reasoningDeltaState, reasoningState, sessionId } =\n params;\n const reasoningText = readAppServerReasoningText(item);\n const alreadyStarted = reasoningState.has(itemId);\n if (!alreadyStarted && (eventType === \"item/started\" || reasoningText)) {\n reasoningState.add(itemId);\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageReasoningStart,\n payload: { sessionId, messageId },\n });\n }\n if (!reasoningDeltaState.has(itemId) && reasoningText) {\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageReasoningDelta,\n payload: { sessionId, messageId, delta: reasoningText },\n });\n }\n if (eventType === \"item/completed\" && reasoningState.has(itemId)) {\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageReasoningEnd,\n payload: { sessionId, messageId },\n });\n }\n };\n\n private handleToolItem = async function* (\n this: CodexAppServerNcpAgentRuntime,\n params: {\n item: AppServerThreadItem;\n itemId: string;\n eventType: \"item/started\" | \"item/completed\";\n sessionId: string;\n messageId: string;\n toolState: Set<string>;\n },\n ): AsyncGenerator<NcpEndpointEvent> {\n const { eventType, item, itemId, messageId, sessionId, toolState } = params;\n if (!toolState.has(itemId)) {\n toolState.add(itemId);\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageToolCallStart,\n payload: { sessionId, messageId, toolCallId: itemId, toolName: readAppServerToolName(item) },\n });\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId,\n toolCallId: itemId,\n args: stringifyAppServerToolArgs(readAppServerToolArgs(item)),\n },\n });\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageToolCallEnd,\n payload: { sessionId, toolCallId: itemId },\n });\n }\n if (eventType === \"item/completed\") {\n yield* this.eventEmitter.emitEvent({\n type: NcpEventType.MessageToolCallResult,\n payload: { sessionId, toolCallId: itemId, content: readAppServerToolResult(item) },\n });\n }\n };\n\n private updateThreadId = async (nextThreadId: string): Promise<void> => {\n const normalizedThreadId = nextThreadId.trim();\n if (!normalizedThreadId || normalizedThreadId === this.threadId) {\n return;\n }\n this.threadId = normalizedThreadId;\n const nextMetadata = {\n ...this.sessionMetadata,\n session_type: \"codex\",\n codex_thread_id: normalizedThreadId,\n codex_thread_model: buildThreadModelScope(this.config),\n };\n this.sessionMetadata.codex_thread_id = normalizedThreadId;\n this.sessionMetadata.codex_thread_model = nextMetadata.codex_thread_model;\n this.sessionMetadata.session_type = \"codex\";\n await this.config.setSessionMetadata?.(nextMetadata);\n };\n}\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction readString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction readRawString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction buildThreadModelScope(config: CodexAppServerNcpAgentRuntimeConfig): string {\n return readString(config.threadOptions?.model) ??\n readString(config.model) ??\n \"__nextclaw_runtime_default__\";\n}\n\nfunction toAbortError(reason: unknown): Error {\n if (reason instanceof Error) {\n return reason;\n }\n const message = typeof reason === \"string\" && reason.trim() ? reason.trim() : \"operation aborted\";\n const error = new Error(message);\n error.name = \"AbortError\";\n return error;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CodexAssetContentPathResolver, CodexThreadInput } from "../codex-input.utils.js";
|
|
2
|
+
import { NcpAgentConversationStateManager, NcpAgentRunInput } from "@nextclaw/ncp";
|
|
3
|
+
import { CodexOptions, ThreadOptions } from "@openai/codex-sdk";
|
|
4
|
+
|
|
5
|
+
//#region src/types/codex-app-server-runtime.types.d.ts
|
|
6
|
+
type CodexAppServerNcpAgentRuntimeConfig = {
|
|
7
|
+
sessionId: string;
|
|
8
|
+
apiKey: string;
|
|
9
|
+
apiBase?: string;
|
|
10
|
+
model?: string;
|
|
11
|
+
threadId?: string | null;
|
|
12
|
+
codexPathOverride?: string;
|
|
13
|
+
env?: Record<string, string>;
|
|
14
|
+
cliConfig?: CodexOptions["config"];
|
|
15
|
+
threadOptions?: ThreadOptions;
|
|
16
|
+
sessionMetadata?: Record<string, unknown>;
|
|
17
|
+
setSessionMetadata?: (nextMetadata: Record<string, unknown>) => void | Promise<void>;
|
|
18
|
+
inputBuilder?: (input: NcpAgentRunInput) => Promise<CodexThreadInput> | CodexThreadInput;
|
|
19
|
+
resolveAssetContentPath?: CodexAssetContentPathResolver;
|
|
20
|
+
stateManager?: NcpAgentConversationStateManager;
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { CodexAppServerNcpAgentRuntimeConfig };
|
|
24
|
+
//# sourceMappingURL=codex-app-server-runtime.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-app-server-runtime.types.d.ts","names":[],"sources":["../../src/types/codex-app-server-runtime.types.ts"],"mappings":";;;;;KAyBY,mCAAA;EACV,SAAA;EACA,MAAA;EACA,OAAA;EACA,KAAA;EACA,QAAA;EACA,iBAAA;EACA,GAAA,GAAM,MAAA;EACN,SAAA,GAAY,YAAA;EACZ,aAAA,GAAgB,aAAA;EAChB,eAAA,GAAkB,MAAA;EAClB,kBAAA,IAAsB,YAAA,EAAc,MAAA,6BAAmC,OAAA;EACvE,YAAA,IAAgB,KAAA,EAAO,gBAAA,KAAqB,OAAA,CAAQ,gBAAA,IAAoB,gBAAA;EACxE,uBAAA,GAA0B,6BAAA;EAC1B,YAAA,GAAe,gCAAA;AAAA"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//#region src/utils/codex-app-server-item-mapper.utils.ts
|
|
2
|
+
function readAppServerReasoningText(item) {
|
|
3
|
+
const content = Array.isArray(item.content) ? item.content.filter((value) => typeof value === "string") : [];
|
|
4
|
+
if (content.length > 0) return content.join("");
|
|
5
|
+
const summary = Array.isArray(item.summary) ? item.summary.filter((value) => typeof value === "string") : [];
|
|
6
|
+
return summary.length > 0 ? summary.join("\n") : void 0;
|
|
7
|
+
}
|
|
8
|
+
function isAppServerToolLikeItem(type) {
|
|
9
|
+
return type === "mcpToolCall" || type === "dynamicToolCall" || type === "commandExecution" || type === "webSearch" || type === "fileChange" || type === "plan";
|
|
10
|
+
}
|
|
11
|
+
function readAppServerToolName(item) {
|
|
12
|
+
if (item.type === "mcpToolCall") {
|
|
13
|
+
const server = readString(item.server);
|
|
14
|
+
const tool = readString(item.tool) ?? "tool";
|
|
15
|
+
return server ? `mcp:${server}.${tool}` : `mcp:${tool}`;
|
|
16
|
+
}
|
|
17
|
+
if (item.type === "dynamicToolCall") {
|
|
18
|
+
const namespace = readString(item.namespace);
|
|
19
|
+
const tool = readString(item.tool) ?? "tool";
|
|
20
|
+
return namespace ? `${namespace}.${tool}` : tool;
|
|
21
|
+
}
|
|
22
|
+
return readString(item.type) ?? "tool";
|
|
23
|
+
}
|
|
24
|
+
function readAppServerToolArgs(item) {
|
|
25
|
+
if (item.type === "mcpToolCall" || item.type === "dynamicToolCall") return item.arguments;
|
|
26
|
+
if (item.type === "commandExecution") return {
|
|
27
|
+
command: item.command,
|
|
28
|
+
cwd: item.cwd
|
|
29
|
+
};
|
|
30
|
+
if (item.type === "webSearch") return {
|
|
31
|
+
query: item.query,
|
|
32
|
+
action: item.action
|
|
33
|
+
};
|
|
34
|
+
if (item.type === "fileChange") return { changes: item.changes };
|
|
35
|
+
if (item.type === "plan") return { text: item.text };
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
function readAppServerToolResult(item) {
|
|
39
|
+
if (item.type === "mcpToolCall" || item.type === "dynamicToolCall") return {
|
|
40
|
+
status: item.status,
|
|
41
|
+
result: item.result ?? item.contentItems ?? null,
|
|
42
|
+
error: item.error ?? null
|
|
43
|
+
};
|
|
44
|
+
if (item.type === "commandExecution") return {
|
|
45
|
+
status: item.status,
|
|
46
|
+
command: item.command,
|
|
47
|
+
aggregated_output: item.aggregatedOutput,
|
|
48
|
+
exit_code: item.exitCode
|
|
49
|
+
};
|
|
50
|
+
return item;
|
|
51
|
+
}
|
|
52
|
+
function stringifyAppServerToolArgs(args) {
|
|
53
|
+
try {
|
|
54
|
+
return JSON.stringify(args ?? {});
|
|
55
|
+
} catch {
|
|
56
|
+
return JSON.stringify({ __serialization_error__: "tool arguments are not JSON serializable" });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function readString(value) {
|
|
60
|
+
if (typeof value !== "string") return;
|
|
61
|
+
const trimmed = value.trim();
|
|
62
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { isAppServerToolLikeItem, readAppServerReasoningText, readAppServerToolArgs, readAppServerToolName, readAppServerToolResult, stringifyAppServerToolArgs };
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=codex-app-server-item-mapper.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-app-server-item-mapper.utils.js","names":[],"sources":["../../src/utils/codex-app-server-item-mapper.utils.ts"],"sourcesContent":["import type { AppServerThreadItem } from \"@/types/codex-app-server-runtime.types.js\";\n\nexport function readAppServerReasoningText(\n item: AppServerThreadItem,\n): string | undefined {\n const content = Array.isArray(item.content)\n ? item.content.filter((value): value is string => typeof value === \"string\")\n : [];\n if (content.length > 0) {\n return content.join(\"\");\n }\n const summary = Array.isArray(item.summary)\n ? item.summary.filter((value): value is string => typeof value === \"string\")\n : [];\n return summary.length > 0 ? summary.join(\"\\n\") : undefined;\n}\n\nexport function isAppServerToolLikeItem(type: unknown): boolean {\n return (\n type === \"mcpToolCall\" ||\n type === \"dynamicToolCall\" ||\n type === \"commandExecution\" ||\n type === \"webSearch\" ||\n type === \"fileChange\" ||\n type === \"plan\"\n );\n}\n\nexport function readAppServerToolName(item: AppServerThreadItem): string {\n if (item.type === \"mcpToolCall\") {\n const server = readString(item.server);\n const tool = readString(item.tool) ?? \"tool\";\n return server ? `mcp:${server}.${tool}` : `mcp:${tool}`;\n }\n if (item.type === \"dynamicToolCall\") {\n const namespace = readString(item.namespace);\n const tool = readString(item.tool) ?? \"tool\";\n return namespace ? `${namespace}.${tool}` : tool;\n }\n return readString(item.type) ?? \"tool\";\n}\n\nexport function readAppServerToolArgs(item: AppServerThreadItem): unknown {\n if (item.type === \"mcpToolCall\" || item.type === \"dynamicToolCall\") {\n return item.arguments;\n }\n if (item.type === \"commandExecution\") {\n return { command: item.command, cwd: item.cwd };\n }\n if (item.type === \"webSearch\") {\n return { query: item.query, action: item.action };\n }\n if (item.type === \"fileChange\") {\n return { changes: item.changes };\n }\n if (item.type === \"plan\") {\n return { text: item.text };\n }\n return {};\n}\n\nexport function readAppServerToolResult(item: AppServerThreadItem): unknown {\n if (item.type === \"mcpToolCall\" || item.type === \"dynamicToolCall\") {\n return {\n status: item.status,\n result: item.result ?? item.contentItems ?? null,\n error: item.error ?? null,\n };\n }\n if (item.type === \"commandExecution\") {\n return {\n status: item.status,\n command: item.command,\n aggregated_output: item.aggregatedOutput,\n exit_code: item.exitCode,\n };\n }\n return item;\n}\n\nexport function stringifyAppServerToolArgs(args: unknown): string {\n try {\n return JSON.stringify(args ?? {});\n } catch {\n return JSON.stringify({\n __serialization_error__: \"tool arguments are not JSON serializable\",\n });\n }\n}\n\nfunction readString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n"],"mappings":";AAEA,SAAgB,2BACd,MACoB;CACpB,MAAM,UAAU,MAAM,QAAQ,KAAK,QAAQ,GACvC,KAAK,QAAQ,QAAQ,UAA2B,OAAO,UAAU,SAAS,GAC1E,EAAE;AACN,KAAI,QAAQ,SAAS,EACnB,QAAO,QAAQ,KAAK,GAAG;CAEzB,MAAM,UAAU,MAAM,QAAQ,KAAK,QAAQ,GACvC,KAAK,QAAQ,QAAQ,UAA2B,OAAO,UAAU,SAAS,GAC1E,EAAE;AACN,QAAO,QAAQ,SAAS,IAAI,QAAQ,KAAK,KAAK,GAAG,KAAA;;AAGnD,SAAgB,wBAAwB,MAAwB;AAC9D,QACE,SAAS,iBACT,SAAS,qBACT,SAAS,sBACT,SAAS,eACT,SAAS,gBACT,SAAS;;AAIb,SAAgB,sBAAsB,MAAmC;AACvE,KAAI,KAAK,SAAS,eAAe;EAC/B,MAAM,SAAS,WAAW,KAAK,OAAO;EACtC,MAAM,OAAO,WAAW,KAAK,KAAK,IAAI;AACtC,SAAO,SAAS,OAAO,OAAO,GAAG,SAAS,OAAO;;AAEnD,KAAI,KAAK,SAAS,mBAAmB;EACnC,MAAM,YAAY,WAAW,KAAK,UAAU;EAC5C,MAAM,OAAO,WAAW,KAAK,KAAK,IAAI;AACtC,SAAO,YAAY,GAAG,UAAU,GAAG,SAAS;;AAE9C,QAAO,WAAW,KAAK,KAAK,IAAI;;AAGlC,SAAgB,sBAAsB,MAAoC;AACxE,KAAI,KAAK,SAAS,iBAAiB,KAAK,SAAS,kBAC/C,QAAO,KAAK;AAEd,KAAI,KAAK,SAAS,mBAChB,QAAO;EAAE,SAAS,KAAK;EAAS,KAAK,KAAK;EAAK;AAEjD,KAAI,KAAK,SAAS,YAChB,QAAO;EAAE,OAAO,KAAK;EAAO,QAAQ,KAAK;EAAQ;AAEnD,KAAI,KAAK,SAAS,aAChB,QAAO,EAAE,SAAS,KAAK,SAAS;AAElC,KAAI,KAAK,SAAS,OAChB,QAAO,EAAE,MAAM,KAAK,MAAM;AAE5B,QAAO,EAAE;;AAGX,SAAgB,wBAAwB,MAAoC;AAC1E,KAAI,KAAK,SAAS,iBAAiB,KAAK,SAAS,kBAC/C,QAAO;EACL,QAAQ,KAAK;EACb,QAAQ,KAAK,UAAU,KAAK,gBAAgB;EAC5C,OAAO,KAAK,SAAS;EACtB;AAEH,KAAI,KAAK,SAAS,mBAChB,QAAO;EACL,QAAQ,KAAK;EACb,SAAS,KAAK;EACd,mBAAmB,KAAK;EACxB,WAAW,KAAK;EACjB;AAEH,QAAO;;AAGT,SAAgB,2BAA2B,MAAuB;AAChE,KAAI;AACF,SAAO,KAAK,UAAU,QAAQ,EAAE,CAAC;SAC3B;AACN,SAAO,KAAK,UAAU,EACpB,yBAAyB,4CAC1B,CAAC;;;AAIN,SAAS,WAAW,OAAoC;AACtD,KAAI,OAAO,UAAU,SACnB;CAEF,MAAM,UAAU,MAAM,MAAM;AAC5B,QAAO,QAAQ,SAAS,IAAI,UAAU,KAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/utils/codex-app-server-request.utils.ts
|
|
2
|
+
function toAppServerInput(input) {
|
|
3
|
+
if (typeof input === "string") return input.trim() ? [{
|
|
4
|
+
type: "text",
|
|
5
|
+
text: input
|
|
6
|
+
}] : [];
|
|
7
|
+
const out = [];
|
|
8
|
+
for (const item of input) {
|
|
9
|
+
if (item.type === "text") {
|
|
10
|
+
out.push({
|
|
11
|
+
type: "text",
|
|
12
|
+
text: item.text
|
|
13
|
+
});
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (item.type === "local_image") out.push({
|
|
17
|
+
type: "localImage",
|
|
18
|
+
path: item.path
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
function splitModelRoute(value) {
|
|
24
|
+
const normalized = readString(value);
|
|
25
|
+
if (!normalized) return {};
|
|
26
|
+
const slashIndex = normalized.indexOf("/");
|
|
27
|
+
if (slashIndex <= 0 || slashIndex === normalized.length - 1) return { model: normalized };
|
|
28
|
+
return {
|
|
29
|
+
modelProvider: normalized.slice(0, slashIndex),
|
|
30
|
+
model: normalized.slice(slashIndex + 1)
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function compactObject(value) {
|
|
34
|
+
const out = {};
|
|
35
|
+
for (const [key, child] of Object.entries(value)) if (child !== void 0) out[key] = child;
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
function normalizeSandbox(value) {
|
|
39
|
+
if (value === "read-only" || value === "workspace-write" || value === "danger-full-access") return value;
|
|
40
|
+
}
|
|
41
|
+
function readString(value) {
|
|
42
|
+
if (typeof value !== "string") return;
|
|
43
|
+
const trimmed = value.trim();
|
|
44
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { compactObject, normalizeSandbox, splitModelRoute, toAppServerInput };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=codex-app-server-request.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-app-server-request.utils.js","names":[],"sources":["../../src/utils/codex-app-server-request.utils.ts"],"sourcesContent":["import type { ThreadOptions } from \"@openai/codex-sdk\";\nimport type { CodexThreadInput } from \"@/codex-input.utils.js\";\nimport type { JsonObject } from \"@/types/codex-app-server-runtime.types.js\";\n\ntype AppServerUserInput =\n | { type: \"text\"; text: string }\n | { type: \"localImage\"; path: string };\n\nexport function toAppServerInput(input: CodexThreadInput): AppServerUserInput[] {\n if (typeof input === \"string\") {\n return input.trim() ? [{ type: \"text\", text: input }] : [];\n }\n const out: AppServerUserInput[] = [];\n for (const item of input) {\n if (item.type === \"text\") {\n out.push({ type: \"text\", text: item.text });\n continue;\n }\n if (item.type === \"local_image\") {\n out.push({ type: \"localImage\", path: item.path });\n }\n }\n return out;\n}\n\nexport function splitModelRoute(value: string | undefined): {\n model?: string;\n modelProvider?: string;\n} {\n const normalized = readString(value);\n if (!normalized) {\n return {};\n }\n const slashIndex = normalized.indexOf(\"/\");\n if (slashIndex <= 0 || slashIndex === normalized.length - 1) {\n return { model: normalized };\n }\n return {\n modelProvider: normalized.slice(0, slashIndex),\n model: normalized.slice(slashIndex + 1),\n };\n}\n\nexport function compactObject(value: JsonObject): JsonObject {\n const out: JsonObject = {};\n for (const [key, child] of Object.entries(value)) {\n if (child !== undefined) {\n out[key] = child;\n }\n }\n return out;\n}\n\nexport function normalizeSandbox(\n value: ThreadOptions[\"sandboxMode\"] | undefined,\n): string | undefined {\n if (value === \"read-only\" || value === \"workspace-write\" || value === \"danger-full-access\") {\n return value;\n }\n return undefined;\n}\n\nfunction readString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n"],"mappings":";AAQA,SAAgB,iBAAiB,OAA+C;AAC9E,KAAI,OAAO,UAAU,SACnB,QAAO,MAAM,MAAM,GAAG,CAAC;EAAE,MAAM;EAAQ,MAAM;EAAO,CAAC,GAAG,EAAE;CAE5D,MAAM,MAA4B,EAAE;AACpC,MAAK,MAAM,QAAQ,OAAO;AACxB,MAAI,KAAK,SAAS,QAAQ;AACxB,OAAI,KAAK;IAAE,MAAM;IAAQ,MAAM,KAAK;IAAM,CAAC;AAC3C;;AAEF,MAAI,KAAK,SAAS,cAChB,KAAI,KAAK;GAAE,MAAM;GAAc,MAAM,KAAK;GAAM,CAAC;;AAGrD,QAAO;;AAGT,SAAgB,gBAAgB,OAG9B;CACA,MAAM,aAAa,WAAW,MAAM;AACpC,KAAI,CAAC,WACH,QAAO,EAAE;CAEX,MAAM,aAAa,WAAW,QAAQ,IAAI;AAC1C,KAAI,cAAc,KAAK,eAAe,WAAW,SAAS,EACxD,QAAO,EAAE,OAAO,YAAY;AAE9B,QAAO;EACL,eAAe,WAAW,MAAM,GAAG,WAAW;EAC9C,OAAO,WAAW,MAAM,aAAa,EAAE;EACxC;;AAGH,SAAgB,cAAc,OAA+B;CAC3D,MAAM,MAAkB,EAAE;AAC1B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,CAC9C,KAAI,UAAU,KAAA,EACZ,KAAI,OAAO;AAGf,QAAO;;AAGT,SAAgB,iBACd,OACoB;AACpB,KAAI,UAAU,eAAe,UAAU,qBAAqB,UAAU,qBACpE,QAAO;;AAKX,SAAS,WAAW,OAAoC;AACtD,KAAI,OAAO,UAAU,SACnB;CAEF,MAAM,UAAU,MAAM,MAAM;AAC5B,QAAO,QAAQ,SAAS,IAAI,UAAU,KAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readArray, readRawString, readRecord, readString } from "
|
|
1
|
+
import { readArray, readRawString, readRecord, readString } from "../codex-openai-responses-bridge-shared.utils.js";
|
|
2
2
|
import { normalizeAssistantText } from "@nextclaw/ncp";
|
|
3
|
-
//#region src/codex-openai-responses-bridge-assistant-output.utils.ts
|
|
3
|
+
//#region src/utils/codex-openai-responses-bridge-assistant-output.utils.ts
|
|
4
4
|
function extractAssistantText(content) {
|
|
5
5
|
if (typeof content === "string") return content;
|
|
6
6
|
if (!Array.isArray(content)) return "";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-openai-responses-bridge-assistant-output.utils.js","names":[],"sources":["../../src/utils/codex-openai-responses-bridge-assistant-output.utils.ts"],"sourcesContent":["import type { ServerResponse } from \"node:http\";\nimport { normalizeAssistantText } from \"@nextclaw/ncp\";\nimport {\n nextSequenceNumber,\n readArray,\n readRecord,\n readRawString,\n readString,\n writeSseEvent,\n type OpenAiChatCompletionChoiceMessage,\n type OpenResponsesOutputItem,\n type StreamSequenceState,\n} from \"@/codex-openai-responses-bridge-shared.utils.js\";\n\nfunction extractAssistantText(content: unknown): string {\n if (typeof content === \"string\") {\n return content;\n }\n if (!Array.isArray(content)) {\n return \"\";\n }\n return content\n .map((entry) => {\n const record = readRecord(entry);\n if (!record) {\n return \"\";\n }\n const type = readString(record.type);\n if (type === \"text\" || type === \"output_text\") {\n return readString(record.text) ?? \"\";\n }\n return \"\";\n })\n .filter(Boolean)\n .join(\"\");\n}\n\ntype ReasoningExtraction = {\n present: boolean;\n text: string;\n};\n\nfunction readReasoningRecordText(value: unknown): string {\n const record = readRecord(value);\n if (!record) {\n return \"\";\n }\n return (\n readRawString(record.text) ??\n readRawString(record.content) ??\n readRawString(record.reasoning) ??\n readRawString(record.reasoning_content) ??\n readRawString(record.thinking) ??\n \"\"\n );\n}\n\nfunction extractReasoningDetailsText(value: unknown): ReasoningExtraction | undefined {\n const rawString = readRawString(value);\n if (rawString !== undefined) {\n return {\n present: true,\n text: rawString,\n };\n }\n\n const record = readRecord(value);\n if (record) {\n return {\n present: true,\n text: readReasoningRecordText(record),\n };\n }\n\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const text = readArray(value)\n .map((entry) => readReasoningRecordText(entry))\n .join(\"\");\n return {\n present: true,\n text,\n };\n}\n\nfunction extractContentReasoningText(content: unknown): string {\n if (!Array.isArray(content)) {\n return \"\";\n }\n return content\n .map((entry) => {\n const record = readRecord(entry);\n if (!record) {\n return \"\";\n }\n const type = readString(record.type);\n if (\n type === \"reasoning\" ||\n type === \"reasoning_text\" ||\n type === \"thinking\" ||\n type === \"thinking_text\"\n ) {\n return readReasoningRecordText(record);\n }\n return \"\";\n })\n .join(\"\");\n}\n\nfunction extractExplicitReasoning(\n message: OpenAiChatCompletionChoiceMessage | undefined,\n): ReasoningExtraction | undefined {\n const candidates = [\n message?.reasoning_content,\n message?.reasoning,\n message?.thinking,\n message?.reasoning_details,\n ];\n\n for (const candidate of candidates) {\n const extracted = extractReasoningDetailsText(candidate);\n if (extracted) {\n return extracted;\n }\n }\n\n const contentReasoning = extractContentReasoningText(message?.content);\n return contentReasoning\n ? {\n present: true,\n text: contentReasoning,\n }\n : undefined;\n}\n\nfunction extractAssistantOutput(message: OpenAiChatCompletionChoiceMessage | undefined): {\n text: string;\n reasoning: string;\n reasoningPresent: boolean;\n} {\n const rawText = extractAssistantText(message?.content);\n const normalized = normalizeAssistantText(rawText, \"think-tags\");\n const explicitReasoning = extractExplicitReasoning(message);\n const reasoning = explicitReasoning?.text ?? readString(normalized.reasoning) ?? \"\";\n const reasoningPresent = explicitReasoning?.present === true || Boolean(normalized.reasoning);\n const text =\n explicitReasoning?.present === true\n ? readString(normalized.text) ?? readString(rawText) ?? \"\"\n : normalized.reasoning\n ? readString(normalized.text) ?? \"\"\n : readString(rawText) ?? \"\";\n\n return {\n text,\n reasoning,\n reasoningPresent,\n };\n}\n\nfunction buildInProgressReasoningItem(item: OpenResponsesOutputItem): OpenResponsesOutputItem {\n return {\n ...structuredClone(item),\n status: \"in_progress\",\n content: [],\n summary: [],\n };\n}\n\nexport function buildAssistantOutputItems(params: {\n message: OpenAiChatCompletionChoiceMessage | undefined;\n responseId: string;\n}): OpenResponsesOutputItem[] {\n const { reasoning, reasoningPresent, text } = extractAssistantOutput(params.message);\n const outputItems: OpenResponsesOutputItem[] = [];\n\n if (reasoningPresent) {\n outputItems.push({\n type: \"reasoning\",\n id: `${params.responseId}:reasoning:0`,\n summary: [\n {\n type: \"summary_text\",\n text: reasoning,\n },\n ],\n content: [\n {\n type: \"reasoning_text\",\n text: reasoning,\n },\n ],\n status: \"completed\",\n });\n }\n\n if (text) {\n outputItems.push({\n type: \"message\",\n id: `${params.responseId}:message:${outputItems.length}`,\n role: \"assistant\",\n status: \"completed\",\n content: [\n {\n type: \"output_text\",\n text,\n annotations: [],\n },\n ],\n });\n }\n\n return outputItems;\n}\n\nexport function writeReasoningOutputItemEvents(params: {\n response: ServerResponse;\n item: OpenResponsesOutputItem;\n outputIndex: number;\n sequenceState: StreamSequenceState;\n}): void {\n const { item, outputIndex, response, sequenceState } = params;\n const itemId = readString(item.id);\n const content = readArray(item.content);\n const textPart = content.find((entry) => readString(readRecord(entry)?.type) === \"reasoning_text\");\n const text = readString(readRecord(textPart)?.text) ?? \"\";\n const summary = readArray(item.summary);\n const summaryIndex = summary.findIndex((entry) => readString(readRecord(entry)?.type) === \"summary_text\");\n const summaryText =\n summaryIndex >= 0 ? readString(readRecord(summary[summaryIndex])?.text) ?? \"\" : \"\";\n\n writeSseEvent(response, \"response.output_item.added\", {\n type: \"response.output_item.added\",\n sequence_number: nextSequenceNumber(sequenceState),\n output_index: outputIndex,\n item: buildInProgressReasoningItem(item),\n });\n\n if (itemId && summaryText) {\n writeSseEvent(response, \"response.reasoning_summary_part.added\", {\n type: \"response.reasoning_summary_part.added\",\n sequence_number: nextSequenceNumber(sequenceState),\n output_index: outputIndex,\n item_id: itemId,\n summary_index: summaryIndex,\n part: {\n type: \"summary_text\",\n text: \"\",\n },\n });\n writeSseEvent(response, \"response.reasoning_summary_text.delta\", {\n type: \"response.reasoning_summary_text.delta\",\n sequence_number: nextSequenceNumber(sequenceState),\n output_index: outputIndex,\n item_id: itemId,\n summary_index: summaryIndex,\n delta: summaryText,\n });\n writeSseEvent(response, \"response.reasoning_summary_text.done\", {\n type: \"response.reasoning_summary_text.done\",\n sequence_number: nextSequenceNumber(sequenceState),\n output_index: outputIndex,\n item_id: itemId,\n summary_index: summaryIndex,\n text: summaryText,\n });\n writeSseEvent(response, \"response.reasoning_summary_part.done\", {\n type: \"response.reasoning_summary_part.done\",\n sequence_number: nextSequenceNumber(sequenceState),\n output_index: outputIndex,\n item_id: itemId,\n summary_index: summaryIndex,\n part: {\n type: \"summary_text\",\n text: summaryText,\n },\n });\n }\n\n if (itemId) {\n writeSseEvent(response, \"response.reasoning_text.done\", {\n type: \"response.reasoning_text.done\",\n sequence_number: nextSequenceNumber(sequenceState),\n output_index: outputIndex,\n item_id: itemId,\n content_index: 0,\n text,\n });\n }\n\n writeSseEvent(response, \"response.output_item.done\", {\n type: \"response.output_item.done\",\n sequence_number: nextSequenceNumber(sequenceState),\n output_index: outputIndex,\n item,\n });\n}\n"],"mappings":"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"}
|