@agile-vibe-coding/avc 0.1.0 → 0.2.3
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/README.md +2 -0
- package/cli/agent-loader.js +21 -0
- package/cli/agents/agent-selector.md +129 -0
- package/cli/agents/architecture-recommender.md +418 -0
- package/cli/agents/database-deep-dive.md +470 -0
- package/cli/agents/database-recommender.md +634 -0
- package/cli/agents/doc-distributor.md +176 -0
- package/cli/agents/documentation-updater.md +203 -0
- package/cli/agents/epic-story-decomposer.md +280 -0
- package/cli/agents/feature-context-generator.md +91 -0
- package/cli/agents/gap-checker-epic.md +52 -0
- package/cli/agents/impact-checker-story.md +51 -0
- package/cli/agents/migration-guide-generator.md +305 -0
- package/cli/agents/mission-scope-generator.md +79 -0
- package/cli/agents/mission-scope-validator.md +112 -0
- package/cli/agents/project-context-extractor.md +107 -0
- package/cli/agents/project-documentation-creator.json +226 -0
- package/cli/agents/project-documentation-creator.md +595 -0
- package/cli/agents/question-prefiller.md +269 -0
- package/cli/agents/refiner-epic.md +39 -0
- package/cli/agents/refiner-story.md +42 -0
- package/cli/agents/solver-epic-api.json +15 -0
- package/cli/agents/solver-epic-api.md +39 -0
- package/cli/agents/solver-epic-backend.json +15 -0
- package/cli/agents/solver-epic-backend.md +39 -0
- package/cli/agents/solver-epic-cloud.json +15 -0
- package/cli/agents/solver-epic-cloud.md +39 -0
- package/cli/agents/solver-epic-data.json +15 -0
- package/cli/agents/solver-epic-data.md +39 -0
- package/cli/agents/solver-epic-database.json +15 -0
- package/cli/agents/solver-epic-database.md +39 -0
- package/cli/agents/solver-epic-developer.json +15 -0
- package/cli/agents/solver-epic-developer.md +39 -0
- package/cli/agents/solver-epic-devops.json +15 -0
- package/cli/agents/solver-epic-devops.md +39 -0
- package/cli/agents/solver-epic-frontend.json +15 -0
- package/cli/agents/solver-epic-frontend.md +39 -0
- package/cli/agents/solver-epic-mobile.json +15 -0
- package/cli/agents/solver-epic-mobile.md +39 -0
- package/cli/agents/solver-epic-qa.json +15 -0
- package/cli/agents/solver-epic-qa.md +39 -0
- package/cli/agents/solver-epic-security.json +15 -0
- package/cli/agents/solver-epic-security.md +39 -0
- package/cli/agents/solver-epic-solution-architect.json +15 -0
- package/cli/agents/solver-epic-solution-architect.md +39 -0
- package/cli/agents/solver-epic-test-architect.json +15 -0
- package/cli/agents/solver-epic-test-architect.md +39 -0
- package/cli/agents/solver-epic-ui.json +15 -0
- package/cli/agents/solver-epic-ui.md +39 -0
- package/cli/agents/solver-epic-ux.json +15 -0
- package/cli/agents/solver-epic-ux.md +39 -0
- package/cli/agents/solver-story-api.json +15 -0
- package/cli/agents/solver-story-api.md +39 -0
- package/cli/agents/solver-story-backend.json +15 -0
- package/cli/agents/solver-story-backend.md +39 -0
- package/cli/agents/solver-story-cloud.json +15 -0
- package/cli/agents/solver-story-cloud.md +39 -0
- package/cli/agents/solver-story-data.json +15 -0
- package/cli/agents/solver-story-data.md +39 -0
- package/cli/agents/solver-story-database.json +15 -0
- package/cli/agents/solver-story-database.md +39 -0
- package/cli/agents/solver-story-developer.json +15 -0
- package/cli/agents/solver-story-developer.md +39 -0
- package/cli/agents/solver-story-devops.json +15 -0
- package/cli/agents/solver-story-devops.md +39 -0
- package/cli/agents/solver-story-frontend.json +15 -0
- package/cli/agents/solver-story-frontend.md +39 -0
- package/cli/agents/solver-story-mobile.json +15 -0
- package/cli/agents/solver-story-mobile.md +39 -0
- package/cli/agents/solver-story-qa.json +15 -0
- package/cli/agents/solver-story-qa.md +39 -0
- package/cli/agents/solver-story-security.json +15 -0
- package/cli/agents/solver-story-security.md +39 -0
- package/cli/agents/solver-story-solution-architect.json +15 -0
- package/cli/agents/solver-story-solution-architect.md +39 -0
- package/cli/agents/solver-story-test-architect.json +15 -0
- package/cli/agents/solver-story-test-architect.md +39 -0
- package/cli/agents/solver-story-ui.json +15 -0
- package/cli/agents/solver-story-ui.md +39 -0
- package/cli/agents/solver-story-ux.json +15 -0
- package/cli/agents/solver-story-ux.md +39 -0
- package/cli/agents/story-doc-enricher.md +133 -0
- package/cli/agents/suggestion-business-analyst.md +88 -0
- package/cli/agents/suggestion-deployment-architect.md +263 -0
- package/cli/agents/suggestion-product-manager.md +129 -0
- package/cli/agents/suggestion-security-specialist.md +156 -0
- package/cli/agents/suggestion-technical-architect.md +269 -0
- package/cli/agents/suggestion-ux-researcher.md +93 -0
- package/cli/agents/task-subtask-decomposer.md +188 -0
- package/cli/agents/validator-documentation.json +152 -0
- package/cli/agents/validator-documentation.md +453 -0
- package/cli/agents/validator-epic-api.json +93 -0
- package/cli/agents/validator-epic-api.md +137 -0
- package/cli/agents/validator-epic-backend.json +93 -0
- package/cli/agents/validator-epic-backend.md +130 -0
- package/cli/agents/validator-epic-cloud.json +93 -0
- package/cli/agents/validator-epic-cloud.md +137 -0
- package/cli/agents/validator-epic-data.json +93 -0
- package/cli/agents/validator-epic-data.md +130 -0
- package/cli/agents/validator-epic-database.json +93 -0
- package/cli/agents/validator-epic-database.md +137 -0
- package/cli/agents/validator-epic-developer.json +74 -0
- package/cli/agents/validator-epic-developer.md +153 -0
- package/cli/agents/validator-epic-devops.json +74 -0
- package/cli/agents/validator-epic-devops.md +153 -0
- package/cli/agents/validator-epic-frontend.json +74 -0
- package/cli/agents/validator-epic-frontend.md +153 -0
- package/cli/agents/validator-epic-mobile.json +93 -0
- package/cli/agents/validator-epic-mobile.md +130 -0
- package/cli/agents/validator-epic-qa.json +93 -0
- package/cli/agents/validator-epic-qa.md +130 -0
- package/cli/agents/validator-epic-security.json +74 -0
- package/cli/agents/validator-epic-security.md +154 -0
- package/cli/agents/validator-epic-solution-architect.json +74 -0
- package/cli/agents/validator-epic-solution-architect.md +156 -0
- package/cli/agents/validator-epic-test-architect.json +93 -0
- package/cli/agents/validator-epic-test-architect.md +130 -0
- package/cli/agents/validator-epic-ui.json +93 -0
- package/cli/agents/validator-epic-ui.md +130 -0
- package/cli/agents/validator-epic-ux.json +93 -0
- package/cli/agents/validator-epic-ux.md +130 -0
- package/cli/agents/validator-selector.md +211 -0
- package/cli/agents/validator-story-api.json +104 -0
- package/cli/agents/validator-story-api.md +152 -0
- package/cli/agents/validator-story-backend.json +104 -0
- package/cli/agents/validator-story-backend.md +152 -0
- package/cli/agents/validator-story-cloud.json +104 -0
- package/cli/agents/validator-story-cloud.md +152 -0
- package/cli/agents/validator-story-data.json +104 -0
- package/cli/agents/validator-story-data.md +152 -0
- package/cli/agents/validator-story-database.json +104 -0
- package/cli/agents/validator-story-database.md +152 -0
- package/cli/agents/validator-story-developer.json +104 -0
- package/cli/agents/validator-story-developer.md +152 -0
- package/cli/agents/validator-story-devops.json +104 -0
- package/cli/agents/validator-story-devops.md +152 -0
- package/cli/agents/validator-story-frontend.json +104 -0
- package/cli/agents/validator-story-frontend.md +152 -0
- package/cli/agents/validator-story-mobile.json +104 -0
- package/cli/agents/validator-story-mobile.md +152 -0
- package/cli/agents/validator-story-qa.json +104 -0
- package/cli/agents/validator-story-qa.md +152 -0
- package/cli/agents/validator-story-security.json +104 -0
- package/cli/agents/validator-story-security.md +152 -0
- package/cli/agents/validator-story-solution-architect.json +104 -0
- package/cli/agents/validator-story-solution-architect.md +152 -0
- package/cli/agents/validator-story-test-architect.json +104 -0
- package/cli/agents/validator-story-test-architect.md +152 -0
- package/cli/agents/validator-story-ui.json +104 -0
- package/cli/agents/validator-story-ui.md +152 -0
- package/cli/agents/validator-story-ux.json +104 -0
- package/cli/agents/validator-story-ux.md +152 -0
- package/cli/ansi-colors.js +21 -0
- package/cli/build-docs.js +298 -0
- package/cli/ceremony-history.js +369 -0
- package/cli/command-logger.js +245 -0
- package/cli/components/static-output.js +63 -0
- package/cli/console-output-manager.js +94 -0
- package/cli/docs-sync.js +306 -0
- package/cli/epic-story-validator.js +1174 -0
- package/cli/evaluation-prompts.js +1008 -0
- package/cli/execution-context.js +195 -0
- package/cli/generate-summary-table.js +340 -0
- package/cli/index.js +3 -25
- package/cli/init-model-config.js +697 -0
- package/cli/init.js +1765 -100
- package/cli/kanban-server-manager.js +228 -0
- package/cli/llm-claude.js +109 -0
- package/cli/llm-gemini.js +115 -0
- package/cli/llm-mock.js +233 -0
- package/cli/llm-openai.js +233 -0
- package/cli/llm-provider.js +300 -0
- package/cli/llm-token-limits.js +102 -0
- package/cli/llm-verifier.js +454 -0
- package/cli/logger.js +32 -5
- package/cli/message-constants.js +58 -0
- package/cli/message-manager.js +334 -0
- package/cli/message-types.js +96 -0
- package/cli/messaging-api.js +297 -0
- package/cli/model-pricing.js +169 -0
- package/cli/model-query-engine.js +468 -0
- package/cli/model-recommendation-analyzer.js +495 -0
- package/cli/model-selector.js +269 -0
- package/cli/output-buffer.js +107 -0
- package/cli/process-manager.js +332 -0
- package/cli/repl-ink.js +5840 -504
- package/cli/repl-old.js +4 -4
- package/cli/seed-processor.js +792 -0
- package/cli/sprint-planning-processor.js +1813 -0
- package/cli/template-processor.js +2306 -108
- package/cli/templates/project.md +25 -8
- package/cli/templates/vitepress-config.mts.template +34 -0
- package/cli/token-tracker.js +520 -0
- package/cli/tools/generate-story-validators.js +317 -0
- package/cli/tools/generate-validators.js +669 -0
- package/cli/update-checker.js +19 -17
- package/cli/update-notifier.js +4 -4
- package/cli/validation-router.js +605 -0
- package/cli/verification-tracker.js +563 -0
- package/kanban/README.md +386 -0
- package/kanban/client/README.md +205 -0
- package/kanban/client/components.json +20 -0
- package/kanban/client/dist/assets/index-CiD8PS2e.js +306 -0
- package/kanban/client/dist/assets/index-nLh0m82Q.css +1 -0
- package/kanban/client/dist/index.html +16 -0
- package/kanban/client/dist/vite.svg +1 -0
- package/kanban/client/index.html +15 -0
- package/kanban/client/package-lock.json +9442 -0
- package/kanban/client/package.json +44 -0
- package/kanban/client/postcss.config.js +6 -0
- package/kanban/client/public/vite.svg +1 -0
- package/kanban/client/src/App.jsx +622 -0
- package/kanban/client/src/components/ProjectFileEditorPopup.jsx +117 -0
- package/kanban/client/src/components/ceremony/AskArchPopup.jsx +416 -0
- package/kanban/client/src/components/ceremony/AskModelPopup.jsx +616 -0
- package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +946 -0
- package/kanban/client/src/components/ceremony/EpicStorySelectionModal.jsx +254 -0
- package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +619 -0
- package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +704 -0
- package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +150 -0
- package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +154 -0
- package/kanban/client/src/components/ceremony/steps/DatabaseStep.jsx +202 -0
- package/kanban/client/src/components/ceremony/steps/DeploymentStep.jsx +123 -0
- package/kanban/client/src/components/ceremony/steps/MissionStep.jsx +106 -0
- package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +125 -0
- package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +228 -0
- package/kanban/client/src/components/kanban/CardDetailModal.jsx +559 -0
- package/kanban/client/src/components/kanban/EpicSection.jsx +146 -0
- package/kanban/client/src/components/kanban/FilterToolbar.jsx +222 -0
- package/kanban/client/src/components/kanban/GroupingSelector.jsx +57 -0
- package/kanban/client/src/components/kanban/KanbanBoard.jsx +211 -0
- package/kanban/client/src/components/kanban/KanbanCard.jsx +138 -0
- package/kanban/client/src/components/kanban/KanbanColumn.jsx +90 -0
- package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +789 -0
- package/kanban/client/src/components/layout/LoadingScreen.jsx +82 -0
- package/kanban/client/src/components/process/ProcessMonitorBar.jsx +80 -0
- package/kanban/client/src/components/settings/AgentEditorPopup.jsx +171 -0
- package/kanban/client/src/components/settings/AgentsTab.jsx +353 -0
- package/kanban/client/src/components/settings/ApiKeysTab.jsx +113 -0
- package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +98 -0
- package/kanban/client/src/components/settings/CostThresholdsTab.jsx +94 -0
- package/kanban/client/src/components/settings/ModelPricingTab.jsx +204 -0
- package/kanban/client/src/components/settings/ServersTab.jsx +121 -0
- package/kanban/client/src/components/settings/SettingsModal.jsx +84 -0
- package/kanban/client/src/components/stats/CostModal.jsx +353 -0
- package/kanban/client/src/components/ui/badge.jsx +27 -0
- package/kanban/client/src/components/ui/dialog.jsx +121 -0
- package/kanban/client/src/components/ui/tabs.jsx +85 -0
- package/kanban/client/src/hooks/__tests__/useGrouping.test.js +232 -0
- package/kanban/client/src/hooks/useGrouping.js +118 -0
- package/kanban/client/src/hooks/useWebSocket.js +120 -0
- package/kanban/client/src/lib/__tests__/api.test.js +196 -0
- package/kanban/client/src/lib/__tests__/status-grouping.test.js +94 -0
- package/kanban/client/src/lib/api.js +401 -0
- package/kanban/client/src/lib/status-grouping.js +144 -0
- package/kanban/client/src/lib/utils.js +11 -0
- package/kanban/client/src/main.jsx +10 -0
- package/kanban/client/src/store/__tests__/kanbanStore.test.js +164 -0
- package/kanban/client/src/store/ceremonyStore.js +172 -0
- package/kanban/client/src/store/filterStore.js +201 -0
- package/kanban/client/src/store/kanbanStore.js +115 -0
- package/kanban/client/src/store/processStore.js +65 -0
- package/kanban/client/src/store/sprintPlanningStore.js +33 -0
- package/kanban/client/src/styles/globals.css +59 -0
- package/kanban/client/tailwind.config.js +77 -0
- package/kanban/client/vite.config.js +28 -0
- package/kanban/client/vitest.config.js +28 -0
- package/kanban/dev-start.sh +47 -0
- package/kanban/package.json +12 -0
- package/kanban/server/index.js +516 -0
- package/kanban/server/routes/ceremony.js +305 -0
- package/kanban/server/routes/costs.js +157 -0
- package/kanban/server/routes/processes.js +50 -0
- package/kanban/server/routes/settings.js +303 -0
- package/kanban/server/routes/websocket.js +276 -0
- package/kanban/server/routes/work-items.js +347 -0
- package/kanban/server/services/CeremonyService.js +1190 -0
- package/kanban/server/services/FileSystemScanner.js +95 -0
- package/kanban/server/services/FileWatcher.js +144 -0
- package/kanban/server/services/HierarchyBuilder.js +196 -0
- package/kanban/server/services/ProcessRegistry.js +122 -0
- package/kanban/server/services/WorkItemReader.js +123 -0
- package/kanban/server/services/WorkItemRefineService.js +510 -0
- package/kanban/server/start.js +49 -0
- package/kanban/server/utils/kanban-logger.js +132 -0
- package/kanban/server/utils/markdown.js +91 -0
- package/kanban/server/utils/status-grouping.js +107 -0
- package/kanban/server/workers/sponsor-call-worker.js +84 -0
- package/kanban/server/workers/sprint-planning-worker.js +130 -0
- package/package.json +34 -7
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model Pricing Information
|
|
3
|
+
*
|
|
4
|
+
* Centralized pricing data for all supported LLM models.
|
|
5
|
+
* Used by cost calculator in model configuration UI.
|
|
6
|
+
*
|
|
7
|
+
* Pricing is per million tokens (input + output).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const MODEL_PRICING = {
|
|
11
|
+
// Claude models
|
|
12
|
+
'claude-opus-4-6': {
|
|
13
|
+
input: 15.0,
|
|
14
|
+
output: 75.0,
|
|
15
|
+
unit: 1000000,
|
|
16
|
+
displayName: 'Claude Opus 4.6',
|
|
17
|
+
provider: 'claude'
|
|
18
|
+
},
|
|
19
|
+
'claude-sonnet-4-5-20250929': {
|
|
20
|
+
input: 3.0,
|
|
21
|
+
output: 15.0,
|
|
22
|
+
unit: 1000000,
|
|
23
|
+
displayName: 'Claude Sonnet 4.5',
|
|
24
|
+
provider: 'claude'
|
|
25
|
+
},
|
|
26
|
+
'claude-3-5-haiku-20241022': {
|
|
27
|
+
input: 1.0,
|
|
28
|
+
output: 5.0,
|
|
29
|
+
unit: 1000000,
|
|
30
|
+
displayName: 'Claude Haiku 3.5',
|
|
31
|
+
provider: 'claude'
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
// Gemini models
|
|
35
|
+
'gemini-3.1-pro-preview': {
|
|
36
|
+
input: 2.0,
|
|
37
|
+
output: 12.0,
|
|
38
|
+
unit: 1000000,
|
|
39
|
+
displayName: 'Gemini 3.1 Pro Preview',
|
|
40
|
+
provider: 'gemini'
|
|
41
|
+
},
|
|
42
|
+
'gemini-3-flash-preview': {
|
|
43
|
+
input: 0.5,
|
|
44
|
+
output: 3.0,
|
|
45
|
+
unit: 1000000,
|
|
46
|
+
displayName: 'Gemini 3 Flash Preview',
|
|
47
|
+
provider: 'gemini'
|
|
48
|
+
},
|
|
49
|
+
'gemini-2.5-pro': {
|
|
50
|
+
input: 1.25,
|
|
51
|
+
output: 10.0,
|
|
52
|
+
unit: 1000000,
|
|
53
|
+
displayName: 'Gemini 2.5 Pro',
|
|
54
|
+
provider: 'gemini'
|
|
55
|
+
},
|
|
56
|
+
'gemini-2.5-flash': {
|
|
57
|
+
input: 0.30,
|
|
58
|
+
output: 2.50,
|
|
59
|
+
unit: 1000000,
|
|
60
|
+
displayName: 'Gemini 2.5 Flash',
|
|
61
|
+
provider: 'gemini'
|
|
62
|
+
},
|
|
63
|
+
'gemini-2.5-flash-lite': {
|
|
64
|
+
input: 0.10,
|
|
65
|
+
output: 0.40,
|
|
66
|
+
unit: 1000000,
|
|
67
|
+
displayName: 'Gemini 2.5 Flash-Lite',
|
|
68
|
+
provider: 'gemini'
|
|
69
|
+
},
|
|
70
|
+
'gemini-2.0-flash-exp': {
|
|
71
|
+
input: 0.0,
|
|
72
|
+
output: 0.0,
|
|
73
|
+
unit: 1000000,
|
|
74
|
+
displayName: 'Gemini 2.0 Flash (Free Tier)',
|
|
75
|
+
provider: 'gemini'
|
|
76
|
+
},
|
|
77
|
+
'gemini-1.5-pro': {
|
|
78
|
+
input: 1.25,
|
|
79
|
+
output: 5.0,
|
|
80
|
+
unit: 1000000,
|
|
81
|
+
displayName: 'Gemini 1.5 Pro',
|
|
82
|
+
provider: 'gemini'
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
// OpenAI models
|
|
86
|
+
'gpt-4o': {
|
|
87
|
+
input: 5.0,
|
|
88
|
+
output: 15.0,
|
|
89
|
+
unit: 1000000,
|
|
90
|
+
displayName: 'GPT-4o',
|
|
91
|
+
provider: 'openai'
|
|
92
|
+
},
|
|
93
|
+
'gpt-4o-mini': {
|
|
94
|
+
input: 0.15,
|
|
95
|
+
output: 0.6,
|
|
96
|
+
unit: 1000000,
|
|
97
|
+
displayName: 'GPT-4o Mini',
|
|
98
|
+
provider: 'openai'
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get pricing information for a model
|
|
104
|
+
*/
|
|
105
|
+
export function getModelPricing(modelId) {
|
|
106
|
+
return MODEL_PRICING[modelId] || null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Calculate cost for given model and token count
|
|
111
|
+
*/
|
|
112
|
+
export function calculateCost(modelId, tokenCount) {
|
|
113
|
+
const pricing = MODEL_PRICING[modelId];
|
|
114
|
+
if (!pricing) return 0;
|
|
115
|
+
|
|
116
|
+
// Estimate 60% input, 40% output tokens
|
|
117
|
+
const inputTokens = tokenCount * 0.6;
|
|
118
|
+
const outputTokens = tokenCount * 0.4;
|
|
119
|
+
|
|
120
|
+
const inputCost = (inputTokens / pricing.unit) * pricing.input;
|
|
121
|
+
const outputCost = (outputTokens / pricing.unit) * pricing.output;
|
|
122
|
+
|
|
123
|
+
return inputCost + outputCost;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Format cost as currency string
|
|
128
|
+
*/
|
|
129
|
+
export function formatCost(cost) {
|
|
130
|
+
if (cost === 0) return 'Free';
|
|
131
|
+
if (cost < 0.01) return '< $0.01';
|
|
132
|
+
return `$${cost.toFixed(2)}`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get estimated token count for a stage
|
|
137
|
+
*/
|
|
138
|
+
export function getEstimatedTokens(ceremonyName, stageId) {
|
|
139
|
+
const avgTokensPerCall = 3000; // Average tokens per LLM call
|
|
140
|
+
|
|
141
|
+
const callCounts = {
|
|
142
|
+
'sprint-planning': {
|
|
143
|
+
'decomposition': 1,
|
|
144
|
+
'doc-distribution': 25,
|
|
145
|
+
'validation': 145,
|
|
146
|
+
'validation-universal': 30,
|
|
147
|
+
'validation-domain': 90,
|
|
148
|
+
'validation-feature': 25
|
|
149
|
+
},
|
|
150
|
+
'sponsor-call': {
|
|
151
|
+
'suggestions': 1,
|
|
152
|
+
'documentation': 1,
|
|
153
|
+
'validation': 2,
|
|
154
|
+
'refinement': 2
|
|
155
|
+
},
|
|
156
|
+
'seed': {
|
|
157
|
+
'decomposition': 1,
|
|
158
|
+
'validation': 20,
|
|
159
|
+
'context-generation': 10
|
|
160
|
+
},
|
|
161
|
+
'context-retrospective': {
|
|
162
|
+
'documentation-update': 10,
|
|
163
|
+
'context-refinement': 15
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const calls = callCounts[ceremonyName]?.[stageId] || 0;
|
|
168
|
+
return calls * avgTokensPerCall;
|
|
169
|
+
}
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model Query Engine
|
|
3
|
+
* Orchestrates multi-provider LLM queries for model selection evaluation
|
|
4
|
+
*
|
|
5
|
+
* Queries all available providers (Claude, OpenAI, Gemini) in parallel
|
|
6
|
+
* for each evaluation prompt to collect model recommendations.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { LLMProvider } from './llm-provider.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Model configurations for querying
|
|
13
|
+
* Using each provider's most capable model for best recommendations
|
|
14
|
+
*/
|
|
15
|
+
const QUERY_MODELS = {
|
|
16
|
+
claude: 'claude-opus-4-6', // Most capable Claude model
|
|
17
|
+
openai: 'gpt-5.2-chat-latest', // Most capable OpenAI model
|
|
18
|
+
gemini: 'gemini-2.5-pro' // Most capable Gemini model
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Debug logging helper
|
|
23
|
+
*/
|
|
24
|
+
function debug(message, data = null) {
|
|
25
|
+
const timestamp = new Date().toISOString();
|
|
26
|
+
if (data) {
|
|
27
|
+
console.log(`[DEBUG][${timestamp}] ${message}`, JSON.stringify(data, null, 2));
|
|
28
|
+
} else {
|
|
29
|
+
console.log(`[DEBUG][${timestamp}] ${message}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class ModelQueryEngine {
|
|
34
|
+
constructor() {
|
|
35
|
+
this.providers = {};
|
|
36
|
+
this.results = [];
|
|
37
|
+
this.errors = [];
|
|
38
|
+
this.totalExecutionTime = 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Initialize LLM providers
|
|
43
|
+
* Only creates providers for which API keys are available
|
|
44
|
+
* @returns {Promise<Object>} Object with provider names and initialization status
|
|
45
|
+
*/
|
|
46
|
+
async initializeProviders() {
|
|
47
|
+
debug('Initializing LLM providers...');
|
|
48
|
+
|
|
49
|
+
const availableProviders = {};
|
|
50
|
+
const errors = [];
|
|
51
|
+
|
|
52
|
+
// Attempt to create each provider
|
|
53
|
+
for (const [providerName, model] of Object.entries(QUERY_MODELS)) {
|
|
54
|
+
try {
|
|
55
|
+
debug(`Initializing ${providerName} with model ${model}`);
|
|
56
|
+
const provider = await LLMProvider.create(providerName, model);
|
|
57
|
+
|
|
58
|
+
// Validate API key
|
|
59
|
+
const validation = await provider.validateApiKey();
|
|
60
|
+
if (validation.valid) {
|
|
61
|
+
this.providers[providerName] = provider;
|
|
62
|
+
availableProviders[providerName] = { status: 'ready', model };
|
|
63
|
+
debug(`${providerName} initialized successfully`);
|
|
64
|
+
} else {
|
|
65
|
+
errors.push({
|
|
66
|
+
provider: providerName,
|
|
67
|
+
error: validation.error || 'API key validation failed',
|
|
68
|
+
code: validation.code
|
|
69
|
+
});
|
|
70
|
+
availableProviders[providerName] = {
|
|
71
|
+
status: 'error',
|
|
72
|
+
error: validation.error || 'API key validation failed'
|
|
73
|
+
};
|
|
74
|
+
debug(`${providerName} validation failed:`, validation.error);
|
|
75
|
+
}
|
|
76
|
+
} catch (error) {
|
|
77
|
+
errors.push({
|
|
78
|
+
provider: providerName,
|
|
79
|
+
error: error.message,
|
|
80
|
+
details: error.stack
|
|
81
|
+
});
|
|
82
|
+
availableProviders[providerName] = {
|
|
83
|
+
status: 'error',
|
|
84
|
+
error: error.message
|
|
85
|
+
};
|
|
86
|
+
debug(`${providerName} initialization failed:`, error.message);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const readyCount = Object.values(availableProviders).filter(p => p.status === 'ready').length;
|
|
91
|
+
debug(`Initialization complete: ${readyCount}/${Object.keys(QUERY_MODELS).length} providers ready`);
|
|
92
|
+
|
|
93
|
+
if (readyCount === 0) {
|
|
94
|
+
throw new Error('No LLM providers available. Check API keys in .env file.');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
available: availableProviders,
|
|
99
|
+
errors: errors.length > 0 ? errors : null,
|
|
100
|
+
readyCount
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Query a single provider with an evaluation prompt
|
|
106
|
+
* @param {string} providerName - Provider name (claude, openai, gemini)
|
|
107
|
+
* @param {Object} evaluationPrompt - Evaluation prompt object
|
|
108
|
+
* @returns {Promise<Object>} Normalized response with model recommendation
|
|
109
|
+
*/
|
|
110
|
+
async queryProvider(providerName, evaluationPrompt) {
|
|
111
|
+
const startTime = Date.now();
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
debug(`Querying ${providerName} for ${evaluationPrompt.id}...`);
|
|
115
|
+
|
|
116
|
+
const provider = this.providers[providerName];
|
|
117
|
+
if (!provider) {
|
|
118
|
+
throw new Error(`Provider ${providerName} not initialized`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Query the provider with the evaluation prompt
|
|
122
|
+
const response = await provider.generateText(
|
|
123
|
+
evaluationPrompt.prompt,
|
|
124
|
+
`You are an expert in LLM model selection. Analyze the task requirements and recommend the best model from your provider's lineup for this specific use case.
|
|
125
|
+
|
|
126
|
+
Consider:
|
|
127
|
+
1. Which of your models best matches the output quality requirements?
|
|
128
|
+
2. Which model provides the best balance of capability and cost for this task?
|
|
129
|
+
3. What are the specific strengths of your recommended model for this task?
|
|
130
|
+
|
|
131
|
+
Provide your response in the following format:
|
|
132
|
+
|
|
133
|
+
RECOMMENDED MODEL: [model name]
|
|
134
|
+
|
|
135
|
+
REASONING:
|
|
136
|
+
[2-3 sentences explaining why this model is optimal for this task]
|
|
137
|
+
|
|
138
|
+
CONFIDENCE: [High/Medium/Low]
|
|
139
|
+
|
|
140
|
+
ALTERNATIVES:
|
|
141
|
+
[Optional: Mention any alternative models if appropriate]`
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const endTime = Date.now();
|
|
145
|
+
const responseTime = (endTime - startTime) / 1000; // seconds
|
|
146
|
+
|
|
147
|
+
// Get token usage
|
|
148
|
+
const tokenUsage = provider.getTokenUsage();
|
|
149
|
+
|
|
150
|
+
// Normalize the response
|
|
151
|
+
const normalized = this._normalizeResponse(providerName, response, tokenUsage, responseTime);
|
|
152
|
+
|
|
153
|
+
debug(`${providerName} query complete for ${evaluationPrompt.id}`, {
|
|
154
|
+
model: normalized.model,
|
|
155
|
+
tokens: normalized.tokens,
|
|
156
|
+
cost: normalized.cost,
|
|
157
|
+
responseTime: normalized.responseTime
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return normalized;
|
|
161
|
+
} catch (error) {
|
|
162
|
+
const endTime = Date.now();
|
|
163
|
+
const responseTime = (endTime - startTime) / 1000;
|
|
164
|
+
|
|
165
|
+
debug(`${providerName} query failed for ${evaluationPrompt.id}:`, error.message);
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
provider: providerName,
|
|
169
|
+
status: 'error',
|
|
170
|
+
error: error.message,
|
|
171
|
+
errorCode: error.status || error.code,
|
|
172
|
+
responseTime,
|
|
173
|
+
timestamp: new Date().toISOString()
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Normalize provider response to common format
|
|
180
|
+
* Extracts model recommendation, reasoning, and confidence from response text
|
|
181
|
+
* @param {string} providerName - Provider name
|
|
182
|
+
* @param {string} responseText - Raw response text from provider
|
|
183
|
+
* @param {Object} tokenUsage - Token usage from provider
|
|
184
|
+
* @param {number} responseTime - Response time in seconds
|
|
185
|
+
* @returns {Object} Normalized response object
|
|
186
|
+
*/
|
|
187
|
+
_normalizeResponse(providerName, responseText, tokenUsage, responseTime) {
|
|
188
|
+
// Extract model name (look for "RECOMMENDED MODEL:" line)
|
|
189
|
+
let model = 'Unknown';
|
|
190
|
+
const modelMatch = responseText.match(/RECOMMENDED MODEL:\s*(.+)/i);
|
|
191
|
+
if (modelMatch) {
|
|
192
|
+
model = modelMatch[1].trim();
|
|
193
|
+
} else {
|
|
194
|
+
// Fallback: try to extract model name from first line or prominent text
|
|
195
|
+
const firstLine = responseText.split('\n')[0].trim();
|
|
196
|
+
if (firstLine.length < 100) {
|
|
197
|
+
model = firstLine;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Extract reasoning (look for "REASONING:" section)
|
|
202
|
+
let reasoning = '';
|
|
203
|
+
const reasoningMatch = responseText.match(/REASONING:\s*(.+?)(?=\n\nCONFIDENCE:|$)/is);
|
|
204
|
+
if (reasoningMatch) {
|
|
205
|
+
reasoning = reasoningMatch[1].trim();
|
|
206
|
+
} else {
|
|
207
|
+
// Fallback: use full response if structure not found
|
|
208
|
+
reasoning = responseText.substring(0, 500).trim() + (responseText.length > 500 ? '...' : '');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Extract confidence (look for "CONFIDENCE:" line)
|
|
212
|
+
let confidence = 'Unknown';
|
|
213
|
+
const confidenceMatch = responseText.match(/CONFIDENCE:\s*(.+)/i);
|
|
214
|
+
if (confidenceMatch) {
|
|
215
|
+
const conf = confidenceMatch[1].trim().toLowerCase();
|
|
216
|
+
if (conf.includes('high')) confidence = 'High';
|
|
217
|
+
else if (conf.includes('medium')) confidence = 'Medium';
|
|
218
|
+
else if (conf.includes('low')) confidence = 'Low';
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
provider: providerName,
|
|
223
|
+
status: 'success',
|
|
224
|
+
model,
|
|
225
|
+
reasoning,
|
|
226
|
+
confidence,
|
|
227
|
+
tokens: {
|
|
228
|
+
input: tokenUsage.inputTokens || 0,
|
|
229
|
+
output: tokenUsage.outputTokens || 0,
|
|
230
|
+
total: tokenUsage.totalTokens || 0
|
|
231
|
+
},
|
|
232
|
+
cost: tokenUsage.estimatedCost || 0,
|
|
233
|
+
responseTime,
|
|
234
|
+
rawResponse: responseText,
|
|
235
|
+
timestamp: new Date().toISOString()
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Query all providers for a single evaluation prompt
|
|
241
|
+
* Executes provider queries in parallel for efficiency
|
|
242
|
+
* @param {Object} evaluationPrompt - Evaluation prompt object
|
|
243
|
+
* @param {Function} progressCallback - Optional callback for progress updates
|
|
244
|
+
* @returns {Promise<Object>} Results from all providers
|
|
245
|
+
*/
|
|
246
|
+
async queryAllProvidersForPrompt(evaluationPrompt, progressCallback = null) {
|
|
247
|
+
debug(`Querying all providers for prompt: ${evaluationPrompt.id}`);
|
|
248
|
+
|
|
249
|
+
const startTime = Date.now();
|
|
250
|
+
|
|
251
|
+
// Get list of available providers
|
|
252
|
+
const providerNames = Object.keys(this.providers);
|
|
253
|
+
|
|
254
|
+
if (providerNames.length === 0) {
|
|
255
|
+
throw new Error('No providers available for querying');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Query all providers in parallel
|
|
259
|
+
const promises = providerNames.map(providerName =>
|
|
260
|
+
this.queryProvider(providerName, evaluationPrompt)
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
// Wait for all queries to complete
|
|
264
|
+
const results = await Promise.all(promises);
|
|
265
|
+
|
|
266
|
+
const endTime = Date.now();
|
|
267
|
+
const totalTime = (endTime - startTime) / 1000;
|
|
268
|
+
|
|
269
|
+
// Aggregate results
|
|
270
|
+
const recommendations = {};
|
|
271
|
+
const errors = [];
|
|
272
|
+
|
|
273
|
+
for (const result of results) {
|
|
274
|
+
if (result.status === 'success') {
|
|
275
|
+
recommendations[result.provider] = result;
|
|
276
|
+
} else {
|
|
277
|
+
errors.push({
|
|
278
|
+
provider: result.provider,
|
|
279
|
+
error: result.error,
|
|
280
|
+
errorCode: result.errorCode,
|
|
281
|
+
timestamp: result.timestamp
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Count successful queries
|
|
287
|
+
const successCount = Object.keys(recommendations).length;
|
|
288
|
+
const failureCount = errors.length;
|
|
289
|
+
|
|
290
|
+
debug(`Query complete for ${evaluationPrompt.id}: ${successCount} success, ${failureCount} failed`);
|
|
291
|
+
|
|
292
|
+
// Call progress callback if provided
|
|
293
|
+
if (progressCallback) {
|
|
294
|
+
progressCallback({
|
|
295
|
+
promptId: evaluationPrompt.id,
|
|
296
|
+
successCount,
|
|
297
|
+
failureCount,
|
|
298
|
+
totalTime
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
promptId: evaluationPrompt.id,
|
|
304
|
+
ceremony: evaluationPrompt.ceremony,
|
|
305
|
+
stage: evaluationPrompt.stage,
|
|
306
|
+
stageName: evaluationPrompt.stageName,
|
|
307
|
+
recommendations,
|
|
308
|
+
errors: errors.length > 0 ? errors : null,
|
|
309
|
+
executionTime: totalTime,
|
|
310
|
+
timestamp: new Date().toISOString()
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Query all providers for all evaluation prompts
|
|
316
|
+
* Processes prompts sequentially but providers in parallel
|
|
317
|
+
* @param {Array} evaluationPrompts - Array of evaluation prompt objects
|
|
318
|
+
* @param {Function} progressCallback - Optional callback for progress updates
|
|
319
|
+
* @returns {Promise<Object>} Complete evaluation results
|
|
320
|
+
*/
|
|
321
|
+
async evaluateAll(evaluationPrompts, progressCallback = null) {
|
|
322
|
+
debug(`Starting evaluation of ${evaluationPrompts.length} prompts`);
|
|
323
|
+
|
|
324
|
+
const overallStartTime = Date.now();
|
|
325
|
+
this.results = [];
|
|
326
|
+
this.errors = [];
|
|
327
|
+
|
|
328
|
+
// Process each prompt sequentially (but providers in parallel per prompt)
|
|
329
|
+
for (let i = 0; i < evaluationPrompts.length; i++) {
|
|
330
|
+
const prompt = evaluationPrompts[i];
|
|
331
|
+
|
|
332
|
+
if (progressCallback) {
|
|
333
|
+
progressCallback({
|
|
334
|
+
type: 'prompt-start',
|
|
335
|
+
current: i + 1,
|
|
336
|
+
total: evaluationPrompts.length,
|
|
337
|
+
promptId: prompt.id,
|
|
338
|
+
ceremony: prompt.ceremony,
|
|
339
|
+
stage: prompt.stage
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
const result = await this.queryAllProvidersForPrompt(
|
|
345
|
+
prompt,
|
|
346
|
+
(queryProgress) => {
|
|
347
|
+
if (progressCallback) {
|
|
348
|
+
progressCallback({
|
|
349
|
+
type: 'prompt-complete',
|
|
350
|
+
current: i + 1,
|
|
351
|
+
total: evaluationPrompts.length,
|
|
352
|
+
...queryProgress
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
this.results.push(result);
|
|
359
|
+
|
|
360
|
+
// Track errors
|
|
361
|
+
if (result.errors) {
|
|
362
|
+
this.errors.push(...result.errors);
|
|
363
|
+
}
|
|
364
|
+
} catch (error) {
|
|
365
|
+
debug(`Failed to evaluate prompt ${prompt.id}:`, error.message);
|
|
366
|
+
|
|
367
|
+
this.errors.push({
|
|
368
|
+
promptId: prompt.id,
|
|
369
|
+
error: error.message,
|
|
370
|
+
details: error.stack,
|
|
371
|
+
timestamp: new Date().toISOString()
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// Still add a partial result
|
|
375
|
+
this.results.push({
|
|
376
|
+
promptId: prompt.id,
|
|
377
|
+
ceremony: prompt.ceremony,
|
|
378
|
+
stage: prompt.stage,
|
|
379
|
+
stageName: prompt.stageName,
|
|
380
|
+
recommendations: {},
|
|
381
|
+
errors: [{ error: error.message }],
|
|
382
|
+
executionTime: 0,
|
|
383
|
+
timestamp: new Date().toISOString()
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const overallEndTime = Date.now();
|
|
389
|
+
this.totalExecutionTime = (overallEndTime - overallStartTime) / 1000;
|
|
390
|
+
|
|
391
|
+
debug(`Evaluation complete: ${this.results.length} prompts processed in ${this.totalExecutionTime}s`);
|
|
392
|
+
|
|
393
|
+
// Generate summary
|
|
394
|
+
return this._generateSummary();
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Generate summary of evaluation results
|
|
399
|
+
* @returns {Object} Summary with statistics and aggregated results
|
|
400
|
+
*/
|
|
401
|
+
_generateSummary() {
|
|
402
|
+
const totalPrompts = this.results.length;
|
|
403
|
+
const totalQueries = this.results.reduce((sum, r) =>
|
|
404
|
+
sum + Object.keys(r.recommendations).length, 0
|
|
405
|
+
);
|
|
406
|
+
const failedQueries = this.errors.length;
|
|
407
|
+
|
|
408
|
+
// Calculate total cost per provider
|
|
409
|
+
const costByProvider = {};
|
|
410
|
+
for (const result of this.results) {
|
|
411
|
+
for (const [provider, rec] of Object.entries(result.recommendations)) {
|
|
412
|
+
if (!costByProvider[provider]) {
|
|
413
|
+
costByProvider[provider] = 0;
|
|
414
|
+
}
|
|
415
|
+
costByProvider[provider] += rec.cost || 0;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const totalCost = Object.values(costByProvider).reduce((sum, cost) => sum + cost, 0);
|
|
420
|
+
|
|
421
|
+
// Format execution time
|
|
422
|
+
const minutes = Math.floor(this.totalExecutionTime / 60);
|
|
423
|
+
const seconds = Math.floor(this.totalExecutionTime % 60);
|
|
424
|
+
const executionTimeFormatted = `${minutes}m ${seconds}s`;
|
|
425
|
+
|
|
426
|
+
return {
|
|
427
|
+
executedAt: new Date().toISOString(),
|
|
428
|
+
models: QUERY_MODELS,
|
|
429
|
+
evaluations: this.results,
|
|
430
|
+
summary: {
|
|
431
|
+
totalPrompts,
|
|
432
|
+
successfulQueries: totalQueries,
|
|
433
|
+
failedQueries,
|
|
434
|
+
totalCost: {
|
|
435
|
+
...costByProvider,
|
|
436
|
+
total: totalCost
|
|
437
|
+
},
|
|
438
|
+
executionTime: executionTimeFormatted,
|
|
439
|
+
executionTimeSeconds: this.totalExecutionTime
|
|
440
|
+
},
|
|
441
|
+
errors: this.errors.length > 0 ? this.errors : null
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Get current results
|
|
447
|
+
* @returns {Array} Array of evaluation results
|
|
448
|
+
*/
|
|
449
|
+
getResults() {
|
|
450
|
+
return this.results;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Get current errors
|
|
455
|
+
* @returns {Array} Array of error objects
|
|
456
|
+
*/
|
|
457
|
+
getErrors() {
|
|
458
|
+
return this.errors;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Get summary statistics
|
|
463
|
+
* @returns {Object} Summary statistics
|
|
464
|
+
*/
|
|
465
|
+
getSummary() {
|
|
466
|
+
return this._generateSummary();
|
|
467
|
+
}
|
|
468
|
+
}
|