fix: Refactor of gemini-cli provider for structured output#987
fix: Refactor of gemini-cli provider for structured output#987ben-vargas wants to merge 4 commits intoeyaltoledano:nextfrom
Conversation
* fix: prevent CLAUDE.md overwrite by using imports - Copy Task Master instructions to .taskmaster/CLAUDE.md - Add import section to user's CLAUDE.md instead of overwriting - Preserve existing user content - Clean removal of Task Master content on uninstall Closes eyaltoledano#929 * chore: add changeset for Claude import fix
…edano#968) * feat: add task master (tm) custom slash commands Add comprehensive task management system integration via custom slash commands. Includes commands for: - Project initialization and setup - Task parsing from PRD documents - Task creation, update, and removal - Subtask management - Dependency tracking and validation - Complexity analysis and task expansion - Project status and reporting - Workflow automation This provides a complete task management workflow directly within Claude Code. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: add changeset --------- Co-authored-by: neno-is-ooo <204701868+neno-is-ooo@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 42fedf9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Major refactor to fix GitHub issue eyaltoledano#983 where gemini-cli's expand --all was producing identical generic subtasks. The issue was that Gemini CLI returns structured JSON correctly but generateObject expects objects at root level, not arrays. Changes: - Simplified gemini-cli.js from 664 lines to 213 lines - Implemented generateText override that detects JSON requests and redirects to generateObject with proper schema detection - Added object-wrapper prompt variants for commands that expect arrays: - analyze-complexity: wraps array in {analysis: [...]} - update-tasks: wraps array in {tasks: [...]} - expand-task: already expects {subtasks: [...]} - Updated command files to detect gemini-cli provider and use object-wrapper variants automatically - Fixed expand-task prompts with clearer dependency examples using proper Handlebars syntax ({{add}} helper) instead of confusing [{{id}} + 1] - Removed all the complex error handling, retries, and manual JSON parsing that was no longer needed Result: - Gemini CLI now works consistently across all commands - expand --all generates unique, contextual subtasks with proper dependencies - Clean architecture where provider-specific handling is encapsulated - Commands remain provider-agnostic
0a80daf to
42fedf9
Compare
Crunchyman-ralph
left a comment
There was a problem hiding this comment.
Nice PR, but I don't think we should have a different prompt per model, I think its worth looking into consolidating it, reduces code complexity and overhead.
| }, | ||
| "gemini-cli": { | ||
| "system": "You are an AI assistant helping to update software development tasks based on new context.\nYou will be given a set of tasks and a prompt describing changes or new implementation details.\nYour job is to update the tasks to reflect these changes, while preserving their basic structure.\n\nGuidelines:\n1. Maintain the same IDs, statuses, and dependencies unless specifically mentioned in the prompt\n2. Update titles, descriptions, details, and test strategies to reflect the new information\n3. Do not change anything unnecessarily - just adapt what needs to change based on the prompt\n4. You should return ALL the tasks in order, not just the modified ones\n5. Return a complete valid JSON object with the updated tasks array\n6. VERY IMPORTANT: Preserve all subtasks marked as \"done\" or \"completed\" - do not modify their content\n7. For tasks with completed subtasks, build upon what has already been done rather than rewriting everything\n8. If an existing completed subtask needs to be changed/undone based on the new context, DO NOT modify it directly\n9. Instead, add a new subtask that clearly indicates what needs to be changed or replaced\n10. Use the existence of completed subtasks as an opportunity to make new subtasks more specific and targeted\n\nThe changes described in the prompt should be applied to ALL tasks in the list.", | ||
| "user": "Here are the tasks to update:\n{{{json tasks}}}\n\nPlease update these tasks based on the following new context:\n{{updatePrompt}}\n\nIMPORTANT: In the tasks JSON above, any subtasks with \"status\": \"done\" or \"status\": \"completed\" should be preserved exactly as is. Build your changes around these completed items.{{#if projectContext}}\n\n# Project Context\n\n{{projectContext}}{{/if}}\n\nReturn only the updated tasks as a valid JSON object with a single key \"tasks\" containing the array of updated tasks.\n\nExpected format:\n{\n \"tasks\": [\n // ... updated task objects\n ]\n}" |
There was a problem hiding this comment.
don't like the idea of having separate prompts, think we can merge it ?
| "gemini-cli": { | ||
| "system": "You are an AI assistant helping with task breakdown for software development.\nYou need to break down a high-level task into {{#if (gt subtaskCount 0)}}{{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks that can be implemented one by one.\n\nSubtasks should:\n1. Be specific and actionable implementation steps\n2. Follow a logical sequence\n3. Each handle a distinct part of the parent task\n4. Include clear guidance on implementation approach\n5. Have appropriate dependency chains between subtasks (using the new sequential IDs)\n6. Collectively cover all aspects of the parent task\n\nFor each subtask, provide:\n- id: Sequential integer starting from the provided nextSubtaskId\n- title: Clear, specific title\n- description: Detailed description\n- dependencies: Array of prerequisite subtask IDs (use the new sequential IDs)\n- details: Implementation details, the output should be in string\n- testStrategy: Optional testing approach\n\nRespond ONLY with a valid JSON object containing a single key \"subtasks\" whose value is an array matching the structure described. Do not include any explanatory text, markdown formatting, or code block markers.", |
There was a problem hiding this comment.
same here, think we can merge these into 1 prompt ?
| "gemini-cli-complexity": { | ||
| "condition": "expansionPrompt && isGeminiCli", | ||
| "system": "You are an AI assistant helping with task breakdown. Generate {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks based on the provided prompt and context.\n\nRespond ONLY with a valid JSON object containing a single key \"subtasks\" whose value is an array of the generated subtask objects.\n\nEach subtask must follow this exact structure:\n- id: Sequential integer starting from {{nextSubtaskId}}\n- title: Clear, actionable subtask title\n- description: What this subtask accomplishes\n- dependencies: Array of IDs this subtask depends on (use [] for no dependencies)\n- details: Implementation guidance\n- status: Must be \"pending\"\n- testStrategy: (optional) How to test this subtask\n\nDependency rules:\n- First subtask should have dependencies: []\n- Later subtasks can depend on earlier ones: dependencies: [{{nextSubtaskId}}] or [{{nextSubtaskId}}, {{add nextSubtaskId 1}}]\n- Only reference IDs from THIS response\n\nDo not include any other text or explanation.", |
There was a problem hiding this comment.
same here, merge into one potentially
| }, | ||
| "gemini-cli": { | ||
| "system": "You are an expert software architect and project manager analyzing task complexity. Respond only with the requested valid JSON object.", | ||
| "user": "Analyze the following tasks to determine their complexity (1-10 scale) and recommend the number of subtasks for expansion. Provide a brief reasoning and an initial expansion prompt for each.{{#if useResearch}} Consider current best practices, common implementation patterns, and industry standards in your analysis.{{/if}}\n\nTasks:\n{{{json tasks}}}\n{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}\n{{/if}}\n\nRespond ONLY with a valid JSON object matching the schema:\n{\n \"analysis\": [\n {\n \"taskId\": <number>,\n \"taskTitle\": \"<string>\",\n \"complexityScore\": <number 1-10>,\n \"recommendedSubtasks\": <number>,\n \"expansionPrompt\": \"<string>\",\n \"reasoning\": \"<string>\"\n },\n ...\n ]\n}\n\nDo not include any explanatory text, markdown formatting, or code block markers before or after the JSON object." |
There was a problem hiding this comment.
if gemini cli needs to be wrapped, then why not wrap them all ? would allow us to have the same prompt, less overhead of prompt differences
| logFn, | ||
| isMCP | ||
| isMCP, | ||
| promptVariant // Pass the promptVariant to handle gemini-cli |
There was a problem hiding this comment.
now we're adding more complexity to the code instead of resolving the core issue
There was a problem hiding this comment.
yeah, core issue is that we use generateText too much... but with all the path changes and other refactors going on, not super hot on trying that refactor right now.
There was a problem hiding this comment.
I'll merge the path changes stuff, and maybe you can tackle that ?
|
Closing this since we're going in the #1034 direction as discussed |
Fix: Refactor of Gemini CLI Provider for Structured Output
Summary
This PR completely refactors the
gemini-cliprovider to fix issue #983 whereexpand --allwas producing identical generic subtasks for all tasks. The refactor simplifies the implementation from 664 lines to 213 lines while making it more robust and maintainable.Problem Statement
Issue #983: Gemini CLI
expand --allproduces identical generic subtasksWhen using the Gemini CLI provider with the
tm expand --allcommand, instead of generating unique, contextual subtasks for each task, it was producing the same generic subtasks repeatedly:Root Cause Analysis
After extensive debugging, we discovered the core issue:
generateObjectmethod expects objects at the root level, not arraysanalyze-complexityandupdate-tasksexpect array responses:[{...}, {...}]generateObjectvalidates against schemas expecting:{key: [{...}, {...}]}Solution Overview
1. Provider-Level Solution
Instead of modifying individual commands, we implemented a clean solution at the provider level:
2. Gemini-CLI Specific Prompt Variants
For commands that expect arrays, we created gemini-cli specific variants that request properly structured objects:
3. Automatic Provider Detection
Commands now automatically detect Gemini CLI and use the appropriate variant:
Detailed File Changes
1.
src/ai-providers/gemini-cli.jsMajor refactor - reduced from 664 to 213 lines
What Changed:
_extractSystemMessage,_detectJsonRequest,_getJsonEnforcementPrompt,_isValidJson,extractJsongenerateTextoverride that detects JSON requests and redirects togenerateObjectWhy:
generateTextto return structured JSON through prompts and parsinggenerateObjectwhich is designed for structured output2.
src/prompts/analyze-complexity.jsonAdded gemini-cli variant
What Changed:
"gemini-cli"variant that wraps the expected array in an object:{"analysis": [...]}Why:
generateObjectexpects an object at root level, not an array{"analysis": [{task1}, {task2}]}instead of[{task1}, {task2}]3.
src/prompts/update-tasks.jsonAdded gemini-cli variant
What Changed:
"gemini-cli"variant that wraps the tasks array:{"tasks": [...]}Why:
generateObjectvalidation4.
src/prompts/expand-task.json(+gemini-cli and gemini-cli-complexity variants)Added gemini-cli specific variants with improved dependency examples
What Changed:
"gemini-cli"variant for standard expansion"gemini-cli-complexity"variant for expansion from complexity reports{{add nextSubtaskId 1}}instead of confusing[{{nextSubtaskId}} + 1]"dependencies": []complexity-report,research, ordefaultvariants to preserve behavior for other providersWhy:
tm expand --allwith gemini-cli, it needs the object wrapper structure{{add}}helper properly calculates the next ID5.
scripts/modules/task-manager/analyze-task-complexity.jsAdded provider detection and variant selection
What Changed:
getMainProviderandgetResearchProvidervariant→promptVariantfor clarityWhy:
6.
scripts/modules/task-manager/update-tasks.jsAdded provider detection and improved parsing
What Changed:
parseUpdatedTasksFromTextto handle object-wrapped responsesvariant→promptVariantWhy:
7.
scripts/modules/task-manager/expand-task.jsAdded provider detection and fixed variant selection logic
What Changed:
expansionPromptText && isGeminiClifirstgemini-cli-complexityvariant selection for complexity report expansionsvariantKey→promptVariantWhy:
gemini-cli-complexitywhen expanding from complexity reports with gemini-cli8.
tests/unit/ai-providers/gemini-cli.test.jsUpdated tests to match new implementation
What Changed:
_extractSystemMessage,_detectJsonRequest, etc.)Why:
9.
tests/unit/scripts/modules/task-manager/expand-task.test.jsFixed missing mock functions
What Changed:
getMainProviderandgetResearchProviderto config-manager mockWhy:
10.
tests/unit/scripts/modules/task-manager/update-tasks.test.jsFixed missing mock functions
What Changed:
getMainProviderandgetResearchProviderto config-manager mockWhy:
Testing Results
Before the Fix
After the Fix
Test Suite Results
Technical Details
Schema Detection Logic
The provider now detects the expected response structure by analyzing the prompt content:
Error Handling
Compatibility
Impact
This refactor:
promptVariantinstead ofvariant)Future Considerations
This pattern of provider-specific prompt variants could be extended to:
The clean separation of concerns makes it easy to add new variants without touching core logic.
Checklist