winter-super-cli 2026.5.27 → 2026.5.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,13 @@
1
1
  /**
2
2
  * Dynamic System Prompt Builder
3
3
  * Builds context-aware system prompts based on task, role, and session state.
4
+ * Small models get compact structural guidance so the task stays in focus.
4
5
  */
5
6
 
7
+ import { isSmallModel, getModelCapabilityLabel } from '../model-capabilities.js';
8
+
6
9
  const BASE_PRINCIPLES = [
10
+ 'Execute, don\'t describe - Do the work, don\'t write plans about doing the work',
7
11
  'Think Before Coding - State assumptions, ask when unclear',
8
12
  'Simplicity First - Minimum code that solves the problem',
9
13
  'Surgical Changes - Touch only what you must',
@@ -36,55 +40,122 @@ function buildEnvironmentSummary() {
36
40
  ].join('\n');
37
41
  }
38
42
 
39
- export function buildSystemPrompt({
40
- role = 'coding',
41
- context,
42
- tools = [],
43
- session,
44
- environment,
45
- } = {}) {
46
- const parts = [
47
- `You are Winter, an expert AI coding assistant.`,
48
- '',
49
- '## Core Principles',
50
- ...BASE_PRINCIPLES.map((p, i) => `${i + 1}. ${p}`),
51
- '',
52
- '## Runtime Environment',
53
- environment || buildEnvironmentSummary(),
54
- '',
55
- ];
43
+ function formatToolList(tools = []) {
44
+ return tools.length > 0 ? tools.slice(0, 10).join(', ') : '';
45
+ }
56
46
 
57
- if (tools.length > 0) {
58
- parts.push('## Available Tools', tools.join(', '), '');
59
- }
47
+ function appendSharedContext(parts, { environment, session, design, resourceContext, context, includeResources = false } = {}) {
48
+ parts.push('## Runtime Environment', environment || buildEnvironmentSummary(), '');
60
49
 
61
50
  if (session?.memory?.length) {
62
51
  parts.push('## Session Memory');
63
- session.memory.forEach(m => parts.push(` - ${m.substring(0, 120)}`));
52
+ session.memory.slice(-5).forEach(m => parts.push('- ' + String(m).slice(0, 100)));
64
53
  parts.push('');
65
54
  }
66
55
 
67
56
  if (session?.plans?.length) {
68
57
  parts.push('## Active Plans');
69
- session.plans.forEach(p => parts.push(` - ${p.title || p.substring(0, 80)}`));
58
+ session.plans.slice(-3).forEach(p => parts.push('- ' + (p.title || String(p).slice(0, 80))));
70
59
  parts.push('');
71
60
  }
72
61
 
62
+ if (design) {
63
+ parts.push('## Design Context');
64
+ if (design.brand) {
65
+ parts.push('Brand: ' + design.brand);
66
+ parts.push(design.content.split('\n').filter(Boolean).slice(0, 18).join('\n'));
67
+ } else if (design.type === 'design_hint') {
68
+ parts.push('Available design systems: ' + design.brands.slice(0, 5).join(', '));
69
+ }
70
+ parts.push('');
71
+ }
72
+
73
+ if (includeResources && resourceContext) {
74
+ parts.push(resourceContext.trim().slice(0, 1200), '');
75
+ }
76
+
77
+ if (context && typeof context === 'object') {
78
+ parts.push('Task: ' + (context.category || 'coding') + ' / ' + (context.type || 'simple'), '');
79
+ }
80
+ }
81
+
82
+ function buildCompactSmallModelPrompt(options = {}) {
83
+ const { tools = [], modelTier } = options;
84
+ const parts = [
85
+ 'You are Winter, an AI coding assistant running on a ' + getModelCapabilityLabel(modelTier) + '.',
86
+ '',
87
+ '## Operating Rules',
88
+ '1. Understand the user request first. If project state matters, inspect files before answering.',
89
+ '2. Keep context tight. Use only relevant tools and avoid long explanations.',
90
+ '3. For coding: Read/Grep/Glob -> Edit/Write -> Bash/test. Do not guess file paths.',
91
+ '4. Final answer in Vietnamese. Mention changed files and verification only.',
92
+ '',
93
+ ];
94
+
95
+ const toolList = formatToolList(tools);
96
+ if (toolList) parts.push('## Tools', toolList, '');
97
+ appendSharedContext(parts, { ...options, includeResources: false });
98
+
73
99
  parts.push(
74
- '## Guidelines',
75
- '- After using tools, always provide a direct final answer to the user.',
76
- '- Answer normal questions directly without unnecessary legal or policy disclaimers.',
77
- '- If a request is illegal, unsafe, or harmful, refuse briefly and offer a safe alternative.',
78
- '- Be proactive: anticipate what the user needs next.',
100
+ '## Response Shape',
101
+ '- If action is needed, use tools instead of describing the action.',
102
+ '- Keep final output short and concrete.',
79
103
  );
80
104
 
81
- return parts.join('\n');
105
+ return parts.filter(Boolean).join('\n');
106
+ }
107
+
108
+ function buildStandardSystemPrompt(options = {}) {
109
+ const { role = 'coding', tools = [], resourceContext } = options;
110
+ const parts = [
111
+ 'You are Winter, an expert AI coding assistant.',
112
+ '',
113
+ '## Core Principles',
114
+ ...BASE_PRINCIPLES.map((p, i) => (i + 1) + '. ' + p),
115
+ '',
116
+ '## Tool Usage',
117
+ 'Use tools when they materially improve correctness. Inspect before editing. Verify after changes.',
118
+ 'Never invent file paths, APIs, command output, or test results.',
119
+ '',
120
+ ];
121
+
122
+ const toolList = formatToolList(tools);
123
+ if (toolList) parts.push('## Tools', toolList, '');
124
+ appendSharedContext(parts, { ...options, includeResources: Boolean(resourceContext) && (role === 'design' || role === 'ui') });
125
+
126
+ parts.push('Always respond in Vietnamese.');
127
+ return parts.filter(Boolean).join('\n');
128
+ }
129
+
130
+ export function buildSystemPrompt({
131
+ role = 'coding',
132
+ context,
133
+ tools = [],
134
+ session,
135
+ environment,
136
+ design,
137
+ resourceContext,
138
+ modelTier,
139
+ } = {}) {
140
+ const options = { role, context, tools, session, environment, design, resourceContext, modelTier };
141
+ return isSmallModel(modelTier)
142
+ ? buildCompactSmallModelPrompt(options)
143
+ : buildStandardSystemPrompt(options);
82
144
  }
83
145
 
84
146
  export function buildFastSystemPrompt({
85
147
  role = 'coding',
86
148
  tools = [],
149
+ modelTier,
87
150
  } = {}) {
151
+ if (modelTier && isSmallModel(modelTier)) {
152
+ return [
153
+ 'Winter (fast mode - small model). Be concise. Use tools when needed.',
154
+ tools.length > 0 ? `Tools: ${tools.join(', ')}` : '',
155
+ 'Use a brief private plan, then answer in 1 sentence.',
156
+ ].filter(Boolean).join('\n');
157
+ }
158
+
88
159
  return [
89
160
  'You are Winter (fast mode). Be concise. Use tools when needed.',
90
161
  tools.length > 0 ? `Tools: ${tools.join(', ')}` : '',
@@ -92,20 +163,26 @@ export function buildFastSystemPrompt({
92
163
  ].filter(Boolean).join('\n');
93
164
  }
94
165
 
95
- export function buildAgentSystemPrompt(role, { tools = [] } = {}) {
166
+ export function buildAgentSystemPrompt(role, { tools = [], modelTier } = {}) {
96
167
  const roleConfigs = {
97
168
  plan: 'You analyze codebases and plan multi-step implementations. Output clear steps.',
98
169
  review: 'You review code for bugs, style issues, and improvements. Be critical but constructive.',
99
170
  debug: 'You are a debug specialist. Use systematic elimination to find root causes.',
100
171
  research: 'You search codebases and documentation to answer questions comprehensively.',
101
172
  browser: 'You interact with web pages via browser automation. Report findings clearly.',
173
+ coding: 'You solve coding tasks directly. Inspect files, edit surgically, and verify.',
102
174
  };
103
175
 
104
176
  const base = roleConfigs[role] || roleConfigs.coding;
177
+ const smallNote = modelTier && isSmallModel(modelTier)
178
+ ? '\n\nYou are running on a small model. Keep context tight, use tools early, and keep final output short.'
179
+ : '';
180
+
105
181
  return [
106
182
  `You are Winter (${role} agent).`,
107
183
  base,
108
184
  tools.length > 0 ? `\nTools: ${tools.join(', ')}` : '',
185
+ smallNote,
109
186
  '\nCRITICAL: Output only the requested format. No extra commentary.',
110
187
  ].filter(Boolean).join('\n');
111
188
  }
@@ -24,6 +24,8 @@ export const TASK_CATEGORIES = {
24
24
  TEST: 'test',
25
25
  CONFIG: 'config',
26
26
  INSTALL: 'install',
27
+ DESIGN: 'design',
28
+ UI: 'ui',
27
29
  };
28
30
 
29
31
  const TYPE_KEYWORDS = {
@@ -39,6 +41,8 @@ const TYPE_KEYWORDS = {
39
41
  test: ['test', 'unit test', 'integration test', 'assert', 'spec'],
40
42
  config: ['config', 'setup', 'install', 'configure', 'initialize'],
41
43
  install: ['install', 'npm install', 'pip install', 'gem install', 'cargo install', 'brew install'],
44
+ design: ['design', 'ui', 'brand', 'style guide', 'make it look', 'pixel perfect', 'layout', 'color scheme', 'palette', 'typography', 'theme'],
45
+ ui: ['ui', 'interface', 'component', 'button', 'card', 'modal', 'form', 'navbar', 'sidebar', 'header', 'footer', 'dashboard', 'landing page'],
42
46
  };
43
47
 
44
48
  const COMPLEXITY_SIGNALS = {
@@ -108,7 +112,7 @@ export function classifyTask(userInput) {
108
112
  wordCount,
109
113
  estimatedTokens,
110
114
  requiresTools: bestCategory !== TASK_CATEGORIES.EXPLAIN,
111
- requiresContext: ['edit', 'refactor', 'debug', 'review', 'test'].includes(bestCategory),
115
+ requiresContext: ['edit', 'refactor', 'debug', 'review', 'test', 'design', 'ui'].includes(bestCategory),
112
116
  };
113
117
  }
114
118
 
@@ -8,6 +8,9 @@ import { selectExecutionProfile } from '../context/router.js';
8
8
  import { buildSystemPrompt, buildFastSystemPrompt, buildAgentSystemPrompt } from './prompts/system-prompt.js';
9
9
  import { classifyTask } from './prompts/task-classifier.js';
10
10
  import SuccessCriteria from './prompts/success-criteria.js';
11
+ import { ReasoningConfig, REASONING_LEVELS, complexityToReasoningLevel } from './reasoning.js';
12
+ import { buildResourceContext, getRelevantDesignGuide } from '../context/resource-loader.js';
13
+ import { classifyModelTier } from './model-capabilities.js';
11
14
 
12
15
  function isAuthError(error) {
13
16
  const msg = String(error?.message || error || '');
@@ -23,6 +26,10 @@ export class AIProviderManager {
23
26
  this.tools = [];
24
27
  this.initialized = false;
25
28
  this.authToken = null;
29
+ this._cachedResourceContext = '';
30
+ this._cachedDesignGuide = null;
31
+ this._fallbackWarned = false;
32
+ this._modelTier = null;
26
33
  }
27
34
 
28
35
  async init() {
@@ -96,9 +103,17 @@ export class AIProviderManager {
96
103
  if (available) this.activeProvider = available;
97
104
  }
98
105
 
106
+ this.updateActiveModelTier();
107
+
99
108
  this.initialized = true;
100
109
  }
101
110
 
111
+ updateActiveModelTier() {
112
+ const providerConfig = this.providers[this.activeProvider] || {};
113
+ this._modelTier = classifyModelTier(providerConfig.model, this.activeProvider);
114
+ return this._modelTier;
115
+ }
116
+
102
117
  async loadAuthToken() {
103
118
  // 1) Honor explicit environment variables (highest priority)
104
119
  const envToken = process.env.CLAUDE_AUTH_TOKEN || process.env.ANTHROPIC_API_KEY || process.env.CLAUDE_TOKEN || null;
@@ -158,6 +173,7 @@ export class AIProviderManager {
158
173
  const providerName = this.normalizeProviderName(name);
159
174
  if (this.providers[providerName]) {
160
175
  this.activeProvider = providerName;
176
+ this.updateActiveModelTier();
161
177
  return true;
162
178
  }
163
179
  return false;
@@ -229,17 +245,27 @@ export class AIProviderManager {
229
245
  const routedProvider = this.providers[executionProfile.provider] || this.providers[this.activeProvider];
230
246
  const defaultProvider = this.providers[this.activeProvider];
231
247
 
248
+ const routingModel = options.model || executionProfile.model;
249
+ const routingReasoning = options.reasoning || executionProfile.reasoningParam;
250
+
232
251
  try {
233
252
  return await withRetry(() => this.sendRequestToProvider(routedProvider, messages, {
234
253
  ...options,
235
- model: options.model || executionProfile.model,
254
+ model: routingModel,
255
+ reasoning: routingReasoning,
256
+ reasoningLevel: options.reasoningLevel || executionProfile.reasoningLevel,
236
257
  }), { maxAttempts: 3, baseDelayMs: 150 });
237
258
  } catch (error) {
238
259
  if (isAuthError(error) && routedProvider !== defaultProvider && defaultProvider) {
239
- console.warn(`[winter] ${executionProfile.provider} provider auth error, falling back to ${this.activeProvider}`);
260
+ if (!this._fallbackWarned) {
261
+ console.warn(`[winter] ${executionProfile.provider} auth error, falling back to ${this.activeProvider}`);
262
+ this._fallbackWarned = true;
263
+ }
240
264
  return await withRetry(() => this.sendRequestToProvider(defaultProvider, messages, {
241
265
  ...options,
242
266
  model: options.model || defaultProvider.model,
267
+ reasoning: routingReasoning,
268
+ reasoningLevel: options.reasoningLevel || executionProfile.reasoningLevel,
243
269
  }), { maxAttempts: 1, baseDelayMs: 0 });
244
270
  }
245
271
  throw error;
@@ -257,17 +283,27 @@ export class AIProviderManager {
257
283
  const routedProvider = this.providers[executionProfile.provider] || this.providers[this.activeProvider];
258
284
  const defaultProvider = this.providers[this.activeProvider];
259
285
 
286
+ const routingModel = options.model || executionProfile.model;
287
+ const routingReasoning = options.reasoning || executionProfile.reasoningParam;
288
+
260
289
  try {
261
290
  yield* this.streamRequestToProvider(routedProvider, messages, {
262
291
  ...options,
263
- model: options.model || executionProfile.model,
292
+ model: routingModel,
293
+ reasoning: routingReasoning,
294
+ reasoningLevel: options.reasoningLevel || executionProfile.reasoningLevel,
264
295
  });
265
296
  } catch (error) {
266
297
  if (isAuthError(error) && routedProvider !== defaultProvider && defaultProvider) {
267
- console.warn(`[winter] ${executionProfile.provider} provider auth error, falling back to ${this.activeProvider}`);
298
+ if (!this._fallbackWarned) {
299
+ console.warn(`[winter] ${executionProfile.provider} auth error, falling back to ${this.activeProvider}`);
300
+ this._fallbackWarned = true;
301
+ }
268
302
  yield* this.streamRequestToProvider(defaultProvider, messages, {
269
303
  ...options,
270
304
  model: options.model || defaultProvider.model,
305
+ reasoning: routingReasoning,
306
+ reasoningLevel: options.reasoningLevel || executionProfile.reasoningLevel,
271
307
  });
272
308
  } else {
273
309
  throw error;
@@ -285,6 +321,17 @@ export class AIProviderManager {
285
321
  messages,
286
322
  };
287
323
 
324
+ // Apply reasoning configuration
325
+ const reasoningParam = options.reasoning || this._getReasoningParam(options, provider);
326
+ if (reasoningParam) {
327
+ if (reasoningParam.reasoning_effort) {
328
+ body.reasoning_effort = reasoningParam.reasoning_effort;
329
+ }
330
+ if (reasoningParam.thinking) {
331
+ body.thinking = reasoningParam.thinking;
332
+ }
333
+ }
334
+
288
335
  if (this.tools.length > 0 && options.enableTools) {
289
336
  body.tools = this.tools;
290
337
  }
@@ -329,6 +376,17 @@ export class AIProviderManager {
329
376
  body.stream_options = { include_usage: true };
330
377
  }
331
378
 
379
+ // Apply reasoning configuration
380
+ const reasoningParam = options.reasoning || this._getReasoningParam(options, provider);
381
+ if (reasoningParam) {
382
+ if (reasoningParam.reasoning_effort) {
383
+ body.reasoning_effort = reasoningParam.reasoning_effort;
384
+ }
385
+ if (reasoningParam.thinking) {
386
+ body.thinking = reasoningParam.thinking;
387
+ }
388
+ }
389
+
332
390
  if (this.tools.length > 0 && options.enableTools) {
333
391
  body.tools = this.tools;
334
392
  }
@@ -519,32 +577,111 @@ export class AIProviderManager {
519
577
  return { error: 'Tool execution handled by REPL' };
520
578
  }
521
579
 
580
+ _getReasoningParam(options, provider) {
581
+ // 1. Explicit reasoning param passed through options
582
+ if (options.reasoning) return options.reasoning;
583
+
584
+ // 2. Reasoning level specified -> build from level
585
+ if (options.reasoningLevel) {
586
+ const config = new ReasoningConfig({
587
+ level: options.reasoningLevel,
588
+ provider: provider?.name || this.activeProvider,
589
+ });
590
+ return config.getApiReasoningParam();
591
+ }
592
+
593
+ // 3. No reasoning config at all
594
+ return null;
595
+ }
596
+
522
597
  getSystemPrompt(options = {}) {
523
598
  const taskInfo = options.task ? classifyTask(options.task) : null;
524
- const tools = this.tools ? Object.keys(this.tools) : [];
599
+ const tools = Array.isArray(this.tools)
600
+ ? this.tools.map(tool => tool?.function?.name || tool?.name).filter(Boolean)
601
+ : [];
525
602
  const sessionInfo = {
526
603
  memory: options.memory || [],
527
604
  plans: options.plans || [],
528
605
  };
529
606
 
607
+ // Inject reasoning instructions if applicable
608
+ let reasoningPrompt = '';
609
+ if (options.reasoningLevel || options.reasoningPrompt) {
610
+ reasoningPrompt = options.reasoningPrompt || new ReasoningConfig({
611
+ level: options.reasoningLevel || REASONING_LEVELS.MEDIUM,
612
+ provider: this.activeProvider,
613
+ modelTier: this._modelTier,
614
+ }).getPromptInstructions();
615
+ } else if (taskInfo) {
616
+ // Auto-inject based on task complexity for providers without API reasoning
617
+ const level = complexityToReasoningLevel(taskInfo.type);
618
+ const config = new ReasoningConfig({
619
+ level,
620
+ provider: this.activeProvider,
621
+ modelTier: this._modelTier,
622
+ });
623
+ if (config.needsPromptInjection && level !== REASONING_LEVELS.NONE) {
624
+ reasoningPrompt = config.getPromptInstructions();
625
+ }
626
+ }
627
+
530
628
  if (options.role === 'agent') {
531
- return buildAgentSystemPrompt(options.agentRole || 'coding', { tools });
629
+ return buildAgentSystemPrompt(options.agentRole || 'coding', { tools, modelTier: this._modelTier }) + reasoningPrompt;
532
630
  }
533
631
 
534
632
  if (options.fast) {
535
- return buildFastSystemPrompt({ role: 'coding', tools });
633
+ return buildFastSystemPrompt({ role: 'coding', tools, modelTier: this._modelTier });
536
634
  }
537
635
 
538
636
  const successPrompt = options.task
539
637
  ? '\n\n' + SuccessCriteria.fromRequest(options.task).buildPrompt()
540
638
  : '';
541
639
 
640
+ const resourceContext = options.includeResources ? (this._cachedResourceContext || '') : '';
641
+
642
+ // Auto-detect relevant design guide for UI/design tasks
643
+ let designGuide = null;
644
+ if (taskInfo && (taskInfo.category === 'design' || taskInfo.category === 'ui')) {
645
+ this._designGuidePromise = this._designGuidePromise || this._loadDesignGuide(options.task);
646
+ }
647
+ const design = this._cachedDesignGuide || null;
648
+
542
649
  return buildSystemPrompt({
543
650
  role: taskInfo?.category || 'coding',
544
651
  context: taskInfo,
545
652
  tools,
546
653
  session: sessionInfo,
547
- }) + successPrompt;
654
+ design,
655
+ resourceContext,
656
+ modelTier: this._modelTier,
657
+ }) + reasoningPrompt + successPrompt;
658
+ }
659
+
660
+ /**
661
+ * Load resource context (cached for session lifetime).
662
+ */
663
+ async _loadResourceContext() {
664
+ try {
665
+ this._cachedResourceContext = await buildResourceContext();
666
+ } catch (e) {
667
+ this._cachedResourceContext = '';
668
+ }
669
+ return this._cachedResourceContext;
670
+ }
671
+
672
+ /**
673
+ * Load relevant design guide for a task.
674
+ */
675
+ async _loadDesignGuide(task) {
676
+ try {
677
+ const guide = await getRelevantDesignGuide(task);
678
+ if (guide) {
679
+ this._cachedDesignGuide = guide;
680
+ }
681
+ } catch (e) {
682
+ // Silently fail - design context is optional
683
+ }
684
+ return this._cachedDesignGuide;
548
685
  }
549
686
 
550
687
  classifyTask(userInput) {
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Reasoning Configuration Manager
3
+ *
4
+ * Controls reasoning effort / extended thinking per provider and task complexity.
5
+ *
6
+ * Supported APIs:
7
+ * - OpenAI: reasoning_effort ("low" | "medium" | "high") — o1, o3 models
8
+ * - Anthropic: thinking ({ type: "enabled", budget_tokens: number }) — Claude 3.7+ Sonnet
9
+ * - DeepSeek: built-in CoT reasoning (no explicit param needed)
10
+ * - Others: falls back to prompt-level reasoning instructions
11
+ */
12
+
13
+ import { isSmallModel } from './model-capabilities.js';
14
+
15
+ export const REASONING_LEVELS = {
16
+ NONE: 'none',
17
+ LOW: 'low',
18
+ MEDIUM: 'medium',
19
+ HIGH: 'high',
20
+ MAX: 'max',
21
+ };
22
+
23
+ const REASONING_EFFORT_MAP = {
24
+ [REASONING_LEVELS.NONE]: null,
25
+ [REASONING_LEVELS.LOW]: 'low',
26
+ [REASONING_LEVELS.MEDIUM]: 'medium',
27
+ [REASONING_LEVELS.HIGH]: 'high',
28
+ [REASONING_LEVELS.MAX]: 'high',
29
+ };
30
+
31
+ const EXTENDED_THINKING_BUDGET_MAP = {
32
+ [REASONING_LEVELS.NONE]: null,
33
+ [REASONING_LEVELS.LOW]: 1024,
34
+ [REASONING_LEVELS.MEDIUM]: 4096,
35
+ [REASONING_LEVELS.HIGH]: 8192,
36
+ [REASONING_LEVELS.MAX]: 16384,
37
+ };
38
+
39
+ /**
40
+ * Standard reasoning prompt templates for API-level reasoning models.
41
+ */
42
+ /**
43
+ * Unified deep reasoning prompts — ALL models use these aggressive templates.
44
+ * Every model, regardless of size, must think step by step with explicit structure.
45
+ * The structured <thinking> format forces deep reasoning, catches edge cases,
46
+ * and produces significantly higher quality code.
47
+ */
48
+ const REASONING_PROMPT_TEMPLATES = {
49
+ [REASONING_LEVELS.NONE]: '',
50
+ [REASONING_LEVELS.LOW]:
51
+ 'Think briefly before acting. Keep the final answer concise.',
52
+ [REASONING_LEVELS.MEDIUM]:
53
+ 'Before editing: identify relevant files, make the smallest change, then verify. Do not show long reasoning.',
54
+ [REASONING_LEVELS.HIGH]:
55
+ 'Use a private reasoning plan: understand the request, inspect evidence, implement surgically, verify with commands, then summarize.',
56
+ [REASONING_LEVELS.MAX]:
57
+ 'For complex work, maintain a private checklist covering requirements, files, risks, implementation, and verification. Show only useful results.',
58
+ };
59
+
60
+ /**
61
+ * Maps task complexity to recommended reasoning level.
62
+ */
63
+ export function complexityToReasoningLevel(taskType) {
64
+ switch (taskType) {
65
+ case 'quick': return REASONING_LEVELS.NONE;
66
+ case 'simple': return REASONING_LEVELS.LOW;
67
+ case 'moderate': return REASONING_LEVELS.MEDIUM;
68
+ case 'complex': return REASONING_LEVELS.HIGH;
69
+ case 'deep': return REASONING_LEVELS.MAX;
70
+ default: return REASONING_LEVELS.MEDIUM;
71
+ }
72
+ }
73
+
74
+ export class ReasoningConfig {
75
+ /**
76
+ * @param {object} options
77
+ * @param {string} options.level - One of REASONING_LEVELS
78
+ * @param {string} options.provider - Provider name (for API-specific config)
79
+ * @param {string} [options.modelTier] - Model capability tier from model-capabilities.js
80
+ * @param {object} [options.modelInfo] - Model metadata
81
+ * @param {object} [options.taskInfo] - Task classification result from task-classifier
82
+ */
83
+ constructor(options = {}) {
84
+ this.level = options.level || REASONING_LEVELS.MEDIUM;
85
+ this.provider = options.provider || '';
86
+ this.modelTier = options.modelTier || null;
87
+ this.modelInfo = options.modelInfo || {};
88
+ this.taskInfo = options.taskInfo || null;
89
+ }
90
+
91
+ /**
92
+ * Whether reasoning is enabled at all.
93
+ */
94
+ get enabled() {
95
+ return this.level !== REASONING_LEVELS.NONE && this.level !== null;
96
+ }
97
+
98
+ /**
99
+ * Whether this level should inject reasoning instructions into the system prompt.
100
+ */
101
+ get needsPromptInjection() {
102
+ return this.providerSupportsApiReasoning === false || !this.provider;
103
+ }
104
+
105
+ /**
106
+ * Check if provider has native API-level reasoning support.
107
+ */
108
+ get providerSupportsApiReasoning() {
109
+ const p = (this.provider || '').toLowerCase();
110
+ if (p === 'openai') return true;
111
+ if (p === 'anthropic' || p === 'claude') return true;
112
+ return false;
113
+ }
114
+
115
+ /**
116
+ * Whether this is a small model that needs aggressive prompting.
117
+ */
118
+ get isSmall() {
119
+ return this.modelTier ? isSmallModel(this.modelTier) : false;
120
+ }
121
+
122
+ /**
123
+ * Get the API-level reasoning parameter for the request body.
124
+ * Returns null if provider doesn't support API reasoning or level is NONE.
125
+ */
126
+ getApiReasoningParam() {
127
+ if (!this.enabled) return null;
128
+
129
+ const p = (this.provider || '').toLowerCase();
130
+
131
+ if (p === 'openai') {
132
+ const effort = REASONING_EFFORT_MAP[this.level];
133
+ if (!effort) return null;
134
+ return { reasoning_effort: effort };
135
+ }
136
+
137
+ if (p === 'anthropic' || p === 'claude') {
138
+ const budget = EXTENDED_THINKING_BUDGET_MAP[this.level];
139
+ if (!budget) return null;
140
+ return {
141
+ thinking: {
142
+ type: 'enabled',
143
+ budget_tokens: budget,
144
+ },
145
+ };
146
+ }
147
+
148
+ return null;
149
+ }
150
+
151
+ /**
152
+ * Get reasoning prompt instructions to inject into the system prompt.
153
+ * Compact prompt-level reasoning instructions for providers without API reasoning.
154
+ * @param {string} [modelTier] - Unused, kept for backward compatibility.
155
+ * @returns {string}
156
+ */
157
+ getPromptInstructions(modelTier) {
158
+ if (!this.enabled || this.providerSupportsApiReasoning) return '';
159
+ return REASONING_PROMPT_TEMPLATES[this.level] || '';
160
+ }
161
+
162
+ /**
163
+ * Build a reasoning config for a given provider and task info.
164
+ */
165
+ static fromTask(taskInfo, provider, options = {}) {
166
+ const level = options.reasoningLevel
167
+ || (taskInfo ? complexityToReasoningLevel(taskInfo.type) : REASONING_LEVELS.MEDIUM);
168
+
169
+ return new ReasoningConfig({
170
+ level,
171
+ provider: provider || '',
172
+ taskInfo: taskInfo || null,
173
+ ...options,
174
+ });
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Default reasoning configuration for the system.
180
+ */
181
+ export const DEFAULT_REASONING_CONFIG = {
182
+ defaultLevel: REASONING_LEVELS.MEDIUM,
183
+ maxBudgetTokens: 16384,
184
+ // Per-provider overrides
185
+ providers: {
186
+ openai: { supports: true, paramType: 'reasoning_effort' },
187
+ anthropic: { supports: true, paramType: 'thinking' },
188
+ claude: { supports: true, paramType: 'thinking' },
189
+ },
190
+ };