Skip to content

Commit 0d5eaf2

Browse files
authored
Merge pull request subsy#123 from manascb1344/feature/issue-122-opencode-variant-support
feat(opencode): add support for --variant flag
2 parents 2ad2390 + b44d434 commit 0d5eaf2

8 files changed

Lines changed: 105 additions & 1 deletion

File tree

src/commands/run.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ export function parseRunArgs(args: string[]): ExtendedRuntimeOptions {
115115
}
116116
break;
117117

118+
case '--variant':
119+
if (nextArg && !nextArg.startsWith('-')) {
120+
options.variant = nextArg;
121+
i++;
122+
}
123+
break;
124+
118125
case '--tracker':
119126
if (nextArg && !nextArg.startsWith('-')) {
120127
options.tracker = nextArg;
@@ -239,6 +246,7 @@ Options:
239246
--prd <path> PRD file path (auto-switches to json tracker)
240247
--agent <name> Override agent plugin (e.g., claude, opencode)
241248
--model <name> Override model (e.g., opus, sonnet)
249+
--variant <level> Model variant/reasoning effort (minimal, high, max)
242250
--tracker <name> Override tracker plugin (e.g., beads, beads-bv, json)
243251
--prompt <path> Custom prompt file (default: based on tracker mode)
244252
--output-dir <path> Directory for iteration logs (default: .ralph-tui/iterations)

src/config/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,14 @@ function getDefaultAgentConfig(
299299
};
300300
}
301301

302+
// Apply CLI --variant to agent options (for agents like OpenCode that support it)
303+
if (options.variant) {
304+
result = {
305+
...result,
306+
options: { ...result.options, variant: options.variant },
307+
};
308+
}
309+
302310
// Apply fallbackAgents shorthand (only if not already set on agent config)
303311
if (storedConfig.fallbackAgents && !result.fallbackAgents) {
304312
result = {

src/config/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ export interface RuntimeOptions {
9090
/** Override model for the agent */
9191
model?: string;
9292

93+
/** Override model variant for the agent (e.g., minimal, high, max for Gemini) */
94+
variant?: string;
95+
9396
/** Override tracker plugin */
9497
tracker?: string;
9598

src/plugins/agents/builtin/opencode.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ export class OpenCodeAgentPlugin extends BaseAgentPlugin {
135135
/** Model name (without provider prefix) */
136136
private model?: string;
137137

138+
/** Model variant (provider-specific reasoning effort: high, max, minimal) */
139+
private variant?: string;
140+
138141
/** Agent type to use (general, build, plan) */
139142
private agent: string = 'general';
140143

@@ -153,6 +156,12 @@ export class OpenCodeAgentPlugin extends BaseAgentPlugin {
153156
this.model = config.model;
154157
}
155158

159+
// Accept any variant string - validation is delegated to OpenCode CLI
160+
// Different models support different variant values (e.g., Gemini: minimal/high/max)
161+
if (typeof config.variant === 'string' && config.variant.length > 0) {
162+
this.variant = config.variant;
163+
}
164+
156165
if (
157166
typeof config.agent === 'string' &&
158167
['general', 'build', 'plan'].includes(config.agent)
@@ -328,6 +337,11 @@ export class OpenCodeAgentPlugin extends BaseAgentPlugin {
328337
args.push('--model', modelToUse);
329338
}
330339

340+
// Add model variant if specified
341+
if (this.variant) {
342+
args.push('--variant', this.variant);
343+
}
344+
331345
// Always use JSON format for streaming output parsing
332346
// This gives us structured events (text, tool_use, etc.) that we can format nicely
333347
args.push('--format', 'json');
@@ -423,6 +437,8 @@ export class OpenCodeAgentPlugin extends BaseAgentPlugin {
423437
return 'Invalid agent type. Must be one of: general, build, plan';
424438
}
425439

440+
// Variant validation is delegated to OpenCode CLI - different models support different values
441+
426442
return null;
427443
}
428444

tests/commands/run.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,28 @@ describe('run command', () => {
7272
});
7373
});
7474

75+
describe('variant option', () => {
76+
test('parses --variant with value', () => {
77+
const result = parseRunArgs(['--variant', 'high']);
78+
expect(result.variant).toBe('high');
79+
});
80+
81+
test('parses --variant max', () => {
82+
const result = parseRunArgs(['--variant', 'max']);
83+
expect(result.variant).toBe('max');
84+
});
85+
86+
test('parses --variant minimal', () => {
87+
const result = parseRunArgs(['--variant', 'minimal']);
88+
expect(result.variant).toBe('minimal');
89+
});
90+
91+
test('ignores --variant without value', () => {
92+
const result = parseRunArgs(['--variant']);
93+
expect(result.variant).toBeUndefined();
94+
});
95+
});
96+
7597
describe('tracker option', () => {
7698
test('parses --tracker with name', () => {
7799
const result = parseRunArgs(['--tracker', 'beads']);
@@ -262,6 +284,7 @@ describe('run command', () => {
262284
'--epic', 'my-epic',
263285
'--agent', 'claude',
264286
'--model', 'opus',
287+
'--variant', 'high',
265288
'--tracker', 'beads-bv',
266289
'--iterations', '15',
267290
'--delay', '1000',
@@ -272,6 +295,7 @@ describe('run command', () => {
272295
expect(result.epicId).toBe('my-epic');
273296
expect(result.agent).toBe('claude');
274297
expect(result.model).toBe('opus');
298+
expect(result.variant).toBe('high');
275299
expect(result.tracker).toBe('beads-bv');
276300
expect(result.iterations).toBe(15);
277301
expect(result.iterationDelay).toBe(1000);
@@ -322,6 +346,7 @@ describe('run command', () => {
322346
const output = consoleOutput.join('\n');
323347
expect(output).toContain('--prd');
324348
expect(output).toContain('--model');
349+
expect(output).toContain('--variant');
325350
expect(output).toContain('--delay');
326351
expect(output).toContain('--cwd');
327352
expect(output).toContain('--resume');

tests/plugins/opencode-agent.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ describe('OpenCodeAgentPlugin', () => {
5959
expect(await plugin.isReady()).toBe(true);
6060
});
6161

62+
test('accepts variant config', async () => {
63+
// Variant validation is delegated to OpenCode CLI - any string is accepted
64+
await plugin.initialize({ variant: 'high' });
65+
expect(await plugin.isReady()).toBe(true);
66+
});
67+
68+
test('accepts any variant string', async () => {
69+
// Different models support different variants, so we accept any value
70+
await plugin.initialize({ variant: 'custom-variant' });
71+
expect(await plugin.isReady()).toBe(true);
72+
});
73+
6274
test('accepts agent type config', async () => {
6375
await plugin.initialize({ agent: 'build' });
6476
expect(await plugin.isReady()).toBe(true);
@@ -140,6 +152,15 @@ describe('OpenCodeAgentPlugin', () => {
140152
expect(await plugin.validateSetup({ provider: 'google' })).toBeNull();
141153
expect(await plugin.validateSetup({ provider: 'custom-provider' })).toBeNull();
142154
});
155+
156+
test('accepts any variant string', async () => {
157+
// Variant validation is delegated to OpenCode CLI - different models have different values
158+
expect(await plugin.validateSetup({ variant: 'minimal' })).toBeNull();
159+
expect(await plugin.validateSetup({ variant: 'high' })).toBeNull();
160+
expect(await plugin.validateSetup({ variant: 'max' })).toBeNull();
161+
expect(await plugin.validateSetup({ variant: 'custom' })).toBeNull();
162+
expect(await plugin.validateSetup({ variant: '' })).toBeNull();
163+
});
143164
});
144165

145166
describe('getSetupQuestions', () => {

website/content/docs/plugins/agents/opencode.mdx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ opencode --version
4343
ralph-tui run --prd ./prd.json --agent opencode --model anthropic/claude-3-5-sonnet
4444
```
4545
</Step>
46+
47+
<Step title="Select a Variant">
48+
Control reasoning effort with `--variant`:
49+
50+
```bash
51+
ralph-tui run --prd ./prd.json --agent opencode --model google/gemini-2.5-pro --variant high
52+
```
53+
</Step>
4654
</Steps>
4755

4856
## Configuration
@@ -58,6 +66,7 @@ agent = "opencode"
5866
[agentOptions]
5967
provider = "anthropic"
6068
model = "claude-3-5-sonnet"
69+
variant = "high"
6170
```
6271

6372
### Full Config
@@ -74,6 +83,7 @@ timeout = 300000
7483
[agents.options]
7584
provider = "anthropic"
7685
model = "claude-3-5-sonnet"
86+
variant = "high"
7787
agent = "general"
7888
format = "default"
7989
```
@@ -84,6 +94,7 @@ format = "default"
8494
|--------|------|---------|-------------|
8595
| `provider` | string | - | AI provider: `anthropic`, `openai`, `google`, `xai`, `ollama` |
8696
| `model` | string | - | Model name within the provider |
97+
| `variant` | string | - | Model reasoning effort (model-specific, e.g., `minimal`, `high`, `max` for Gemini) |
8798
| `agent` | string | `"general"` | Agent type: `general`, `build`, or `plan` |
8899
| `format` | string | `"default"` | Output format: `default` or `json` |
89100
| `timeout` | number | `0` | Execution timeout in ms (0 = no timeout) |
@@ -140,6 +151,18 @@ OpenCode supports multiple AI providers. Models are specified in `provider/model
140151
Model names are validated by the provider's API. Invalid model names result in errors from OpenCode, not Ralph TUI.
141152
</Callout>
142153

154+
## Model Variants
155+
156+
You can control the reasoning effort for supported models using the `variant` option:
157+
158+
```bash
159+
ralph-tui run --agent opencode --model google/gemini-2.5-pro --variant max
160+
```
161+
162+
<Callout type="info">
163+
Variant values are model-specific and validated by the provider's API. Check your model's documentation for supported variants.
164+
</Callout>
165+
143166
## Agent Types
144167

145168
OpenCode offers specialized agent personalities:

website/next-env.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// <reference types="next" />
22
/// <reference types="next/image-types/global" />
3-
import "./.next/types/routes.d.ts";
3+
import "./.next/dev/types/routes.d.ts";
44

55
// NOTE: This file should not be edited
66
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

0 commit comments

Comments
 (0)