Bladeren bron

fix(preset): catch all whitespace in multi-word guard, show variant/options in summary

Greptile P2 fixes:
- Use /\s/ regex instead of includes(' ') to catch tabs and other whitespace
- Include variant and options fields in switch confirmation message

Adds 2 tests: tab-separated argument guard, variant+options in summary.
ReqX 4 maanden geleden
bovenliggende
commit
a29cb835b8
2 gewijzigde bestanden met toevoegingen van 49 en 1 verwijderingen
  1. 46 0
      src/tools/preset-manager.test.ts
  2. 3 1
      src/tools/preset-manager.ts

+ 46 - 0
src/tools/preset-manager.test.ts

@@ -355,6 +355,26 @@ describe('createPresetManager', () => {
       expect(ctx.client.config.update).not.toHaveBeenCalled();
     });
 
+    test('catches tab-separated arguments', async () => {
+      const ctx = createMockContext();
+      const config: PluginConfig = {
+        presets: {
+          cheap: { orchestrator: { model: 'anthropic/claude-3.5-haiku' } },
+        },
+      };
+      const manager = createPresetManager(ctx, config);
+      const output = createOutput();
+
+      await manager.handleCommandExecuteBefore(
+        { command: 'preset', sessionID: 's1', arguments: 'cheap\tpowerful' },
+        output,
+      );
+
+      const text = getOutputText(output);
+      expect(text).toContain('cannot contain spaces');
+      expect(ctx.client.config.update).not.toHaveBeenCalled();
+    });
+
     test('skips agents with empty overrides in mixed preset', async () => {
       const ctx = createMockContext();
       const config: PluginConfig = {
@@ -451,6 +471,32 @@ describe('createPresetManager', () => {
       });
     });
 
+    test('shows variant and options in switch summary', async () => {
+      const ctx = createMockContext();
+      const config: PluginConfig = {
+        presets: {
+          thinker: {
+            oracle: {
+              model: 'anthropic/claude-sonnet-4-6',
+              variant: 'thinking',
+              options: { thinking: { type: 'enabled', budgetTokens: 10000 } },
+            },
+          },
+        },
+      };
+      const manager = createPresetManager(ctx, config);
+      const output = createOutput();
+
+      await manager.handleCommandExecuteBefore(
+        { command: 'preset', sessionID: 's1', arguments: 'thinker' },
+        output,
+      );
+
+      const text = getOutputText(output);
+      expect(text).toContain('variant: thinking');
+      expect(text).toContain('options: yes');
+    });
+
     test('tracks active preset after switch', async () => {
       const ctx = createMockContext();
       const config: PluginConfig = {

+ 3 - 1
src/tools/preset-manager.ts

@@ -54,7 +54,7 @@ export function createPresetManager(ctx: PluginInput, config: PluginConfig) {
     }
 
     // Guard against multi-word arguments
-    if (arg.includes(' ')) {
+    if (/\s/.test(arg)) {
       const suggestion = arg.split(/\s+/)[0];
       output.parts.push(
         createInternalAgentTextPart(
@@ -150,8 +150,10 @@ export function createPresetManager(ctx: PluginInput, config: PluginConfig) {
         .map(([name, cfg]) => {
           const parts: string[] = [name];
           if (cfg.model) parts.push(`model: ${cfg.model}`);
+          if (cfg.variant) parts.push(`variant: ${cfg.variant}`);
           if (cfg.temperature !== undefined)
             parts.push(`temp: ${cfg.temperature}`);
+          if (cfg.options) parts.push('options: yes');
           return parts.join(' → ');
         })
         .join('\n');