lunel-cli 0.1.48 → 0.1.50

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.
@@ -58,6 +58,7 @@ export declare class CodexProvider implements AIProvider {
58
58
  private ensureAssistantMessage;
59
59
  private upsertLocalMessagePart;
60
60
  private fetchServerThreads;
61
+ private fetchModels;
61
62
  private parseThreadListEntry;
62
63
  private hasNextCursor;
63
64
  private ingestThreadMetadata;
@@ -94,6 +95,9 @@ export declare class CodexProvider implements AIProvider {
94
95
  private isAssistantMessageItem;
95
96
  private extractIncomingItem;
96
97
  private describeToolPart;
98
+ private normalizeStructuredType;
99
+ private extractStructuredOutput;
100
+ private extractDiffLikePayload;
97
101
  private extractToolInput;
98
102
  private describeCompletedItemOutput;
99
103
  }
package/dist/ai/codex.js CHANGED
@@ -119,7 +119,7 @@ export class CodexProvider {
119
119
  await this.call("turn/start", {
120
120
  threadId: session.id,
121
121
  input: [{ type: "text", text }],
122
- ...(model ? { model: `${model.providerID}/${model.modelID}` } : {}),
122
+ ...(model ? { model: model.providerID === "codex" ? model.modelID : `${model.providerID}/${model.modelID}` } : {}),
123
123
  ...(agent ? { agent } : {}),
124
124
  });
125
125
  }
@@ -145,7 +145,23 @@ export class CodexProvider {
145
145
  return { agents: [] };
146
146
  }
147
147
  async providers() {
148
- return { providers: [], default: {} };
148
+ const items = await this.fetchModels();
149
+ const models = Object.fromEntries(items.map((item) => [
150
+ item.model,
151
+ {
152
+ id: item.model,
153
+ name: item.displayName || item.model,
154
+ provider: "codex",
155
+ description: item.description,
156
+ },
157
+ ]));
158
+ const defaultModel = items.find((item) => item.isDefault)?.model;
159
+ return {
160
+ providers: items.length > 0
161
+ ? [{ id: "codex", name: "Codex", models }]
162
+ : [],
163
+ default: defaultModel ? { codex: defaultModel } : {},
164
+ };
149
165
  }
150
166
  async setAuth(providerId, key) {
151
167
  throw new Error("Codex auth configuration is not supported by Lunel yet");
@@ -486,10 +502,10 @@ export class CodexProvider {
486
502
  const turnId = this.extractTurnId(params) ?? session.activeTurnId ?? `session:${session.id}`;
487
503
  const messageId = this.ensureAssistantMessage(session, turnId);
488
504
  const item = this.extractIncomingItem(params);
489
- const normalizedType = this.normalizedItemType(this.readString(item.type) ?? method);
505
+ const normalizedType = this.normalizeStructuredType(this.readString(item.type) ?? method);
490
506
  const itemId = this.extractItemId(params) ?? this.readString(item.id) ?? normalizedType ?? "tool";
491
507
  const partId = `${messageId}:tool:${itemId}`;
492
- const nextText = this.extractTextPayload(params);
508
+ const nextText = this.extractStructuredOutput(params, item, normalizedType);
493
509
  const prevOutput = this.partTextById.get(partId) ?? "";
494
510
  const output = completed
495
511
  ? nextText ?? prevOutput
@@ -500,7 +516,7 @@ export class CodexProvider {
500
516
  const state = completed ? "completed" : "running";
501
517
  const name = this.describeToolPart(normalizedType, method, item);
502
518
  const input = this.extractToolInput(item, params);
503
- const outputValue = output || this.describeCompletedItemOutput(item, normalizedType) || undefined;
519
+ const outputValue = output || this.describeCompletedItemOutput(item, params, normalizedType) || undefined;
504
520
  const part = {
505
521
  id: partId,
506
522
  sessionID: session.id,
@@ -589,7 +605,13 @@ export class CodexProvider {
589
605
  cursor: nextCursor,
590
606
  });
591
607
  const payload = this.asRecord(result);
592
- const page = this.readArray(payload.data) ?? this.readArray(payload.items) ?? this.readArray(payload.threads) ?? [];
608
+ const page = Array.isArray(payload.data)
609
+ ? payload.data
610
+ : Array.isArray(payload.items)
611
+ ? payload.items
612
+ : Array.isArray(payload.threads)
613
+ ? payload.threads
614
+ : [];
593
615
  for (const entry of page) {
594
616
  const parsed = this.parseThreadListEntry(entry);
595
617
  if (parsed)
@@ -600,6 +622,39 @@ export class CodexProvider {
600
622
  } while (hasRequestedFirstPage && this.hasNextCursor(nextCursor));
601
623
  return threads;
602
624
  }
625
+ async fetchModels() {
626
+ const result = await this.call("model/list", {
627
+ cursor: null,
628
+ limit: 50,
629
+ includeHidden: false,
630
+ });
631
+ const payload = this.asRecord(result);
632
+ const items = Array.isArray(payload.items)
633
+ ? payload.items
634
+ : Array.isArray(payload.data)
635
+ ? payload.data
636
+ : Array.isArray(payload.models)
637
+ ? payload.models
638
+ : [];
639
+ return items
640
+ .map((value) => {
641
+ const obj = this.asRecord(value);
642
+ const model = this.readString(obj.model) ?? this.readString(obj.id);
643
+ if (!model)
644
+ return undefined;
645
+ const displayName = this.readString(obj.displayName)
646
+ ?? this.readString(obj.display_name)
647
+ ?? model;
648
+ return {
649
+ id: this.readString(obj.id) ?? model,
650
+ model,
651
+ displayName,
652
+ description: this.readString(obj.description) ?? "",
653
+ isDefault: Boolean(obj.isDefault ?? obj.is_default),
654
+ };
655
+ })
656
+ .filter((value) => Boolean(value));
657
+ }
603
658
  parseThreadListEntry(value) {
604
659
  const obj = this.asRecord(value);
605
660
  const id = this.extractThreadId(obj);
@@ -1028,10 +1083,61 @@ export class CodexProvider {
1028
1083
  }
1029
1084
  return this.readString(item.name) ?? method.replace(/^.*\//, "");
1030
1085
  }
1086
+ normalizeStructuredType(rawType) {
1087
+ const normalized = this.normalizedItemType(rawType);
1088
+ if (normalized.includes("turndiff") || normalized === "diff")
1089
+ return "diff";
1090
+ if (normalized.includes("filechange"))
1091
+ return "filechange";
1092
+ if (normalized.includes("toolcall"))
1093
+ return "toolcall";
1094
+ if (normalized.includes("commandexecution"))
1095
+ return "commandexecution";
1096
+ return normalized;
1097
+ }
1098
+ extractStructuredOutput(params, item, normalizedType) {
1099
+ if (normalizedType === "filechange" || normalizedType === "toolcall" || normalizedType === "diff") {
1100
+ return this.extractDiffLikePayload(params, item) ?? this.extractTextPayload(params);
1101
+ }
1102
+ return this.extractTextPayload(params);
1103
+ }
1104
+ extractDiffLikePayload(params, item) {
1105
+ const event = this.asRecord(params.event);
1106
+ const nestedItem = this.asRecord(event.item);
1107
+ const sources = [params, item, event, nestedItem];
1108
+ for (const source of sources) {
1109
+ const direct = this.firstString(source, [
1110
+ "diff",
1111
+ "unified_diff",
1112
+ "unifiedDiff",
1113
+ "patch",
1114
+ "text",
1115
+ "message",
1116
+ "summary",
1117
+ "output",
1118
+ "output_text",
1119
+ "outputText",
1120
+ ]);
1121
+ if (direct)
1122
+ return direct;
1123
+ }
1124
+ const changes = this.readArray(item.changes ?? params.changes ?? event.changes ?? nestedItem.changes);
1125
+ if (changes.length === 0)
1126
+ return undefined;
1127
+ return changes
1128
+ .map((change) => {
1129
+ const obj = this.asRecord(change);
1130
+ const path = this.readString(obj.path) ?? this.readString(obj.filePath) ?? this.readString(obj.file_path) ?? "file";
1131
+ const kind = this.readString(obj.kind) ?? "change";
1132
+ const diff = this.firstString(obj, ["diff", "unified_diff", "unifiedDiff", "patch"]) ?? "";
1133
+ return diff ? `Path: ${path}\nKind: ${kind}\n\n\`\`\`diff\n${diff}\n\`\`\`` : `Path: ${path}\nKind: ${kind}`;
1134
+ })
1135
+ .join("\n\n---\n\n");
1136
+ }
1031
1137
  extractToolInput(item, params) {
1032
1138
  return item.input ?? item.command ?? item.path ?? item.args ?? params.command ?? params.path ?? undefined;
1033
1139
  }
1034
- describeCompletedItemOutput(item, normalizedType) {
1140
+ describeCompletedItemOutput(item, params, normalizedType) {
1035
1141
  if (normalizedType === "commandexecution") {
1036
1142
  return this.firstString(item, ["stdout", "stderr", "text", "message", "summary"]);
1037
1143
  }
@@ -1039,7 +1145,7 @@ export class CodexProvider {
1039
1145
  return this.decodePlanItemText(item);
1040
1146
  }
1041
1147
  if (normalizedType === "filechange" || normalizedType === "toolcall" || normalizedType === "diff") {
1042
- return this.decodeFileLikeItemText(item);
1148
+ return this.extractDiffLikePayload(params, item) ?? this.decodeFileLikeItemText(item);
1043
1149
  }
1044
1150
  if (normalizedType === "enteredreviewmode") {
1045
1151
  return `Reviewing ${this.readString(item.review) ?? "changes"}...`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lunel-cli",
3
- "version": "0.1.48",
3
+ "version": "0.1.50",
4
4
  "author": [
5
5
  {
6
6
  "name": "Soham Bharambe",