@yasserkhanorg/e2e-agents 0.3.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.
- package/LICENSE +168 -0
- package/README.md +620 -0
- package/dist/agent/analysis.d.ts +62 -0
- package/dist/agent/analysis.d.ts.map +1 -0
- package/dist/agent/analysis.js +292 -0
- package/dist/agent/blast_radius.d.ts +4 -0
- package/dist/agent/blast_radius.d.ts.map +1 -0
- package/dist/agent/blast_radius.js +37 -0
- package/dist/agent/cache_utils.d.ts +38 -0
- package/dist/agent/cache_utils.d.ts.map +1 -0
- package/dist/agent/cache_utils.js +67 -0
- package/dist/agent/config.d.ts +148 -0
- package/dist/agent/config.d.ts.map +1 -0
- package/dist/agent/config.js +640 -0
- package/dist/agent/dependency_graph.d.ts +14 -0
- package/dist/agent/dependency_graph.d.ts.map +1 -0
- package/dist/agent/dependency_graph.js +227 -0
- package/dist/agent/feedback.d.ts +55 -0
- package/dist/agent/feedback.d.ts.map +1 -0
- package/dist/agent/feedback.js +257 -0
- package/dist/agent/flags.d.ts +23 -0
- package/dist/agent/flags.d.ts.map +1 -0
- package/dist/agent/flags.js +171 -0
- package/dist/agent/flow_catalog.d.ts +25 -0
- package/dist/agent/flow_catalog.d.ts.map +1 -0
- package/dist/agent/flow_catalog.js +106 -0
- package/dist/agent/flow_mapping.d.ts +10 -0
- package/dist/agent/flow_mapping.d.ts.map +1 -0
- package/dist/agent/flow_mapping.js +84 -0
- package/dist/agent/framework.d.ts +13 -0
- package/dist/agent/framework.d.ts.map +1 -0
- package/dist/agent/framework.js +149 -0
- package/dist/agent/gap_suggestions.d.ts +14 -0
- package/dist/agent/gap_suggestions.d.ts.map +1 -0
- package/dist/agent/gap_suggestions.js +101 -0
- package/dist/agent/generator.d.ts +10 -0
- package/dist/agent/generator.d.ts.map +1 -0
- package/dist/agent/generator.js +115 -0
- package/dist/agent/git.d.ts +11 -0
- package/dist/agent/git.d.ts.map +1 -0
- package/dist/agent/git.js +90 -0
- package/dist/agent/handoff.d.ts +22 -0
- package/dist/agent/handoff.d.ts.map +1 -0
- package/dist/agent/handoff.js +180 -0
- package/dist/agent/impact-analyzer.d.ts +114 -0
- package/dist/agent/impact-analyzer.d.ts.map +1 -0
- package/dist/agent/impact-analyzer.js +557 -0
- package/dist/agent/index.d.ts +21 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +38 -0
- package/dist/agent/model-router.d.ts +57 -0
- package/dist/agent/model-router.d.ts.map +1 -0
- package/dist/agent/model-router.js +154 -0
- package/dist/agent/operational_insights.d.ts +41 -0
- package/dist/agent/operational_insights.d.ts.map +1 -0
- package/dist/agent/operational_insights.js +126 -0
- package/dist/agent/pipeline.d.ts +23 -0
- package/dist/agent/pipeline.d.ts.map +1 -0
- package/dist/agent/pipeline.js +609 -0
- package/dist/agent/plan.d.ts +91 -0
- package/dist/agent/plan.d.ts.map +1 -0
- package/dist/agent/plan.js +331 -0
- package/dist/agent/playwright_report.d.ts +8 -0
- package/dist/agent/playwright_report.d.ts.map +1 -0
- package/dist/agent/playwright_report.js +126 -0
- package/dist/agent/report-generator.d.ts +24 -0
- package/dist/agent/report-generator.d.ts.map +1 -0
- package/dist/agent/report-generator.js +250 -0
- package/dist/agent/report.d.ts +81 -0
- package/dist/agent/report.d.ts.map +1 -0
- package/dist/agent/report.js +147 -0
- package/dist/agent/runner.d.ts +7 -0
- package/dist/agent/runner.d.ts.map +1 -0
- package/dist/agent/runner.js +576 -0
- package/dist/agent/selectors.d.ts +10 -0
- package/dist/agent/selectors.d.ts.map +1 -0
- package/dist/agent/selectors.js +75 -0
- package/dist/agent/spec-bridge.d.ts +101 -0
- package/dist/agent/spec-bridge.d.ts.map +1 -0
- package/dist/agent/spec-bridge.js +273 -0
- package/dist/agent/spec-builder.d.ts +102 -0
- package/dist/agent/spec-builder.d.ts.map +1 -0
- package/dist/agent/spec-builder.js +273 -0
- package/dist/agent/subsystem_risk.d.ts +23 -0
- package/dist/agent/subsystem_risk.d.ts.map +1 -0
- package/dist/agent/subsystem_risk.js +207 -0
- package/dist/agent/telemetry.d.ts +84 -0
- package/dist/agent/telemetry.d.ts.map +1 -0
- package/dist/agent/telemetry.js +220 -0
- package/dist/agent/test_path.d.ts +2 -0
- package/dist/agent/test_path.d.ts.map +1 -0
- package/dist/agent/test_path.js +23 -0
- package/dist/agent/tests.d.ts +18 -0
- package/dist/agent/tests.d.ts.map +1 -0
- package/dist/agent/tests.js +106 -0
- package/dist/agent/traceability.d.ts +22 -0
- package/dist/agent/traceability.d.ts.map +1 -0
- package/dist/agent/traceability.js +183 -0
- package/dist/agent/traceability_capture.d.ts +18 -0
- package/dist/agent/traceability_capture.d.ts.map +1 -0
- package/dist/agent/traceability_capture.js +313 -0
- package/dist/agent/traceability_ingest.d.ts +21 -0
- package/dist/agent/traceability_ingest.d.ts.map +1 -0
- package/dist/agent/traceability_ingest.js +237 -0
- package/dist/agent/utils.d.ts +13 -0
- package/dist/agent/utils.d.ts.map +1 -0
- package/dist/agent/utils.js +152 -0
- package/dist/agent/validators/selector-validator.d.ts +74 -0
- package/dist/agent/validators/selector-validator.d.ts.map +1 -0
- package/dist/agent/validators/selector-validator.js +165 -0
- package/dist/anthropic_provider.d.ts +65 -0
- package/dist/anthropic_provider.d.ts.map +1 -0
- package/dist/anthropic_provider.js +332 -0
- package/dist/api.d.ts +48 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +113 -0
- package/dist/base_provider.d.ts +53 -0
- package/dist/base_provider.d.ts.map +1 -0
- package/dist/base_provider.js +81 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +843 -0
- package/dist/custom_provider.d.ts +20 -0
- package/dist/custom_provider.d.ts.map +1 -0
- package/dist/custom_provider.js +276 -0
- package/dist/e2e-test-gen/index.d.ts +51 -0
- package/dist/e2e-test-gen/index.d.ts.map +1 -0
- package/dist/e2e-test-gen/index.js +57 -0
- package/dist/e2e-test-gen/spec_parser.d.ts +142 -0
- package/dist/e2e-test-gen/spec_parser.d.ts.map +1 -0
- package/dist/e2e-test-gen/spec_parser.js +786 -0
- package/dist/e2e-test-gen/types.d.ts +185 -0
- package/dist/e2e-test-gen/types.d.ts.map +1 -0
- package/dist/e2e-test-gen/types.js +4 -0
- package/dist/esm/agent/analysis.js +287 -0
- package/dist/esm/agent/blast_radius.js +34 -0
- package/dist/esm/agent/cache_utils.js +63 -0
- package/dist/esm/agent/config.js +637 -0
- package/dist/esm/agent/dependency_graph.js +224 -0
- package/dist/esm/agent/feedback.js +253 -0
- package/dist/esm/agent/flags.js +160 -0
- package/dist/esm/agent/flow_catalog.js +103 -0
- package/dist/esm/agent/flow_mapping.js +81 -0
- package/dist/esm/agent/framework.js +145 -0
- package/dist/esm/agent/gap_suggestions.js +98 -0
- package/dist/esm/agent/generator.js +112 -0
- package/dist/esm/agent/git.js +87 -0
- package/dist/esm/agent/handoff.js +177 -0
- package/dist/esm/agent/impact-analyzer.js +548 -0
- package/dist/esm/agent/index.js +22 -0
- package/dist/esm/agent/model-router.js +150 -0
- package/dist/esm/agent/operational_insights.js +123 -0
- package/dist/esm/agent/pipeline.js +605 -0
- package/dist/esm/agent/plan.js +324 -0
- package/dist/esm/agent/playwright_report.js +123 -0
- package/dist/esm/agent/report-generator.js +247 -0
- package/dist/esm/agent/report.js +144 -0
- package/dist/esm/agent/runner.js +572 -0
- package/dist/esm/agent/selectors.js +71 -0
- package/dist/esm/agent/spec-bridge.js +267 -0
- package/dist/esm/agent/spec-builder.js +267 -0
- package/dist/esm/agent/subsystem_risk.js +204 -0
- package/dist/esm/agent/telemetry.js +216 -0
- package/dist/esm/agent/test_path.js +20 -0
- package/dist/esm/agent/tests.js +101 -0
- package/dist/esm/agent/traceability.js +180 -0
- package/dist/esm/agent/traceability_capture.js +310 -0
- package/dist/esm/agent/traceability_ingest.js +234 -0
- package/dist/esm/agent/utils.js +138 -0
- package/dist/esm/agent/validators/selector-validator.js +160 -0
- package/dist/esm/anthropic_provider.js +324 -0
- package/dist/esm/api.js +105 -0
- package/dist/esm/base_provider.js +77 -0
- package/dist/esm/cli.js +841 -0
- package/dist/esm/custom_provider.js +272 -0
- package/dist/esm/e2e-test-gen/index.js +50 -0
- package/dist/esm/e2e-test-gen/spec_parser.js +782 -0
- package/dist/esm/e2e-test-gen/types.js +3 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/logger.js +89 -0
- package/dist/esm/mcp-server.js +465 -0
- package/dist/esm/ollama_provider.js +300 -0
- package/dist/esm/openai_provider.js +242 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/plan-and-test-constants.js +126 -0
- package/dist/esm/provider_factory.js +336 -0
- package/dist/esm/provider_interface.js +23 -0
- package/dist/esm/provider_utils.js +96 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/logger.d.ts +23 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +93 -0
- package/dist/mcp-server.d.ts +35 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +469 -0
- package/dist/ollama_provider.d.ts +65 -0
- package/dist/ollama_provider.d.ts.map +1 -0
- package/dist/ollama_provider.js +308 -0
- package/dist/openai_provider.d.ts +23 -0
- package/dist/openai_provider.d.ts.map +1 -0
- package/dist/openai_provider.js +250 -0
- package/dist/plan-and-test-constants.d.ts +110 -0
- package/dist/plan-and-test-constants.d.ts.map +1 -0
- package/dist/plan-and-test-constants.js +132 -0
- package/dist/provider_factory.d.ts +99 -0
- package/dist/provider_factory.d.ts.map +1 -0
- package/dist/provider_factory.js +341 -0
- package/dist/provider_interface.d.ts +358 -0
- package/dist/provider_interface.d.ts.map +1 -0
- package/dist/provider_interface.js +28 -0
- package/dist/provider_utils.d.ts +39 -0
- package/dist/provider_utils.d.ts.map +1 -0
- package/dist/provider_utils.js +103 -0
- package/package.json +101 -0
- package/schemas/gap.schema.json +18 -0
- package/schemas/impact.schema.json +418 -0
- package/schemas/plan.schema.json +285 -0
- package/schemas/subsystem-risk-map.schema.json +62 -0
- package/schemas/traceability-input.schema.json +122 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
import { AnthropicProvider } from './anthropic_provider.js';
|
|
4
|
+
import { CustomProvider } from './custom_provider.js';
|
|
5
|
+
import { OllamaProvider } from './ollama_provider.js';
|
|
6
|
+
import { OpenAIProvider } from './openai_provider.js';
|
|
7
|
+
import { UnsupportedCapabilityError } from './provider_interface.js';
|
|
8
|
+
/**
|
|
9
|
+
* LLM Provider Factory
|
|
10
|
+
*
|
|
11
|
+
* Creates and configures LLM providers based on configuration.
|
|
12
|
+
* Supports multiple strategies:
|
|
13
|
+
* - Single provider (Ollama, Anthropic, etc.)
|
|
14
|
+
* - Hybrid provider (free primary + premium fallback)
|
|
15
|
+
* - Auto-selection based on environment
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
*
|
|
19
|
+
* // Create single provider
|
|
20
|
+
* const provider = LLMProviderFactory.create({
|
|
21
|
+
* type: 'ollama',
|
|
22
|
+
* config: { model: 'deepseek-r1:7b' }
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Create hybrid provider
|
|
26
|
+
* const provider = LLMProviderFactory.createHybrid({
|
|
27
|
+
* primary: { type: 'ollama', config: { model: 'deepseek-r1:7b' } },
|
|
28
|
+
* fallback: { type: 'anthropic', config: { apiKey: '...' } },
|
|
29
|
+
* useFallbackFor: ['vision']
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Auto-detect from environment
|
|
33
|
+
* const provider = LLMProviderFactory.createFromEnv();
|
|
34
|
+
*/
|
|
35
|
+
export class LLMProviderFactory {
|
|
36
|
+
/**
|
|
37
|
+
* Create a single LLM provider
|
|
38
|
+
*/
|
|
39
|
+
static create(config) {
|
|
40
|
+
switch (config.type) {
|
|
41
|
+
case 'ollama':
|
|
42
|
+
return new OllamaProvider(config.config);
|
|
43
|
+
case 'anthropic':
|
|
44
|
+
return new AnthropicProvider(config.config);
|
|
45
|
+
case 'openai':
|
|
46
|
+
return new OpenAIProvider(config.config);
|
|
47
|
+
case 'custom':
|
|
48
|
+
return new CustomProvider(config.config);
|
|
49
|
+
default:
|
|
50
|
+
throw new Error(`Unknown provider type: ${config.type}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create a hybrid provider (free primary + premium fallback)
|
|
55
|
+
*
|
|
56
|
+
* Use cases:
|
|
57
|
+
* - Most operations use free Ollama
|
|
58
|
+
* - Vision tasks fall back to Claude
|
|
59
|
+
* - Complex diagnosis falls back to Claude
|
|
60
|
+
*
|
|
61
|
+
* This gives best cost/quality balance:
|
|
62
|
+
* - ~$20/month instead of $80/month (75% cost reduction)
|
|
63
|
+
* - Still get premium quality for vision and complex tasks
|
|
64
|
+
*/
|
|
65
|
+
static createHybrid(config) {
|
|
66
|
+
const primary = this.create(config.primary);
|
|
67
|
+
const fallback = this.create(config.fallback);
|
|
68
|
+
return new HybridProvider({
|
|
69
|
+
primary,
|
|
70
|
+
fallback,
|
|
71
|
+
useFallbackFor: config.useFallbackFor || ['vision'],
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Auto-detect provider from environment variables
|
|
76
|
+
*
|
|
77
|
+
* Priority:
|
|
78
|
+
* 1. LLM_PROVIDER env var (ollama, anthropic, openai)
|
|
79
|
+
* 2. ANTHROPIC_API_KEY exists → Anthropic
|
|
80
|
+
* 3. OPENAI_API_KEY exists → OpenAI
|
|
81
|
+
* 4. Ollama running locally → Ollama
|
|
82
|
+
* 5. Error (no provider available)
|
|
83
|
+
*/
|
|
84
|
+
static async createFromEnv() {
|
|
85
|
+
const providerType = process.env.LLM_PROVIDER?.toLowerCase();
|
|
86
|
+
if (providerType === 'ollama') {
|
|
87
|
+
return new OllamaProvider({
|
|
88
|
+
baseUrl: process.env.OLLAMA_BASE_URL || 'http://localhost:11434/v1',
|
|
89
|
+
model: process.env.OLLAMA_MODEL || 'deepseek-r1:7b',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (providerType === 'openai') {
|
|
93
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
94
|
+
throw new Error('OPENAI_API_KEY environment variable is required for OpenAI provider');
|
|
95
|
+
}
|
|
96
|
+
return new OpenAIProvider({
|
|
97
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
98
|
+
model: process.env.OPENAI_MODEL || 'gpt-4',
|
|
99
|
+
baseUrl: process.env.OPENAI_BASE_URL,
|
|
100
|
+
organizationId: process.env.OPENAI_ORG_ID,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (providerType === 'anthropic') {
|
|
104
|
+
if (!process.env.ANTHROPIC_API_KEY) {
|
|
105
|
+
throw new Error('ANTHROPIC_API_KEY environment variable is required for Anthropic provider');
|
|
106
|
+
}
|
|
107
|
+
return new AnthropicProvider({
|
|
108
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
109
|
+
model: process.env.ANTHROPIC_MODEL || 'claude-sonnet-4-5-20250929',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
113
|
+
return new AnthropicProvider({
|
|
114
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
115
|
+
model: process.env.ANTHROPIC_MODEL || 'claude-sonnet-4-5-20250929',
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (process.env.OPENAI_API_KEY) {
|
|
119
|
+
return new OpenAIProvider({
|
|
120
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
121
|
+
model: process.env.OPENAI_MODEL || 'gpt-4',
|
|
122
|
+
baseUrl: process.env.OPENAI_BASE_URL,
|
|
123
|
+
organizationId: process.env.OPENAI_ORG_ID,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Try Ollama as default
|
|
127
|
+
const ollama = new OllamaProvider({});
|
|
128
|
+
const health = await ollama.checkHealth();
|
|
129
|
+
if (health.healthy) {
|
|
130
|
+
// eslint-disable-next-line no-console
|
|
131
|
+
console.log('Auto-detected Ollama provider (free, local)');
|
|
132
|
+
return ollama;
|
|
133
|
+
}
|
|
134
|
+
throw new Error('No LLM provider available. Please either:\n' +
|
|
135
|
+
'1. Install Ollama: curl -fsSL https://ollama.com/install.sh | sh\n' +
|
|
136
|
+
'2. Set ANTHROPIC_API_KEY environment variable\n' +
|
|
137
|
+
'3. Set OPENAI_API_KEY environment variable\n' +
|
|
138
|
+
'4. Set LLM_PROVIDER environment variable');
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Create provider from simple string format
|
|
142
|
+
*
|
|
143
|
+
* Examples:
|
|
144
|
+
* - "ollama" → Ollama with defaults
|
|
145
|
+
* - "ollama:deepseek-r1:14b" → Ollama with specific model
|
|
146
|
+
* - "anthropic" → Anthropic with env API key
|
|
147
|
+
* - "anthropic:claude-opus-4-5" → Anthropic with specific model
|
|
148
|
+
* - "openai" → OpenAI with env API key
|
|
149
|
+
* - "openai:gpt-4" → OpenAI with specific model
|
|
150
|
+
*/
|
|
151
|
+
static createFromString(providerString) {
|
|
152
|
+
const [type, ...modelParts] = providerString.split(':');
|
|
153
|
+
const model = modelParts.join(':');
|
|
154
|
+
switch (type.toLowerCase()) {
|
|
155
|
+
case 'ollama':
|
|
156
|
+
return new OllamaProvider({
|
|
157
|
+
model: model || 'deepseek-r1:7b',
|
|
158
|
+
});
|
|
159
|
+
case 'anthropic':
|
|
160
|
+
if (!process.env.ANTHROPIC_API_KEY) {
|
|
161
|
+
throw new Error('ANTHROPIC_API_KEY environment variable is required');
|
|
162
|
+
}
|
|
163
|
+
return new AnthropicProvider({
|
|
164
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
165
|
+
model: model || 'claude-sonnet-4-5-20250929',
|
|
166
|
+
});
|
|
167
|
+
case 'openai':
|
|
168
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
169
|
+
throw new Error('OPENAI_API_KEY environment variable is required');
|
|
170
|
+
}
|
|
171
|
+
return new OpenAIProvider({
|
|
172
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
173
|
+
model: model || 'gpt-4',
|
|
174
|
+
baseUrl: process.env.OPENAI_BASE_URL,
|
|
175
|
+
organizationId: process.env.OPENAI_ORG_ID,
|
|
176
|
+
});
|
|
177
|
+
default:
|
|
178
|
+
throw new Error(`Unknown provider type: ${type}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Hybrid Provider - Mix free and premium providers
|
|
184
|
+
*
|
|
185
|
+
* Strategy:
|
|
186
|
+
* - Use free provider (Ollama) for most operations (~80% of requests)
|
|
187
|
+
* - Fall back to premium (Claude) only when needed (~20% of requests)
|
|
188
|
+
*
|
|
189
|
+
* Cost savings example:
|
|
190
|
+
* - Pure Claude: $80/month
|
|
191
|
+
* - Pure Ollama: $0/month but no vision
|
|
192
|
+
* - Hybrid: $20/month (75% cost reduction, keeps vision)
|
|
193
|
+
*/
|
|
194
|
+
class HybridProvider {
|
|
195
|
+
constructor(config) {
|
|
196
|
+
this.name = 'hybrid';
|
|
197
|
+
this.capabilities = {
|
|
198
|
+
// Report combined capabilities
|
|
199
|
+
vision: true, // Fallback provides vision
|
|
200
|
+
streaming: true, // Both support streaming
|
|
201
|
+
maxTokens: 0, // Will be set in constructor
|
|
202
|
+
costPer1MInputTokens: 0, // Variable cost
|
|
203
|
+
costPer1MOutputTokens: 0, // Variable cost
|
|
204
|
+
supportsTools: true,
|
|
205
|
+
supportsPromptCaching: false,
|
|
206
|
+
typicalResponseTimeMs: 0, // Variable
|
|
207
|
+
};
|
|
208
|
+
this.primary = config.primary;
|
|
209
|
+
this.fallback = config.fallback;
|
|
210
|
+
this.useFallbackFor = new Set(config.useFallbackFor);
|
|
211
|
+
// Set combined capabilities
|
|
212
|
+
this.capabilities.maxTokens = Math.max(this.primary.capabilities.maxTokens, this.fallback.capabilities.maxTokens);
|
|
213
|
+
this.capabilities.typicalResponseTimeMs = this.primary.capabilities.typicalResponseTimeMs;
|
|
214
|
+
}
|
|
215
|
+
async generateText(prompt, options) {
|
|
216
|
+
// Use primary for text generation (free)
|
|
217
|
+
// eslint-disable-next-line no-console
|
|
218
|
+
console.log(`[Hybrid] Using ${this.primary.name} for text generation`);
|
|
219
|
+
return await this.primary.generateText(prompt, options);
|
|
220
|
+
}
|
|
221
|
+
async analyzeImage(images, prompt, options) {
|
|
222
|
+
// Check if vision is a fallback trigger
|
|
223
|
+
if (this.useFallbackFor.has('vision')) {
|
|
224
|
+
// Use fallback if primary doesn't support vision
|
|
225
|
+
if (!this.primary.capabilities.vision) {
|
|
226
|
+
// eslint-disable-next-line no-console
|
|
227
|
+
console.log(`[Hybrid] Using ${this.fallback.name} for vision analysis (primary doesn't support vision)`);
|
|
228
|
+
if (!this.fallback.analyzeImage) {
|
|
229
|
+
throw new UnsupportedCapabilityError(this.name, 'vision');
|
|
230
|
+
}
|
|
231
|
+
return await this.fallback.analyzeImage(images, prompt, options);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// Try primary first
|
|
235
|
+
if (this.primary.analyzeImage) {
|
|
236
|
+
// eslint-disable-next-line no-console
|
|
237
|
+
console.log(`[Hybrid] Using ${this.primary.name} for vision analysis`);
|
|
238
|
+
return await this.primary.analyzeImage(images, prompt, options);
|
|
239
|
+
}
|
|
240
|
+
throw new UnsupportedCapabilityError(this.name, 'vision');
|
|
241
|
+
}
|
|
242
|
+
async *streamText(prompt, options) {
|
|
243
|
+
// Use primary for streaming (free)
|
|
244
|
+
if (!this.primary.streamText) {
|
|
245
|
+
throw new UnsupportedCapabilityError(this.primary.name, 'streaming');
|
|
246
|
+
}
|
|
247
|
+
// eslint-disable-next-line no-console
|
|
248
|
+
console.log(`[Hybrid] Using ${this.primary.name} for streaming`);
|
|
249
|
+
yield* this.primary.streamText(prompt, options);
|
|
250
|
+
}
|
|
251
|
+
getUsageStats() {
|
|
252
|
+
const primaryStats = this.primary.getUsageStats();
|
|
253
|
+
const fallbackStats = this.fallback.getUsageStats();
|
|
254
|
+
// Combine stats
|
|
255
|
+
return {
|
|
256
|
+
requestCount: primaryStats.requestCount + fallbackStats.requestCount,
|
|
257
|
+
totalInputTokens: primaryStats.totalInputTokens + fallbackStats.totalInputTokens,
|
|
258
|
+
totalOutputTokens: primaryStats.totalOutputTokens + fallbackStats.totalOutputTokens,
|
|
259
|
+
totalTokens: primaryStats.totalTokens + fallbackStats.totalTokens,
|
|
260
|
+
totalCost: primaryStats.totalCost + fallbackStats.totalCost,
|
|
261
|
+
averageResponseTimeMs: (primaryStats.averageResponseTimeMs * primaryStats.requestCount +
|
|
262
|
+
fallbackStats.averageResponseTimeMs * fallbackStats.requestCount) /
|
|
263
|
+
(primaryStats.requestCount + fallbackStats.requestCount),
|
|
264
|
+
failedRequests: primaryStats.failedRequests + fallbackStats.failedRequests,
|
|
265
|
+
startTime: new Date(Math.min(primaryStats.startTime.getTime(), fallbackStats.startTime.getTime())),
|
|
266
|
+
lastUpdated: new Date(Math.max(primaryStats.lastUpdated.getTime(), fallbackStats.lastUpdated.getTime())),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
resetUsageStats() {
|
|
270
|
+
this.primary.resetUsageStats();
|
|
271
|
+
this.fallback.resetUsageStats();
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Get breakdown of which provider was used for what
|
|
275
|
+
*/
|
|
276
|
+
getProviderBreakdown() {
|
|
277
|
+
const primaryStats = this.primary.getUsageStats();
|
|
278
|
+
const fallbackStats = this.fallback.getUsageStats();
|
|
279
|
+
// Calculate what it would cost if we used only fallback
|
|
280
|
+
const totalRequests = primaryStats.requestCount + fallbackStats.requestCount;
|
|
281
|
+
const fallbackCostPerRequest = fallbackStats.requestCount > 0 ? fallbackStats.totalCost / fallbackStats.requestCount : 0;
|
|
282
|
+
const hypotheticalFullCost = totalRequests * fallbackCostPerRequest;
|
|
283
|
+
const actualCost = primaryStats.totalCost + fallbackStats.totalCost;
|
|
284
|
+
const savings = hypotheticalFullCost - actualCost;
|
|
285
|
+
const savingsPercent = hypotheticalFullCost > 0 ? (savings / hypotheticalFullCost) * 100 : 0;
|
|
286
|
+
return {
|
|
287
|
+
primary: {
|
|
288
|
+
name: this.primary.name,
|
|
289
|
+
stats: primaryStats,
|
|
290
|
+
},
|
|
291
|
+
fallback: {
|
|
292
|
+
name: this.fallback.name,
|
|
293
|
+
stats: fallbackStats,
|
|
294
|
+
},
|
|
295
|
+
costSavings: `$${savings.toFixed(2)} saved (${savingsPercent.toFixed(1)}% reduction)`,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Helper to validate provider setup
|
|
301
|
+
*/
|
|
302
|
+
export async function validateProviderSetup(provider) {
|
|
303
|
+
const capabilities = [];
|
|
304
|
+
if (provider.capabilities.vision) {
|
|
305
|
+
capabilities.push('✓ Vision support (screenshot comparison)');
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
capabilities.push('✗ No vision support');
|
|
309
|
+
}
|
|
310
|
+
if (provider.capabilities.streaming) {
|
|
311
|
+
capabilities.push('✓ Streaming responses');
|
|
312
|
+
}
|
|
313
|
+
if (provider.capabilities.supportsTools) {
|
|
314
|
+
capabilities.push('✓ Function calling');
|
|
315
|
+
}
|
|
316
|
+
capabilities.push(`✓ ${provider.capabilities.maxTokens.toLocaleString()} token context window`);
|
|
317
|
+
capabilities.push(`✓ Cost: $${provider.capabilities.costPer1MOutputTokens}/1M tokens`);
|
|
318
|
+
try {
|
|
319
|
+
// Try a simple request
|
|
320
|
+
const response = await provider.generateText('Say "OK" if you can read this', {
|
|
321
|
+
maxTokens: 10,
|
|
322
|
+
});
|
|
323
|
+
return {
|
|
324
|
+
valid: response.text.length > 0,
|
|
325
|
+
message: `Provider '${provider.name}' is working correctly`,
|
|
326
|
+
capabilities,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
return {
|
|
331
|
+
valid: false,
|
|
332
|
+
message: `Provider '${provider.name}' validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
333
|
+
capabilities,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
/**
|
|
4
|
+
* Error thrown by LLM providers
|
|
5
|
+
*/
|
|
6
|
+
export class LLMProviderError extends Error {
|
|
7
|
+
constructor(message, provider, statusCode, cause) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.provider = provider;
|
|
10
|
+
this.statusCode = statusCode;
|
|
11
|
+
this.cause = cause;
|
|
12
|
+
this.name = 'LLMProviderError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Error thrown when a required capability is not supported
|
|
17
|
+
*/
|
|
18
|
+
export class UnsupportedCapabilityError extends LLMProviderError {
|
|
19
|
+
constructor(provider, capability) {
|
|
20
|
+
super(`Provider '${provider}' does not support capability: ${capability}`, provider);
|
|
21
|
+
this.name = 'UnsupportedCapabilityError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
2
|
+
// See LICENSE.txt for license information.
|
|
3
|
+
/**
|
|
4
|
+
* SECURITY: Shared utility functions for all LLM providers
|
|
5
|
+
* Eliminates code duplication and ensures consistent error handling
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Pre-compiled regex patterns for API key validation
|
|
9
|
+
* Compiled once and reused to avoid repeated regex compilation
|
|
10
|
+
*/
|
|
11
|
+
export const API_KEY_PATTERNS = {
|
|
12
|
+
anthropic: /^sk-ant-[a-zA-Z0-9_\-]{20,}$/,
|
|
13
|
+
openai: /^sk-[a-zA-Z0-9_\-]{20,}$/,
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* SECURITY: Sanitize error messages to prevent information leakage
|
|
17
|
+
* Maps specific API errors to safe, user-friendly messages
|
|
18
|
+
* Prevents leaking stack traces, API keys, or internal details
|
|
19
|
+
*/
|
|
20
|
+
export function sanitizeErrorMessage(error, context) {
|
|
21
|
+
if (error instanceof Error) {
|
|
22
|
+
const msg = error.message.toLowerCase();
|
|
23
|
+
// Map specific API errors to safe messages
|
|
24
|
+
if (msg.includes('401') || msg.includes('authentication')) {
|
|
25
|
+
return `Authentication failed (${context})`;
|
|
26
|
+
}
|
|
27
|
+
if (msg.includes('429') || msg.includes('rate')) {
|
|
28
|
+
return `Rate limit exceeded (${context})`;
|
|
29
|
+
}
|
|
30
|
+
if (msg.includes('timeout') || msg.includes('etimedout')) {
|
|
31
|
+
return `Request timeout (${context})`;
|
|
32
|
+
}
|
|
33
|
+
if (msg.includes('network') || msg.includes('econnrefused')) {
|
|
34
|
+
return `Connection failed (${context})`;
|
|
35
|
+
}
|
|
36
|
+
if (msg.includes('enotfound') || msg.includes('getaddrinfo')) {
|
|
37
|
+
return `Host not found (${context})`;
|
|
38
|
+
}
|
|
39
|
+
// Don't leak stack traces, API keys, or internal details
|
|
40
|
+
return `Operation failed (${context})`;
|
|
41
|
+
}
|
|
42
|
+
return 'An unexpected error occurred';
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Generic timeout wrapper for promises
|
|
46
|
+
* Rejects with timeout error if promise doesn't resolve in time
|
|
47
|
+
*/
|
|
48
|
+
export function withTimeout(promise, timeoutMs, context) {
|
|
49
|
+
if (!timeoutMs) {
|
|
50
|
+
return promise;
|
|
51
|
+
}
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
const timer = setTimeout(() => reject(new Error(`Request timeout (${context})`)), timeoutMs);
|
|
54
|
+
promise.then((value) => {
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
resolve(value);
|
|
57
|
+
}, (error) => {
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
reject(error);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if a hostname is localhost
|
|
65
|
+
* Used by URL validation to allow HTTP for local development
|
|
66
|
+
*/
|
|
67
|
+
export function isLocalhost(hostname) {
|
|
68
|
+
if (!hostname) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1';
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* SECURITY: Validate and enforce HTTPS for remote URLs
|
|
75
|
+
* Allows HTTP only for localhost development
|
|
76
|
+
* Returns validation result with optional warning message
|
|
77
|
+
*/
|
|
78
|
+
export function validateAndSanitizeUrl(baseUrl) {
|
|
79
|
+
if (!baseUrl) {
|
|
80
|
+
return { valid: true };
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const url = new URL(baseUrl);
|
|
84
|
+
// For non-localhost URLs, require HTTPS
|
|
85
|
+
if (!isLocalhost(url.hostname) && url.protocol !== 'https:') {
|
|
86
|
+
return {
|
|
87
|
+
valid: false,
|
|
88
|
+
warning: `HTTPS required for remote URLs. Got: ${url.protocol}//${url.hostname}`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return { valid: true, url: baseUrl };
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return { valid: false };
|
|
95
|
+
}
|
|
96
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Provider Module
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic library for working with Language Learning Models.
|
|
5
|
+
* Pluggable architecture supports multiple providers:
|
|
6
|
+
* - Anthropic Claude (premium, vision support)
|
|
7
|
+
* - Ollama (free, local)
|
|
8
|
+
* - OpenAI (official API)
|
|
9
|
+
* - Custom providers
|
|
10
|
+
*
|
|
11
|
+
* Switch between providers seamlessly without changing application code.
|
|
12
|
+
*/
|
|
13
|
+
export type { LLMProvider, GenerateOptions, ImageInput, LLMResponse, TokenUsage, ProviderCapabilities, ProviderUsageStats, ProviderConfig, AnthropicConfig, OllamaConfig, OpenAIConfig, CustomConfig, } from './provider_interface.js';
|
|
14
|
+
export { LLMProviderError, UnsupportedCapabilityError } from './provider_interface.js';
|
|
15
|
+
export { AnthropicProvider, checkAnthropicSetup } from './anthropic_provider.js';
|
|
16
|
+
export { OllamaProvider, checkOllamaSetup } from './ollama_provider.js';
|
|
17
|
+
export { OpenAIProvider, checkOpenAISetup } from './openai_provider.js';
|
|
18
|
+
export { CustomProvider } from './custom_provider.js';
|
|
19
|
+
export { LLMProviderFactory, validateProviderSetup } from './provider_factory.js';
|
|
20
|
+
export type { HybridConfig } from './provider_factory.js';
|
|
21
|
+
export { analyzeImpact, findGaps, recommendTests, handoffGeneratedTests, ingestTraceability, captureTraceability } from './api.js';
|
|
22
|
+
export type { AgentApiOptions, AnalyzeResult, RecommendTestsResult, TraceabilityIngestApiOptions, TraceabilityCaptureApiOptions, } from './api.js';
|
|
23
|
+
export { appendFeedbackAndRecompute, readCalibration } from './agent/feedback.js';
|
|
24
|
+
export type { RecommendationFeedbackEntry, CalibrationSummary } from './agent/feedback.js';
|
|
25
|
+
export { finalizeGeneratedTests } from './agent/handoff.js';
|
|
26
|
+
export type { FinalizeGeneratedTestsOptions, FinalizeGeneratedTestsResult } from './agent/handoff.js';
|
|
27
|
+
export { ingestTraceabilityInput } from './agent/traceability_ingest.js';
|
|
28
|
+
export type { TraceabilityIngestOptions, TraceabilityIngestResult, TraceabilityIngestEntry } from './agent/traceability_ingest.js';
|
|
29
|
+
export { captureTraceabilityInput } from './agent/traceability_capture.js';
|
|
30
|
+
export type { TraceabilityCaptureOptions, TraceabilityCaptureResult } from './agent/traceability_capture.js';
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAGH,YAAY,EACR,WAAW,EACX,eAAe,EACf,UAAU,EACV,WAAW,EACX,UAAU,EACV,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,YAAY,GACf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAC,gBAAgB,EAAE,0BAA0B,EAAC,MAAM,yBAAyB,CAAC;AAGrF,OAAO,EAAC,iBAAiB,EAAE,mBAAmB,EAAC,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EAAC,cAAc,EAAE,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAC,cAAc,EAAE,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EAAC,kBAAkB,EAAE,qBAAqB,EAAC,MAAM,uBAAuB,CAAC;AAChF,YAAY,EAAC,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAC,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,mBAAmB,EAAC,MAAM,UAAU,CAAC;AACjI,YAAY,EACR,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,4BAA4B,EAC5B,6BAA6B,GAChC,MAAM,UAAU,CAAC;AAClB,OAAO,EAAC,0BAA0B,EAAE,eAAe,EAAC,MAAM,qBAAqB,CAAC;AAChF,YAAY,EAAC,2BAA2B,EAAE,kBAAkB,EAAC,MAAM,qBAAqB,CAAC;AACzF,OAAO,EAAC,sBAAsB,EAAC,MAAM,oBAAoB,CAAC;AAC1D,YAAY,EAAC,6BAA6B,EAAE,4BAA4B,EAAC,MAAM,oBAAoB,CAAC;AACpG,OAAO,EAAC,uBAAuB,EAAC,MAAM,gCAAgC,CAAC;AACvE,YAAY,EAAC,yBAAyB,EAAE,wBAAwB,EAAE,uBAAuB,EAAC,MAAM,gCAAgC,CAAC;AACjI,OAAO,EAAC,wBAAwB,EAAC,MAAM,iCAAiC,CAAC;AACzE,YAAY,EAAC,0BAA0B,EAAE,yBAAyB,EAAC,MAAM,iCAAiC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
|
+
// See LICENSE.txt for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.captureTraceabilityInput = exports.ingestTraceabilityInput = exports.finalizeGeneratedTests = exports.readCalibration = exports.appendFeedbackAndRecompute = exports.captureTraceability = exports.ingestTraceability = exports.handoffGeneratedTests = exports.recommendTests = exports.findGaps = exports.analyzeImpact = exports.validateProviderSetup = exports.LLMProviderFactory = exports.CustomProvider = exports.checkOpenAISetup = exports.OpenAIProvider = exports.checkOllamaSetup = exports.OllamaProvider = exports.checkAnthropicSetup = exports.AnthropicProvider = exports.UnsupportedCapabilityError = exports.LLMProviderError = void 0;
|
|
6
|
+
var provider_interface_js_1 = require("./provider_interface.js");
|
|
7
|
+
Object.defineProperty(exports, "LLMProviderError", { enumerable: true, get: function () { return provider_interface_js_1.LLMProviderError; } });
|
|
8
|
+
Object.defineProperty(exports, "UnsupportedCapabilityError", { enumerable: true, get: function () { return provider_interface_js_1.UnsupportedCapabilityError; } });
|
|
9
|
+
// Provider implementations
|
|
10
|
+
var anthropic_provider_js_1 = require("./anthropic_provider.js");
|
|
11
|
+
Object.defineProperty(exports, "AnthropicProvider", { enumerable: true, get: function () { return anthropic_provider_js_1.AnthropicProvider; } });
|
|
12
|
+
Object.defineProperty(exports, "checkAnthropicSetup", { enumerable: true, get: function () { return anthropic_provider_js_1.checkAnthropicSetup; } });
|
|
13
|
+
var ollama_provider_js_1 = require("./ollama_provider.js");
|
|
14
|
+
Object.defineProperty(exports, "OllamaProvider", { enumerable: true, get: function () { return ollama_provider_js_1.OllamaProvider; } });
|
|
15
|
+
Object.defineProperty(exports, "checkOllamaSetup", { enumerable: true, get: function () { return ollama_provider_js_1.checkOllamaSetup; } });
|
|
16
|
+
var openai_provider_js_1 = require("./openai_provider.js");
|
|
17
|
+
Object.defineProperty(exports, "OpenAIProvider", { enumerable: true, get: function () { return openai_provider_js_1.OpenAIProvider; } });
|
|
18
|
+
Object.defineProperty(exports, "checkOpenAISetup", { enumerable: true, get: function () { return openai_provider_js_1.checkOpenAISetup; } });
|
|
19
|
+
var custom_provider_js_1 = require("./custom_provider.js");
|
|
20
|
+
Object.defineProperty(exports, "CustomProvider", { enumerable: true, get: function () { return custom_provider_js_1.CustomProvider; } });
|
|
21
|
+
// Factory
|
|
22
|
+
var provider_factory_js_1 = require("./provider_factory.js");
|
|
23
|
+
Object.defineProperty(exports, "LLMProviderFactory", { enumerable: true, get: function () { return provider_factory_js_1.LLMProviderFactory; } });
|
|
24
|
+
Object.defineProperty(exports, "validateProviderSetup", { enumerable: true, get: function () { return provider_factory_js_1.validateProviderSetup; } });
|
|
25
|
+
// Agent API (impact, gap, suggest, traceability ingest)
|
|
26
|
+
var api_js_1 = require("./api.js");
|
|
27
|
+
Object.defineProperty(exports, "analyzeImpact", { enumerable: true, get: function () { return api_js_1.analyzeImpact; } });
|
|
28
|
+
Object.defineProperty(exports, "findGaps", { enumerable: true, get: function () { return api_js_1.findGaps; } });
|
|
29
|
+
Object.defineProperty(exports, "recommendTests", { enumerable: true, get: function () { return api_js_1.recommendTests; } });
|
|
30
|
+
Object.defineProperty(exports, "handoffGeneratedTests", { enumerable: true, get: function () { return api_js_1.handoffGeneratedTests; } });
|
|
31
|
+
Object.defineProperty(exports, "ingestTraceability", { enumerable: true, get: function () { return api_js_1.ingestTraceability; } });
|
|
32
|
+
Object.defineProperty(exports, "captureTraceability", { enumerable: true, get: function () { return api_js_1.captureTraceability; } });
|
|
33
|
+
var feedback_js_1 = require("./agent/feedback.js");
|
|
34
|
+
Object.defineProperty(exports, "appendFeedbackAndRecompute", { enumerable: true, get: function () { return feedback_js_1.appendFeedbackAndRecompute; } });
|
|
35
|
+
Object.defineProperty(exports, "readCalibration", { enumerable: true, get: function () { return feedback_js_1.readCalibration; } });
|
|
36
|
+
var handoff_js_1 = require("./agent/handoff.js");
|
|
37
|
+
Object.defineProperty(exports, "finalizeGeneratedTests", { enumerable: true, get: function () { return handoff_js_1.finalizeGeneratedTests; } });
|
|
38
|
+
var traceability_ingest_js_1 = require("./agent/traceability_ingest.js");
|
|
39
|
+
Object.defineProperty(exports, "ingestTraceabilityInput", { enumerable: true, get: function () { return traceability_ingest_js_1.ingestTraceabilityInput; } });
|
|
40
|
+
var traceability_capture_js_1 = require("./agent/traceability_capture.js");
|
|
41
|
+
Object.defineProperty(exports, "captureTraceabilityInput", { enumerable: true, get: function () { return traceability_capture_js_1.captureTraceabilityInput; } });
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple structured logging system
|
|
3
|
+
* Replaces 18 console.log statements with configurable logging
|
|
4
|
+
* Environment variable: LOG_LEVEL (ERROR, WARN, INFO, DEBUG)
|
|
5
|
+
*/
|
|
6
|
+
export declare enum LogLevel {
|
|
7
|
+
ERROR = 0,
|
|
8
|
+
WARN = 1,
|
|
9
|
+
INFO = 2,
|
|
10
|
+
DEBUG = 3
|
|
11
|
+
}
|
|
12
|
+
export declare class Logger {
|
|
13
|
+
private level;
|
|
14
|
+
constructor(minLevel?: LogLevel);
|
|
15
|
+
error(message: string, context?: Record<string, unknown>): void;
|
|
16
|
+
warn(message: string, context?: Record<string, unknown>): void;
|
|
17
|
+
info(message: string, context?: Record<string, unknown>): void;
|
|
18
|
+
debug(message: string, context?: Record<string, unknown>): void;
|
|
19
|
+
setLevel(level: LogLevel): void;
|
|
20
|
+
private log;
|
|
21
|
+
}
|
|
22
|
+
export declare const logger: Logger;
|
|
23
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,oBAAY,QAAQ;IAChB,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACZ;AAqCD,qBAAa,MAAM;IACf,OAAO,CAAC,KAAK,CAAW;gBAEZ,QAAQ,CAAC,EAAE,QAAQ;IAI/B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM9D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM9D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAM/D,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAI/B,OAAO,CAAC,GAAG;CAYd;AAGD,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
|
+
// See LICENSE.txt for license information.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.logger = exports.Logger = exports.LogLevel = void 0;
|
|
6
|
+
/**
|
|
7
|
+
* Simple structured logging system
|
|
8
|
+
* Replaces 18 console.log statements with configurable logging
|
|
9
|
+
* Environment variable: LOG_LEVEL (ERROR, WARN, INFO, DEBUG)
|
|
10
|
+
*/
|
|
11
|
+
var LogLevel;
|
|
12
|
+
(function (LogLevel) {
|
|
13
|
+
LogLevel[LogLevel["ERROR"] = 0] = "ERROR";
|
|
14
|
+
LogLevel[LogLevel["WARN"] = 1] = "WARN";
|
|
15
|
+
LogLevel[LogLevel["INFO"] = 2] = "INFO";
|
|
16
|
+
LogLevel[LogLevel["DEBUG"] = 3] = "DEBUG";
|
|
17
|
+
})(LogLevel || (exports.LogLevel = LogLevel = {}));
|
|
18
|
+
/**
|
|
19
|
+
* Get log level from environment variable
|
|
20
|
+
*/
|
|
21
|
+
function getLogLevelFromEnv() {
|
|
22
|
+
const level = process.env.LOG_LEVEL?.toUpperCase() || 'INFO';
|
|
23
|
+
switch (level) {
|
|
24
|
+
case 'ERROR':
|
|
25
|
+
return LogLevel.ERROR;
|
|
26
|
+
case 'WARN':
|
|
27
|
+
return LogLevel.WARN;
|
|
28
|
+
case 'INFO':
|
|
29
|
+
return LogLevel.INFO;
|
|
30
|
+
case 'DEBUG':
|
|
31
|
+
return LogLevel.DEBUG;
|
|
32
|
+
default:
|
|
33
|
+
return LogLevel.INFO;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Convert log level to string
|
|
38
|
+
*/
|
|
39
|
+
function logLevelToString(level) {
|
|
40
|
+
switch (level) {
|
|
41
|
+
case LogLevel.ERROR:
|
|
42
|
+
return 'ERROR';
|
|
43
|
+
case LogLevel.WARN:
|
|
44
|
+
return 'WARN';
|
|
45
|
+
case LogLevel.INFO:
|
|
46
|
+
return 'INFO';
|
|
47
|
+
case LogLevel.DEBUG:
|
|
48
|
+
return 'DEBUG';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
class Logger {
|
|
52
|
+
constructor(minLevel) {
|
|
53
|
+
this.level = minLevel ?? getLogLevelFromEnv();
|
|
54
|
+
}
|
|
55
|
+
error(message, context) {
|
|
56
|
+
if (this.level >= LogLevel.ERROR) {
|
|
57
|
+
this.log(LogLevel.ERROR, message, context);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
warn(message, context) {
|
|
61
|
+
if (this.level >= LogLevel.WARN) {
|
|
62
|
+
this.log(LogLevel.WARN, message, context);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
info(message, context) {
|
|
66
|
+
if (this.level >= LogLevel.INFO) {
|
|
67
|
+
this.log(LogLevel.INFO, message, context);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
debug(message, context) {
|
|
71
|
+
if (this.level >= LogLevel.DEBUG) {
|
|
72
|
+
this.log(LogLevel.DEBUG, message, context);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
setLevel(level) {
|
|
76
|
+
this.level = level;
|
|
77
|
+
}
|
|
78
|
+
log(level, message, context) {
|
|
79
|
+
const timestamp = new Date().toISOString();
|
|
80
|
+
const levelStr = logLevelToString(level);
|
|
81
|
+
const contextStr = context ? ` ${JSON.stringify(context)}` : '';
|
|
82
|
+
const output = `[${timestamp}] [${levelStr}] ${message}${contextStr}`;
|
|
83
|
+
if (level <= LogLevel.WARN) {
|
|
84
|
+
console.error(output);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.log(output);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.Logger = Logger;
|
|
92
|
+
// Global logger instance
|
|
93
|
+
exports.logger = new Logger();
|