specweave 0.3.12 → 0.4.0
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/CLAUDE.md +17 -1
- package/README.md +1 -1
- package/bin/install-all.sh +9 -2
- package/bin/install-hooks.sh +57 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +55 -0
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/core/agent-model-manager.d.ts +52 -0
- package/dist/core/agent-model-manager.d.ts.map +1 -0
- package/dist/core/agent-model-manager.js +120 -0
- package/dist/core/agent-model-manager.js.map +1 -0
- package/dist/core/cost-tracker.d.ts +108 -0
- package/dist/core/cost-tracker.d.ts.map +1 -0
- package/dist/core/cost-tracker.js +281 -0
- package/dist/core/cost-tracker.js.map +1 -0
- package/dist/core/model-selector.d.ts +57 -0
- package/dist/core/model-selector.d.ts.map +1 -0
- package/dist/core/model-selector.js +115 -0
- package/dist/core/model-selector.js.map +1 -0
- package/dist/core/phase-detector.d.ts +62 -0
- package/dist/core/phase-detector.d.ts.map +1 -0
- package/dist/core/phase-detector.js +229 -0
- package/dist/core/phase-detector.js.map +1 -0
- package/dist/types/cost-tracking.d.ts +43 -0
- package/dist/types/cost-tracking.d.ts.map +1 -0
- package/dist/types/cost-tracking.js +8 -0
- package/dist/types/cost-tracking.js.map +1 -0
- package/dist/types/model-selection.d.ts +53 -0
- package/dist/types/model-selection.d.ts.map +1 -0
- package/dist/types/model-selection.js +12 -0
- package/dist/types/model-selection.js.map +1 -0
- package/dist/utils/cost-reporter.d.ts +58 -0
- package/dist/utils/cost-reporter.d.ts.map +1 -0
- package/dist/utils/cost-reporter.js +224 -0
- package/dist/utils/cost-reporter.js.map +1 -0
- package/dist/utils/pricing-constants.d.ts +70 -0
- package/dist/utils/pricing-constants.d.ts.map +1 -0
- package/dist/utils/pricing-constants.js +71 -0
- package/dist/utils/pricing-constants.js.map +1 -0
- package/package.json +1 -1
- package/src/agents/architect/AGENT.md +3 -0
- package/src/agents/code-reviewer.md +156 -0
- package/src/agents/data-scientist/AGENT.md +181 -0
- package/src/agents/database-optimizer/AGENT.md +147 -0
- package/src/agents/devops/AGENT.md +3 -0
- package/src/agents/diagrams-architect/AGENT.md +3 -0
- package/src/agents/docs-writer/AGENT.md +3 -0
- package/src/agents/kubernetes-architect/AGENT.md +142 -0
- package/src/agents/ml-engineer/AGENT.md +150 -0
- package/src/agents/mlops-engineer/AGENT.md +201 -0
- package/src/agents/network-engineer/AGENT.md +149 -0
- package/src/agents/observability-engineer/AGENT.md +213 -0
- package/src/agents/payment-integration/AGENT.md +35 -0
- package/src/agents/performance/AGENT.md +3 -0
- package/src/agents/performance-engineer/AGENT.md +153 -0
- package/src/agents/pm/AGENT.md +3 -0
- package/src/agents/qa-lead/AGENT.md +3 -0
- package/src/agents/security/AGENT.md +3 -0
- package/src/agents/sre/AGENT.md +3 -0
- package/src/agents/tdd-orchestrator/AGENT.md +169 -0
- package/src/agents/tech-lead/AGENT.md +3 -0
- package/src/commands/specweave.costs.md +261 -0
- package/src/commands/specweave.ml-pipeline.md +292 -0
- package/src/commands/specweave.monitor-setup.md +501 -0
- package/src/commands/specweave.slo-implement.md +1055 -0
- package/src/commands/specweave.sync-github.md +1 -1
- package/src/commands/specweave.tdd-cycle.md +199 -0
- package/src/commands/specweave.tdd-green.md +842 -0
- package/src/commands/specweave.tdd-red.md +135 -0
- package/src/commands/specweave.tdd-refactor.md +165 -0
- package/src/skills/SKILLS-INDEX.md +18 -10
- package/src/skills/billing-automation/SKILL.md +559 -0
- package/src/skills/distributed-tracing/SKILL.md +438 -0
- package/src/skills/e2e-playwright/README.md +1 -1
- package/src/skills/e2e-playwright/package.json +1 -1
- package/src/skills/gitops-workflow/SKILL.md +285 -0
- package/src/skills/gitops-workflow/references/argocd-setup.md +134 -0
- package/src/skills/gitops-workflow/references/sync-policies.md +131 -0
- package/src/skills/grafana-dashboards/SKILL.md +369 -0
- package/src/skills/helm-chart-scaffolding/SKILL.md +544 -0
- package/src/skills/helm-chart-scaffolding/assets/Chart.yaml.template +42 -0
- package/src/skills/helm-chart-scaffolding/assets/values.yaml.template +185 -0
- package/src/skills/helm-chart-scaffolding/references/chart-structure.md +500 -0
- package/src/skills/helm-chart-scaffolding/scripts/validate-chart.sh +244 -0
- package/src/skills/increment-planner/SKILL.md +1 -1
- package/src/skills/k8s-manifest-generator/SKILL.md +511 -0
- package/src/skills/k8s-manifest-generator/assets/configmap-template.yaml +296 -0
- package/src/skills/k8s-manifest-generator/assets/deployment-template.yaml +203 -0
- package/src/skills/k8s-manifest-generator/assets/service-template.yaml +171 -0
- package/src/skills/k8s-manifest-generator/references/deployment-spec.md +753 -0
- package/src/skills/k8s-manifest-generator/references/service-spec.md +724 -0
- package/src/skills/k8s-security-policies/SKILL.md +334 -0
- package/src/skills/k8s-security-policies/assets/network-policy-template.yaml +177 -0
- package/src/skills/k8s-security-policies/references/rbac-patterns.md +187 -0
- package/src/skills/ml-pipeline-workflow/SKILL.md +245 -0
- package/src/skills/paypal-integration/SKILL.md +467 -0
- package/src/skills/pci-compliance/SKILL.md +466 -0
- package/src/skills/project-kickstarter/SKILL.md +299 -0
- package/src/skills/project-kickstarter/test-cases/test-1-high-confidence-full-product.yaml +52 -0
- package/src/skills/project-kickstarter/test-cases/test-2-medium-confidence-partial.yaml +34 -0
- package/src/skills/project-kickstarter/test-cases/test-3-low-confidence-technical-question.yaml +34 -0
- package/src/skills/project-kickstarter/test-cases/test-4-opt-out-explicit.yaml +41 -0
- package/src/skills/prometheus-configuration/SKILL.md +392 -0
- package/src/skills/skill-router/SKILL.md +1 -1
- package/src/skills/slo-implementation/SKILL.md +329 -0
- package/src/skills/spec-driven-brainstorming/SKILL.md +1 -1
- package/src/skills/specweave-detector/SKILL.md +9 -3
- package/src/skills/stripe-integration/SKILL.md +442 -0
- package/src/skills/tdd-workflow/SKILL.md +378 -0
- package/src/templates/CLAUDE.md.template +59 -0
- package/src/templates/README.md.template +1 -1
- package/src/skills/bmad-method-expert/SKILL.md +0 -626
- package/src/skills/bmad-method-expert/scripts/analyze-project.js +0 -318
- package/src/skills/bmad-method-expert/scripts/check-setup.js +0 -208
- package/src/skills/bmad-method-expert/scripts/generate-template.js +0 -1149
- package/src/skills/bmad-method-expert/scripts/validate-documents.js +0 -340
- package/src/skills/context-optimizer/SKILL.md +0 -588
- package/src/skills/figma-designer/SKILL.md +0 -149
- package/src/skills/figma-implementer/SKILL.md +0 -148
- package/src/skills/figma-mcp-connector/SKILL.md +0 -136
- package/src/skills/figma-to-code/SKILL.md +0 -128
- package/src/skills/spec-kit-expert/SKILL.md +0 -1010
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost Tracker Service
|
|
3
|
+
*
|
|
4
|
+
* Real-time cost tracking for agent executions. Tracks token usage, calculates
|
|
5
|
+
* costs, aggregates by increment, and calculates savings vs baseline (Sonnet-only).
|
|
6
|
+
*
|
|
7
|
+
* Persistence: Stores data in .specweave/logs/costs.json
|
|
8
|
+
*/
|
|
9
|
+
import fs from 'fs-extra';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { calculateCost, calculateSavings } from '../utils/pricing-constants';
|
|
12
|
+
const DEFAULT_LOG_PATH = '.specweave/logs/costs.json';
|
|
13
|
+
export class CostTracker {
|
|
14
|
+
constructor(config = {}) {
|
|
15
|
+
this.sessions = new Map();
|
|
16
|
+
this.currentSessionId = null;
|
|
17
|
+
this.logPath = config.logPath || DEFAULT_LOG_PATH;
|
|
18
|
+
this.autoSave = config.autoSave !== false; // Default true
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Start a new tracking session
|
|
22
|
+
*
|
|
23
|
+
* @param agent - Agent name (e.g., 'pm', 'frontend')
|
|
24
|
+
* @param model - Model used ('sonnet', 'haiku', 'opus')
|
|
25
|
+
* @param increment - Optional increment ID (e.g., '0003')
|
|
26
|
+
* @param command - Optional command that triggered this (e.g., '/specweave.inc')
|
|
27
|
+
* @returns Session ID
|
|
28
|
+
*/
|
|
29
|
+
startSession(agent, model, increment, command) {
|
|
30
|
+
const sessionId = this.generateSessionId();
|
|
31
|
+
const session = {
|
|
32
|
+
sessionId,
|
|
33
|
+
agent,
|
|
34
|
+
model,
|
|
35
|
+
increment,
|
|
36
|
+
command,
|
|
37
|
+
startedAt: new Date().toISOString(),
|
|
38
|
+
tokenUsage: {
|
|
39
|
+
inputTokens: 0,
|
|
40
|
+
outputTokens: 0,
|
|
41
|
+
totalTokens: 0,
|
|
42
|
+
},
|
|
43
|
+
cost: 0,
|
|
44
|
+
savings: 0,
|
|
45
|
+
};
|
|
46
|
+
this.sessions.set(sessionId, session);
|
|
47
|
+
this.currentSessionId = sessionId;
|
|
48
|
+
return sessionId;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Record token usage for current session
|
|
52
|
+
*
|
|
53
|
+
* @param inputTokens - Number of input tokens
|
|
54
|
+
* @param outputTokens - Number of output tokens
|
|
55
|
+
* @param sessionId - Optional session ID (defaults to current)
|
|
56
|
+
*/
|
|
57
|
+
recordTokens(inputTokens, outputTokens, sessionId) {
|
|
58
|
+
const id = sessionId || this.currentSessionId;
|
|
59
|
+
if (!id) {
|
|
60
|
+
throw new Error('No active session. Call startSession() first.');
|
|
61
|
+
}
|
|
62
|
+
const session = this.sessions.get(id);
|
|
63
|
+
if (!session) {
|
|
64
|
+
throw new Error(`Session ${id} not found`);
|
|
65
|
+
}
|
|
66
|
+
// Update token usage
|
|
67
|
+
session.tokenUsage.inputTokens += inputTokens;
|
|
68
|
+
session.tokenUsage.outputTokens += outputTokens;
|
|
69
|
+
session.tokenUsage.totalTokens += inputTokens + outputTokens;
|
|
70
|
+
// Recalculate cost
|
|
71
|
+
session.cost = calculateCost(session.model, session.tokenUsage.inputTokens, session.tokenUsage.outputTokens);
|
|
72
|
+
// Calculate savings vs Sonnet baseline
|
|
73
|
+
session.savings = calculateSavings(session.model, session.tokenUsage.inputTokens, session.tokenUsage.outputTokens);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* End current session
|
|
77
|
+
*
|
|
78
|
+
* @param sessionId - Optional session ID (defaults to current)
|
|
79
|
+
*/
|
|
80
|
+
endSession(sessionId) {
|
|
81
|
+
const id = sessionId || this.currentSessionId;
|
|
82
|
+
if (!id) {
|
|
83
|
+
throw new Error('No active session to end');
|
|
84
|
+
}
|
|
85
|
+
const session = this.sessions.get(id);
|
|
86
|
+
if (!session) {
|
|
87
|
+
throw new Error(`Session ${id} not found`);
|
|
88
|
+
}
|
|
89
|
+
session.endedAt = new Date().toISOString();
|
|
90
|
+
if (this.autoSave) {
|
|
91
|
+
this.saveToDisk();
|
|
92
|
+
}
|
|
93
|
+
// Clear current session if it's the one we just ended
|
|
94
|
+
if (this.currentSessionId === id) {
|
|
95
|
+
this.currentSessionId = null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get session by ID
|
|
100
|
+
*/
|
|
101
|
+
getSession(sessionId) {
|
|
102
|
+
return this.sessions.get(sessionId);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get current session
|
|
106
|
+
*/
|
|
107
|
+
getCurrentSession() {
|
|
108
|
+
return this.currentSessionId
|
|
109
|
+
? this.sessions.get(this.currentSessionId)
|
|
110
|
+
: undefined;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get all sessions for a specific increment
|
|
114
|
+
*
|
|
115
|
+
* @param incrementId - Increment ID (e.g., '0003')
|
|
116
|
+
* @returns Array of sessions for this increment
|
|
117
|
+
*/
|
|
118
|
+
getIncrementSessions(incrementId) {
|
|
119
|
+
return Array.from(this.sessions.values()).filter((s) => s.increment === incrementId);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get cost report for a specific increment
|
|
123
|
+
*
|
|
124
|
+
* @param incrementId - Increment ID (e.g., '0003')
|
|
125
|
+
* @returns Aggregate cost report
|
|
126
|
+
*/
|
|
127
|
+
getIncrementCost(incrementId) {
|
|
128
|
+
const sessions = this.getIncrementSessions(incrementId);
|
|
129
|
+
if (sessions.length === 0) {
|
|
130
|
+
return {
|
|
131
|
+
incrementId,
|
|
132
|
+
totalCost: 0,
|
|
133
|
+
totalSavings: 0,
|
|
134
|
+
totalTokens: 0,
|
|
135
|
+
sessionCount: 0,
|
|
136
|
+
costByModel: {},
|
|
137
|
+
costByAgent: {},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const report = {
|
|
141
|
+
incrementId,
|
|
142
|
+
totalCost: 0,
|
|
143
|
+
totalSavings: 0,
|
|
144
|
+
totalTokens: 0,
|
|
145
|
+
sessionCount: sessions.length,
|
|
146
|
+
costByModel: {},
|
|
147
|
+
costByAgent: {},
|
|
148
|
+
};
|
|
149
|
+
for (const session of sessions) {
|
|
150
|
+
// Aggregate totals
|
|
151
|
+
report.totalCost += session.cost;
|
|
152
|
+
report.totalSavings += session.savings;
|
|
153
|
+
report.totalTokens += session.tokenUsage.totalTokens;
|
|
154
|
+
// Aggregate by model
|
|
155
|
+
if (!report.costByModel[session.model]) {
|
|
156
|
+
report.costByModel[session.model] = 0;
|
|
157
|
+
}
|
|
158
|
+
report.costByModel[session.model] += session.cost;
|
|
159
|
+
// Aggregate by agent
|
|
160
|
+
if (!report.costByAgent[session.agent]) {
|
|
161
|
+
report.costByAgent[session.agent] = 0;
|
|
162
|
+
}
|
|
163
|
+
report.costByAgent[session.agent] += session.cost;
|
|
164
|
+
}
|
|
165
|
+
return report;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get total cost across all sessions
|
|
169
|
+
*/
|
|
170
|
+
getTotalCost() {
|
|
171
|
+
return Array.from(this.sessions.values()).reduce((sum, session) => sum + session.cost, 0);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get total savings across all sessions
|
|
175
|
+
*/
|
|
176
|
+
getTotalSavings() {
|
|
177
|
+
return Array.from(this.sessions.values()).reduce((sum, session) => sum + session.savings, 0);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get all sessions
|
|
181
|
+
*/
|
|
182
|
+
getAllSessions() {
|
|
183
|
+
return Array.from(this.sessions.values());
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Clear all sessions (useful for testing)
|
|
187
|
+
*/
|
|
188
|
+
clearSessions() {
|
|
189
|
+
this.sessions.clear();
|
|
190
|
+
this.currentSessionId = null;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Save sessions to disk
|
|
194
|
+
*/
|
|
195
|
+
async saveToDisk() {
|
|
196
|
+
try {
|
|
197
|
+
const data = {
|
|
198
|
+
version: '1.0',
|
|
199
|
+
savedAt: new Date().toISOString(),
|
|
200
|
+
sessions: Array.from(this.sessions.entries()).map(([id, session]) => ({
|
|
201
|
+
...session,
|
|
202
|
+
sessionId: id,
|
|
203
|
+
})),
|
|
204
|
+
};
|
|
205
|
+
await fs.ensureDir(path.dirname(this.logPath));
|
|
206
|
+
await fs.writeJson(this.logPath, data, { spaces: 2 });
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
throw new Error(`Failed to save cost data: ${error.message}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Load sessions from disk
|
|
214
|
+
*/
|
|
215
|
+
async loadFromDisk() {
|
|
216
|
+
try {
|
|
217
|
+
if (!(await fs.pathExists(this.logPath))) {
|
|
218
|
+
// No data file yet, that's ok
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const data = await fs.readJson(this.logPath);
|
|
222
|
+
// Validate version (for future migrations)
|
|
223
|
+
if (data.version !== '1.0') {
|
|
224
|
+
throw new Error(`Unsupported cost data version: ${data.version}`);
|
|
225
|
+
}
|
|
226
|
+
// Load sessions
|
|
227
|
+
this.sessions.clear();
|
|
228
|
+
for (const session of data.sessions) {
|
|
229
|
+
this.sessions.set(session.sessionId, session);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
throw new Error(`Failed to load cost data: ${error.message}`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Generate unique session ID
|
|
238
|
+
*/
|
|
239
|
+
generateSessionId() {
|
|
240
|
+
const timestamp = Date.now();
|
|
241
|
+
const random = Math.random().toString(36).substring(2, 9);
|
|
242
|
+
return `session_${timestamp}_${random}`;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Get summary statistics
|
|
246
|
+
*/
|
|
247
|
+
getSummary() {
|
|
248
|
+
const sessions = this.getAllSessions();
|
|
249
|
+
if (sessions.length === 0) {
|
|
250
|
+
return {
|
|
251
|
+
totalSessions: 0,
|
|
252
|
+
totalCost: 0,
|
|
253
|
+
totalSavings: 0,
|
|
254
|
+
savingsPercentage: 0,
|
|
255
|
+
mostExpensiveAgent: null,
|
|
256
|
+
cheapestAgent: null,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
const totalCost = this.getTotalCost();
|
|
260
|
+
const totalSavings = this.getTotalSavings();
|
|
261
|
+
const baselineCost = totalCost + totalSavings;
|
|
262
|
+
// Calculate by agent
|
|
263
|
+
const agentCosts = {};
|
|
264
|
+
for (const session of sessions) {
|
|
265
|
+
if (!agentCosts[session.agent]) {
|
|
266
|
+
agentCosts[session.agent] = 0;
|
|
267
|
+
}
|
|
268
|
+
agentCosts[session.agent] += session.cost;
|
|
269
|
+
}
|
|
270
|
+
const sortedAgents = Object.entries(agentCosts).sort(([, a], [, b]) => b - a);
|
|
271
|
+
return {
|
|
272
|
+
totalSessions: sessions.length,
|
|
273
|
+
totalCost,
|
|
274
|
+
totalSavings,
|
|
275
|
+
savingsPercentage: baselineCost > 0 ? (totalSavings / baselineCost) * 100 : 0,
|
|
276
|
+
mostExpensiveAgent: sortedAgents[0]?.[0] || null,
|
|
277
|
+
cheapestAgent: sortedAgents[sortedAgents.length - 1]?.[0] || null,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=cost-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-tracker.js","sourceRoot":"","sources":["../../src/core/cost-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model Selector
|
|
3
|
+
*
|
|
4
|
+
* Decision engine that combines agent preferences + phase detection to select
|
|
5
|
+
* the optimal AI model for each task.
|
|
6
|
+
*
|
|
7
|
+
* Decision hierarchy:
|
|
8
|
+
* 1. User override (--model flag) - Always wins
|
|
9
|
+
* 2. Agent preference (from AGENT.md) - Used when not 'auto'
|
|
10
|
+
* 3. Phase detection - Used for 'auto' agents with high confidence
|
|
11
|
+
* 4. Safe default (Sonnet) - Used when confidence is low
|
|
12
|
+
*
|
|
13
|
+
* Achieves 60-70% cost savings by routing execution to Haiku.
|
|
14
|
+
*/
|
|
15
|
+
import type { Model, ModelSelectionDecision } from '../types/model-selection';
|
|
16
|
+
import type { ExecutionContext } from './phase-detector';
|
|
17
|
+
import { AgentModelManager } from './agent-model-manager';
|
|
18
|
+
import { PhaseDetector } from './phase-detector';
|
|
19
|
+
export interface ModelSelectionConfig {
|
|
20
|
+
mode: 'auto' | 'balanced' | 'manual';
|
|
21
|
+
forceModel?: Exclude<Model, 'auto'>;
|
|
22
|
+
highConfidenceThreshold: number;
|
|
23
|
+
mediumConfidenceThreshold: number;
|
|
24
|
+
defaultPlanningModel: 'sonnet' | 'opus';
|
|
25
|
+
defaultExecutionModel: 'haiku' | 'sonnet';
|
|
26
|
+
defaultReviewModel: 'sonnet' | 'opus';
|
|
27
|
+
logDecisions: boolean;
|
|
28
|
+
showReasoning: boolean;
|
|
29
|
+
}
|
|
30
|
+
export declare class ModelSelector {
|
|
31
|
+
private agentModelManager;
|
|
32
|
+
private phaseDetector;
|
|
33
|
+
private config;
|
|
34
|
+
constructor(agentModelManager: AgentModelManager, phaseDetector: PhaseDetector, config?: Partial<ModelSelectionConfig>);
|
|
35
|
+
/**
|
|
36
|
+
* Select optimal model for a given task
|
|
37
|
+
*
|
|
38
|
+
* @param prompt - User's prompt/task description
|
|
39
|
+
* @param agent - Agent name (e.g., 'pm', 'frontend', 'architect')
|
|
40
|
+
* @param context - Execution context (command, increment state, etc.)
|
|
41
|
+
* @returns Model selection decision with reasoning
|
|
42
|
+
*/
|
|
43
|
+
select(prompt: string, agent: string, context?: ExecutionContext): ModelSelectionDecision;
|
|
44
|
+
/**
|
|
45
|
+
* Log model selection decision (if logging enabled)
|
|
46
|
+
*/
|
|
47
|
+
logDecision(decision: ModelSelectionDecision, agent: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Update configuration
|
|
50
|
+
*/
|
|
51
|
+
updateConfig(config: Partial<ModelSelectionConfig>): void;
|
|
52
|
+
/**
|
|
53
|
+
* Get current configuration
|
|
54
|
+
*/
|
|
55
|
+
getConfig(): ModelSelectionConfig;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=model-selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-selector.d.ts","sourceRoot":"","sources":["../../src/core/model-selector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAS,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAC;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACpC,uBAAuB,EAAE,MAAM,CAAC;IAChC,yBAAyB,EAAE,MAAM,CAAC;IAClC,oBAAoB,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxC,qBAAqB,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1C,kBAAkB,EAAE,QAAQ,GAAG,MAAM,CAAC;IACtC,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;CACxB;AAsBD,qBAAa,aAAa;IACxB,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,MAAM,CAAuB;gBAGnC,iBAAiB,EAAE,iBAAiB,EACpC,aAAa,EAAE,aAAa,EAC5B,MAAM,GAAE,OAAO,CAAC,oBAAoB,CAAM;IAO5C;;;;;;;OAOG;IACH,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,gBAAqB,GAC7B,sBAAsB;IA8CzB;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,sBAAsB,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAalE;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,IAAI;IAIzD;;OAEG;IACH,SAAS,IAAI,oBAAoB;CAGlC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model Selector
|
|
3
|
+
*
|
|
4
|
+
* Decision engine that combines agent preferences + phase detection to select
|
|
5
|
+
* the optimal AI model for each task.
|
|
6
|
+
*
|
|
7
|
+
* Decision hierarchy:
|
|
8
|
+
* 1. User override (--model flag) - Always wins
|
|
9
|
+
* 2. Agent preference (from AGENT.md) - Used when not 'auto'
|
|
10
|
+
* 3. Phase detection - Used for 'auto' agents with high confidence
|
|
11
|
+
* 4. Safe default (Sonnet) - Used when confidence is low
|
|
12
|
+
*
|
|
13
|
+
* Achieves 60-70% cost savings by routing execution to Haiku.
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_CONFIG = {
|
|
16
|
+
mode: 'auto',
|
|
17
|
+
highConfidenceThreshold: 0.7,
|
|
18
|
+
mediumConfidenceThreshold: 0.4,
|
|
19
|
+
defaultPlanningModel: 'sonnet',
|
|
20
|
+
defaultExecutionModel: 'haiku',
|
|
21
|
+
defaultReviewModel: 'sonnet',
|
|
22
|
+
logDecisions: true,
|
|
23
|
+
showReasoning: true,
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Phase-to-model mapping (when agent is 'auto')
|
|
27
|
+
*/
|
|
28
|
+
const PHASE_MODEL_MAP = {
|
|
29
|
+
planning: 'sonnet',
|
|
30
|
+
execution: 'haiku',
|
|
31
|
+
review: 'sonnet',
|
|
32
|
+
};
|
|
33
|
+
export class ModelSelector {
|
|
34
|
+
constructor(agentModelManager, phaseDetector, config = {}) {
|
|
35
|
+
this.agentModelManager = agentModelManager;
|
|
36
|
+
this.phaseDetector = phaseDetector;
|
|
37
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Select optimal model for a given task
|
|
41
|
+
*
|
|
42
|
+
* @param prompt - User's prompt/task description
|
|
43
|
+
* @param agent - Agent name (e.g., 'pm', 'frontend', 'architect')
|
|
44
|
+
* @param context - Execution context (command, increment state, etc.)
|
|
45
|
+
* @returns Model selection decision with reasoning
|
|
46
|
+
*/
|
|
47
|
+
select(prompt, agent, context = {}) {
|
|
48
|
+
// Step 1: Check explicit user override
|
|
49
|
+
if (this.config.forceModel) {
|
|
50
|
+
return {
|
|
51
|
+
model: this.config.forceModel,
|
|
52
|
+
reason: 'user_override',
|
|
53
|
+
reasoning: `User explicitly forced ${this.config.forceModel} model via --model flag`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Step 2: Load agent preference
|
|
57
|
+
const agentPref = this.agentModelManager.getPreferredModel(agent);
|
|
58
|
+
const costProfile = this.agentModelManager.getCostProfile(agent);
|
|
59
|
+
// If agent has explicit preference (not 'auto'), use it
|
|
60
|
+
if (agentPref !== 'auto') {
|
|
61
|
+
return {
|
|
62
|
+
model: agentPref,
|
|
63
|
+
reason: 'agent_preference',
|
|
64
|
+
reasoning: `Agent '${agent}' prefers ${agentPref} for ${costProfile} work`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// Step 3: Detect phase (for 'auto' agents)
|
|
68
|
+
const phaseDetection = this.phaseDetector.detect(prompt, context);
|
|
69
|
+
// Step 4: Apply decision matrix based on confidence
|
|
70
|
+
if (phaseDetection.confidence >= this.config.highConfidenceThreshold) {
|
|
71
|
+
// High confidence - use phase-based model
|
|
72
|
+
return {
|
|
73
|
+
model: PHASE_MODEL_MAP[phaseDetection.phase],
|
|
74
|
+
reason: 'phase_detection',
|
|
75
|
+
confidence: phaseDetection.confidence,
|
|
76
|
+
reasoning: phaseDetection.reasoning,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// Step 5: Low confidence - default to Sonnet for safety
|
|
80
|
+
return {
|
|
81
|
+
model: 'sonnet',
|
|
82
|
+
reason: 'low_confidence_default',
|
|
83
|
+
confidence: phaseDetection.confidence,
|
|
84
|
+
reasoning: `Low confidence (${(phaseDetection.confidence * 100).toFixed(0)}%), defaulting to Sonnet for safety. Detected: ${phaseDetection.reasoning}`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Log model selection decision (if logging enabled)
|
|
89
|
+
*/
|
|
90
|
+
logDecision(decision, agent) {
|
|
91
|
+
if (!this.config.logDecisions)
|
|
92
|
+
return;
|
|
93
|
+
const timestamp = new Date().toISOString();
|
|
94
|
+
const logMessage = `[${timestamp}] [Model Selection] Agent: ${agent} → ${decision.model} (${decision.reason})`;
|
|
95
|
+
if (this.config.showReasoning) {
|
|
96
|
+
console.log(`${logMessage}\n Reasoning: ${decision.reasoning}`);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.log(logMessage);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Update configuration
|
|
104
|
+
*/
|
|
105
|
+
updateConfig(config) {
|
|
106
|
+
this.config = { ...this.config, ...config };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get current configuration
|
|
110
|
+
*/
|
|
111
|
+
getConfig() {
|
|
112
|
+
return { ...this.config };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=model-selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-selector.js","sourceRoot":"","sources":["../../src/core/model-selector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase Detector
|
|
3
|
+
*
|
|
4
|
+
* Multi-signal phase detection algorithm that analyzes user prompts and context
|
|
5
|
+
* to determine whether work is in planning, execution, or review phase.
|
|
6
|
+
*
|
|
7
|
+
* Uses 4 signals with weighted scoring:
|
|
8
|
+
* 1. Keyword analysis (40%) - Planning/execution/review keywords
|
|
9
|
+
* 2. Command analysis (30%) - Slash commands hint at phase
|
|
10
|
+
* 3. Context analysis (20%) - Increment state, file types
|
|
11
|
+
* 4. Explicit hints (10%) - User explicitly states phase
|
|
12
|
+
*
|
|
13
|
+
* Target accuracy: >95%
|
|
14
|
+
*/
|
|
15
|
+
import type { Phase } from '../types/model-selection';
|
|
16
|
+
export interface PhaseDetectionResult {
|
|
17
|
+
phase: Phase;
|
|
18
|
+
confidence: number;
|
|
19
|
+
signals: {
|
|
20
|
+
keywords: string[];
|
|
21
|
+
command?: string;
|
|
22
|
+
context: string[];
|
|
23
|
+
};
|
|
24
|
+
reasoning: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ExecutionContext {
|
|
27
|
+
command?: string;
|
|
28
|
+
incrementState?: 'backlog' | 'planned' | 'in-progress' | 'completed' | 'closed';
|
|
29
|
+
previousPhases?: Phase[];
|
|
30
|
+
filesModified?: string[];
|
|
31
|
+
}
|
|
32
|
+
export declare class PhaseDetector {
|
|
33
|
+
private readonly planningKeywords;
|
|
34
|
+
private readonly executionKeywords;
|
|
35
|
+
private readonly reviewKeywords;
|
|
36
|
+
private readonly commandPhaseMap;
|
|
37
|
+
/**
|
|
38
|
+
* Detect phase from user prompt and execution context
|
|
39
|
+
*/
|
|
40
|
+
detect(prompt: string, context?: ExecutionContext): PhaseDetectionResult;
|
|
41
|
+
/**
|
|
42
|
+
* Analyze keywords in prompt
|
|
43
|
+
*/
|
|
44
|
+
private analyzeKeywords;
|
|
45
|
+
/**
|
|
46
|
+
* Analyze command hints
|
|
47
|
+
*/
|
|
48
|
+
private analyzeCommand;
|
|
49
|
+
/**
|
|
50
|
+
* Analyze execution context
|
|
51
|
+
*/
|
|
52
|
+
private analyzeContext;
|
|
53
|
+
/**
|
|
54
|
+
* Analyze explicit hints in prompt
|
|
55
|
+
*/
|
|
56
|
+
private analyzeHints;
|
|
57
|
+
/**
|
|
58
|
+
* Generate human-readable reasoning
|
|
59
|
+
*/
|
|
60
|
+
private generateReasoning;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=phase-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phase-detector.d.ts","sourceRoot":"","sources":["../../src/core/phase-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAEtD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAC;IAChF,cAAc,CAAC,EAAE,KAAK,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,qBAAa,aAAa;IAExB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAK/B;IAEF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAKhC;IAEF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAI7B;IAGF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAU9B;IAEF;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,oBAAoB;IA4C5E;;OAEG;IACH,OAAO,CAAC,eAAe;IA4CvB;;OAEG;IACH,OAAO,CAAC,cAAc;IActB;;OAEG;IACH,OAAO,CAAC,cAAc;IAuDtB;;OAEG;IACH,OAAO,CAAC,YAAY;IAwBpB;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAuC1B"}
|