@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.
Files changed (290) hide show
  1. package/README.md +2 -0
  2. package/cli/agent-loader.js +21 -0
  3. package/cli/agents/agent-selector.md +129 -0
  4. package/cli/agents/architecture-recommender.md +418 -0
  5. package/cli/agents/database-deep-dive.md +470 -0
  6. package/cli/agents/database-recommender.md +634 -0
  7. package/cli/agents/doc-distributor.md +176 -0
  8. package/cli/agents/documentation-updater.md +203 -0
  9. package/cli/agents/epic-story-decomposer.md +280 -0
  10. package/cli/agents/feature-context-generator.md +91 -0
  11. package/cli/agents/gap-checker-epic.md +52 -0
  12. package/cli/agents/impact-checker-story.md +51 -0
  13. package/cli/agents/migration-guide-generator.md +305 -0
  14. package/cli/agents/mission-scope-generator.md +79 -0
  15. package/cli/agents/mission-scope-validator.md +112 -0
  16. package/cli/agents/project-context-extractor.md +107 -0
  17. package/cli/agents/project-documentation-creator.json +226 -0
  18. package/cli/agents/project-documentation-creator.md +595 -0
  19. package/cli/agents/question-prefiller.md +269 -0
  20. package/cli/agents/refiner-epic.md +39 -0
  21. package/cli/agents/refiner-story.md +42 -0
  22. package/cli/agents/solver-epic-api.json +15 -0
  23. package/cli/agents/solver-epic-api.md +39 -0
  24. package/cli/agents/solver-epic-backend.json +15 -0
  25. package/cli/agents/solver-epic-backend.md +39 -0
  26. package/cli/agents/solver-epic-cloud.json +15 -0
  27. package/cli/agents/solver-epic-cloud.md +39 -0
  28. package/cli/agents/solver-epic-data.json +15 -0
  29. package/cli/agents/solver-epic-data.md +39 -0
  30. package/cli/agents/solver-epic-database.json +15 -0
  31. package/cli/agents/solver-epic-database.md +39 -0
  32. package/cli/agents/solver-epic-developer.json +15 -0
  33. package/cli/agents/solver-epic-developer.md +39 -0
  34. package/cli/agents/solver-epic-devops.json +15 -0
  35. package/cli/agents/solver-epic-devops.md +39 -0
  36. package/cli/agents/solver-epic-frontend.json +15 -0
  37. package/cli/agents/solver-epic-frontend.md +39 -0
  38. package/cli/agents/solver-epic-mobile.json +15 -0
  39. package/cli/agents/solver-epic-mobile.md +39 -0
  40. package/cli/agents/solver-epic-qa.json +15 -0
  41. package/cli/agents/solver-epic-qa.md +39 -0
  42. package/cli/agents/solver-epic-security.json +15 -0
  43. package/cli/agents/solver-epic-security.md +39 -0
  44. package/cli/agents/solver-epic-solution-architect.json +15 -0
  45. package/cli/agents/solver-epic-solution-architect.md +39 -0
  46. package/cli/agents/solver-epic-test-architect.json +15 -0
  47. package/cli/agents/solver-epic-test-architect.md +39 -0
  48. package/cli/agents/solver-epic-ui.json +15 -0
  49. package/cli/agents/solver-epic-ui.md +39 -0
  50. package/cli/agents/solver-epic-ux.json +15 -0
  51. package/cli/agents/solver-epic-ux.md +39 -0
  52. package/cli/agents/solver-story-api.json +15 -0
  53. package/cli/agents/solver-story-api.md +39 -0
  54. package/cli/agents/solver-story-backend.json +15 -0
  55. package/cli/agents/solver-story-backend.md +39 -0
  56. package/cli/agents/solver-story-cloud.json +15 -0
  57. package/cli/agents/solver-story-cloud.md +39 -0
  58. package/cli/agents/solver-story-data.json +15 -0
  59. package/cli/agents/solver-story-data.md +39 -0
  60. package/cli/agents/solver-story-database.json +15 -0
  61. package/cli/agents/solver-story-database.md +39 -0
  62. package/cli/agents/solver-story-developer.json +15 -0
  63. package/cli/agents/solver-story-developer.md +39 -0
  64. package/cli/agents/solver-story-devops.json +15 -0
  65. package/cli/agents/solver-story-devops.md +39 -0
  66. package/cli/agents/solver-story-frontend.json +15 -0
  67. package/cli/agents/solver-story-frontend.md +39 -0
  68. package/cli/agents/solver-story-mobile.json +15 -0
  69. package/cli/agents/solver-story-mobile.md +39 -0
  70. package/cli/agents/solver-story-qa.json +15 -0
  71. package/cli/agents/solver-story-qa.md +39 -0
  72. package/cli/agents/solver-story-security.json +15 -0
  73. package/cli/agents/solver-story-security.md +39 -0
  74. package/cli/agents/solver-story-solution-architect.json +15 -0
  75. package/cli/agents/solver-story-solution-architect.md +39 -0
  76. package/cli/agents/solver-story-test-architect.json +15 -0
  77. package/cli/agents/solver-story-test-architect.md +39 -0
  78. package/cli/agents/solver-story-ui.json +15 -0
  79. package/cli/agents/solver-story-ui.md +39 -0
  80. package/cli/agents/solver-story-ux.json +15 -0
  81. package/cli/agents/solver-story-ux.md +39 -0
  82. package/cli/agents/story-doc-enricher.md +133 -0
  83. package/cli/agents/suggestion-business-analyst.md +88 -0
  84. package/cli/agents/suggestion-deployment-architect.md +263 -0
  85. package/cli/agents/suggestion-product-manager.md +129 -0
  86. package/cli/agents/suggestion-security-specialist.md +156 -0
  87. package/cli/agents/suggestion-technical-architect.md +269 -0
  88. package/cli/agents/suggestion-ux-researcher.md +93 -0
  89. package/cli/agents/task-subtask-decomposer.md +188 -0
  90. package/cli/agents/validator-documentation.json +152 -0
  91. package/cli/agents/validator-documentation.md +453 -0
  92. package/cli/agents/validator-epic-api.json +93 -0
  93. package/cli/agents/validator-epic-api.md +137 -0
  94. package/cli/agents/validator-epic-backend.json +93 -0
  95. package/cli/agents/validator-epic-backend.md +130 -0
  96. package/cli/agents/validator-epic-cloud.json +93 -0
  97. package/cli/agents/validator-epic-cloud.md +137 -0
  98. package/cli/agents/validator-epic-data.json +93 -0
  99. package/cli/agents/validator-epic-data.md +130 -0
  100. package/cli/agents/validator-epic-database.json +93 -0
  101. package/cli/agents/validator-epic-database.md +137 -0
  102. package/cli/agents/validator-epic-developer.json +74 -0
  103. package/cli/agents/validator-epic-developer.md +153 -0
  104. package/cli/agents/validator-epic-devops.json +74 -0
  105. package/cli/agents/validator-epic-devops.md +153 -0
  106. package/cli/agents/validator-epic-frontend.json +74 -0
  107. package/cli/agents/validator-epic-frontend.md +153 -0
  108. package/cli/agents/validator-epic-mobile.json +93 -0
  109. package/cli/agents/validator-epic-mobile.md +130 -0
  110. package/cli/agents/validator-epic-qa.json +93 -0
  111. package/cli/agents/validator-epic-qa.md +130 -0
  112. package/cli/agents/validator-epic-security.json +74 -0
  113. package/cli/agents/validator-epic-security.md +154 -0
  114. package/cli/agents/validator-epic-solution-architect.json +74 -0
  115. package/cli/agents/validator-epic-solution-architect.md +156 -0
  116. package/cli/agents/validator-epic-test-architect.json +93 -0
  117. package/cli/agents/validator-epic-test-architect.md +130 -0
  118. package/cli/agents/validator-epic-ui.json +93 -0
  119. package/cli/agents/validator-epic-ui.md +130 -0
  120. package/cli/agents/validator-epic-ux.json +93 -0
  121. package/cli/agents/validator-epic-ux.md +130 -0
  122. package/cli/agents/validator-selector.md +211 -0
  123. package/cli/agents/validator-story-api.json +104 -0
  124. package/cli/agents/validator-story-api.md +152 -0
  125. package/cli/agents/validator-story-backend.json +104 -0
  126. package/cli/agents/validator-story-backend.md +152 -0
  127. package/cli/agents/validator-story-cloud.json +104 -0
  128. package/cli/agents/validator-story-cloud.md +152 -0
  129. package/cli/agents/validator-story-data.json +104 -0
  130. package/cli/agents/validator-story-data.md +152 -0
  131. package/cli/agents/validator-story-database.json +104 -0
  132. package/cli/agents/validator-story-database.md +152 -0
  133. package/cli/agents/validator-story-developer.json +104 -0
  134. package/cli/agents/validator-story-developer.md +152 -0
  135. package/cli/agents/validator-story-devops.json +104 -0
  136. package/cli/agents/validator-story-devops.md +152 -0
  137. package/cli/agents/validator-story-frontend.json +104 -0
  138. package/cli/agents/validator-story-frontend.md +152 -0
  139. package/cli/agents/validator-story-mobile.json +104 -0
  140. package/cli/agents/validator-story-mobile.md +152 -0
  141. package/cli/agents/validator-story-qa.json +104 -0
  142. package/cli/agents/validator-story-qa.md +152 -0
  143. package/cli/agents/validator-story-security.json +104 -0
  144. package/cli/agents/validator-story-security.md +152 -0
  145. package/cli/agents/validator-story-solution-architect.json +104 -0
  146. package/cli/agents/validator-story-solution-architect.md +152 -0
  147. package/cli/agents/validator-story-test-architect.json +104 -0
  148. package/cli/agents/validator-story-test-architect.md +152 -0
  149. package/cli/agents/validator-story-ui.json +104 -0
  150. package/cli/agents/validator-story-ui.md +152 -0
  151. package/cli/agents/validator-story-ux.json +104 -0
  152. package/cli/agents/validator-story-ux.md +152 -0
  153. package/cli/ansi-colors.js +21 -0
  154. package/cli/build-docs.js +298 -0
  155. package/cli/ceremony-history.js +369 -0
  156. package/cli/command-logger.js +245 -0
  157. package/cli/components/static-output.js +63 -0
  158. package/cli/console-output-manager.js +94 -0
  159. package/cli/docs-sync.js +306 -0
  160. package/cli/epic-story-validator.js +1174 -0
  161. package/cli/evaluation-prompts.js +1008 -0
  162. package/cli/execution-context.js +195 -0
  163. package/cli/generate-summary-table.js +340 -0
  164. package/cli/index.js +3 -25
  165. package/cli/init-model-config.js +697 -0
  166. package/cli/init.js +1765 -100
  167. package/cli/kanban-server-manager.js +228 -0
  168. package/cli/llm-claude.js +109 -0
  169. package/cli/llm-gemini.js +115 -0
  170. package/cli/llm-mock.js +233 -0
  171. package/cli/llm-openai.js +233 -0
  172. package/cli/llm-provider.js +300 -0
  173. package/cli/llm-token-limits.js +102 -0
  174. package/cli/llm-verifier.js +454 -0
  175. package/cli/logger.js +32 -5
  176. package/cli/message-constants.js +58 -0
  177. package/cli/message-manager.js +334 -0
  178. package/cli/message-types.js +96 -0
  179. package/cli/messaging-api.js +297 -0
  180. package/cli/model-pricing.js +169 -0
  181. package/cli/model-query-engine.js +468 -0
  182. package/cli/model-recommendation-analyzer.js +495 -0
  183. package/cli/model-selector.js +269 -0
  184. package/cli/output-buffer.js +107 -0
  185. package/cli/process-manager.js +332 -0
  186. package/cli/repl-ink.js +5840 -504
  187. package/cli/repl-old.js +4 -4
  188. package/cli/seed-processor.js +792 -0
  189. package/cli/sprint-planning-processor.js +1813 -0
  190. package/cli/template-processor.js +2306 -108
  191. package/cli/templates/project.md +25 -8
  192. package/cli/templates/vitepress-config.mts.template +34 -0
  193. package/cli/token-tracker.js +520 -0
  194. package/cli/tools/generate-story-validators.js +317 -0
  195. package/cli/tools/generate-validators.js +669 -0
  196. package/cli/update-checker.js +19 -17
  197. package/cli/update-notifier.js +4 -4
  198. package/cli/validation-router.js +605 -0
  199. package/cli/verification-tracker.js +563 -0
  200. package/kanban/README.md +386 -0
  201. package/kanban/client/README.md +205 -0
  202. package/kanban/client/components.json +20 -0
  203. package/kanban/client/dist/assets/index-CiD8PS2e.js +306 -0
  204. package/kanban/client/dist/assets/index-nLh0m82Q.css +1 -0
  205. package/kanban/client/dist/index.html +16 -0
  206. package/kanban/client/dist/vite.svg +1 -0
  207. package/kanban/client/index.html +15 -0
  208. package/kanban/client/package-lock.json +9442 -0
  209. package/kanban/client/package.json +44 -0
  210. package/kanban/client/postcss.config.js +6 -0
  211. package/kanban/client/public/vite.svg +1 -0
  212. package/kanban/client/src/App.jsx +622 -0
  213. package/kanban/client/src/components/ProjectFileEditorPopup.jsx +117 -0
  214. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +416 -0
  215. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +616 -0
  216. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +946 -0
  217. package/kanban/client/src/components/ceremony/EpicStorySelectionModal.jsx +254 -0
  218. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +619 -0
  219. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +704 -0
  220. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +150 -0
  221. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +154 -0
  222. package/kanban/client/src/components/ceremony/steps/DatabaseStep.jsx +202 -0
  223. package/kanban/client/src/components/ceremony/steps/DeploymentStep.jsx +123 -0
  224. package/kanban/client/src/components/ceremony/steps/MissionStep.jsx +106 -0
  225. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +125 -0
  226. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +228 -0
  227. package/kanban/client/src/components/kanban/CardDetailModal.jsx +559 -0
  228. package/kanban/client/src/components/kanban/EpicSection.jsx +146 -0
  229. package/kanban/client/src/components/kanban/FilterToolbar.jsx +222 -0
  230. package/kanban/client/src/components/kanban/GroupingSelector.jsx +57 -0
  231. package/kanban/client/src/components/kanban/KanbanBoard.jsx +211 -0
  232. package/kanban/client/src/components/kanban/KanbanCard.jsx +138 -0
  233. package/kanban/client/src/components/kanban/KanbanColumn.jsx +90 -0
  234. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +789 -0
  235. package/kanban/client/src/components/layout/LoadingScreen.jsx +82 -0
  236. package/kanban/client/src/components/process/ProcessMonitorBar.jsx +80 -0
  237. package/kanban/client/src/components/settings/AgentEditorPopup.jsx +171 -0
  238. package/kanban/client/src/components/settings/AgentsTab.jsx +353 -0
  239. package/kanban/client/src/components/settings/ApiKeysTab.jsx +113 -0
  240. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +98 -0
  241. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +94 -0
  242. package/kanban/client/src/components/settings/ModelPricingTab.jsx +204 -0
  243. package/kanban/client/src/components/settings/ServersTab.jsx +121 -0
  244. package/kanban/client/src/components/settings/SettingsModal.jsx +84 -0
  245. package/kanban/client/src/components/stats/CostModal.jsx +353 -0
  246. package/kanban/client/src/components/ui/badge.jsx +27 -0
  247. package/kanban/client/src/components/ui/dialog.jsx +121 -0
  248. package/kanban/client/src/components/ui/tabs.jsx +85 -0
  249. package/kanban/client/src/hooks/__tests__/useGrouping.test.js +232 -0
  250. package/kanban/client/src/hooks/useGrouping.js +118 -0
  251. package/kanban/client/src/hooks/useWebSocket.js +120 -0
  252. package/kanban/client/src/lib/__tests__/api.test.js +196 -0
  253. package/kanban/client/src/lib/__tests__/status-grouping.test.js +94 -0
  254. package/kanban/client/src/lib/api.js +401 -0
  255. package/kanban/client/src/lib/status-grouping.js +144 -0
  256. package/kanban/client/src/lib/utils.js +11 -0
  257. package/kanban/client/src/main.jsx +10 -0
  258. package/kanban/client/src/store/__tests__/kanbanStore.test.js +164 -0
  259. package/kanban/client/src/store/ceremonyStore.js +172 -0
  260. package/kanban/client/src/store/filterStore.js +201 -0
  261. package/kanban/client/src/store/kanbanStore.js +115 -0
  262. package/kanban/client/src/store/processStore.js +65 -0
  263. package/kanban/client/src/store/sprintPlanningStore.js +33 -0
  264. package/kanban/client/src/styles/globals.css +59 -0
  265. package/kanban/client/tailwind.config.js +77 -0
  266. package/kanban/client/vite.config.js +28 -0
  267. package/kanban/client/vitest.config.js +28 -0
  268. package/kanban/dev-start.sh +47 -0
  269. package/kanban/package.json +12 -0
  270. package/kanban/server/index.js +516 -0
  271. package/kanban/server/routes/ceremony.js +305 -0
  272. package/kanban/server/routes/costs.js +157 -0
  273. package/kanban/server/routes/processes.js +50 -0
  274. package/kanban/server/routes/settings.js +303 -0
  275. package/kanban/server/routes/websocket.js +276 -0
  276. package/kanban/server/routes/work-items.js +347 -0
  277. package/kanban/server/services/CeremonyService.js +1190 -0
  278. package/kanban/server/services/FileSystemScanner.js +95 -0
  279. package/kanban/server/services/FileWatcher.js +144 -0
  280. package/kanban/server/services/HierarchyBuilder.js +196 -0
  281. package/kanban/server/services/ProcessRegistry.js +122 -0
  282. package/kanban/server/services/WorkItemReader.js +123 -0
  283. package/kanban/server/services/WorkItemRefineService.js +510 -0
  284. package/kanban/server/start.js +49 -0
  285. package/kanban/server/utils/kanban-logger.js +132 -0
  286. package/kanban/server/utils/markdown.js +91 -0
  287. package/kanban/server/utils/status-grouping.js +107 -0
  288. package/kanban/server/workers/sponsor-call-worker.js +84 -0
  289. package/kanban/server/workers/sprint-planning-worker.js +130 -0
  290. 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
+ }