Skip to content

feat(session-viewer): hide subagent sessions, add FTS5 search, pagination, and loop commands#20

Merged
KooshaPari merged 71 commits into
KooshaPari:mainfrom
Dmouse92:feat/session-viewer
Jun 16, 2026
Merged

feat(session-viewer): hide subagent sessions, add FTS5 search, pagination, and loop commands#20
KooshaPari merged 71 commits into
KooshaPari:mainfrom
Dmouse92:feat/session-viewer

Conversation

@Dmouse92

Copy link
Copy Markdown

Summary

This PR adds a hierarchical session viewer to Forge. It solves a real pain point in the
session history: subagent traces from the orchestrator were polluting the conversation
list, making it hard to find the user's own sessions. It also adds search, pagination,
and a couple of new CLI commands.

Problem

When a user runs Forge, the orchestrator spawns subagents (e.g. forge_app/orch.rs,
agent_executor.rs) that each open their own conversation rows. Before this PR, every
one of those rows showed up in the :conversation picker. The list quickly became a mix
of user-initiated sessions and dozens of subagent traces, with no way to distinguish them
or drill into a parent's children.

Solution

Add hierarchical linking between conversations and filter the picker to user-initiated
sessions by default. New commands expose the children of a session and the loop/goal
state, and an FTS5-backed search index makes it possible to find a session by content.

Key Changes

  • parent_id column on conversations for hierarchical linking. Subagent sessions
    now point at the parent that spawned them; user-initiated sessions have parent_id = NULL.
  • :conversation now shows only user-initiated parents (where parent_id IS NULL).
    Implemented in forge_main::ui and applied to SelectCommand::Conversation in
    forge_main::ui.rs (the post-merge fix on 7065903a0).
  • :subagents <id> and :parent <id> commands to walk the tree down and up.
  • FTS5 search index on conversation content via a new SQLite virtual table
    (up.sql migration adds the index and triggers). The repo exposes a search query
    in conversation_repo.rs.
  • source column on conversations so we can tell apart -p/headless sessions
    from interactive ones. The ToolCallContext carries the source through to the repo.
  • :goal <id> and :loop <id> commands for inspecting and toggling the
    loop/goal state of a session.
  • ConversationSelector optimization in forge_main::conversation_selector.rs
    for paginated loading of large histories.
  • Upstream fixes carried forward from upstream/main (commit 34cfeb666 /
    v2.13.11): the :conversation filter is now correctly applied to
    SelectCommand::Conversation as well, not just the picker entry point.

Files Changed

 crates/forge_api/src/api.rs                                       |  19 ++
 crates/forge_api/src/forge_api.rs                                 |  34 ++++
 crates/forge_app/src/agent_executor.rs                            |   9 +-
 crates/forge_app/src/orch.rs                                      |  10 +-
 crates/forge_app/src/services.rs                                  |  47 +++++
 crates/forge_app/src/tool_registry.rs                             |   8 +-
 crates/forge_domain/src/conversation.rs                           |   4 +
 crates/forge_domain/src/repo.rs                                   |  38 ++++
 crates/forge_domain/src/tools/call/context.rs                     |  40 +++-
 crates/forge_main/src/conversation_selector.rs                    | 111 +++++------
 crates/forge_main/src/model.rs                                    |  45 ++++-
 crates/forge_main/src/state.rs                                    |  20 +-
 crates/forge_main/src/ui.rs                                       | 211 ++++++++++++++++-----
 crates/forge_repo/src/conversation/conversation_record.rs         |   6 +
 crates/forge_repo/src/conversation/conversation_repo.rs           |  89 +++++++++
 crates/forge_repo/src/database/migrations/2025-11-12-001000/down.sql |   1 +
 crates/forge_repo/src/database/migrations/2025-11-12-001000/up.sql   |   1 +
 crates/forge_repo/src/database/migrations/2025-11-13-000000/down.sql |   2 +
 crates/forge_repo/src/database/migrations/2025-11-13-000000/up.sql   |   4 +
 crates/forge_repo/src/database/migrations/2025-11-14-000000/down.sql |   4 +
 crates/forge_repo/src/database/migrations/2025-11-14-000000/up.sql   |  46 +++++
 crates/forge_repo/src/database/schema.rs                          |   2 +
 crates/forge_repo/src/forge_repo.rs                               |  33 +++-
 crates/forge_services/src/conversation.rs                         |  28 +++
 24 files changed, 690 insertions(+), 122 deletions(-)

Branch HEAD: 7065903a0. Upstream base: 34cfeb666 (v2.13.11).

Testing

  • cargo check — clean across the workspace.
  • cargo build — succeeds; binary produced at ~/.local/bin/forge-dev and smoke-run
    locally.
  • Manual verification of the picker:
    • :conversation lists only user-initiated sessions.
    • :subagents <id> lists the children of a parent.
    • :parent <id> jumps to the parent.
    • FTS5 search returns the expected row for a known phrase.
  • Migration up.sql files apply cleanly on a fresh SQLite database and the
    down.sql files roll back symmetrically.

Commits

7065903a0 fix(ui): apply user_initiated_conversations filter to SelectCommand::Conversation
fd4a28d21 Merge upstream/main into feat/session-viewer
f3beee1a7 feat: add parent_id, source, FTS5, subagent hiding, and loop commands

amitksingh1490 and others added 30 commits May 28, 2026 19:52
Co-authored-by: ForgeCode <noreply@forgecode.dev>
Co-authored-by: laststylebender <43403528+laststylebender14@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…lcallhq#3412)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…ilcallhq#3416)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: ForgeCode <noreply@forgecode.dev>
…hq#3399)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: ForgeCode <noreply@forgecode.dev>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Amit Singh <amitksingh1490@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…lcallhq#3440)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…allhq#3431)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…hq#3449)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
dependabot Bot and others added 20 commits June 12, 2026 06:44
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Amit Singh <amitksingh1490@gmail.com>
…3485)

Co-authored-by: laststylebender <43403528+laststylebender14@users.noreply.github.com>
…#3490)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Amit Singh <amitksingh1490@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
…lcallhq#3480)

Co-authored-by: akhilapp <akhilapp@google.com>
Co-authored-by: Amit Singh <amitksingh1490@gmail.com>
…hq#3491)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…lcallhq#3492)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
…lcallhq#3495)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…ilcallhq#3499)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…nversation` command (tailcallhq#3510)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
@Dmouse92 Dmouse92 requested a review from KooshaPari as a code owner June 15, 2026 05:53
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@codeant-ai

codeant-ai Bot commented Jun 15, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary

This PR introduces a hierarchical session viewer for Forge's conversation history by establishing parent-child relationships between conversations. The implementation spans database schema changes (migrations for parent_id, source, and FTS5 virtual tables), new API/service/repository query methods, UI enhancements for conversation navigation, and a major terminal editor refactor from reedline to rustyline.

Overall Assessment: The PR should APPROVE with minor documentation notes. Compilation passes (cargo check/cargo build), database migrations are properly structured, and the layered architecture (API → Services → Repository) is consistently implemented across all three new query methods. The codebase maintains good separation of concerns and backward compatibility.


Must Fix

None identified. The code compiles successfully and follows the required patterns.


Should Fix

1. Missing Public API Documentation (Medium Priority)

  • The three new public API methods (get_subagents, get_parent_conversations, get_conversations_by_source) in crates/forge_api/src/api.rs lack doc comments explaining parameters, return semantics, and filtering behavior.
  • Impact: Downstream consumers must read the implementation to understand filtering rules (e.g., why parent_conversations returns None for empty results rather than Some(vec![])).
  • Recommendation: Add /// doc comments to the trait methods in api.rs before merge.

2. Inconsistent Documentation in Repository Layer (Low Priority)

  • crates/forge_repo/src/conversation/conversation_repo.rs has inline documentation for the query methods, but the trait methods in crates/forge_domain/src/repo.rs lack corresponding doc comments.
  • Recommendation: Propagate documentation to the trait level for consistency.

3. Editor Migration Completeness Check (Low Priority)

  • The refactor from reedline::Completer to inherent complete() method in CommandCompleter and InputCompleter is incomplete in terms of error handling.
  • InputCompleter::complete() returns Vec<InputSuggestion>, but there's no documented fallback behavior if completion fails during field extraction.
  • Recommendation: Ensure all error paths in the new rustyline integration are tested (tests appear minimal in editor.rs).

Consider

1. Test Coverage for New Query Methods

  • No direct unit tests found for get_conversations_by_parent, get_parent_conversations, or get_conversations_by_source in the conversation_repo.rs test suite.
  • The PR relies on integration testing and manual verification as noted in the objectives.
  • Recommendation: Consider adding repository-layer unit tests for edge cases (e.g., empty parent IDs, malformed UUIDs in parent_id field, source filtering with null/empty strings).

2. FTS5 Migration Backfill Logic

  • The add_fts5_to_conversations/up.sql migration filters on context IS NOT NULL during backfill.
  • This means conversations with NULL context will not be searchable until they are next updated (trigger will backfill them).
  • Impact: Minimal (FTS is likely a new feature), but document this behavior if FTS is used in filtering logic.

3. Conversation::related_conversation_ids Scope

  • This method is used to filter out related conversations in the UI layer, but the logic depends on context containing specific tool result structures.
  • If context schema changes, this filtering may break silently.
  • Recommendation: Consider adding a debug log when filtering to help diagnose issues in production.

4. Parent-Child Relationship Cleanup

  • No migration or cleanup logic to orphan children if a parent conversation is deleted.
  • Deleting a conversation leaves children with dangling parent_id references.
  • Recommendation: Document whether cascading deletes are intentional, or add a soft-delete marker instead.

5. Rustyline Editor: History File Path

  • The editor stores history in history_file: PathBuf, but initialization is not visible in the diff.
  • Ensure the path is configurable and doesn't conflict with other tools' history (e.g., ~/.forge_history vs. shared shell history).

Approve

All critical requirements met:

  • cargo check and cargo build pass cleanly (verified in PR objectives)
  • ✅ Database schema changes properly versioned with up/down migrations
  • ✅ Three new API methods consistently implemented across trait, implementation, services, and repository layers
  • ✅ New parent_id, source, and ToolCallContext fields properly initialized in domain constructors
  • Conversation struct derives Debug and Clone as required
  • ✅ No unsafe code blocks introduced
  • provider.json is valid JSON and properly extends existing model catalogs
  • ✅ Conversation selector optimized with FastConversationRow format (reduced overhead)
  • ✅ No inter-crate dependency violations introduced
  • ✅ ConversationId parsing is safe (uses try_from and ok() for conversions)

Recommended Action: Approve with a note to add docstrings to the three new API methods before merge for completeness.

Walkthrough

This PR introduces a parent/subagent conversation hierarchy with DB migrations (parent_id, source, FTS5), propagates metadata through ToolCallContext and AgentExecutor, and adds new CLI commands (/subagents, /goal, /loop, /parent). The terminal editor is migrated from reedline to rustyline. New model entries are added (claude-opus-4-8, claude-fable/mythos, MiniMax M3, Gemini 3.5 Flash, Ambient provider). OpenAI Responses SSE handling gains explicit response.completed/response.incomplete event support with 503 retry logic. rmcp is upgraded to 1.0 with transport refactoring.

Changes

Conversation hierarchy: parent_id, source, subagent tree

Layer / File(s) Summary
Domain model, DB migrations, and Diesel schema
crates/forge_domain/src/conversation.rs, crates/forge_repo/src/database/migrations/..., crates/forge_repo/src/database/schema.rs
Conversation gains parent_id/source fields; three migrations add parent_id column, source column+index, and FTS5 virtual table with insert/update/delete triggers and backfill; Diesel schema updated.
Repository, service, and API layers
crates/forge_domain/src/repo.rs, crates/forge_repo/src/conversation/..., crates/forge_repo/src/forge_repo.rs, crates/forge_services/src/conversation.rs, crates/forge_app/src/services.rs, crates/forge_api/src/...
ConversationRepository gains three query methods (by parent, top-level, by source); ConversationRecord updated for persistence; upsert extended; all forwarding layers wired up through ForgeRepo, ForgeConversationService, ConversationService trait, and ForgeAPI.
ToolCallContext propagation through orchestrator and executor
crates/forge_domain/src/tools/call/context.rs, crates/forge_app/src/orch.rs, crates/forge_app/src/agent_executor.rs, crates/forge_app/src/tool_registry.rs, crates/forge_app/src/lib.rs
ToolCallContext gains conversation_id, parent_id, source fields; orchestrator populates them from current conversation; AgentExecutor::execute gains parent_id parameter; ToolRegistry captures and passes parent_id for Task and agent-delegation paths.
CLI commands, UI handlers, and shell plugin
crates/forge_main/src/cli.rs, crates/forge_main/src/model.rs, crates/forge_main/src/state.rs, crates/forge_main/src/ui.rs, shell-plugin/lib/..., crates/forge_main/src/zsh/plugin.rs
ListCommand::Conversation and SelectCommand::Conversation gain --parent filter; AppCommand adds Subagents/Goal/Loop/Parent; UIState gains goal/loop_enabled/last_activity; UI adds detect_source, subagent listing, user-initiated filtering, and conversation source assignment; shell plugin adds _forge_action_conversation_tree and conversation-tree|ct dispatch; _forge_reset gains BUFFERLINES padding.

Terminal editor: reedline → rustyline migration

Layer / File(s) Summary
Local types decoupled from reedline
crates/forge_main/src/completer/search_term.rs, crates/forge_main/src/highlighter.rs, crates/forge_main/src/completer/input_completer.rs, crates/forge_main/src/completer/command.rs
Local Span, StyledText, and InputSuggestion types replace reedline equivalents; InputCompleter and CommandCompleter switch from reedline Completer trait to inherent complete() methods.
Prompt and conversation selector
crates/forge_main/src/prompt.rs, crates/forge_main/src/conversation_selector.rs
ForgePrompt methods moved from reedline trait impl to inherent pub methods; tests use local PromptHistorySearch types; conversation selector replaced with FastConversationRow formatting.
ForgeEditor on rustyline
crates/forge_main/Cargo.toml, crates/forge_main/src/editor.rs, crates/forge_select/src/input.rs, crates/forge_select/src/preview.rs
ForgeEditor rebuilt on rustyline::Editor; ForgeHelper wires completion/highlighting/hints; dual raw+styled prompt rendering for cursor geometry; alternate screen guard added in forge_select; key-release events ignored in preview.

New model support and Ambient provider

Layer / File(s) Summary
Ambient provider constant and config
crates/forge_domain/src/provider.rs, crates/forge_repo/src/provider/provider.json, crates/forge_repo/src/provider/provider_repo.rs
ProviderId::AMBIENT constant added with display/parse/built-in support; ambient entry added to provider catalog; endpoint URL validated in test.
New model entries
crates/forge_repo/src/provider/provider.json, vertex.json
claude-opus-4-8, claude-fable-5 added across Anthropic/Bedrock/VertexAI providers; MiniMax-M3 in minimax/bedrock/fireworks-ai; gemini-3.5-flash in vertex_ai/google_ai_studio; qwen3.7-max, glm-5.2, DeepSeek V4, Kimi K2.7, Qwen 3.7 Plus added across providers.
Model-specific parameter and schema logic
crates/forge_app/src/dto/anthropic/response.rs, crates/forge_repo/src/provider/anthropic.rs, crates/forge_app/src/transformers/model_specific_reasoning.rs, crates/forge_app/src/dto/openai/transformers/minimax.rs, crates/forge_app/src/utils.rs
claude-mythos/fable recognized as image-capable with 1M context; Anthropic interleaved-thinking beta extended to opus-4-8/mythos/fable; AdaptiveOnly reasoning extended to Opus 4.8; MiniMax M3 transformer adds correct params; Gemini schema sanitizer strips propertyNames.

OpenAI Responses Codex terminal events and retry

Layer / File(s) Summary
ResponsesStreamEvent types and reasoning fix
crates/forge_repo/src/provider/openai_responses/response.rs, crates/forge_repo/src/provider/openai_responses/request.rs, Cargo.toml
ResponseCompleted/ResponseIncomplete variants added with payload structs and helper functions; reasoning id field option-wrapping fixed; async-openai bumped to 0.41.
Repository SSE dispatch and error handling
crates/forge_repo/src/provider/openai_responses/repository.rs, crates/forge_infra/src/http.rs
Chat and Codex streaming paths handle terminal events; SSE error mapping preserves HTTP status code via InvalidStatusCode; http.rs enriches error with body context; 503 retryability tests added.

MCP rmcp 1.0 upgrade

Layer / File(s) Summary
MCP client refactoring and token storage
Cargo.toml, crates/forge_infra/src/mcp_client.rs, crates/forge_infra/src/auth/mcp_token_storage.rs
rmcp upgraded to 1.0; ForgeMcpClient drops cached reqwest::Client; connections use StreamableHttpClientTransportConfig; CallToolRequestParams builder used; StoredCredentials::new() and VendorExtraTokenFields from rmcp adopted.

Infrastructure and minor fixes

Layer / File(s) Summary
VS Code auto-install config
crates/forge_config/src/config.rs, crates/forge_config/.forge.toml, forge.schema.json
auto_install_vscode_extension bool field added to ForgeConfig with serde defaulting, default true in TOML, schema property, and two config-resolution tests.
Dependency bumps and minor fixes
Cargo.toml, crates/forge_tracker/Cargo.toml, rust-toolchain.toml, crates/forge_app/src/fmt/todo_fmt.rs
posthog-rs bumped to 0.12.0; Rust toolchain updated to 1.96; todo cancelled icon glyph updated.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI (ui.rs)
    participant ToolRegistry
    participant AgentExecutor
    participant ConversationRepo
    participant DB as SQLite (conversations + FTS5)

    UI->>UI: detect_source(cli) → "interactive" / "forge-p" / etc.
    UI->>ConversationRepo: upsert Conversation {source: detect_source, parent_id: None}
    ConversationRepo->>DB: INSERT ... ON CONFLICT UPDATE (parent_id, source)
    UI->>ToolRegistry: dispatch Task tool with ToolCallContext {conversation_id, source}
    ToolRegistry->>ToolRegistry: parent_id = context.conversation_id()
    ToolRegistry->>AgentExecutor: execute(agent_id, task, ctx, parent_id=Some(...))
    AgentExecutor->>ConversationRepo: upsert Conversation {parent_id: Some(parent), source}
    ConversationRepo->>DB: INSERT subagent conversation row
    DB-->>DB: AFTER INSERT trigger → conversations_fts
    UI->>ConversationRepo: get_conversations_by_parent(parent_id)
    ConversationRepo->>DB: SELECT WHERE parent_id = ? ORDER BY updated_at DESC
    DB-->>UI: Vec<Conversation> (subagent list)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

@socket-security

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: cargo openssl is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: ?cargo/reqwest@0.11.27cargo/openssl@0.10.80

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore cargo/openssl@0.10.80. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 21

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
crates/forge_app/src/fmt/todo_fmt.rs (1)

20-25: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Cancelled icon is now inconsistent across render paths.

You updated TodoStatus::Cancelled to here, but removed-item rendering still uses 󰅙 (same file, Line 95). This yields inconsistent output for the same status.

Proposed fix
                 let checkbox = match before_todo.status {
                     TodoStatus::InProgress => "󰄗",
                     TodoStatus::Pending => "󰄱",
-                    TodoStatus::Cancelled => "󰅙",
+                    TodoStatus::Cancelled => "",
                     TodoStatus::Completed => "󰄵",
                 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_app/src/fmt/todo_fmt.rs` around lines 20 - 25, The
TodoStatus::Cancelled icon assignment in the checkbox match statement uses an
empty string, but the removed-item rendering elsewhere in the same file uses the
icon 󰅙 for the same status, creating inconsistency. Update the
TodoStatus::Cancelled case in the checkbox match block to use the same icon (󰅙)
that is used in the removed-item rendering path to ensure consistent output for
cancelled todos across all render paths.
Cargo.toml (1)

62-136: ⚠️ Potential issue | 🟠 Major

Set up cargo deny in the project CI/CD before merging this PR.

The coding guidelines require cargo deny check for Cargo.toml changes, but the project does not have cargo-deny configured. There is no deny.toml file and no cargo deny check step in the CI workflow. Either add cargo-deny configuration and integrate it into .github/workflows/ci.yml, or confirm with the team if this requirement is intentionally waived.

Note: cargo clippy --workspace --all-targets -- -D warnings is already running in CI via the autofix workflow, satisfying the strict linting requirement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Cargo.toml` around lines 62 - 136, The project lacks cargo-deny configuration
which is required by the coding guidelines for Cargo.toml changes. Create a
deny.toml configuration file at the project root with appropriate policy rules
for dependency validation, then add a cargo deny check step to the CI workflow
in .github/workflows/ci.yml to ensure cargo deny check runs on every CI build,
validating that dependencies meet the project's security and licensing
requirements.

Source: Coding guidelines

crates/forge_app/src/agent_executor.rs (1)

37-49: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update execute Rust docs to cover the new parameter and error contract.

The public method documentation no longer reflects the signature after adding parent_id, and it should include explicit # Arguments/# Errors sections.

Suggested doc update
-    /// Executes an agent tool call by creating a new chat request for the
-    /// Executes an agent tool call by creating a new chat request for the
-    /// specified agent. If conversation_id is provided, the agent will reuse
-    /// that conversation, maintaining context across invocations. Otherwise,
-    /// a new conversation is created.
+    /// Executes an agent tool call for the specified agent.
+    ///
+    /// Reuses an existing conversation when `conversation_id` is provided;
+    /// otherwise creates a new conversation and optionally sets parent/source metadata.
+    ///
+    /// # Arguments
+    /// * `agent_id` - Agent to execute
+    /// * `task` - Task text sent to the agent
+    /// * `ctx` - Tool call context used for event propagation and metadata
+    /// * `conversation_id` - Existing conversation to reuse, if any
+    /// * `parent_id` - Parent conversation ID for newly created agent conversations
+    ///
+    /// # Errors
+    /// Returns an error if conversation lookup fails, chat execution fails,
+    /// the tool call is interrupted, or no tool output is produced.

As per coding guidelines, "Always write Rust docs (///) for all public methods, functions, structs, enums, and traits" and "Document parameters with # Arguments and errors with # Errors sections in Rust docs when applicable."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_app/src/agent_executor.rs` around lines 37 - 49, The Rust doc
comment for the `execute` method is incomplete and does not document the newly
added `parent_id` parameter. Update the doc comment to include a proper `#
Arguments` section that documents all parameters including `agent_id`, `task`,
`ctx`, `conversation_id`, and `parent_id`, and add an `# Errors` section that
documents the types of errors the method can return (currently documented as
`anyhow::Result<ToolOutput>`). Ensure the documentation follows Rust doc
standards with clear descriptions for each parameter.

Source: Coding guidelines

crates/forge_main/src/cli.rs (1)

1303-1317: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add explicit parse assertions for the new --parent filter.

Line 1303 and Line 1315 only confirm variant shape. They don’t verify that --parent <ConversationId> is parsed and stored correctly for list conversation/list session (and this new CLI surface is the core behavior change).

Proposed test addition
+    #[test]
+    fn test_list_conversation_with_parent_filter() {
+        let fixture = Cli::parse_from([
+            "forge",
+            "list",
+            "conversation",
+            "--parent",
+            "550e8400-e29b-41d4-a716-446655440100",
+        ]);
+        let actual = match fixture.subcommands {
+            Some(TopLevelCommand::List(list)) => match list.command {
+                ListCommand::Conversation { parent } => parent,
+                _ => None,
+            },
+            _ => None,
+        };
+        let expected =
+            Some(ConversationId::parse("550e8400-e29b-41d4-a716-446655440100").unwrap());
+        assert_eq!(actual, expected);
+    }

As per coding guidelines, “Tests should always be written in the same file as the source code” and “All tests should use three discrete steps: setup, actual, and expected...”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_main/src/cli.rs` around lines 1303 - 1317, The test functions
test_list_conversation_alias_command and test_list_session_alias_command
currently only verify the variant shape of ListCommand::Conversation but do not
verify that the --parent filter argument is correctly parsed and stored. Enhance
both tests by parsing the CLI with the --parent argument including a
ConversationId value, then extract the parsed list command and add explicit
assertions that verify the parent filter is present and contains the expected
ConversationId value. This ensures the new CLI surface for filtering by parent
is working correctly, following the three-step test pattern of setup, actual,
and expected.

Source: Coding guidelines

crates/forge_infra/src/mcp_client.rs (1)

570-702: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add # Errors sections for public Result-returning functions in this file.

mcp_auth, mcp_logout, and mcp_logout_all return Result but their Rust docs currently omit # Errors.

As per coding guidelines, “Document parameters with # Arguments and errors with # Errors sections in Rust docs when applicable.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_infra/src/mcp_client.rs` around lines 570 - 702, Add `# Errors`
documentation sections to the three public functions that return
`anyhow::Result`: `mcp_auth`, `mcp_logout`, and `mcp_logout_all`. For
`mcp_auth`, document that errors can occur during OAuth state initialization,
authorization flow, token exchange, callback handling, or credential storage.
For `mcp_logout`, document that errors can occur during credential removal. For
`mcp_logout_all`, document that errors can occur during credential removal.
Place these sections after the `# Arguments` sections in their respective doc
comments.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/forge_app/src/dto/anthropic/response.rs`:
- Around line 82-85: The new code branches for claude-mythos and claude-fable
models (returning 1M context) and the new modality matching logic lack test
coverage. Add focused regression tests for the get_context_length function that
verify both claude-mythos* and claude-fable* model IDs correctly return a
context length of 1,000,000, and also add tests for the Model to
forge_domain::Model conversion to ensure the new modality matching handles these
models properly without breaking existing behavior.

In `@crates/forge_config/src/config.rs`:
- Around line 497-515: Both test functions
test_auto_install_vscode_extension_defaults_to_true and
test_auto_install_vscode_extension_can_be_disabled need to be refactored to
follow the required three-step test structure: setup, actual, and expected. Add
explicit expected variables that define the anticipated values (true for the
defaults test and false for the disabled test), then update each assertion to
compare the actual.auto_install_vscode_extension value against these expected
variables instead of using literal values in the assertion.

In `@crates/forge_domain/src/provider.rs`:
- Around line 705-714: The test functions test_ambient_display_name and
test_ambient_in_built_in_providers do not follow the required
setup/actual/expected structure with proper variable naming conventions.
Refactor both tests to include discrete setup, actual, and expected steps using
variable names that include expected and actual (and fixture where applicable),
and replace the assertions with pretty_assertions::assert_eq calls to align with
your Rust test conventions.

In `@crates/forge_infra/src/mcp_client.rs`:
- Around line 557-568: The build_header_map function uses filter_map to silently
discard headers that fail to parse as valid HeaderName or HeaderValue, making
header misconfiguration difficult to detect and debug. Instead of silently
filtering out invalid headers with the .ok()? pattern, explicitly log or signal
each parsing failure (including the key, value, and parse error details) so that
configuration issues are visible. This ensures that header misconfiguration
problems do not cause opaque auth failures.
- Around line 339-342: The connect_with_token method in
crates/forge_infra/src/mcp_client.rs (lines 339-342) creates a
StreamableHttpClientTransportConfig with only the URI and auth_header, but does
not include custom headers. This causes servers that require both OAuth
authentication and custom headers to fail. Modify the config creation to also
include custom headers by adding the same header configuration logic that is
used in create_standard_http_connection, ensuring both the token and custom
headers are propagated to the StreamableHttpClientTransportConfig before
creating the transport.

In `@crates/forge_main/src/completer/command.rs`:
- Around line 29-30: The public method `complete` in the `CommandCompleter`
implementation is missing rustdoc documentation. Add rustdoc comments (///)
above the method definition that include a brief description of what the method
does, an Arguments section documenting the `line` parameter and the `usize`
parameter, and a description of the return value. Follow the pattern of
documenting all public API surface area as per the coding guidelines.

In `@crates/forge_main/src/completer/input_completer.rs`:
- Around line 62-66: Add rustdoc comments to the public API additions to comply
with coding guidelines. For the InputSuggestion struct at lines 62-66, add
triple-slash documentation above the struct and each field explaining their
purpose. For the InputCompleter::complete method at line 73, add triple-slash
documentation above the method explaining what it does, use an Arguments section
to document each parameter, and use a Returns section to document the return
value. Ensure all public additions have clear, descriptive rustdoc that explains
their purpose and usage.

In `@crates/forge_main/src/completer/search_term.rs`:
- Around line 1-11: Add Rust documentation comments (`///`) to all public API
items across multiple files. In `crates/forge_main/src/completer/search_term.rs`
at lines 1-11, add docs for the `Span` struct and its `new` method, including an
`# Arguments` section describing the `start` and `end` parameters. In
`crates/forge_main/src/prompt.rs` at lines 64-207, add docs for the public
functions `render_prompt_left`, `render_prompt_right`, and
`render_prompt_indicator` with appropriate descriptions and argument sections.
In `crates/forge_main/src/editor.rs` at lines 45-118, complete the documentation
for `ForgeEditor::new`, `ForgeEditor::prompt`, `ForgeEditor::set_buffer`, and
`ReadLineError` with `# Arguments` sections for methods taking parameters and `#
Errors` sections for any error conditions. Ensure all documentation follows the
repository's Rust docs guidelines of using `///` comments with descriptive text
and structured sections for arguments and errors.

In `@crates/forge_main/src/model.rs`:
- Around line 663-689: Add test cases in the same file
(crates/forge_main/src/model.rs) to verify parsing and name mapping for the four
new command variants: Subagents, Goal, Loop, and Parent. Create tests that
follow the three-step structure (setup, actual, expected) to verify that: (1)
each command parses correctly when invoked by its primary name (subagents, goal,
loop, parent), (2) each command parses correctly when invoked by its alias (sa,
g, l, p respectively), and (3) the name() function returns the correct canonical
command name for each variant. Ensure comprehensive coverage for both the parser
behavior and the name() function mapping referenced at lines 756-759.

In `@crates/forge_main/src/prompt.rs`:
- Around line 258-289: The render_prompt_history_search_indicator function along
with the PromptHistorySearchStatus enum and PromptHistorySearch struct currently
exist only within test modules, meaning the tests do not cover production
behavior after the rustyline migration. Either move the
render_prompt_history_search_indicator function, PromptHistorySearchStatus enum,
and PromptHistorySearch struct from the test module into production code and
update the tests to verify this production API, or remove the test assertions
(at both the location shown and at lines 348-386) if rustyline now owns and
handles reverse-search indicator rendering in production.

In `@crates/forge_main/src/state.rs`:
- Around line 31-34: The public constructor method `UIState::new` is missing
Rustdoc documentation. Add Rust doc comments (///) immediately above the `pub fn
new(env: Environment) -> Self` method declaration to document its purpose.
Include an `# Arguments` section that documents the `env` parameter and what it
represents. Also consider adding a brief description of what the method does and
what the returned `Self` instance represents.

In `@crates/forge_main/src/ui.rs`:
- Around line 518-522: The ListCommand::Conversation and
SelectCommand::Conversation branches are not properly handling the parent
parameter for conversation filtering. In the ListCommand::Conversation block at
lines 518-522, replace the generic fetch_related_conversations call with a
parent-aware repository query using get_subagents or a query by parent_id when
the parent parameter is provided. Similarly, in the SelectCommand::Conversation
block at lines 897-902, the parent parameter is currently being ignored
entirely, so add logic to use the parent_id for filtering when parent is
specified. Both commands should use the same parent-aware query mechanism to
ensure --parent returns the correct set of child conversations and maintains
proper conversation-tree navigation.

In `@crates/forge_repo/src/conversation/conversation_record.rs`:
- Around line 1028-1029: The deserialization logic for parent_id in the
ConversationRecord conversion is silently discarding parse failures by using
.ok() to convert Result errors into None values. This hides bad persisted IDs
and breaks parent-child relationship semantics. Instead of using and_then with
ConversationId::parse(id).ok(), propagate the parse error properly by handling
the Result explicitly, either by returning an error from the conversion function
or by using a method that surfaces the error when an invalid parent_id is
encountered. This ensures that data integrity issues are detected and reported
rather than silently ignored during deserialization.

In `@crates/forge_repo/src/conversation/conversation_repo.rs`:
- Around line 188-190: The unchecked cast of limit_value from usize to i64 can
overflow for large input values, producing invalid or negative limits. Replace
the direct cast `limit_value as i64` with a safe conversion check using
`i64::try_from(limit_value)` or similar safe conversion method that handles the
case where the value exceeds i64::MAX. This should be applied to both the
location at lines 188-190 and the similar pattern at lines 220-222 in the same
file.

In
`@crates/forge_repo/src/database/migrations/2026-06-13-000000_add_parent_id_to_conversations/up.sql`:
- Line 1: The up.sql migration adds the parent_id column but lacks an index on
it, which will cause performance degradation on parent-filtered queries as data
grows. Add a CREATE INDEX statement in the up.sql migration to create an index
named idx_conversations_parent_id on the parent_id column of the conversations
table. Additionally, update the corresponding down.sql rollback migration to
drop the index (using DROP INDEX IF EXISTS idx_conversations_parent_id) before
dropping the parent_id column to ensure proper cleanup during rollback.

In
`@crates/forge_repo/src/database/migrations/2026-06-14-000002_add_fts5_to_conversations/up.sql`:
- Around line 43-46: The INSERT statement in the conversations_fts backfill
migration uses a WHERE clause that filters on context IS NOT NULL, which
excludes conversations that have a non-NULL title but NULL context from being
indexed. Since title is searchable in the FTS index, these conversations should
be included. Remove or modify the WHERE clause to ensure rows are indexed when
either the title or context contains non-NULL values, preventing incomplete
search results for title-only conversations that existed before the migration.

In `@crates/forge_repo/src/provider/anthropic.rs`:
- Around line 101-106: The interleaved_thinking_required logic has been updated
to include mythos and fable model IDs in the gating check, but the test
test_get_headers_drops_interleaved_thinking_for_4_6_plus_models does not cover
these new model IDs. Locate the
test_get_headers_drops_interleaved_thinking_for_4_6_plus_models test function
and add test cases for both mythos and fable model IDs to the existing
table-driven test to ensure the new gate is properly validated.

In `@crates/forge_repo/src/provider/openai_responses/response.rs`:
- Around line 1811-1817: The test uses panic! in the fallback pattern match arm
for the other variant when validating the ResponsesStreamEvent type, which
violates the assertion-driven testing guidelines. Replace the panic! call with
an assert!(matches!(...)) macro to validate that the actual event matches
ResponsesStreamEvent::ResponseCompleted, making this consistent with similar
assertion patterns used elsewhere in the test file.

In `@crates/forge_repo/src/provider/provider_repo.rs`:
- Around line 888-903: Restructure the test_ambient_config function into three
explicit phases with clear variable naming. In the setup phase, initialize the
configs and retrieve the ambient configuration. In the actual phase, extract all
the values being tested (id, api_key_vars, url_param_vars, response_type, url)
into variables with names prefixed like actual_id, actual_api_key_vars, etc. In
the expected phase, define the expected values for each field and use
pretty_assertions::assert_eq to compare each actual value against its
corresponding expected value, ensuring all assertions follow the repository's
test pattern guidelines.

In `@forge.schema.json`:
- Around line 18-22: The auto_install_vscode_extension property in the schema
has a default value of false, but the actual runtime default is true as
confirmed in the forge configuration and tests. Update the default value for the
auto_install_vscode_extension property from false to true in the schema to
ensure consistency between the documented schema contract and the actual runtime
behavior.

In `@shell-plugin/lib/actions/conversation.zsh`:
- Around line 121-123: The `_forge_action_conversation_tree()` function calls
the picker via `_forge_select` but discards the result without storing or
switching to the selected conversation. Add an early guard clause to check if an
active conversation exists (validate `_FORGE_CONVERSATION_ID`), capture the
result from the `_forge_select conversation --parent` call into a variable,
update `_FORGE_CONVERSATION_ID` with the selected ID, and then display or switch
context into the selected conversation session.

---

Outside diff comments:
In `@Cargo.toml`:
- Around line 62-136: The project lacks cargo-deny configuration which is
required by the coding guidelines for Cargo.toml changes. Create a deny.toml
configuration file at the project root with appropriate policy rules for
dependency validation, then add a cargo deny check step to the CI workflow in
.github/workflows/ci.yml to ensure cargo deny check runs on every CI build,
validating that dependencies meet the project's security and licensing
requirements.

In `@crates/forge_app/src/agent_executor.rs`:
- Around line 37-49: The Rust doc comment for the `execute` method is incomplete
and does not document the newly added `parent_id` parameter. Update the doc
comment to include a proper `# Arguments` section that documents all parameters
including `agent_id`, `task`, `ctx`, `conversation_id`, and `parent_id`, and add
an `# Errors` section that documents the types of errors the method can return
(currently documented as `anyhow::Result<ToolOutput>`). Ensure the documentation
follows Rust doc standards with clear descriptions for each parameter.

In `@crates/forge_app/src/fmt/todo_fmt.rs`:
- Around line 20-25: The TodoStatus::Cancelled icon assignment in the checkbox
match statement uses an empty string, but the removed-item rendering elsewhere
in the same file uses the icon 󰅙 for the same status, creating inconsistency.
Update the TodoStatus::Cancelled case in the checkbox match block to use the
same icon (󰅙) that is used in the removed-item rendering path to ensure
consistent output for cancelled todos across all render paths.

In `@crates/forge_infra/src/mcp_client.rs`:
- Around line 570-702: Add `# Errors` documentation sections to the three public
functions that return `anyhow::Result`: `mcp_auth`, `mcp_logout`, and
`mcp_logout_all`. For `mcp_auth`, document that errors can occur during OAuth
state initialization, authorization flow, token exchange, callback handling, or
credential storage. For `mcp_logout`, document that errors can occur during
credential removal. For `mcp_logout_all`, document that errors can occur during
credential removal. Place these sections after the `# Arguments` sections in
their respective doc comments.

In `@crates/forge_main/src/cli.rs`:
- Around line 1303-1317: The test functions test_list_conversation_alias_command
and test_list_session_alias_command currently only verify the variant shape of
ListCommand::Conversation but do not verify that the --parent filter argument is
correctly parsed and stored. Enhance both tests by parsing the CLI with the
--parent argument including a ConversationId value, then extract the parsed list
command and add explicit assertions that verify the parent filter is present and
contains the expected ConversationId value. This ensures the new CLI surface for
filtering by parent is working correctly, following the three-step test pattern
of setup, actual, and expected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 39c0ecf4-78a7-42ac-b42c-a14e22a3e6de

📥 Commits

Reviewing files that changed from the base of the PR and between ba9b6b8 and 7065903.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (61)
  • Cargo.toml
  • crates/forge_api/src/api.rs
  • crates/forge_api/src/forge_api.rs
  • crates/forge_app/src/agent_executor.rs
  • crates/forge_app/src/dto/anthropic/response.rs
  • crates/forge_app/src/dto/openai/transformers/minimax.rs
  • crates/forge_app/src/fmt/todo_fmt.rs
  • crates/forge_app/src/lib.rs
  • crates/forge_app/src/orch.rs
  • crates/forge_app/src/services.rs
  • crates/forge_app/src/tool_registry.rs
  • crates/forge_app/src/transformers/model_specific_reasoning.rs
  • crates/forge_app/src/utils.rs
  • crates/forge_config/.forge.toml
  • crates/forge_config/src/config.rs
  • crates/forge_domain/src/conversation.rs
  • crates/forge_domain/src/provider.rs
  • crates/forge_domain/src/repo.rs
  • crates/forge_domain/src/tools/call/context.rs
  • crates/forge_infra/src/auth/mcp_token_storage.rs
  • crates/forge_infra/src/http.rs
  • crates/forge_infra/src/mcp_client.rs
  • crates/forge_main/Cargo.toml
  • crates/forge_main/src/cli.rs
  • crates/forge_main/src/completer/command.rs
  • crates/forge_main/src/completer/input_completer.rs
  • crates/forge_main/src/completer/search_term.rs
  • crates/forge_main/src/conversation_selector.rs
  • crates/forge_main/src/editor.rs
  • crates/forge_main/src/highlighter.rs
  • crates/forge_main/src/model.rs
  • crates/forge_main/src/prompt.rs
  • crates/forge_main/src/state.rs
  • crates/forge_main/src/ui.rs
  • crates/forge_main/src/zsh/plugin.rs
  • crates/forge_repo/src/conversation/conversation_record.rs
  • crates/forge_repo/src/conversation/conversation_repo.rs
  • crates/forge_repo/src/database/migrations/2026-06-13-000000_add_parent_id_to_conversations/down.sql
  • crates/forge_repo/src/database/migrations/2026-06-13-000000_add_parent_id_to_conversations/up.sql
  • crates/forge_repo/src/database/migrations/2026-06-14-000001_add_source_to_conversations/down.sql
  • crates/forge_repo/src/database/migrations/2026-06-14-000001_add_source_to_conversations/up.sql
  • crates/forge_repo/src/database/migrations/2026-06-14-000002_add_fts5_to_conversations/down.sql
  • crates/forge_repo/src/database/migrations/2026-06-14-000002_add_fts5_to_conversations/up.sql
  • crates/forge_repo/src/database/schema.rs
  • crates/forge_repo/src/forge_repo.rs
  • crates/forge_repo/src/provider/anthropic.rs
  • crates/forge_repo/src/provider/openai_responses/repository.rs
  • crates/forge_repo/src/provider/openai_responses/request.rs
  • crates/forge_repo/src/provider/openai_responses/response.rs
  • crates/forge_repo/src/provider/provider.json
  • crates/forge_repo/src/provider/provider_repo.rs
  • crates/forge_select/src/input.rs
  • crates/forge_select/src/preview.rs
  • crates/forge_services/src/conversation.rs
  • crates/forge_tracker/Cargo.toml
  • forge.schema.json
  • rust-toolchain.toml
  • shell-plugin/lib/actions/conversation.zsh
  • shell-plugin/lib/dispatcher.zsh
  • shell-plugin/lib/helpers.zsh
  • vertex.json
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: update_release_draft
  • GitHub Check: semgrep-cloud-platform/scan
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: All tests should use three discrete steps: setup, actual, and expected with assertions using pretty_assertions::assert_eq
Use pretty_assertions for better error messages in tests
Use fixtures to create test data
Use assert_eq! for equality checks in tests
Use assert!(...) for boolean checks in tests
Use unwraps in test functions and anyhow::Result in fixtures
Use words like fixture, actual and expected in test function variable names
Fixtures should be generic and reusable
Tests should always be written in the same file as the source code
Use new, Default and derive_setters::Setters to create test fixtures, actual and expected values rather than struct literals or custom builder methods
Use unwrap() for tests unless the error information is useful; use expect with descriptive messages instead of panic! when error message is useful
Prefer using assert_eq on full objects instead of asserting each field individually
Use derive_setters to derive setters and use the strip_option and into attributes on struct types
Always write Rust docs (///) for all public methods, functions, structs, enums, and traits
Document parameters with # Arguments and errors with # Errors sections in Rust docs when applicable
Do not include code examples in Rust documentation - docs are for LLMs, focus on clear, concise functionality descriptions

**/*.rs: Run cargo fmt --check to ensure all Rust code formatting complies with standard conventions
Run cargo clippy --workspace --all-targets -- -D warnings with zero lints allowed for all Rust code

Files:

  • crates/forge_api/src/forge_api.rs
  • crates/forge_infra/src/auth/mcp_token_storage.rs
  • crates/forge_app/src/orch.rs
  • crates/forge_api/src/api.rs
  • crates/forge_app/src/lib.rs
  • crates/forge_config/src/config.rs
  • crates/forge_app/src/dto/anthropic/response.rs
  • crates/forge_repo/src/provider/provider_repo.rs
  • crates/forge_app/src/services.rs
  • crates/forge_domain/src/conversation.rs
  • crates/forge_infra/src/http.rs
  • crates/forge_domain/src/repo.rs
  • crates/forge_app/src/fmt/todo_fmt.rs
  • crates/forge_select/src/input.rs
  • crates/forge_main/src/zsh/plugin.rs
  • crates/forge_app/src/agent_executor.rs
  • crates/forge_app/src/dto/openai/transformers/minimax.rs
  • crates/forge_services/src/conversation.rs
  • crates/forge_main/src/completer/search_term.rs
  • crates/forge_repo/src/provider/openai_responses/request.rs
  • crates/forge_repo/src/forge_repo.rs
  • crates/forge_repo/src/conversation/conversation_record.rs
  • crates/forge_main/src/conversation_selector.rs
  • crates/forge_app/src/transformers/model_specific_reasoning.rs
  • crates/forge_repo/src/provider/anthropic.rs
  • crates/forge_app/src/utils.rs
  • crates/forge_app/src/tool_registry.rs
  • crates/forge_repo/src/database/schema.rs
  • crates/forge_domain/src/provider.rs
  • crates/forge_domain/src/tools/call/context.rs
  • crates/forge_main/src/completer/command.rs
  • crates/forge_main/src/model.rs
  • crates/forge_select/src/preview.rs
  • crates/forge_main/src/completer/input_completer.rs
  • crates/forge_main/src/highlighter.rs
  • crates/forge_repo/src/conversation/conversation_repo.rs
  • crates/forge_repo/src/provider/openai_responses/repository.rs
  • crates/forge_main/src/state.rs
  • crates/forge_repo/src/provider/openai_responses/response.rs
  • crates/forge_infra/src/mcp_client.rs
  • crates/forge_main/src/editor.rs
  • crates/forge_main/src/prompt.rs
  • crates/forge_main/src/cli.rs
  • crates/forge_main/src/ui.rs
**/*service*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*service*.rs: Use anyhow::Result for error handling in services and repositories
Avoid Box<dyn ...> in services - use concrete types and generics instead
Implement new() constructor without type bounds on services; apply bounds only on methods that need them
Compose infrastructure dependencies using the + operator to combine multiple infrastructure traits into a single bound in services
Store infrastructure as Arc<T> in services for cheap cloning and shared ownership
For simple services with a single infrastructure dependency, use tuple struct pattern struct Service<T>(Arc<T>)

Files:

  • crates/forge_app/src/services.rs
{Cargo.toml,Cargo.lock,deny.toml}

📄 CodeRabbit inference engine (CLAUDE.md)

Run cargo deny check and ensure dependency audit passes before merging PRs

Files:

  • Cargo.toml
🔇 Additional comments (23)
crates/forge_config/.forge.toml (1)

35-35: LGTM!

rust-toolchain.toml (1)

2-2: LGTM!

crates/forge_tracker/Cargo.toml (1)

16-16: Dependency bump is safe; cargo deny verification is not applicable to this repository.

The posthog-rs 0.12.0 bump has no known security vulnerabilities (verified against RustSec and NVD as of June 2026). However, this repository does not have a deny.toml configuration file or a cargo deny compliance gate in its CI pipeline, so the original requirement to run cargo deny check does not apply. The structural change is correct and ready to merge.

			> Likely an incorrect or invalid review comment.
crates/forge_domain/src/conversation.rs (1)

49-50: LGTM!

Also applies to: 76-77

crates/forge_domain/src/repo.rs (1)

97-133: LGTM!

crates/forge_repo/src/database/migrations/2026-06-13-000000_add_parent_id_to_conversations/down.sql (1)

1-1: LGTM!

crates/forge_repo/src/database/migrations/2026-06-14-000001_add_source_to_conversations/down.sql (1)

1-2: LGTM!

crates/forge_api/src/forge_api.rs (1)

195-227: LGTM!

crates/forge_app/src/agent_executor.rs (1)

70-78: LGTM!

crates/forge_repo/src/database/migrations/2026-06-14-000002_add_fts5_to_conversations/down.sql (1)

1-4: LGTM!

crates/forge_repo/src/forge_repo.rs (1)

143-178: LGTM!

crates/forge_services/src/conversation.rs (1)

70-96: LGTM!

crates/forge_app/src/services.rs (1)

261-278: LGTM!

Also applies to: 657-683

crates/forge_api/src/api.rs (1)

82-99: LGTM!

crates/forge_main/src/zsh/plugin.rs (1)

421-434: LGTM!

crates/forge_repo/src/conversation/conversation_repo.rs (1)

150-173: Verify that required Rust quality gates are executed and passing.

The coding guidelines mandate running cargo fmt --check and cargo clippy --workspace --all-targets -- -D warnings for all Rust files. The current CI workflow (ci.yml) does not explicitly run these checks. While the autofix workflow runs related checks on nightly (cargo +nightly fmt --all and cargo +nightly clippy with --fix), these differ from the mandated format and stricter flags. Ensure this PR passes both required quality gates before merge.

crates/forge_main/Cargo.toml (1)

42-42: No cargo deny audit required for this repository.

The repository does not use cargo deny in its CI workflow or configuration. There is no deny.toml file, and the actual CI checks run cargo llvm-cov for coverage and cargo build for validation. The rustyline dependency is correctly configured using the workspace mechanism.

			> Likely an incorrect or invalid review comment.
crates/forge_main/src/highlighter.rs (1)

3-15: LGTM!

Also applies to: 27-63

crates/forge_select/src/preview.rs (1)

10-13: LGTM!

Also applies to: 438-443

crates/forge_app/src/transformers/model_specific_reasoning.rs (1)

30-40: LGTM!

Also applies to: 94-97, 120-120, 167-223

crates/forge_app/src/dto/openai/transformers/minimax.rs (1)

7-16: LGTM!

Also applies to: 28-31, 35-39, 45-46, 156-187

crates/forge_app/src/utils.rs (1)

584-585: LGTM!

Also applies to: 614-615, 1688-1720

crates/forge_infra/src/auth/mcp_token_storage.rs (1)

101-105: LGTM!

Also applies to: 130-139

Comment on lines +82 to +85
// Claude Mythos / Fable models (1M context)
if model_id.starts_with("claude-mythos") || model_id.starts_with("claude-fable") {
return Some(1_000_000);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Add regression tests for the new Mythos/Fable branches.

Line 83 and Line 84 introduce a new 1M-context path, and Line 37-Line 38 add new modality matching, but there is no explicit test for either branch. Please add focused tests for claude-mythos* and claude-fable* in get_context_length and Model -> forge_domain::Model conversion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_app/src/dto/anthropic/response.rs` around lines 82 - 85, The new
code branches for claude-mythos and claude-fable models (returning 1M context)
and the new modality matching logic lack test coverage. Add focused regression
tests for the get_context_length function that verify both claude-mythos* and
claude-fable* model IDs correctly return a context length of 1,000,000, and also
add tests for the Model to forge_domain::Model conversion to ensure the new
modality matching handles these models properly without breaking existing
behavior.

Comment on lines +497 to +515
#[test]
fn test_auto_install_vscode_extension_defaults_to_true() {
let actual = ConfigReader::default().read_defaults().build().unwrap();

assert_eq!(actual.auto_install_vscode_extension, true);
}

#[test]
fn test_auto_install_vscode_extension_can_be_disabled() {
let toml = "auto_install_vscode_extension = false\n";

let actual = ConfigReader::default()
.read_defaults()
.read_toml(toml)
.build()
.unwrap();

assert_eq!(actual.auto_install_vscode_extension, false);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align new tests with the required setup/actual/expected structure.

These tests currently skip a clear expected step/variable, which conflicts with the Rust test-style rules for this repo.

Proposed test-structure fix
 #[test]
 fn test_auto_install_vscode_extension_defaults_to_true() {
-    let actual = ConfigReader::default().read_defaults().build().unwrap();
-
-    assert_eq!(actual.auto_install_vscode_extension, true);
+    let setup_reader = ConfigReader::default();
+    let actual = setup_reader.read_defaults().build().unwrap();
+    let expected = true;
+
+    assert_eq!(actual.auto_install_vscode_extension, expected);
 }

 #[test]
 fn test_auto_install_vscode_extension_can_be_disabled() {
-    let toml = "auto_install_vscode_extension = false\n";
+    let fixture_toml = "auto_install_vscode_extension = false\n";

     let actual = ConfigReader::default()
         .read_defaults()
-        .read_toml(toml)
+        .read_toml(fixture_toml)
         .build()
         .unwrap();

-    assert_eq!(actual.auto_install_vscode_extension, false);
+    let expected = false;
+    assert_eq!(actual.auto_install_vscode_extension, expected);
 }

As per coding guidelines, "**/*.rs: All tests should use three discrete steps: setup, actual, and expected..." and "Use words like fixture, actual and expected in test function variable names".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[test]
fn test_auto_install_vscode_extension_defaults_to_true() {
let actual = ConfigReader::default().read_defaults().build().unwrap();
assert_eq!(actual.auto_install_vscode_extension, true);
}
#[test]
fn test_auto_install_vscode_extension_can_be_disabled() {
let toml = "auto_install_vscode_extension = false\n";
let actual = ConfigReader::default()
.read_defaults()
.read_toml(toml)
.build()
.unwrap();
assert_eq!(actual.auto_install_vscode_extension, false);
}
#[test]
fn test_auto_install_vscode_extension_defaults_to_true() {
let setup_reader = ConfigReader::default();
let actual = setup_reader.read_defaults().build().unwrap();
let expected = true;
assert_eq!(actual.auto_install_vscode_extension, expected);
}
#[test]
fn test_auto_install_vscode_extension_can_be_disabled() {
let fixture_toml = "auto_install_vscode_extension = false\n";
let actual = ConfigReader::default()
.read_defaults()
.read_toml(fixture_toml)
.build()
.unwrap();
let expected = false;
assert_eq!(actual.auto_install_vscode_extension, expected);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_config/src/config.rs` around lines 497 - 515, Both test
functions test_auto_install_vscode_extension_defaults_to_true and
test_auto_install_vscode_extension_can_be_disabled need to be refactored to
follow the required three-step test structure: setup, actual, and expected. Add
explicit expected variables that define the anticipated values (true for the
defaults test and false for the disabled test), then update each assertion to
compare the actual.auto_install_vscode_extension value against these expected
variables instead of using literal values in the assertion.

Source: Coding guidelines

Comment on lines +705 to +714
#[test]
fn test_ambient_display_name() {
assert_eq!(ProviderId::AMBIENT.to_string(), "Ambient");
}

#[test]
fn test_ambient_in_built_in_providers() {
let built_in = ProviderId::built_in_providers();
assert!(built_in.contains(&ProviderId::AMBIENT));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Align new ambient tests with the required setup/actual/expected structure.

These new tests assert directly without discrete setup/actual/expected steps and variable naming that includes actual/expected (and fixture when applicable), which is required by your Rust test conventions.

As per coding guidelines, "All tests should use three discrete steps: setup, actual, and expected with assertions using pretty_assertions::assert_eq" and "Use words like fixture, actual and expected in test function variable names".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_domain/src/provider.rs` around lines 705 - 714, The test
functions test_ambient_display_name and test_ambient_in_built_in_providers do
not follow the required setup/actual/expected structure with proper variable
naming conventions. Refactor both tests to include discrete setup, actual, and
expected steps using variable names that include expected and actual (and
fixture where applicable), and replace the assertions with
pretty_assertions::assert_eq calls to align with your Rust test conventions.

Source: Coding guidelines

Comment on lines +339 to 342
let config =
StreamableHttpClientTransportConfig::with_uri(http.url.clone()).auth_header(token);
let transport = StreamableHttpClientTransport::from_config(config);
Ok(Arc::new(self.client_info().serve(transport).await?))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify header propagation consistency across HTTP transport builders.
rg -n -C3 'create_standard_http_connection|connect_with_token|custom_headers\(|auth_header\(' crates/forge_infra/src/mcp_client.rs

Repository: KooshaPari/forgecode

Length of output: 2760


Propagate configured custom headers in OAuth-authenticated connections.

The connect_with_token method omits custom headers that are included in create_standard_http_connection. Servers requiring both custom headers and OAuth authentication will fail silently on the OAuth path.

🔧 Fix
 async fn connect_with_token(
     &self,
     http: &McpHttpServer,
     token: &str,
 ) -> anyhow::Result<Arc<RmcpClient>> {
-    let config =
-        StreamableHttpClientTransportConfig::with_uri(http.url.clone()).auth_header(token);
+    let config = StreamableHttpClientTransportConfig::with_uri(http.url.clone())
+        .custom_headers(build_header_map(&http.headers))
+        .auth_header(token);
     let transport = StreamableHttpClientTransport::from_config(config);
     Ok(Arc::new(self.client_info().serve(transport).await?))
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let config =
StreamableHttpClientTransportConfig::with_uri(http.url.clone()).auth_header(token);
let transport = StreamableHttpClientTransport::from_config(config);
Ok(Arc::new(self.client_info().serve(transport).await?))
let config = StreamableHttpClientTransportConfig::with_uri(http.url.clone())
.custom_headers(build_header_map(&http.headers))
.auth_header(token);
let transport = StreamableHttpClientTransport::from_config(config);
Ok(Arc::new(self.client_info().serve(transport).await?))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_infra/src/mcp_client.rs` around lines 339 - 342, The
connect_with_token method in crates/forge_infra/src/mcp_client.rs (lines
339-342) creates a StreamableHttpClientTransportConfig with only the URI and
auth_header, but does not include custom headers. This causes servers that
require both OAuth authentication and custom headers to fail. Modify the config
creation to also include custom headers by adding the same header configuration
logic that is used in create_standard_http_connection, ensuring both the token
and custom headers are propagated to the StreamableHttpClientTransportConfig
before creating the transport.

Comment on lines +557 to +568
fn build_header_map(
headers: &BTreeMap<String, String>,
) -> std::collections::HashMap<HeaderName, HeaderValue> {
headers
.iter()
.filter_map(|(k, v)| {
let name = k.parse::<HeaderName>().ok()?;
let val = v.parse::<HeaderValue>().ok()?;
Some((name, val))
})
.collect()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Do not silently drop invalid configured headers.

filter_map discards invalid header names/values with no signal. That makes header misconfiguration hard to detect and can cause opaque auth failures.

🔧 Proposed fix
-fn build_header_map(
-    headers: &BTreeMap<String, String>,
-) -> std::collections::HashMap<HeaderName, HeaderValue> {
-    headers
-        .iter()
-        .filter_map(|(k, v)| {
-            let name = k.parse::<HeaderName>().ok()?;
-            let val = v.parse::<HeaderValue>().ok()?;
-            Some((name, val))
-        })
-        .collect()
+fn build_header_map(
+    headers: &BTreeMap<String, String>,
+) -> anyhow::Result<std::collections::HashMap<HeaderName, HeaderValue>> {
+    headers
+        .iter()
+        .map(|(k, v)| {
+            let name = k
+                .parse::<HeaderName>()
+                .map_err(|e| anyhow::anyhow!("Invalid MCP header name '{}': {}", k, e))?;
+            let val = v
+                .parse::<HeaderValue>()
+                .map_err(|e| anyhow::anyhow!("Invalid MCP header value for '{}': {}", k, e))?;
+            Ok((name, val))
+        })
+        .collect()
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn build_header_map(
headers: &BTreeMap<String, String>,
) -> std::collections::HashMap<HeaderName, HeaderValue> {
headers
.iter()
.filter_map(|(k, v)| {
let name = k.parse::<HeaderName>().ok()?;
let val = v.parse::<HeaderValue>().ok()?;
Some((name, val))
})
.collect()
}
fn build_header_map(
headers: &BTreeMap<String, String>,
) -> anyhow::Result<std::collections::HashMap<HeaderName, HeaderValue>> {
headers
.iter()
.map(|(k, v)| {
let name = k
.parse::<HeaderName>()
.map_err(|e| anyhow::anyhow!("Invalid MCP header name '{}': {}", k, e))?;
let val = v
.parse::<HeaderValue>()
.map_err(|e| anyhow::anyhow!("Invalid MCP header value for '{}': {}", k, e))?;
Ok((name, val))
})
.collect()
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_infra/src/mcp_client.rs` around lines 557 - 568, The
build_header_map function uses filter_map to silently discard headers that fail
to parse as valid HeaderName or HeaderValue, making header misconfiguration
difficult to detect and debug. Instead of silently filtering out invalid headers
with the .ok()? pattern, explicitly log or signal each parsing failure
(including the key, value, and parse error details) so that configuration issues
are visible. This ensures that header misconfiguration problems do not cause
opaque auth failures.

Comment on lines +101 to +106
!(id.contains("opus-4-8")
|| id.contains("opus-4-7")
|| id.contains("opus-4-6")
|| id.contains("sonnet-4-6")
|| id.contains("mythos")
|| id.contains("fable"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Extend header-gating tests to cover Mythos/Fable IDs.

Line 105 and Line 106 add mythos/fable into interleaved_thinking_required, but test_get_headers_drops_interleaved_thinking_for_4_6_plus_models does not include those model IDs. Add them to the existing table test so this new gate is locked in.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_repo/src/provider/anthropic.rs` around lines 101 - 106, The
interleaved_thinking_required logic has been updated to include mythos and fable
model IDs in the gating check, but the test
test_get_headers_drops_interleaved_thinking_for_4_6_plus_models does not cover
these new model IDs. Locate the
test_get_headers_drops_interleaved_thinking_for_4_6_plus_models test function
and add test cases for both mythos and fable model IDs to the existing
table-driven test to ensure the new gate is properly validated.

Comment on lines +1811 to +1817
match actual {
ResponsesStreamEvent::ResponseCompleted { response } => {
assert_eq!(response.end_turn, Some(false));
assert_eq!(response.usage.unwrap().into_domain(), expected);
}
other => panic!("Expected ResponseCompleted, got {:?}", other),
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, verify the file exists and check the lines in question
if [ -f "crates/forge_repo/src/provider/openai_responses/response.rs" ]; then
    echo "=== File exists. Checking line count ==="
    wc -l crates/forge_repo/src/provider/openai_responses/response.rs
    echo ""
    echo "=== Content around lines 1811-1817 ==="
    sed -n '1800,1825p' crates/forge_repo/src/provider/openai_responses/response.rs
else
    echo "File not found"
fi

Repository: KooshaPari/forgecode

Length of output: 1270


🏁 Script executed:

# Verify this is within a test function and check the full test context
sed -n '1780,1825p' crates/forge_repo/src/provider/openai_responses/response.rs

Repository: KooshaPari/forgecode

Length of output: 1897


🏁 Script executed:

# Check if there are other similar patterns in the test file to understand consistency
rg -n "panic!" crates/forge_repo/src/provider/openai_responses/response.rs | head -20

Repository: KooshaPari/forgecode

Length of output: 281


🏁 Script executed:

# Check the context of the other panic! calls to see if there's a pattern
sed -n '1755,1780p' crates/forge_repo/src/provider/openai_responses/response.rs
echo ""
echo "=== Content around second panic at 1778 ==="
sed -n '1768,1785p' crates/forge_repo/src/provider/openai_responses/response.rs

Repository: KooshaPari/forgecode

Length of output: 1682


🏁 Script executed:

# Verify the coding guidelines match what's in the review
# Check if there are setter methods or other test utilities for ResponsesStreamEvent
rg -A 5 "impl.*ResponsesStreamEvent" crates/forge_repo/src/provider/openai_responses/response.rs | head -40

Repository: KooshaPari/forgecode

Length of output: 46


🏁 Script executed:

# Let me check if there are any examples of how other pattern match errors are handled in tests
rg -B 3 -A 3 "matches!\(" crates/forge_repo/src/provider/openai_responses/response.rs | head -40

Repository: KooshaPari/forgecode

Length of output: 799


🏁 Script executed:

# Check if there are git changes to understand if these panic! calls were added or pre-existing
git diff HEAD -- crates/forge_repo/src/provider/openai_responses/response.rs | grep -A 5 -B 5 "panic!" | head -60

Repository: KooshaPari/forgecode

Length of output: 46


🏁 Script executed:

# Check the broader test patterns in the file to understand best practices used
rg -B 2 -A 6 "#\[test\]" crates/forge_repo/src/provider/openai_responses/response.rs | grep -A 8 "ResponseCompleted\|Keepalive\|Unknown" | head -80

Repository: KooshaPari/forgecode

Length of output: 390


🏁 Script executed:

# Check the coding guidelines in the repo to verify they match what's quoted
find . -name "*.md" -type f | xargs grep -l "assert_eq\|panic!" 2>/dev/null | head -5

Repository: KooshaPari/forgecode

Length of output: 123


🏁 Script executed:

# Check AGENTS.md for the coding guidelines
grep -A 5 -B 5 "assert_eq\|panic!" ./AGENTS.md | head -50

Repository: KooshaPari/forgecode

Length of output: 1402


🏁 Script executed:

# Check if the pattern with assert!(matches!(...)) is the preferred style in similar test context
sed -n '1640,1680p' crates/forge_repo/src/provider/openai_responses/response.rs

Repository: KooshaPari/forgecode

Length of output: 1691


🏁 Script executed:

# Check test patterns to see what's the most idiomatic approach used in this file
rg -B 5 -A 5 "ResponsesStreamEvent::" crates/forge_repo/src/provider/openai_responses/response.rs | grep -A 6 "match actual"

Repository: KooshaPari/forgecode

Length of output: 867


Replace the panic! fallback with assertion-based matching in this test.

Line 1816 uses panic! to validate the stream event type; the coding guidelines require tests to be assertion-driven (assert!, assert_eq!). This pattern is inconsistent with similar tests in the file that use assert!(matches!(...)) to validate enum variants.

Suggested patch
-        match actual {
-            ResponsesStreamEvent::ResponseCompleted { response } => {
-                assert_eq!(response.end_turn, Some(false));
-                assert_eq!(response.usage.unwrap().into_domain(), expected);
-            }
-            other => panic!("Expected ResponseCompleted, got {:?}", other),
-        }
+        assert!(matches!(
+            actual,
+            ResponsesStreamEvent::ResponseCompleted { .. }
+        ));
+        let response = match actual {
+            ResponsesStreamEvent::ResponseCompleted { response } => response,
+            _ => unreachable!("asserted above"),
+        };
+        assert_eq!(response.end_turn, Some(false));
+        assert_eq!(response.usage.unwrap().into_domain(), expected);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
match actual {
ResponsesStreamEvent::ResponseCompleted { response } => {
assert_eq!(response.end_turn, Some(false));
assert_eq!(response.usage.unwrap().into_domain(), expected);
}
other => panic!("Expected ResponseCompleted, got {:?}", other),
}
assert!(matches!(
actual,
ResponsesStreamEvent::ResponseCompleted { .. }
));
let response = match actual {
ResponsesStreamEvent::ResponseCompleted { response } => response,
_ => unreachable!("asserted above"),
};
assert_eq!(response.end_turn, Some(false));
assert_eq!(response.usage.unwrap().into_domain(), expected);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_repo/src/provider/openai_responses/response.rs` around lines
1811 - 1817, The test uses panic! in the fallback pattern match arm for the
other variant when validating the ResponsesStreamEvent type, which violates the
assertion-driven testing guidelines. Replace the panic! call with an
assert!(matches!(...)) macro to validate that the actual event matches
ResponsesStreamEvent::ResponseCompleted, making this consistent with similar
assertion patterns used elsewhere in the test file.

Source: Coding guidelines

Comment on lines +888 to +903
#[test]
fn test_ambient_config() {
let configs = get_provider_configs();
let config = configs
.iter()
.find(|c| c.id == ProviderId::AMBIENT)
.unwrap();
assert_eq!(config.id, ProviderId::AMBIENT);
assert_eq!(config.api_key_vars, Some("AMBIENT_API_KEY".to_string()));
assert!(config.url_param_vars.is_empty());
assert_eq!(config.response_type, Some(ProviderResponse::OpenAI));
assert_eq!(
config.url.as_str(),
"https://api.ambient.xyz/v1/chat/completions"
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Refactor test_ambient_config to the required test-step pattern.

Please restructure this test into explicit setup/actual/expected phases and use actual/expected variable naming consistently to match repository test rules.

As per coding guidelines, "All tests should use three discrete steps: setup, actual, and expected with assertions using pretty_assertions::assert_eq" and "Use words like fixture, actual and expected in test function variable names".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/forge_repo/src/provider/provider_repo.rs` around lines 888 - 903,
Restructure the test_ambient_config function into three explicit phases with
clear variable naming. In the setup phase, initialize the configs and retrieve
the ambient configuration. In the actual phase, extract all the values being
tested (id, api_key_vars, url_param_vars, response_type, url) into variables
with names prefixed like actual_id, actual_api_key_vars, etc. In the expected
phase, define the expected values for each field and use
pretty_assertions::assert_eq to compare each actual value against its
corresponding expected value, ensuring all assertions follow the repository's
test pattern guidelines.

Source: Coding guidelines

Comment thread forge.schema.json
Comment on lines +18 to +22
"auto_install_vscode_extension": {
"description": "Enables automatic VS Code extension installation when Forge runs inside\nVS Code and the extension is not already installed.",
"type": "boolean",
"default": false
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Schema default conflicts with actual runtime default.

auto_install_vscode_extension is documented here as default: false, but defaults resolve to true (crates/forge_config/.forge.toml Line 35 and config tests). Update schema default to keep contract consistency.

Proposed fix
     "auto_install_vscode_extension": {
       "description": "Enables automatic VS Code extension installation when Forge runs inside\nVS Code and the extension is not already installed.",
       "type": "boolean",
-      "default": false
+      "default": true
     },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@forge.schema.json` around lines 18 - 22, The auto_install_vscode_extension
property in the schema has a default value of false, but the actual runtime
default is true as confirmed in the forge configuration and tests. Update the
default value for the auto_install_vscode_extension property from false to true
in the schema to ensure consistency between the documented schema contract and
the actual runtime behavior.

Comment on lines +121 to +123
function _forge_action_conversation_tree() {
_forge_select conversation --parent "$_FORGE_CONVERSATION_ID"
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

conversation-tree discards the selected conversation and never switches context.

The action invokes the picker but does not store the chosen ID, update _FORGE_CONVERSATION_ID, or display/switch into that session. Add selection handling (and an early guard when no active conversation exists).

Suggested fix
 function _forge_action_conversation_tree() {
-    _forge_select conversation --parent "$_FORGE_CONVERSATION_ID"
+    if [[ -z "$_FORGE_CONVERSATION_ID" ]]; then
+        _forge_log error "No active conversation. Start a conversation first."
+        return 0
+    fi
+
+    local conversation_id
+    conversation_id=$(_forge_select conversation --parent "$_FORGE_CONVERSATION_ID")
+
+    if [[ -n "$conversation_id" ]]; then
+        _forge_switch_conversation "$conversation_id"
+        echo
+        _forge_exec conversation show "$conversation_id"
+        _forge_exec conversation info "$conversation_id"
+        _forge_log success "Switched to subagent \033[1m${conversation_id}\033[0m"
+    fi
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shell-plugin/lib/actions/conversation.zsh` around lines 121 - 123, The
`_forge_action_conversation_tree()` function calls the picker via
`_forge_select` but discards the result without storing or switching to the
selected conversation. Add an early guard clause to check if an active
conversation exists (validate `_FORGE_CONVERSATION_ID`), capture the result from
the `_forge_select conversation --parent` call into a variable, update
`_FORGE_CONVERSATION_ID` with the selected ID, and then display or switch
context into the selected conversation session.

/// Creates a new ToolCallContext with default values
pub fn new(metrics: Metrics) -> Self {
Self { sender: None, metrics: Arc::new(Mutex::new(metrics)) }
Self { sender: None, metrics: Arc::new(Mutex::new(metrics)), conversation_id: None, parent_id: None, source: 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.

CRITICAL: This single-line struct initializer exceeds rustfmt's default max_width (100 cols) — cargo fmt --check will fail. The new fields force a multi-line layout.

Suggested change
Self { sender: None, metrics: Arc::new(Mutex::new(metrics)), conversation_id: None, parent_id: None, source: None }
Self {
sender: None,
metrics: Arc::new(Mutex::new(metrics)),
conversation_id: None,
parent_id: None,
source: None,
}

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Jun 15, 2026

Copy link
Copy Markdown

Code Review Summary

Status: 1 New Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 0
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
crates/forge_domain/src/tools/call/context.rs 23 ToolCallContext::new initializer on a single line exceeds rustfmt's 100-col max_width; cargo fmt --check will fail.
Other Observations (not in diff)

Existing inline review comments (21 from prior reviewers) already cover the major concerns:

  • parent_id column lacks an index (migration 2026-06-13-000000_add_parent_id_to_conversations/up.sql:1)
  • FTS5 backfill excludes title-only historical rows (2026-06-14-000002_add_fts5_to_conversations/up.sql:46)
  • Silent .ok() on parent_id parse failure (conversation_record.rs:1029)
  • Unchecked usizei64 cast for SQL LIMIT (conversation_repo.rs:190)
  • Schema default mismatch (forge.schema.json:22)
  • panic! in test pattern (openai_responses/response.rs:1817)
  • Test refactor to fixture/actual/expected pattern (provider_repo.rs:903)
  • interleaved_thinking_required Mythos/Fable test coverage (anthropic.rs:106)
  • SelectCommand::Conversation parent-filter handling (ui.rs:522)
  • Conversation picker duplicates + subagent visibility (state.rs:34, model.rs:689, ui.rs:522, prompt.rs:289, completer/*)
  • regression: reedlinerustyline migration and rmcp 0.10 → 1.0 / posthog-rs 0.7 → 0.12 bumps; async-openai 0.34 → 0.41. Verify changelog impact and feature parity (no transport-sse-client-reqwest feature on rmcp 1.0 — confirm transport paths still work).
  • Additional FTS5/parent_id considerations already raised on mcp_client.rs, forge_app/src/dto/anthropic/response.rs, and shell-plugin (CodeRabbit comments).
Files Reviewed (63 files)
  • Cargo.lock, Cargo.toml — dep bumps (regression risk; see notes)
  • crates/forge_api/src/api.rs, forge_api.rs — new public API surface
  • crates/forge_app/src/agent_executor.rs, orch.rs, tool_registry.rs, services.rs — wiring parent/source into tool context
  • crates/forge_app/src/dto/anthropic/response.rs — Mythos/Fable detection (1M ctx)
  • crates/forge_app/src/dto/openai/transformers/minimax.rs — minimax-m2/m3 params
  • crates/forge_app/src/fmt/todo_fmt.rs — cancelled-icon glyph swap
  • crates/forge_app/src/lib.rspub mod retry (visibility change)
  • crates/forge_app/src/transformers/model_specific_reasoning.rs — Opus 4.8 + Mythos/Fable
  • crates/forge_app/src/utils.rs — gemini propertyNames sanitizer
  • crates/forge_config/.forge.toml, config.rsauto_install_vscode_extension default = true
  • crates/forge_domain/src/conversation.rs, provider.rs, repo.rs, tools/call/context.rs — domain types
  • crates/forge_infra/src/auth/mcp_token_storage.rs, http.rs, mcp_client.rs
  • crates/forge_main/... — picker, completer, ui, zsh plugin, editor, highlighter, model, state, prompt
  • crates/forge_repo/... — repo, conversation record/repo, FTS5 migration, provider/openai_responses
  • crates/forge_services/src/conversation.rs
  • crates/forge_select/src/input.rs, preview.rs
  • crates/forge_tracker/Cargo.toml
  • forge.schema.json, vertex.json, package-lock.json, rust-toolchain.toml
  • shell-plugin/lib/...

Fix these issues in Kilo Cloud


Reviewed by minimax-m3 · 2,277,953 tokens

@KooshaPari KooshaPari merged commit 70e43e7 into KooshaPari:main Jun 16, 2026
6 checks passed
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.

10 participants