codex-python 0.2.13__tar.gz → 0.2.15__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-python
3
- Version: 0.2.13
3
+ Version: 0.2.15
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3 :: Only
6
6
  Classifier: Programming Language :: Python :: 3.13
@@ -31,4 +31,4 @@ __all__ = [
31
31
  ]
32
32
 
33
33
  # Package version. Kept in sync with Cargo.toml via CI before builds.
34
- __version__ = "0.2.13"
34
+ __version__ = "0.2.15"
@@ -4,7 +4,7 @@ from collections.abc import Iterable, Iterator, Mapping, Sequence
4
4
  from dataclasses import dataclass
5
5
 
6
6
  from .config import CodexConfig
7
- from .event import Event
7
+ from .event import AnyEventMsg, Event
8
8
  from .native import run_exec_collect as native_run_exec_collect
9
9
  from .native import start_exec_stream as native_start_exec_stream
10
10
 
@@ -32,7 +32,15 @@ class Conversation:
32
32
  def __iter__(self) -> Iterator[Event]:
33
33
  """Yield `Event` objects from the native stream."""
34
34
  for item in self._stream:
35
- yield Event.model_validate(item)
35
+ try:
36
+ yield Event.model_validate(item)
37
+ except Exception:
38
+ ev_id = item.get("id") if isinstance(item, dict) else None
39
+ msg_obj = item.get("msg") if isinstance(item, dict) else None
40
+ if isinstance(msg_obj, dict) and isinstance(msg_obj.get("type"), str):
41
+ yield Event(id=ev_id or "unknown", msg=AnyEventMsg(**msg_obj))
42
+ else:
43
+ yield Event(id=ev_id or "unknown", msg=AnyEventMsg(type="unknown"))
36
44
 
37
45
 
38
46
  @dataclass(slots=True)
@@ -88,6 +96,18 @@ def run_exec(
88
96
  config_overrides=config.to_dict() if config else None,
89
97
  load_default_config=load_default_config,
90
98
  )
91
- return [Event.model_validate(e) for e in events]
92
99
  except RuntimeError as e:
93
100
  raise CodexNativeError() from e
101
+
102
+ out: list[Event] = []
103
+ for item in events:
104
+ try:
105
+ out.append(Event.model_validate(item))
106
+ except Exception:
107
+ ev_id = item.get("id") if isinstance(item, dict) else None
108
+ msg_obj = item.get("msg") if isinstance(item, dict) else None
109
+ if isinstance(msg_obj, dict) and isinstance(msg_obj.get("type"), str):
110
+ out.append(Event(id=ev_id or "unknown", msg=AnyEventMsg(**msg_obj)))
111
+ else:
112
+ out.append(Event(id=ev_id or "unknown", msg=AnyEventMsg(type="unknown")))
113
+ return out
@@ -0,0 +1,29 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import BaseModel
4
+ from pydantic.config import ConfigDict
5
+
6
+ from .protocol.types import EventMsg
7
+
8
+
9
+ class AnyEventMsg(BaseModel):
10
+ """Fallback event payload that preserves the original `type` and fields.
11
+
12
+ Accepts any additional keys to retain upstream payloads when strict
13
+ validation fails for generated models.
14
+ """
15
+
16
+ type: str
17
+
18
+ # Allow arbitrary extra fields so we don't lose information
19
+ model_config = ConfigDict(extra="allow")
20
+
21
+
22
+ class Event(BaseModel):
23
+ """Protocol event envelope with typed `msg` (union of EventMsg_*)."""
24
+
25
+ id: str
26
+ msg: EventMsg | AnyEventMsg
27
+
28
+ # Allow forward compatibility with additional envelope fields
29
+ model_config = ConfigDict(extra="allow")
@@ -7,7 +7,7 @@ from __future__ import annotations
7
7
  from enum import Enum
8
8
  from typing import Any, Literal
9
9
 
10
- from pydantic import Field, RootModel
10
+ from pydantic import ConfigDict, Field, RootModel
11
11
 
12
12
  from codex.protocol._base_model import BaseModelWithExtras
13
13
 
@@ -140,10 +140,18 @@ class ExecCommandApprovalParams(BaseModelWithExtras):
140
140
  reason: str | None = None
141
141
 
142
142
 
143
+ class Duration(BaseModelWithExtras):
144
+ model_config = ConfigDict(
145
+ extra="forbid",
146
+ )
147
+ secs: int
148
+ nanos: int
149
+
150
+
143
151
  class ExecCommandEndEvent(BaseModelWithExtras):
144
152
  aggregated_output: str = Field(..., description="Captured aggregated output")
145
153
  call_id: str = Field(..., description="Identifier for the ExecCommandBegin that finished.")
146
- duration: str = Field(..., description="The duration of the command execution.")
154
+ duration: str | Duration
147
155
  exit_code: int = Field(..., description="The command's exit code.")
148
156
  formatted_output: str = Field(
149
157
  ..., description="Formatted output from the command, as seen by the model."
@@ -765,7 +773,7 @@ class EventMsgExecCommandOutputDelta(BaseModelWithExtras):
765
773
  class EventMsgExecCommandEnd(BaseModelWithExtras):
766
774
  aggregated_output: str = Field(..., description="Captured aggregated output")
767
775
  call_id: str = Field(..., description="Identifier for the ExecCommandBegin that finished.")
768
- duration: str = Field(..., description="The duration of the command execution.")
776
+ duration: str | Duration
769
777
  exit_code: int = Field(..., description="The command's exit code.")
770
778
  formatted_output: str = Field(
771
779
  ..., description="Formatted output from the command, as seen by the model."
@@ -1438,7 +1446,7 @@ class McpToolCallEndEvent(BaseModelWithExtras):
1438
1446
  ...,
1439
1447
  description="Identifier for the corresponding McpToolCallBegin that finished.",
1440
1448
  )
1441
- duration: str
1449
+ duration: str | Duration
1442
1450
  invocation: McpInvocation
1443
1451
  result: Result | Result1 = Field(
1444
1452
  ..., description="Result of the tool call. Note this could be an error."
@@ -1450,7 +1458,7 @@ class EventMsgMcpToolCallEnd(BaseModelWithExtras):
1450
1458
  ...,
1451
1459
  description="Identifier for the corresponding McpToolCallBegin that finished.",
1452
1460
  )
1453
- duration: str
1461
+ duration: str | Duration
1454
1462
  invocation: McpInvocation
1455
1463
  result: Result | Result1 = Field(
1456
1464
  ..., description="Result of the tool call. Note this could be an error."
@@ -91,6 +91,50 @@ version = "1.0.99"
91
91
  source = "registry+https://github.com/rust-lang/crates.io-index"
92
92
  checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
93
93
 
94
+ [[package]]
95
+ name = "askama"
96
+ version = "0.12.1"
97
+ source = "registry+https://github.com/rust-lang/crates.io-index"
98
+ checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
99
+ dependencies = [
100
+ "askama_derive",
101
+ "askama_escape",
102
+ "humansize",
103
+ "num-traits",
104
+ "percent-encoding",
105
+ ]
106
+
107
+ [[package]]
108
+ name = "askama_derive"
109
+ version = "0.12.5"
110
+ source = "registry+https://github.com/rust-lang/crates.io-index"
111
+ checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
112
+ dependencies = [
113
+ "askama_parser",
114
+ "basic-toml",
115
+ "mime",
116
+ "mime_guess",
117
+ "proc-macro2",
118
+ "quote",
119
+ "serde",
120
+ "syn",
121
+ ]
122
+
123
+ [[package]]
124
+ name = "askama_escape"
125
+ version = "0.10.3"
126
+ source = "registry+https://github.com/rust-lang/crates.io-index"
127
+ checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
128
+
129
+ [[package]]
130
+ name = "askama_parser"
131
+ version = "0.2.1"
132
+ source = "registry+https://github.com/rust-lang/crates.io-index"
133
+ checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0"
134
+ dependencies = [
135
+ "nom",
136
+ ]
137
+
94
138
  [[package]]
95
139
  name = "async-channel"
96
140
  version = "2.5.0"
@@ -136,6 +180,15 @@ version = "0.22.1"
136
180
  source = "registry+https://github.com/rust-lang/crates.io-index"
137
181
  checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
138
182
 
183
+ [[package]]
184
+ name = "basic-toml"
185
+ version = "0.1.10"
186
+ source = "registry+https://github.com/rust-lang/crates.io-index"
187
+ checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
188
+ dependencies = [
189
+ "serde",
190
+ ]
191
+
139
192
  [[package]]
140
193
  name = "bitflags"
141
194
  version = "1.3.2"
@@ -157,6 +210,16 @@ dependencies = [
157
210
  "generic-array",
158
211
  ]
159
212
 
213
+ [[package]]
214
+ name = "bstr"
215
+ version = "1.12.0"
216
+ source = "registry+https://github.com/rust-lang/crates.io-index"
217
+ checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
218
+ dependencies = [
219
+ "memchr",
220
+ "serde",
221
+ ]
222
+
160
223
  [[package]]
161
224
  name = "bumpalo"
162
225
  version = "3.19.0"
@@ -248,7 +311,7 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
248
311
  [[package]]
249
312
  name = "codex-apply-patch"
250
313
  version = "0.0.0"
251
- source = "git+https://github.com/openai/codex?rev=c13c3dad#c13c3dadbf68d5369f24a20594cedd6b3973516b"
314
+ source = "git+https://github.com/openai/codex?branch=main#fdf4a686463f13b56ee83f807bccbe3457542564"
252
315
  dependencies = [
253
316
  "anyhow",
254
317
  "once_cell",
@@ -261,14 +324,16 @@ dependencies = [
261
324
  [[package]]
262
325
  name = "codex-core"
263
326
  version = "0.0.0"
264
- source = "git+https://github.com/openai/codex?rev=c13c3dad#c13c3dadbf68d5369f24a20594cedd6b3973516b"
327
+ source = "git+https://github.com/openai/codex?branch=main#fdf4a686463f13b56ee83f807bccbe3457542564"
265
328
  dependencies = [
266
329
  "anyhow",
330
+ "askama",
267
331
  "async-channel",
268
332
  "base64",
269
333
  "bytes",
270
334
  "chrono",
271
335
  "codex-apply-patch",
336
+ "codex-file-search",
272
337
  "codex-mcp-client",
273
338
  "codex-protocol",
274
339
  "dirs",
@@ -306,10 +371,24 @@ dependencies = [
306
371
  "wildmatch",
307
372
  ]
308
373
 
374
+ [[package]]
375
+ name = "codex-file-search"
376
+ version = "0.0.0"
377
+ source = "git+https://github.com/openai/codex?branch=main#fdf4a686463f13b56ee83f807bccbe3457542564"
378
+ dependencies = [
379
+ "anyhow",
380
+ "clap",
381
+ "ignore",
382
+ "nucleo-matcher",
383
+ "serde",
384
+ "serde_json",
385
+ "tokio",
386
+ ]
387
+
309
388
  [[package]]
310
389
  name = "codex-mcp-client"
311
390
  version = "0.0.0"
312
- source = "git+https://github.com/openai/codex?rev=c13c3dad#c13c3dadbf68d5369f24a20594cedd6b3973516b"
391
+ source = "git+https://github.com/openai/codex?branch=main#fdf4a686463f13b56ee83f807bccbe3457542564"
313
392
  dependencies = [
314
393
  "anyhow",
315
394
  "mcp-types",
@@ -323,7 +402,7 @@ dependencies = [
323
402
  [[package]]
324
403
  name = "codex-protocol"
325
404
  version = "0.0.0"
326
- source = "git+https://github.com/openai/codex?rev=c13c3dad#c13c3dadbf68d5369f24a20594cedd6b3973516b"
405
+ source = "git+https://github.com/openai/codex?branch=main#fdf4a686463f13b56ee83f807bccbe3457542564"
327
406
  dependencies = [
328
407
  "base64",
329
408
  "icu_decimal",
@@ -343,12 +422,13 @@ dependencies = [
343
422
 
344
423
  [[package]]
345
424
  name = "codex_native"
346
- version = "0.2.13"
425
+ version = "0.2.15"
347
426
  dependencies = [
348
427
  "anyhow",
349
428
  "clap",
350
429
  "codex-core",
351
430
  "codex-protocol",
431
+ "dotenvy",
352
432
  "openssl-sys",
353
433
  "pathdiff",
354
434
  "pyo3",
@@ -400,6 +480,25 @@ dependencies = [
400
480
  "libc",
401
481
  ]
402
482
 
483
+ [[package]]
484
+ name = "crossbeam-deque"
485
+ version = "0.8.6"
486
+ source = "registry+https://github.com/rust-lang/crates.io-index"
487
+ checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
488
+ dependencies = [
489
+ "crossbeam-epoch",
490
+ "crossbeam-utils",
491
+ ]
492
+
493
+ [[package]]
494
+ name = "crossbeam-epoch"
495
+ version = "0.9.18"
496
+ source = "registry+https://github.com/rust-lang/crates.io-index"
497
+ checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
498
+ dependencies = [
499
+ "crossbeam-utils",
500
+ ]
501
+
403
502
  [[package]]
404
503
  name = "crossbeam-utils"
405
504
  version = "0.8.21"
@@ -503,6 +602,12 @@ dependencies = [
503
602
  "syn",
504
603
  ]
505
604
 
605
+ [[package]]
606
+ name = "dotenvy"
607
+ version = "0.15.7"
608
+ source = "registry+https://github.com/rust-lang/crates.io-index"
609
+ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
610
+
506
611
  [[package]]
507
612
  name = "downcast-rs"
508
613
  version = "1.2.1"
@@ -796,6 +901,19 @@ version = "0.31.1"
796
901
  source = "registry+https://github.com/rust-lang/crates.io-index"
797
902
  checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
798
903
 
904
+ [[package]]
905
+ name = "globset"
906
+ version = "0.4.16"
907
+ source = "registry+https://github.com/rust-lang/crates.io-index"
908
+ checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5"
909
+ dependencies = [
910
+ "aho-corasick",
911
+ "bstr",
912
+ "log",
913
+ "regex-automata",
914
+ "regex-syntax",
915
+ ]
916
+
799
917
  [[package]]
800
918
  name = "h2"
801
919
  version = "0.4.12"
@@ -888,6 +1006,15 @@ version = "1.10.1"
888
1006
  source = "registry+https://github.com/rust-lang/crates.io-index"
889
1007
  checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
890
1008
 
1009
+ [[package]]
1010
+ name = "humansize"
1011
+ version = "2.1.3"
1012
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1013
+ checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
1014
+ dependencies = [
1015
+ "libm",
1016
+ ]
1017
+
891
1018
  [[package]]
892
1019
  name = "hyper"
893
1020
  version = "1.7.0"
@@ -1150,6 +1277,22 @@ dependencies = [
1150
1277
  "icu_properties",
1151
1278
  ]
1152
1279
 
1280
+ [[package]]
1281
+ name = "ignore"
1282
+ version = "0.4.23"
1283
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1284
+ checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
1285
+ dependencies = [
1286
+ "crossbeam-deque",
1287
+ "globset",
1288
+ "log",
1289
+ "memchr",
1290
+ "regex-automata",
1291
+ "same-file",
1292
+ "walkdir",
1293
+ "winapi-util",
1294
+ ]
1295
+
1153
1296
  [[package]]
1154
1297
  name = "indexmap"
1155
1298
  version = "1.9.3"
@@ -1250,6 +1393,12 @@ version = "0.2.175"
1250
1393
  source = "registry+https://github.com/rust-lang/crates.io-index"
1251
1394
  checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
1252
1395
 
1396
+ [[package]]
1397
+ name = "libm"
1398
+ version = "0.2.15"
1399
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1400
+ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
1401
+
1253
1402
  [[package]]
1254
1403
  name = "libredox"
1255
1404
  version = "0.1.10"
@@ -1278,6 +1427,16 @@ version = "0.8.0"
1278
1427
  source = "registry+https://github.com/rust-lang/crates.io-index"
1279
1428
  checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
1280
1429
 
1430
+ [[package]]
1431
+ name = "lock_api"
1432
+ version = "0.4.13"
1433
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1434
+ checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
1435
+ dependencies = [
1436
+ "autocfg",
1437
+ "scopeguard",
1438
+ ]
1439
+
1281
1440
  [[package]]
1282
1441
  name = "log"
1283
1442
  version = "0.4.28"
@@ -1296,7 +1455,7 @@ dependencies = [
1296
1455
  [[package]]
1297
1456
  name = "mcp-types"
1298
1457
  version = "0.0.0"
1299
- source = "git+https://github.com/openai/codex?rev=c13c3dad#c13c3dadbf68d5369f24a20594cedd6b3973516b"
1458
+ source = "git+https://github.com/openai/codex?branch=main#fdf4a686463f13b56ee83f807bccbe3457542564"
1300
1459
  dependencies = [
1301
1460
  "serde",
1302
1461
  "serde_json",
@@ -1408,6 +1567,16 @@ dependencies = [
1408
1567
  "windows-sys 0.52.0",
1409
1568
  ]
1410
1569
 
1570
+ [[package]]
1571
+ name = "nucleo-matcher"
1572
+ version = "0.3.1"
1573
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1574
+ checksum = "bf33f538733d1a5a3494b836ba913207f14d9d4a1d3cd67030c5061bdd2cac85"
1575
+ dependencies = [
1576
+ "memchr",
1577
+ "unicode-segmentation",
1578
+ ]
1579
+
1411
1580
  [[package]]
1412
1581
  name = "num-conv"
1413
1582
  version = "0.1.0"
@@ -1531,6 +1700,29 @@ version = "2.2.1"
1531
1700
  source = "registry+https://github.com/rust-lang/crates.io-index"
1532
1701
  checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
1533
1702
 
1703
+ [[package]]
1704
+ name = "parking_lot"
1705
+ version = "0.12.4"
1706
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1707
+ checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
1708
+ dependencies = [
1709
+ "lock_api",
1710
+ "parking_lot_core",
1711
+ ]
1712
+
1713
+ [[package]]
1714
+ name = "parking_lot_core"
1715
+ version = "0.9.11"
1716
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1717
+ checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
1718
+ dependencies = [
1719
+ "cfg-if",
1720
+ "libc",
1721
+ "redox_syscall",
1722
+ "smallvec",
1723
+ "windows-targets 0.52.6",
1724
+ ]
1725
+
1534
1726
  [[package]]
1535
1727
  name = "pathdiff"
1536
1728
  version = "0.2.3"
@@ -1749,6 +1941,15 @@ dependencies = [
1749
1941
  "getrandom 0.3.3",
1750
1942
  ]
1751
1943
 
1944
+ [[package]]
1945
+ name = "redox_syscall"
1946
+ version = "0.5.17"
1947
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1948
+ checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
1949
+ dependencies = [
1950
+ "bitflags 2.9.4",
1951
+ ]
1952
+
1752
1953
  [[package]]
1753
1954
  name = "redox_users"
1754
1955
  version = "0.5.2"
@@ -1949,6 +2150,15 @@ version = "1.0.20"
1949
2150
  source = "registry+https://github.com/rust-lang/crates.io-index"
1950
2151
  checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
1951
2152
 
2153
+ [[package]]
2154
+ name = "same-file"
2155
+ version = "1.0.6"
2156
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2157
+ checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
2158
+ dependencies = [
2159
+ "winapi-util",
2160
+ ]
2161
+
1952
2162
  [[package]]
1953
2163
  name = "schannel"
1954
2164
  version = "0.1.28"
@@ -1982,6 +2192,12 @@ dependencies = [
1982
2192
  "serde_json",
1983
2193
  ]
1984
2194
 
2195
+ [[package]]
2196
+ name = "scopeguard"
2197
+ version = "1.2.0"
2198
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2199
+ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
2200
+
1985
2201
  [[package]]
1986
2202
  name = "seccompiler"
1987
2203
  version = "0.5.0"
@@ -2434,6 +2650,7 @@ dependencies = [
2434
2650
  "io-uring",
2435
2651
  "libc",
2436
2652
  "mio",
2653
+ "parking_lot",
2437
2654
  "pin-project-lite",
2438
2655
  "signal-hook-registry",
2439
2656
  "slab",
@@ -2723,6 +2940,12 @@ version = "1.0.19"
2723
2940
  source = "registry+https://github.com/rust-lang/crates.io-index"
2724
2941
  checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
2725
2942
 
2943
+ [[package]]
2944
+ name = "unicode-segmentation"
2945
+ version = "1.12.0"
2946
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2947
+ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
2948
+
2726
2949
  [[package]]
2727
2950
  name = "unindent"
2728
2951
  version = "0.2.4"
@@ -2789,6 +3012,16 @@ version = "0.9.5"
2789
3012
  source = "registry+https://github.com/rust-lang/crates.io-index"
2790
3013
  checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
2791
3014
 
3015
+ [[package]]
3016
+ name = "walkdir"
3017
+ version = "2.5.0"
3018
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3019
+ checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
3020
+ dependencies = [
3021
+ "same-file",
3022
+ "winapi-util",
3023
+ ]
3024
+
2792
3025
  [[package]]
2793
3026
  name = "want"
2794
3027
  version = "0.3.1"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "codex_native"
3
- version = "0.2.13"
3
+ version = "0.2.15"
4
4
  edition = "2021"
5
5
 
6
6
  [lib]
@@ -22,11 +22,12 @@ tracing = "0.1"
22
22
  clap = { version = "4", features = ["derive"] }
23
23
  which = "6"
24
24
  pathdiff = "0.2"
25
+ dotenvy = "0.15.7"
25
26
 
26
27
  # Upstream Codex crates from the monorepo (use git deps; pin to main for now)
27
28
  # Pin to a specific commit of the upstream Codex monorepo to avoid breaking API changes
28
- codex-core = { git = "https://github.com/openai/codex", package = "codex-core", rev = "c13c3dad" }
29
- codex-protocol = { git = "https://github.com/openai/codex", package = "codex-protocol", rev = "c13c3dad" }
29
+ codex-core = { git = "https://github.com/openai/codex", package = "codex-core", branch = "main" }
30
+ codex-protocol = { git = "https://github.com/openai/codex", package = "codex-protocol", branch = "main" }
30
31
 
31
32
  # Tell maturin to include the Python sources from the repo root (mixed project)
32
33
  [package.metadata.maturin]
@@ -1,7 +1,7 @@
1
1
  use anyhow::{Context, Result};
2
2
  use codex_core::config::{find_codex_home, Config, ConfigOverrides, ConfigToml};
3
3
  use codex_core::protocol::{EventMsg, InputItem};
4
- use codex_core::{AuthManager, ConversationManager};
4
+ use codex_core::{AuthManager, CodexAuth, ConversationManager};
5
5
  // use of SandboxMode is handled within core::config; not needed here
6
6
  use pyo3::prelude::*;
7
7
  use pyo3::types::{PyDict, PyFloat, PyList, PyModule, PyString};
@@ -38,10 +38,14 @@ fn run_exec_collect(
38
38
  }
39
39
 
40
40
  async fn run_exec_impl(prompt: String, config: Config) -> Result<Vec<JsonValue>> {
41
- let conversation_manager = ConversationManager::new(AuthManager::shared(
42
- config.codex_home.clone(),
43
- config.preferred_auth_method,
44
- ));
41
+ let conversation_manager = match std::env::var("OPENAI_API_KEY") {
42
+ Ok(val) if !val.trim().is_empty() => {
43
+ ConversationManager::with_auth(CodexAuth::from_api_key(&val))
44
+ }
45
+ _ => ConversationManager::new(AuthManager::shared(
46
+ config.codex_home.clone(),
47
+ )),
48
+ };
45
49
  let new_conv = conversation_manager.new_conversation(config).await?;
46
50
  let conversation = new_conv.conversation.clone();
47
51
 
@@ -174,6 +178,10 @@ fn build_config(
174
178
  overrides: Option<Bound<'_, PyDict>>,
175
179
  load_default_config: bool,
176
180
  ) -> Result<Config> {
181
+ // Match CLI behavior: import env vars from ~/.codex/.env (if present)
182
+ // before reading config/auth so OPENAI_API_KEY and friends are visible.
183
+ // Security: filter out CODEX_* variables just like the CLI does.
184
+ load_dotenv();
177
185
  let mut overrides_struct = ConfigOverrides::default();
178
186
  let mut cli_overrides: Vec<(String, TomlValue)> = Vec::new();
179
187
 
@@ -292,6 +300,33 @@ fn build_config(
292
300
  }
293
301
  }
294
302
 
303
+ const ILLEGAL_ENV_VAR_PREFIX: &str = "CODEX_";
304
+
305
+ /// Load env vars from ~/.codex/.env, filtering out any keys that start with
306
+ /// CODEX_ (reserved for internal use). This mirrors the behavior in the
307
+ /// `codex-arg0` crate used by the CLI so python users get the same DX.
308
+ fn load_dotenv() {
309
+ if let Ok(codex_home) = find_codex_home() {
310
+ let env_path = codex_home.join(".env");
311
+ if let Ok(iter) = dotenvy::from_path_iter(env_path) {
312
+ set_filtered(iter);
313
+ }
314
+ }
315
+ }
316
+
317
+ /// Helper to set vars from a dotenvy iterator while filtering out `CODEX_` keys.
318
+ fn set_filtered<I>(iter: I)
319
+ where
320
+ I: IntoIterator<Item = Result<(String, String), dotenvy::Error>>,
321
+ {
322
+ for (key, value) in iter.into_iter().flatten() {
323
+ if !key.to_ascii_uppercase().starts_with(ILLEGAL_ENV_VAR_PREFIX) {
324
+ // Safe to modify env here – we do it up front before we spawn runtimes/threads.
325
+ unsafe { std::env::set_var(&key, &value) };
326
+ }
327
+ }
328
+ }
329
+
295
330
  /// Convert a Python object into a TOML value. Returns Ok(None) for `None`.
296
331
  fn py_to_toml_value(obj: Bound<'_, PyAny>) -> Result<Option<TomlValue>> {
297
332
  use pyo3::types::{PyBool, PyDict, PyFloat, PyInt, PyList, PyString};
@@ -398,10 +433,14 @@ fn insert_parts(current: &mut TomlTable, parts: &[&str], val: TomlValue) {
398
433
  fn run_exec_stream_impl(prompt: String, config: Config, tx: mpsc::Sender<JsonValue>) -> Result<()> {
399
434
  let rt = tokio::runtime::Runtime::new()?;
400
435
  rt.block_on(async move {
401
- let conversation_manager = ConversationManager::new(AuthManager::shared(
402
- config.codex_home.clone(),
403
- config.preferred_auth_method,
404
- ));
436
+ let conversation_manager = match std::env::var("OPENAI_API_KEY") {
437
+ Ok(val) if !val.trim().is_empty() => {
438
+ ConversationManager::with_auth(CodexAuth::from_api_key(&val))
439
+ }
440
+ _ => ConversationManager::new(AuthManager::shared(
441
+ config.codex_home.clone(),
442
+ )),
443
+ };
405
444
  let new_conv = conversation_manager.new_conversation(config).await?;
406
445
  let conversation = new_conv.conversation.clone();
407
446
 
@@ -1,16 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from pydantic import BaseModel
4
- from pydantic.config import ConfigDict
5
-
6
- from .protocol.types import EventMsg
7
-
8
-
9
- class Event(BaseModel):
10
- """Protocol event envelope with typed `msg` (union of EventMsg_*)."""
11
-
12
- id: str
13
- msg: EventMsg
14
-
15
- # Allow forward compatibility with additional envelope fields
16
- model_config = ConfigDict(extra="allow")
File without changes
File without changes