main
96 次代码提交
| 作者 | SHA1 | 备注 | 提交日期 | |
|---|---|---|---|---|
|
|
d98a6b0ca0 |
Add a native FCC desktop launcher for Windows and macOS (#1225)
## Problem Free Claude Code currently has to remain attached to a terminal, so closing that window stops the proxy and users have no native way to reopen Admin or control the background server. The contributed Windows wrapper also would have introduced a second bundled server lifecycle instead of reusing FCC's cleanup and restart ownership. Fixes #1147. ## Changes | Before | After | | --- | --- | | Users keep `fcc-server` running in a terminal. | Windows and macOS users can launch a console-free FCC Desktop host from a desktop/application shortcut and control it from the tray or menu bar. | | A wrapper would need to spawn and terminate a child server. | The terminal and desktop paths share one in-process supervisor, one graceful runtime shutdown path, and an OS-held singleton lock. | | Installers manage only command entry points. | Windows installs desktop and Start-menu shortcuts; macOS installs a per-user app bundle and owned desktop link; uninstallers remove only those FCC artifacts. | | Desktop behavior had no contract coverage. | Lifecycle, duplicate launch, restart/quit, GUI packaging, Windows shortcuts, macOS bundle creation, quoting, and ownership boundaries are covered alongside the full CI suite. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR adds a native FCC desktop launcher for Windows and macOS. The main changes are: - A shared server supervisor for terminal and desktop launches. - A singleton desktop host with tray or menu-bar controls. - Windows shortcuts and a per-user macOS app bundle. - Ownership checks for launcher installation and removal. - Tests for lifecycle, packaging, shortcuts, and uninstall behavior. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. Startup restart requests are reserved before the worker starts. macOS bundle operations verify ownership before modifying or deleting files. Windows shortcut operations verify their targets before replacement or removal. No blocking issues were found in the updated code. <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** - Compared the pre-change contract test results against the parent commit f81af55630aa1adb518b748b9e6985c73c4c4775 and observed 3 failures and 4 passes, indicating the missing scheduled-startup lifecycle contract. - Executed the after-state contract validation with uv run pytest -n 0 tests/cli/test\_desktop.py -q and confirmed the run finished with 7 passes and an exit code of 0. - Verified that no real proxy or native GUI dependency was started during the after-state run. - Inspected the two log artifacts that accompany the proof to corroborate the test outcomes. <a href="https://app.greptile.com/trex/runs/15235588/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 | |----------|----------| | src/free_claude_code/cli/commands.py | Adds the shared server supervisor and scheduled-run state for startup restart requests. | | src/free_claude_code/cli/desktop.py | Adds singleton locking and coordinates the tray loop with the server worker. | | scripts/install.sh | Creates the macOS app bundle only when an existing bundle is FCC-owned. | | scripts/uninstall.sh | Removes the macOS launcher only on macOS and only with the expected ownership marker. | | scripts/install.ps1 | Creates Windows shortcuts while preserving shortcuts with unrelated targets. | | scripts/uninstall.ps1 | Removes Windows shortcuts only when their targets match an FCC desktop entry point. | </details> <sub>Reviews (3): Last reviewed commit: ["fix: coalesce desktop startup restarts"](https://github.com/alishahryar1/free-claude-code/commit/b9554729770e08a58818d677de39757c751e760e) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45925660)</sub> <!-- /greptile_comment --> |
||
|
|
2a676cc6d9 |
Make ProviderModelInfo the sole model-catalog contract (#1222)
## Problem Provider model discovery consumes metadata, but providers and the cache still expose a parallel IDs-only contract. The duplicate contract adds adapters and lets tests bypass capability metadata. ## Changes | Before | After | | --- | --- | | `BaseProvider` exposed `list_model_ids()` plus a metadata adapter. | `BaseProvider` exposes only abstract `list_model_infos()` returning application-owned metadata. | | Ordinary providers parsed IDs and converted them later. | Ordinary providers parse OpenAI-compatible catalogs directly into `ProviderModelInfo` values. | | OpenRouter, Cloudflare, and GitHub Models maintained redundant IDs-only wrappers. | Provider-specific filters and capability metadata have one return path. | | Vertex returned paginated IDs for the base adapter to wrap. | Vertex returns metadata after completing the same paginated discovery flow. | | The runtime cache exposed test-only raw-ID write and prefixed-ID read helpers. | The runtime cache accepts and returns metadata while retaining its production admin-status ID projection. | | Provider tests asserted the parallel IDs-only API. | Provider tests enforce the metadata-only contract and preserve provider-specific discovery behavior. | | The package version was `4.11.6`. | The package version is `4.11.7` with an updated lockfile. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes provider metadata the only model-catalog contract. The main changes are: - Makes `list_model_infos()` the abstract provider discovery API. - Migrates provider parsers and implementations to `ProviderModelInfo`. - Removes IDs-only cache and parser helpers. - Updates provider tests, architecture documentation, and package metadata. </details> <h3>Confidence Score: 4/5</h3> The catalog migration is consistent, but the release version must reflect the incompatible API removal. Repository provider and cache call paths use the new metadata shape consistently. Existing external consumers of the removed contracts can fail after a patch upgrade. The repository rules classify incompatible API removals as a major release. pyproject.toml and the matching package entry in uv.lock <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** - The external-consumer compatibility probe was run against both revisions, confirming the base still supports the legacy provider contract, while head fails with a TypeError due to the missing list\_model\_infos method, and runtime metadata shows head at version 4.11.7, indicating the removal is a patch transition rather than a major change. - An automated test suite completed successfully with 83 tests passing in 3.31 seconds. <a href="https://app.greptile.com/trex/runs/15207030/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 | |----------|----------| | src/free_claude_code/providers/base.py | Replaces the IDs-only provider API with an abstract metadata-only contract. | | src/free_claude_code/providers/model_listing.py | Consolidates OpenAI-compatible parsing into ProviderModelInfo results and removes IDs-only helpers. | | src/free_claude_code/providers/runtime/model_cache.py | Removes raw-ID helpers while retaining metadata storage and the admin ID projection. | | src/free_claude_code/providers/openai_chat/provider.py | Provides the metadata discovery implementation inherited by ordinary OpenAI-compatible providers. | | src/free_claude_code/providers/vertex/client.py | Preserves paginated discovery while returning metadata values. | | pyproject.toml | Uses a patch bump for a release that removes callable and importable contracts. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart LR A[Provider catalog endpoint] --> B[list_model_infos] B --> C[ProviderModelInfo set] C --> D[Provider model discovery] D --> E[ProviderModelCache] E --> F[Metadata-aware catalog] E --> G[Admin ID projection] ``` </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"}}}%% flowchart LR A[Provider catalog endpoint] --> B[list_model_infos] B --> C[ProviderModelInfo set] C --> D[Provider model discovery] D --> E[ProviderModelCache] E --> F[Metadata-aware catalog] E --> G[Admin ID projection] ``` </a> </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fprovider-model-info-contract%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fprovider-model-info-contract%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apyproject.toml%3A7%0A**Breaking%20Contract%20Ships%20as%20Patch**%0A%0AThis%20release%20removes%20%60BaseProvider.list_model_ids%28%29%60%20and%20cache%2Fparser%20methods%20that%20existing%20integrations%20can%20import%20or%20call.%20Such%20consumers%20will%20fail%20with%20%60TypeError%60%2C%20%60AttributeError%60%2C%20or%20%60ImportError%60%20after%20a%20patch%20upgrade%2C%20so%20this%20incompatible%20API%20change%20requires%20a%20major%20version%20bump%20under%20the%20repository's%20versioning%20rules.%0A%0A%60%60%60suggestion%0Aversion%20%3D%20%225.0.0%22%0A%60%60%60%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1222&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["Make ProviderModelInfo the sole catalog ..."](https://github.com/alishahryar1/free-claude-code/commit/5c543eadc114201a4085d38885a27ac49153ca29) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45869248)</sub> > Greptile also left **1 inline comment** on this PR. **Context used:** - Context used - CLAUDE.md ([source](https://app.greptile.com/alishahryar1/github/Alishahryar1/free-claude-code/-/custom-context?memory=d2fd24d8-0dec-4faf-8ee4-e085e215a2f8)) <!-- /greptile_comment --> |
||
|
|
1a476562fc |
Make provider model discovery the sole catalog owner (#1221)
## Problem Startup model-list I/O was split between a non-enforcing configured-model validator and the real discovery path. Both queried providers and populated the same cache even though synchronous cache warm-up was the validator's only required effect. ## Changes | Before | After | | --- | --- | | Validation and discovery independently resolved providers, queried model lists, and cached results. | `ProviderModelDiscovery` solely owns model-list queries, failure reporting, and cache population. | | Startup ran configured-model validation and then launched discovery. | Startup synchronously warms referenced providers through discovery, then launches the existing missing-provider background pass. | | Absence from a provider catalog produced a non-enforcing missing-model warning. | Provider catalogs remain discovery metadata and provider execution remains authoritative. | | Configured model references retained environment-source metadata for validator diagnostics. | Configured model references retain only routing data. | | Successful startup providers could be represented by two separate subsystems. | Focused tests enforce concurrent warm-up, single successful queries, failed-query eligibility, and warm-before-background ordering. | | The package version was `4.11.5`. | The package version is `4.11.6` with an updated lockfile. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes provider discovery the sole owner of model catalogs. The main changes are: - Warms routed provider catalogs before background discovery starts. - Reuses successful warm results while retrying failed providers. - Removes configured-model catalog validation and source metadata. - Moves query-failure reporting into the discovery module. - Updates focused tests, architecture docs, and package version. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. Provider failures remain isolated and eligible for background retry. Successful warm results are not queried again by the missing-provider pass. Lease release and startup cleanup remain protected by existing control flow. None. <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** - \`test\_runtime\_warm\_queries\_referenced\_providers\_concurrently\`, \`test\_startup\_discovery\_queries\_each\_successful\_provider\_once\`, \`test\_failed\_startup\_warm\_remains\_eligible\_for\_background\_refresh\`, \`test\_runtime\_warm\_caches\_all\_referenced\_provider\_models\`, and \`test\_runtime\_startup\_warms\_catalog\_before\_background\_refresh\` all passed. - The complete verbose HEAD run, including command, working directory, exit code, test nodes, and summary, is preserved in \`trex-artifacts/provider-discovery-startup-validation.log\` and the paired after artifact. <a href="https://app.greptile.com/trex/runs/15203372/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 | |----------|----------| | src/free_claude_code/providers/runtime/discovery.py | Centralizes catalog queries, failure reporting, referenced-provider warming, and cache population. | | src/free_claude_code/runtime/provider_manager.py | Replaces validation with discovery-based warming under a generation lease. | | src/free_claude_code/runtime/application.py | Warms referenced catalogs before launching the missing-provider background pass. | | src/free_claude_code/config/model_refs.py | Removes validation-only source metadata while preserving deterministic deduplication. | | tests/providers/test_model_discovery.py | Covers concurrent warming, partial failures, retry eligibility, and single successful queries. | </details> <details open><summary><h3>Sequence Diagram</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% sequenceDiagram participant App as ApplicationRuntime participant Manager as ProviderRuntimeManager participant Discovery as ProviderModelDiscovery participant Provider participant Cache as ProviderModelCache App->>Manager: warm_referenced_model_cache() Manager->>Discovery: warm referenced providers par Provider queries Discovery->>Provider: list_model_infos() end Provider-->>Discovery: metadata or failure Discovery->>Cache: cache successful results Discovery-->>Manager: refresh result Manager-->>App: warm complete App->>Manager: start_model_list_refresh() Manager->>Discovery: refresh only missing providers Discovery->>Cache: cache remaining catalogs ``` </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 App as ApplicationRuntime participant Manager as ProviderRuntimeManager participant Discovery as ProviderModelDiscovery participant Provider participant Cache as ProviderModelCache App->>Manager: warm_referenced_model_cache() Manager->>Discovery: warm referenced providers par Provider queries Discovery->>Provider: list_model_infos() end Provider-->>Discovery: metadata or failure Discovery->>Cache: cache successful results Discovery-->>Manager: refresh result Manager-->>App: warm complete App->>Manager: start_model_list_refresh() Manager->>Discovery: refresh only missing providers Discovery->>Cache: cache remaining catalogs ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["Unify provider model discovery ownership"](https://github.com/alishahryar1/free-claude-code/commit/33f68e4338fd2326a7d8fd3e7e28246b47fa4210) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45862060)</sub> <!-- /greptile_comment --> |
||
|
|
5305bd7e08 |
Remove obsolete init and server alias commands (#1220)
## Problem
FCC still publishes `fcc-init` and the `free-claude-code` server alias
from an obsolete installation flow. Configuration creation now belongs
to the Admin UI, while `fcc-server` owns startup and legacy migration.
## Changes
| Before | After |
| --- | --- |
| The package installs six console commands. | The package installs only
`fcc-server`, `fcc-claude`, `fcc-codex`, and `fcc-pi`. |
| `fcc-init` duplicates configuration creation outside the Admin UI. |
The Admin UI exclusively creates managed configuration, and server
startup retains legacy migration. |
| Smoke contracts and architecture describe the retired commands. |
Smoke contracts and architecture describe the supported command surface.
|
| Installer safety lists contain unexplained retired names. | Installer
safety lists document why retired names remain detectable during updates
and uninstall. |
| The package version is `4.11.4`. | The package version is `4.11.5`. |
<!-- greptile_comment -->
<details open><summary><h3>Greptile Summary</h3></summary>
This PR retires the obsolete initialization command and server alias.
The main changes are:
- Removes `fcc-init` and `free-claude-code` from package scripts.
- Moves fresh configuration creation exclusively to the Admin UI.
- Keeps legacy environment migration in `fcc-server` startup.
- Updates smoke coverage, installer comments, documentation, and package
metadata.
</details>
<h3>Confidence Score: 4/5</h3>
The CLI removal needs a compatible release version or temporary aliases
before merging.
Existing automation can lose `fcc-init` and `free-claude-code` after a
patch upgrade. Fresh installs can still start the server and create
configuration through the Admin UI.
pyproject.toml and uv.lock; legacy configuration migration remains
before settings loading.
<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**
- I reproduced the patch upgrade path by installing base revision
|
||
|
|
36bb282558 |
Recover Claude sessions from provider context overflow (#1215)
## Problem NVIDIA NIM can report context exhaustion as a 400 `BadRequestError` saying its derived `max_tokens` is negative. FCC treated that as a generic invalid request, so Claude Code could not recognize the smaller upstream context window, compact the conversation, and replay the interrupted turn. LM Studio also encoded Claude's recovery phrase inside provider code instead of reporting a protocol-neutral failure. Fixes #1198. ## Changes - Add one protocol-neutral `context_window_exceeded` execution failure with a non-retryable 400 contract. - Narrowly classify only NVIDIA NIM's negative derived-`max_tokens` signature while preserving the complete redacted provider diagnostic and request ID. - Let the Anthropic serializer alone add Claude's `prompt is too long` compaction trigger; OpenAI Responses keeps a standard invalid-request envelope. - Migrate LM Studio's existing context preflight to the same neutral semantic and document the ownership boundary. - Add provider, protocol, API, trace, near-miss, and real Claude compaction/replay coverage; bump FCC to 4.11.4. | Before | After | | --- | --- | | Context overflow appeared as an ordinary provider 400 and ended the Claude turn. | Claude receives a typed 400 with its recognized compaction trigger, compacts once, and replays the interrupted turn without an FCC or SDK retry loop. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR adds protocol-neutral recovery from provider context-window exhaustion. The main changes are: - Classify NVIDIA NIM negative derived-`max_tokens` errors as context-window failures. - Move Claude's compaction trigger into the Anthropic serializer. - Migrate LM Studio context preflight to the neutral failure type. - Preserve the standard OpenAI Responses invalid-request envelope. - Add provider, protocol, API, trace, and recovery tests. - Bump the package version to 4.11.4. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. - No blocking issues found in the changed code. - The new failure kind is covered by both protocol mappings. - Provider classification remains narrow and non-retryable. - The protocol-specific compaction phrase stays at the Anthropic boundary. <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 narrow pytest command from /home/user/repo without live provider credentials or services, and observed a clean test run with all tests passing. <a href="https://app.greptile.com/trex/runs/15073403/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 | |----------|----------| | src/free_claude_code/providers/nvidia_nim/client.py | Adds narrow context-window classification for nested and top-level NVIDIA NIM error bodies. | | src/free_claude_code/providers/lmstudio/client.py | Migrates context-budget preflight failures to the canonical context-window failure. | | src/free_claude_code/core/anthropic/errors.py | Adds Anthropic mapping and injects Claude's compaction phrase at the wire boundary. | | src/free_claude_code/core/openai_responses/errors.py | Maps context exhaustion to the standard OpenAI invalid-request error. | | src/free_claude_code/providers/failure_policy.py | Adds the canonical non-retryable status-400 context-window failure factory. | | src/free_claude_code/core/failures.py | Adds the protocol-neutral context-window failure category. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A[Provider detects context exhaustion] --> B[Context-window ExecutionFailure] B --> C{Protocol adapter} C -->|Anthropic Messages| D[400 invalid_request_error] D --> E[Add prompt is too long trigger] E --> F[Claude compacts and replays] C -->|OpenAI Responses| G[400 invalid_request_error] G --> H[Keep neutral provider message] ``` </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"}}}%% flowchart TD A[Provider detects context exhaustion] --> B[Context-window ExecutionFailure] B --> C{Protocol adapter} C -->|Anthropic Messages| D[400 invalid_request_error] D --> E[Add prompt is too long trigger] E --> F[Claude compacts and replays] C -->|OpenAI Responses| G[400 invalid_request_error] G --> H[Keep neutral provider message] ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["Normalize provider context overflow for ..."](https://github.com/alishahryar1/free-claude-code/commit/29c89a4c1011d986284e9d163855174d1d433293) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45603631)</sub> <!-- /greptile_comment --> |
||
|
|
258ed3e7ed |
Keep FCC-local traffic off outbound proxies (#1214)
## Problem FCC-local health and model-catalog requests inherited machine proxy settings, so an outbound proxy could return HTTP 502 even while `fcc-server` was healthy. Spawned agents inherited the same missing loopback bypass. Fixes #1199. ## Changes | Before | After | | --- | --- | | Launcher probes used the process-wide urllib proxy policy. | FCC-local probes use one proxy-disabled transport owner. | | Codex catalog loading could leave through an outbound proxy. | Codex catalog loading uses the same direct local transport. | | Claude, Codex, Pi, and managed messaging inherited incomplete bypass lists. | Spawned clients preserve outbound proxies while merging FCC and loopback hosts into `NO_PROXY` and `no_proxy`. | | Local and upstream proxy responsibilities overlapped. | CLI-local transport and provider-specific upstream proxies have explicit separate owners. | | Tests mocked launcher reachability without exercising proxy interception. | A real fake-proxy regression proves loopback traffic never reaches the proxy, and an ownership contract prevents raw local transports from returning. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR keeps FCC-local traffic separate from configured outbound proxies. The main changes are: - Adds one direct HTTP transport for FCC health and model-catalog requests. - Adds FCC and loopback hosts to spawned clients' proxy-bypass environments. - Updates Claude, Codex, and Pi launcher integration. - Adds proxy-interception and transport-ownership tests. - Documents the boundary and bumps the package version. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. Updated callers supply the new Codex environment argument. The direct opener changes proxy handling while retaining urllib's standard request handlers. Tests cover real proxy interception and preservation of existing bypass policy. No changed files need additional 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** - T-Rex validated the contract by comparing preflight and forward-proxy state before and after HEAD, noting the preflight result moved from HTTP 502 and the forward-proxy hits to a clean health-check state. - T-Rex confirmed all three tests in tests/cli/test\_local\_http.py passed. <a href="https://app.greptile.com/trex/runs/15066178/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 | |----------|----------| | src/free_claude_code/cli/local_http.py | Adds the shared direct opener and proxy-bypass environment policy. | | src/free_claude_code/cli/launchers/common.py | Routes FCC health checks through the direct local transport. | | src/free_claude_code/cli/launchers/codex.py | Routes catalog requests directly and adds local bypass entries to the Codex environment. | | src/free_claude_code/cli/claude_env.py | Adds FCC and loopback proxy bypasses to Claude environments. | | src/free_claude_code/cli/launchers/pi.py | Adds FCC and loopback proxy bypasses to Pi environments. | | tests/cli/test_local_http.py | Tests direct local access, proxy interception, environment merging, and deduplication. | | tests/contracts/test_import_boundaries.py | Enforces one owner for direct local transports and proxy-bypass variables. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart LR L[Launcher] --> R[FCC health or catalog request] R --> D[Direct local opener] D --> F[FCC server] L --> E[Build child environment] E --> N[Merge FCC and loopback hosts into NO_PROXY] N --> C[Claude, Codex, or Pi] C -->|FCC-local traffic| F C -->|Other outbound traffic| P[Configured outbound proxy] ``` </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"}}}%% flowchart LR L[Launcher] --> R[FCC health or catalog request] R --> D[Direct local opener] D --> F[FCC server] L --> E[Build child environment] E --> N[Merge FCC and loopback hosts into NO_PROXY] N --> C[Claude, Codex, or Pi] C -->|FCC-local traffic| F C -->|Other outbound traffic| P[Configured outbound proxy] ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["Keep FCC-local traffic off outbound prox..."](https://github.com/alishahryar1/free-claude-code/commit/072cc4b7474c1b33bfc368d148da5c1aa24914b6) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45589926)</sub> <!-- /greptile_comment --> |
||
|
|
fe40548a30 |
Give Google reasoning controls one owner (#1211)
## Problem Gemini requests with FCC reasoning could send both `reasoning_effort` and `extra_body.google.thinking_config`, which [Google documents as mutually exclusive](https://ai.google.dev/gemini-api/docs/openai#thinking). Google reasoning and thought-signature postprocessing had overlapping request ownership. Fixes #1206. ## Changes | Before | After | | --- | --- | | Shared Google quirks injected thought output independently of the profile encoder. | One provider-selected Google encoder owns every reasoning wire field. | | Gemini could send named effort beside a custom thinking config. | Gemini selects one channel, with exact budgets taking precedence over named effort. | | Vertex reasoning and thought-signature behavior shared one quirks module. | Vertex retains its budget mapping while thought signatures have a separate owner. | | Caller-native Google controls could collide with FCC controls. | Native controls are preserved only under provider-default reasoning; controlled collisions fail preflight. | | Regression coverage inspected isolated body fragments. | Policy matrices, SDK-merge assertions, and an ownership contract enforce the final wire shape. | | The reported Gemini 3.5 Flash path failed upstream with HTTP 400. | The same live path streams to a normal terminal stop with one reasoning channel. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR gives each Google provider one owner for reasoning request fields. The main changes are: - Adds dedicated Gemini and Vertex reasoning encoders. - Separates thought-signature replay from reasoning serialization. - Validates caller-provided Google configuration before encoding. - Adds request-policy and final wire-shape tests. - Bumps the package version to 4.11.2. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. The request pipeline keeps thought signatures and reasoning fields separate. Tests cover the supported reasoning policies and caller configuration conflicts. <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** - The focused validation suite was executed and completed with 78 passed in 4.57s. - Before the change, adaptive/high emitted two channels: reasoning\_effort: high and thinking\_config.include\_thoughts: true. - After the change, the same request emits exactly one channel: reasoning\_effort: high, with thinking\_config: null. <a href="https://app.greptile.com/trex/runs/15056242/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 | |----------|----------| | src/free_claude_code/providers/google_openai/reasoning.py | Adds exclusive Gemini and Vertex reasoning encoders and validates caller-native thinking configuration. | | src/free_claude_code/providers/google_openai/provider.py | Separates message signature replay from profile-owned reasoning encoding. | | src/free_claude_code/providers/google_openai/thought_signatures.py | Narrows the former quirks module to tool-call thought-signature replay. | | src/free_claude_code/providers/gemini/client.py | Selects the Gemini encoder and enables validated extra-body forwarding. | | src/free_claude_code/providers/vertex/client.py | Selects the Vertex encoder while retaining budget-based reasoning controls. | | tests/providers/test_gemini.py | Covers channel exclusivity, budget precedence, native configuration, conflicts, and SDK merging. | | tests/providers/test_vertex.py | Covers Vertex policy mapping, native configuration, conflicts, and final wire shape. | | tests/contracts/test_import_boundaries.py | Enforces one source owner for Google reasoning wire fields. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A[Messages request] --> B[Resolve reasoning policy] A --> C[Validate and copy extra_body] B --> D{Google provider profile} C --> E[Build OpenAI request body] E --> F[Replay thought signatures] F --> D D -->|Gemini| G[Gemini reasoning encoder] D -->|Vertex| H[Vertex reasoning encoder] G --> I[One Gemini reasoning channel] H --> J[Google thinking configuration] I --> K[Final SDK request] J --> K ``` </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"}}}%% flowchart TD A[Messages request] --> B[Resolve reasoning policy] A --> C[Validate and copy extra_body] B --> D{Google provider profile} C --> E[Build OpenAI request body] E --> F[Replay thought signatures] F --> D D -->|Gemini| G[Gemini reasoning encoder] D -->|Vertex| H[Vertex reasoning encoder] G --> I[One Gemini reasoning channel] H --> J[Google thinking configuration] I --> K[Final SDK request] J --> K ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["Give Google reasoning controls one owner"](https://github.com/alishahryar1/free-claude-code/commit/cdfba8273878d5075ac8d6afb702e0f76224cba4) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45569811)</sub> <!-- /greptile_comment --> |
||
|
|
af12e7b2bb |
Coordinate provider recovery under concurrent load (#1205)
## Problem Concurrent transient failures could start independent retry, replay, continuation, and repair loops while holding provider concurrency slots. This multiplied upstream attempts and could delay or strand terminal errors under fan-out. ## Changes | Before | After | | --- | --- | | Retry paths owned separate attempt budgets. | One logical-execution session caps all upstream work at five attempts. | | Concurrent failures backed off independently. | One provider-owned recovery episode elects a single half-open probe while followers coalesce. | | Backoff occupied stream concurrency. | Concurrency is held only while an upstream operation or stream is active. | | Provider catalog calls and stream creation used separate admission paths. | Every upstream operation uses one provider-generation admission controller. | | Cancellation could leave recovery ownership or follower state unresolved. | Cancellation releases permits, transfers probe ownership, and unregisters waiting followers. | | Late in-flight failures could cross an exhausted episode boundary. | Every coalesced execution retains that generation's terminal outcome. | | Replay tests allowed loose lifecycle assertions. | Exact SSE contracts prove retries and continuations emit one unduplicated response. | | Recovery wrappers could mask final diagnostics. | Final responses and traces retain the raw provider failure and request ID. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR coordinates provider recovery and retry work under concurrent load. The main changes are: - One five-attempt budget for each logical execution. - Provider-wide recovery episodes with one elected probe. - Shared admission for streams, catalog calls, rate limits, and concurrency. - Concurrency permits held only during active upstream work. - Cancellation-safe probe ownership and preserved final diagnostics. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. <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** - Reviewed the coordinated-recovery-01-before.log to understand how the exhausted generation outcome was not preserved in a late in-flight failure. - Reviewed the coordinated-recovery-02-after.log to confirm that the updated implementation preserves the exhausted generation outcome for the same focused contract set. - Validated that the provider-admission-full-current.log shows the complete requested test file passed under Python 3.14 with uv run pytest -n 0. <a href="https://app.greptile.com/trex/runs/15050270/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 | |----------|----------| | src/free_claude_code/providers/admission.py | Adds shared admission, retry budgets, recovery episodes, probe election, and cancellation handling. | | src/free_claude_code/providers/openai_chat/provider.py | Moves stream creation, replay, continuation, and repair onto one admission-owned retry session. | | src/free_claude_code/providers/stream_recovery.py | Selects replay, continuation, repair, or final failure using the remaining shared attempt budget. | | src/free_claude_code/providers/failure_policy.py | Adds recovery exhaustion handling and preserves the underlying provider error for final classification. | | src/free_claude_code/providers/runtime/factory.py | Creates one admission controller per provider generation and passes it through provider factories. | </details> <details open><summary><h3>Sequence Diagram</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% sequenceDiagram participant E as Execution participant A as Admission controller participant P as Provider participant F as Concurrent follower E->>A: Open attempt A->>P: Send upstream request P-->>E: Retryable failure E->>A: Open recovery episode F->>A: Request admission A-->>F: Coalesce and wait E->>A: Claim probe A->>P: Send half-open probe alt Probe succeeds P-->>E: Valid response E->>A: Close recovery episode A-->>F: Release waiter else Probe fails P-->>E: Retryable failure E->>A: Schedule next probe or finalize error end ``` </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 E as Execution participant A as Admission controller participant P as Provider participant F as Concurrent follower E->>A: Open attempt A->>P: Send upstream request P-->>E: Retryable failure E->>A: Open recovery episode F->>A: Request admission A-->>F: Coalesce and wait E->>A: Claim probe A->>P: Send half-open probe alt Probe succeeds P-->>E: Valid response E->>A: Close recovery episode A-->>F: Release waiter else Probe fails P-->>E: Retryable failure E->>A: Schedule next probe or finalize error end ``` </a> </details> <sub>Reviews (2): Last reviewed commit: ["Harden coordinated retry lifecycle invar..."](https://github.com/alishahryar1/free-claude-code/commit/2e871c8649d148b5eb71d21f80bf870ae2d11708) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45554917)</sub> <!-- /greptile_comment --> |
||
|
|
a0f62c598c |
Add Google Vertex AI with renewable ADC (#1193)
## Problem | Before | After | | --- | --- | | FCC supported Google AI Studio API keys but could not route coding agents through a Google Cloud Vertex AI project. | `vertex/...` routes through Google's [documented OpenAI-compatible Chat Completions endpoint](https://cloud.google.com/vertex-ai/generative-ai/docs/start/openai), using the global endpoint by default or an explicitly configured region. | | A pasted Vertex access token would expire, while Application Default Credentials were not part of provider construction. | FCC loads [Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials), supplies a renewable credential callback to the OpenAI transport, coalesces concurrent refreshes, and returns typed authentication or transient failures. | | Vertex does not expose its model catalog through the compatible OpenAI `/models` route. | FCC translates its generic discovery operation to Google's paginated [publisher-model list API](https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/publishers.models/list) and converts resource names into the model IDs accepted by Chat Completions. | | Google thought signatures were owned by the AI Studio adapter even though Vertex shares the same protocol behavior. | A neutral Google OpenAI family owns shared thought-signature and request behavior; AI Studio and Vertex retain separate endpoint and authentication ownership. | ## Changes - Added the Vertex provider, `VERTEX_PROJECT_ID`, optional `VERTEX_LOCATION` and `VERTEX_PROXY`, Admin UI configuration, model-picker discovery, smoke metadata, and customer setup documentation. - Added renewable ADC access tokens with refresh coalescing, proxy-aware refresh, sanitized failure classification, and project quota headers. - Added global/regional endpoint composition plus native model-catalog pagination, strict response validation, response cleanup, and repeated-page protection. - Generalized provider readiness around declared configuration fields so project-based and multi-field providers no longer pretend every remote provider is configured by one API key. - Moved shared Google request quirks out of the Gemini adapter, preserved AI Studio behavior, and bumped the package to `4.11.0`. <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR adds Google Vertex AI as a new provider using Application Default Credentials. The main changes are: - New `vertex` provider with project/location endpoint construction. - Renewable ADC access-token loading with refresh coalescing and proxy-aware refresh. - Native Vertex publisher-model discovery with pagination and response validation. - Shared Google OpenAI-compatible request behavior for Gemini and Vertex. - Admin UI, settings, smoke config, docs, version, lockfile, and tests for the new provider. </details> <h3>Confidence Score: 5/5</h3> Safe to merge with low risk. No blocking correctness or security issues were identified. The new provider follows the existing provider-runtime and Admin configuration patterns. Endpoint, auth, model parsing, readiness, docs, version, lockfile, and tests are updated together. 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** - The T-Rex test suite was executed to validate the code-execution proof-of-work, generating a full verbose pytest log and recording the run metadata, and the run completed with EXIT\_CODE: 0. <a href="https://app.greptile.com/trex/runs/14991235/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 | |----------|----------| | src/free_claude_code/providers/vertex/client.py | Adds the Vertex provider with OpenAI-compatible chat routing and native paginated model discovery. | | src/free_claude_code/providers/vertex/auth.py | Implements renewable ADC token loading, proxy-aware refresh, coalescing, and sanitized auth failures. | | src/free_claude_code/providers/vertex/endpoint.py | Builds validated Vertex global/regional service, chat, and model-list endpoints. | | src/free_claude_code/providers/vertex/models.py | Parses Vertex publisher-model pages into OpenAI-compatible model IDs with malformed-response checks. | | src/free_claude_code/providers/google_openai/provider.py | Adds shared Google thought-signature caching and thinking-budget request body handling. | | src/free_claude_code/providers/google_openai/quirks.py | Renames Gemini-specific quirks to shared Google quirks and exposes model-neutral thinking config helpers. | | src/free_claude_code/providers/openai_chat/provider.py | Allows OpenAI-chat providers to pass an async API-key callback into the OpenAI SDK. | | src/free_claude_code/providers/runtime/discovery.py | Uses descriptor-defined readiness to choose providers eligible for model cache/discovery. | | src/free_claude_code/config/provider_catalog.py | Adds the Vertex descriptor and required settings metadata, and makes Cloudflare readiness require both token and account ID. | | src/free_claude_code/config/admin/status.py | Generalizes Admin provider readiness status to use each descriptor's configuration attributes. | | src/free_claude_code/config/admin/provider_manifest.py | Adds Admin UI fields for Vertex project and location alongside generated provider fields. | | tests/providers/test_vertex.py | Adds targeted tests for Vertex endpoints, ADC token refresh, reasoning mapping, and model discovery pagination. | </details> <details open><summary><h3>Sequence Diagram</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% sequenceDiagram participant User as User / Admin UI participant Settings as Settings + Provider Catalog participant Runtime as Provider Runtime participant Vertex as VertexProvider participant ADC as Google ADC participant OpenAI as OpenAI-compatible Chat Endpoint participant Models as Vertex Publisher Models API User->>Settings: Set VERTEX_PROJECT_ID / VERTEX_LOCATION / VERTEX_PROXY Settings->>Runtime: Descriptor reports vertex configured by project id Runtime->>Vertex: Construct with project, location, proxy, rate limiter Vertex->>ADC: Load/refresh Application Default Credentials ADC-->>Vertex: Renewable access token Vertex->>OpenAI: Stream chat completion with bearer token + x-goog-user-project OpenAI-->>Vertex: Streaming chat chunks Vertex-->>Runtime: Normalized provider stream Runtime->>Vertex: Refresh model list Vertex->>Models: GET paginated publishers/google/models Models-->>Vertex: publisherModels + nextPageToken Vertex-->>Runtime: Prefixed model IDs for cache/model picker ``` </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 User as User / Admin UI participant Settings as Settings + Provider Catalog participant Runtime as Provider Runtime participant Vertex as VertexProvider participant ADC as Google ADC participant OpenAI as OpenAI-compatible Chat Endpoint participant Models as Vertex Publisher Models API User->>Settings: Set VERTEX_PROJECT_ID / VERTEX_LOCATION / VERTEX_PROXY Settings->>Runtime: Descriptor reports vertex configured by project id Runtime->>Vertex: Construct with project, location, proxy, rate limiter Vertex->>ADC: Load/refresh Application Default Credentials ADC-->>Vertex: Renewable access token Vertex->>OpenAI: Stream chat completion with bearer token + x-goog-user-project OpenAI-->>Vertex: Streaming chat chunks Vertex-->>Runtime: Normalized provider stream Runtime->>Vertex: Refresh model list Vertex->>Models: GET paginated publishers/google/models Models-->>Vertex: publisherModels + nextPageToken Vertex-->>Runtime: Prefixed model IDs for cache/model picker ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["feat: add Google Vertex AI provider"](https://github.com/alishahryar1/free-claude-code/commit/97e753f0772e60377865876ca59b2fd8888d922e) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45405432)</sub> <!-- /greptile_comment --> |
||
|
|
af658287bd |
Add Amazon Bedrock Mantle support (#1192)
## Problem FCC cannot route coding-agent requests through Amazon Bedrock even though Bedrock Mantle exposes an OpenAI-compatible streaming Chat Completions API. Users currently need a separate compatibility layer, and FCC has no catalog, Admin UI, model-discovery, or smoke-test contract for Bedrock. Fixes #863. ## Changes | Before | After | | --- | --- | | Amazon Bedrock was absent from provider routing. | `bedrock/` uses the existing OpenAI Chat provider with AWS's [Bedrock Mantle endpoint](https://docs.aws.amazon.com/bedrock/latest/userguide/inference-chat-completions-mantle.html). | | Bedrock integration would have implied a new AWS-native transport. | The ordinary profile owns streaming, tools, retries, and `/models` discovery without boto3, SigV4, Converse, or Invoke machinery. | | FCC had no Bedrock authentication or regional endpoint configuration. | `AWS_BEARER_TOKEN_BEDROCK`, `BEDROCK_BASE_URL`, and `BEDROCK_PROXY` are available through environment and Admin UI configuration, with the current `us-east-1` Mantle URL as the default. | | Heterogeneous Bedrock models had no safe provider-wide reasoning control. | FCC replays prior reasoning through portable think tags and leaves model-specific reasoning parameters upstream-owned. | | Smoke configuration duplicated credential checks for every provider. | Smoke configuration reads primary credentials and configurable endpoints from the provider catalog, retaining only Cloudflare's two-field exception. | | Bedrock behavior had no deterministic coverage or release documentation. | Provider requests, regional URL normalization, model discovery, Admin persistence, smoke selection, README usage, architecture boundaries, and version 4.10.0 cover the new capability. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR adds Amazon Bedrock Mantle as an OpenAI-compatible provider. The main changes are: - Bedrock catalog, settings, proxy, and regional base-URL configuration. - OpenAI Chat routing with portable reasoning replay and model discovery. - Admin UI fields and configuration persistence. - Catalog-driven smoke configuration and Bedrock smoke coverage. - Provider documentation and a version bump to 4.10.0. </details> <h3>Confidence Score: 5/5</h3> The provider flow looks mergeable after handling an explicitly empty Bedrock base URL. Catalog, runtime, Admin, and smoke wiring are consistent. Regional URLs with or without `/v1` are normalized correctly. src/free_claude_code/config/settings.py: an empty `BEDROCK_BASE_URL` can still create a client with an invalid endpoint. <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** - Before the change, bedrock was rejected as an unknown provider with exit code 1. - After the change, the fake service captured the normalized URL, Bearer trex...oken, portable Chat Completions JSON, one tool, think-tag history, and no reasoning\_effort, reasoning, or thinking fields; exit code 0. - Focused pytest validation completed with 6/6 passing tests. <a href="https://app.greptile.com/trex/runs/14988686/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 | |----------|----------| | src/free_claude_code/config/provider_catalog.py | Adds the Bedrock provider descriptor, regional default endpoint, credential mapping, and proxy metadata. | | src/free_claude_code/config/settings.py | Adds Bedrock settings, but an explicitly empty base URL bypasses the regional default. | | src/free_claude_code/providers/openai_chat/profiles.py | Registers Bedrock with URL normalization, think-tag replay, and no provider-wide reasoning parameter. | | src/free_claude_code/config/admin/provider_manifest.py | Generalizes provider base-URL fields and adds Bedrock-specific labels and help text. | | smoke/lib/config.py | Adds Bedrock smoke defaults and replaces provider-specific checks with catalog-driven configuration checks. | | tests/providers/test_bedrock.py | Covers Bedrock URL normalization, request fields, reasoning replay, tool calls, and model discovery. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart LR Config[Environment or Admin config] --> Settings[Settings] Catalog[Provider catalog] --> Runtime[Provider runtime] Settings --> Runtime Runtime --> Profile[Bedrock OpenAI Chat profile] Profile --> Client[AsyncOpenAI client] Client --> Mantle[Regional Bedrock Mantle endpoint] Catalog --> Admin[Admin manifest] Catalog --> Smoke[Smoke selection] ``` </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"}}}%% flowchart LR Config[Environment or Admin config] --> Settings[Settings] Catalog[Provider catalog] --> Runtime[Provider runtime] Settings --> Runtime Runtime --> Profile[Bedrock OpenAI Chat profile] Profile --> Client[AsyncOpenAI client] Client --> Mantle[Regional Bedrock Mantle endpoint] Catalog --> Admin[Admin manifest] Catalog --> Smoke[Smoke selection] ``` </a> </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fadd-bedrock-mantle%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fadd-bedrock-mantle%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fconfig%2Fsettings.py%3A60-63%0A**Empty%20Override%20Bypasses%20Default%20URL**%0A%0AWhen%20%60BEDROCK_BASE_URL%60%20is%20present%20but%20empty%2C%20settings%20keep%20the%20empty%20string%20instead%20of%20using%20%60BEDROCK_DEFAULT_BASE%60.%20Clearing%20this%20field%20through%20environment%20or%20Admin%20configuration%20therefore%20builds%20the%20Bedrock%20client%20with%20an%20invalid%20base%20URL%2C%20and%20Bedrock%20requests%20and%20model%20discovery%20fail%20instead%20of%20using%20the%20documented%20default.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1192&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["Add Amazon Bedrock Mantle provider"](https://github.com/alishahryar1/free-claude-code/commit/f40b539c99c9f6a888762b8da69d5a738a4f4d70) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45400300)</sub> > Greptile also left **1 inline comment** on this PR. <!-- /greptile_comment --> |
||
|
|
b89e849fff |
Add Kimi Code subscription support (#1183)
## Problem FCC's existing `kimi` provider targets Kimi Open Platform credits. Kimi Code subscription keys use a separate coding-agent endpoint, so subscribers cannot currently use their plan or select its K3 and coding models. Fixes #1161. ## Changes | Before | After | | --- | --- | | `KIMI_API_KEY` was the only Kimi contract and routed to the credit-based API platform. | `KIMI_API_KEY` remains unchanged, while `KIMI_CODE_API_KEY` routes the separate [Kimi Code subscription](https://www.kimi.com/code/docs/en/) through `https://api.kimi.com/coding/v1`. | | OpenAI-chat profiles could not declare an upstream client identity. | The Kimi Code profile sends an honest `free-claude-code` user agent as required by [Kimi's integration policy](https://www.kimi.com/code/docs/en/kimi-code/community-guidelines.html), without adding a specialized provider class. | | FCC's fallback output limit and generic token field would override Kimi's default when the client omitted a limit. | Explicit client limits become `max_completion_tokens`; omitted limits remain upstream-owned, and learned cap recovery still handles model-specific rejections. | | Kimi Code reasoning and history had no provider contract. | The profile maps FCC intent to Kimi's documented `low`, `high`, `max`, and `none` efforts and replays prior thinking through `reasoning_content`, with no model-name branching. | | Admin, model discovery, and smoke coverage knew only the credit-based Kimi provider. | Catalog-derived Admin fields, `/models` discovery, README setup, smoke configuration, and deterministic provider/runtime contracts cover `kimi_code`; the release is bumped to 4.9.0. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR adds Kimi Code subscription support as a separate provider. The main changes are: - Adds dedicated API key, proxy, endpoint, and Admin settings. - Adds Kimi-specific reasoning, token-limit, history, and user-agent behavior. - Extends model discovery and smoke configuration for `kimi_code`. - Adds provider contract tests and updates documentation. - Bumps the package and lockfile version to 4.9.0. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. <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** - The contract validation compared the Kimi code HTTP flow before and after the change and confirmed the after state exits with code 0 and includes Bearer authentication, User-Agent: free-claude-code, model discovery, max\_completion\_tokens, Kimi reasoning effort max, reasoning\_content replay, and omission of token/reasoning fields when unspecified. - Focused tests for the Kimi code HTTP flow were run, and 88 tests passed with exit code 0. - Artifacts document both the initial failure scenario and the successful post-change state, along with the focused tests results. <a href="https://app.greptile.com/trex/runs/14945625/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 | |----------|----------| | src/free_claude_code/config/provider_catalog.py | Registers Kimi Code with its dedicated credential, endpoint, and proxy setting. | | src/free_claude_code/config/settings.py | Adds environment-backed fields for the Kimi Code subscription key and proxy. | | src/free_claude_code/providers/openai_chat/__init__.py | Passes an optional profile user agent into the shared OpenAI-compatible client. | | src/free_claude_code/providers/openai_chat/profiles.py | Defines Kimi Code reasoning, token-limit, history replay, extra-body, and user-agent behavior. | | smoke/lib/config.py | Adds Kimi Code configuration detection and its default smoke model. | | tests/providers/test_kimi_code.py | Covers the new endpoint, headers, request mapping, reasoning behavior, and model discovery. | </details> <sub>Reviews (1): Last reviewed commit: ["Add Kimi Code subscription provider"](https://github.com/alishahryar1/free-claude-code/commit/dfc66f2755e5885775a77f5c91b4b9a82eb8fd1d) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45309322)</sub> <!-- /greptile_comment --> |
||
|
|
ac2ccbdd16 |
Report output-limit truncation as incomplete Responses (#1180)
## Problem Responses streams discarded the canonical Anthropic `max_tokens` stop reason and emitted `response.completed`. Codex therefore treated truncated provider output as a successful end and could stop midway without explaining why. Fixes #1178. ## Changes | Before | After | | --- | --- | | The Responses boundary discarded `message_delta.stop_reason`. | The Responses assembler retains the canonical terminal stop reason. | | Output-limit streams ended with `response.completed`. | Output-limit streams end with `response.incomplete` and `incomplete_details.reason=max_output_tokens`. | | Truncated output had no dedicated Responses contract coverage. | Core and API tests cover partial-output and zero-visible-output truncation while preserving response ID and usage. | | The package version was `4.8.6`. | The patch release is `4.8.7`. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR reports Anthropic output-limit termination as an incomplete Responses result. The main changes are: - Retains the canonical `message_delta.stop_reason` until stream finalization. - Emits `response.incomplete` with `max_output_tokens` details for `max_tokens` termination. - Preserves partial output, usage, and response identity. - Adds core and API tests for visible and empty truncated output. - Updates the package and lockfile version to 4.8.7. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. Terminal failure handling still takes precedence over incomplete completion. Tests cover both partial-output and zero-visible-output truncation. <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** - Validated that after the change, both requests end with response.incomplete instead of response.completed. - Observed that partial output remains as 3/4/7 and zero-visible output remains as 3/64/67, confirming the output retention behavior after the change. - Confirmed that created and terminal response IDs match in every after-change case. - Reviewed the Python contract-validation artifact to support the conclusions. <a href="https://app.greptile.com/trex/runs/14931704/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 | |----------|----------| | src/free_claude_code/core/openai_responses/streaming/assembler.py | Retains the provider stop reason and emits an incomplete terminal response when output reaches the token limit. | | src/free_claude_code/core/openai_responses/streaming/event_builders.py | Adds the Responses SSE envelope for `response.incomplete`. | | tests/core/openai_responses/test_sse.py | Covers truncated streams with partial output and no visible output. | | tests/api/test_openai_responses.py | Covers output-limit reporting through the public Responses API route. | | pyproject.toml | Bumps the package patch version to 4.8.7. | | uv.lock | Synchronizes the locked editable package version. | </details> <sub>Reviews (1): Last reviewed commit: ["Fix Responses output-limit terminal stat..."](https://github.com/alishahryar1/free-claude-code/commit/d41767572b0820481e3e7555c5b361b184c139c0) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45277818)</sub> <!-- /greptile_comment --> |
||
|
|
65a342ede4 |
Honor reasoning tiers on numeric-budget providers (#1150)
## Problem FCC preserved named reasoning effort but numeric-budget providers received no intensity unless a client supplied an exact token budget. NIM and llama.cpp therefore treated Low through Max like the same provider default. ## Changes | Before | After | | --- | --- | | Named effort had no FCC-owned numeric meaning. | FCC maps Low, Medium, High, X-High, and Max to 512, 1,024, 2,048, 4,096, and 8,192 tokens. | | NIM received only thinking booleans for named effort. | [NIM](https://docs.nvidia.com/nim/large-language-models/1.15.0/thinking-budget-control.html) receives thinking booleans plus the mapped `reasoning_budget`, retaining its existing retry without rejected budget control. | | llama.cpp forwarded only exact client budgets. | [llama.cpp](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md) receives the mapped `thinking_budget_tokens` value. | | Named, boolean, and provider-default adapters shared no explicit numeric contract. | Named adapters keep words, boolean adapters keep on/off, and only numeric-budget adapters consume the FCC scale. | | Documentation prohibited every named-effort budget conversion. | Documentation defines the product scale, exact-budget precedence, and model-independent ownership boundary. | | Version 4.8.0 exposed tiers that collapsed on numeric providers. | Version 4.8.1 completes the tiers; all five local CI checks pass with 2,383 tests passed and 40 skipped. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR gives named reasoning tiers numeric budgets for providers that require token counts. The main changes are: - Adds one shared tier-to-token scale with exact-budget precedence. - Sends mapped budgets to NVIDIA NIM and llama.cpp. - Removes conflicting client-supplied NIM budget fields. - Adds focused provider and policy tests. - Updates documentation and bumps the package to 4.8.1. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. The NIM fix removes both conflicting budget locations while preserving unrelated nested options. No blocking issue remains in the changed paths. <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** - T-Rex ran a pre-change focused validation against the budget logic and observed 16 failures and 2 passes, establishing the baseline. - T-Rex ran a post-change focused validation (head run) and confirmed all 18 cases passed, including the mocked NIM retry paths. - T-Rex executed the full focused validation after the change and produced a verbose log showing 91/91 passing. <a href="https://app.greptile.com/trex/runs/14800553/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 | |----------|----------| | src/free_claude_code/core/reasoning.py | Adds the shared effort-to-token scale and preserves exact client budgets as the higher-priority value. | | src/free_claude_code/providers/nvidia_nim/request_options.py | Removes top-level and nested client budgets before inserting one policy-derived NIM budget. | | src/free_claude_code/providers/openai_chat/reasoning.py | Extends llama.cpp request encoding to send mapped named-effort budgets. | </details> <sub>Reviews (2): Last reviewed commit: ["fix: canonicalize NIM reasoning budgets"](https://github.com/alishahryar1/free-claude-code/commit/368f1a88d3f1404fcab2365703cca89f1077f1ea) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=44998377)</sub> <!-- /greptile_comment --> |
||
|
|
0de7608b52 |
Keep inline system reminders cache-stable across providers (#1154)
## Problem Inline Anthropic system reminders were forwarded as mid-conversation OpenAI system roles. Compatible provider chat templates could reposition those roles, changing prior prompt tokens and causing periodic full cache misses. Fixes #1152. ## Changes | Before | After | | --- | --- | | Top-level and inline system content both used downstream system roles. | Only top-level system content uses the leading downstream system role. | | Inline system reminders could trigger provider-side prompt retemplating. | Inline system reminders keep their text and position as downstream user messages. | | Provider policies could reinterpret the shared role mapping. | Shared conversion owns one provider-independent role mapping. | | Cache-prefix coverage allowed mid-conversation system roles. | Cache-prefix coverage requires append-only user-encoded reminders. | | The package version was 4.8.0. | The package version is 4.8.1. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR keeps inline system reminders stable across OpenAI-compatible providers. The main changes are: - Maps only the top-level system prompt to the downstream system role. - Encodes inline system reminders as ordered user content. - Coalesces adjacent user messages after transcript ordering. - Adds tests for text, multimodal content, cache-prefix stability, and tool-result ordering. - Updates the architecture notes and bumps the package to 4.8.1. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. Adjacent user messages are combined after assistant and tool dependencies are ordered. Multimodal content keeps its part order. No blocking issues were found in the changed code. <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** - Before capture, the converted prefix roles were shown as system, user, and assistant. - After capture, the same prefix appeared, followed by a user continuation containing a second question and a system-reminder tag; all runtime assertions passed. - The preserved harness documents and reproduces the public-builder validation. <a href="https://app.greptile.com/trex/runs/14803290/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 | |----------|----------| | src/free_claude_code/core/anthropic/conversion.py | Maps inline system reminders to user content and coalesces adjacent user messages after transcript ordering. | | tests/providers/test_converter.py | Adds tests for inline reminders, multimodal content, cache-prefix stability, and tool-result ordering. | | ARCHITECTURE.md | Documents the shared role-mapping and adjacent-user coalescing rules. | | pyproject.toml | Bumps the package version to 4.8.1. | | uv.lock | Synchronizes the locked editable package version with 4.8.1. | </details> <sub>Reviews (2): Last reviewed commit: ["fix: coalesce adjacent provider user tur..."](https://github.com/alishahryar1/free-claude-code/commit/7af6327c79fa15c0f4922bad8864f1c6656b2814) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=45005803)</sub> <!-- /greptile_comment --> |
||
|
|
6455c63e1d |
Make reasoning policy provider-neutral and client-aware (#1148)
## Problem FCC reduced reasoning to global and route booleans, mixing client intent, configuration, provider wire capabilities, output visibility, and history replay. That discarded named client efforts, encouraged model-name checks, and made provider behavior inconsistent. ## Changes | Before | After | | --- | --- | | Admin exposed global and route thinking toggles. | Admin exposes **Off**, **From client**, **Low**, **Medium**, **High**, **X-High**, and **Max**; Fable, Opus, Sonnet, and Haiku also expose **Inherit**. | | Request intent was repeatedly reduced to a boolean across routing and providers. | The application boundary resolves one immutable `ReasoningPolicy` with independent control, named effort, and exact positive token budget. | | Provider adapters could infer reasoning behavior from upstream model names or versions. | Provider profiles translate only documented provider-wide wire capabilities; architecture and contributor rules prohibit model-specific reasoning branches. | | Gateway reasoning controls were ad hoc. | [OpenRouter](https://openrouter.ai/docs/guides/best-practices/reasoning-tokens) and [Vercel AI Gateway](https://vercel.com/docs/ai-gateway/models-and-providers) use documented reasoning objects, including exact budgets where representable. | | Named effort forwarding was inconsistent or absent. | [Gemini](https://ai.google.dev/gemini-api/docs/openai), [Ollama](https://docs.ollama.com/api/openai-compatibility), [LM Studio](https://lmstudio.ai/changelog/lmstudio-v0.4.8), [Fireworks](https://docs.fireworks.ai/guides/querying-text-models/reasoning), [Cohere](https://docs.cohere.com/docs/compatibility-api), [Wafer](https://docs.wafer.ai/serverless/api-reference), [Groq](https://console.groq.com/docs/reasoning), [Cerebras](https://inference-docs.cerebras.ai/capabilities/reasoning), [SambaNova](https://docs.sambanova.ai/docs/api-reference/chat-completions/create-chat-based-completion), and [Mistral](https://docs.mistral.ai/studio-api/conversations/reasoning) receive their documented named vocabularies with explicit provider-owned downgrades. | | Boolean thinking controls were mixed into shared conversion. | [DeepSeek](https://api-docs.deepseek.com/guides/thinking_mode/), [Kimi](https://platform.kimi.ai/docs/guide/use-kimi-k2-thinking-model), [Z.ai](https://docs.z.ai/guides/capabilities/thinking-mode), [Cloudflare Workers AI](https://developers.cloudflare.com/changelog/post/2026-04-20-kimi-k2-6-workers-ai/), and [NVIDIA NIM](https://docs.nvidia.com/nim/large-language-models/1.15.0/thinking-budget-control.html) use provider-owned thinking-object or chat-template controls. | | Effort names and output limits could become fabricated reasoning budgets. | Exact budgets remain exact and are forwarded only through documented fields for OpenRouter, Fireworks, LM Studio, NIM, and [llama.cpp](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md); named efforts and output limits are never converted into token budgets. | | New-turn reasoning and prior-turn replay shared one switch. | Every profile independently declares native reasoning replay, `<think>` tag replay, provider-specific replay, or no replay; **Off** suppresses new reasoning output without corrupting required history. | | Providers without a stable generic compute control received guessed controls. | [MiniMax](https://platform.minimax.io/docs/api-reference/text-openai-api) requests split output only, while [GitHub Models](https://docs.github.com/en/rest/models/inference), [Hugging Face Inference Providers](https://huggingface.co/docs/inference-providers/en/tasks/chat-completion), Codestral, and OpenCode keep provider defaults and use only their explicit replay profile. | | OpenAI Responses effort became a lossy Anthropic thinking boolean. | Responses preserves `reasoning.effort` through `output_config`, then resolves it through the same application policy as Messages without inventing a budget. | | Legacy booleans remained the persisted contract. | FCC-owned dotenv files migrate to typed `REASONING_*` values, explicit env files receive an actionable warning, documentation describes the ownership boundary, and the package advances to 4.8.0. | | Reasoning behavior was covered by scattered boolean assertions. | New policy, routing, encoder, provider, Admin, migration, Responses, and smoke contracts pass all five local CI checks: 2,368 tests passed, 40 skipped; 92 smoke tests collect and both live config migration checks pass. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes reasoning policy client-aware and independent of provider model names. The main changes are: - Adds one immutable reasoning policy resolved at the application boundary. - Adds typed root and route reasoning settings with Admin UI support. - Moves wire controls and history replay behavior into provider profiles. - Migrates owned dotenv files from legacy thinking booleans. - Expands provider, routing, migration, API, and smoke coverage. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. <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 contract-validation test suite with the specified test modules, and the tests reported 78 passed in 1.53s with exit code 0. - Reviewed the complete captured output artifact reasoning-contract-02-after.log to verify the final test outcomes and successful contract validation. <a href="https://app.greptile.com/trex/runs/14792858/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 | |----------|----------| | src/free_claude_code/config/env_migrations.py | Migrates legacy reasoning booleans in owned dotenv files and warns for explicit environment files. | | src/free_claude_code/application/reasoning.py | Resolves client controls and configured preferences into one provider-neutral reasoning policy. | | src/free_claude_code/application/routing.py | Carries route-level reasoning preferences into request-scoped policy resolution. | | src/free_claude_code/providers/openai_chat/reasoning.py | Provides shared provider encoders for reasoning controls and replay behavior. | </details> <sub>Reviews (2): Last reviewed commit: ["chore: release reasoning controls as 4.8..."](https://github.com/alishahryar1/free-claude-code/commit/9d4be767f7dbdca5709474012f43dcdc6f4347e3) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=44984039)</sub> <!-- /greptile_comment --> |
||
|
|
f77fe8581c |
Add LOG_LEVEL env var to control log verbosity (#1142)
## Problem The server always writes DEBUG logs, producing detailed request traces customers rarely need and allowing rotated files to accumulate without a retention cap. Supervised restarts also need to apply changed logging settings consistently. Closes #1141. ## Changes | Before | After | | --- | --- | | The file sink always starts at `DEBUG`. | `LOG_LEVEL` supports `DEBUG`, `INFO`, `WARNING`, `ERROR`, and `CRITICAL`, with a customer-friendly `INFO` default. | | Structured request traces are emitted at `INFO`. | Structured request traces are emitted at `DEBUG` and remain available for opt-in diagnostics. | | Logs rotate at 50 MB without a retention limit. | Logs retain five rotated files, bounding normal usage to roughly 300 MB including the active file. | | Supervised restarts can keep stale sink and third-party logger levels. | Supervised restarts replace the sink or third-party levels only when their effective settings change. | | The package version is `4.7.2`. | The package version is `4.7.3`. | <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR adds configurable file-log verbosity and improves logging behavior across supervised restarts. The main changes are: - Adds a validated `LOG_LEVEL` setting with an `INFO` default. - Moves structured request traces from `INFO` to `DEBUG`. - Retains five rotated log files. - Replaces the file sink when its normalized path or level changes. - Updates third-party logger levels when verbose logging changes. - Bumps the package version to `4.7.3`. <h3>Confidence Score: 5/5</h3> This looks safe to merge. The supervised restart path now replaces the sink when its normalized path or level changes. Verbosity-only changes update third-party logger levels without replacing the file sink. No blocking issues were found in the changed code. <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** - T-Rex captured the baseline parent-revision import failure in runtime-logging-01-before.log. - T-Rex re-created the virtual environment for the current revision and captured runtime-logging-02-after.log, which shows the same import failure after uv reinstallation. - T-Rex verified the uv-managed Python 3.14 environment exists but cannot import loguru, as shown in runtime-logging-environment-blocker.log. - Artifacts corresponding to the three runtime-logging logs and the Python artifact were prepared for review. <a href="https://app.greptile.com/trex/runs/14767708/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> <h3>Important Files Changed</h3> | Filename | Overview | |----------|----------| | src/free_claude_code/config/logging_config.py | Tracks the active sink path, level, verbosity, and identifier so supervised restarts apply changed logging settings. | | src/free_claude_code/config/settings.py | Adds and validates the `LOG_LEVEL` environment setting. | | src/free_claude_code/runtime/bootstrap.py | Passes the configured log level and third-party verbosity into logging setup. | | src/free_claude_code/core/trace.py | Emits structured request traces at `DEBUG` instead of `INFO`. | | tests/config/test_logging_config.py | Covers path, level, and verbosity changes along with default filtering and retention. | <sub>Reviews (6): Last reviewed commit: ["Make customer logging configurable and s..."](https://github.com/alishahryar1/free-claude-code/commit/0cae08607ee8b92a51b5094de9e01cc89478dbfd) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=44854591)</sub> <!-- /greptile_comment --> --------- Co-authored-by: Alishahryar1 <alishahryar2@gmail.com> |
||
|
|
8d7f560589 |
Preserve DeepSeek cache prefixes across tool turns (#1126)
## Problem DeepSeek cache accounting was restored, but a later tool turn could still make FCC rewrite older assistant history. That prevented FCC from guaranteeing the identical serialized prefix required for cache reuse and left the remaining behavior in #904 unresolved. ## Changes | Before | After | | --- | --- | | Non-tool reasoning was replayed until a later tool fallback removed it. | Non-tool reasoning is omitted consistently from its first history serialization. | | Current-generation thinking controlled all historical reasoning replay. | Required tool-call reasoning is replayed independently of current-generation thinking. | | One replayable tool turn made the entire tool history appear safe. | Every tool-call turn must have replayable reasoning before thinking remains enabled. | | Prefix behavior was not verified after SDK request serialization. | DeepSeek tests capture final SDK JSON and require an exact append-only message prefix. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR preserves DeepSeek cache prefixes while retaining required tool-call reasoning. The main changes are: - Omits non-tool reasoning from its first history serialization. - Replays tool-call reasoning independently of current thinking mode. - Disables thinking unless every historical tool call has replayable reasoning. - Tests the final SDK-serialized message prefix. - Bumps the package patch version and updates the lockfile. </details> <h3>Confidence Score: 4/5</h3> The reasoning-only assistant path needs a fix before merging. The main prefix-preservation flow is covered at the SDK wire boundary. Filtering a `redacted_thinking`-only turn emits empty assistant content instead of the converter's non-empty sentinel. Other request-policy callers retain their previous behavior. src/free_claude_code/providers/deepseek/compat.py <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** - T-Rex executed the requested verification of the code base. - T-Rex ran the focused test wire\_messages\_keep\_prefix\_across\_tool\_thinking\_fallback with pytest; the exact command and harness are captured in the log, and the test completed with exit code 0. <a href="https://app.greptile.com/trex/runs/14533439/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 | |----------|----------| | src/free_claude_code/providers/deepseek/compat.py | Separates historical tool reasoning from current thinking, but can serialize an empty assistant message after filtering. | | src/free_claude_code/providers/openai_chat/request_policy.py | Adds an optional reasoning-history switch while preserving existing defaults for other callers. | | tests/providers/test_deepseek.py | Adds SDK wire-format tests for stable prefixes and independent tool-reasoning replay. | | pyproject.toml | Bumps the package patch version to 4.6.4. | | uv.lock | Synchronizes the editable package version with the project metadata. | | ARCHITECTURE.md | Documents DeepSeek's per-turn reasoning replay and append-only prefix behavior. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart LR A[Anthropic history] --> B[Classify tool-call reasoning] B --> C[Sanitize assistant history] C --> D[Convert to OpenAI messages] D --> E[Serialize through SDK] E --> F[DeepSeek request] B -->|Every tool call replayable| G[Keep current thinking] B -->|Any tool call not replayable| H[Disable current thinking] C -->|Tool-call turn| I[Retain reasoning] C -->|Non-tool turn| J[Omit reasoning] ``` </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"}}}%% flowchart LR A[Anthropic history] --> B[Classify tool-call reasoning] B --> C[Sanitize assistant history] C --> D[Convert to OpenAI messages] D --> E[Serialize through SDK] E --> F[DeepSeek request] B -->|Every tool call replayable| G[Keep current thinking] B -->|Any tool call not replayable| H[Disable current thinking] C -->|Tool-call turn| I[Retain reasoning] C -->|Non-tool turn| J[Omit reasoning] ``` </a> </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fdeepseek-cache-stable-history%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fdeepseek-cache-stable-history%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fproviders%2Fdeepseek%2Fcompat.py%3A146%0A**Empty%20Assistant%20Content%20Reaches%20Wire**%0A%0AWhen%20an%20assistant%20turn%20contains%20only%20%60redacted_thinking%60%2C%20filtering%20removes%20every%20block%20and%20replaces%20the%20list%20with%20%60%22%22%60.%20Revalidation%20then%20takes%20the%20string-content%20path%20and%20bypasses%20the%20converter's%20existing%20%60%22%20%22%60%20fallback%2C%20so%20DeepSeek%20can%20reject%20the%20continued%20conversation%20as%20an%20empty%20assistant%20message.%0A%0A%60%60%60suggestion%0A%20%20%20%20%20%20%20%20new_msg%5B%22content%22%5D%20%3D%20filtered%20or%20%22%20%22%0A%60%60%60%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1126&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["Preserve DeepSeek prompt cache prefixes"](https://github.com/alishahryar1/free-claude-code/commit/b07ecf28a193e9cff1624e4ef75f38344a146d49) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=44440120)</sub> > Greptile also left **1 inline comment** on this PR. <!-- /greptile_comment --> |
||
|
|
f0b31065ee |
Preserve mid-conversation system messages through provider conversion (#1125)
## Problem FCC hoisted inline Anthropic `system` messages into the top-level system prompt during request validation. Mid-conversation system messages are position-sensitive, so this applied later instructions retroactively, changed the existing prompt/cache prefix, and prevented provider conversion from seeing the original transcript. ## Changes - Preserve inline `system` messages, content, metadata, and ordering in Messages and token-count requests while keeping the top-level system prompt distinct. - Convert text-only inline system messages to OpenAI Chat `system` messages at the same transcript position; reject unrepresentable inline blocks before streaming instead of silently dropping them. - Remove the lossy normalization path and its unused role enum, and document protocol-model versus target-conversion ownership in `ARCHITECTURE.md`. - Cover API routing, model serialization, cache-prefix stability, text blocks, tool-result ordering, invalid content, and token counting; bump the package to `4.6.2`. - Verify all five local CI checks (2,287 tests) and the ordered transcript against NVIDIA NIM, OpenRouter, Gemini, DeepSeek, Mistral, and Hugging Face. <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR preserves inline Anthropic system messages through provider conversion. The main changes are: - Keeps top-level and inline system content separate and ordered. - Converts text-only inline system messages without moving them. - Rejects system blocks that OpenAI Chat cannot represent safely. - Updates request detection to ignore system context when counting user turns. - Adds serialization, routing, token-counting, and conversion coverage. - Updates the package version and architecture documentation. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. The leading-system detection path ignores system entries when counting user turns. Inline system content remains ordered for provider conversion. Unsupported system blocks fail explicitly instead of being dropped. No blocking issues were found in the changed code. No files require 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** - Validated that the transcript roles now follow the order user, assistant, system, user and that the top-level prompt remains separate. - Verified that inline system content is no longer counted in message tokens and that cache\_control metadata survives parsing. - Confirmed that the converted OpenAI transcript preserves position and cache prefix. - Observed that a system message following a tool result is converted as assistant, tool, system. - Ran the focused pytest and confirmed 209 passed in 2.82s with exit code 0. <a href="https://app.greptile.com/trex/runs/14526513/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 | |----------|----------| | src/free_claude_code/core/anthropic/models.py | Preserves system-role messages in the original transcript instead of hoisting them into the top-level prompt. | | src/free_claude_code/core/anthropic/conversion.py | Converts ordered text-only system messages and rejects unsupported system content before streaming. | | src/free_claude_code/api/detection.py | Builds a read-only semantic view of system context and conversational user turns for local request detection. | </details> <sub>Reviews (2): Last reviewed commit: ["Restore optimizations with inline system..."](https://github.com/alishahryar1/free-claude-code/commit/6605ede7f604053381552106489dbd16bcd37987) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=44423885)</sub> <!-- /greptile_comment --> |
||
|
|
b1877a4b21 |
Add Ollama Cloud as a first-class provider (#1106)
## Problem FCC supports Ollama only through a local daemon, so users cannot authenticate directly to Ollama Cloud or discover its hosted models from the Admin UI. Ollama's OpenAI-compatible API also uses the standard `reasoning` field instead of `reasoning_content`, which would otherwise drop thinking output and tool-history reasoning. ## Changes | Before | After | | --- | --- | | `ollama/...` requires a local Ollama server. | `ollama_cloud/...` connects directly to `https://ollama.com/v1` with `OLLAMA_API_KEY`, while local Ollama remains unchanged. | | OpenAI-chat reasoning was hard-coded to `reasoning_content`. | Provider profiles declare their reasoning field, so Ollama streams and replays `reasoning` without a specialized transport. | | Ollama Cloud was absent from configuration, model discovery, docs, and smoke coverage. | The catalog, Admin UI, proxy setting, model picker, README, smoke matrix, and `4.5.0` release metadata expose the provider consistently. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR adds Ollama Cloud as a separate OpenAI-compatible provider. The main changes are: - New `ollama_cloud` catalog entry, settings, admin fields, proxy setting, and smoke configuration. - Provider profiles now choose the streamed and replayed reasoning field per provider. - Ollama Cloud uses `reasoning` and `reasoning_effort`, while local Ollama stays on its separate local configuration. - Streaming recovery now respects the resolved thinking setting when collecting reasoning. - Tests, docs, environment examples, and release metadata were updated for the new provider. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. No files need 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 provider/runtime/converter/streaming tests with full verbose pytest output and confirmed EXIT\_CODE: 0. - Ran the config/catalog/contracts/admin tests with full verbose pytest output and confirmed EXIT\_CODE: 0. - Generated and ran an introspection script to verify catalog, profile, settings, and admin manifest values without external API calls, and recorded the local execution output. <a href="https://app.greptile.com/trex/runs/14367965/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 | |----------|----------| | src/free_claude_code/providers/openai_chat/profiles.py | Adds provider-level reasoning field selection and the Ollama Cloud profile. | | src/free_claude_code/providers/openai_chat/provider.py | Uses the profile reasoning field for streaming and passes the thinking setting into recovery. | | src/free_claude_code/providers/openai_chat/request_policy.py | Selects reasoning replay mode from the provider policy only when thinking is enabled. | | src/free_claude_code/core/anthropic/conversion.py | Supports replaying assistant reasoning through either `reasoning_content` or `reasoning`. | | src/free_claude_code/config/provider_catalog.py | Registers Ollama Cloud as a remote provider distinct from local Ollama. | | src/free_claude_code/config/settings.py | Adds the Ollama Cloud API key and proxy settings. | </details> <sub>Reviews (3): Last reviewed commit: ["Keep local Ollama wire behavior unchange..."](https://github.com/alishahryar1/free-claude-code/commit/d6f97cdb0074a4cbda140d484fb6dd679a1406df) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=44089262)</sub> <!-- /greptile_comment --> |
||
|
|
eb1b688c8c |
Default messaging sessions to Fable (#1100)
## Problem Discord and Telegram sessions remained pinned to Opus after Fable became a first-class routing tier. ## Changes | Before | After | | --- | --- | | Managed messaging launched Claude Code with `--model opus`. | Managed messaging launches Claude Code with `--model fable`. | | Phone sessions selected `MODEL_OPUS` or the `MODEL` fallback. | Phone sessions select `MODEL_FABLE` or the `MODEL` fallback. | | The architecture documented the Opus pin. | The architecture documents the Fable pin. | | FCC reported version `4.4.0`. | FCC reports version `4.4.1`. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR changes managed messaging sessions to use the Fable tier by default. The main changes are: - Managed Claude Code invocations now pass `--model fable`. - Managed messaging documentation now points to `MODEL_FABLE` and the `MODEL` fallback. - Tests now assert the managed tier default is `fable`. - The package version is bumped from `4.4.0` to `4.4.1` in both project metadata and the lockfile. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. No files need 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** - Validated that the focused PyTest run for Claude Fable version completed with EXIT\_CODE: 0, confirming the validation command produced a successful result. - Verified that the pytest node collection for the same validation scope finished with EXIT\_CODE: 0, confirming all intended tests were discovered. <a href="https://app.greptile.com/trex/runs/14345687/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 | |----------|----------| | src/free_claude_code/cli/managed/claude.py | Changes the managed Claude model tier constant from `opus` to `fable`. | | tests/cli/test_managed_claude.py | Adds coverage for the new managed tier default. | | ARCHITECTURE.md | Updates the managed messaging architecture notes for Fable routing. | | pyproject.toml | Bumps the package version to `4.4.1`. | | uv.lock | Updates the locked editable package version to `4.4.1`. | </details> <sub>Reviews (1): Last reviewed commit: ["Default messaging sessions to Fable"](https://github.com/alishahryar1/free-claude-code/commit/08772b5c9a8f2bba91eddb1f9599eef043bb4557) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=44041521)</sub> <!-- /greptile_comment --> |
||
|
|
4f56a6aa17 |
Add Fable as a first-class Claude routing tier (#1099)
## Problem Claude Code now sends `claude-fable-5` for the Fable alias, but FCC treated it as an unrecognized model and collapsed it into the global fallback route. Users could not map Fable traffic or reasoning behavior independently. Fixes #1097. ## Changes | Before | After | | --- | --- | | Fable requests inherited `MODEL` and `ENABLE_MODEL_THINKING`. | Fable requests use `MODEL_FABLE` and `ENABLE_FABLE_THINKING` when configured, otherwise inherit the existing defaults. | | `/v1/models` omitted Claude Fable 5. | `/v1/models` advertises the canonical `claude-fable-5` identifier. | | Admin, documentation, validation, and smoke contracts described three Claude tiers. | Admin, documentation, validation, and smoke contracts describe Fable alongside Opus, Sonnet, and Haiku. | | The package version was `4.3.1`. | The package version is `4.4.0`. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR adds Fable as a Claude routing tier. The main changes are: - `MODEL_FABLE` and `ENABLE_FABLE_THINKING` settings. - Fable routing and thinking resolution in `ModelRouter`. - `claude-fable-5` in the model catalog. - Admin, docs, smoke, and test coverage updates. - Package version bump to `4.4.0`. </details> <h3>Confidence Score: 4/5</h3> The changed routing path needs a fix for direct provider model ids containing `fable`. Fable settings, validation, admin fields, and model listing are consistent with the existing tier patterns. Blank Fable settings inherit the existing defaults. Direct provider model ids can receive the Fable thinking override when their model name contains `fable`. src/free_claude_code/application/routing.py <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** - Reproduced the Fable thinking overmatch by running a focused Python repro that disables global thinking and enables Fable thinking, then resolves sambanova/my-fable-ensemble-v2. - The repro confirmed direct routing preserved provider\_id=sambanova, provider\_model=my-fable-ensemble-v2, and provider\_model\_ref=sambanova/my-fable-ensemble-v2, with resolved\_thinking\_enabled and thinking\_enabled both true. - Ran the fable-tier validation pytest, which finished with exit code 0 and 177 tests passed. - Ran the runtime probe to exercise the API model list, Settings env parsing, and ModelRouter paths, and observed a 200 OK on GET /v1/models, with the catalog item id claude-fable-5 and the expected Fable vs global-default routing behavior. - Generated the probe source file used to exercise the API and Settings paths, enabling repeatable validation without real provider credentials. <a href="https://app.greptile.com/trex/runs/14275379/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 | |----------|----------| | src/free_claude_code/application/routing.py | Adds Fable model and thinking branches; the thinking branch can also match unrelated direct provider model ids containing `fable`. | | src/free_claude_code/config/settings.py | Adds optional Fable model and thinking settings with blank-env inheritance and provider/model validation. | | src/free_claude_code/config/model_refs.py | Includes Fable in configured chat model reference collection and dedupe. | | src/free_claude_code/config/admin/manifest.py | Adds Fable model and thinking controls to the admin manifest. | | src/free_claude_code/api/model_catalog.py | Adds `claude-fable-5` to the advertised Claude model aliases. | | pyproject.toml | Bumps the package version to `4.4.0`. | | uv.lock | Updates the editable package version to match `pyproject.toml`. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A[Incoming model name] --> B{Direct provider or gateway id?} B -- yes --> C[Use provider/model directly] C --> D[Resolve thinking from provider model string] B -- no --> E{Claude tier match} E -- Fable --> F[MODEL_FABLE or MODEL] E -- Opus/Sonnet/Haiku --> G[Tier override or MODEL] E -- None --> H[MODEL] D --> I[Provider request] F --> I G --> I H --> I ``` </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"}}}%% flowchart TD A[Incoming model name] --> B{Direct provider or gateway id?} B -- yes --> C[Use provider/model directly] C --> D[Resolve thinking from provider model string] B -- no --> E{Claude tier match} E -- Fable --> F[MODEL_FABLE or MODEL] E -- Opus/Sonnet/Haiku --> G[Tier override or MODEL] E -- None --> H[MODEL] D --> I[Provider request] F --> I G --> I H --> I ``` </a> </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fadd-fable-routing-tier%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fadd-fable-routing-tier%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fapplication%2Frouting.py%3A134-135%0A**Fable%20Thinking%20Overmatches%20Models**%0A%0AWhen%20a%20direct%20provider%20request%20uses%20a%20model%20id%20like%20%60sambanova%2Fmy-fable-ensemble-v2%60%2C%20the%20direct%20route%20bypasses%20tier%20remapping%20but%20still%20calls%20%60_resolve_thinking%28%29%60%20with%20the%20provider%20model%20string.%20With%20%60ENABLE_FABLE_THINKING%60%20set%2C%20this%20substring%20check%20applies%20Fable%20thinking%20behavior%20to%20an%20unrelated%20provider%20model%2C%20changing%20the%20outgoing%20request%20shape%20just%20because%20the%20model%20id%20contains%20%60fable%60.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1099&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["Add Fable as a first-class routing tier"](https://github.com/alishahryar1/free-claude-code/commit/0705840c65511fd85c74fd2c62ba8ea97afe7c12) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43892323)</sub> > Greptile also left **1 inline comment** on this PR. <!-- /greptile_comment --> |
||
|
|
984c4c23b7 |
Fix Auto Mode classifier responses when stream is omitted (#1098)
## Problem Claude Code Auto Mode classifier requests omit `stream`, which means they expect a non-streaming Messages response. FCC treated omission as streaming, returned SSE, and caused Claude to report the classifier model as temporarily unavailable. Fixes #1094. ## Changes | Before | After | | --- | --- | | Omitted `stream` defaulted to streaming SSE. | Omitted `stream` defaults to a complete JSON Message; only `stream: true` selects SSE. | | Classifier side queries received a body without top-level `usage`. | Classifier side queries receive a JSON Message with top-level `usage` while thinking remains disabled. | | Tests encoded FCC's nonstandard streaming default. | Model and HTTP-boundary tests enforce Anthropic's response-mode contract. | | The package version was 4.3.0. | The package version is 4.3.1. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR fixes Messages response mode handling when clients omit `stream`. The main changes are: - Defaulted Anthropic Messages requests to non-streaming JSON. - Returned SSE only when `stream: true` is set. - Updated classifier, handler, web-tool, and model tests for the new contract. - Documented the default response mode and bumped the package version. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge after deciding whether `stream: null` should remain accepted. The JSON-by-default Messages path is covered in the model, handler, and API tests. Explicit streaming still flows through the SSE path. Clients that send `stream: null` can now get a validation error instead of a response. <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 full test suite for the code under test; pytest completed with 132 tests passed in 2.96s and exited with code 0. - Validated the testclient probe non-stream request returned 200 OK with a JSON message. - Validated the testclient probe stream request returned 200 OK with a text/event-stream SSE and routing/behaviors as expected (routed\_stream true, thinking\_enabled\_kwarg false). <a href="https://app.greptile.com/trex/runs/14257681/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 | |----------|----------| | src/free_claude_code/core/anthropic/models.py | Changes `MessagesRequest.stream` to default to non-streaming JSON and reject null values. | | src/free_claude_code/api/handlers/messages.py | Aggregates internal SSE into JSON unless streaming was explicitly requested. | | src/free_claude_code/api/routes.py | Updates the Messages route description to match the new JSON-by-default behavior. | | src/free_claude_code/core/anthropic/sse_aggregation.py | Updates aggregation documentation for omitted and false stream requests. | | tests/api/test_api.py | Adds coverage for classifier-style requests that omit `stream` and expect JSON. | | tests/api/test_api_handlers.py | Marks streaming handler tests with explicit `stream=True`. | | tests/api/test_web_server_tools.py | Marks the forced web-search streaming test with explicit `stream=True`. | | tests/core/anthropic/test_models.py | Updates model expectations for the new default and adds null-stream rejection coverage. | | pyproject.toml | Bumps the package version to `4.3.1`. | | uv.lock | Keeps the editable package version in sync with `pyproject.toml`. | | ARCHITECTURE.md | Documents that Messages responses are non-streaming unless `stream: true` is provided. | </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Ffix-auto-mode-omitted-stream%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Ffix-auto-mode-omitted-stream%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fcore%2Fanthropic%2Fmodels.py%3A186%0A**Null%20Stream%20Now%20Fails%20Validation**%0A%0AWhen%20a%20client%20serializes%20an%20unspecified%20optional%20stream%20flag%20as%20%60%22stream%22%3A%20null%60%2C%20this%20narrowed%20field%20rejects%20the%20request%20before%20the%20handler%20can%20return%20the%20new%20non-streaming%20JSON%20response.%20The%20old%20model%20accepted%20that%20input%2C%20so%20these%20clients%20now%20receive%20a%20validation%20error%20instead%20of%20a%20Message%20object.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1098&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["Fix omitted Messages stream default"](https://github.com/alishahryar1/free-claude-code/commit/ca61e5ad4adf085d5cef1e0e5f3a8ae26d189853) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43859149)</sub> > Greptile also left **1 inline comment** on this PR. <!-- /greptile_comment --> |
||
|
|
0d5bec3dcd |
Make proxy authentication bearer-only across every client (#1096)
## Problem Proxy authentication selected the first of three credential headers, so a stale `X-API-Key` could mask valid bearer authorization and leave Claude CLI or IDE clients at their login gate. Fixes #902. ## Changes | Before | After | | --- | --- | | FCC accepted three proxy credential headers and stripped legacy model suffixes. | FCC accepts one exact `Authorization: Bearer` token without mutation. | | Conflicting provider credentials could override valid proxy authorization. | Unrelated credential headers are ignored during proxy authentication. | | Codex catalog discovery and Pi catalog or inference paths used API-key authentication. | Every FCC-owned Codex and Pi path uses bearer authorization. | | Authentication failures referred ambiguously to an API key. | Authentication failures identify the proxy authentication token. | | FCC reported version `4.2.0`. | FCC reports version `4.3.0`. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes proxy authentication use bearer tokens only. The main changes are: - Replaced multi-header proxy auth with exact `Authorization: Bearer <token>` checks. - Updated protected route dependencies to use the renamed auth dependency. - Switched FCC-owned Codex and Pi catalog requests to bearer authorization. - Added Pi provider `authHeader` registration for inference requests. - Updated smoke tests, API tests, docs, examples, and package metadata for the new auth contract. </details> <h3>Confidence Score: 4/5</h3> The changed auth flow is mostly consistent, but Codex inference can still fail if its generated provider config sends API-key auth. Server-side bearer parsing is direct and covered by updated tests. Route protection appears preserved after the dependency rename. Codex catalog auth was updated, but the inference path still depends on external client header behavior. The version bump may understate a breaking auth-contract change. src/free_claude_code/api/dependencies.py, src/free_claude_code/cli/launchers/codex.py, pyproject.toml <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** - T-Rex executed targeted proxy authentication validation to verify bearer token behavior before and after the change. - T-Rex compared pre-change and post-change test results, confirming 31 passed before and 39 passed after, and validating HTTP 200 for exact bearer with unrelated X-API-Key plus HTTP 401 for missing or invalid tokens. <a href="https://app.greptile.com/trex/runs/14225355/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 | |----------|----------| | src/free_claude_code/api/dependencies.py | Replaces proxy authentication with exact bearer-token validation and new error details. | | src/free_claude_code/api/routes.py | Updates protected route dependencies to call the renamed auth dependency. | | src/free_claude_code/cli/launchers/codex.py | Changes Codex catalog discovery to send bearer auth while leaving inference auth delegated through Codex config. | | src/free_claude_code/cli/launchers/pi_extension.ts | Changes Pi catalog discovery to bearer auth and registers the provider with `authHeader` enabled. | | smoke/lib/config.py | Updates smoke helper auth headers to emit bearer authorization. | | pyproject.toml | Bumps the package version from 4.2.0 to 4.3.0. | </details> <details open><summary><h3>Sequence Diagram</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Codex participant Launcher as FCC Codex launcher participant API as FCC API Launcher->>API: GET /v1/models with Authorization Bearer token API-->>Launcher: Catalog response Launcher-->>Codex: Raw token in FCC_CODEX_API_KEY Codex->>API: POST /v1/responses with client-built auth alt Client sends bearer authorization API-->>Codex: Accepted else Client sends API-key auth API-->>Codex: 401 proxy auth failure end ``` </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 Codex participant Launcher as FCC Codex launcher participant API as FCC API Launcher->>API: GET /v1/models with Authorization Bearer token API-->>Launcher: Catalog response Launcher-->>Codex: Raw token in FCC_CODEX_API_KEY Codex->>API: POST /v1/responses with client-built auth alt Client sends bearer authorization API-->>Codex: Accepted else Client sends API-key auth API-->>Codex: 401 proxy auth failure end ``` </a> </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fcanonical-proxy-bearer-auth%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fcanonical-proxy-bearer-auth%22.%0A%0AFix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0Asrc%2Ffree_claude_code%2Fapi%2Fdependencies.py%3A56%0A**Codex%20Inference%20Still%20Delegates%20Auth**%0A%0AWhen%20Codex%20launches%2C%20FCC%20now%20sends%20bearer%20auth%20only%20for%20its%20own%20%60%2Fv1%2Fmodels%60%20catalog%20request%2C%20but%20inference%20still%20depends%20on%20Codex%20turning%20the%20raw%20%60FCC_CODEX_API_KEY%60%20value%20into%20the%20same%20bearer%20header.%20If%20Codex%20sends%20that%20env%20key%20as%20an%20API-key%20header%2C%20this%20server%20branch%20treats%20the%20request%20as%20missing%20proxy%20auth%20and%20%60%2Fv1%2Fresponses%60%20fails%20with%20401%20even%20though%20catalog%20discovery%20succeeded.%0A%0A%23%23%23%20Issue%202%20of%202%0Apyproject.toml%3A7%0A**Breaking%20Auth%20Contract%20Understated**%0A%0AThis%20change%20removes%20previously%20accepted%20proxy%20credential%20shapes%2C%20including%20%60X-API-Key%60%2C%20%60anthropic-auth-token%60%2C%20and%20suffixed%20bearer%20tokens%2C%20but%20the%20package%20version%20only%20moves%20from%20%604.2.0%60%20to%20%604.3.0%60.%20Existing%20users%20can%20upgrade%20within%20the%20same%20major%20line%20and%20have%20every%20protected%20endpoint%20start%20returning%20401%20until%20their%20clients%20are%20reconfigured%2C%20which%20does%20not%20match%20the%20repository%20guidance%20for%20incompatible%20API%20or%20CLI%20behavior.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1096&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["fix: make proxy auth bearer-only"](https://github.com/alishahryar1/free-claude-code/commit/c437ee0e23dc8f8411272a8dcfcf1ff69f315857) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43791345)</sub> > Greptile also left **2 inline comments** on this PR. **Context used:** - Context used - CLAUDE.md ([source](https://app.greptile.com/alishahryar1/github/Alishahryar1/free-claude-code/-/custom-context?memory=d2fd24d8-0dec-4faf-8ee4-e085e215a2f8)) <!-- /greptile_comment --> |
||
|
|
1b4c7e6779 |
feat: add vision support for OpenAI chat conversion (#1061)
## Problem FCC rejects Anthropic user image blocks before vision-capable OpenAI-compatible providers can receive them. This blocks pasted images in Claude Code and IDE clients. Fixes #512. ## Changes | Before | After | | --- | --- | | User image blocks fail during Anthropic-to-OpenAI conversion. | Base64 and URL image sources become OpenAI `image_url` parts. | | Mixed text and image input cannot reach an upstream model. | Mixed content preserves exact block order and text-only behavior. | | Invalid image sources require ambiguous downstream handling. | Missing or unsupported source fields fail explicitly before execution. | | Vision support could require flags or proxy-side downloads. | Conversion stays provider-neutral and performs no network I/O. | | The package remains on `4.1.0`. | The package advances to `4.2.0` with a regenerated lockfile. | | Converter coverage rejects every user image. | Tests cover source mapping, ordering, tool boundaries, validation, and request construction. | <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR adds OpenAI-compatible vision conversion for Anthropic image blocks. The main changes are: - Converts base64 image sources into data image URLs. - Converts URL image sources into OpenAI `image_url` parts. - Preserves mixed text and image ordering in user messages. - Rejects unsupported or incomplete image sources. - Updates converter tests for image and tool-result cases. - Bumps package metadata to `4.2.0` in both project and lock files. <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. No files need 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** - Reviewed the initial focused run and confirmed all tests passed, with the wrapper exit code reported as nonzero and retained for traceability. - Validated the focused rerun completed cleanly with 10 tests passed and exit code 0. - Validated the full converter run completed with 73 tests passed and exit code 0. <a href="https://app.greptile.com/trex/runs/14209442/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> <h3>Important Files Changed</h3> | Filename | Overview | |----------|----------| | src/free_claude_code/core/anthropic/conversion.py | Adds ordered image conversion for OpenAI-compatible chat content. | | tests/providers/test_converter.py | Adds tests for image conversion, ordering, validation, and request-body output. | | pyproject.toml | Updates the package version to `4.2.0`. | | uv.lock | Updates the locked local package version to `4.2.0`. | | ARCHITECTURE.md | Documents core image conversion behavior for OpenAI-compatible providers. | | README.md | Mentions image input support across compatible models. | <sub>Reviews (8): Last reviewed commit: ["feat: add vision support for OpenAI chat..."](https://github.com/alishahryar1/free-claude-code/commit/4a6b6de14d19ce22e3be5981f84bb6f236a11181) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43544835)</sub> <!-- /greptile_comment --> |
||
|
|
db3831d9e7 |
Fix Pi routing for nested FCC model IDs (#1090)
## Problem Pi registered FCC models but rejected the launcher scope because nested provider/model IDs contain an additional slash. Pi then retained a non-FCC model, so prompts did not reach the local proxy. ## Changes | Before | After | | --- | --- | | `free-claude-code/*` matched only one model-ID path segment. | `free-claude-code/**` matches every nested FCC provider/model ID. | | The integration architecture described a single-segment scope. | The integration architecture records the nested routing-reference contract. | | The package version remained 3.6.0. | The package version is released as 4.0.0. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR updates Pi launcher routing so nested FCC model IDs can be scoped. The main changes are: - Pi sessions now pass `free-claude-code/**` as the model scope. - Pi launcher tests now expect the recursive scope string. - Architecture docs now describe nested FCC provider/model routing. - Package metadata and lockfile version move from `3.6.0` to `4.0.0`. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge after confirming Pi accepts the recursive model scope. The changed launcher passes the new scope as a literal subprocess argument, and no blocking issue was found in the repository-visible changed code. The only follow-up is external matcher compatibility for `free-claude-code/**`. <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** - The Pi launcher configuration was updated to enable recursive scope and to target all models under free-claude-code, as shown by the before and after launcher logs. - The focused Pi tests ran and completed successfully, with 19 passed and 31 deselected, exit code 0. - The Pi test harness initialization registered extensions, preserved and replaced environment variables, enabled recursive scope, and recorded PACKAGE\_VERSION= 4.0.0. - The lint step with ruff ran and passed with exit code 0. <a href="https://app.greptile.com/trex/runs/14193741/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 | |----------|----------| | src/free_claude_code/cli/launchers/pi.py | Changes the Pi model scope from a single-segment pattern to a recursive nested-model pattern. | | tests/cli/test_entrypoints.py | Updates Pi launcher command assertions to expect the new scope string. | | ARCHITECTURE.md | Documents the nested FCC routing-reference contract for Pi sessions. | | pyproject.toml | Bumps the package version to `4.0.0`. | | uv.lock | Synchronizes the editable package version with the project metadata. | </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Ffix-pi-model-scope%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Ffix-pi-model-scope%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fcli%2Flaunchers%2Fpi.py%3A20%0A**Recursive%20Scope%20Depends%20On%20Pi**%0A%0AWhen%20Pi's%20%60--models%60%20matcher%20does%20not%20support%20recursive%20%60**%60%20patterns%2C%20this%20launcher%20now%20passes%20a%20scope%20that%20can%20match%20no%20FCC%20models%20even%20though%20the%20extension%20registers%20them.%20The%20session%20still%20starts%2C%20but%20the%20FCC%20models%20can%20be%20absent%20from%20Pi's%20picker%20and%20prompts%20can%20continue%20using%20a%20non-FCC%20model.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1090&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["Fix Pi nested model scope"](https://github.com/alishahryar1/free-claude-code/commit/f931b9db4a54801cb82c3d0e1c7674528a6bb5a3) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43725034)</sub> > Greptile also left **1 inline comment** on this PR. <!-- /greptile_comment --> |
||
|
|
2fe2ba82d2 |
Add Pi as a first-class FCC client (#1088)
## Problem FCC had no first-class Pi path, so Pi users had to maintain provider configuration themselves. FCC's installers and ownership docs also covered only Claude Code and Codex. ## Changes | Before | After | | --- | --- | | Pi required persistent user-managed provider configuration. | `fcc-pi` registers an ephemeral FCC provider from the live model catalog and leaves Pi-owned state untouched. | | Client launchers normalized blank proxy authentication separately. | Claude, Codex, and Pi share one neutral proxy-auth policy. | | FCC installers and uninstallers did not account for Pi. | Installers delegate missing Pi setup to its official platform installer, while uninstallers remove only `fcc-pi` and preserve native Pi. | | Pi compatibility had no executable FCC contract. | Deterministic launcher and lifecycle coverage plus a real Pi 0.80.6 smoke verify model discovery and `/v1/messages` end to end. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR adds Pi as a supported FCC client. The main changes are: - A new `fcc-pi` launcher and bundled Pi extension. - Shared proxy-auth handling for client launchers. - Pi installation, verification, and uninstall coverage in platform scripts. - Pi-focused tests, smoke coverage, and user documentation. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. None. <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 targeted pytest command and confirmed deterministic success with 27 passed in 2.68s and EXIT\_CODE: 0. - Analyzed the blocker log and determined that Pi CLI and live-smoke prerequisites are missing, blocking external Pi execution; uv is available and provider smoke models are discoverable, narrowing the issue to Pi CLI plus live-smoke opt-in. <a href="https://app.greptile.com/trex/runs/14192651/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 | |----------|----------| | src/free_claude_code/cli/launchers/pi.py | Adds the `fcc-pi` launcher, Pi capability checks, passthrough handling, extension loading, and FCC-scoped environment setup. | | src/free_claude_code/cli/launchers/pi_extension.ts | Adds the Pi extension that fetches FCC models and registers a process-local Anthropic Messages provider. | | scripts/install.sh | Adds Pi install, PATH refresh, capability verification, and `fcc-pi` command checks for POSIX installs. | | scripts/install.ps1 | Adds Pi install, PATH refresh, capability verification, and `fcc-pi` command checks for Windows installs. | | pyproject.toml | Registers the `fcc-pi` console script and bumps the package version. | </details> <!-- greptile_failed_comments --> <h3>Comments Outside Diff (1)</h3> 1. General comment <a href="#"><img alt="P1" src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9" align="top"></a> **Pi entrypoint contract test fails due install-hint mismatch** - **Bug** - The narrow Pi launcher/entrypoint test selection fails on current HEAD. `test_launch_pi_rejects_unrelated_pi_binary` expects stderr to include the Windows PowerShell install URL `https://pi.dev/install.ps1`, but the launcher emitted the POSIX install command `curl -fsSL https://pi.dev/install.sh | sh` in this Linux sandbox. - **Cause** - The Pi launcher's incompatible-binary error path and the test contract disagree about which platform-specific install hint should be emitted for this scenario. - **Fix** - Align the Pi launcher contract with the test expectation: either update the launcher to emit the expected platform-specific hint for the mocked scenario, or update the test to assert the correct hint for the active/mocked platform. Then rerun `uv run --frozen pytest -q tests/cli/test_entrypoints.py -k 'pi'`. <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> <!-- /greptile_failed_comments --> <sub>Reviews (3): Last reviewed commit: ["Add first-class Pi client integration"](https://github.com/alishahryar1/free-claude-code/commit/cd5c335f8cf2dee93d927496d7cabbffec86f169) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43721088)</sub> <!-- /greptile_comment --> |
||
|
|
12621477c9 |
Fix cross-drive messaging startup with native Claude plan storage (#1085)
## Problem Messaging startup computed a relative path from `ALLOWED_DIR` to FCC's plan directory. Windows raises before Telegram or Discord polling starts when those paths are on different drives, while Claude requires custom plan directories to remain inside the project root. Fixes #1077. ## Changes | Before | After | | --- | --- | | Runtime startup converted FCC's plan path relative to the customer workspace. | Runtime startup no longer computes or transports a custom plan path. | | Managed Claude configuration carried `plans_directory` through four ownership layers. | Managed Claude relies on its native user-level plan storage. | | `~/.fcc/agent_workspace` was described as a Claude workspace. | The existing path is explicitly owned as messaging state for `sessions.json`. | | Cross-volume `ALLOWED_DIR` values could disable messaging startup. | `ALLOWED_DIR` remains the project workspace regardless of filesystem volume. | |
||
|
|
aba94d5c3c |
Disable nonessential Anthropic traffic for FCC Claude sessions (#1083)
## Problem Claude proxy environment policy was duplicated between `fcc-claude`, managed messaging, and live smoke drivers. Managed messaging preserved a legacy endpoint variable, inherited more Anthropic state, and did not disable nonessential traffic, so FCC-launched Claude sessions could drift apart. ## Changes | Before | After | | --- | --- | | `fcc-claude` and managed messaging assembled proxy environments independently. | One shared owner strips inherited Anthropic variables and configures proxy URL, auth, discovery, compaction, and nonessential-traffic policy. | | Managed messaging carried a `/v1` API URL and converted it back to a proxy root while also setting a legacy endpoint variable. | Managed messaging receives the loopback-safe proxy root and uses the supported `ANTHROPIC_BASE_URL` contract directly. | | Managed and interactive policy could diverge while smoke drivers duplicated both shapes. | `fcc-claude`, messaging, and Claude smoke drivers use the same canonical environment builder. | | Managed execution concerns were mixed with shared proxy policy. | Messaging adds only noninteractive process settings and keeps `--model opus` plus stream-JSON flags in command construction. | | IDE examples left nonessential Anthropic traffic enabled. | VS Code and JetBrains examples disable nonessential Anthropic traffic. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR centralizes Claude Code proxy environment setup for FCC-launched sessions. The main changes are: - Adds one shared builder for Claude proxy environment variables. - Routes managed messaging sessions through the same proxy policy as `fcc-claude`. - Strips inherited `ANTHROPIC_*` state before launching Claude. - Sets the nonessential-traffic disable flag for managed and interactive Claude launches. - Updates smoke tests, docs, and version metadata for the new proxy-root URL shape. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues were found in the changed code. Managed Claude launches now use the shared environment builder, and the managed path now sets the nonessential-traffic disable flag. No files need 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** - The executable harness claude\_env\_policy\_harness.py was generated to enable direct module-level runtime proof without requiring a real Claude binary or live Anthropic credentials. - A focused pytest run was executed, and it completed with 14 tests passing and exit code 0, validating the harness workflow. <a href="https://app.greptile.com/trex/runs/14173386/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 | |----------|----------| | src/free_claude_code/cli/claude_env.py | Adds the shared Claude proxy environment builder and canonical traffic-disable policy. | | src/free_claude_code/cli/managed/claude.py | Delegates managed Claude environment construction to the shared proxy builder. | | src/free_claude_code/runtime/application.py | Passes the loopback-safe proxy root into the managed Claude session manager. | | src/free_claude_code/cli/managed/session.py | Renames managed session URL state to use the proxy-root contract. | | src/free_claude_code/cli/managed/manager.py | Carries the proxy-root URL through manager-created managed sessions. | </details> <sub>Reviews (2): Last reviewed commit: ["Keep README focused on client setup"](https://github.com/alishahryar1/free-claude-code/commit/83739a2f8953771ec9e447fc83a2057b08708891) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43684511)</sub> <!-- /greptile_comment --> |
||
|
|
3fba1c6fc3 |
Give messaging clear exact subtree semantics (#1072)
## Problem Messaging `/clear` did not follow the selected platform message boundary. Reply clears preserved the selected user prompt, while standalone clears preserved user-authored messages and could reset FCC state outside the invoking chat. ## Changes | Before | After | | --- | --- | | Reply `/clear` removed a logical conversation branch but retained the selected message. | Reply `/clear` deletes the selected message and its literal reply subtree, including the clear command. | | Standalone `/clear` retained user prompts and voice notes while resetting global messaging state. | Standalone `/clear` deletes every tracked message and resets FCC state only in the invoking platform and chat. | | Trees recorded only logical execution parentage. | Trees separately persist logical execution ancestry and exact prompt/status reply ownership. | | Clear coordination used one global admission boundary. | Per-chat clear generations coordinate admission, voice cancellation, persistence, and best-effort platform deletion. | | Persistence tracked only FCC-authored clearable output. | Persistence tracks managed inbound and outbound messages and migrates legacy entries. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR gives messaging `/clear` exact per-chat and reply-subtree behavior. The main changes are: - Per-chat clear generations for admission and startup-notice cleanup. - Managed inbound and outbound message tracking for deletion. - Exact prompt/status reply ownership in message trees. - Scoped voice cancellation and clear persistence updates. - Updated docs, smoke coverage, and messaging tests. </details> <h3>Confidence Score: 4/5</h3> The clear flow is mostly well-contained, with one upgrade-path issue in legacy tree restoration. Newly created prompt/status subtrees use the new exact reference fields consistently, and legacy snapshots can map old status replies to prompt references. However, reply `/clear` on an upgraded status can miss descendants and leave stale state/messages. src/free_claude_code/messaging/trees/snapshot.py <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** - T-Rex attempted to prepare and run a focused legacy snapshot reproduction harness for legacy status replies detach, but tool access was blocked before execution. - A messaging clear smoke test harness was executed and reported a passing result: 20 items collected and 20 passed in 1.69 seconds, with traces for test\_reply\_clear\_uses\_literal and related paths shown in the log. <a href="https://app.greptile.com/trex/runs/14131337/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 | |----------|----------| | src/free_claude_code/messaging/workflow.py | Adds per-chat clear generations, managed inbound recording, scoped clears, and startup-notice invalidation. | | src/free_claude_code/messaging/trees/graph.py | Adds exact prompt/status reference resolution and literal reply-subtree traversal. | | src/free_claude_code/messaging/trees/runtime.py | Adds exact message-subtree removal and status-only clearing behavior. | | src/free_claude_code/messaging/trees/snapshot.py | Adds parent_reference_id persistence and legacy fallback; the fallback can miss legacy status-reply descendants. | | src/free_claude_code/messaging/session/managed_message_log.py | Replaces the clearable output log with managed inbound and outbound message tracking. | | src/free_claude_code/messaging/commands.py | Routes reply and standalone `/clear` through the new exact deletion ID flows. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A[Incoming message] --> B{Standalone /clear?} B -- yes --> C[Clear invoking chat] C --> D[Cancel scoped voice work] C --> E[Collect managed and tree message IDs] C --> F[Advance chat clear generation] F --> G[Detach scoped trees] G --> H[Clear scoped session store] H --> I[Best-effort platform deletes] B -- no --> J[Record managed inbound message] J --> K[Admit with stop and clear token] K --> L{Reply /clear?} L -- yes --> M[Resolve exact prompt or status reference] M --> N[Remove literal reference subtree] N --> I L -- no --> O[Queue or run tree node] ``` </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"}}}%% flowchart TD A[Incoming message] --> B{Standalone /clear?} B -- yes --> C[Clear invoking chat] C --> D[Cancel scoped voice work] C --> E[Collect managed and tree message IDs] C --> F[Advance chat clear generation] F --> G[Detach scoped trees] G --> H[Clear scoped session store] H --> I[Best-effort platform deletes] B -- no --> J[Record managed inbound message] J --> K[Admit with stop and clear token] K --> L{Reply /clear?} L -- yes --> M[Resolve exact prompt or status reference] M --> N[Remove literal reference subtree] N --> I L -- no --> O[Queue or run tree node] ``` </a> </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fclear-message-subtree%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fclear-message-subtree%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fmessaging%2Ftrees%2Fsnapshot.py%3A192-193%0A**Legacy%20Status%20Replies%20Detach**%0A%0AWhen%20an%20upgraded%20legacy%20snapshot%20contains%20a%20child%20that%20originally%20replied%20to%20its%20parent%20status%2C%20this%20fallback%20rewrites%20the%20missing%20exact%20reference%20to%20the%20parent%20prompt.%20A%20later%20reply%20%60%2Fclear%60%20on%20that%20status%20traverses%20from%20the%20status%20ID%2C%20finds%20no%20migrated%20child%20edge%2C%20and%20leaves%20the%20old%20status-reply%20descendants%20and%20their%20managed%20messages%20behind.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1072&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["Give messaging clear exact subtree seman..."](https://github.com/alishahryar1/free-claude-code/commit/0a3baecf9470da4bb866c864c1d1f01abd517085) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43593126)</sub> > Greptile also left **1 inline comment** on this PR. <!-- /greptile_comment --> |
||
|
|
f3ea35a777 |
Consolidate OpenAI-compatible provider adapters (#1069)
## Problem Sixteen OpenAI-compatible providers were represented by configuration-only subclasses and one factory function each. The sole provider family also lived under a multi-transport namespace that no longer described the codebase, while provider defaults, IDs, and instance caching passed through redundant forwarding layers. ## Changes | Before | After | | --- | --- | | Sixteen provider IDs used configuration-only subclasses. | Immutable OpenAI-chat profiles configure one concrete provider while preserving each provider's request policy. | | Every provider required a dedicated factory function. | Generic profile construction is the default; only eight adapters with real state or algorithms retain factories. | | The sole provider family lived under `providers/transports/`. | `providers/openai_chat/` directly owns shared request, stream, recovery, tool, and usage behavior. | | Provider defaults and IDs passed through forwarding modules, and constructors repeated fallback resolution. | The neutral catalog resolves complete immutable provider configuration once. | | `ProviderRuntime` wrapped a pass-through provider cache. | `ProviderRuntime` directly owns lazy provider instances and cleanup. | | Production carried the duplicated adapter structure. | The final shape removes a net 873 production lines with no compatibility shim or customer-facing provider change. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR consolidates OpenAI-compatible providers behind shared profiles and runtime construction. The main changes are: - OpenAI-chat behavior moved into `providers/openai_chat`. - Configuration-only provider subclasses replaced by immutable profiles. - Provider runtime now owns lazy instance caching and cleanup directly. - Provider defaults and IDs now resolve through the neutral catalog. - Tests and smoke helpers updated for the new provider shape. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. No files need 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** - T-Rex produced a proof for a posted P1 finding and linked it to the corresponding review comment for details. - T-Rex saved contract-validation logs for provider consolidation and preserved four log files that show the test hanging boundary and the timeout exit code 124. <a href="https://app.greptile.com/trex/runs/14125428/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 | |----------|----------| | src/free_claude_code/providers/runtime/config.py | Builds resolved provider configuration from catalog descriptors, including static credentials for local providers. | | src/free_claude_code/providers/openai_chat/provider.py | Creates shared OpenAI-chat clients from resolved configuration and immutable provider profiles. | | src/free_claude_code/providers/openai_chat/profiles.py | Defines declarative profiles for formerly configuration-only OpenAI-compatible adapters. | </details> <!-- greptile_failed_comments --> <h3>Comments Outside Diff (2)</h3> 1. General comment <a href="#"><img alt="P1" src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9" align="top"></a> **NIM OpenAI-compatible 504 exhausted streaming retry path hangs instead of completing with the expected user-facing error** - **Bug** - The broader provider consolidation suite failed all parametrized `test_nim_stream_openai_5xx_exhausted_emits_user_message` cases under xdist with worker crashes. A serial isolation run narrowed this to the same OpenAI-compatible NIM exhausted 5xx streaming path: 500, 502, and 503 completed, but the 504 case did not finish before the explicit 120s timeout, producing exit code 124. This contradicts the expected streaming retry contract that exhausted transient provider failures terminate and emit the configured user-facing error. - **Cause** - The OpenAI-compatible streaming retry/exhaustion path for NIM 504 responses appears to wait indefinitely or otherwise fail to terminate after retries are exhausted. The exact code-level loop/await point was not isolated within the validation budget, but the failure is anchored to the provider streaming retry contract exercised by `tests/providers/test_openai_compat_5xx_retry.py::test_nim_stream_openai_5xx_exhausted_emits_user_message[504-temporarily unavailable]`. - **Fix** - Inspect the OpenAI-compatible/NIM streaming retry exhaustion handling for 504 responses and ensure retry limits are enforced, the async stream is closed/cancelled on exhaustion, and the provider raises/emits the same terminal user-facing error contract as the 500/502/503 cases. Add or keep a serial regression test for the 504 exhausted stream path to prevent hangs. <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> 2. General comment <a href="#"><img alt="P1" src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9" align="top"></a> **OpenAI-compatible 5xx retry suite hangs on exhausted 502 retry path** - **Bug** - The recommended non-xdist retry validation does not complete. A verbose rerun with a 60 second timeout shows the suite passes tests through the exhausted 500 case, then times out while running `test_nim_stream_openai_5xx_exhausted_emits_user_message[502-temporarily unavailable]`. This indicates the consolidated OpenAI-compatible provider retry/error path can hang for at least the 502 exhausted-error scenario, preventing reliable validation and potentially blocking callers from receiving the expected `ExecutionFailure`. - **Cause** - The OpenAI-compatible provider's exhausted 502 retry/error handling path appears not to terminate promptly under the mocked repeated `openai.InternalServerError` scenario. The exact code location was not changed during validation, but the failure is isolated to the shared OpenAI-chat 5xx retry behavior exercised by `NvidiaNimProvider.stream_response`. - **Fix** - Debug the shared OpenAI-chat retry loop/error classification for 502 responses. Ensure retries are bounded, patched `asyncio.sleep` is awaited without real backoff during tests, and exhausted 502/503/504 errors consistently raise `ExecutionFailure` with the expected temporary-unavailable message instead of continuing work indefinitely. <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> <!-- /greptile_failed_comments --> <sub>Reviews (2): Last reviewed commit: ["Prove local provider credential resoluti..."](https://github.com/alishahryar1/free-claude-code/commit/ba226d97efdae1889bea0372c7bacf268122d65c) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43580983)</sub> <!-- /greptile_comment --> |
||
|
|
e37b504636 |
Preserve user messages during messaging clear (#1068)
## Problem Messaging `/clear` used one untyped collection for both internal reply references and platform deletion targets. Clearing a branch or cancelling a voice task could therefore delete the customer's prompt or voice note along with FCC's own status and reply messages. ## Changes | Before | After | | --- | --- | | Tree transitions exposed one message-ID set for repository unindexing and platform deletion. | Tree transitions now separate internal `reference_ids` from FCC-owned `clearable_message_ids`. | | Reply and global clear deleted user prompts and voice notes with FCC output. | Clear removes FCC statuses, replies, notices, and the explicit `/clear` command while preserving user-authored messages. | | The persisted message log accepted ordinary inbound content. | The clearable-message log accepts only FCC output and explicit clear commands, and drops legacy user-content entries when loading. | | Tests treated user-message deletion as successful cleanup. | Deterministic and live messaging coverage enforce preservation across branch, global, and voice clear paths. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR narrows messaging clear behavior so user-authored messages are preserved. The main changes are: - Clearable platform IDs are separated from internal tree reference IDs. - The session message log now tracks FCC-owned output and explicit clear commands. - Branch, global, and voice clear paths now avoid deleting user prompts and voice notes. - Tests, smoke coverage, docs, and the package version were updated. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge after a small migration cleanup. The clear paths now preserve user-authored messages, and current clearable-log writers use the new shape consistently. src/free_claude_code/messaging/session/clearable_message_log.py needs a migration cleanup for old retained clear-command IDs during session reload. <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** - Validated the messaging-clear-preservation contract by reviewing the foreground pytest run log, which captured the exact command, working directory, full test output, and exit code, and by examining the artifact note and its capture log that summarize the command, test count, exit code, and scope. <a href="https://app.greptile.com/trex/runs/14123111/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 | |----------|----------| | src/free_claude_code/messaging/session/clearable_message_log.py | Replaces the broad message log with a clearable-message log, but the migration filter can drop old retained clear-command IDs. | | src/free_claude_code/messaging/session/store.py | Renames the session-store API around clearable message IDs while keeping the same persisted `message_log` key. | | src/free_claude_code/messaging/trees/runtime.py | Returns internal reference IDs separately from FCC-owned deletion IDs during branch removal and chat-wide enumeration. | | src/free_claude_code/messaging/trees/manager.py | Uses reference IDs for repository cleanup and returns clearable IDs for platform deletion. | | src/free_claude_code/messaging/turn_intake.py | Stops recording ordinary inbound content and records clear commands only when needed for cleanup. | | src/free_claude_code/messaging/commands.py | Deletes clearable IDs plus the invoking clear command instead of deleting all branch reference IDs. | | src/free_claude_code/messaging/workflow.py | Aggregates clearable IDs from tree state, the session log, and voice cancellation results. | | src/free_claude_code/messaging/voice.py | Changes voice cancellation deletion ownership so only FCC-authored status messages are clearable. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A[Incoming message] --> B{Clear command?} B -- No --> C[Handle normal turn] C --> D[Record FCC outbound status] B -- Reply clear --> E[Record clear command] E --> F[Clear branch or voice task] F --> G[Delete FCC-owned IDs plus clear command] B -- Global clear --> H[Collect clearable IDs] H --> I[Reset conversation state] I --> J[Delete FCC-owned IDs plus clear command] D --> K[Clearable-message log] K --> H ``` </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"}}}%% flowchart TD A[Incoming message] --> B{Clear command?} B -- No --> C[Handle normal turn] C --> D[Record FCC outbound status] B -- Reply clear --> E[Record clear command] E --> F[Clear branch or voice task] F --> G[Delete FCC-owned IDs plus clear command] B -- Global clear --> H[Collect clearable IDs] H --> I[Reset conversation state] I --> J[Delete FCC-owned IDs plus clear command] D --> K[Clearable-message log] K --> H ``` </a> </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fpreserve-user-messages-on-clear%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fpreserve-user-messages-on-clear%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fmessaging%2Fsession%2Fclearable_message_log.py%3A36-37%0A**Legacy%20Clear%20Commands%20Are%20Dropped**%0A%0AWhen%20an%20existing%20session%20file%20contains%20a%20previously%20retained%20clear%20command%20from%20the%20old%20log%2C%20it%20is%20stored%20as%20%60direction%3D%22in%22%60%20and%20%60kind%3D%22command%22%60.%20This%20new%20load%20filter%20drops%20that%20entry%20because%20it%20only%20keeps%20%60kind%3D%22clear_command%22%60%2C%20so%20a%20failed%20or%20cancelled%20%60%2Fclear%60%20command%20recorded%20before%20the%20upgrade%20is%20no%20longer%20retried%20by%20the%20next%20clear%20and%20remains%20on%20the%20platform.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1068&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["Preserve user messages during clear"](https://github.com/alishahryar1/free-claude-code/commit/af7a910facaa29a5ca8f7fb95ec2faae28798e62) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43576921)</sub> > Greptile also left **1 inline comment** on this PR. **Context used:** - Context used - CLAUDE.md ([source](https://app.greptile.com/alishahryar1/github/Alishahryar1/free-claude-code/-/custom-context?memory=d2fd24d8-0dec-4faf-8ee4-e085e215a2f8)) <!-- /greptile_comment --> |
||
|
|
3a7e0ccf7a |
Remove the native Anthropic provider transport (#1067)
## Problem Ollama and llama.cpp still used a parallel native Anthropic transport after the other providers moved to OpenAI Chat. That kept duplicate request, SSE, recovery, model-list, and server-tool policy machinery alive. ## Changes | Before | After | | --- | --- | | Ollama and llama.cpp streamed through provider-specific Anthropic `/messages` adapters. | Ollama and llama.cpp use the shared OpenAI Chat transport. | | Native request serialization, SSE normalization, error mapping, and recovery remained beside the OpenAI path. | Native-only machinery is removed and all providers share one transport lifecycle. | | Routed models carried a capability object solely to permit native server-tool passthrough. | Routing carries only route decisions; FCC handles forced server tools locally and rejects lossy passthrough. | | Ollama discovery used a separate `/api/tags` parser and rejected `/v1` configuration. | Ollama discovery uses `/v1/models` and accepts either root or `/v1` base URLs. | | Obsolete native tests and a compatibility facade kept deleted internals represented. | Tests cover the shared transport and real Ollama product path without compatibility shims. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR removes the native Anthropic transport path for local providers. The main changes are: - Ollama and llama.cpp now use the shared OpenAI Chat transport. - Local provider base URLs are normalized to the OpenAI-compatible `/v1` API root. - Ollama discovery now uses the OpenAI-compatible model-listing path. - Native Anthropic transport code and server-tool passthrough capability metadata were removed. - Tests and smoke coverage were updated for the shared transport path. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. None. <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 targeted local provider pytest slice and observed exit code 0. - Executed the generated runtime harness to emulate the provider HTTP interactions and capture a request trace. - Validated the request trace showed two GET /v1/models calls authorized as Bearer ollama for root and /v1 base URL configurations, and a POST /v1/chat/completions authorized as Bearer llamacpp with streaming OpenAI chat JSON payload. - Confirmed the exact generated harness script used for the runtime proof is the harness file referenced in the artifacts. <a href="https://app.greptile.com/trex/runs/14121848/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 | |----------|----------| | src/free_claude_code/providers/transports/openai_chat/base_url.py | Adds a helper that normalizes local OpenAI-compatible server roots to `/v1`. | | src/free_claude_code/providers/llamacpp/client.py | Moves llama.cpp to the shared OpenAI Chat transport with local base URL normalization. | | src/free_claude_code/providers/ollama/client.py | Moves Ollama to the shared OpenAI Chat transport with local base URL normalization. | | src/free_claude_code/api/handlers/messages.py | Applies server-tool rejection through the shared request policy instead of provider passthrough metadata. | | src/free_claude_code/application/routing.py | Removes provider capability metadata from routed model results. | </details> <!-- greptile_failed_comments --> <h3>Comments Outside Diff (1)</h3> 1. `src/free_claude_code/api/handlers/messages.py`, line 261-267 ([link](https://github.com/alishahryar1/free-claude-code/blob/3c7ff176da46560c4d27b3846dca1ab1c7db561c/src/free_claude_code/api/handlers/messages.py#L261-L267)) <a href="#"><img alt="P2" src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9" align="top"></a> **Native Server Tools Always Reject** With the passthrough capability check removed, Ollama and llama.cpp requests that previously used their native Anthropic transport for `web_search` or `web_fetch` are rejected before provider execution. The default `ENABLE_WEB_SERVER_TOOLS=false` now makes forced server-tool requests return an invalid-request error instead of reaching the local provider path that used to support them. <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fremove-native-anthropic-transport%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fremove-native-anthropic-transport%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20src%2Ffree_claude_code%2Fapi%2Fhandlers%2Fmessages.py%0ALine%3A%20261-267%0A%0AComment%3A%0A**Native%20Server%20Tools%20Always%20Reject**%0A%0AWith%20the%20passthrough%20capability%20check%20removed%2C%20Ollama%20and%20llama.cpp%20requests%20that%20previously%20used%20their%20native%20Anthropic%20transport%20for%20%60web_search%60%20or%20%60web_fetch%60%20are%20rejected%20before%20provider%20execution.%20The%20default%20%60ENABLE_WEB_SERVER_TOOLS%3Dfalse%60%20now%20makes%20forced%20server-tool%20requests%20return%20an%20invalid-request%20error%20instead%20of%20reaching%20the%20local%20provider%20path%20that%20used%20to%20support%20them.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=alishahryar1%2Ffree-claude-code&pr=1067&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"><img alt="Fix in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"></picture></a> <!-- /greptile_failed_comments --> <sub>Reviews (2): Last reviewed commit: ["Normalize local OpenAI v1 base URLs"](https://github.com/alishahryar1/free-claude-code/commit/2355eac247a6e411f89a781f46e784636ced98d6) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43572841)</sub> <!-- /greptile_comment --> |
||
|
|
ef76bddd58 |
Make Telegram startup notices clearable (#1066)
## Problem Telegram's online notice was sent directly by the SDK runtime and its message ID was discarded, so `/clear` could not delete it. Moving delivery into the workflow also needs to keep slow sends from blocking commands and prevent acknowledged notices from losing clear ownership. ## Changes | Before | After | | --- | --- | | The Telegram runtime sent a transport-specific startup side effect. | The platform declares a semantic notice intent that the application gives to the workflow after transport readiness. | | Startup delivery bypassed the persisted message log. | The workflow renders and records each acknowledged notice in the same bounded log used by `/clear`. | | Serializing send and record held workflow state across platform I/O. | A dedicated clear generation reserves publication, delivery runs outside the state lock, and a short receipt finalizer commits or compensates. | | Concurrent clear, cancellation, or record failure could leave a delivered notice unowned. | Clear or cancellation deletes a late receipt; record failure deletes it; failed deletion restores tracking for a later `/clear`. | | A standalone `/clear` command could evict an older target at the log cap. | Successful standalone clear owns its command ID directly, while failed or cancelled clear records it for the next attempt. | | Startup ownership races were implicit. | Deterministic race, failure, cap, restart, and product-smoke coverage enforce the final state machine in version 3.5.10. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes Telegram startup notices clearable through the messaging workflow. The main changes are: - Moves the Telegram online notice out of the SDK runtime and into workflow-owned publication. - Adds a startup-notice intent to platform composition and publishes it after runtime start and restored-status repair. - Records delivered startup notice IDs for later `/clear` ownership, with delete compensation on interrupted ownership transfer. - Defers standalone `/clear` command ID recording so it cannot evict older deletion targets at the log cap. - Adds tests and smoke coverage for startup notice clearing, cancellation, failures, cap pressure, persistence, and startup ordering. - Bumps the package version and lockfile to 3.5.10. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues were found in the changed code. No files need 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** - A focused proof run for the telegram startup tests completed, showing 121 tests passed in 2.94 seconds with EXIT\_CODE 0. - A smoke proof run for the same flow completed, showing 18 tests skipped in 0.97 seconds with EXIT\_CODE 0. - The shell wrapper issue was addressed by re-running with bash -lc, producing a clean result with EXIT\_CODE 0 in the final artifact. <a href="https://app.greptile.com/trex/runs/14118230/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 | |----------|----------| | src/free_claude_code/messaging/workflow.py | Adds workflow-owned startup notice sending, tracking, compensation, and clear-generation ordering. | | src/free_claude_code/messaging/turn_intake.py | Defers standalone `/clear` command ID recording until failure or cancellation paths need it. | | src/free_claude_code/runtime/application.py | Publishes optional startup notices after messaging runtime start and restored-status repair. | | src/free_claude_code/messaging/platforms/factory.py | Creates a Telegram startup-notice intent when an allowed Telegram user is configured. | | src/free_claude_code/messaging/platforms/telegram.py | Removes the direct Telegram runtime startup-message side effect. | </details> <sub>Reviews (2): Last reviewed commit: ["Make Telegram startup notices clearable"](https://github.com/alishahryar1/free-claude-code/commit/6e779006e0cdaf1df24c27a8d04784e2d7220a66) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43565904)</sub> <!-- /greptile_comment --> |
||
|
|
eda8ea3060 |
Use task status as the sole stop confirmation (#1065)
## Problem Messaging `/stop` edited each affected task status to `Stopped` and also posted a second success message. The duplicate confirmation added noise even though the existing status already represented the terminal result. ## Changes | Before | After | | --- | --- | | Successful active, queued, global, and bound-voice stops posted a second confirmation. | Successful stops use the affected task status as their sole success UI. | | Stop commands returned an ambiguous integer or `None`. | A typed `StopOutcome` carries the cancelled count and terminal status ownership. | | Statusless voice cancellation could become silent if confirmations were removed unconditionally. | Statusless voice cancellation receives one fallback confirmation. | | A global stop could under-report work when any affected status was in another chat. | The invoking chat receives one summary whenever any affected status is outside its scope. | | Zero-work global stops reported that zero requests were cancelled. | No-op global and reply stops report that there was nothing to stop. | | Runtime and product coverage encoded the duplicate message. | Runtime mapping and Discord/Telegram product smokes cover active, queued, voice, no-op, and fallback behavior. | | The package version was 3.5.8. | The package version is 3.5.9 with an updated lockfile. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR changes `/stop` so task statuses become the main success feedback. The main changes are: - Added a typed stop outcome for cancelled counts and status feedback ownership. - Suppressed duplicate stop confirmations when the invoking chat already has complete status feedback. - Kept explicit fallback messages for no-op stops, statusless voice cancellations, and cross-chat stop results. - Updated runtime mapping, docs, product smokes, tests, and the package version. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. None. <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 live messaging product smoke test with FCC\_LIVE\_SMOKE=1 and FCC\_SMOKE\_TARGETS=messaging, executing the command uv run pytest under /home/user/repo; the run exited with code 0 and 17 tests passed in 1.34s. - Reviewed the test run log to verify proper shutdown behavior, noting Discord and Telegram stop statuses, a queued trace, and cancellation messages indicating shutdown tasks were being canceled. - Linked the stop-product-smoke-20260711.log artifact for review of the run's stop behavior. <a href="https://app.greptile.com/trex/runs/14115543/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 | |----------|----------| | src/free_claude_code/messaging/command_context.py | Adds `StopOutcome` and updates stop command context signatures. | | src/free_claude_code/messaging/commands.py | Routes stop confirmations through the new outcome and fallback rules. | | src/free_claude_code/messaging/workflow.py | Builds stop outcomes from voice cancellations and tree cancellation effects. | | src/free_claude_code/runtime/application.py | Maps the messaging stop outcome back to the runtime stop result count. | | tests/messaging/test_handler.py | Covers same-chat status feedback, cross-chat fallback, no-op stops, and voice fallback behavior. | | smoke/product/test_messaging_product_live.py | Updates product smokes for status-only stop success feedback. | </details> <sub>Reviews (2): Last reviewed commit: ["Use task status as the sole stop confirm..."](https://github.com/alishahryar1/free-claude-code/commit/98f0acb01b3405c2afd918539eff49b9410bf487) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43560341)</sub> <!-- /greptile_comment --> |
||
|
|
df038c2470 |
Retry degraded NVIDIA NIM functions as overloads (#1064)
## Problem NVIDIA NVCF can return HTTP 400 when a deployed function is DEGRADED, even though the failure is transient. FCC treated that response as a deterministic invalid request and never used its provider-owned retry budget. Fixes #1057. ## Changes | Before | After | | --- | --- | | Every NVIDIA HTTP 400 was non-retryable. | The NVIDIA adapter recognizes only the structured NVCF `Function id …: DEGRADED function cannot be invoked` response. | | A degraded function failed after one attempt. | The shared limiter applies its existing five-attempt exponential backoff without mutating the request or adding another retry loop. | | Exhaustion returned `INVALID_REQUEST / 400`. | Exhaustion returns canonical `OVERLOADED / 529` while preserving the redacted upstream HTTP 400 detail and request ID. | | NVIDIA-specific wording could have leaked into shared classification. | The exact marker stays NVIDIA-owned; shared provider policy owns canonical semantics, diagnostics, and scheduling, while API wire mapping remains unchanged. | | The degraded-function boundary had no deterministic coverage. | Tests cover recovery, exact exhaustion, near misses, provider isolation, raw exception preservation, trace metadata, and credential redaction; all five CI gates pass with 2,214 tests passed and 7 skipped. | | Package version was 3.5.7. | Package version is 3.5.8 with an updated lockfile. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR teaches NVIDIA NIM degraded-function failures to use the shared overload retry path. The main changes are: - Adds a provider-specific failure override hook. - Maps the exact NVCF degraded-function HTTP 400 marker to canonical overload semantics. - Threads the override through shared retry and final failure classification. - Adds focused tests for retry, exhaustion, near misses, provider isolation, redaction, and trace metadata. - Updates docs, smoke coverage metadata, package version, and lockfile. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge after considering the narrow NVIDIA error-body match. The retry and final classification flow preserve the raw upstream error, and non-NVIDIA providers keep the existing 400 behavior. src/free_claude_code/providers/nvidia_nim/client.py should harden the degraded marker lookup for nested SDK error bodies. <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** - T-Rex produced a proof for the posted P1 finding and linked it to the corresponding review comment. - A contract-validation proof was captured showing the full command transcript with timestamps, working directory, commands, pytest verbose output, and exit codes. - The focused Nvidia degraded retry test ran and completed with 8 passed in 2.43s. - A broader test run reported worker crashes, with 3 failed and 70 passed. - A serial test for test\_openai\_compat\_5xx\_retry.py timed out after a hang, exiting at 124. <a href="https://app.greptile.com/trex/runs/14112472/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 | |----------|----------| | src/free_claude_code/providers/nvidia_nim/client.py | Adds NVIDIA-specific degraded-function detection; the match is narrow and only reads a top-level `detail` field. | | src/free_claude_code/providers/rate_limit.py | Uses provider overrides for retry qualification while preserving the raw exception after retry exhaustion. | | src/free_claude_code/providers/failure_policy.py | Adds the shared override type and final classification hook, plus a reusable overloaded-provider failure constructor. | | src/free_claude_code/providers/transports/openai_chat/transport.py | Passes provider-specific failure overrides into stream creation retries and final failure mapping. | | tests/providers/test_nvidia_nim_degraded_retry.py | Adds coverage for NVIDIA degraded-function retry success, retry exhaustion, non-matching 400s, provider isolation, redaction, and traces. | </details> <!-- greptile_failed_comments --> <h3>Comments Outside Diff (1)</h3> 1. General comment <a href="#"><img alt="P1" src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9" align="top"></a> **Adjacent OpenAI-compatible 5xx exhaustion test crashes workers and hangs serially** - **Bug** - The requested adjacent retry/rate-limit coverage is not stable on current head. Under xdist, three parameters of `test_nim_stream_openai_5xx_exhausted_emits_user_message` caused workers to terminate unexpectedly, producing an exit code 1. A follow-up serial rerun passed the 500 parameter but timed out after 60 seconds while running the 502 parameter, indicating the exhausted 5xx path can hang or terminate the worker rather than completing deterministically. - **Cause** - The executed evidence points to the OpenAI-compatible NIM 5xx exhaustion path exercised by `tests/providers/test_openai_compat_5xx_retry.py::test_nim_stream_openai_5xx_exhausted_emits_user_message`. The exact root cause was not isolated within the validation budget, but the affected area overlaps changed retry/transport handling files. - **Fix** - Investigate the OpenAI-compatible streaming 5xx exhaustion path for non-terminating retry/stream cleanup or worker-fatal behavior. Ensure exhausted 5xx cases raise the expected user-facing error promptly for all status parameters, then rerun the adjacent command and the targeted serial parametrized test. <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> <!-- /greptile_failed_comments --> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fretry-nim-degraded-function%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fretry-nim-degraded-function%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fproviders%2Fnvidia_nim%2Fclient.py%3A126-127%0A**Nested%20Error%20Body%20Misses%20Retry**%0A%0AWhen%20the%20OpenAI%20SDK%20exposes%20a%20400%20response%20as%20the%20common%20nested%20error%20shape%2C%20such%20as%20%60%7B%22error%22%3A%20%7B%22message%22%3A%20%22Function%20id%20...%3A%20DEGRADED%20function%20cannot%20be%20invoked%22%7D%7D%60%2C%20this%20lookup%20never%20sees%20the%20degraded%20marker.%20That%20path%20falls%20back%20to%20the%20shared%20400%20handling%2C%20so%20a%20transient%20degraded%20NVCF%20function%20still%20fails%20after%20one%20attempt%20instead%20of%20using%20the%20provider%20retry%20budget.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1064&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (1): Last reviewed commit: ["Retry degraded NVIDIA NIM functions as o..."](https://github.com/alishahryar1/free-claude-code/commit/2cc7f056a73d1baefb1e1395b181d26efc32dc9e) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43555691)</sub> > Greptile also left **1 inline comment** on this PR. <!-- /greptile_comment --> |
||
|
|
78377253d6 |
Keep voice ownership continuous through admission (#1063)
## Problem Pending voice ownership ended before workflow admission completed. A concurrent reply or global stop/clear could miss the handoff and return while transcribed work was still able to enter the tree. ## Changes | Before | After | | --- | --- | | The registry released voice and status aliases before the workflow callback finished. | The registry retains both aliases and an owned child through callback completion or explicit cancellation and join. | | Caller and nested cancellation could interrupt cleanup or form recursive joins. | Completion-driven cleanup preserves cancellation state and excludes current or actively cancelling claims. | | Commands coordinated voice-registry and message-tree primitives. | The workflow exposes typed reply and global stop/clear use cases that own voice-to-tree synchronization. | | Admission could be interrupted between tree mutation, processor publication, and persistence. | One workflow-owned transaction validates the epoch, admits work, publishes processing, and persists its exact snapshot. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR keeps voice-message ownership active until admission, stop, or clear work finishes. The main changes are: - Adds registry-managed voice handoff tasks and bulk cancellation. - Moves reply `/stop` and `/clear` into workflow-owned voice/tree operations. - Wraps admission, stop, and clear work so state changes finish before caller cancellation is restored. - Updates platform ports, adapters, tests, smoke fixtures, docs, and package metadata. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. None. <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 primary test suite for messaging and platform voice flow; 64 tests passed with exit code 0. - Ran the live smoke tests for messaging product; 15 tests passed with exit code 0. - Captured and organized logs documenting the test commands, working directory, pytest outputs, and exit codes for both runs. <a href="https://app.greptile.com/trex/runs/14110540/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 | |----------|----------| | src/free_claude_code/messaging/voice.py | Adds continuous pending-voice ownership, handoff task tracking, alias cleanup, and guarded bulk cancellation. | | src/free_claude_code/messaging/platforms/voice_flow.py | Routes transcription handoff and cleanup through the registry-owned lifecycle. | | src/free_claude_code/messaging/workflow.py | Coordinates voice cancellation with tree admission, reply stop, reply clear, and global stop/clear operations. | | src/free_claude_code/messaging/commands.py | Delegates reply-scoped stop and clear behavior to typed workflow operations. | </details> <sub>Reviews (3): Last reviewed commit: ["Keep voice ownership continuous through ..."](https://github.com/alishahryar1/free-claude-code/commit/14acdfad8c38c1410620ac461fa05988aa417913) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43549792)</sub> <!-- /greptile_comment --> |
||
|
|
5ffa47fbc3 |
Make response stream lifetimes explicit (#1060)
## Problem Client disconnects and response-start send failures could abandon a prefetched provider stream and its generation lease. Re-yielding iterators and response-proxy middleware left no owner that closed the complete body chain before runtime release. ## Changes | Before | After | | --- | --- | | Starlette body iteration indirectly owned stream cleanup and lease release. | One FCC streaming response surrounds the real ASGI send, closes the body transitively, then releases the lease exactly once. | | The prefetched first-frame generator could not close its tail before replay began. | An explicit closeable replay iterator owns the prefetched tail in every commit state. | | Tracing, execution, Responses conversion, and native transport transforms re-yielded inputs without closing them. | Every retained transform closes its direct input; redundant transport wrappers are removed while provider construction failures remain deferred. | | Function-style correlation middleware proxied and canceled streaming responses. | Pure ASGI correlation spans the complete stream, preserves request headers and log context, and keeps the catch-all 500 fallback correlated. | | Repeated cancellation could interrupt pre-start and post-start cleanup. | Shielded completion tasks finish body closure before release and then restore caller cancellation. | | The package version was 3.5.5. | The package version is 3.5.6; full CI passes with 2,162 tests and stable live API/provider/disconnect/client smoke passes 63 scenarios. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes streaming response ownership explicit across the API path. The main changes are: - Adds a managed streaming response that closes the body chain before releasing provider resources. - Adds a prefetched replay iterator for first-frame commit handling. - Moves request correlation to pure ASGI middleware for full-stream context. - Propagates direct-input closure through execution, tracing, Responses conversion, and provider transports. - Bumps the package version and updates tests for stream cleanup behavior. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. None. <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** - Validated the execution environment by reviewing the environment proof log, confirming uv 0.11.28, CPython 3.14.0, a repo-local virtual environment, and exit code 0. - Verified that the requested test command was executed, based on the test proof log. - Confirmed the test run completed successfully with 91 tests passing in 3.63 seconds, as shown in the test proof log. <a href="https://app.greptile.com/trex/runs/14099258/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 | |----------|----------| | src/free_claude_code/api/response_streams.py | Adds the managed response owner, first-frame replay iterator, and shielded cleanup flow. | | src/free_claude_code/api/request_ids.py | Adds pure ASGI request correlation and response-start header injection. | | src/free_claude_code/core/trace.py | Adds shared stream input closure tracing and closes traced inputs on exit. | | src/free_claude_code/application/execution.py | Closes provider stream iterators from the executor wrapper when streaming ends. | | src/free_claude_code/providers/transports/anthropic_messages/transport.py | Returns provider runner streams directly and closes layered SSE iterators explicitly. | </details> <sub>Reviews (2): Last reviewed commit: ["Make response stream lifetimes explicit"](https://github.com/alishahryar1/free-claude-code/commit/cb698c62c08924d5f80a1cea7dbd19c0b8af26a2) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43527620)</sub> <!-- /greptile_comment --> |
||
|
|
5b35ac7c49 |
Make provider stream ownership exact and typed (#1059)
## Problem Provider stream runners lived in sibling modules, accepted `transport: Any`, and reached through private transport state. The split hid ownership behind an import-cycle workaround and prevented type checking from protecting the collaboration. ## Changes | Before | After | | --- | --- | | OpenAI-chat and native Messages streaming and recovery were split across six modules. | Each transport module owns one exactly typed private request runner and its recovery lifecycle; four obsolete modules are deleted without shims. | | Native streaming retained an unused mode export and transformation hooks. | Native streaming directly owns the single normalization path used by llama.cpp and Ollama. | | Provider retry, holdback, continuation, tool salvage, tracing, and subclass hooks crossed an untyped backchannel. | Existing behavior and provider-specific hooks remain unchanged behind checked `OpenAIChatTransport` and `AnthropicMessagesTransport` collaborators. | | Architecture checks did not cover this internal ownership boundary. | A generic AST contract rejects untyped transport collaborators and cross-module private transport access. | | Package version was `3.5.4`. | Package version is `3.5.5`; full CI passes with 2,136 tests and configured-provider behavior was exercised live. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR moves provider streaming ownership into typed transport modules. The main changes are: - OpenAI-chat stream and recovery logic now lives in `openai_chat/transport.py`. - Anthropic Messages stream and recovery logic now lives in `anthropic_messages/transport.py`. - Obsolete stream and recovery helper modules were removed. - Import-boundary tests now check typed transport collaborators and private transport access. - The package version and architecture notes were updated. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. <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 provider contract tests; the test suite completed with 19 passing tests and EXIT\_CODE 0. - Initiated the provider regression test run, which was terminated before completion with EXIT\_CODE 137. - Executed Ruff provider checks; all checks passed with EXIT\_CODE 0. - Executed Ty provider type checks; all checks passed with EXIT\_CODE 0. <a href="https://app.greptile.com/trex/runs/14096487/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 | |----------|----------| | src/free_claude_code/providers/transports/anthropic_messages/transport.py | Native streaming and recovery were moved into a typed per-request runner. | | src/free_claude_code/providers/transports/openai_chat/transport.py | OpenAI-chat streaming and recovery were moved into a typed per-request runner. | | tests/contracts/test_import_boundaries.py | The transport boundary contract now rejects nested `Any` transport annotations and private transport access from helper modules. | </details> <sub>Reviews (2): Last reviewed commit: ["Make provider stream owners exact and ty..."](https://github.com/alishahryar1/free-claude-code/commit/30d0c88e7a28e4c7ac44cc622f52deca5cf83b93) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43519560)</sub> <!-- /greptile_comment --> |
||
|
|
3081a72f41 |
Make application shutdown completion-driven (#1056)
## Problem\n\nShutdown could report success after bounded messaging cleanup, hidden persistence failures, or failed managed-process stops. An Admin restart could then construct a replacement while the old runtime still owned work.\n\n## Changes\n\n| Before | After |\n| --- | --- |\n| Runtime reused bounded interactive stop semantics for terminal messaging cleanup. | Workflow close cancels work, stops managed sessions, awaits every claim and recovery task, then flushes persistence. |\n| Explicit persistence failures were logged and treated as successful writes. | Explicit flushes and authoritative writes propagate failure and stay dirty for retry; timer writes remain best effort. |\n| Managed sessions and aliases were removed before subprocess termination was confirmed. | Manager and session terminal states prevent reuse, retain failed owners and PIDs, reject ID collisions, and retry exact sessions. |\n| Admin restart followed the restart request even after incomplete shutdown. | Supervisor restarts only when the prior runtime reports its entire ownership graph closed. |\n| Partial messaging startup cleanup could fail while application startup continued. | Incomplete partial cleanup fails startup and retains the exact graph for a later close attempt. |\n| Messaging task failures read process-global settings. | Runtime injects diagnostic policy and the messaging package depends only on core. |\n| Lifecycle edge cases were verified only in isolated components. | Deterministic and live product coverage proves composed retry, drain, privacy, and customer command behavior. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes application shutdown wait for owned work to finish before restart or exit. The main changes are: - Runtime close now waits for messaging work, managed sessions, and persistence flushes. - Admin restart now requires the previous runtime to report full closure. - Managed Claude sessions now keep aliases and PIDs until stop is confirmed. - Session persistence now propagates explicit write failures and keeps dirty state for retry. - Messaging no longer reads global config from task-failure callbacks. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. No files need 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** - I reviewed the general contract validation proof and confirmed that the lifecycle\_session pytest run completed with 73 passed in 2.68s (EXIT\_CODE: 0) and the messaging pytest run completed with 95 passed in 1.96s (EXIT\_CODE: 0). <a href="https://app.greptile.com/trex/runs/14094038/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 | |----------|----------| | src/free_claude_code/messaging/trees/processor.py | Completion callback failures now release task ownership and surface through the idle waiter. | | src/free_claude_code/messaging/workflow.py | Terminal workflow close now cancels tasks, waits for processor cleanup, and flushes persistence. | | src/free_claude_code/runtime/application.py | Runtime shutdown now keeps incomplete ownership cleanup retryable and exposes closure state. | | src/free_claude_code/cli/entrypoints.py | The supervisor now restarts only after the old runtime reports full closure. | | src/free_claude_code/cli/managed/manager.py | Managed session shutdown now blocks reuse and retains failed owners for retry. | | src/free_claude_code/cli/managed/session.py | Managed sessions now mark terminal state under a lifecycle lock and retain PID ownership until exit. | </details> <!-- greptile_failed_comments --> <h3>Comments Outside Diff (1)</h3> 1. `src/free_claude_code/messaging/trees/processor.py`, line 194-202 ([link](https://github.com/alishahryar1/free-claude-code/blob/b736bad1aacb66784e7b4d1e09d27a32b2a380c7/src/free_claude_code/messaging/trees/processor.py#L194-L202)) <a href="#"><img alt="P1" src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9" align="top"></a> **Idle Event Stays Cleared** When `_claim_finished_callback` raises a non-cancellation exception, `_finish_and_continue` exits before `slot.transitioned` is set, before the slot is removed from `_tasks`, and before `_idle` is set. `MessagingWorkflow.close()` now waits on `wait_idle()`, so a finish-path error can leave shutdown waiting forever instead of returning a failed close. <details><summary><strong>Artifacts</strong></summary><br /> **[Repro: standalone async harness that drives TreeQueueManager and forces a finish callback RuntimeError](https://app.greptile.com/trex/artifacts/da413ba3-7f69-459d-b8c8-3141c2bb6c41)** - Contains supporting evidence from the run (text/x-python; charset=utf-8). **[Repro: uv run output showing finish callback RuntimeError, retained task\_count, cleared idle event, and wait\_idle timeout](https://app.greptile.com/trex/artifacts/35b2beaa-ec52-47bd-b36b-2735b3ebc62c)** - Keeps the command output available without making the summary code-heavy. <a href="https://app.greptile.com/trex/runs/14093236/artifacts?artifact=da413ba3-7f69-459d-b8c8-3141c2bb6c41"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifacts.svg?v=4"><img alt="View artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifacts.svg?v=4"></picture></a> </details> <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> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fcompletion-driven-shutdown%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fcompletion-driven-shutdown%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20src%2Ffree_claude_code%2Fmessaging%2Ftrees%2Fprocessor.py%0ALine%3A%20194-202%0A%0AComment%3A%0A**Idle%20Event%20Stays%20Cleared**%0A%0AWhen%20%60_claim_finished_callback%60%20raises%20a%20non-cancellation%20exception%2C%20%60_finish_and_continue%60%20exits%20before%20%60slot.transitioned%60%20is%20set%2C%20before%20the%20slot%20is%20removed%20from%20%60_tasks%60%2C%20and%20before%20%60_idle%60%20is%20set.%20%60MessagingWorkflow.close%28%29%60%20now%20waits%20on%20%60wait_idle%28%29%60%2C%20so%20a%20finish-path%20error%20can%20leave%20shutdown%20waiting%20forever%20instead%20of%20returning%20a%20failed%20close.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=alishahryar1%2Ffree-claude-code&pr=1056&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"><img alt="Fix in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"></picture></a> <!-- /greptile_failed_comments --> <sub>Reviews (2): Last reviewed commit: ["Surface messaging completion failures"](https://github.com/alishahryar1/free-claude-code/commit/39a874c8f0e0614847d80321dd51c9654707a7ff) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43514893)</sub> <!-- /greptile_comment --> |
||
|
|
b323b45434 |
Isolate nested Codex launches from parent task context (#1055)
## Problem\n\nNested Codex launches inherited the parent task's thread, shell, permission, and origin identity. This could attach a new client or compatibility probe to the parent task, hang startup, or decode probe output with the wrong Windows locale.\n\n## Changes\n\n| Before | After |\n| --- | --- |\n| cc-codex forwarded parent-only Codex task context. | cc-codex removes parent-only task context while preserving user configuration such as CODEX_HOME. |\n| The installed-Codex probe inherited the parent task and user Codex home. | The probe runs with a standalone task identity and isolated Codex home. |\n| The probe decoded output with the platform default encoding. | The probe decodes output as UTF-8 with safe replacement. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR isolates nested Codex launches from parent task identity. The main changes are: - Strips Codex thread, shell, permission, and origin context from launched child environments. - Preserves `CODEX_HOME` as durable user configuration. - Runs the installed Codex catalog probe with an isolated home and cleaned task context. - Decodes probe output as UTF-8 with replacement. - Updates architecture notes and bumps the package version to `3.5.3`. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. No files need 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** - Logged the proof with exact commands, the working directory, timestamps, and test and lint summaries, including exit codes. - The first pytest capture showed tests passed but the shell wrapper exited with code 2 because /bin/sh does not support ${PIPESTATUS\[0\]}. - Re-ran the proof under bash, and the run exited with code 0. - Artifacts containing the three proof logs were created for review. <a href="https://app.greptile.com/trex/runs/14092911/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 | |----------|----------| | src/free_claude_code/cli/launchers/codex.py | Strips parent-only Codex context variables from the child launcher environment while keeping `CODEX_HOME`. | | tests/cli/test_entrypoints.py | Adds launcher coverage for stripped Codex task variables and preserved `CODEX_HOME`. | | tests/cli/test_codex_model_catalog.py | Runs the installed Codex catalog probe with a cleaned environment, isolated home, and UTF-8 replacement decoding. | | ARCHITECTURE.md | Documents the Codex launcher context-isolation behavior. | | pyproject.toml | Bumps the project version to `3.5.3`. | | uv.lock | Updates the locked editable package version to `3.5.3`. | </details> <sub>Reviews (3): Last reviewed commit: ["Document Codex home ownership"](https://github.com/alishahryar1/free-claude-code/commit/2140315b1f33c4162e74ca8f816228f50c38c0a1) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43513448)</sub> <!-- /greptile_comment --> |
||
|
|
795a83a826 |
Make pending voice cancellation atomic (#1054)
## Problem Reply-scoped `/clear` could miss a voice note during status delivery or race its final handoff. It could report cancellation while the transcription still executed or later emitted a contradictory error. ## Changes | Before | After | | --- | --- | | Pending state appeared only after status delivery. | The flow reserves an opaque claim before any status I/O. | | Pending checks and removal were separate transitions. | One registry-locked handoff claim is exclusive with cancellation. | | Cancellation always assumed a status message existed. | Cancellation returns the voice ID with an optional bound status ID. | | Stale flows could mutate reused IDs or report late failures. | Exact claim IDs reject ABA updates and make late canceled work cleanup-only. | | Race coverage exercised only ordinary transcription cancellation. | Deterministic tests cover pre-bind cancel, handoff races, stale claims, and late failures. | | The architecture documented registration but not ownership transfer. | The architecture defines reservation, status binding, cancellation, and handoff ownership. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes voice-note cancellation claim-based and race-safe. The main changes are: - Pending voice work now reserves an opaque claim before status delivery. - Status binding, cancellation, discard, and handoff now run through the shared registry. - Reply-scoped `/clear` now handles cancellations with or without a bound status message. - Platform runtimes, smoke fakes, and tests now use the new cancellation result shape. - Architecture notes and package metadata were updated for the patch release. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues were found in the changed code. The registry uses locked claim checks for cancellation, discard, status binding, and handoff, and the updated callers handle cancellation results with and without a status message. No files need 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** - Validated the focused voice cancellation pytest run completed successfully with 58 tests passing (EXIT\_CODE: 0) according to the focused log. - Validated the broader voice cancellation regression pytest run completed successfully with 120 tests passing (EXIT\_CODE: 0) according to the broader log. <a href="https://app.greptile.com/trex/runs/14089714/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 | |----------|----------| | src/free_claude_code/messaging/voice.py | Adds claim-based pending voice reservation, status binding, cancellation, discard, and handoff. | | src/free_claude_code/messaging/platforms/voice_flow.py | Reorders voice handling around early claim reservation and exclusive final handoff. | | src/free_claude_code/messaging/commands.py | Updates `/clear` to delete the voice message and optional status message from a cancellation result. | | src/free_claude_code/messaging/platforms/ports.py | Updates the cancellation protocol to return `VoiceCancellationResult | None`. | | src/free_claude_code/messaging/platforms/discord.py | Updates the Discord cancellation signature to match the shared protocol. | | src/free_claude_code/messaging/platforms/telegram.py | Updates the Telegram cancellation signature to match the shared protocol. | | tests/messaging/test_platform_voice_flow.py | Adds race-focused coverage for pre-bind cancellation, late failures, and handoff cancellation. | | tests/messaging/test_voice_services.py | Adds registry coverage for stale claims, duplicate reservations, and cancellation/handoff exclusivity. | | tests/messaging/test_handler.py | Covers `/clear` deletion behavior for bound and unbound voice cancellation results. | | smoke/lib/e2e.py | Updates the fake platform cancellation helper to return the new result object. | | smoke/product/test_messaging_product_live.py | Updates the smoke test setup to use the renamed pending voice seeding helper. | | ARCHITECTURE.md | Documents pending voice reservation, binding, cancellation, and handoff ownership. | | pyproject.toml | Bumps the package version for the production change. | | uv.lock | Synchronizes the lockfile package version. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A[Voice note received] --> B[Reserve pending claim] B -->|duplicate voice id| Z[Return handled] B --> C[Send status message] C --> D[Bind status id] D -->|canceled or stale claim| E[Delete late status and stop] D --> F[Download and transcribe] F --> G[Claim for handoff] G -->|cancel won| E G -->|handoff won| H[Remove registry entry] H --> I[Invoke message workflow] J[/Reply-scoped clear/] --> K[Cancel registry entry] K --> L[Return voice id and optional status id] L --> M[Delete clear command, voice, and bound status] ``` </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"}}}%% flowchart TD A[Voice note received] --> B[Reserve pending claim] B -->|duplicate voice id| Z[Return handled] B --> C[Send status message] C --> D[Bind status id] D -->|canceled or stale claim| E[Delete late status and stop] D --> F[Download and transcribe] F --> G[Claim for handoff] G -->|cancel won| E G -->|handoff won| H[Remove registry entry] H --> I[Invoke message workflow] J[/Reply-scoped clear/] --> K[Cancel registry entry] K --> L[Return voice id and optional status id] L --> M[Delete clear command, voice, and bound status] ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["Make pending voice cancellation atomic"](https://github.com/alishahryar1/free-claude-code/commit/6680c794247d66aa631e78001488492ae8128045) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43507813)</sub> <!-- /greptile_comment --> |
||
|
|
23ed6bc87e |
Make provider backoff admission monotonic (#1053)
## Problem Concurrent provider requests could miss or shorten a reactive backoff while waiting for proactive admission. Separate gate commits could also waste quota or release requests as an expiry burst. ## Changes | Before | After | | --- | --- | | Reactive deadlines were checked once and replaced by later backoffs. | Reactive deadlines are rechecked until clear and only extended by later backoffs. | | Proactive capacity was recorded before the final reactive decision. | Conditional commit records proactive capacity only while the reactive deadline is clear. | | The limiter exposed an ambiguous `set_blocked` callback. | Both transport families use the explicit `extend_reactive_block` operation. | | Cross-gate races and wait cancellation lacked deterministic coverage. | Deterministic tests cover conditional commit, extensions, non-shortening, and cancellation. | | The architecture left gate interaction implicit. | The architecture defines monotonic two-gate admission without wasted quota or expiry bursts. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes provider backoff admission monotonic. The main changes are: - Conditional proactive admission before recording quota. - Reactive waits that recheck extended deadlines. - Monotonic reactive block extension for retry and stream failure paths. - Tests for admission retries, deadline extension, non-shortening, and cancellation. - Version and architecture updates for the new limiter behavior. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. None. <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 provider-rate-limit pytest suite; all 53 tests completed and passed in 4.02 seconds with EXIT\_CODE: 0. - Started the transport-backoff pytest run; it advanced through most tests before xdist workers were terminated and the process exited with EXIT\_CODE: 143. - Verified that no live provider credentials, Docker containers, or external service smoke tests were used. <a href="https://app.greptile.com/trex/runs/14088781/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 | |----------|----------| | src/free_claude_code/core/rate_limit.py | Adds conditional sliding-window admission without recording quota on rejection. | | src/free_claude_code/providers/rate_limit.py | Reworks provider admission to combine reactive waits with final proactive commit checks. | | src/free_claude_code/providers/transports/anthropic_messages/stream.py | Routes stream rate-limit marking through monotonic reactive block extension. | | src/free_claude_code/providers/transports/openai_chat/stream.py | Routes stream rate-limit marking through monotonic reactive block extension. | | tests/core/test_strict_sliding_window.py | Covers rejected conditional admission and commit-time timestamp recording. | | tests/providers/test_provider_rate_limit.py | Covers reactive admission retries, extended deadlines, cancellation, and non-shortening behavior. | </details> <sub>Reviews (2): Last reviewed commit: ["Make provider backoff admission monotoni..."](https://github.com/alishahryar1/free-claude-code/commit/a5c637393d1996e51c195875636ecb0536522932) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43504969)</sub> <!-- /greptile_comment --> |
||
|
|
26cc73e6ce |
Use installed metadata as the single package version source (#1051)
## Problem FCC runtime surfaces reported stale, unrelated versions, and users could not inspect the installed FCC version without starting the server or scaffolding configuration. ## Changes | Before | After | | --- | --- | | FastAPI/OpenAPI and the web-tools user agent duplicated stale release literals. | Every FCC runtime surface reads installed distribution metadata through one `core.version` owner. | | FCC-owned commands had no side-effect-free version query. | `fcc-server`, `free-claude-code`, and `fcc-init` print the installed version whenever `--version` is present, before any configuration or process work. | | Wrapped Claude and Codex argument handling was adjacent to FCC command behavior. | Claude and Codex launchers remain transparent and pass `--version` to their wrapped clients unchanged. | | A source-only checkout had no explicit fallback contract. | Missing distribution metadata reports `0+unknown`, while malformed installed metadata still fails visibly. | | Version behavior lacked end-to-end contract coverage. | API, CLI, metadata, user-agent, feature-inventory, and live command tests verify one value and zero CLI side effects; the complete 2,077-test CI gate passes. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes installed package metadata the single source for the FCC version. The main changes are: - Adds `core.version.package_version()` with a source-checkout fallback. - Uses that version in FastAPI/OpenAPI metadata and web-tool User-Agent headers. - Adds side-effect-free `--version` handling for FCC-owned CLI entrypoints. - Keeps Claude and Codex launchers transparent to wrapped client arguments. - Updates tests, smoke coverage, docs, and package metadata to `3.5.0`. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. No files need 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** - The version contract pytest run completed successfully with EXIT\_CODE: 0, as captured in the version contract pytest log. - The direct CLI version commands sequence completed with final EXIT\_CODE: 0, as recorded in the CLI version commands log. <a href="https://app.greptile.com/trex/runs/14086115/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 | |----------|----------| | src/free_claude_code/core/version.py | Adds the canonical installed-metadata version helper with an explicit missing-metadata fallback. | | src/free_claude_code/cli/entrypoints.py | Adds early `--version` output for FCC-owned server and init commands before startup or config work. | | src/free_claude_code/api/app.py | Uses the centralized package version for FastAPI and OpenAPI metadata. | | src/free_claude_code/api/web_tools/constants.py | Uses the centralized package version in the outbound web-tool User-Agent. | </details> <sub>Reviews (2): Last reviewed commit: ["Use installed metadata as the package ve..."](https://github.com/alishahryar1/free-claude-code/commit/f240f9c363115e63f407d7ac8d5c35833f6b66c8) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43500448)</sub> <!-- /greptile_comment --> |
||
|
|
d428b5904a |
Replace historical architecture tests with declarative boundaries (#1050)
## Problem Architecture contracts mixed real dependency rules with deleted-module tombstones and exact internal file inventories. Correct refactors therefore had to preserve history instead of the current ownership model. ## Changes | Before | After | | --- | --- | | Cross-package rules were duplicated across narrow source and layout assertions. | One least-privilege matrix and AST scanner enforce every production package edge. | | Bare imports, undeclared ownership roots, and module cycles could escape generic enforcement. | Namespaced imports, initialized owners, exact exceptions, and an acyclic module graph are enforced. | | Responses, messaging-tree, and optional dependency ownership relied on scattered checks. | Facade use and lazy optional dependency owners are declared and verified centrally. | | The messaging facade re-exported workflow, persistence, and parsing internals. | The messaging facade exposes only ingress values, platform ports, and managed-session protocols. | | Migration-era tests froze deleted modules and internal filenames. | Customer contracts remain while obsolete tombstones and layout inventories are removed. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR replaces historical architecture checks with declarative import-boundary rules. The main changes are: - Added a documented package dependency matrix and facade ownership rules. - Narrowed the messaging package facade to its supported extension surface. - Moved messaging tree consumers to the `messaging.trees` facade. - Reworked architecture tests around AST scanning, optional dependency owners, and acyclic imports. - Bumped the package version and refreshed the lockfile. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. <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** - The architecture contracts tests were executed as part of the general contract validation. - The test run completed with exit code 0, indicating success. - The pytest summary shows 26 tests passed in 3.99 seconds. - An artifact log captures the exact command, working directory, environment recreation output, and verbose test item names for audit. <a href="https://app.greptile.com/trex/runs/14085499/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 | |----------|----------| | src/free_claude_code/messaging/__init__.py | Narrows the top-level messaging exports to the documented supported extension types. | | tests/contracts/test_import_boundaries.py | Replaces historical layout checks with declarative import-boundary enforcement. | | ARCHITECTURE.md | Documents the current dependency matrix, facade boundaries, and optional dependency owners. | | src/free_claude_code/messaging/node_event_pipeline.py | Uses the messaging tree facade for `NodeClaim`. | | src/free_claude_code/messaging/node_runner.py | Uses the messaging tree facade for queue, snapshot, cancellation, and claim types. | </details> <sub>Reviews (2): Last reviewed commit: ["Enforce architecture with declarative im..."](https://github.com/alishahryar1/free-claude-code/commit/68508f3d2bad19d4d1b8a9ca5d181e1433db4d71) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43498975)</sub> <!-- /greptile_comment --> |
||
|
|
2bcaf3ac74 |
Make messaging trees atomic ownership boundaries (#1048)
## Problem Messaging tree state, queue coordination, task ownership, and persistence were jointly mutated across several classes. Raw message IDs were treated as globally unique, allowing cross-chat collisions and unsafe cancellation or clear ordering. ## Changes | Before | After | | --- | --- | | Managers and processors coordinated partial tree mutations through exposed locks and mutable nodes. | MessageTree owns atomic transitions and returns detached effects to task, UI, and persistence owners. | | Raw message IDs and task identities could collide across chats or detached generations. | Scoped tree identities and opaque claim IDs isolate chats and reject stale task writes. | | Session snapshots duplicated graph links and retained ingress payloads. | Lean scoped snapshots rebuild validated indexes and continue reading existing session files. | | Stop, clear, and runner persistence could interleave across commit boundaries. | Admission epochs, cancellation-safe detach, and authoritative writes make committed cleanup durable. | | Tree implementation classes leaked through messaging package exports. | Adapter-facing values and ports remain supported while tree internals stay internal. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR makes messaging trees own their state transitions and scoped identities. The main changes are: - Scoped tree and voice ownership by platform and chat. - Opaque claim IDs for queued task execution. - Manager-owned atomic cancellation, clear, and successor task launch paths. - Lean scoped snapshots with legacy session restore support. - Messaging tree internals removed from the public package surface. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. <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** - Executed the messaging and contract-boundary test suite with pytest across all specified test modules. - Observed the run completed with 96 tests passing in 4.10 seconds and an exit code of 0. - The exact pytest command used for the run is documented in the proof to enable reproducibility of the test scope. - The run log is available as an artifact for reviewers to inspect test output and details. <a href="https://app.greptile.com/trex/runs/14083891/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 | |----------|----------| | src/free_claude_code/messaging/trees/runtime.py | Adds claim-scoped state transitions and cancellation tombstones for late runner writes. | | src/free_claude_code/messaging/trees/manager.py | Centralizes aggregate publication, branch removal, global clear, and successor task launch decisions. | | src/free_claude_code/messaging/trees/processor.py | Runs tasks by opaque claim ID and routes cleanup through manager-owned finish handling. | | src/free_claude_code/messaging/trees/snapshot.py | Serializes scoped tree snapshots and restores supported legacy tree shapes. | | src/free_claude_code/messaging/voice.py | Scopes pending voice registrations by message scope and message ID. | </details> <!-- greptile_failed_comments --> <h3>Comments Outside Diff (1)</h3> 1. `src/free_claude_code/messaging/commands.py`, line 161-164 ([link](https://github.com/alishahryar1/free-claude-code/blob/a4e49f082a9d3ffc1f6cdf3ab6a065b0f22a759d/src/free_claude_code/messaging/commands.py#L161-L164)) <a href="#"><img alt="P1" src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9" align="top"></a> **Voice Cancellation Is Unscoped** The tree reply path is now scoped by `incoming.scope`, but the voice fallback still cancels by only `chat_id` and `reply_id`. If Discord and Telegram both have the same raw chat/message IDs, a reply `/clear` from one platform can cancel a pending voice note from the other platform, crossing the ownership boundary this PR adds for message trees. <details><summary><strong>Artifacts</strong></summary><br /> **[Repro: focused pytest harness that models cross-platform raw ID collision for voice cancellation](https://app.greptile.com/trex/artifacts/0ad480a9-4e20-4b4e-970e-63aebc4577b3)** - Contains supporting evidence from the run (text/x-python; charset=utf-8). **[Repro: verbose pytest output showing unscoped cancel\_pending\_voice call and Discord-owned voice cancellation from Telegram /clear](https://app.greptile.com/trex/artifacts/ead824f3-2f41-4028-a8e3-8359c5f6d3a9)** - Keeps the command output available without making the summary code-heavy. <a href="https://app.greptile.com/trex/runs/14082218/artifacts?artifact=0ad480a9-4e20-4b4e-970e-63aebc4577b3"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifactsDark.svg?v=4"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifacts.svg?v=4"><img alt="View artifacts" src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifacts.svg?v=4"></picture></a> </details> <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> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22architecture%2Fmessage-tree-ownership%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22architecture%2Fmessage-tree-ownership%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20src%2Ffree_claude_code%2Fmessaging%2Fcommands.py%0ALine%3A%20161-164%0A%0AComment%3A%0A**Voice%20Cancellation%20Is%20Unscoped**%0A%0AThe%20tree%20reply%20path%20is%20now%20scoped%20by%20%60incoming.scope%60%2C%20but%20the%20voice%20fallback%20still%20cancels%20by%20only%20%60chat_id%60%20and%20%60reply_id%60.%20If%20Discord%20and%20Telegram%20both%20have%20the%20same%20raw%20chat%2Fmessage%20IDs%2C%20a%20reply%20%60%2Fclear%60%20from%20one%20platform%20can%20cancel%20a%20pending%20voice%20note%20from%20the%20other%20platform%2C%20crossing%20the%20ownership%20boundary%20this%20PR%20adds%20for%20message%20trees.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=alishahryar1%2Ffree-claude-code&pr=1048&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"><img alt="Fix in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"></picture></a> <!-- /greptile_failed_comments --> <sub>Reviews (4): Last reviewed commit: ["Serialize successor task publication wit..."](https://github.com/alishahryar1/free-claude-code/commit/ec8744a8882c1ebc38d5dc7e87aaf2e31b08f653) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43492190)</sub> <!-- /greptile_comment --> |
||
|
|
701a394697 |
Make provider capabilities semantic and typed (#1047)
## Problem Provider metadata mixed descriptive strings and transport-family names with product policy. The Messages API had to know provider implementation details to decide server-tool behavior, while locality and thinking metadata had ambiguous owners. ## Changes | Before | After | | --- | --- | | Provider descriptors exposed transport names and untyped capability strings. | Provider descriptors expose an immutable semantic value containing only locality and server-tool passthrough. | | The Messages handler derived provider sets from transport families. | `ResolvedModel` carries catalog capabilities and the handler asks the resolved semantic policy. | | Discovery, Admin, and smoke selection inferred locality from credentials or string membership. | Discovery, Admin, and smoke selection read the catalog-owned `local` capability. | | Provider-wide thinking strings competed with discovered model metadata. | `ProviderModelInfo.supports_thinking` remains the sole per-model thinking authority. | | Invalid mapped providers could become raw catalog lookup failures during the migration. | Routing and provider construction share the canonical typed unknown-provider error. | | LM Studio smoke contracts described a native Anthropic transport. | LM Studio smoke contracts describe its OpenAI-chat-backed Messages path. | | Tests encoded transport identities as product behavior. | Tests prove both directions of capability-versus-identity independence while preserving existing wire behavior and diagnostics. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR moves provider policy from transport names to typed catalog capabilities. The main changes are: - Added immutable provider capability values for locality and server-tool passthrough. - Routed provider capabilities through `ResolvedModel` for Messages API policy. - Updated admin status, discovery, smoke config, docs, and tests to read semantic capabilities. - Centralized unknown-provider diagnostics for routing and provider construction. - Bumped the package version and lockfile to `3.4.22`. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. None. <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** - The Pytest run for the provider capabilities changes was executed and completed successfully, as shown by the log's EXIT\_CODE: 0. - The Ruff linter run for the provider capabilities changes was executed and completed successfully, as shown by the log's EXIT\_CODE: 0. - The focused suite exercised the changed code paths via repository tests rather than relying solely on static inspection. <a href="https://app.greptile.com/trex/runs/14074560/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 | |----------|----------| | src/free_claude_code/config/provider_catalog.py | Replaces transport and string capability metadata with typed immutable provider capabilities. | | src/free_claude_code/application/routing.py | Adds catalog capabilities to resolved models and uses the shared unknown-provider error. | | src/free_claude_code/api/handlers/messages.py | Uses resolved semantic capabilities to decide server-tool passthrough. | | src/free_claude_code/config/admin/status.py | Classifies local providers through the new catalog capability. | | src/free_claude_code/providers/runtime/discovery.py | Uses typed locality to decide which providers are discovered only when referenced. | | src/free_claude_code/application/errors.py | Adds a shared constructor for canonical unknown-provider messages. | </details> <sub>Reviews (1): Last reviewed commit: ["Make provider capabilities semantic and ..."](https://github.com/alishahryar1/free-claude-code/commit/b2732ef74d61c632ccae332a19aaa655f45a96e7) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43475337)</sub> <!-- /greptile_comment --> |
||
|
|
e22a38b2c2 |
Canonicalize provider failure and retry ownership (#1046)
## Problem Provider SDK classification, retry policy, canonical failures, and downstream wire errors shared exception types across layers. That blurred ownership and let cleanup or provisional Responses tool failures mask the real provider diagnostic. ## Changes | Before | After | | --- | --- | | Provider failures carried Anthropic wire types and core code classified OpenAI/httpx errors. | Protocol-neutral `ExecutionFailure` values cross layers, providers classify SDK errors, and protocol packages map wire types. | | Provider adapters could author terminal wire events. | The HTTP commit boundary selects non-2xx JSON or a protocol terminal event with one ingress request ID. | | Retry policy and diagnostic handling were spread across core and provider modules. | Providers own the unchanged retry budgets while neutral core utilities own bounded credential redaction. | | Stream cleanup could replace an already-mapped provider failure. | Cleanup records safe metadata and preserves the canonical failure, status, and diagnostic. | | An incomplete Responses tool could preempt a later provider failure. | Tool-finalization errors remain provisional so canonical provider failures take precedence. | | Readiness failures reused provider exception types. | Application-owned errors represent deterministic validation and availability phases without terminal retry headers. | | Legacy exception and recovery owners remained importable. | Obsolete modules are deleted without shims, architecture rules enforce the boundaries, and package version is 3.4.21. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR canonicalizes provider failure handling across the API boundary. The main changes are: - Adds protocol-neutral execution failure values and safe diagnostics. - Moves SDK and HTTP failure classification into provider-owned policy. - Lets Messages and Responses choose their own wire error payloads. - Preserves canonical failures across stream cleanup and committed stream failures. - Makes incomplete Responses tool errors provisional until finalization. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. No files need 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 API failure contract suite and related tests (tests/api/test\_execution\_failure\_contract.py, tests/core/test\_failure\_protocol\_mapping.py, tests/providers/test\_execution\_failure\_boundary.py, tests/providers/test\_failure\_policy.py); 48 passed in 3.36s. - Ran the streaming boundaries tests including response streams, stream recovery, and streaming errors; 70 passed in 5.36s. - Ran the OpenAI responses tests; 20 passed in 4.42s. <a href="https://app.greptile.com/trex/runs/14071383/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 | |----------|----------| | src/free_claude_code/providers/transports/http.py | Adds cleanup-safe stream closing that preserves established outcomes. | | src/free_claude_code/core/openai_responses/stream.py | Preserves canonical execution failures when committed Responses streams fail. | | src/free_claude_code/core/openai_responses/streaming/assembler.py | Keeps malformed tool-call errors provisional so later provider failures can win. | | src/free_claude_code/core/failures.py | Defines neutral failure kinds and exception-group lookup for execution failures. | </details> <sub>Reviews (2): Last reviewed commit: ["Preserve canonical outcomes in grouped a..."](https://github.com/alishahryar1/free-claude-code/commit/f57f21241dbe582985627ed4fb40734b2c656809) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43468297)</sub> <!-- /greptile_comment --> |
||
|
|
f8c21a48f2 |
Introduce a typed application boundary for provider execution (#1045)
## Problem The HTTP adapter owned model routing, provider execution, and runtime-facing contracts, so API handlers depended on provider implementation types. Provider preflight also discovered private request builders dynamically, obscuring the boundary that must fail before streaming begins. ## Changes | Before | After | | --- | --- | | `api/` owned model routing and shared provider execution. | `application/` owns routing and a settings-independent `ProviderExecutor`. | | API handlers accepted `BaseProvider` callbacks. | API handlers consume the narrow structural `ProviderPort`. | | `BaseProvider` discovered `_build_request_body` dynamically. | Both transport families implement explicit abstract preflight, with LM Studio composing context validation. | | Request leases, task control, and provider model metadata had adapter/provider owners. | Application-owned ports and immutable values define those cross-package contracts. | | Boundary direction was implicit. | Architecture contracts and documentation enforce the final dependency direction. | | Package version was `3.4.19`. | Package version is `3.4.20`, with the lockfile updated. | | Coverage followed the old module layout. | Deterministic boundary/preflight regressions and live Messages/Responses smokes cover the new shape. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR adds a typed application boundary for provider execution. The main changes are: - New `application` package for routing, execution, ports, and model metadata. - API handlers now call application-owned routing and provider execution. - Provider preflight is now explicit on the transport families. - Runtime API composition now uses a task-control port for `/stop`. - Import-boundary tests, smoke references, docs, version, and lockfile were updated. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues found in the changed code. None. <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 a deterministic pytest run for the provider boundary preflight, which completed with exit code 0 and 102 tests passing in 4.77 seconds. - Launched the environment presence check as part of the preflight, which completed with exit code 0 and confirmed OPENCODE\_API\_KEY=\[REDACTED\] matched. - Attempted the live provider smoke test, which completed with exit code 0 and 2 tests skipped due to incomplete smoke configuration. <a href="https://app.greptile.com/trex/runs/14067905/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 | |----------|----------| | src/free_claude_code/application/execution.py | Moves shared provider execution into the application layer and keeps eager preflight before token counting and streaming. | | src/free_claude_code/application/ports.py | Adds structural provider, request-runtime, and task-control protocols used across the new boundary. | | src/free_claude_code/api/routes.py | Updates route composition to use the application provider resolver and task-control stop path. | | src/free_claude_code/providers/base.py | Makes provider preflight explicit by requiring subclasses or transport bases to implement it. | | src/free_claude_code/providers/transports/openai_chat/transport.py | Adds OpenAI-chat preflight through the same request-body builder used by streaming. | | src/free_claude_code/providers/transports/anthropic_messages/transport.py | Adds native Messages preflight through the native request-body builder. | | src/free_claude_code/providers/model_listing.py | Keeps provider model-list parsing while moving `ProviderModelInfo` ownership to the application layer. | | src/free_claude_code/runtime/bootstrap.py | Passes the runtime object through the new `tasks` service slot. | | tests/contracts/test_import_boundaries.py | Extends import-boundary tests for the new application package. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart LR API[api handlers and routes] --> Routing[application.routing] API --> Executor[application.execution] API --> Ports[application.ports] Executor --> ProviderPort[ProviderPort] ProviderPort --> Preflight[preflight_stream] ProviderPort --> Stream[stream_response] Runtime[runtime bootstrap and provider manager] --> Ports Providers[providers] --> Metadata[application.model_metadata] Executor --> Core[core anthropic and trace] Routing --> Config[config settings and model refs] ``` </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"}}}%% flowchart LR API[api handlers and routes] --> Routing[application.routing] API --> Executor[application.execution] API --> Ports[application.ports] Executor --> ProviderPort[ProviderPort] ProviderPort --> Preflight[preflight_stream] ProviderPort --> Stream[stream_response] Runtime[runtime bootstrap and provider manager] --> Ports Providers[providers] --> Metadata[application.model_metadata] Executor --> Core[core anthropic and trace] Routing --> Config[config settings and model refs] ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["Introduce typed application boundary"](https://github.com/alishahryar1/free-claude-code/commit/4cdcf97231c812c6f568ca3d74af7ce759d7f2dc) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43462788)</sub> <!-- /greptile_comment --> |
||
|
|
4a0a0360de |
Move protocol models to their protocol owners (#1044)
## Problem Anthropic Messages and OpenAI Responses wire models lived under the inbound API adapter. Neutral protocol and provider code therefore duck-typed requests, obscuring ownership and weakening dependency boundaries. ## Changes | Before | After | | --- | --- | | The API package owned Anthropic and Responses protocol models. | Each protocol package owns and publicly exports its wire models. | | Core and provider request paths accepted `Any` and probed known fields with `getattr()`. | Core, transports, and providers consume concrete `MessagesRequest` values. | | Responses conversion and streaming received a dumped request mapping. | Responses conversion and streaming receive one concrete `OpenAIResponsesRequest`. | | Anthropic request snapshots lived in generic tracing code. | Anthropic request snapshots live with the protocol while generic tracing stays protocol-independent. | | Protocol tests and provider request doubles reflected the old API ownership. | Protocol tests live under core and provider tests construct real wire requests. | | The API model package mixed protocol and model-catalog schemas. | The API model package is removed, with catalog schemas beside catalog construction and no compatibility shim. | | Package version was `3.4.18`. | Package version is `3.4.19` with an updated lockfile. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR moves protocol request models to their protocol-owned packages. The main changes are: - Anthropic Messages models now live under `core.anthropic`. - OpenAI Responses models now live under `core.openai_responses`. - API handlers, routes, providers, and tests now use concrete protocol request types. - Anthropic request snapshots moved beside the Anthropic protocol models. - API model catalog schemas were kept with catalog response construction. - The package version and lockfile were updated. </details> <h3>Confidence Score: 5/5</h3> This looks safe to merge. No blocking issues were found in the changed code. Internal callers were updated to pass the new concrete protocol models, and no stale internal imports from the removed API model package were identified. No files need 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** - The Pytest run for protocol ownership focused tests completed, showing 71 passed in 6.24s and EXIT\_CODE: 0. - A protocol import smoke script was generated for the import/conversion/trace workflow. - The protocol import smoke run completed successfully, including model ownership output, adapter payload evidence, and trace snapshot evidence, with EXIT\_CODE: 0. <a href="https://app.greptile.com/trex/runs/14066157/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 | |----------|----------| | src/free_claude_code/core/anthropic/models.py | Anthropic wire request and response models moved under the Anthropic protocol package. | | src/free_claude_code/core/anthropic/native_messages_request.py | Native Anthropic serialization now expects concrete `MessagesRequest` instances. | | src/free_claude_code/core/anthropic/conversion.py | OpenAI chat conversion now reads fields directly from `MessagesRequest`. | | src/free_claude_code/core/anthropic/request_snapshot.py | Anthropic request snapshotting moved from generic tracing into the protocol package. | | src/free_claude_code/core/openai_responses/models.py | OpenAI Responses ingress models moved under the Responses protocol package. | | src/free_claude_code/core/openai_responses/input.py | Responses conversion now consumes the concrete request model instead of a dumped mapping. | | src/free_claude_code/core/openai_responses/streaming/assembler.py | Responses stream assembly now reads request attributes from `OpenAIResponsesRequest`. | | src/free_claude_code/api/routes.py | Routes now import protocol request models from their new core owners. | | src/free_claude_code/api/model_catalog.py | Model-list response schemas now live with model catalog construction. | </details> <details open><summary><h3>Flowchart</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart LR API[API routes and handlers] --> Anthropic[core.anthropic models and helpers] API --> Responses[core.openai_responses models and adapter] Responses --> Anthropic Providers[Provider clients and transports] --> Anthropic Anthropic --> Trace[core.trace sanitization] API --> Catalog[api.model_catalog response schemas] ``` </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"}}}%% flowchart LR API[API routes and handlers] --> Anthropic[core.anthropic models and helpers] API --> Responses[core.openai_responses models and adapter] Responses --> Anthropic Providers[Provider clients and transports] --> Anthropic Anthropic --> Trace[core.trace sanitization] API --> Catalog[api.model_catalog response schemas] ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["Move protocol models to their protocol o..."](https://github.com/alishahryar1/free-claude-code/commit/f1be5c1af4a10da710f80b5f9e7f6044a601f6af) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43459428)</sub> <!-- /greptile_comment --> |
||
|
|
4951983b5e |
Replace global runtime resources with explicit ownership (#1042)
## Problem Provider, messaging, and transcription resources relied on process-global state, leaving replacement, cancellation, and shutdown ownership ambiguous. Separate server lifetimes could share event-loop-bound resources or retain failed cleanup work. ## Changes | Before | After | | --- | --- | | Provider clients found limiters through global singleton and scoped registries. | Each provider instance receives and owns one explicitly constructed limiter. | | Messaging queues and voice pipelines relied on singleton or module-global state. | Each platform owns its limiter and outbox, while the application owns one injected transcriber. | | Messaging shutdown mixed ingress, active work, delivery, and SDK cleanup. | Application shutdown quiesces ingress, drains work, closes delivery, then releases transcription and providers. | | Cancelled or failed provider cleanup could be forgotten or treated as complete. | The provider manager retains shielded generation and unpublished-runtime cleanup until it succeeds. | | Discord and Telegram startup tasks could outlive or poison runtime readiness. | Platform runtimes observe long-lived tasks and retry only independently repeatable lifecycle steps. | | Constructor-captured security and diagnostic settings appeared hot-applicable. | Admin marks those settings restart-required so applied policy matches the running resource graph. | | Lifecycle races lacked direct ownership coverage. | Deterministic cancellation, retry, isolation, teardown, and live smoke contracts protect the final ownership model. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR moves runtime resources from global state into explicitly owned application objects. The main changes are: - Provider generations own their rate limiters and cleanup tasks. - Messaging platforms own their limiter, outbox, ingress, and delivery lifecycle. - Application shutdown now runs through ordered cleanup gates. - Voice transcription is injected as an owned runtime resource. - Admin config marks constructor-captured settings as restart-required. </details> <h3>Confidence Score: 4/5</h3> The shutdown path needs a bounded cleanup result before merging. Cleanup steps that hang never reach the retryable incomplete-shutdown path. ASGI shutdown can remain stuck while waiting for an external SDK, transcriber, workflow, or provider cleanup. The retry ownership model works only after cleanup returns or raises. src/free_claude_code/runtime/application.py <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** - T-Rex ran the requested verification, but its local artifact references were not uploaded. - The validation run completed successfully with EXIT\_CODE: 0 and 62 tests passed in 3.91 seconds, using the command uv run pytest -vv tests/runtime/test\_application\_runtime.py tests/runtime/test\_provider\_manager.py tests/providers/test\_provider\_runtime.py. <a href="https://app.greptile.com/trex/runs/14064214/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 | |----------|----------| | src/free_claude_code/runtime/application.py | Refactors shutdown into ordered retryable cleanup gates, but cleanup awaitables can still block shutdown forever. | | src/free_claude_code/runtime/asgi.py | Reports incomplete runtime shutdown when `close()` returns false. | | src/free_claude_code/runtime/provider_manager.py | Adds owned provider cleanup retry state and shielded generation cleanup. | </details> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22refactor%2Fruntime-owned-resources%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22refactor%2Fruntime-owned-resources%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fruntime%2Fapplication.py%3A59%0A**Cleanup%20Await%20Blocks%20Shutdown**%0A%0AWhen%20a%20platform%20SDK%20stop%2C%20workflow%20drain%2C%20transcriber%20close%2C%20or%20provider%20cleanup%20hangs%2C%20this%20helper%20waits%20forever%20and%20never%20returns%20%60False%60.%20ASGI%20shutdown%20stays%20stuck%20in%20%60runtime.close%28%29%60%20instead%20of%20reporting%20an%20incomplete%20shutdown%2C%20so%20the%20retained%20resource%20graph%20cannot%20be%20retried%20cleanly.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1042&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <sub>Reviews (2): Last reviewed commit: ["Report incomplete runtime shutdown to AS..."](https://github.com/alishahryar1/free-claude-code/commit/338b2bd179c3875b15bbd52818dd04c780e5d46d) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=43454593)</sub> > Greptile also left **1 inline comment** on this PR. **Context used:** - Context used - CLAUDE.md ([source](https://app.greptile.com/alishahryar1/github/Alishahryar1/free-claude-code/-/custom-context?memory=d2fd24d8-0dec-4faf-8ee4-e085e215a2f8)) <!-- /greptile_comment --> |