tachibot-mcp 2.0.2

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 (214) hide show
  1. package/.env.example +260 -0
  2. package/CHANGELOG.md +54 -0
  3. package/CODE_OF_CONDUCT.md +56 -0
  4. package/CONTRIBUTING.md +54 -0
  5. package/Dockerfile +36 -0
  6. package/LICENSE +644 -0
  7. package/README.md +201 -0
  8. package/SECURITY.md +95 -0
  9. package/dist/personality/komaai-expressions.js +12 -0
  10. package/dist/profiles/balanced.json +33 -0
  11. package/dist/profiles/code_focus.json +33 -0
  12. package/dist/profiles/full.json +33 -0
  13. package/dist/profiles/minimal.json +33 -0
  14. package/dist/profiles/research_power.json +33 -0
  15. package/dist/scripts/build-profiles.js +46 -0
  16. package/dist/src/application/services/focus/FocusModeRegistry.js +46 -0
  17. package/dist/src/application/services/focus/FocusTool.service.js +109 -0
  18. package/dist/src/application/services/focus/ModeRegistry.js +46 -0
  19. package/dist/src/application/services/focus/modes/focus-deep.mode.js +27 -0
  20. package/dist/src/application/services/focus/modes/status.mode.js +50 -0
  21. package/dist/src/application/services/focus/modes/tachibot-status.mode.js +50 -0
  22. package/dist/src/collaborative-orchestrator.js +391 -0
  23. package/dist/src/config/model-constants.js +188 -0
  24. package/dist/src/config/model-defaults.js +57 -0
  25. package/dist/src/config/model-preferences.js +382 -0
  26. package/dist/src/config/timeout-config.js +130 -0
  27. package/dist/src/config.js +173 -0
  28. package/dist/src/domain/interfaces/IFocusMode.js +5 -0
  29. package/dist/src/domain/interfaces/IProvider.js +6 -0
  30. package/dist/src/domain/interfaces/ITool.js +5 -0
  31. package/dist/src/focus-deep.js +245 -0
  32. package/dist/src/infrastructure/ascii/art/robots.ascii.js +16 -0
  33. package/dist/src/mcp-client.js +90 -0
  34. package/dist/src/memory/index.js +17 -0
  35. package/dist/src/memory/memory-config.js +135 -0
  36. package/dist/src/memory/memory-interface.js +174 -0
  37. package/dist/src/memory/memory-manager.js +383 -0
  38. package/dist/src/memory/providers/devlog-provider.js +385 -0
  39. package/dist/src/memory/providers/hybrid-provider.js +399 -0
  40. package/dist/src/memory/providers/local-provider.js +388 -0
  41. package/dist/src/memory/providers/mem0-provider.js +337 -0
  42. package/dist/src/modes/architect.js +477 -0
  43. package/dist/src/modes/auditor.js +362 -0
  44. package/dist/src/modes/challenger.js +841 -0
  45. package/dist/src/modes/code-reviewer.js +382 -0
  46. package/dist/src/modes/commit-guardian.js +424 -0
  47. package/dist/src/modes/documentation-writer.js +572 -0
  48. package/dist/src/modes/scout.js +587 -0
  49. package/dist/src/modes/shared/helpers/challenger-helpers.js +454 -0
  50. package/dist/src/modes/shared/helpers/index.js +17 -0
  51. package/dist/src/modes/shared/helpers/scout-helpers.js +270 -0
  52. package/dist/src/modes/shared/helpers/verifier-helpers.js +332 -0
  53. package/dist/src/modes/test-architect.js +767 -0
  54. package/dist/src/modes/verifier.js +378 -0
  55. package/dist/src/monitoring/performance-monitor.js +435 -0
  56. package/dist/src/optimization/batch-executor.js +121 -0
  57. package/dist/src/optimization/context-pruner.js +196 -0
  58. package/dist/src/optimization/cost-monitor.js +338 -0
  59. package/dist/src/optimization/index.js +65 -0
  60. package/dist/src/optimization/model-router.js +264 -0
  61. package/dist/src/optimization/result-cache.js +114 -0
  62. package/dist/src/optimization/token-optimizer.js +257 -0
  63. package/dist/src/optimization/token-tracker.js +118 -0
  64. package/dist/src/orchestrator-instructions.js +128 -0
  65. package/dist/src/orchestrator-lite.js +139 -0
  66. package/dist/src/orchestrator.js +191 -0
  67. package/dist/src/orchestrators/collaborative/interfaces/IToolExecutionEngine.js +1 -0
  68. package/dist/src/orchestrators/collaborative/interfaces/IToolExecutionStrategy.js +5 -0
  69. package/dist/src/orchestrators/collaborative/interfaces/IVisualizationRenderer.js +1 -0
  70. package/dist/src/orchestrators/collaborative/registries/ModelProviderRegistry.js +95 -0
  71. package/dist/src/orchestrators/collaborative/registries/ToolAdapterRegistry.js +64 -0
  72. package/dist/src/orchestrators/collaborative/services/tool-execution/ToolExecutionService.js +502 -0
  73. package/dist/src/orchestrators/collaborative/services/visualization/VisualizationService.js +206 -0
  74. package/dist/src/orchestrators/collaborative/types/session-types.js +5 -0
  75. package/dist/src/profiles/balanced.js +37 -0
  76. package/dist/src/profiles/code_focus.js +37 -0
  77. package/dist/src/profiles/debug_intensive.js +59 -0
  78. package/dist/src/profiles/full.js +37 -0
  79. package/dist/src/profiles/minimal.js +37 -0
  80. package/dist/src/profiles/research_code.js +59 -0
  81. package/dist/src/profiles/research_power.js +37 -0
  82. package/dist/src/profiles/types.js +5 -0
  83. package/dist/src/profiles/workflow_builder.js +53 -0
  84. package/dist/src/prompt-engineer-lite.js +78 -0
  85. package/dist/src/prompt-engineer.js +399 -0
  86. package/dist/src/reasoning-chain.js +508 -0
  87. package/dist/src/sequential-thinking.js +291 -0
  88. package/dist/src/server-diagnostic.js +74 -0
  89. package/dist/src/server-raw.js +158 -0
  90. package/dist/src/server-simple.js +58 -0
  91. package/dist/src/server.js +514 -0
  92. package/dist/src/session/session-logger.js +617 -0
  93. package/dist/src/session/session-manager.js +571 -0
  94. package/dist/src/session/session-tools.js +400 -0
  95. package/dist/src/tools/advanced-modes.js +200 -0
  96. package/dist/src/tools/claude-integration.js +356 -0
  97. package/dist/src/tools/consolidated/ai-router.js +174 -0
  98. package/dist/src/tools/consolidated/ai-tool.js +48 -0
  99. package/dist/src/tools/consolidated/brainstorm-tool.js +87 -0
  100. package/dist/src/tools/consolidated/environment-detector.js +80 -0
  101. package/dist/src/tools/consolidated/index.js +50 -0
  102. package/dist/src/tools/consolidated/search-tool.js +110 -0
  103. package/dist/src/tools/consolidated/workflow-tool.js +238 -0
  104. package/dist/src/tools/gemini-tools.js +329 -0
  105. package/dist/src/tools/grok-enhanced.js +376 -0
  106. package/dist/src/tools/grok-tools.js +299 -0
  107. package/dist/src/tools/lmstudio-tools.js +223 -0
  108. package/dist/src/tools/openai-tools.js +498 -0
  109. package/dist/src/tools/openrouter-tools.js +317 -0
  110. package/dist/src/tools/optimized-wrapper.js +204 -0
  111. package/dist/src/tools/perplexity-tools.js +294 -0
  112. package/dist/src/tools/pingpong-tool.js +343 -0
  113. package/dist/src/tools/qwen-wrapper.js +74 -0
  114. package/dist/src/tools/tool-router.js +444 -0
  115. package/dist/src/tools/unified-ai-provider.js +260 -0
  116. package/dist/src/tools/workflow-runner.js +425 -0
  117. package/dist/src/tools/workflow-validator-tool.js +107 -0
  118. package/dist/src/types.js +23 -0
  119. package/dist/src/utils/input-validator.js +130 -0
  120. package/dist/src/utils/model-router.js +91 -0
  121. package/dist/src/utils/progress-stream.js +255 -0
  122. package/dist/src/utils/provider-router.js +88 -0
  123. package/dist/src/utils/smart-api-client.js +146 -0
  124. package/dist/src/utils/table-builder.js +218 -0
  125. package/dist/src/utils/timestamp-formatter.js +134 -0
  126. package/dist/src/utils/tool-compressor.js +257 -0
  127. package/dist/src/utils/tool-config.js +201 -0
  128. package/dist/src/validators/dependency-graph-validator.js +147 -0
  129. package/dist/src/validators/interpolation-validator.js +222 -0
  130. package/dist/src/validators/output-usage-validator.js +151 -0
  131. package/dist/src/validators/syntax-validator.js +102 -0
  132. package/dist/src/validators/tool-registry-validator.js +123 -0
  133. package/dist/src/validators/tool-types.js +97 -0
  134. package/dist/src/validators/types.js +8 -0
  135. package/dist/src/validators/workflow-validator.js +134 -0
  136. package/dist/src/visualizer-lite.js +42 -0
  137. package/dist/src/visualizer.js +179 -0
  138. package/dist/src/workflows/circuit-breaker.js +199 -0
  139. package/dist/src/workflows/custom-workflows.js +451 -0
  140. package/dist/src/workflows/engine/AutoSynthesizer.js +97 -0
  141. package/dist/src/workflows/engine/StepParameterResolver.js +74 -0
  142. package/dist/src/workflows/engine/VariableInterpolator.js +123 -0
  143. package/dist/src/workflows/engine/WorkflowDiscovery.js +125 -0
  144. package/dist/src/workflows/engine/WorkflowExecutionEngine.js +485 -0
  145. package/dist/src/workflows/engine/WorkflowExecutor.js +113 -0
  146. package/dist/src/workflows/engine/WorkflowFileManager.js +244 -0
  147. package/dist/src/workflows/engine/WorkflowHelpers.js +114 -0
  148. package/dist/src/workflows/engine/WorkflowOutputFormatter.js +83 -0
  149. package/dist/src/workflows/engine/events/WorkflowEventBus.js +132 -0
  150. package/dist/src/workflows/engine/events/interfaces/IEventBus.js +5 -0
  151. package/dist/src/workflows/engine/handlers/ErrorRecoveryHandler.js +162 -0
  152. package/dist/src/workflows/engine/handlers/PromptEnhancementHandler.js +115 -0
  153. package/dist/src/workflows/engine/handlers/SessionPersistenceHandler.js +167 -0
  154. package/dist/src/workflows/engine/handlers/StepExecutionHandler.js +231 -0
  155. package/dist/src/workflows/engine/handlers/ToolInvocationHandler.js +46 -0
  156. package/dist/src/workflows/engine/interfaces/IAutoSynthesizer.js +5 -0
  157. package/dist/src/workflows/engine/interfaces/IStepParameterResolver.js +5 -0
  158. package/dist/src/workflows/engine/interfaces/IVariableInterpolator.js +5 -0
  159. package/dist/src/workflows/engine/interfaces/IWorkflowDiscovery.js +4 -0
  160. package/dist/src/workflows/engine/interfaces/IWorkflowFileManager.js +5 -0
  161. package/dist/src/workflows/engine/interfaces/IWorkflowOutputFormatter.js +5 -0
  162. package/dist/src/workflows/engine/state/WorkflowStateMachine.js +194 -0
  163. package/dist/src/workflows/engine/state/interfaces/IStateMachine.js +17 -0
  164. package/dist/src/workflows/fallback-strategies.js +373 -0
  165. package/dist/src/workflows/message-queue.js +455 -0
  166. package/dist/src/workflows/model-router.js +189 -0
  167. package/dist/src/workflows/orchestrator-examples.js +174 -0
  168. package/dist/src/workflows/orchestrator-integration.js +200 -0
  169. package/dist/src/workflows/self-healing.js +524 -0
  170. package/dist/src/workflows/tool-mapper.js +407 -0
  171. package/dist/src/workflows/tool-orchestrator.js +796 -0
  172. package/dist/src/workflows/workflow-engine.js +573 -0
  173. package/dist/src/workflows/workflow-parser.js +283 -0
  174. package/dist/src/workflows/workflow-types.js +95 -0
  175. package/dist/src/workflows.js +568 -0
  176. package/dist/test-workflow-file-output.js +93 -0
  177. package/docs/API_KEYS.md +570 -0
  178. package/docs/CLAUDE_CODE_SETUP.md +181 -0
  179. package/docs/CLAUDE_DESKTOP_MANUAL.md +127 -0
  180. package/docs/CONFIGURATION.md +745 -0
  181. package/docs/FOCUS_MODES.md +240 -0
  182. package/docs/INSTALLATION_BOTH.md +145 -0
  183. package/docs/TERMS.md +352 -0
  184. package/docs/TOOLS_REFERENCE.md +1622 -0
  185. package/docs/TOOL_PARAMETERS.md +496 -0
  186. package/docs/TOOL_PROFILES.md +236 -0
  187. package/docs/WORKFLOWS.md +987 -0
  188. package/docs/WORKFLOW_OUTPUT.md +198 -0
  189. package/docs/WORKFLOW_PROGRESS_TRACKING.md +305 -0
  190. package/docs/workflows/design-brainstorm.md +335 -0
  191. package/package.json +97 -0
  192. package/profiles/balanced.json +37 -0
  193. package/profiles/code_focus.json +37 -0
  194. package/profiles/debug_intensive.json +34 -0
  195. package/profiles/full.json +37 -0
  196. package/profiles/minimal.json +37 -0
  197. package/profiles/research_power.json +37 -0
  198. package/profiles/workflow_builder.json +37 -0
  199. package/smithery.yaml +66 -0
  200. package/start.sh +8 -0
  201. package/tools.config.json +81 -0
  202. package/tsconfig.json +18 -0
  203. package/workflows/accessibility-code-audit.yaml +92 -0
  204. package/workflows/code-architecture-review.yaml +202 -0
  205. package/workflows/code-review.yaml +142 -0
  206. package/workflows/core/iterative-problem-solver.yaml +283 -0
  207. package/workflows/creative-brainstorm-yaml.yaml +215 -0
  208. package/workflows/pingpong.yaml +141 -0
  209. package/workflows/system/README.md +412 -0
  210. package/workflows/system/challenger.yaml +175 -0
  211. package/workflows/system/scout.yaml +164 -0
  212. package/workflows/system/verifier.yaml +133 -0
  213. package/workflows/ultra-creative-brainstorm.yaml +318 -0
  214. package/workflows/ux-research-flow.yaml +92 -0
@@ -0,0 +1,196 @@
1
+ export class ContextPruner {
2
+ constructor() {
3
+ this.strategies = new Map([
4
+ ['embedding-similarity', this.pruneByEmbedding.bind(this)],
5
+ ['keyword', this.pruneByKeyword.bind(this)],
6
+ ['length', this.pruneByLength.bind(this)],
7
+ ['hybrid', this.pruneHybrid.bind(this)]
8
+ ]);
9
+ }
10
+ prune(text, options) {
11
+ const strategy = this.strategies.get(options.strategy) || this.pruneByLength.bind(this);
12
+ const pruned = strategy(text, options);
13
+ const originalTokens = this.estimateTokens(text);
14
+ const prunedTokens = this.estimateTokens(pruned);
15
+ const tokensReduced = originalTokens - prunedTokens;
16
+ const reductionRate = tokensReduced / originalTokens;
17
+ return {
18
+ original: text,
19
+ pruned,
20
+ tokensReduced,
21
+ reductionRate,
22
+ preservedSections: this.identifyPreservedSections(text, pruned)
23
+ };
24
+ }
25
+ pruneByEmbedding(text, options) {
26
+ const sentences = this.splitIntoSentences(text);
27
+ const scores = this.calculateSentenceImportance(sentences);
28
+ const sortedSentences = sentences
29
+ .map((sentence, index) => ({ sentence, score: scores[index], index }))
30
+ .sort((a, b) => b.score - a.score);
31
+ let result = [];
32
+ let currentTokens = 0;
33
+ for (const item of sortedSentences) {
34
+ const sentenceTokens = this.estimateTokens(item.sentence);
35
+ if (currentTokens + sentenceTokens <= options.maxTokens) {
36
+ result.push(item.sentence);
37
+ currentTokens += sentenceTokens;
38
+ }
39
+ }
40
+ // Preserve order
41
+ result = result.sort((a, b) => {
42
+ const indexA = sentences.indexOf(a);
43
+ const indexB = sentences.indexOf(b);
44
+ return indexA - indexB;
45
+ });
46
+ return result.join(' ');
47
+ }
48
+ pruneByKeyword(text, options) {
49
+ const keywords = this.extractKeywords(text);
50
+ const sentences = this.splitIntoSentences(text);
51
+ const scoredSentences = sentences.map(sentence => {
52
+ const score = keywords.reduce((sum, keyword) => {
53
+ return sum + (sentence.toLowerCase().includes(keyword.toLowerCase()) ? 1 : 0);
54
+ }, 0);
55
+ return { sentence, score };
56
+ });
57
+ scoredSentences.sort((a, b) => b.score - a.score);
58
+ let result = [];
59
+ let currentTokens = 0;
60
+ for (const item of scoredSentences) {
61
+ const sentenceTokens = this.estimateTokens(item.sentence);
62
+ if (currentTokens + sentenceTokens <= options.maxTokens) {
63
+ result.push(item.sentence);
64
+ currentTokens += sentenceTokens;
65
+ }
66
+ }
67
+ return result.join(' ');
68
+ }
69
+ pruneByLength(text, options) {
70
+ const targetLength = options.maxTokens * 4; // Rough character estimate
71
+ if (text.length <= targetLength) {
72
+ return text;
73
+ }
74
+ const sections = this.splitIntoSections(text);
75
+ let result = '';
76
+ for (const section of sections) {
77
+ if (result.length + section.length <= targetLength) {
78
+ result += section + '\n\n';
79
+ }
80
+ else {
81
+ const remaining = targetLength - result.length;
82
+ result += section.substring(0, remaining);
83
+ break;
84
+ }
85
+ }
86
+ return result.trim();
87
+ }
88
+ pruneHybrid(text, options) {
89
+ // Combine multiple strategies
90
+ const embeddingWeight = 0.4;
91
+ const keywordWeight = 0.3;
92
+ const recencyWeight = 0.3;
93
+ const sentences = this.splitIntoSentences(text);
94
+ const embeddingScores = this.calculateSentenceImportance(sentences);
95
+ const keywords = this.extractKeywords(text);
96
+ const finalScores = sentences.map((sentence, index) => {
97
+ const embeddingScore = embeddingScores[index] * embeddingWeight;
98
+ const keywordScore = keywords.reduce((sum, keyword) => {
99
+ return sum + (sentence.toLowerCase().includes(keyword.toLowerCase()) ? 1 : 0);
100
+ }, 0) * keywordWeight;
101
+ const recencyScore = (index / sentences.length) * recencyWeight;
102
+ return {
103
+ sentence,
104
+ score: embeddingScore + keywordScore + recencyScore,
105
+ index
106
+ };
107
+ });
108
+ finalScores.sort((a, b) => b.score - a.score);
109
+ let result = [];
110
+ let currentTokens = 0;
111
+ for (const item of finalScores) {
112
+ const sentenceTokens = this.estimateTokens(item.sentence);
113
+ if (currentTokens + sentenceTokens <= options.maxTokens) {
114
+ result.push(item);
115
+ currentTokens += sentenceTokens;
116
+ }
117
+ }
118
+ // Preserve original order
119
+ result.sort((a, b) => a.index - b.index);
120
+ return result.map(item => item.sentence).join(' ');
121
+ }
122
+ splitIntoSentences(text) {
123
+ return text.match(/[^.!?]+[.!?]+/g) || [text];
124
+ }
125
+ splitIntoSections(text) {
126
+ return text.split(/\n\n+/).filter(s => s.trim());
127
+ }
128
+ calculateSentenceImportance(sentences) {
129
+ // Simplified importance calculation
130
+ return sentences.map(sentence => {
131
+ let score = 0;
132
+ // Length factor
133
+ if (sentence.length > 50 && sentence.length < 200)
134
+ score += 0.3;
135
+ // Contains numbers or data
136
+ if (/\d+/.test(sentence))
137
+ score += 0.2;
138
+ // Contains technical terms (simplified)
139
+ const technicalTerms = ['function', 'class', 'method', 'api', 'error', 'bug', 'feature'];
140
+ technicalTerms.forEach(term => {
141
+ if (sentence.toLowerCase().includes(term))
142
+ score += 0.1;
143
+ });
144
+ // Question or conclusion indicators
145
+ if (sentence.includes('?') || sentence.includes('therefore') || sentence.includes('conclusion')) {
146
+ score += 0.3;
147
+ }
148
+ return Math.min(score, 1);
149
+ });
150
+ }
151
+ extractKeywords(text) {
152
+ const words = text.toLowerCase().split(/\s+/);
153
+ const wordFreq = new Map();
154
+ const stopWords = new Set([
155
+ 'the', 'is', 'at', 'which', 'on', 'a', 'an', 'as', 'are', 'was', 'were',
156
+ 'been', 'be', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would',
157
+ 'could', 'should', 'may', 'might', 'must', 'can', 'this', 'that', 'these',
158
+ 'those', 'i', 'you', 'he', 'she', 'it', 'we', 'they', 'what', 'which', 'who',
159
+ 'when', 'where', 'why', 'how', 'all', 'each', 'every', 'both', 'few', 'more',
160
+ 'most', 'other', 'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same',
161
+ 'so', 'than', 'too', 'very', 'just', 'but', 'for', 'with', 'about', 'into',
162
+ 'through', 'during', 'before', 'after', 'above', 'below', 'to', 'from', 'of', 'in'
163
+ ]);
164
+ for (const word of words) {
165
+ if (word.length > 3 && !stopWords.has(word)) {
166
+ wordFreq.set(word, (wordFreq.get(word) || 0) + 1);
167
+ }
168
+ }
169
+ return Array.from(wordFreq.entries())
170
+ .sort((a, b) => b[1] - a[1])
171
+ .slice(0, 10)
172
+ .map(([word]) => word);
173
+ }
174
+ estimateTokens(text) {
175
+ return Math.ceil(text.length / 4);
176
+ }
177
+ identifyPreservedSections(original, pruned) {
178
+ const prunedSentences = this.splitIntoSentences(pruned);
179
+ return prunedSentences.slice(0, 3).map(s => s.substring(0, 50) + '...');
180
+ }
181
+ getRecommendedStrategy(text, requirements) {
182
+ const length = text.length;
183
+ const hasCode = /```[\s\S]*?```/.test(text);
184
+ const hasNumbers = /\d+/.test(text);
185
+ if (hasCode) {
186
+ return 'keyword'; // Preserve code blocks
187
+ }
188
+ if (length > 10000) {
189
+ return 'hybrid'; // Use multiple strategies for long text
190
+ }
191
+ if (hasNumbers || requirements.preserveData) {
192
+ return 'embedding-similarity'; // Better at preserving important data
193
+ }
194
+ return 'length'; // Simple and fast for short text
195
+ }
196
+ }
@@ -0,0 +1,338 @@
1
+ /**
2
+ * Cost Monitor - Real-time tracking and limits for API usage
3
+ * Part of Phase 1C implementation for cost control
4
+ */
5
+ import { EventEmitter } from "events";
6
+ export class CostMonitor extends EventEmitter {
7
+ constructor() {
8
+ super();
9
+ // Cost limits
10
+ this.limits = {
11
+ hourly: 1.0, // $1 per hour
12
+ daily: 10.0, // $10 per day
13
+ monthly: 300.0, // $300 per month
14
+ };
15
+ // Warning thresholds (percentage of limit)
16
+ this.thresholds = {
17
+ warning: 0.75, // 75% of limit
18
+ critical: 0.9, // 90% of limit
19
+ };
20
+ // Usage tracking
21
+ this.usage = new Map();
22
+ this.records = [];
23
+ this.modelUsage = new Map();
24
+ // Model pricing (updated Nov 2025 - includes GPT-5)
25
+ this.modelCosts = new Map([
26
+ // GPT-5 Models (Official pricing as of Nov 2025)
27
+ [
28
+ "gpt-5-nano",
29
+ { model: "gpt-5-nano", inputCost: 0.00005, outputCost: 0.0004 },
30
+ ], // ULTRA CHEAP!
31
+ [
32
+ "gpt-5-mini",
33
+ { model: "gpt-5-mini", inputCost: 0.00025, outputCost: 0.002 },
34
+ ],
35
+ ["gpt-5", { model: "gpt-5", inputCost: 0.00125, outputCost: 0.01 }],
36
+ [
37
+ "gpt-5-chat-latest",
38
+ { model: "gpt-5-chat-latest", inputCost: 0.00125, outputCost: 0.01 },
39
+ ],
40
+ // Existing models
41
+ [
42
+ "gemini-2.5-flash",
43
+ { model: "gemini-2.5-flash", inputCost: 0.000075, outputCost: 0.0003 },
44
+ ],
45
+ ["gpt-5-nano", { model: "gpt-5-nano", inputCost: 0.00005, outputCost: 0.0004 }],
46
+ [
47
+ "gpt-5-mini",
48
+ { model: "gpt-5-mini", inputCost: 0.00025, outputCost: 0.002 },
49
+ ],
50
+ ["gpt-5", { model: "gpt-5", inputCost: 0.0025, outputCost: 0.01 }],
51
+ [
52
+ "perplexity-sonar-pro",
53
+ { model: "perplexity-sonar-pro", inputCost: 0.006, outputCost: 0.006 },
54
+ ],
55
+ [
56
+ "claude-3.5-sonnet",
57
+ { model: "claude-3.5-sonnet", inputCost: 0.003, outputCost: 0.015 },
58
+ ],
59
+ ["grok-4", { model: "grok-4", inputCost: 0.005, outputCost: 0.015 }],
60
+ ]);
61
+ // Clean up old records periodically
62
+ setInterval(() => this.cleanupOldRecords(), 60 * 60 * 1000); // Every hour
63
+ }
64
+ /**
65
+ * Set custom limits
66
+ */
67
+ setLimits(limits) {
68
+ this.limits = { ...this.limits, ...limits };
69
+ }
70
+ /**
71
+ * Calculate cost for a request
72
+ */
73
+ calculateCost(model, inputTokens, outputTokens) {
74
+ const normalizedModel = this.normalizeModelId(model);
75
+ const pricing = this.modelCosts.get(normalizedModel);
76
+ if (!pricing) {
77
+ console.warn(`Unknown model pricing for: ${model}, using default`);
78
+ return (inputTokens * 0.001 + outputTokens * 0.002) / 1000; // Default pricing
79
+ }
80
+ return ((inputTokens * pricing.inputCost + outputTokens * pricing.outputCost) /
81
+ 1000);
82
+ }
83
+ /**
84
+ * Track usage for a request
85
+ */
86
+ async trackUsage(model, inputTokens, outputTokens, requestId, userId) {
87
+ const normalizedModel = this.normalizeModelId(model);
88
+ const cost = this.calculateCost(model, inputTokens, outputTokens);
89
+ const now = Date.now();
90
+ // Check if request would exceed limits
91
+ const hourKey = this.getTimeKey("hour");
92
+ const dayKey = this.getTimeKey("day");
93
+ const monthKey = this.getTimeKey("month");
94
+ const hourlyUsage = (this.usage.get(`hour:${hourKey}`) || 0) + cost;
95
+ const dailyUsage = (this.usage.get(`day:${dayKey}`) || 0) + cost;
96
+ const monthlyUsage = (this.usage.get(`month:${monthKey}`) || 0) + cost;
97
+ // Check hard limits
98
+ if (hourlyUsage > this.limits.hourly) {
99
+ const alert = {
100
+ type: "limit_exceeded",
101
+ message: `Hourly limit exceeded. Current: $${hourlyUsage.toFixed(2)}, Limit: $${this.limits.hourly}`,
102
+ currentCost: hourlyUsage,
103
+ limit: this.limits.hourly,
104
+ timeframe: "hourly",
105
+ };
106
+ this.emit("limitExceeded", alert);
107
+ return { allowed: false, cost, alert };
108
+ }
109
+ if (dailyUsage > this.limits.daily) {
110
+ const alert = {
111
+ type: "limit_exceeded",
112
+ message: `Daily limit exceeded. Current: $${dailyUsage.toFixed(2)}, Limit: $${this.limits.daily}`,
113
+ currentCost: dailyUsage,
114
+ limit: this.limits.daily,
115
+ timeframe: "daily",
116
+ };
117
+ this.emit("limitExceeded", alert);
118
+ return { allowed: false, cost, alert };
119
+ }
120
+ // Record the usage
121
+ const record = {
122
+ timestamp: now,
123
+ model: normalizedModel,
124
+ inputTokens,
125
+ outputTokens,
126
+ cost,
127
+ requestId,
128
+ userId,
129
+ };
130
+ this.records.push(record);
131
+ this.usage.set(`hour:${hourKey}`, hourlyUsage);
132
+ this.usage.set(`day:${dayKey}`, dailyUsage);
133
+ this.usage.set(`month:${monthKey}`, monthlyUsage);
134
+ // Update model usage stats
135
+ const modelStats = this.modelUsage.get(normalizedModel) || {
136
+ count: 0,
137
+ cost: 0,
138
+ };
139
+ modelStats.count++;
140
+ modelStats.cost += cost;
141
+ this.modelUsage.set(normalizedModel, modelStats);
142
+ // Check warning thresholds
143
+ let alert;
144
+ if (hourlyUsage > this.limits.hourly * this.thresholds.critical) {
145
+ alert = {
146
+ type: "critical",
147
+ message: `Critical: Approaching hourly limit (${((hourlyUsage / this.limits.hourly) * 100).toFixed(0)}%)`,
148
+ currentCost: hourlyUsage,
149
+ limit: this.limits.hourly,
150
+ timeframe: "hourly",
151
+ };
152
+ this.emit("criticalAlert", alert);
153
+ }
154
+ else if (hourlyUsage > this.limits.hourly * this.thresholds.warning) {
155
+ alert = {
156
+ type: "warning",
157
+ message: `Warning: ${((hourlyUsage / this.limits.hourly) * 100).toFixed(0)}% of hourly limit used`,
158
+ currentCost: hourlyUsage,
159
+ limit: this.limits.hourly,
160
+ timeframe: "hourly",
161
+ };
162
+ this.emit("warningAlert", alert);
163
+ }
164
+ return { allowed: true, cost, alert };
165
+ }
166
+ /**
167
+ * Check if a request would be allowed
168
+ */
169
+ async checkRequest(model, estimatedTokens) {
170
+ // Estimate 40% input, 60% output
171
+ const inputTokens = estimatedTokens * 0.4;
172
+ const outputTokens = estimatedTokens * 0.6;
173
+ const estimatedCost = this.calculateCost(model, inputTokens, outputTokens);
174
+ const hourKey = this.getTimeKey("hour");
175
+ const dayKey = this.getTimeKey("day");
176
+ const hourlyUsage = this.usage.get(`hour:${hourKey}`) || 0;
177
+ const dailyUsage = this.usage.get(`day:${dayKey}`) || 0;
178
+ // Check if it would exceed limits
179
+ if (hourlyUsage + estimatedCost > this.limits.hourly) {
180
+ return {
181
+ allowed: false,
182
+ estimatedCost,
183
+ requiresConfirmation: true,
184
+ warning: `Would exceed hourly limit ($${this.limits.hourly})`,
185
+ };
186
+ }
187
+ if (dailyUsage + estimatedCost > this.limits.daily) {
188
+ return {
189
+ allowed: false,
190
+ estimatedCost,
191
+ requiresConfirmation: true,
192
+ warning: `Would exceed daily limit ($${this.limits.daily})`,
193
+ };
194
+ }
195
+ // Check if confirmation needed
196
+ const requiresConfirmation = estimatedCost > 0.1; // Confirm for requests > $0.10
197
+ return {
198
+ allowed: true,
199
+ estimatedCost,
200
+ requiresConfirmation,
201
+ warning: requiresConfirmation
202
+ ? `High cost request: $${estimatedCost.toFixed(2)}`
203
+ : undefined,
204
+ };
205
+ }
206
+ /**
207
+ * Get usage report
208
+ */
209
+ getUsageReport() {
210
+ const hourKey = this.getTimeKey("hour");
211
+ const dayKey = this.getTimeKey("day");
212
+ const monthKey = this.getTimeKey("month");
213
+ const hourlyUsage = this.usage.get(`hour:${hourKey}`) || 0;
214
+ const dailyUsage = this.usage.get(`day:${dayKey}`) || 0;
215
+ const monthlyUsage = this.usage.get(`month:${monthKey}`) || 0;
216
+ // Get top models by cost
217
+ const topModels = Array.from(this.modelUsage.entries())
218
+ .map(([model, stats]) => ({
219
+ model,
220
+ usage: stats.count,
221
+ cost: stats.cost,
222
+ }))
223
+ .sort((a, b) => b.cost - a.cost)
224
+ .slice(0, 5);
225
+ // Generate alerts
226
+ const alerts = [];
227
+ if (hourlyUsage > this.limits.hourly * this.thresholds.warning) {
228
+ alerts.push({
229
+ type: hourlyUsage > this.limits.hourly * this.thresholds.critical
230
+ ? "critical"
231
+ : "warning",
232
+ message: `${((hourlyUsage / this.limits.hourly) * 100).toFixed(0)}% of hourly limit used`,
233
+ currentCost: hourlyUsage,
234
+ limit: this.limits.hourly,
235
+ timeframe: "hourly",
236
+ });
237
+ }
238
+ if (dailyUsage > this.limits.daily * this.thresholds.warning) {
239
+ alerts.push({
240
+ type: dailyUsage > this.limits.daily * this.thresholds.critical
241
+ ? "critical"
242
+ : "warning",
243
+ message: `${((dailyUsage / this.limits.daily) * 100).toFixed(0)}% of daily limit used`,
244
+ currentCost: dailyUsage,
245
+ limit: this.limits.daily,
246
+ timeframe: "daily",
247
+ });
248
+ }
249
+ return {
250
+ hourly: {
251
+ used: hourlyUsage,
252
+ limit: this.limits.hourly,
253
+ remaining: Math.max(0, this.limits.hourly - hourlyUsage),
254
+ percentage: (hourlyUsage / this.limits.hourly) * 100,
255
+ },
256
+ daily: {
257
+ used: dailyUsage,
258
+ limit: this.limits.daily,
259
+ remaining: Math.max(0, this.limits.daily - dailyUsage),
260
+ percentage: (dailyUsage / this.limits.daily) * 100,
261
+ },
262
+ monthly: {
263
+ used: monthlyUsage,
264
+ limit: this.limits.monthly,
265
+ remaining: Math.max(0, this.limits.monthly - monthlyUsage),
266
+ percentage: (monthlyUsage / this.limits.monthly) * 100,
267
+ },
268
+ topModels,
269
+ alerts,
270
+ };
271
+ }
272
+ normalizeModelId(model) {
273
+ switch (model) {
274
+ case "gpt5":
275
+ return "gpt-5";
276
+ case "gpt5_mini":
277
+ return "gpt-5-mini";
278
+ case "gpt5_nano":
279
+ return "gpt-5-nano";
280
+ default:
281
+ return model;
282
+ }
283
+ }
284
+ /**
285
+ * Get time key for usage tracking
286
+ */
287
+ getTimeKey(period) {
288
+ const now = new Date();
289
+ switch (period) {
290
+ case "hour":
291
+ return now.toISOString().slice(0, 13); // YYYY-MM-DDTHH
292
+ case "day":
293
+ return now.toISOString().slice(0, 10); // YYYY-MM-DD
294
+ case "month":
295
+ return now.toISOString().slice(0, 7); // YYYY-MM
296
+ }
297
+ }
298
+ /**
299
+ * Clean up old records
300
+ */
301
+ cleanupOldRecords() {
302
+ const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;
303
+ // Remove records older than 24 hours
304
+ this.records = this.records.filter((r) => r.timestamp > oneDayAgo);
305
+ // Clean up old usage keys
306
+ const currentHour = this.getTimeKey("hour");
307
+ const currentDay = this.getTimeKey("day");
308
+ const currentMonth = this.getTimeKey("month");
309
+ for (const [key] of this.usage.entries()) {
310
+ if (key.startsWith("hour:") && !key.includes(currentHour.slice(0, 10))) {
311
+ this.usage.delete(key);
312
+ }
313
+ else if (key.startsWith("day:") && !key.includes(currentMonth)) {
314
+ this.usage.delete(key);
315
+ }
316
+ }
317
+ }
318
+ /**
319
+ * Reset all usage data
320
+ */
321
+ reset() {
322
+ this.usage.clear();
323
+ this.records = [];
324
+ this.modelUsage.clear();
325
+ }
326
+ /**
327
+ * Export usage data for analysis
328
+ */
329
+ exportUsageData() {
330
+ return {
331
+ records: this.records,
332
+ summary: this.getUsageReport(),
333
+ modelBreakdown: this.modelUsage,
334
+ };
335
+ }
336
+ }
337
+ // Export singleton instance
338
+ export const costMonitor = new CostMonitor();
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Optimization Module - Exports for Phase 1 improvements
3
+ * Provides smart model routing, token optimization, and cost monitoring
4
+ */
5
+ // Import singletons
6
+ import { modelRouter } from './model-router.js';
7
+ import { tokenOptimizer } from './token-optimizer.js';
8
+ import { costMonitor } from './cost-monitor.js';
9
+ // Re-export all types and classes
10
+ export { SmartModelRouter, modelRouter, ModelTier } from './model-router.js';
11
+ export { TokenOptimizer, tokenOptimizer } from './token-optimizer.js';
12
+ export { CostMonitor, costMonitor } from './cost-monitor.js';
13
+ /**
14
+ * Initialize all optimization modules
15
+ */
16
+ export function initializeOptimizations(config) {
17
+ // Set cost limits if provided
18
+ if (config?.costLimits) {
19
+ costMonitor.setLimits(config.costLimits);
20
+ }
21
+ // Listen for cost alerts
22
+ costMonitor.on('warningAlert', (alert) => {
23
+ console.warn(`⚠️ Cost Warning: ${alert.message}`);
24
+ });
25
+ costMonitor.on('criticalAlert', (alert) => {
26
+ console.error(`🚨 Cost Critical: ${alert.message}`);
27
+ });
28
+ costMonitor.on('limitExceeded', (alert) => {
29
+ console.error(`🛑 Cost Limit Exceeded: ${alert.message}`);
30
+ });
31
+ console.error('✅ Optimizations initialized:');
32
+ console.error(' • Smart model routing enabled');
33
+ console.error(' • Token optimization active');
34
+ console.error(' • Cost monitoring configured');
35
+ return {
36
+ modelRouter,
37
+ tokenOptimizer,
38
+ costMonitor,
39
+ };
40
+ }
41
+ /**
42
+ * Get optimization statistics
43
+ */
44
+ export function getOptimizationStats() {
45
+ const tokenMetrics = tokenOptimizer.getMetrics();
46
+ const costReport = costMonitor.getUsageReport();
47
+ return {
48
+ tokenOptimization: {
49
+ cacheHitRate: tokenMetrics.cacheHitRate,
50
+ compressionRatio: tokenMetrics.compressionRatio,
51
+ tokensSaved: tokenMetrics.totalSaved,
52
+ batchesProcessed: tokenMetrics.batchesProcessed,
53
+ },
54
+ costMonitoring: {
55
+ hourlyUsage: costReport.hourly.used,
56
+ dailyUsage: costReport.daily.used,
57
+ monthlyUsage: costReport.monthly.used,
58
+ topModels: costReport.topModels,
59
+ },
60
+ recommendations: [
61
+ ...tokenMetrics.recommendations,
62
+ ...costReport.alerts.map((a) => a.message),
63
+ ],
64
+ };
65
+ }