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.
- package/bin/winter.js +2 -1
- package/package.json +1 -1
- package/src/ai/benchmark.js +352 -0
- package/src/ai/model-capabilities.js +185 -0
- package/src/ai/prompts/system-prompt.js +106 -29
- package/src/ai/prompts/task-classifier.js +5 -1
- package/src/ai/providers.js +145 -8
- package/src/ai/reasoning.js +190 -0
- package/src/cli/commands.js +62 -0
- package/src/cli/context-loader.js +64 -1
- package/src/cli/conversation-format.js +90 -12
- package/src/cli/prompt-builder.js +43 -17
- package/src/cli/repl-commands.js +15 -3
- package/src/cli/repl.js +327 -209
- package/src/context/resource-loader.js +136 -0
- package/src/context/router.js +77 -20
- package/src/tools/executor.js +78 -9
|
@@ -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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
58
|
-
|
|
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(
|
|
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(
|
|
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
|
-
'##
|
|
75
|
-
'-
|
|
76
|
-
'-
|
|
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
|
|
package/src/ai/providers.js
CHANGED
|
@@ -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:
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
+
};
|