Skip to content

fix: Resolve backlog plan generation for Claude-compatible providers#809

Merged
gsxdsm merged 1 commit intoAutoMaker-Org:v0.15.0rcfrom
patrick-patel:fix/backlog-plan-claude-compatible-provider
Feb 25, 2026
Merged

fix: Resolve backlog plan generation for Claude-compatible providers#809
gsxdsm merged 1 commit intoAutoMaker-Org:v0.15.0rcfrom
patrick-patel:fix/backlog-plan-claude-compatible-provider

Conversation

@patrick-patel
Copy link
Copy Markdown
Contributor

@patrick-patel patrick-patel commented Feb 25, 2026

Summary

Plan generation was failing when using MiniMax or other Claude-compatible providers. This PR fixes provider resolution and request formatting in apps/server/src/routes/backlog-plan/generate-plan.ts.

  • Resolve provider via getProviderByModelId() when the Plan dialog sends a model (e.g. MiniMax-M2.1) so the correct baseUrl and credentials are used instead of the default Anthropic endpoint
  • Fall back to getPhaseModelWithOverrides('backlogPlanningModel') when model lookup finds no provider, so the phase’s provider is used when the resolved model matches
  • Use a plain system prompt instead of the claude_code preset when a Claude-compatible provider is set; the preset is for native Claude CLI and was breaking requests to MiniMax/GLM HTTP APIs

Testing

  • npm run build:server passes
  • npm run format:check passes
  • Plan generation verified with MiniMax as backlog planning model

Summary by CodeRabbit

Release Notes

  • New Features
    • Extended support for Claude-compatible AI providers (including MiniMax and GLM) in backlog plan generation.
    • Improved automatic provider detection and configuration based on model selection.
    • Enhanced system prompt handling for compatible providers to optimize API flow.
    • Refined credential management and provider resolution logic.

…sends model

When the Plan dialog sends a model (e.g. MiniMax-M2.1 from phase
settings), the server now:

- Calls getProviderByModelId() so the correct provider config
  (baseUrl, credentials) is used for backlog plan generation.
- Falls back to getPhaseModelWithOverrides('backlogPlanningModel')
  when model lookup finds no provider, so the phase's provider is
  used when the model matches.
- Uses a plain system prompt instead of the claude_code preset when
  a Claude-compatible provider is set; the preset is for native
  Claude CLI and can break requests to MiniMax/GLM APIs.

Previously the request was sent to the default Anthropic endpoint
and/or used the preset, causing plan generation to fail for
MiniMax/GLM users.

Co-authored-by: Cursor <cursoragent@cursor.com>
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @patrick-patel, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses an issue where plan generation was failing for Claude-compatible providers like MiniMax due to incorrect provider resolution and system prompt formatting. The changes ensure that the system correctly identifies and utilizes the appropriate provider settings and formats requests correctly for these models, thereby restoring functionality for backlog plan generation.

Highlights

  • Provider Resolution: Implemented logic to correctly resolve Claude-compatible providers (e.g., MiniMax, GLM) using getProviderByModelId when a specific model is sent from the client, ensuring the correct base URL and credentials are used.
  • Fallback Mechanism: Added a fallback to use the phase's configured provider if the initial model-based provider lookup does not yield a result, but the resolved model matches the effective model.
  • System Prompt Handling: Adjusted the system prompt generation to use a plain system prompt for Claude-compatible providers, avoiding the claude_code preset which is intended for native Claude CLI and was causing request failures.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • apps/server/src/routes/backlog-plan/generate-plan.ts
    • Imported getProviderByModelId to facilitate provider lookup.
    • Introduced new logic to resolve claudeCompatibleProvider and its associated credentials based on the effectiveModel.
    • Added a fallback mechanism to claudeCompatibleProvider resolution, checking phase settings if direct model lookup fails.
    • Modified the system prompt selection to use a plain systemPrompt when a claudeCompatibleProvider is detected, preventing the use of the claude_code preset.
Activity
  • Verified that npm run build:server passes.
  • Verified that npm run format:check passes.
  • Confirmed successful plan generation using MiniMax as the backlog planning model.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 25, 2026

📝 Walkthrough

Walkthrough

Added provider resolution logic to the backlog plan generation handler. When a model is explicitly provided or determined via phase overrides, the code resolves the associated Claude-compatible provider. If found, the handler bypasses the claude_code system prompt in favor of directly using the existing system prompt. Provider credentials are updated accordingly.

Changes

Cohort / File(s) Summary
Provider Resolution for Backlog Plan Generation
apps/server/src/routes/backlog-plan/generate-plan.ts
Added import of getProviderByModelId and introduced logic to resolve Claude-compatible providers (MiniMax, GLM, etc.) when a model is provided. Adjusted prompt construction to bypass claude_code preset for these providers, using the existing system prompt directly instead. Extended model resolution path to consider provider credentials and override them if a provider is discovered.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant GeneratePlan as generate-plan handler
    participant SettingsHelper as getProviderByModelId
    participant PromptBuilder as Prompt Constructor

    Caller->>GeneratePlan: Request backlog plan with model
    alt Explicit model provided
        GeneratePlan->>SettingsHelper: Resolve provider by model ID
        SettingsHelper-->>GeneratePlan: Provider found (e.g., MiniMax, GLM)
        GeneratePlan->>GeneratePlan: Set claudeCompatibleProvider
        GeneratePlan->>GeneratePlan: Update credentials if needed
    else No provider found
        GeneratePlan->>GeneratePlan: Attempt fallback via phase overrides
    end
    
    alt Claude-compatible provider active
        GeneratePlan->>PromptBuilder: Use existing systemPrompt directly
        PromptBuilder-->>GeneratePlan: Bypass claude_code preset
    else Native Claude provider
        GeneratePlan->>PromptBuilder: Use claude_code preset-driven prompt
    end
    
    GeneratePlan-->>Caller: Return configured plan with appropriate prompt
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 Through model lands, a rabbit quests,
Finding providers—nature's best!
Claude-compatible friends align,
System prompts in harmony shine,
Provider paths—perfectly fine! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: fixing backlog plan generation for Claude-compatible providers, which is the core purpose of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively addresses the issue of backlog plan generation failing for Claude-compatible providers. The changes to resolve the provider and adjust the system prompt are logical and well-implemented. I have one suggestion to simplify the code by removing some redundant variable assignments, which should improve maintainability.

Comment on lines +242 to +262
if (providerResult.provider) {
claudeCompatibleProvider = providerResult.provider;
if (providerResult.credentials) {
credentials = providerResult.credentials;
}
}
// Fallback: use phase settings provider if model lookup found nothing (e.g. model
// string format differs from provider's model id, but backlog planning phase has providerId).
if (!claudeCompatibleProvider) {
const phaseResult = await getPhaseModelWithOverrides(
'backlogPlanningModel',
settingsService,
projectPath,
'[BacklogPlan]'
);
const phaseResolved = resolvePhaseModel(phaseResult.phaseModel);
if (phaseResult.provider && phaseResolved.model === effectiveModel) {
claudeCompatibleProvider = phaseResult.provider;
credentials = phaseResult.credentials ?? credentials;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The credentials variable is initialized on line 234, but then it's reassigned multiple times within this block with what appears to be the same value. The helper functions getProviderByModelId and getPhaseModelWithOverrides both retrieve the same global credentials object. You can simplify this logic by removing these redundant assignments, as the credentials object is passed to executeQuery later anyway.

        if (providerResult.provider) {
          claudeCompatibleProvider = providerResult.provider;
        }
        // Fallback: use phase settings provider if model lookup found nothing (e.g. model
        // string format differs from provider's model id, but backlog planning phase has providerId).
        if (!claudeCompatibleProvider) {
          const phaseResult = await getPhaseModelWithOverrides(
            'backlogPlanningModel',
            settingsService,
            projectPath,
            '[BacklogPlan]'
          );
          const phaseResolved = resolvePhaseModel(phaseResult.phaseModel);
          if (phaseResult.provider && phaseResolved.model === effectiveModel) {
            claudeCompatibleProvider = phaseResult.provider;
          }
        }

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/server/src/routes/backlog-plan/generate-plan.ts (2)

235-263: Extract provider-resolution logic into a service

This block adds substantial provider/credential business logic inside the route handler. Please move it to services/ and keep the route focused on orchestration.

As per coding guidelines, "Server business logic should be organized into services in the services/ directory, with Express route handlers in routes/ that delegate to services".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/server/src/routes/backlog-plan/generate-plan.ts` around lines 235 - 263,
Extract the provider/credential resolution logic from the route handler into a
new service function (e.g., create a service in services/ like
resolveProviderForModel) that encapsulates the sequence using
getProviderByModelId, fallback to getPhaseModelWithOverrides and
resolvePhaseModel, and returns { provider, credentials } given inputs
(effectiveModel, settingsService, projectPath, and a context tag like
'[BacklogPlan]'). In the route (generate-plan.ts) replace the inlined block that
sets claudeCompatibleProvider and credentials with a single call to this new
service and use its returned provider/credentials; ensure the new service
handles both primary lookup and the phase fallback and preserves existing
precedence (providerResult first, then phaseResult if model matches) and
null-safety for settingsService.

38-39: Import getProviderByModelId via an @automaker/* package

This new relative import adds another cross-module relative dependency in a TS server file. Please consume it from a shared @automaker/* package export instead.

As per coding guidelines, "Always import from shared packages (@automaker/*), never from old paths or relative imports to other modules".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/server/src/routes/backlog-plan/generate-plan.ts` around lines 38 - 39,
Replace the relative import of getProviderByModelId with the shared package
export: remove the '../../lib/settings-helpers.js' relative import and instead
import getProviderByModelId from the appropriate `@automaker/`* package (e.g.,
`@automaker/settings-helpers` or the shared package that re-exports it); update
the import statement that currently references getProviderByModelId so the
symbol is consumed from the `@automaker` package and ensure any other references
to getProviderByModelId remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/server/src/routes/backlog-plan/generate-plan.ts`:
- Around line 251-259: The equality check between phaseResolved.model and
effectiveModel can miss matches because phaseResolved.model may be an
unnormalized provider alias; update the comparison in the block handling
getPhaseModelWithOverrides / resolvePhaseModel so both sides are normalized via
resolveModelString (e.g., compute normalizedPhaseModel =
resolveModelString(phaseResolved.model) and normalizedEffective =
resolveModelString(effectiveModel)) and compare those normalized values before
assigning claudeCompatibleProvider; keep the rest of the logic intact.

---

Nitpick comments:
In `@apps/server/src/routes/backlog-plan/generate-plan.ts`:
- Around line 235-263: Extract the provider/credential resolution logic from the
route handler into a new service function (e.g., create a service in services/
like resolveProviderForModel) that encapsulates the sequence using
getProviderByModelId, fallback to getPhaseModelWithOverrides and
resolvePhaseModel, and returns { provider, credentials } given inputs
(effectiveModel, settingsService, projectPath, and a context tag like
'[BacklogPlan]'). In the route (generate-plan.ts) replace the inlined block that
sets claudeCompatibleProvider and credentials with a single call to this new
service and use its returned provider/credentials; ensure the new service
handles both primary lookup and the phase fallback and preserves existing
precedence (providerResult first, then phaseResult if model matches) and
null-safety for settingsService.
- Around line 38-39: Replace the relative import of getProviderByModelId with
the shared package export: remove the '../../lib/settings-helpers.js' relative
import and instead import getProviderByModelId from the appropriate `@automaker/`*
package (e.g., `@automaker/settings-helpers` or the shared package that re-exports
it); update the import statement that currently references getProviderByModelId
so the symbol is consumed from the `@automaker` package and ensure any other
references to getProviderByModelId remain unchanged.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0330c70 and 1c304bd.

📒 Files selected for processing (1)
  • apps/server/src/routes/backlog-plan/generate-plan.ts

Comment on lines +251 to +259
const phaseResult = await getPhaseModelWithOverrides(
'backlogPlanningModel',
settingsService,
projectPath,
'[BacklogPlan]'
);
const phaseResolved = resolvePhaseModel(phaseResult.phaseModel);
if (phaseResult.provider && phaseResolved.model === effectiveModel) {
claudeCompatibleProvider = phaseResult.provider;
Copy link
Copy Markdown
Contributor

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:

cat -n apps/server/src/routes/backlog-plan/generate-plan.ts | sed -n '240,270p'

Repository: AutoMaker-Org/automaker

Length of output: 1532


🏁 Script executed:

rg -n "resolveModelString|resolvePhaseModel" apps/server/src/routes/backlog-plan/generate-plan.ts -A 2 -B 2

Repository: AutoMaker-Org/automaker

Length of output: 1320


🏁 Script executed:

fd -t f model-resolver.ts -o model-resolver.js

Repository: AutoMaker-Org/automaker

Length of output: 220


🏁 Script executed:

find . -path "*/model-resolver*" -type f | grep -E "\.(ts|tsx|js|jsx)$" | head -20

Repository: AutoMaker-Org/automaker

Length of output: 275


🏁 Script executed:

cat -n ./libs/model-resolver/src/index.ts

Repository: AutoMaker-Org/automaker

Length of output: 618


🏁 Script executed:

cat -n ./libs/model-resolver/src/resolver.ts | head -150

Repository: AutoMaker-Org/automaker

Length of output: 6735


🏁 Script executed:

cat -n ./libs/model-resolver/src/resolver.ts | sed -n '150,250p'

Repository: AutoMaker-Org/automaker

Length of output: 4325


🏁 Script executed:

rg -n "providerId" ./libs/model-resolver/src/resolver.ts | head -20

Repository: AutoMaker-Org/automaker

Length of output: 646


🏁 Script executed:

rg -B5 -A5 "getPhaseModelWithOverrides" apps/server/src/routes/backlog-plan/generate-plan.ts | head -40

Repository: AutoMaker-Org/automaker

Length of output: 1176


🏁 Script executed:

cat -n apps/server/src/lib/settings-helpers.ts | grep -A 30 "getPhaseModelWithOverrides"

Repository: AutoMaker-Org/automaker

Length of output: 4144


🏁 Script executed:

rg -n "phaseModel.providerId|providerId.*phaseModel" apps/server/src -A 3 -B 3

Repository: AutoMaker-Org/automaker

Length of output: 1298


Normalize model strings before comparison to handle alias/provider-model mismatches

When phaseModel.providerId is set, resolvePhaseModel() returns the model string unchanged (without normalization). This can cause the equality check at line 258 to fail when comparing against effectiveModel, which has been normalized through resolveModelString(). For example, if effectiveModel is "claude-3-5-sonnet-20241022" but phaseResolved.model is "sonnet" (from a provider configuration), the fallback provider won't be used despite both referring to the same model.

Normalize both values with resolveModelString() before comparing.

Proposed fix
-import { resolvePhaseModel } from '@automaker/model-resolver';
+import { resolvePhaseModel, resolveModelString } from '@automaker/model-resolver';
...
-          const phaseResolved = resolvePhaseModel(phaseResult.phaseModel);
-          if (phaseResult.provider && phaseResolved.model === effectiveModel) {
+          const phaseResolved = resolvePhaseModel(phaseResult.phaseModel);
+          const normalizedPhaseModel = resolveModelString(phaseResolved.model);
+          const normalizedEffectiveModel = resolveModelString(effectiveModel);
+          if (phaseResult.provider && normalizedPhaseModel === normalizedEffectiveModel) {
📝 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
const phaseResult = await getPhaseModelWithOverrides(
'backlogPlanningModel',
settingsService,
projectPath,
'[BacklogPlan]'
);
const phaseResolved = resolvePhaseModel(phaseResult.phaseModel);
if (phaseResult.provider && phaseResolved.model === effectiveModel) {
claudeCompatibleProvider = phaseResult.provider;
const phaseResult = await getPhaseModelWithOverrides(
'backlogPlanningModel',
settingsService,
projectPath,
'[BacklogPlan]'
);
const phaseResolved = resolvePhaseModel(phaseResult.phaseModel);
const normalizedPhaseModel = resolveModelString(phaseResolved.model);
const normalizedEffectiveModel = resolveModelString(effectiveModel);
if (phaseResult.provider && normalizedPhaseModel === normalizedEffectiveModel) {
claudeCompatibleProvider = phaseResult.provider;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/server/src/routes/backlog-plan/generate-plan.ts` around lines 251 - 259,
The equality check between phaseResolved.model and effectiveModel can miss
matches because phaseResolved.model may be an unnormalized provider alias;
update the comparison in the block handling getPhaseModelWithOverrides /
resolvePhaseModel so both sides are normalized via resolveModelString (e.g.,
compute normalizedPhaseModel = resolveModelString(phaseResolved.model) and
normalizedEffective = resolveModelString(effectiveModel)) and compare those
normalized values before assigning claudeCompatibleProvider; keep the rest of
the logic intact.

@gsxdsm gsxdsm merged commit 09a4d3f into AutoMaker-Org:v0.15.0rc Feb 25, 2026
8 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.

2 participants