main
9 次代码提交
| 作者 | SHA1 | 备注 | 提交日期 | |
|---|---|---|---|---|
|
|
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 --> |
||
|
|
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 --> |
||
|
|
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 --> |
||
|
|
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 --> |
||
|
|
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 --> |
||
|
|
71a78a0c5a |
Move runtime packages under src namespace (#1029)
## Problem Runtime modules were published as generic top-level packages like `api`, `cli`, and `providers`. That shape is fragile for PyPI packaging and weakens explicit ownership boundaries. ## Changes | Before | After | | --- | --- | | Runtime code lived in root-level packages. | Runtime code lives under `src/free_claude_code/`. | | Console scripts targeted top-level modules. | Console scripts target namespaced modules. | | Tests and smoke helpers imported old package roots. | Tests and smoke helpers import `free_claude_code.*`. | | Packaging listed six root packages. | Packaging builds the single namespaced package. | | Contracts allowed old root package directories. | Contracts require the src namespace and reject old root imports. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR moves the runtime packages into the `src/free_claude_code` namespace. The main changes are: - Console scripts now point to `free_claude_code.*` entrypoints. - Runtime imports, tests, and smoke helpers now use the namespaced package. - Packaging now builds the single `src/free_claude_code` package. - Contract tests now reject old top-level runtime package roots and imports. </details> <h3>Confidence Score: 5/5</h3> This PR is safe to merge with minimal risk. The changes are a broad but mostly mechanical namespace and package-layout migration with updated packaging, tests, and contract coverage. 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** - Reviewed the primary contract validation by examining the namespace validation log, which documents the exact commands executed, the working directory, exit codes, pytest output, wheel build output, install output, and import/entrypoint resolution. - Verified the wheel listing by inspecting the wheel listing artifact, confirming the available wheel filenames for the namespace validation. - Ran and inspected the isolated import/entrypoint validation harness saved as package-installed-import-check.py to validate import resolution and entrypoint exposure. - Captured and noted the wheel filename record in package-wheel-filename.txt to enable traceability of the observed artifact. <a href="https://app.greptile.com/trex/runs/13810533/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 | |----------|----------| | pyproject.toml | Updates packaging to build the single `src/free_claude_code` package and retargets console scripts to namespaced modules. | | src/free_claude_code/config/env_template.py | Loads `.env.example` from packaged resources with a source-checkout fallback after the runtime package move. | | src/free_claude_code/cli/entrypoints.py | Updates CLI entrypoint imports to `free_claude_code.*` and continues to use the shared env template loader. | | src/free_claude_code/api/routes.py | Retargets API route dependencies and handlers to the namespaced package without changing route behavior. | | src/free_claude_code/api/app.py | Updates app factory imports to the namespaced package while preserving middleware, routers, and exception handling. | | src/free_claude_code/providers/runtime/factory.py | Updates lazy provider factory imports to `free_claude_code.providers.*` under the new package layout. | | tests/contracts/test_import_boundaries.py | Adds contract coverage requiring runtime packages to live under `src/free_claude_code` and rejecting old top-level imports. | | smoke/lib/child_process.py | Updates smoke child-process helpers to import CLI entrypoints from the namespaced package. | | README.md | Updates the project layout and extension guidance to refer to `src/free_claude_code` and importable `free_claude_code.*` modules. | | uv.lock | Reflects the package version bump associated with the runtime packaging move. | </details> <details open><summary><h3>Sequence Diagram</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% sequenceDiagram participant User as User / CLI participant Script as Console script participant Pkg as free_claude_code package participant API as free_claude_code.api participant Runtime as free_claude_code.providers.runtime participant Provider as Provider adapter User->>Script: run fcc-server / free-claude-code Script->>Pkg: load free_claude_code.cli.entrypoints:serve Pkg->>API: create FastAPI app and routes API->>Runtime: resolve configured provider Runtime->>Provider: instantiate namespaced adapter Provider-->>Runtime: stream/model responses Runtime-->>API: provider result API-->>User: Anthropic/OpenAI-compatible response ``` </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 / CLI participant Script as Console script participant Pkg as free_claude_code package participant API as free_claude_code.api participant Runtime as free_claude_code.providers.runtime participant Provider as Provider adapter User->>Script: run fcc-server / free-claude-code Script->>Pkg: load free_claude_code.cli.entrypoints:serve Pkg->>API: create FastAPI app and routes API->>Runtime: resolve configured provider Runtime->>Provider: instantiate namespaced adapter Provider-->>Runtime: stream/model responses Runtime-->>API: provider result API-->>User: Anthropic/OpenAI-compatible response ``` </a> </details> <sub>Reviews (2): Last reviewed commit: ["Fix documented package import paths"](https://github.com/alishahryar1/free-claude-code/commit/bfa9f2704c45f3684da39657d5e13f3814e5d450) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=42950471)</sub> <!-- /greptile_comment --> |
||
|
|
755a3851f7 |
Use batch delete boundary for messaging (#996)
## Problem Messaging cleanup had two public queued delete paths. Command code could loop single-message deletes and bypass Telegram batch deletion. ## Changes | Before | After | | --- | --- | | Workflow code could call `queue_delete_message` or `queue_delete_messages`. | Workflow code calls only `queue_delete_messages`. | | Telegram `/clear` cleanup used one API request per message. | Telegram `/clear` cleanup uses `deleteMessages` in chunks of 100. | | The outbox dedupe key used Python process hashing. | The outbox dedupe key uses a stable SHA-based digest. | | Voice and smoke cleanup depended on the single-delete queue API. | Voice and smoke cleanup pass one-item delete lists. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR moves messaging cleanup to a list-based delete boundary. The main changes are: - `/clear` now sends collected message IDs through `queue_delete_messages`. - Telegram deletion uses `deleteMessages` in 100-message chunks with per-message fallback. - Discord keeps per-message deletion behind the list-based outbound API. - Delete-batch dedupe keys now use a stable SHA digest instead of Python process hashing. - Voice cleanup, smoke fakes, protocol tests, and messaging tests were updated for the new delete boundary. </details> <h3>Confidence Score: 5/5</h3> Safe to merge with minimal risk. The change is well-scoped to the messaging delete boundary, keeps platform-specific best-effort behavior, addresses the batch-fallback concern, updates protocol consumers and tests, and includes the required version and lockfile bump. 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** - No execution evidence is available for this session; no harness was created, no tests were run, and no artifacts were produced. <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 | |----------|----------| | messaging/commands.py | Routes `/clear` cleanup through `queue_delete_messages` once per collected message set while preserving best-effort state cleanup. | | messaging/platforms/outbox.py | Removes single-delete queueing, snapshots delete batches, and uses a stable SHA digest for delete dedupe keys. | | messaging/platforms/telegram_io.py | Adds Telegram `deleteMessages` batching with 100-message chunks and per-message fallback when batch deletion fails. | | messaging/platforms/discord_io.py | Removes the public single queued-delete wrapper and backs queued deletion with the list-based outbox API. | | messaging/platforms/voice_flow.py | Changes shared voice cleanup call sites to submit one-item lists to the delete queue. | | messaging/platforms/ports.py | Narrows the outbound protocol to the list-based delete queue method. | | tests/messaging/test_telegram.py | Adds Telegram batch delete, chunking, and fallback coverage. | | tests/messaging/test_platform_outbox.py | Covers stable delete-batch dedupe keys and snapshotting mutable message ID lists before queueing. | | pyproject.toml | Bumps the package patch version for the production messaging changes. | | uv.lock | Updates the editable package version in the lockfile to match `pyproject.toml`. | </details> <details open><summary><h3>Sequence Diagram</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Command as /clear or voice cleanup participant Outbound as OutboundMessenger.queue_delete_messages participant Outbox as PlatformOutbox participant Telegram as TelegramMessenger participant Discord as DiscordMessenger participant API as Platform API Command->>Outbound: queue_delete_messages(chat_id, message_ids) Outbound->>Outbox: snapshot IDs and dedupe batch alt Telegram Outbox->>Telegram: delete_messages(chat_id, ids) loop chunks of 100 Telegram->>API: deleteMessages(chat_id, chunk) alt batch fails Telegram->>API: deleteMessage(chat_id, each id) end end else Discord Outbox->>Discord: delete_messages(chat_id, ids) loop each id Discord->>API: fetch_message + delete end 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 Command as /clear or voice cleanup participant Outbound as OutboundMessenger.queue_delete_messages participant Outbox as PlatformOutbox participant Telegram as TelegramMessenger participant Discord as DiscordMessenger participant API as Platform API Command->>Outbound: queue_delete_messages(chat_id, message_ids) Outbound->>Outbox: snapshot IDs and dedupe batch alt Telegram Outbox->>Telegram: delete_messages(chat_id, ids) loop chunks of 100 Telegram->>API: deleteMessages(chat_id, chunk) alt batch fails Telegram->>API: deleteMessage(chat_id, each id) end end else Discord Outbox->>Discord: delete_messages(chat_id, ids) loop each id Discord->>API: fetch_message + delete end end ``` </a> </details> <sub>Reviews (2): Last reviewed commit: ["Preserve Telegram batch delete fallback"](https://github.com/alishahryar1/free-claude-code/commit/87090edcd95c4014cae37c2f540d9bfa4eba8962) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=41993526)</sub> <!-- /greptile_comment --> |
||
|
|
d4683bf3f6 |
Add Hugging Face inference provider (#985)
## Problem FCC did not expose Hugging Face Inference Providers as a selectable backend. Voice transcription also used the legacy `HF_TOKEN` setting instead of the canonical Hugging Face API key. ## Changes | Before | After | | --- | --- | | Hugging Face models could not be selected through provider-prefixed routing. | Hugging Face routes through a thin OpenAI-chat provider using `huggingface/<model>`. | | Provider credentials did not include `HUGGINGFACE_API_KEY`. | Admin config, settings, smoke config, and docs use `HUGGINGFACE_API_KEY`. | | `HF_TOKEN` remained a voice-only config key. | Owned dotenv files migrate `HF_TOKEN` to `HUGGINGFACE_API_KEY`, while explicit `FCC_ENV_FILE` users get a warning. | | Version metadata stayed on `2.6.0`. | Version metadata moves to `3.0.0` with a refreshed lockfile. | <!-- greptile_comment --> <details open><summary><h3>Greptile Summary</h3></summary> This PR adds Hugging Face Inference Providers as a selectable backend. The main changes are: - Adds a `huggingface` provider using the shared OpenAI-compatible chat transport. - Wires `HUGGINGFACE_API_KEY` and `HUGGINGFACE_PROXY` through settings, Admin UI, provider catalog, runtime factory, and smoke config. - Migrates owned dotenv files from `HF_TOKEN` to `HUGGINGFACE_API_KEY` and warns for explicit `FCC_ENV_FILE` users. - Updates voice transcription plumbing to use the canonical Hugging Face key. - Updates docs, examples, version metadata, lockfile, and related tests. </details> <h3>Confidence Score: 5/5</h3> Safe to merge with minimal risk. No blocking correctness or security issues were identified. The new provider reuses the existing OpenAI-chat transport pattern. Provider wiring, env migration, Admin UI, smoke config, voice plumbing, and tests are consistent. 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 Pytest suite for providers, runtime, env migrations, config, and contract tests ran and completed with exit code 0 and 198 tests passed. - The HuggingFace runtime validator script ran and completed successfully, printing provider\_class=HuggingFaceProvider, default\_base\_url=https://router.huggingface.co/v1, credential\_env=HUGGINGFACE\_API\_KEY, and admin\_field=HUGGINGFACE\_API\_KEY:\[REDACTED\]. - Logs from both runs were captured as artifacts to aid review. <a href="https://app.greptile.com/trex/runs/13308618/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 | |----------|----------| | providers/huggingface/client.py | Implements Hugging Face via the shared OpenAI-chat transport with `extra_body` passthrough. | | config/provider_catalog.py | Registers Hugging Face metadata, default router URL, credential, proxy, and capabilities. | | providers/runtime/factory.py | Wires Hugging Face into runtime provider construction. | | config/env_migrations.py | Adds safe `HF_TOKEN` to `HUGGINGFACE_API_KEY` dotenv migration helpers for owned env files. | | config/settings.py | Adds Hugging Face API key/proxy settings and removes the legacy `hf_token` setting. | | api/admin_config/manifest.py | Removes the voice-only `HF_TOKEN` field and adds Hugging Face smoke model configuration. | | api/admin_config/provider_manifest.py | Adds Admin UI labeling and description for `HUGGINGFACE_API_KEY`. | | messaging/transcription.py | Renames local Whisper token handling to use the canonical Hugging Face API key. | | smoke/lib/config.py | Adds Hugging Face smoke-test default model and credential detection. | | tests/providers/test_huggingface.py | Adds provider tests for Hugging Face base URL, request body policy, streaming, and cleanup. | </details> <details open><summary><h3>Sequence Diagram</h3></summary> <a href="#gh-light-mode-only"> ```mermaid %%{init: {'theme': 'neutral'}}%% sequenceDiagram participant User as Admin/User participant Settings as Settings + dotenv migration participant Catalog as Provider Catalog participant Runtime as Provider Runtime Factory participant HF as HuggingFaceProvider participant Router as router.huggingface.co/v1 User->>Settings: "Configure MODEL=huggingface/<model> and HUGGINGFACE_API_KEY" Settings->>Settings: Rename owned HF_TOKEN to HUGGINGFACE_API_KEY when present Settings->>Catalog: Resolve huggingface descriptor and credential/proxy attrs Catalog->>Runtime: Build ProviderConfig for huggingface Runtime->>HF: Create HuggingFaceProvider HF->>Router: Stream OpenAI-compatible chat completion Router-->>HF: Streaming chunks HF-->>User: Anthropic SSE response ``` </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 Admin/User participant Settings as Settings + dotenv migration participant Catalog as Provider Catalog participant Runtime as Provider Runtime Factory participant HF as HuggingFaceProvider participant Router as router.huggingface.co/v1 User->>Settings: "Configure MODEL=huggingface/<model> and HUGGINGFACE_API_KEY" Settings->>Settings: Rename owned HF_TOKEN to HUGGINGFACE_API_KEY when present Settings->>Catalog: Resolve huggingface descriptor and credential/proxy attrs Catalog->>Runtime: Build ProviderConfig for huggingface Runtime->>HF: Create HuggingFaceProvider HF->>Router: Stream OpenAI-compatible chat completion Router-->>HF: Streaming chunks HF-->>User: Anthropic SSE response ``` </a> </details> <sub>Reviews (1): Last reviewed commit: ["Add Hugging Face inference provider"](https://github.com/alishahryar1/free-claude-code/commit/7341d9a923986ac84d5e4fdf858128f913f3e5d3) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=41885587)</sub> <!-- /greptile_comment --> |
||
|
|
92488456bc |
Refactor messaging platform bridge (#858)
## Summary - Extract shared messaging platform outbox for queued send/edit/delete, dedup keys, limiter delegation, and fire-and-forget behavior - Extract shared voice-note flow for pending voice state, transcription, cancellation, cleanup, error replies, and IncomingMessage handoff - Keep Telegram and Discord adapters focused on SDK lifecycle, event extraction, attachment download, and raw send/edit/delete calls - Document the split in ARCHITECTURE.md and bump version to 2.3.8 ## Verification - uv run pytest tests/messaging/test_platform_outbox.py tests/messaging/test_platform_voice_flow.py tests/messaging/test_voice_handlers.py tests/messaging/test_telegram.py tests/messaging/test_telegram_edge_cases.py tests/messaging/test_discord_platform.py tests/contracts/test_import_boundaries.py tests/contracts/test_architecture_contracts.py - .\\scripts\\ci.ps1 |