lunel-cli 0.1.60 → 0.1.61
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 +4 -0
- package/dist/ai/codex.js +92 -12
- package/package.json +1 -1
package/dist/ai/codex.d.ts
CHANGED
|
@@ -74,7 +74,11 @@ export declare class CodexProvider implements AIProvider {
|
|
|
74
74
|
private resolveSessionFromPayload;
|
|
75
75
|
private resolveInFlightTurnId;
|
|
76
76
|
private decodeMessagesFromThreadRead;
|
|
77
|
+
private decodeUserMessageParts;
|
|
77
78
|
private decodeItemText;
|
|
79
|
+
private makeTurnInputPayload;
|
|
80
|
+
private shouldRetryTurnStartWithImageURLField;
|
|
81
|
+
private inferImageMimeFromDataUrl;
|
|
78
82
|
private decodeReasoningItemText;
|
|
79
83
|
private decodePlanItemText;
|
|
80
84
|
private decodeCommandExecutionItemText;
|
package/dist/ai/codex.js
CHANGED
|
@@ -121,19 +121,31 @@ export class CodexProvider {
|
|
|
121
121
|
return { messages: session.messages };
|
|
122
122
|
}
|
|
123
123
|
async prompt(sessionId, text, model, agent, files = []) {
|
|
124
|
-
if (files.length > 0) {
|
|
125
|
-
throw new Error("Codex image attachments are not supported in Lunel yet");
|
|
126
|
-
}
|
|
127
124
|
const session = this.ensureLocalSession(sessionId);
|
|
128
125
|
session.updatedAt = Date.now();
|
|
129
126
|
(async () => {
|
|
130
127
|
try {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
128
|
+
let imageUrlKey = "url";
|
|
129
|
+
while (true) {
|
|
130
|
+
try {
|
|
131
|
+
await this.call("turn/start", {
|
|
132
|
+
threadId: session.id,
|
|
133
|
+
input: this.makeTurnInputPayload(text, files, imageUrlKey),
|
|
134
|
+
...(model ? { model: model.providerID === "codex" ? model.modelID : `${model.providerID}/${model.modelID}` } : {}),
|
|
135
|
+
...(agent ? { agent } : {}),
|
|
136
|
+
});
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
if (imageUrlKey === "url"
|
|
141
|
+
&& files.length > 0
|
|
142
|
+
&& this.shouldRetryTurnStartWithImageURLField(err)) {
|
|
143
|
+
imageUrlKey = "image_url";
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
throw err;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
137
149
|
}
|
|
138
150
|
catch (err) {
|
|
139
151
|
const message = err.message;
|
|
@@ -860,13 +872,13 @@ export class CodexProvider {
|
|
|
860
872
|
const itemId = this.readString(itemObject.id) ?? crypto.randomUUID();
|
|
861
873
|
const timestamp = this.extractUpdatedAt(itemObject) ?? this.extractCreatedAt(itemObject) ?? (turnTime + orderOffset++);
|
|
862
874
|
if (type === "usermessage") {
|
|
863
|
-
const
|
|
864
|
-
if (
|
|
875
|
+
const parts = this.decodeUserMessageParts(itemObject, threadId, itemId);
|
|
876
|
+
if (parts.length === 0)
|
|
865
877
|
continue;
|
|
866
878
|
messages.push({
|
|
867
879
|
id: itemId,
|
|
868
880
|
role: "user",
|
|
869
|
-
parts
|
|
881
|
+
parts,
|
|
870
882
|
time: timestamp,
|
|
871
883
|
});
|
|
872
884
|
continue;
|
|
@@ -957,6 +969,40 @@ export class CodexProvider {
|
|
|
957
969
|
}
|
|
958
970
|
return messages;
|
|
959
971
|
}
|
|
972
|
+
decodeUserMessageParts(itemObject, threadId, itemId) {
|
|
973
|
+
const parts = [];
|
|
974
|
+
const content = this.readArray(itemObject.content);
|
|
975
|
+
let fileIndex = 0;
|
|
976
|
+
for (const entry of content) {
|
|
977
|
+
const obj = this.asRecord(entry);
|
|
978
|
+
const type = this.normalizedItemType(this.readString(obj.type) ?? "");
|
|
979
|
+
if (type === "image" || type === "localimage") {
|
|
980
|
+
const url = this.readString(obj.url) ?? this.readString(obj.image_url) ?? this.readString(obj.imageUrl);
|
|
981
|
+
if (!url)
|
|
982
|
+
continue;
|
|
983
|
+
parts.push({
|
|
984
|
+
id: `${itemId}:file:${fileIndex++}`,
|
|
985
|
+
type: "file",
|
|
986
|
+
mime: this.inferImageMimeFromDataUrl(url),
|
|
987
|
+
filename: this.readString(obj.filename) ?? this.readString(obj.name) ?? undefined,
|
|
988
|
+
url,
|
|
989
|
+
sessionID: threadId,
|
|
990
|
+
messageID: itemId,
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
const text = this.decodeItemText(itemObject);
|
|
995
|
+
if (text) {
|
|
996
|
+
parts.push({
|
|
997
|
+
id: `${itemId}:text`,
|
|
998
|
+
type: "text",
|
|
999
|
+
text,
|
|
1000
|
+
sessionID: threadId,
|
|
1001
|
+
messageID: itemId,
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
return parts;
|
|
1005
|
+
}
|
|
960
1006
|
decodeItemText(itemObject) {
|
|
961
1007
|
const content = this.readArray(itemObject.content);
|
|
962
1008
|
const parts = [];
|
|
@@ -977,6 +1023,40 @@ export class CodexProvider {
|
|
|
977
1023
|
const joined = parts.join("\n").trim();
|
|
978
1024
|
return joined || this.readString(itemObject.text) || this.readString(itemObject.message) || "";
|
|
979
1025
|
}
|
|
1026
|
+
makeTurnInputPayload(text, files, imageUrlKey) {
|
|
1027
|
+
const items = [];
|
|
1028
|
+
for (const file of files) {
|
|
1029
|
+
const url = typeof file.url === "string" ? file.url.trim() : "";
|
|
1030
|
+
if (!url)
|
|
1031
|
+
continue;
|
|
1032
|
+
items.push({
|
|
1033
|
+
type: "image",
|
|
1034
|
+
[imageUrlKey]: url,
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
const trimmedText = text.trim();
|
|
1038
|
+
if (trimmedText) {
|
|
1039
|
+
items.push({ type: "text", text: trimmedText });
|
|
1040
|
+
}
|
|
1041
|
+
return items;
|
|
1042
|
+
}
|
|
1043
|
+
shouldRetryTurnStartWithImageURLField(error) {
|
|
1044
|
+
const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
|
|
1045
|
+
if (!message.includes("image_url")) {
|
|
1046
|
+
return false;
|
|
1047
|
+
}
|
|
1048
|
+
return (message.includes("missing")
|
|
1049
|
+
|| message.includes("unknown field")
|
|
1050
|
+
|| message.includes("expected")
|
|
1051
|
+
|| message.includes("invalid"));
|
|
1052
|
+
}
|
|
1053
|
+
inferImageMimeFromDataUrl(url) {
|
|
1054
|
+
const match = /^data:([^;,]+)[;,]/i.exec(url);
|
|
1055
|
+
if (match?.[1]) {
|
|
1056
|
+
return match[1];
|
|
1057
|
+
}
|
|
1058
|
+
return "image/jpeg";
|
|
1059
|
+
}
|
|
980
1060
|
decodeReasoningItemText(itemObject) {
|
|
981
1061
|
const summary = this.flattenTextValue(itemObject.summary).trim();
|
|
982
1062
|
const content = this.flattenTextValue(itemObject.content).trim();
|