lunel-cli 0.1.46 → 0.1.47
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/ai/codex.d.ts +5 -0
- package/dist/ai/codex.js +100 -19
- package/package.json +1 -1
package/dist/ai/codex.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export declare class CodexProvider implements AIProvider {
|
|
|
6
6
|
private nextId;
|
|
7
7
|
private pending;
|
|
8
8
|
private sessions;
|
|
9
|
+
private sessionIdByThreadId;
|
|
9
10
|
init(): Promise<void>;
|
|
10
11
|
destroy(): Promise<void>;
|
|
11
12
|
subscribe(emitter: AiEventEmitter): () => void;
|
|
@@ -43,4 +44,8 @@ export declare class CodexProvider implements AIProvider {
|
|
|
43
44
|
private send;
|
|
44
45
|
private call;
|
|
45
46
|
private handleLine;
|
|
47
|
+
private ensureThread;
|
|
48
|
+
private ingestThreadMetadata;
|
|
49
|
+
private extractThreadId;
|
|
50
|
+
private readString;
|
|
46
51
|
}
|
package/dist/ai/codex.js
CHANGED
|
@@ -28,6 +28,7 @@ export class CodexProvider {
|
|
|
28
28
|
nextId = 1;
|
|
29
29
|
pending = new Map();
|
|
30
30
|
sessions = new Map();
|
|
31
|
+
sessionIdByThreadId = new Map();
|
|
31
32
|
// -------------------------------------------------------------------------
|
|
32
33
|
// Lifecycle
|
|
33
34
|
// -------------------------------------------------------------------------
|
|
@@ -76,10 +77,7 @@ export class CodexProvider {
|
|
|
76
77
|
this.sessions.set(id, session);
|
|
77
78
|
// Start a new Codex thread for this session.
|
|
78
79
|
try {
|
|
79
|
-
|
|
80
|
-
if (result?.threadId) {
|
|
81
|
-
session.threadId = result.threadId;
|
|
82
|
-
}
|
|
80
|
+
await this.ensureThread(session);
|
|
83
81
|
}
|
|
84
82
|
catch (err) {
|
|
85
83
|
console.warn("[codex] thread/start failed:", err.message);
|
|
@@ -102,6 +100,10 @@ export class CodexProvider {
|
|
|
102
100
|
return { session: { id: s.id, title: s.title ?? "", created: s.createdAt } };
|
|
103
101
|
}
|
|
104
102
|
async deleteSession(id) {
|
|
103
|
+
const session = this.sessions.get(id);
|
|
104
|
+
if (session?.threadId) {
|
|
105
|
+
this.sessionIdByThreadId.delete(session.threadId);
|
|
106
|
+
}
|
|
105
107
|
this.sessions.delete(id);
|
|
106
108
|
return {};
|
|
107
109
|
}
|
|
@@ -117,7 +119,6 @@ export class CodexProvider {
|
|
|
117
119
|
// -------------------------------------------------------------------------
|
|
118
120
|
async prompt(sessionId, text, model, agent) {
|
|
119
121
|
const session = this.sessions.get(sessionId);
|
|
120
|
-
const threadId = session?.threadId;
|
|
121
122
|
// Append the user message to local history immediately.
|
|
122
123
|
if (session) {
|
|
123
124
|
session.messages.push({
|
|
@@ -128,20 +129,33 @@ export class CodexProvider {
|
|
|
128
129
|
});
|
|
129
130
|
}
|
|
130
131
|
// Fire-and-forget — the response streams back as JSON-RPC notifications.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
132
|
+
(async () => {
|
|
133
|
+
try {
|
|
134
|
+
if (!session) {
|
|
135
|
+
throw new Error(`Session ${sessionId} not found`);
|
|
136
|
+
}
|
|
137
|
+
const threadId = await this.ensureThread(session);
|
|
138
|
+
await this.call("turn/start", {
|
|
139
|
+
threadId,
|
|
140
|
+
input: [{ type: "message", role: "user", content: [{ type: "input_text", text }] }],
|
|
141
|
+
...(model ? { model: `${model.providerID}/${model.modelID}` } : {}),
|
|
142
|
+
...(agent ? { agent } : {}),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
const message = err.message;
|
|
147
|
+
console.error("[codex] turn/start error:", message);
|
|
148
|
+
this.emitter?.({ type: "prompt_error", properties: { sessionId, error: message } });
|
|
149
|
+
}
|
|
150
|
+
})();
|
|
140
151
|
return { ack: true };
|
|
141
152
|
}
|
|
142
153
|
async abort(sessionId) {
|
|
143
154
|
const session = this.sessions.get(sessionId);
|
|
144
|
-
|
|
155
|
+
if (!session?.threadId) {
|
|
156
|
+
throw new Error(`Session ${sessionId} has no active Codex thread`);
|
|
157
|
+
}
|
|
158
|
+
await this.call("turn/abort", { threadId: session.threadId });
|
|
145
159
|
return {};
|
|
146
160
|
}
|
|
147
161
|
// -------------------------------------------------------------------------
|
|
@@ -181,8 +195,11 @@ export class CodexProvider {
|
|
|
181
195
|
// -------------------------------------------------------------------------
|
|
182
196
|
async command(sessionId, command, args) {
|
|
183
197
|
const session = this.sessions.get(sessionId);
|
|
198
|
+
if (!session?.threadId) {
|
|
199
|
+
throw new Error(`Session ${sessionId} has no active Codex thread`);
|
|
200
|
+
}
|
|
184
201
|
const result = await this.call("session/command", {
|
|
185
|
-
|
|
202
|
+
threadId: session.threadId,
|
|
186
203
|
command,
|
|
187
204
|
arguments: args,
|
|
188
205
|
});
|
|
@@ -190,16 +207,22 @@ export class CodexProvider {
|
|
|
190
207
|
}
|
|
191
208
|
async revert(sessionId, messageId) {
|
|
192
209
|
const session = this.sessions.get(sessionId);
|
|
210
|
+
if (!session?.threadId) {
|
|
211
|
+
throw new Error(`Session ${sessionId} has no active Codex thread`);
|
|
212
|
+
}
|
|
193
213
|
await this.call("session/revert", {
|
|
194
|
-
|
|
214
|
+
threadId: session.threadId,
|
|
195
215
|
messageId,
|
|
196
216
|
});
|
|
197
217
|
return {};
|
|
198
218
|
}
|
|
199
219
|
async unrevert(sessionId) {
|
|
200
220
|
const session = this.sessions.get(sessionId);
|
|
221
|
+
if (!session?.threadId) {
|
|
222
|
+
throw new Error(`Session ${sessionId} has no active Codex thread`);
|
|
223
|
+
}
|
|
201
224
|
await this.call("session/unrevert", {
|
|
202
|
-
|
|
225
|
+
threadId: session.threadId,
|
|
203
226
|
});
|
|
204
227
|
return {};
|
|
205
228
|
}
|
|
@@ -209,8 +232,11 @@ export class CodexProvider {
|
|
|
209
232
|
}
|
|
210
233
|
async permissionReply(sessionId, permissionId, response) {
|
|
211
234
|
const session = this.sessions.get(sessionId);
|
|
235
|
+
if (!session?.threadId) {
|
|
236
|
+
throw new Error(`Session ${sessionId} has no active Codex thread`);
|
|
237
|
+
}
|
|
212
238
|
await this.call("session/permission", {
|
|
213
|
-
|
|
239
|
+
threadId: session.threadId,
|
|
214
240
|
permissionId,
|
|
215
241
|
response,
|
|
216
242
|
});
|
|
@@ -265,7 +291,62 @@ export class CodexProvider {
|
|
|
265
291
|
const notif = msg;
|
|
266
292
|
const params = (notif.params ?? {});
|
|
267
293
|
const mappedType = NOTIFICATION_TYPE_MAP[notif.method] ?? notif.method;
|
|
294
|
+
this.ingestThreadMetadata(params);
|
|
268
295
|
console.log("[codex]", notif.method);
|
|
269
296
|
this.emitter?.({ type: mappedType, properties: params });
|
|
270
297
|
}
|
|
298
|
+
async ensureThread(session) {
|
|
299
|
+
if (session.threadId)
|
|
300
|
+
return session.threadId;
|
|
301
|
+
const result = await this.call("thread/start", {
|
|
302
|
+
...(session.title ? { title: session.title } : {}),
|
|
303
|
+
});
|
|
304
|
+
const threadId = this.extractThreadId(result);
|
|
305
|
+
if (!threadId) {
|
|
306
|
+
throw new Error("thread/start response missing threadId");
|
|
307
|
+
}
|
|
308
|
+
session.threadId = threadId;
|
|
309
|
+
this.sessionIdByThreadId.set(threadId, session.id);
|
|
310
|
+
return threadId;
|
|
311
|
+
}
|
|
312
|
+
ingestThreadMetadata(payload) {
|
|
313
|
+
const threadId = this.extractThreadId(payload);
|
|
314
|
+
if (!threadId)
|
|
315
|
+
return;
|
|
316
|
+
const sessionId = this.sessionIdByThreadId.get(threadId);
|
|
317
|
+
if (sessionId) {
|
|
318
|
+
const session = this.sessions.get(sessionId);
|
|
319
|
+
if (session) {
|
|
320
|
+
session.threadId = threadId;
|
|
321
|
+
}
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
for (const session of this.sessions.values()) {
|
|
325
|
+
if (!session.threadId) {
|
|
326
|
+
session.threadId = threadId;
|
|
327
|
+
this.sessionIdByThreadId.set(threadId, session.id);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
extractThreadId(payload) {
|
|
333
|
+
if (!payload || typeof payload !== "object")
|
|
334
|
+
return undefined;
|
|
335
|
+
const obj = payload;
|
|
336
|
+
const direct = this.readString(obj.threadId) ??
|
|
337
|
+
this.readString(obj.thread_id);
|
|
338
|
+
if (direct)
|
|
339
|
+
return direct;
|
|
340
|
+
const thread = obj.thread;
|
|
341
|
+
if (thread && typeof thread === "object") {
|
|
342
|
+
const threadObj = thread;
|
|
343
|
+
return (this.readString(threadObj.id) ??
|
|
344
|
+
this.readString(threadObj.threadId) ??
|
|
345
|
+
this.readString(threadObj.thread_id));
|
|
346
|
+
}
|
|
347
|
+
return undefined;
|
|
348
|
+
}
|
|
349
|
+
readString(value) {
|
|
350
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
351
|
+
}
|
|
271
352
|
}
|