Skip to content

release: v1.1.7 — live model discovery for all providers#125

Open
Christiantyemele wants to merge 6 commits into
mainfrom
release/v1.1.7
Open

release: v1.1.7 — live model discovery for all providers#125
Christiantyemele wants to merge 6 commits into
mainfrom
release/v1.1.7

Conversation

@Christiantyemele

Copy link
Copy Markdown
Collaborator

Changes

Live model discovery for all providers (no more hardcoded lists)

Fireworks

  • Paginate /inference/v1/models with limit=200 and cursor-based pagination (after param + has_more) to discover all models, not just the first 50
  • 30s HTTP timeout (was unlimited, could hang)
  • Structured error logging (tracing::warn! / tracing::debug!) for network, HTTP, and JSON parse errors
  • Content-Type header added
  • Filter now accepts all accounts/fireworks/models/ prefixed models (the endpoint already returns only inference-ready models), with exclusion for clearly non-chat families (embedding, whisper, tts, dall-e, flux, etc.)
  • Minimal 2-model hardcoded fallback only when API is completely unreachable

Anthropic

  • Paginate /v1/models with limit=1000 and after_id cursor
  • 30s timeout and structured error logging (previously had no timeout, silent failures)
  • Removed the old discover_claude_models() wrapper with 4 hardcoded 2024-era models
  • New flow: Anthropic API → Claude CLI → minimal 2-model discover_known_anthropic_models() fallback

OpenAI

  • Request /v1/models?limit=500 for full model list
  • Structured error handling (network/HTTP/parse errors each logged and reported separately)
  • Previously returned bare Err("No OpenAI API key configured") with no fallback — now has Codex CLI → OpenAI API → minimal 2-model discover_known_openai_models()

Default model update

  • Updated default Fireworks model from llama-v3p1-8b-instruct to deepseek-v3p1 across all files

Tests

  • Added test_discover_known_anthropic_models
  • Added test_discover_known_openai_models
  • Updated test_is_fireworks_chat_model for new prefix-based filter
  • Updated test_discover_known_fireworks_models for reduced fallback
  • Updated test_default_model_for_provider for new default

- Fireworks: paginate /inference/v1/models (limit=200, cursor-based),
  30s timeout, structured error logging, accept all
  accounts/fireworks/models/ prefixed models, minimal 2-model fallback
- Anthropic: paginate /v1/models (limit=1000, after_id cursor),
  30s timeout, structured error logging, minimal 2-model fallback
- OpenAI: request /v1/models with limit=500, structured error handling,
  minimal 2-model fallback (previously returned bare error)
- All providers: graceful degradation chain (API → CLI → hardcoded
  fallback with tracing::warn), no more silent failures
- Update default Fireworks model from llama-v3p1-8b-instruct to
  deepseek-v3p1 across fireworks.rs, fallback.rs, mod.rs, process.rs
- Add 3 new unit tests for fallback lists (Anthropic, OpenAI, Fireworks)
Comment thread crates/agentflow-tui/src/setup/model_discovery.rs
Comment thread crates/agentflow-tui/src/setup/model_discovery.rs
Comment thread crates/agentflow-tui/src/setup/model_discovery.rs
AgentFlow added 2 commits June 22, 2026 11:14
… error logging

The OpenAI-compatible /inference/v1/models endpoint does not support
the ?limit= query parameter — that's only for the native
/v1/accounts/{account_id}/models API. Adding it may cause unexpected
responses or empty results, which explains why live discovery was
failing and only the hardcoded fallback was shown.

Also adds detailed tracing::warn! for every failure path in the
Fireworks discovery so the exact error is visible in logs.
… discovery

The OpenAI-compatible /inference/v1/models endpoint returns HTTP 500
'Error listing deployed models' — it's broken on Fireworks' side.

Switched to the native Fireworks API which:
- Uses /v1/accounts/fireworks/models?pageSize=200 with pageToken pagination
- Returns rich model metadata (supportsServerless, contextLength, supportsTools, supportsImageInput, displayName)
- Filters for serverless models with contextLength > 0 (excludes image gen, embeddings, rerankers)
- Falls back to the OpenAI-compat endpoint if the native API returns an error
- Shows context length, tool support, and vision capability in descriptions
Comment thread crates/agentflow-tui/src/setup/model_discovery.rs Outdated
@github-actions

Copy link
Copy Markdown

Snif Review

This change replaces hardcoded model lists with live API-based model discovery for Anthropic, OpenAI, and Fireworks providers, adding pagination, 30s HTTP timeouts, structured error logging, and minimal hardcoded fallbacks. It also updates the default Fireworks model from llama-v3p1-8b-instruct to deepseek-v3p1.

No issues found. Change looks clean.

Review details

Changed files:

  • Cargo.lock
  • binary/Cargo.toml
  • crates/agent-client/src/fallback.rs
  • crates/agent-client/src/fireworks.rs
  • crates/agentflow-tui/src/setup/mod.rs
  • crates/agentflow-tui/src/setup/model_discovery.rs
  • crates/pair-harness/src/process.rs

Context analyzed: 99 related files (26 via semantic similarity, 99 via keyword matching).

Stats: 1000 lines | glm-5p1 | 89s

The TUI appeared to freeze after entering the API key because
discover_models() was called before any UI was drawn. Now shows
a 'Discovering available models...' message with the provider name
while the HTTP request is in flight.
@github-actions

Copy link
Copy Markdown

Snif Review

This change replaces hardcoded model lists with live API-based model discovery for Anthropic, OpenAI, and Fireworks providers, adding pagination, timeouts, structured error logging, and minimal fallback lists. It also updates the default Fireworks model from llama-v3p1-8b-instruct to deepseek-v3p1 and adds a loading screen during model discovery in the TUI setup.

No issues found. Change looks clean.

Review details

Changed files:

  • Cargo.lock
  • binary/Cargo.toml
  • crates/agent-client/src/fallback.rs
  • crates/agent-client/src/fireworks.rs
  • crates/agentflow-tui/src/setup/mod.rs
  • crates/agentflow-tui/src/setup/model_discovery.rs
  • crates/agentflow-tui/src/setup/step_agents.rs
  • crates/pair-harness/src/process.rs

Context analyzed: 99 related files (25 via semantic similarity, 99 via keyword matching).

Stats: 1060 lines | glm-5p1 | 93s

- Add max page limit (5 pages) and 60s overall timeout for Fireworks native API
- Add connect_timeout (10s) to all HTTP clients
- Filter empty nextPageToken strings that would cause infinite loops
- Return partial results on timeout/API error instead of failing entirely
- Add max pages to Anthropic and OpenAI-compat pagination too
- Fix indentation issue in discover_openai_models (removed stray loop)
@github-actions

Copy link
Copy Markdown

Snif Review

This change replaces hardcoded model lists with live API-based model discovery for Anthropic, OpenAI, and Fireworks providers, adding pagination, timeouts, structured error logging, and minimal fallback lists. It also updates the default Fireworks model from llama-v3p1-8b-instruct to deepseek-v3p1 and adds a loading screen in the TUI setup flow.

No issues found. Change looks clean.

Review details

Changed files:

  • Cargo.lock
  • binary/Cargo.toml
  • crates/agent-client/src/fallback.rs
  • crates/agent-client/src/fireworks.rs
  • crates/agentflow-tui/src/setup/mod.rs
  • crates/agentflow-tui/src/setup/model_discovery.rs
  • crates/agentflow-tui/src/setup/step_agents.rs
  • crates/pair-harness/src/process.rs

Context analyzed: 99 related files (25 via semantic similarity, 99 via keyword matching).

Stats: 1117 lines | glm-5p1 | 94s

Comment on lines +294 to +308
fn ensure_default_branch_via_orphan_checkout(&self) -> Result<()> {
// Save current HEAD so we can restore it after creating the branch
let saved_head = Command::new("git")
.args(["rev-parse", "HEAD"])
.current_dir(&self.project_root)
.output()
.ok()
.and_then(|o| {
if o.status.success() {
Some(String::from_utf8_lossy(&o.stdout).trim().to_string())
} else {
None
}
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: Orphan-checkout fallback mutates main repo & leaves detached HEAD

ensure_default_branch_via_orphan_checkout runs git checkout --orphan, git rm -rf --cached ., and git commit directly in self.project_root — the primary repository working tree/index, not an isolated worktree. Two concrete problems:

  1. Detached HEAD after restore: saved_head is captured via git rev-parse HEAD, which is a commit SHA. restore_head then runs git checkout <sha>, which leaves the project root in a detached HEAD state rather than back on the original branch (e.g. main). Subsequent git operations on the project root then operate on a detached HEAD.

  2. Checkout-back can fail: after git rm -rf --cached . the working-tree files become untracked. git checkout <sha> can abort with "would be overwritten by checkout" when those untracked files conflict, leaving the repo stuck on the orphan branch with an empty index.

Because this runs in the shared project root (and create_worktree may be invoked for multiple pairs against the same root — see pair.rs:1119), a failure here corrupts state for all agents. The safer commit-tree path is tried first, but the fallback is still reachable. Consider performing branch creation entirely via plumbing (commit-tree + push) and never touching HEAD/index, or capturing the original ref with git symbolic-ref --short HEAD (falling back to the SHA) and restoring that, plus using git checkout -f / stashing to avoid the untracked-file abort.

Restore the original branch name instead of a detached SHA.:

// Capture the symbolic ref name when on a branch, else the SHA.
let saved_head = Command::new("git")
    .args(["symbolic-ref", "--short", "-q", "HEAD"])
    .current_dir(&self.project_root)
    .output().ok()
    .filter(|o| o.status.success())
    .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
    .filter(|s| !s.is_empty())
    .or_else(|| /* fall back to rev-parse HEAD as before */ saved_head_sha());
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Comment on lines +393 to +396
let _ = Command::new("git")
.args(["branch", "-d", &self.default_branch])
.current_dir(&self.project_root)
.output();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Bug: Orphan branch cleanup uses git branch -d and will fail

After creating and pushing the orphan default branch, cleanup runs git branch -d <default_branch>. The orphan branch's commit is not merged into any other branch, so -d (safe delete) refuses to delete it ("not fully merged"), leaving a stray local branch ref behind. If the intent is to always remove the temporary local ref, use -D (force delete). Note this is only reached after HEAD has been restored, so deleting the checked-out branch is not a concern.

Force-delete the temporary local orphan branch ref.:

let _ = Command::new("git")
    .args(["branch", "-D", &self.default_branch])
    .current_dir(&self.project_root)
    .output();
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Comment on lines +258 to +272
// Push the commit as the default branch to origin
let push_output = Command::new("git")
.args([
"push",
"origin",
&format!("{}:refs/heads/{}", commit_hash, self.default_branch),
])
.current_dir(&self.project_root)
.output();

match push_output {
Ok(o) if o.status.success() => {
info!(branch = %self.default_branch, "Default branch created on remote via commit-tree");
}
Ok(o) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Bug: Default-branch push from project_root may lack token auth

Both ensure_default_branch_via_commit_tree and ensure_default_branch_via_orphan_checkout run git push origin ... in self.project_root. Token-based remote authentication is only applied to worktrees via configure_remote_with_token (and the github_token is not even passed into ensure_default_branch_on_remote). If the project root's origin URL is a plain https://github.com/... without an embedded x-access-token, these pushes will fail authentication, so the default branch is never created and the feature silently degrades (only a SetupWarning is emitted). Consider configuring the project-root remote with the token (as is done for worktrees) before pushing, or passing the github_token through and using an authenticated push URL.

Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented Jun 22, 2026

Copy link
Copy Markdown
CI failed: The CI build failed because the code does not conform to the project's rustfmt standards, specifically due to unformatted changes in the agent-client and TUI modules.

Overview

The CI pipeline failed in the 'Format' job because the submitted code does not match the repository's rustfmt style configuration. The logs confirm that multiple files were detected with formatting differences during the cargo fmt --check step.

Failures

Rustfmt Violation (confidence: high)

  • Type: build
  • Affected jobs: 82763169599
  • Related to change: yes
  • Root cause: The source code in crates/agent-client/src/runner.rs and crates/agentflow-tui/src/setup/model_discovery.rs contains formatting inconsistencies, including improperly wrapped tracing macro arguments and function calls that violate the defined project style.
  • Suggested fix: Run cargo fmt --all in your local development environment to automatically apply the required formatting, then commit and push the changes.

Summary

  • Change-related failures: 1 (Format check violation)
  • Infrastructure/flaky failures: 0
  • Recommended action: Execute cargo fmt --all locally, verify that cargo fmt --check passes, and push the resulting commit to the branch.
Code Review ⚠️ Changes requested 4 resolved / 7 findings

Implements live model discovery for Fireworks, Anthropic, and OpenAI while resolving pagination loops and hardcoded fallback issues. Changes are requested due to critical side effects in ensure_default_branch_via_orphan_checkout that mutate the main repository and leave it in a detached HEAD state.

⚠️ Bug: Orphan-checkout fallback mutates main repo & leaves detached HEAD

📄 crates/pair-harness/src/worktree.rs:294-308

ensure_default_branch_via_orphan_checkout runs git checkout --orphan, git rm -rf --cached ., and git commit directly in self.project_root — the primary repository working tree/index, not an isolated worktree. Two concrete problems:

  1. Detached HEAD after restore: saved_head is captured via git rev-parse HEAD, which is a commit SHA. restore_head then runs git checkout <sha>, which leaves the project root in a detached HEAD state rather than back on the original branch (e.g. main). Subsequent git operations on the project root then operate on a detached HEAD.

  2. Checkout-back can fail: after git rm -rf --cached . the working-tree files become untracked. git checkout <sha> can abort with "would be overwritten by checkout" when those untracked files conflict, leaving the repo stuck on the orphan branch with an empty index.

Because this runs in the shared project root (and create_worktree may be invoked for multiple pairs against the same root — see pair.rs:1119), a failure here corrupts state for all agents. The safer commit-tree path is tried first, but the fallback is still reachable. Consider performing branch creation entirely via plumbing (commit-tree + push) and never touching HEAD/index, or capturing the original ref with git symbolic-ref --short HEAD (falling back to the SHA) and restoring that, plus using git checkout -f / stashing to avoid the untracked-file abort.

Restore the original branch name instead of a detached SHA.
// Capture the symbolic ref name when on a branch, else the SHA.
let saved_head = Command::new("git")
    .args(["symbolic-ref", "--short", "-q", "HEAD"])
    .current_dir(&self.project_root)
    .output().ok()
    .filter(|o| o.status.success())
    .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
    .filter(|s| !s.is_empty())
    .or_else(|| /* fall back to rev-parse HEAD as before */ saved_head_sha());
💡 Bug: Orphan branch cleanup uses git branch -d and will fail

📄 crates/pair-harness/src/worktree.rs:393-396

After creating and pushing the orphan default branch, cleanup runs git branch -d <default_branch>. The orphan branch's commit is not merged into any other branch, so -d (safe delete) refuses to delete it ("not fully merged"), leaving a stray local branch ref behind. If the intent is to always remove the temporary local ref, use -D (force delete). Note this is only reached after HEAD has been restored, so deleting the checked-out branch is not a concern.

Force-delete the temporary local orphan branch ref.
let _ = Command::new("git")
    .args(["branch", "-D", &self.default_branch])
    .current_dir(&self.project_root)
    .output();
💡 Bug: Default-branch push from project_root may lack token auth

📄 crates/pair-harness/src/worktree.rs:258-272 📄 crates/pair-harness/src/worktree.rs:357-371

Both ensure_default_branch_via_commit_tree and ensure_default_branch_via_orphan_checkout run git push origin ... in self.project_root. Token-based remote authentication is only applied to worktrees via configure_remote_with_token (and the github_token is not even passed into ensure_default_branch_on_remote). If the project root's origin URL is a plain https://github.com/... without an embedded x-access-token, these pushes will fail authentication, so the default branch is never created and the feature silently degrades (only a SetupWarning is emitted). Consider configuring the project-root remote with the token (as is done for worktrees) before pushing, or passing the github_token through and using an authenticated push URL.

✅ 4 resolved
Bug: claude CLI backend lost its hardcoded model fallback

📄 crates/agentflow-tui/src/setup/model_discovery.rs:87-93 📄 crates/agentflow-tui/src/setup/model_discovery.rs:342-356
discover_backend_models("claude") now calls discover_claude_models_from_cli() directly (line 90), which returns Err when the claude CLI is missing or produces no parseable models. The removed discover_claude_models() previously supplied a 4-model hardcoded fallback in this path. This _ arm is reached when selected_provider does not match Anthropic/OpenAI/Fireworks but the CLI backend is claude. The impact is mitigated because the caller in step_agents.rs catches the error and substitutes a single default_model_for_provider entry, but the user now sees only one model instead of the previous list. Confirm this degraded behavior is intended for the non-provider-selected path.

Quality: Fireworks prefix filter denylist may surface non-chat models

📄 crates/agentflow-tui/src/setup/model_discovery.rs:666-680
is_fireworks_chat_model now accepts any accounts/fireworks/models/ model unless it matches a fixed denylist (embedding/whisper/tts/dall-e/flux/stable-diffusion/sd3/clip/audio). This relies on the endpoint pre-filtering to inference-ready models, but Fireworks hosts other non-chat families (e.g. rerankers, vision/image generation with names not in the denylist) that would now pass the filter and be offered as chat models. Since the previous allowlist (instruct/chat) was replaced by a denylist, any new or unlisted non-chat family will leak through. Consider keeping a positive heuristic or expanding the denylist, and verify against the actual model list returned by the account.

Edge Case: Native Fireworks pagination may loop forever on empty pageToken

📄 crates/agentflow-tui/src/setup/model_discovery.rs:658-668
In the new native discovery loop, the next page is determined by:

let next_token = json.get("nextPageToken").and_then(|v| v.as_str()).map(String::from);
if next_token.is_none() || model_array.is_empty() { break; }
page_token = next_token;

The loop only terminates when nextPageToken is absent (is_none()). Fireworks' control-plane API follows Google AIP-158 semantics where the last page is signalled by an empty-string nextPageToken rather than an absent field. If the API ever serializes "nextPageToken": "", as_str() returns Some(""), so next_token.is_none() is false and the loop continues, issuing ...&pageToken= (empty) which typically returns the first page again — an infinite loop that re-fetches every 30s with no upper bound. The Anthropic and OpenAI-compat variants avoid this by gating on a has_more boolean. Treat an empty token the same as a missing one, and/or add a max-iteration guard.

Edge Case: Paginated loops lack max-iteration/dedup safeguard

📄 crates/agentflow-tui/src/setup/model_discovery.rs:222-236 📄 crates/agentflow-tui/src/setup/model_discovery.rs:518-532
Both discover_anthropic_models and discover_fireworks_models loop until has_more is false, advancing a cursor set from the last model's id. If the endpoint reports has_more: true but ignores the after/after_id cursor (returning the same page), the loop never terminates — the per-request 30s timeout does not bound total iterations. The Fireworks /inference/v1/models endpoint's support for cursor pagination is uncertain (OpenAI-compatible /v1/models typically returns all data with no has_more), so an unexpected response shape could spin indefinitely. There is also no de-duplication if pages overlap (cursor inclusive). Consider adding a max-page/iteration cap and breaking if the new cursor equals the previous one.

Sources: crates/agentflow-tui/src/setup/model_discovery.rs:222-297,518-616

🤖 Prompt for agents
Code Review: Implements live model discovery for Fireworks, Anthropic, and OpenAI while resolving pagination loops and hardcoded fallback issues. Changes are requested due to critical side effects in `ensure_default_branch_via_orphan_checkout` that mutate the main repository and leave it in a detached HEAD state.

1. ⚠️ Bug: Orphan-checkout fallback mutates main repo & leaves detached HEAD
   Files: crates/pair-harness/src/worktree.rs:294-308

   `ensure_default_branch_via_orphan_checkout` runs `git checkout --orphan`, `git rm -rf --cached .`, and `git commit` directly in `self.project_root` — the primary repository working tree/index, not an isolated worktree. Two concrete problems:
   
   1. Detached HEAD after restore: `saved_head` is captured via `git rev-parse HEAD`, which is a commit SHA. `restore_head` then runs `git checkout <sha>`, which leaves the project root in a *detached HEAD* state rather than back on the original branch (e.g. `main`). Subsequent git operations on the project root then operate on a detached HEAD.
   
   2. Checkout-back can fail: after `git rm -rf --cached .` the working-tree files become untracked. `git checkout <sha>` can abort with "would be overwritten by checkout" when those untracked files conflict, leaving the repo stuck on the orphan branch with an empty index.
   
   Because this runs in the shared project root (and `create_worktree` may be invoked for multiple pairs against the same root — see pair.rs:1119), a failure here corrupts state for all agents. The safer `commit-tree` path is tried first, but the fallback is still reachable. Consider performing branch creation entirely via plumbing (`commit-tree` + `push`) and never touching HEAD/index, or capturing the original ref with `git symbolic-ref --short HEAD` (falling back to the SHA) and restoring that, plus using `git checkout -f` / stashing to avoid the untracked-file abort.

   Fix (Restore the original branch name instead of a detached SHA.):
   // Capture the symbolic ref name when on a branch, else the SHA.
   let saved_head = Command::new("git")
       .args(["symbolic-ref", "--short", "-q", "HEAD"])
       .current_dir(&self.project_root)
       .output().ok()
       .filter(|o| o.status.success())
       .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
       .filter(|s| !s.is_empty())
       .or_else(|| /* fall back to rev-parse HEAD as before */ saved_head_sha());

2. 💡 Bug: Orphan branch cleanup uses `git branch -d` and will fail
   Files: crates/pair-harness/src/worktree.rs:393-396

   After creating and pushing the orphan default branch, cleanup runs `git branch -d <default_branch>`. The orphan branch's commit is not merged into any other branch, so `-d` (safe delete) refuses to delete it ("not fully merged"), leaving a stray local branch ref behind. If the intent is to always remove the temporary local ref, use `-D` (force delete). Note this is only reached after HEAD has been restored, so deleting the checked-out branch is not a concern.

   Fix (Force-delete the temporary local orphan branch ref.):
   let _ = Command::new("git")
       .args(["branch", "-D", &self.default_branch])
       .current_dir(&self.project_root)
       .output();

3. 💡 Bug: Default-branch push from project_root may lack token auth
   Files: crates/pair-harness/src/worktree.rs:258-272, crates/pair-harness/src/worktree.rs:357-371

   Both `ensure_default_branch_via_commit_tree` and `ensure_default_branch_via_orphan_checkout` run `git push origin ...` in `self.project_root`. Token-based remote authentication is only applied to *worktrees* via `configure_remote_with_token` (and the github_token is not even passed into `ensure_default_branch_on_remote`). If the project root's `origin` URL is a plain `https://github.com/...` without an embedded `x-access-token`, these pushes will fail authentication, so the default branch is never created and the feature silently degrades (only a SetupWarning is emitted). Consider configuring the project-root remote with the token (as is done for worktrees) before pushing, or passing the github_token through and using an authenticated push URL.

Tip

Comment Gitar fix CI or enable auto-apply: gitar auto-apply:on

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Important

Your trial ends in 2 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.

Was this helpful? React with 👍 / 👎 | Gitar

);
}
// If even slimmed JSON is too large, truncate to just issue numbers and titles
let minimal: Vec<serde_json::Value> = slimmed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[logic] (confidence: 90%)

The minimal truncation path extracts "status" but not "state". For GitHub issues, the open/closed indicator is in the "state" field, not "status". The keep_keys list includes both "state" (index 2) and "status" (index 8), but the minimal path only preserves "status", which is typically null for GitHub issue data. This means heavily truncated tool results lose the issue's open/closed status — critical information for the LLM's decision-making.

Impact: When tool results are large enough to trigger heavy truncation, the LLM receives GitHub issues without knowing whether they are open or closed, which can lead to incorrect decisions (e.g., trying to work on already-closed issues or ignoring open ones).

Evidence:

let minimal: Vec<serde_json::Value> = slimmed
    .into_iter()
    .map(|item| {
        let number = item.get("number").cloned().unwrap_or(serde_json::Value::Null);
        let title = item.get("title").cloned().unwrap_or(serde_json::Value::Null);
        let status = item.get("status").cloned().unwrap_or(serde_json::Value::Null);
        serde_json::json!({
            "number": number,
            "title": title,
            "status": status,
        })
    })
    .collect();

Suggestion: Add "state" to the minimal extraction alongside or instead of "status": let state = item.get("state").cloned().unwrap_or(serde_json::Value::Null); and include it in the output JSON.

}
};

// Push the commit as the default branch to origin

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[logic] (confidence: 75%)

The ensure_default_branch_via_orphan_checkout fallback saves the current HEAD as a commit hash via git rev-parse HEAD, then restores it with git checkout . This puts the repository into a detached HEAD state instead of restoring the original branch name. Subsequent git operations that expect to be on a named branch (e.g., git pull, git status showing branch info) will behave unexpectedly.

Impact: After the orphan checkout fallback runs, the project root repository is left in detached HEAD state. This can cause subsequent git operations to fail or produce unexpected results, particularly git pull or any workflow that checks the current branch name.

Evidence:

let saved_head = Command::new("git")
    .args(["rev-parse", "HEAD"])
    ...
fn restore_head(project_root: &Path, saved_head: Option<String>) {
    if let Some(ref head) = saved_head {
        let _ = Command::new("git")
            .args(["checkout", head])
            ...

Suggestion: Save the branch name instead of the commit hash using git rev-parse --abbrev-ref HEAD, and restore with git checkout to stay on the original branch.

@github-actions

Copy link
Copy Markdown

Snif Review

This release replaces hardcoded model lists with live API discovery for Anthropic, OpenAI, and Fireworks providers, adds pagination and timeouts to model fetching, introduces tool result truncation for large GitHub API responses, updates the default Fireworks model to deepseek-v3p1, adds custom deserializers for pr_number to handle LLM-generated empty strings, and improves default branch detection and creation for new repositories.

Found 2 issues. See inline comments for details.

Review details

Changed files:

  • Cargo.lock
  • binary/Cargo.toml
  • crates/agent-client/src/fallback.rs
  • crates/agent-client/src/fireworks.rs
  • crates/agent-client/src/runner.rs
  • crates/agent-forge/src/lib.rs
  • crates/agentflow-tui/src/setup/mod.rs
  • crates/agentflow-tui/src/setup/model_discovery.rs
  • crates/agentflow-tui/src/setup/step_agents.rs
  • crates/pair-harness/src/process.rs
  • crates/pair-harness/src/types.rs
  • crates/pair-harness/src/worktree.rs
  • orchestration/agent/registry.json

Context analyzed: 99 related files (29 via semantic similarity, 99 via keyword matching).

Stats: 1955 lines | glm-5p1 | 141s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant