mirror of
https://github.com/Alishahryar1/free-claude-code.git
synced 2026-07-10 00:14:16 +00:00
## Problem
OpenAI-chat providers lost explicit empty reasoning state and could
replay invalid tool-call history when unrelated messages appeared before
matching tool results.
## Changes
| Before | After |
| --- | --- |
| Empty `reasoning_content` and empty thinking blocks were treated as
absent. | Empty reasoning is preserved as explicit replay state. |
| OpenAI-chat conversion only deferred post-tool assistant text. |
OpenAI-chat conversion buffers later transcript messages until required
tool results are emitted. |
| Responses prior tool calls and outputs were emitted one item per
message. | Responses prior tool calls and outputs are grouped into valid
Anthropic tool-use/result messages. |
| Empty streamed `reasoning_content` produced no thinking block. | Empty
streamed `reasoning_content` starts thinking state without visible delta
text. |
<!-- greptile_comment -->
<details open><summary><h3>Greptile Summary</h3></summary>
This PR fixes OpenAI chat reasoning replay and tool-history ordering.
The main changes are:
- Preserves explicit empty `reasoning_content` and empty thinking
blocks.
- Reworks OpenAI chat conversion around a ledger that waits for required
tool results before replaying buffered transcript messages.
- Groups prior Responses tool calls and outputs into valid Anthropic
tool-use and tool-result messages.
- Starts streamed thinking state when empty `reasoning_content` is
received.
- Adds focused tests for nested tool turns, out-of-order results,
multi-tool replay, and empty reasoning.
</details>
<h3>Confidence Score: 5/5</h3>
Safe to merge with low risk.
No blocking issues were found in the changed conversion paths. The
updated ledger covers the prior invalid replay cases and the tests
include nested, out-of-order, multi-tool, and empty reasoning scenarios.
The required patch version and lockfile updates are present.
No files require special attention.
<details><summary><h3><a href="https://www.greptile.com/trex"><img
alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="20" align="absmiddle"></a> T-Rex Logs</h3></summary>
**What T-Rex did**
- Ran the focused OpenAI conversion regression suite with Pytest,
capturing the command, working directory, pass count, exit code, and
elapsed time.
- Encountered an external timeout during the initial Pytest run at 98%
progress, then re-ran the same focused suite to completion for
definitive proof.
- Validated code quality with Ruff by executing the lint command and
obtaining a successful output.
<a
href="https://app.greptile.com/trex/runs/13503694/artifacts"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img
alt="View all artifacts"
src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a>
<sub><a href="https://www.greptile.com/trex"><img alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="14" align="absmiddle"></a> Ran code and verified through
T-Rex</sub>
</details>
<details open><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| core/anthropic/conversion.py | Replaces single pending-tool state with
a ledger that buffers transcript segments until required OpenAI chat
tool results can be emitted in valid order. |
| core/openai_responses/input.py | Groups consecutive prior Responses
tool calls/results into Anthropic tool-use/result turns and preserves
explicit empty reasoning. |
| core/openai_responses/reasoning.py | Updates reasoning extraction and
combination helpers so empty strings remain explicit replay state
without adding spurious separators. |
| providers/deepseek/compat.py | Treats empty top-level or block-level
thinking as replayable when detecting DeepSeek tool-history
compatibility. |
| providers/transports/openai_chat/stream.py | Starts an Anthropic
thinking block for empty streamed `reasoning_content` while only
emitting deltas for non-empty text. |
| tests/providers/test_converter.py | Adds OpenAI chat conversion
coverage for buffered tool history, nested pending tool turns, and
explicit empty reasoning. |
| tests/core/openai_responses/test_conversion.py | Adds Responses
conversion tests for grouped prior tool calls/results and empty
reasoning attachment. |
| pyproject.toml | Bumps the package patch version for the production
conversion fixes. |
| uv.lock | Keeps the lockfile package version in sync with
`pyproject.toml`. |
</details>
<details open><summary><h3>Sequence Diagram</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant A as Anthropic transcript
participant L as OpenAI chat ledger
participant O as OpenAI chat history
A->>L: Assistant tool_use segment
L->>O: Emit assistant tool_calls
A->>L: Later plain user/assistant messages
L-->>L: Buffer until required tool_result ids arrive
A->>L: User tool_result blocks
L->>O: Emit matching role: tool results in tool_call order
L->>O: Emit deferred assistant post-tool content
L->>O: Drain buffered plain transcript messages
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant A as Anthropic transcript
participant L as OpenAI chat ledger
participant O as OpenAI chat history
A->>L: Assistant tool_use segment
L->>O: Emit assistant tool_calls
A->>L: Later plain user/assistant messages
L-->>L: Buffer until required tool_result ids arrive
A->>L: User tool_result blocks
L->>O: Emit matching role: tool results in tool_call order
L->>O: Emit deferred assistant post-tool content
L->>O: Drain buffered plain transcript messages
```
</a>
</details>
<sub>Reviews (3): Last reviewed commit: ["Refactor OpenAI chat tool
history
replay"](ae1635d2ce)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=42274270)</sub>
<!-- /greptile_comment -->
130 lines
3.6 KiB
TOML
130 lines
3.6 KiB
TOML
[build-system]
|
|
requires = ["hatchling"]
|
|
build-backend = "hatchling.build"
|
|
|
|
[project]
|
|
name = "free-claude-code"
|
|
version = "3.4.7"
|
|
description = "Middleware between Claude Code CLI (Anthropic API) and NVIDIA NIM"
|
|
readme = "README.md"
|
|
requires-python = ">=3.14.0"
|
|
dependencies = [
|
|
"fastapi[standard]>=0.139.0",
|
|
"uvicorn>=0.50.0",
|
|
"httpx[socks]>=0.28.1",
|
|
"markdown-it-py>=4.2.0",
|
|
"pydantic>=2.13.4",
|
|
"python-dotenv>=1.2.2",
|
|
"tiktoken>=0.13.0",
|
|
"python-telegram-bot>=22.8",
|
|
"discord.py>=2.7.1",
|
|
"pydantic-settings>=2.14.2",
|
|
"openai>=2.44.0",
|
|
"loguru>=0.7.0",
|
|
"aiohttp>=3.14.1",
|
|
"jsonschema>=4.25.0",
|
|
]
|
|
|
|
[project.scripts]
|
|
fcc-server = "cli.entrypoints:serve"
|
|
free-claude-code = "cli.entrypoints:serve"
|
|
fcc-init = "cli.entrypoints:init"
|
|
fcc-claude = "cli.launchers.claude:launch"
|
|
fcc-codex = "cli.launchers.codex:launch"
|
|
|
|
[project.optional-dependencies]
|
|
voice = [
|
|
"grpcio>=1.81.1",
|
|
"grpcio-tools>=1.81.1",
|
|
"nvidia-riva-client>=2.26.0",
|
|
]
|
|
voice_local = [
|
|
"torch>=2.12.1",
|
|
"transformers>=5.13.0",
|
|
"accelerate>=1.14.0",
|
|
"librosa>=0.10.0",
|
|
]
|
|
|
|
[tool.hatch.build.targets.wheel]
|
|
packages = ["api", "cli", "config", "core", "messaging", "providers"]
|
|
|
|
[tool.hatch.build.targets.wheel.force-include]
|
|
".env.example" = "config/env.example"
|
|
|
|
[tool.uv]
|
|
required-version = ">=0.11.0"
|
|
|
|
[tool.uv.sources]
|
|
torch = { index = "pytorch-cu130" }
|
|
|
|
[[tool.uv.index]]
|
|
name = "pytorch-cu130"
|
|
url = "https://download.pytorch.org/whl/cu130"
|
|
explicit = true
|
|
|
|
[dependency-groups]
|
|
dev = [
|
|
"pytest>=9.1.1",
|
|
"pytest-asyncio>=1.4.0",
|
|
"pytest-cov>=7.1.0",
|
|
"ty>=0.0.56",
|
|
"ruff>=0.15.20",
|
|
"pytest-xdist>=3.8.0",
|
|
]
|
|
|
|
[tool.ruff]
|
|
target-version = "py314"
|
|
line-length = 88
|
|
|
|
[tool.ruff.lint]
|
|
select = [
|
|
"E", # pycodestyle errors
|
|
"W", # pycodestyle warnings
|
|
"F", # Pyflakes (undefined names, unused imports)
|
|
"I", # isort (import ordering)
|
|
"UP", # pyupgrade (modernise syntax for target Python version)
|
|
"B", # flake8-bugbear (common bugs and anti-patterns)
|
|
"C4", # flake8-comprehensions (idiomatic comprehensions)
|
|
"SIM", # flake8-simplify (simplifiable code patterns)
|
|
"PERF", # Perflint (performance anti-patterns)
|
|
"RUF", # Ruff-specific rules
|
|
]
|
|
ignore = [
|
|
"E501", # line too long — enforced by the formatter instead
|
|
"B008", # FastAPI Depends() in argument defaults is intentional
|
|
"RUF006", # fire-and-forget tasks intentionally not awaited
|
|
]
|
|
|
|
[tool.ruff.lint.isort]
|
|
known-first-party = ["api", "cli", "config", "core", "messaging", "providers", "smoke"]
|
|
|
|
[tool.ruff.format]
|
|
quote-style = "double"
|
|
indent-style = "space"
|
|
line-ending = "auto"
|
|
skip-magic-trailing-comma = false
|
|
|
|
[tool.pytest.ini_options]
|
|
pythonpath = ["."]
|
|
addopts = "-n auto"
|
|
testpaths = ["tests"]
|
|
markers = [
|
|
"live: opt-in local smoke tests that can touch real services",
|
|
"interactive: smoke tests requiring manual user interaction",
|
|
"provider: live provider checks",
|
|
"messaging: live messaging platform checks",
|
|
"cli: CLI integration checks",
|
|
"clients: client compatibility checks",
|
|
"voice: voice transcription checks",
|
|
"contract: deterministic feature contract checks",
|
|
"smoke_target(name): route a smoke test behind FCC_SMOKE_TARGETS",
|
|
"xdist_group(name): group smoke provider items under pytest-xdist --dist=loadgroup",
|
|
]
|
|
|
|
[tool.ty.environment]
|
|
python-version = "3.14"
|
|
|
|
[tool.ty.analysis]
|
|
# Optional voice_local extra: torch, transformers, librosa for local whisper transcription
|
|
# Optional voice extra: nvidia-riva-client for nvidia_nim transcription provider
|
|
allowed-unresolved-imports = ["torch", "transformers", "librosa", "riva.client"]
|