ai-sdk-provider-codex-cli 0.3.0 → 0.5.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.js CHANGED
@@ -5,27 +5,66 @@ import { createRequire } from 'module';
5
5
  import { mkdtempSync, writeFileSync, rmSync, readFileSync } from 'fs';
6
6
  import { tmpdir } from 'os';
7
7
  import { join, dirname } from 'path';
8
- import { generateId } from '@ai-sdk/provider-utils';
9
8
  import { z } from 'zod';
9
+ import { parseProviderOptions, generateId } from '@ai-sdk/provider-utils';
10
10
 
11
11
  // src/codex-cli-provider.ts
12
12
 
13
13
  // src/logger.ts
14
14
  var defaultLogger = {
15
- warn: (m) => console.warn(m),
16
- error: (m) => console.error(m)
15
+ debug: (message) => console.debug(`[DEBUG] ${message}`),
16
+ info: (message) => console.info(`[INFO] ${message}`),
17
+ warn: (message) => console.warn(`[WARN] ${message}`),
18
+ error: (message) => console.error(`[ERROR] ${message}`)
17
19
  };
18
20
  var noopLogger = {
21
+ debug: () => {
22
+ },
23
+ info: () => {
24
+ },
19
25
  warn: () => {
20
26
  },
21
27
  error: () => {
22
28
  }
23
29
  };
24
30
  function getLogger(logger) {
25
- if (logger === false) return noopLogger;
26
- if (!logger) return defaultLogger;
31
+ if (logger === false) {
32
+ return noopLogger;
33
+ }
34
+ if (logger === void 0) {
35
+ return defaultLogger;
36
+ }
27
37
  return logger;
28
38
  }
39
+ function createVerboseLogger(logger, verbose = false) {
40
+ if (verbose) {
41
+ return logger;
42
+ }
43
+ return {
44
+ debug: () => {
45
+ },
46
+ // No-op when not verbose
47
+ info: () => {
48
+ },
49
+ // No-op when not verbose
50
+ warn: logger.warn.bind(logger),
51
+ error: logger.error.bind(logger)
52
+ };
53
+ }
54
+ var loggerFunctionSchema = z.object({
55
+ debug: z.any().refine((val) => typeof val === "function", {
56
+ message: "debug must be a function"
57
+ }),
58
+ info: z.any().refine((val) => typeof val === "function", {
59
+ message: "info must be a function"
60
+ }),
61
+ warn: z.any().refine((val) => typeof val === "function", {
62
+ message: "warn must be a function"
63
+ }),
64
+ error: z.any().refine((val) => typeof val === "function", {
65
+ message: "error must be a function"
66
+ })
67
+ });
29
68
  var settingsSchema = z.object({
30
69
  codexPath: z.string().optional(),
31
70
  cwd: z.string().optional(),
@@ -38,7 +77,29 @@ var settingsSchema = z.object({
38
77
  allowNpx: z.boolean().optional(),
39
78
  env: z.record(z.string(), z.string()).optional(),
40
79
  verbose: z.boolean().optional(),
41
- logger: z.any().optional()
80
+ logger: z.union([z.literal(false), loggerFunctionSchema]).optional(),
81
+ // NEW: Reasoning & Verbosity
82
+ reasoningEffort: z.enum(["minimal", "low", "medium", "high"]).optional(),
83
+ // Note: API rejects 'concise' and 'none' despite error messages claiming they're valid
84
+ reasoningSummary: z.enum(["auto", "detailed"]).optional(),
85
+ reasoningSummaryFormat: z.enum(["none", "experimental"]).optional(),
86
+ modelVerbosity: z.enum(["low", "medium", "high"]).optional(),
87
+ // NEW: Advanced features
88
+ includePlanTool: z.boolean().optional(),
89
+ profile: z.string().optional(),
90
+ oss: z.boolean().optional(),
91
+ webSearch: z.boolean().optional(),
92
+ // NEW: Generic overrides
93
+ configOverrides: z.record(
94
+ z.string(),
95
+ z.union([
96
+ z.string(),
97
+ z.number(),
98
+ z.boolean(),
99
+ z.object({}).passthrough(),
100
+ z.array(z.any())
101
+ ])
102
+ ).optional()
42
103
  }).strict();
43
104
  function validateSettings(settings) {
44
105
  const warnings = [];
@@ -166,6 +227,22 @@ function isAuthenticationError(err) {
166
227
  }
167
228
 
168
229
  // src/codex-cli-language-model.ts
230
+ var codexCliProviderOptionsSchema = z.object({
231
+ reasoningEffort: z.enum(["minimal", "low", "medium", "high"]).optional(),
232
+ reasoningSummary: z.enum(["auto", "detailed"]).optional(),
233
+ reasoningSummaryFormat: z.enum(["none", "experimental"]).optional(),
234
+ textVerbosity: z.enum(["low", "medium", "high"]).optional(),
235
+ configOverrides: z.record(
236
+ z.string(),
237
+ z.union([
238
+ z.string(),
239
+ z.number(),
240
+ z.boolean(),
241
+ z.object({}).passthrough(),
242
+ z.array(z.any())
243
+ ])
244
+ ).optional()
245
+ }).strict();
169
246
  function resolveCodexPath(explicitPath, allowNpx) {
170
247
  if (explicitPath) return { cmd: "node", args: [explicitPath] };
171
248
  try {
@@ -192,13 +269,29 @@ var CodexCliLanguageModel = class {
192
269
  constructor(options) {
193
270
  this.modelId = options.id;
194
271
  this.settings = options.settings ?? {};
195
- this.logger = getLogger(this.settings.logger);
272
+ const baseLogger = getLogger(this.settings.logger);
273
+ this.logger = createVerboseLogger(baseLogger, this.settings.verbose ?? false);
196
274
  if (!this.modelId || this.modelId.trim() === "") {
197
275
  throw new NoSuchModelError({ modelId: this.modelId, modelType: "languageModel" });
198
276
  }
199
277
  const warn = validateModelId(this.modelId);
200
278
  if (warn) this.logger.warn(`Codex CLI model: ${warn}`);
201
279
  }
280
+ mergeSettings(providerOptions) {
281
+ if (!providerOptions) return this.settings;
282
+ const mergedConfigOverrides = providerOptions.configOverrides || this.settings.configOverrides ? {
283
+ ...this.settings.configOverrides ?? {},
284
+ ...providerOptions.configOverrides ?? {}
285
+ } : void 0;
286
+ return {
287
+ ...this.settings,
288
+ reasoningEffort: providerOptions.reasoningEffort ?? this.settings.reasoningEffort,
289
+ reasoningSummary: providerOptions.reasoningSummary ?? this.settings.reasoningSummary,
290
+ reasoningSummaryFormat: providerOptions.reasoningSummaryFormat ?? this.settings.reasoningSummaryFormat,
291
+ modelVerbosity: providerOptions.textVerbosity ?? this.settings.modelVerbosity,
292
+ configOverrides: mergedConfigOverrides
293
+ };
294
+ }
202
295
  // Codex JSONL items use `type` for the item discriminator, but some
203
296
  // earlier fixtures (and defensive parsing) might still surface `item_type`.
204
297
  // This helper returns whichever is present.
@@ -209,28 +302,57 @@ var CodexCliLanguageModel = class {
209
302
  const current = typeof data.type === "string" ? data.type : void 0;
210
303
  return legacy ?? current;
211
304
  }
212
- buildArgs(promptText, responseFormat) {
213
- const base = resolveCodexPath(this.settings.codexPath, this.settings.allowNpx);
305
+ buildArgs(promptText, responseFormat, settings = this.settings) {
306
+ const base = resolveCodexPath(settings.codexPath, settings.allowNpx);
214
307
  const args = [...base.args, "exec", "--experimental-json"];
215
- if (this.settings.fullAuto) {
308
+ if (settings.fullAuto) {
216
309
  args.push("--full-auto");
217
- } else if (this.settings.dangerouslyBypassApprovalsAndSandbox) {
310
+ } else if (settings.dangerouslyBypassApprovalsAndSandbox) {
218
311
  args.push("--dangerously-bypass-approvals-and-sandbox");
219
312
  } else {
220
- const approval = this.settings.approvalMode ?? "on-failure";
313
+ const approval = settings.approvalMode ?? "on-failure";
221
314
  args.push("-c", `approval_policy=${approval}`);
222
- const sandbox = this.settings.sandboxMode ?? "workspace-write";
315
+ const sandbox = settings.sandboxMode ?? "workspace-write";
223
316
  args.push("-c", `sandbox_mode=${sandbox}`);
224
317
  }
225
- if (this.settings.skipGitRepoCheck !== false) {
318
+ if (settings.skipGitRepoCheck !== false) {
226
319
  args.push("--skip-git-repo-check");
227
320
  }
228
- if (this.settings.color) {
229
- args.push("--color", this.settings.color);
321
+ if (settings.reasoningEffort) {
322
+ args.push("-c", `model_reasoning_effort=${settings.reasoningEffort}`);
323
+ }
324
+ if (settings.reasoningSummary) {
325
+ args.push("-c", `model_reasoning_summary=${settings.reasoningSummary}`);
326
+ }
327
+ if (settings.reasoningSummaryFormat) {
328
+ args.push("-c", `model_reasoning_summary_format=${settings.reasoningSummaryFormat}`);
329
+ }
330
+ if (settings.modelVerbosity) {
331
+ args.push("-c", `model_verbosity=${settings.modelVerbosity}`);
332
+ }
333
+ if (settings.includePlanTool) {
334
+ args.push("--include-plan-tool");
335
+ }
336
+ if (settings.profile) {
337
+ args.push("--profile", settings.profile);
338
+ }
339
+ if (settings.oss) {
340
+ args.push("--oss");
341
+ }
342
+ if (settings.webSearch) {
343
+ args.push("-c", "tools.web_search=true");
344
+ }
345
+ if (settings.color) {
346
+ args.push("--color", settings.color);
230
347
  }
231
348
  if (this.modelId) {
232
349
  args.push("-m", this.modelId);
233
350
  }
351
+ if (settings.configOverrides) {
352
+ for (const [key, value] of Object.entries(settings.configOverrides)) {
353
+ this.addConfigOverride(args, key, value);
354
+ }
355
+ }
234
356
  let schemaPath;
235
357
  if (responseFormat?.type === "json" && responseFormat.schema) {
236
358
  const schema = typeof responseFormat.schema === "object" ? responseFormat.schema : {};
@@ -250,16 +372,55 @@ var CodexCliLanguageModel = class {
250
372
  args.push(promptText);
251
373
  const env = {
252
374
  ...process.env,
253
- ...this.settings.env || {},
375
+ ...settings.env || {},
254
376
  RUST_LOG: process.env.RUST_LOG || "error"
255
377
  };
256
- let lastMessagePath = this.settings.outputLastMessageFile;
378
+ let lastMessagePath = settings.outputLastMessageFile;
257
379
  if (!lastMessagePath) {
258
380
  const dir = mkdtempSync(join(tmpdir(), "codex-cli-"));
259
381
  lastMessagePath = join(dir, "last-message.txt");
260
382
  }
261
383
  args.push("--output-last-message", lastMessagePath);
262
- return { cmd: base.cmd, args, env, cwd: this.settings.cwd, lastMessagePath, schemaPath };
384
+ return { cmd: base.cmd, args, env, cwd: settings.cwd, lastMessagePath, schemaPath };
385
+ }
386
+ addConfigOverride(args, key, value) {
387
+ if (this.isPlainObject(value)) {
388
+ for (const [childKey, childValue] of Object.entries(value)) {
389
+ this.addConfigOverride(
390
+ args,
391
+ `${key}.${childKey}`,
392
+ childValue
393
+ );
394
+ }
395
+ return;
396
+ }
397
+ const serialized = this.serializeConfigValue(value);
398
+ args.push("-c", `${key}=${serialized}`);
399
+ }
400
+ /**
401
+ * Serialize a config override value into a CLI-safe string.
402
+ */
403
+ serializeConfigValue(value) {
404
+ if (typeof value === "string") return value;
405
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
406
+ if (Array.isArray(value)) {
407
+ try {
408
+ return JSON.stringify(value);
409
+ } catch {
410
+ return String(value);
411
+ }
412
+ }
413
+ if (value && typeof value === "object") {
414
+ try {
415
+ return JSON.stringify(value);
416
+ } catch {
417
+ return String(value);
418
+ }
419
+ }
420
+ return String(value);
421
+ }
422
+ isPlainObject(value) {
423
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
263
424
  }
264
425
  sanitizeJsonSchema(value) {
265
426
  if (typeof value !== "object" || value === null) {
@@ -501,20 +662,35 @@ var CodexCliLanguageModel = class {
501
662
  });
502
663
  }
503
664
  async doGenerate(options) {
665
+ this.logger.debug(`[codex-cli] Starting doGenerate request with model: ${this.modelId}`);
504
666
  const { promptText, warnings: mappingWarnings } = mapMessagesToPrompt(options.prompt);
505
667
  const promptExcerpt = promptText.slice(0, 200);
506
668
  const warnings = [
507
669
  ...this.mapWarnings(options),
508
670
  ...mappingWarnings?.map((m) => ({ type: "other", message: m })) || []
509
671
  ];
672
+ this.logger.debug(
673
+ `[codex-cli] Converted ${options.prompt.length} messages, response format: ${options.responseFormat?.type ?? "none"}`
674
+ );
675
+ const providerOptions = await parseProviderOptions({
676
+ provider: this.provider,
677
+ providerOptions: options.providerOptions,
678
+ schema: codexCliProviderOptionsSchema
679
+ });
680
+ const effectiveSettings = this.mergeSettings(providerOptions);
510
681
  const responseFormat = options.responseFormat?.type === "json" ? { type: "json", schema: options.responseFormat.schema } : void 0;
511
682
  const { cmd, args, env, cwd, lastMessagePath, schemaPath } = this.buildArgs(
512
683
  promptText,
513
- responseFormat
684
+ responseFormat,
685
+ effectiveSettings
686
+ );
687
+ this.logger.debug(
688
+ `[codex-cli] Executing Codex CLI: ${cmd} with ${args.length} arguments, cwd: ${cwd ?? "default"}`
514
689
  );
515
690
  let text = "";
516
691
  const usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
517
692
  const finishReason = "stop";
693
+ const startTime = Date.now();
518
694
  const child = spawn(cmd, args, { env, cwd, stdio: ["ignore", "pipe", "pipe"] });
519
695
  let onAbort;
520
696
  if (options.abortSignal) {
@@ -536,11 +712,14 @@ var CodexCliLanguageModel = class {
536
712
  for (const line of lines) {
537
713
  const event = this.parseExperimentalJsonEvent(line);
538
714
  if (!event) continue;
715
+ this.logger.debug(`[codex-cli] Received event type: ${event.type ?? "unknown"}`);
539
716
  if (event.type === "thread.started" && typeof event.thread_id === "string") {
540
717
  this.sessionId = event.thread_id;
718
+ this.logger.debug(`[codex-cli] Session started: ${this.sessionId}`);
541
719
  }
542
720
  if (event.type === "session.created" && typeof event.session_id === "string") {
543
721
  this.sessionId = event.session_id;
722
+ this.logger.debug(`[codex-cli] Session created: ${this.sessionId}`);
544
723
  }
545
724
  if (event.type === "turn.completed") {
546
725
  const usageEvent = this.extractUsage(event);
@@ -556,15 +735,21 @@ var CodexCliLanguageModel = class {
556
735
  if (event.type === "turn.failed") {
557
736
  const errorText = event.error && typeof event.error.message === "string" && event.error.message || (typeof event.message === "string" ? event.message : void 0);
558
737
  turnFailureMessage = errorText ?? turnFailureMessage ?? "Codex turn failed";
738
+ this.logger.error(`[codex-cli] Turn failed: ${turnFailureMessage}`);
559
739
  }
560
740
  if (event.type === "error") {
561
741
  const errorText = typeof event.message === "string" ? event.message : void 0;
562
742
  turnFailureMessage = errorText ?? turnFailureMessage ?? "Codex error";
743
+ this.logger.error(`[codex-cli] Error event: ${turnFailureMessage}`);
563
744
  }
564
745
  }
565
746
  });
566
- child.on("error", (e) => reject(this.handleSpawnError(e, promptExcerpt)));
747
+ child.on("error", (e) => {
748
+ this.logger.error(`[codex-cli] Spawn error: ${String(e)}`);
749
+ reject(this.handleSpawnError(e, promptExcerpt));
750
+ });
567
751
  child.on("close", (code) => {
752
+ const duration = Date.now() - startTime;
568
753
  if (code === 0) {
569
754
  if (turnFailureMessage) {
570
755
  reject(
@@ -576,8 +761,15 @@ var CodexCliLanguageModel = class {
576
761
  );
577
762
  return;
578
763
  }
764
+ this.logger.info(
765
+ `[codex-cli] Request completed - Session: ${this.sessionId ?? "N/A"}, Duration: ${duration}ms, Tokens: ${usage.totalTokens}`
766
+ );
767
+ this.logger.debug(
768
+ `[codex-cli] Token usage - Input: ${usage.inputTokens}, Output: ${usage.outputTokens}, Total: ${usage.totalTokens}`
769
+ );
579
770
  resolve();
580
771
  } else {
772
+ this.logger.error(`[codex-cli] Process exited with code ${code} after ${duration}ms`);
581
773
  reject(
582
774
  createAPICallError({
583
775
  message: `Codex CLI exited with code ${code}`,
@@ -626,19 +818,34 @@ var CodexCliLanguageModel = class {
626
818
  };
627
819
  }
628
820
  async doStream(options) {
821
+ this.logger.debug(`[codex-cli] Starting doStream request with model: ${this.modelId}`);
629
822
  const { promptText, warnings: mappingWarnings } = mapMessagesToPrompt(options.prompt);
630
823
  const promptExcerpt = promptText.slice(0, 200);
631
824
  const warnings = [
632
825
  ...this.mapWarnings(options),
633
826
  ...mappingWarnings?.map((m) => ({ type: "other", message: m })) || []
634
827
  ];
828
+ this.logger.debug(
829
+ `[codex-cli] Converted ${options.prompt.length} messages for streaming, response format: ${options.responseFormat?.type ?? "none"}`
830
+ );
831
+ const providerOptions = await parseProviderOptions({
832
+ provider: this.provider,
833
+ providerOptions: options.providerOptions,
834
+ schema: codexCliProviderOptionsSchema
835
+ });
836
+ const effectiveSettings = this.mergeSettings(providerOptions);
635
837
  const responseFormat = options.responseFormat?.type === "json" ? { type: "json", schema: options.responseFormat.schema } : void 0;
636
838
  const { cmd, args, env, cwd, lastMessagePath, schemaPath } = this.buildArgs(
637
839
  promptText,
638
- responseFormat
840
+ responseFormat,
841
+ effectiveSettings
842
+ );
843
+ this.logger.debug(
844
+ `[codex-cli] Executing Codex CLI for streaming: ${cmd} with ${args.length} arguments`
639
845
  );
640
846
  const stream = new ReadableStream({
641
847
  start: (controller) => {
848
+ const startTime = Date.now();
642
849
  const child = spawn(cmd, args, { env, cwd, stdio: ["ignore", "pipe", "pipe"] });
643
850
  controller.enqueue({ type: "stream-start", warnings });
644
851
  let stderr = "";
@@ -661,12 +868,18 @@ var CodexCliLanguageModel = class {
661
868
  if (!item) return;
662
869
  if (event.type === "item.completed" && this.getItemType(item) === "assistant_message" && typeof item.text === "string") {
663
870
  accumulatedText = item.text;
871
+ this.logger.debug(
872
+ `[codex-cli] Received assistant message, length: ${item.text.length}`
873
+ );
664
874
  return;
665
875
  }
666
876
  const toolName = this.getToolName(item);
667
877
  if (!toolName) {
668
878
  return;
669
879
  }
880
+ this.logger.debug(
881
+ `[codex-cli] Tool detected: ${toolName}, item type: ${this.getItemType(item)}`
882
+ );
670
883
  const mapKey = typeof item.id === "string" && item.id.length > 0 ? item.id : randomUUID();
671
884
  let toolState = activeTools.get(mapKey);
672
885
  const latestInput = this.buildToolInputPayload(item);
@@ -685,6 +898,7 @@ var CodexCliLanguageModel = class {
685
898
  }
686
899
  }
687
900
  if (!toolState.hasEmittedCall) {
901
+ this.logger.debug(`[codex-cli] Emitting tool invocation: ${toolState.toolName}`);
688
902
  this.emitToolInvocation(
689
903
  controller,
690
904
  toolState.toolCallId,
@@ -695,6 +909,7 @@ var CodexCliLanguageModel = class {
695
909
  }
696
910
  if (event.type === "item.completed") {
697
911
  const { result, metadata } = this.buildToolResultPayload(item);
912
+ this.logger.debug(`[codex-cli] Tool completed: ${toolState.toolName}`);
698
913
  this.emitToolResult(
699
914
  controller,
700
915
  toolState.toolCallId,
@@ -718,7 +933,11 @@ var CodexCliLanguageModel = class {
718
933
  options.abortSignal.addEventListener("abort", onAbort, { once: true });
719
934
  }
720
935
  const finishStream = (code) => {
936
+ const duration = Date.now() - startTime;
721
937
  if (code !== 0) {
938
+ this.logger.error(
939
+ `[codex-cli] Stream process exited with code ${code} after ${duration}ms`
940
+ );
722
941
  controller.error(
723
942
  createAPICallError({
724
943
  message: `Codex CLI exited with code ${code}`,
@@ -730,6 +949,7 @@ var CodexCliLanguageModel = class {
730
949
  return;
731
950
  }
732
951
  if (turnFailureMessage) {
952
+ this.logger.error(`[codex-cli] Stream failed: ${turnFailureMessage}`);
733
953
  controller.error(
734
954
  createAPICallError({
735
955
  message: turnFailureMessage,
@@ -758,6 +978,12 @@ var CodexCliLanguageModel = class {
758
978
  controller.enqueue({ type: "text-end", id: textId });
759
979
  }
760
980
  const usageSummary = lastUsage ?? { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
981
+ this.logger.info(
982
+ `[codex-cli] Stream completed - Session: ${this.sessionId ?? "N/A"}, Duration: ${duration}ms, Tokens: ${usageSummary.totalTokens}`
983
+ );
984
+ this.logger.debug(
985
+ `[codex-cli] Token usage - Input: ${usageSummary.inputTokens}, Output: ${usageSummary.outputTokens}, Total: ${usageSummary.totalTokens}`
986
+ );
761
987
  controller.enqueue({
762
988
  type: "finish",
763
989
  finishReason: "stop",
@@ -772,8 +998,10 @@ var CodexCliLanguageModel = class {
772
998
  for (const line of lines) {
773
999
  const event = this.parseExperimentalJsonEvent(line);
774
1000
  if (!event) continue;
1001
+ this.logger.debug(`[codex-cli] Stream event: ${event.type ?? "unknown"}`);
775
1002
  if (event.type === "thread.started" && typeof event.thread_id === "string") {
776
1003
  this.sessionId = event.thread_id;
1004
+ this.logger.debug(`[codex-cli] Stream session started: ${this.sessionId}`);
777
1005
  if (!responseMetadataSent) {
778
1006
  responseMetadataSent = true;
779
1007
  sendMetadata();
@@ -782,6 +1010,7 @@ var CodexCliLanguageModel = class {
782
1010
  }
783
1011
  if (event.type === "session.created" && typeof event.session_id === "string") {
784
1012
  this.sessionId = event.session_id;
1013
+ this.logger.debug(`[codex-cli] Stream session created: ${this.sessionId}`);
785
1014
  if (!responseMetadataSent) {
786
1015
  responseMetadataSent = true;
787
1016
  sendMetadata();
@@ -798,6 +1027,7 @@ var CodexCliLanguageModel = class {
798
1027
  if (event.type === "turn.failed") {
799
1028
  const errorText = event.error && typeof event.error.message === "string" && event.error.message || (typeof event.message === "string" ? event.message : void 0);
800
1029
  turnFailureMessage = errorText ?? turnFailureMessage ?? "Codex turn failed";
1030
+ this.logger.error(`[codex-cli] Stream turn failed: ${turnFailureMessage}`);
801
1031
  sendMetadata({ error: turnFailureMessage });
802
1032
  continue;
803
1033
  }
@@ -805,6 +1035,7 @@ var CodexCliLanguageModel = class {
805
1035
  const errorText = typeof event.message === "string" ? event.message : void 0;
806
1036
  const effective = errorText ?? "Codex error";
807
1037
  turnFailureMessage = turnFailureMessage ?? effective;
1038
+ this.logger.error(`[codex-cli] Stream error event: ${effective}`);
808
1039
  sendMetadata({ error: effective });
809
1040
  continue;
810
1041
  }
@@ -822,6 +1053,7 @@ var CodexCliLanguageModel = class {
822
1053
  }
823
1054
  };
824
1055
  child.on("error", (e) => {
1056
+ this.logger.error(`[codex-cli] Stream spawn error: ${String(e)}`);
825
1057
  if (options.abortSignal) options.abortSignal.removeEventListener("abort", onAbort);
826
1058
  cleanupSchema();
827
1059
  controller.error(this.handleSpawnError(e, promptExcerpt));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-sdk-provider-codex-cli",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "AI SDK v5 provider for OpenAI Codex CLI with native JSON Schema support",
5
5
  "keywords": [
6
6
  "ai-sdk",