Commit d24a3f8
authored
fix(proxy): bound Codex WS compression fallback latency (headroomlabs-ai#1802)
## Description
Codex `/v1/responses` WebSocket frames could spend the full global
compression timeout before falling through unchanged, then report only a
generic `compression_exception` reason. That made a recoverable timeout
look like an opaque compression failure and left Codex users waiting
around 30 seconds for frames that did not produce useful compression.
This keeps the existing compression executor, adds a Codex WS-specific
compression timeout bound, and records timeout fallback distinctly from
other compression exceptions. Closes headroomlabs-ai#922.
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)
## Changes Made
- Bound Codex Responses WebSocket frame compression with a WS-specific
timeout.
- Pass that timeout through the existing compression executor instead of
adding a parallel executor path.
- Record timeout passthrough with `compression_timeout` instead of the
generic compression exception reason.
- Preserve generic `compression_exception` for non-timeout failures.
- Add coverage for first-frame timeout bounds, timeout reason logging,
generic exception preservation, and later-frame failed metrics.
## Testing
- [x] Unit tests pass (`uv run pytest
tests/test_openai_codex_ws_lifecycle.py
tests/test_codex_ws_compression_scheduler.py
tests/test_compression_observability.py -q`)
- [x] Linting passes (`uv run ruff check
headroom/proxy/handlers/openai.py
tests/test_openai_codex_ws_lifecycle.py
tests/test_codex_ws_compression_scheduler.py
tests/test_compression_observability.py`)
- [ ] Type checking passes (`uv run mypy headroom`)
- [x] New tests added for new functionality when applicable
- [x] Manual testing performed
### Test Output
```text
uv run pytest tests/test_openai_codex_ws_lifecycle.py -q
22 passed in 1.38s
uv run pytest tests/test_codex_ws_compression_scheduler.py tests/test_compression_observability.py -q
14 passed, 1 skipped in 3.63s
uv run pytest tests/test_openai_codex_ws_lifecycle.py tests/test_codex_ws_compression_scheduler.py tests/test_compression_observability.py -q
36 passed, 1 skipped in 2.09s
uv run ruff check headroom/proxy/handlers/openai.py tests/test_openai_codex_ws_lifecycle.py tests/test_codex_ws_compression_scheduler.py tests/test_compression_observability.py
All checks passed!
uv run ruff format headroom/proxy/handlers/openai.py tests/test_openai_codex_ws_lifecycle.py --check
2 files already formatted
```
## Real Behavior Proof
- Environment: Windows, Python through the project `uv` environment.
- Exact command / steps: run the focused Codex WS timeout regressions
with small monkeypatched timeout values.
- Observed result: base uses the global timeout path or reports only
generic `compression_exception`; head passes with Codex WS timeout
bounded to the smaller WS cap, logs `compression_timeout` for timeout
fallback, preserves `compression_exception` for non-timeout failures,
and records failed metrics for later-frame timeout fallback.
- Not tested: live Codex Desktop traffic against paid OpenAI
credentials.
## Review Readiness
- [x] I have performed a self-review
- [x] This PR is ready for human review
## Checklist
- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] I have updated the CHANGELOG.md if applicable
## Additional Notes
No changelog entry is needed for this request-path bug fix. Type
checking was not part of the focused local validation for this
Python-only change. Live Codex Desktop validation is not included
because the regression is covered at the handler boundary.1 parent 0a3851b commit d24a3f8
2 files changed
Lines changed: 203 additions & 10 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
70 | 77 | | |
71 | 78 | | |
72 | 79 | | |
| |||
1756 | 1763 | | |
1757 | 1764 | | |
1758 | 1765 | | |
| 1766 | + | |
1759 | 1767 | | |
1760 | 1768 | | |
1761 | 1769 | | |
| |||
1778 | 1786 | | |
1779 | 1787 | | |
1780 | 1788 | | |
1781 | | - | |
| 1789 | + | |
1782 | 1790 | | |
1783 | 1791 | | |
1784 | 1792 | | |
| |||
4864 | 4872 | | |
4865 | 4873 | | |
4866 | 4874 | | |
| 4875 | + | |
| 4876 | + | |
| 4877 | + | |
4867 | 4878 | | |
4868 | 4879 | | |
4869 | 4880 | | |
| |||
4949 | 4960 | | |
4950 | 4961 | | |
4951 | 4962 | | |
| 4963 | + | |
4952 | 4964 | | |
4953 | | - | |
| 4965 | + | |
| 4966 | + | |
4954 | 4967 | | |
4955 | 4968 | | |
4956 | 4969 | | |
4957 | | - | |
| 4970 | + | |
4958 | 4971 | | |
4959 | 4972 | | |
4960 | 4973 | | |
| |||
5175 | 5188 | | |
5176 | 5189 | | |
5177 | 5190 | | |
| 5191 | + | |
| 5192 | + | |
| 5193 | + | |
5178 | 5194 | | |
5179 | | - | |
5180 | | - | |
5181 | | - | |
5182 | | - | |
| 5195 | + | |
5183 | 5196 | | |
| 5197 | + | |
| 5198 | + | |
| 5199 | + | |
| 5200 | + | |
| 5201 | + | |
| 5202 | + | |
| 5203 | + | |
| 5204 | + | |
| 5205 | + | |
| 5206 | + | |
| 5207 | + | |
| 5208 | + | |
| 5209 | + | |
| 5210 | + | |
| 5211 | + | |
| 5212 | + | |
| 5213 | + | |
| 5214 | + | |
| 5215 | + | |
| 5216 | + | |
| 5217 | + | |
| 5218 | + | |
| 5219 | + | |
| 5220 | + | |
| 5221 | + | |
| 5222 | + | |
| 5223 | + | |
| 5224 | + | |
| 5225 | + | |
| 5226 | + | |
| 5227 | + | |
| 5228 | + | |
| 5229 | + | |
5184 | 5230 | | |
5185 | 5231 | | |
5186 | 5232 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| 19 | + | |
18 | 20 | | |
19 | | - | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
38 | 39 | | |
39 | 40 | | |
40 | 41 | | |
| 42 | + | |
41 | 43 | | |
42 | 44 | | |
43 | 45 | | |
| |||
63 | 65 | | |
64 | 66 | | |
65 | 67 | | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
66 | 71 | | |
67 | 72 | | |
68 | 73 | | |
| |||
456 | 461 | | |
457 | 462 | | |
458 | 463 | | |
459 | | - | |
| 464 | + | |
460 | 465 | | |
461 | 466 | | |
462 | 467 | | |
| |||
468 | 473 | | |
469 | 474 | | |
470 | 475 | | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
471 | 482 | | |
472 | 483 | | |
473 | 484 | | |
| |||
484 | 495 | | |
485 | 496 | | |
486 | 497 | | |
487 | | - | |
| 498 | + | |
488 | 499 | | |
489 | 500 | | |
490 | 501 | | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
491 | 638 | | |
492 | 639 | | |
493 | 640 | | |
| |||
0 commit comments