mindheal 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +48 -0
- package/CHANGELOG.md +27 -0
- package/LICENSE +21 -0
- package/README.md +481 -0
- package/dist/cjs/ai/ai-provider.js +46 -0
- package/dist/cjs/ai/ai-provider.js.map +1 -0
- package/dist/cjs/ai/anthropic-provider.js +106 -0
- package/dist/cjs/ai/anthropic-provider.js.map +1 -0
- package/dist/cjs/ai/azure-openai-provider.js +130 -0
- package/dist/cjs/ai/azure-openai-provider.js.map +1 -0
- package/dist/cjs/ai/bedrock-provider.js +183 -0
- package/dist/cjs/ai/bedrock-provider.js.map +1 -0
- package/dist/cjs/ai/deepseek-provider.js +118 -0
- package/dist/cjs/ai/deepseek-provider.js.map +1 -0
- package/dist/cjs/ai/gemini-provider.js +129 -0
- package/dist/cjs/ai/gemini-provider.js.map +1 -0
- package/dist/cjs/ai/groq-provider.js +118 -0
- package/dist/cjs/ai/groq-provider.js.map +1 -0
- package/dist/cjs/ai/meta-provider.js +118 -0
- package/dist/cjs/ai/meta-provider.js.map +1 -0
- package/dist/cjs/ai/ollama-provider.js +127 -0
- package/dist/cjs/ai/ollama-provider.js.map +1 -0
- package/dist/cjs/ai/openai-provider.js +117 -0
- package/dist/cjs/ai/openai-provider.js.map +1 -0
- package/dist/cjs/ai/perplexity-provider.js +118 -0
- package/dist/cjs/ai/perplexity-provider.js.map +1 -0
- package/dist/cjs/ai/prompt-templates.js +174 -0
- package/dist/cjs/ai/prompt-templates.js.map +1 -0
- package/dist/cjs/ai/qwen-provider.js +118 -0
- package/dist/cjs/ai/qwen-provider.js.map +1 -0
- package/dist/cjs/analytics/healing-analytics.js +263 -0
- package/dist/cjs/analytics/healing-analytics.js.map +1 -0
- package/dist/cjs/cli/init.js +517 -0
- package/dist/cjs/cli/init.js.map +1 -0
- package/dist/cjs/config/config-loader.js +135 -0
- package/dist/cjs/config/config-loader.js.map +1 -0
- package/dist/cjs/config/defaults.js +109 -0
- package/dist/cjs/config/defaults.js.map +1 -0
- package/dist/cjs/core/dom-snapshot.js +280 -0
- package/dist/cjs/core/dom-snapshot.js.map +1 -0
- package/dist/cjs/core/enterprise-strategy.js +702 -0
- package/dist/cjs/core/enterprise-strategy.js.map +1 -0
- package/dist/cjs/core/healer.js +283 -0
- package/dist/cjs/core/healer.js.map +1 -0
- package/dist/cjs/core/interceptor.js +945 -0
- package/dist/cjs/core/interceptor.js.map +1 -0
- package/dist/cjs/core/locator-analyzer.js +172 -0
- package/dist/cjs/core/locator-analyzer.js.map +1 -0
- package/dist/cjs/core/locator-strategies.js +891 -0
- package/dist/cjs/core/locator-strategies.js.map +1 -0
- package/dist/cjs/core/self-heal-cache.js +178 -0
- package/dist/cjs/core/self-heal-cache.js.map +1 -0
- package/dist/cjs/core/smart-retry.js +248 -0
- package/dist/cjs/core/smart-retry.js.map +1 -0
- package/dist/cjs/core/visual-verification.js +262 -0
- package/dist/cjs/core/visual-verification.js.map +1 -0
- package/dist/cjs/git/code-modifier.js +184 -0
- package/dist/cjs/git/code-modifier.js.map +1 -0
- package/dist/cjs/git/git-operations.js +145 -0
- package/dist/cjs/git/git-operations.js.map +1 -0
- package/dist/cjs/git/pr-creator.js +190 -0
- package/dist/cjs/git/pr-creator.js.map +1 -0
- package/dist/cjs/index.js +97 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/rag/context-retriever.js +289 -0
- package/dist/cjs/rag/context-retriever.js.map +1 -0
- package/dist/cjs/rag/embeddings.js +82 -0
- package/dist/cjs/rag/embeddings.js.map +1 -0
- package/dist/cjs/rag/knowledge-store.js +159 -0
- package/dist/cjs/rag/knowledge-store.js.map +1 -0
- package/dist/cjs/reporters/heal-report.js +279 -0
- package/dist/cjs/reporters/heal-report.js.map +1 -0
- package/dist/cjs/reporters/heal-reporter.js +294 -0
- package/dist/cjs/reporters/heal-reporter.js.map +1 -0
- package/dist/cjs/server/review-server.js +166 -0
- package/dist/cjs/server/review-server.js.map +1 -0
- package/dist/cjs/server/routes.js +92 -0
- package/dist/cjs/server/routes.js.map +1 -0
- package/dist/cjs/utils/environment.js +57 -0
- package/dist/cjs/utils/environment.js.map +1 -0
- package/dist/cjs/utils/file-lock.js +136 -0
- package/dist/cjs/utils/file-lock.js.map +1 -0
- package/dist/cjs/utils/file-utils.js +49 -0
- package/dist/cjs/utils/file-utils.js.map +1 -0
- package/dist/cjs/utils/logger.js +78 -0
- package/dist/cjs/utils/logger.js.map +1 -0
- package/dist/esm/ai/ai-provider.js +44 -0
- package/dist/esm/ai/ai-provider.js.map +1 -0
- package/dist/esm/ai/anthropic-provider.js +104 -0
- package/dist/esm/ai/anthropic-provider.js.map +1 -0
- package/dist/esm/ai/azure-openai-provider.js +128 -0
- package/dist/esm/ai/azure-openai-provider.js.map +1 -0
- package/dist/esm/ai/bedrock-provider.js +181 -0
- package/dist/esm/ai/bedrock-provider.js.map +1 -0
- package/dist/esm/ai/deepseek-provider.js +116 -0
- package/dist/esm/ai/deepseek-provider.js.map +1 -0
- package/dist/esm/ai/gemini-provider.js +127 -0
- package/dist/esm/ai/gemini-provider.js.map +1 -0
- package/dist/esm/ai/groq-provider.js +116 -0
- package/dist/esm/ai/groq-provider.js.map +1 -0
- package/dist/esm/ai/meta-provider.js +116 -0
- package/dist/esm/ai/meta-provider.js.map +1 -0
- package/dist/esm/ai/ollama-provider.js +125 -0
- package/dist/esm/ai/ollama-provider.js.map +1 -0
- package/dist/esm/ai/openai-provider.js +115 -0
- package/dist/esm/ai/openai-provider.js.map +1 -0
- package/dist/esm/ai/perplexity-provider.js +116 -0
- package/dist/esm/ai/perplexity-provider.js.map +1 -0
- package/dist/esm/ai/prompt-templates.js +171 -0
- package/dist/esm/ai/prompt-templates.js.map +1 -0
- package/dist/esm/ai/qwen-provider.js +116 -0
- package/dist/esm/ai/qwen-provider.js.map +1 -0
- package/dist/esm/analytics/healing-analytics.js +261 -0
- package/dist/esm/analytics/healing-analytics.js.map +1 -0
- package/dist/esm/cli/init.js +495 -0
- package/dist/esm/cli/init.js.map +1 -0
- package/dist/esm/config/config-loader.js +132 -0
- package/dist/esm/config/config-loader.js.map +1 -0
- package/dist/esm/config/defaults.js +107 -0
- package/dist/esm/config/defaults.js.map +1 -0
- package/dist/esm/core/dom-snapshot.js +278 -0
- package/dist/esm/core/dom-snapshot.js.map +1 -0
- package/dist/esm/core/enterprise-strategy.js +695 -0
- package/dist/esm/core/enterprise-strategy.js.map +1 -0
- package/dist/esm/core/healer.js +281 -0
- package/dist/esm/core/healer.js.map +1 -0
- package/dist/esm/core/interceptor.js +940 -0
- package/dist/esm/core/interceptor.js.map +1 -0
- package/dist/esm/core/locator-analyzer.js +169 -0
- package/dist/esm/core/locator-analyzer.js.map +1 -0
- package/dist/esm/core/locator-strategies.js +882 -0
- package/dist/esm/core/locator-strategies.js.map +1 -0
- package/dist/esm/core/self-heal-cache.js +176 -0
- package/dist/esm/core/self-heal-cache.js.map +1 -0
- package/dist/esm/core/smart-retry.js +246 -0
- package/dist/esm/core/smart-retry.js.map +1 -0
- package/dist/esm/core/visual-verification.js +260 -0
- package/dist/esm/core/visual-verification.js.map +1 -0
- package/dist/esm/git/code-modifier.js +182 -0
- package/dist/esm/git/code-modifier.js.map +1 -0
- package/dist/esm/git/git-operations.js +143 -0
- package/dist/esm/git/git-operations.js.map +1 -0
- package/dist/esm/git/pr-creator.js +188 -0
- package/dist/esm/git/pr-creator.js.map +1 -0
- package/dist/esm/index.js +37 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/rag/context-retriever.js +287 -0
- package/dist/esm/rag/context-retriever.js.map +1 -0
- package/dist/esm/rag/embeddings.js +77 -0
- package/dist/esm/rag/embeddings.js.map +1 -0
- package/dist/esm/rag/knowledge-store.js +157 -0
- package/dist/esm/rag/knowledge-store.js.map +1 -0
- package/dist/esm/reporters/heal-report.js +277 -0
- package/dist/esm/reporters/heal-report.js.map +1 -0
- package/dist/esm/reporters/heal-reporter.js +290 -0
- package/dist/esm/reporters/heal-reporter.js.map +1 -0
- package/dist/esm/server/review-server.js +164 -0
- package/dist/esm/server/review-server.js.map +1 -0
- package/dist/esm/server/routes.js +90 -0
- package/dist/esm/server/routes.js.map +1 -0
- package/dist/esm/utils/environment.js +53 -0
- package/dist/esm/utils/environment.js.map +1 -0
- package/dist/esm/utils/file-lock.js +134 -0
- package/dist/esm/utils/file-lock.js.map +1 -0
- package/dist/esm/utils/file-utils.js +43 -0
- package/dist/esm/utils/file-utils.js.map +1 -0
- package/dist/esm/utils/logger.js +75 -0
- package/dist/esm/utils/logger.js.map +1 -0
- package/dist/types/ai/ai-provider.d.ts +4 -0
- package/dist/types/ai/ai-provider.d.ts.map +1 -0
- package/dist/types/ai/anthropic-provider.d.ts +11 -0
- package/dist/types/ai/anthropic-provider.d.ts.map +1 -0
- package/dist/types/ai/azure-openai-provider.d.ts +13 -0
- package/dist/types/ai/azure-openai-provider.d.ts.map +1 -0
- package/dist/types/ai/bedrock-provider.d.ts +14 -0
- package/dist/types/ai/bedrock-provider.d.ts.map +1 -0
- package/dist/types/ai/deepseek-provider.d.ts +12 -0
- package/dist/types/ai/deepseek-provider.d.ts.map +1 -0
- package/dist/types/ai/gemini-provider.d.ts +12 -0
- package/dist/types/ai/gemini-provider.d.ts.map +1 -0
- package/dist/types/ai/groq-provider.d.ts +12 -0
- package/dist/types/ai/groq-provider.d.ts.map +1 -0
- package/dist/types/ai/meta-provider.d.ts +12 -0
- package/dist/types/ai/meta-provider.d.ts.map +1 -0
- package/dist/types/ai/ollama-provider.d.ts +10 -0
- package/dist/types/ai/ollama-provider.d.ts.map +1 -0
- package/dist/types/ai/openai-provider.d.ts +11 -0
- package/dist/types/ai/openai-provider.d.ts.map +1 -0
- package/dist/types/ai/perplexity-provider.d.ts +12 -0
- package/dist/types/ai/perplexity-provider.d.ts.map +1 -0
- package/dist/types/ai/prompt-templates.d.ts +11 -0
- package/dist/types/ai/prompt-templates.d.ts.map +1 -0
- package/dist/types/ai/qwen-provider.d.ts +12 -0
- package/dist/types/ai/qwen-provider.d.ts.map +1 -0
- package/dist/types/analytics/healing-analytics.d.ts +36 -0
- package/dist/types/analytics/healing-analytics.d.ts.map +1 -0
- package/dist/types/cli/init.d.ts +15 -0
- package/dist/types/cli/init.d.ts.map +1 -0
- package/dist/types/config/config-loader.d.ts +4 -0
- package/dist/types/config/config-loader.d.ts.map +1 -0
- package/dist/types/config/defaults.d.ts +3 -0
- package/dist/types/config/defaults.d.ts.map +1 -0
- package/dist/types/core/dom-snapshot.d.ts +12 -0
- package/dist/types/core/dom-snapshot.d.ts.map +1 -0
- package/dist/types/core/enterprise-strategy.d.ts +56 -0
- package/dist/types/core/enterprise-strategy.d.ts.map +1 -0
- package/dist/types/core/healer.d.ts +52 -0
- package/dist/types/core/healer.d.ts.map +1 -0
- package/dist/types/core/interceptor.d.ts +64 -0
- package/dist/types/core/interceptor.d.ts.map +1 -0
- package/dist/types/core/locator-analyzer.d.ts +31 -0
- package/dist/types/core/locator-analyzer.d.ts.map +1 -0
- package/dist/types/core/locator-strategies.d.ts +45 -0
- package/dist/types/core/locator-strategies.d.ts.map +1 -0
- package/dist/types/core/self-heal-cache.d.ts +51 -0
- package/dist/types/core/self-heal-cache.d.ts.map +1 -0
- package/dist/types/core/smart-retry.d.ts +64 -0
- package/dist/types/core/smart-retry.d.ts.map +1 -0
- package/dist/types/core/visual-verification.d.ts +46 -0
- package/dist/types/core/visual-verification.d.ts.map +1 -0
- package/dist/types/git/code-modifier.d.ts +51 -0
- package/dist/types/git/code-modifier.d.ts.map +1 -0
- package/dist/types/git/git-operations.d.ts +40 -0
- package/dist/types/git/git-operations.d.ts.map +1 -0
- package/dist/types/git/pr-creator.d.ts +27 -0
- package/dist/types/git/pr-creator.d.ts.map +1 -0
- package/dist/types/index.d.ts +40 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/rag/context-retriever.d.ts +69 -0
- package/dist/types/rag/context-retriever.d.ts.map +1 -0
- package/dist/types/rag/embeddings.d.ts +32 -0
- package/dist/types/rag/embeddings.d.ts.map +1 -0
- package/dist/types/rag/index.d.ts +12 -0
- package/dist/types/rag/index.d.ts.map +1 -0
- package/dist/types/rag/knowledge-store.d.ts +38 -0
- package/dist/types/rag/knowledge-store.d.ts.map +1 -0
- package/dist/types/reporters/heal-report.d.ts +29 -0
- package/dist/types/reporters/heal-report.d.ts.map +1 -0
- package/dist/types/reporters/heal-reporter.d.ts +49 -0
- package/dist/types/reporters/heal-reporter.d.ts.map +1 -0
- package/dist/types/server/review-server.d.ts +20 -0
- package/dist/types/server/review-server.d.ts.map +1 -0
- package/dist/types/server/routes.d.ts +4 -0
- package/dist/types/server/routes.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +433 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/dist/types/utils/environment.d.ts +10 -0
- package/dist/types/utils/environment.d.ts.map +1 -0
- package/dist/types/utils/file-lock.d.ts +37 -0
- package/dist/types/utils/file-lock.d.ts.map +1 -0
- package/dist/types/utils/file-utils.d.ts +7 -0
- package/dist/types/utils/file-utils.d.ts.map +1 -0
- package/dist/types/utils/logger.d.ts +9 -0
- package/dist/types/utils/logger.d.ts.map +1 -0
- package/package.json +106 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var logger = require('./logger.js');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Parallel Execution Safety — File Locking
|
|
9
|
+
*
|
|
10
|
+
* Provides advisory file locking for shared resources (cache, knowledge store,
|
|
11
|
+
* analytics) when Playwright tests run with multiple workers or shards.
|
|
12
|
+
*
|
|
13
|
+
* Uses .lock files with PID + timestamp to detect stale locks.
|
|
14
|
+
* Cross-platform (Windows + macOS + Linux).
|
|
15
|
+
*/
|
|
16
|
+
class FileLock {
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.config = config;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Acquires an advisory lock on the given file path.
|
|
22
|
+
* Returns a release function that MUST be called when done.
|
|
23
|
+
*
|
|
24
|
+
* @param filePath - The file to lock (a .lock file is created alongside it)
|
|
25
|
+
* @returns A function to release the lock
|
|
26
|
+
* @throws If the lock cannot be acquired within the timeout
|
|
27
|
+
*/
|
|
28
|
+
async acquire(filePath) {
|
|
29
|
+
if (!this.config.enabled) {
|
|
30
|
+
return () => { }; // No-op release
|
|
31
|
+
}
|
|
32
|
+
const lockPath = `${filePath}.lock`;
|
|
33
|
+
const startTime = Date.now();
|
|
34
|
+
const workerId = `${process.pid}-${Math.random().toString(36).substring(2, 8)}`;
|
|
35
|
+
while (Date.now() - startTime < this.config.lockTimeout) {
|
|
36
|
+
// Check for existing lock
|
|
37
|
+
if (fs.existsSync(lockPath)) {
|
|
38
|
+
const isStale = this.isLockStale(lockPath);
|
|
39
|
+
if (isStale) {
|
|
40
|
+
logger.logger.debug(`[FileLock] Removing stale lock: ${lockPath}`);
|
|
41
|
+
this.removeLock(lockPath);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Wait and retry
|
|
45
|
+
await new Promise((resolve) => setTimeout(resolve, this.config.lockRetryInterval));
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Try to create the lock
|
|
50
|
+
try {
|
|
51
|
+
const dir = path.dirname(lockPath);
|
|
52
|
+
if (!fs.existsSync(dir)) {
|
|
53
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
54
|
+
}
|
|
55
|
+
const lockInfo = {
|
|
56
|
+
pid: process.pid,
|
|
57
|
+
timestamp: Date.now(),
|
|
58
|
+
workerId,
|
|
59
|
+
};
|
|
60
|
+
// Write lock file atomically-ish (best effort)
|
|
61
|
+
fs.writeFileSync(lockPath, JSON.stringify(lockInfo), { flag: 'wx' });
|
|
62
|
+
logger.logger.debug(`[FileLock] Acquired lock: ${lockPath} (worker: ${workerId})`);
|
|
63
|
+
// Return release function
|
|
64
|
+
return () => {
|
|
65
|
+
this.removeLock(lockPath);
|
|
66
|
+
logger.logger.debug(`[FileLock] Released lock: ${lockPath}`);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
// File already exists (another process beat us) — retry
|
|
71
|
+
if (err.code === 'EEXIST') {
|
|
72
|
+
await new Promise((resolve) => setTimeout(resolve, this.config.lockRetryInterval));
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
throw new Error(`[MindHeal] Could not acquire file lock for ${filePath} within ${this.config.lockTimeout}ms`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Executes a function while holding a file lock.
|
|
82
|
+
* Automatically acquires and releases the lock.
|
|
83
|
+
*/
|
|
84
|
+
async withLock(filePath, fn) {
|
|
85
|
+
if (!this.config.enabled) {
|
|
86
|
+
return fn();
|
|
87
|
+
}
|
|
88
|
+
const release = await this.acquire(filePath);
|
|
89
|
+
try {
|
|
90
|
+
return await fn();
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
release();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Checks if a lock file is stale (process dead or too old).
|
|
98
|
+
*/
|
|
99
|
+
isLockStale(lockPath) {
|
|
100
|
+
try {
|
|
101
|
+
const content = fs.readFileSync(lockPath, 'utf-8');
|
|
102
|
+
const info = JSON.parse(content);
|
|
103
|
+
// Check timestamp
|
|
104
|
+
if (Date.now() - info.timestamp > this.config.staleLockThreshold) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
// Check if PID is still alive
|
|
108
|
+
try {
|
|
109
|
+
process.kill(info.pid, 0); // Signal 0 = check if process exists
|
|
110
|
+
return false; // Process is alive
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return true; // Process is dead
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return true; // Can't read lock — treat as stale
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Safely removes a lock file.
|
|
122
|
+
*/
|
|
123
|
+
removeLock(lockPath) {
|
|
124
|
+
try {
|
|
125
|
+
if (fs.existsSync(lockPath)) {
|
|
126
|
+
fs.unlinkSync(lockPath);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Ignore — another process may have removed it
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
exports.FileLock = FileLock;
|
|
136
|
+
//# sourceMappingURL=file-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock.js","sources":["../../../../src/utils/file-lock.ts"],"sourcesContent":[null],"names":["existsSync","logger","dirname","mkdirSync","writeFileSync","readFileSync","unlinkSync"],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var logger = require('./logger.js');
|
|
6
|
+
|
|
7
|
+
function writeFileContent(filePath, content) {
|
|
8
|
+
try {
|
|
9
|
+
const dir = path.dirname(filePath);
|
|
10
|
+
if (!fs.existsSync(dir)) {
|
|
11
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
logger.logger.error(`Failed to write file: ${filePath}`, error);
|
|
17
|
+
throw new Error(`[MindHeal] Cannot write file: ${filePath}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function fileExists(filePath) {
|
|
21
|
+
return fs.existsSync(filePath);
|
|
22
|
+
}
|
|
23
|
+
function ensureDirectory(dirPath) {
|
|
24
|
+
if (!fs.existsSync(dirPath)) {
|
|
25
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function readJsonFile(filePath) {
|
|
29
|
+
try {
|
|
30
|
+
if (!fs.existsSync(filePath))
|
|
31
|
+
return null;
|
|
32
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
33
|
+
return JSON.parse(content);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
logger.logger.warn(`Failed to parse JSON file: ${filePath}`, error);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function writeJsonFile(filePath, data) {
|
|
41
|
+
writeFileContent(filePath, JSON.stringify(data, null, 2));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
exports.ensureDirectory = ensureDirectory;
|
|
45
|
+
exports.fileExists = fileExists;
|
|
46
|
+
exports.readJsonFile = readJsonFile;
|
|
47
|
+
exports.writeFileContent = writeFileContent;
|
|
48
|
+
exports.writeJsonFile = writeJsonFile;
|
|
49
|
+
//# sourceMappingURL=file-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-utils.js","sources":["../../../../src/utils/file-utils.ts"],"sourcesContent":[null],"names":["dirname","existsSync","mkdirSync","writeFileSync","logger","readFileSync"],"mappings":";;;;;;AAaM,SAAU,gBAAgB,CAAC,QAAgB,EAAE,OAAe,EAAA;AAChE,IAAA,IAAI;AACF,QAAA,MAAM,GAAG,GAAGA,YAAO,CAAC,QAAQ,CAAC;AAC7B,QAAA,IAAI,CAACC,aAAU,CAAC,GAAG,CAAC,EAAE;YACpBC,YAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QACrC;AACA,QAAAC,gBAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC;IAC3C;IAAE,OAAO,KAAK,EAAE;QACdC,aAAM,CAAC,KAAK,CAAC,CAAA,sBAAA,EAAyB,QAAQ,CAAA,CAAE,EAAE,KAAK,CAAC;AACxD,QAAA,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,CAAA,CAAE,CAAC;IAC9D;AACF;AAEM,SAAU,UAAU,CAAC,QAAgB,EAAA;AACzC,IAAA,OAAOH,aAAU,CAAC,QAAQ,CAAC;AAC7B;AAEM,SAAU,eAAe,CAAC,OAAe,EAAA;AAC7C,IAAA,IAAI,CAACA,aAAU,CAAC,OAAO,CAAC,EAAE;QACxBC,YAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACzC;AACF;AAEM,SAAU,YAAY,CAAI,QAAgB,EAAA;AAC9C,IAAA,IAAI;AACF,QAAA,IAAI,CAACD,aAAU,CAAC,QAAQ,CAAC;AAAE,YAAA,OAAO,IAAI;QACtC,MAAM,OAAO,GAAGI,eAAY,CAAC,QAAQ,EAAE,OAAO,CAAC;AAC/C,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAM;IACjC;IAAE,OAAO,KAAK,EAAE;QACdD,aAAM,CAAC,IAAI,CAAC,CAAA,2BAAA,EAA8B,QAAQ,CAAA,CAAE,EAAE,KAAK,CAAC;AAC5D,QAAA,OAAO,IAAI;IACb;AACF;AAEM,SAAU,aAAa,CAAC,QAAgB,EAAE,IAAa,EAAA;AAC3D,IAAA,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC3D;;;;;;;;"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
|
|
6
|
+
const LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
7
|
+
const PREFIX = '[MindHeal]';
|
|
8
|
+
let currentLevel = 'info';
|
|
9
|
+
let logFilePath;
|
|
10
|
+
function configureLogger(config) {
|
|
11
|
+
currentLevel = config.level;
|
|
12
|
+
logFilePath = config.file;
|
|
13
|
+
if (logFilePath) {
|
|
14
|
+
const dir = path.dirname(logFilePath);
|
|
15
|
+
if (!fs.existsSync(dir)) {
|
|
16
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function shouldLog(level) {
|
|
21
|
+
return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
|
|
22
|
+
}
|
|
23
|
+
function formatMessage(level, message, data) {
|
|
24
|
+
const timestamp = new Date().toISOString();
|
|
25
|
+
const base = `${timestamp} ${PREFIX} [${level.toUpperCase()}] ${message}`;
|
|
26
|
+
if (data !== undefined) {
|
|
27
|
+
return `${base} ${JSON.stringify(data, null, 2)}`;
|
|
28
|
+
}
|
|
29
|
+
return base;
|
|
30
|
+
}
|
|
31
|
+
function writeToFile(formatted) {
|
|
32
|
+
if (logFilePath) {
|
|
33
|
+
try {
|
|
34
|
+
fs.appendFileSync(logFilePath, formatted + '\n', 'utf-8');
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Silently fail file logging
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const logger = {
|
|
42
|
+
debug(message, data) {
|
|
43
|
+
if (!shouldLog('debug'))
|
|
44
|
+
return;
|
|
45
|
+
const formatted = formatMessage('debug', message, data);
|
|
46
|
+
writeToFile(formatted);
|
|
47
|
+
// eslint-disable-next-line no-console
|
|
48
|
+
console.debug(formatted);
|
|
49
|
+
},
|
|
50
|
+
info(message, data) {
|
|
51
|
+
if (!shouldLog('info'))
|
|
52
|
+
return;
|
|
53
|
+
const formatted = formatMessage('info', message, data);
|
|
54
|
+
writeToFile(formatted);
|
|
55
|
+
// eslint-disable-next-line no-console
|
|
56
|
+
console.info(formatted);
|
|
57
|
+
},
|
|
58
|
+
warn(message, data) {
|
|
59
|
+
if (!shouldLog('warn'))
|
|
60
|
+
return;
|
|
61
|
+
const formatted = formatMessage('warn', message, data);
|
|
62
|
+
writeToFile(formatted);
|
|
63
|
+
// eslint-disable-next-line no-console
|
|
64
|
+
console.warn(formatted);
|
|
65
|
+
},
|
|
66
|
+
error(message, data) {
|
|
67
|
+
if (!shouldLog('error'))
|
|
68
|
+
return;
|
|
69
|
+
const formatted = formatMessage('error', message, data);
|
|
70
|
+
writeToFile(formatted);
|
|
71
|
+
// eslint-disable-next-line no-console
|
|
72
|
+
console.error(formatted);
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
exports.configureLogger = configureLogger;
|
|
77
|
+
exports.logger = logger;
|
|
78
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sources":["../../../../src/utils/logger.ts"],"sourcesContent":[null],"names":["dirname","existsSync","mkdirSync","appendFileSync"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { AnthropicProvider } from './anthropic-provider.js';
|
|
2
|
+
import { OpenAIProvider } from './openai-provider.js';
|
|
3
|
+
import { AzureOpenAIProvider } from './azure-openai-provider.js';
|
|
4
|
+
import { GeminiProvider } from './gemini-provider.js';
|
|
5
|
+
import { OllamaProvider } from './ollama-provider.js';
|
|
6
|
+
import { BedrockProvider } from './bedrock-provider.js';
|
|
7
|
+
import { DeepSeekProvider } from './deepseek-provider.js';
|
|
8
|
+
import { GroqProvider } from './groq-provider.js';
|
|
9
|
+
import { QwenProvider } from './qwen-provider.js';
|
|
10
|
+
import { MetaProvider } from './meta-provider.js';
|
|
11
|
+
import { PerplexityProvider } from './perplexity-provider.js';
|
|
12
|
+
|
|
13
|
+
function createAIProvider(config) {
|
|
14
|
+
switch (config.provider) {
|
|
15
|
+
case 'anthropic':
|
|
16
|
+
return new AnthropicProvider(config);
|
|
17
|
+
case 'openai':
|
|
18
|
+
return new OpenAIProvider(config);
|
|
19
|
+
case 'azure-openai':
|
|
20
|
+
return new AzureOpenAIProvider(config);
|
|
21
|
+
case 'gemini':
|
|
22
|
+
return new GeminiProvider(config);
|
|
23
|
+
case 'ollama':
|
|
24
|
+
return new OllamaProvider(config);
|
|
25
|
+
case 'aws-bedrock':
|
|
26
|
+
return new BedrockProvider(config);
|
|
27
|
+
case 'deepseek':
|
|
28
|
+
return new DeepSeekProvider(config);
|
|
29
|
+
case 'groq':
|
|
30
|
+
return new GroqProvider(config);
|
|
31
|
+
case 'qwen':
|
|
32
|
+
return new QwenProvider(config);
|
|
33
|
+
case 'meta':
|
|
34
|
+
return new MetaProvider(config);
|
|
35
|
+
case 'perplexity':
|
|
36
|
+
return new PerplexityProvider(config);
|
|
37
|
+
default:
|
|
38
|
+
throw new Error(`[MindHeal] Unsupported AI provider: "${config.provider}". ` +
|
|
39
|
+
`Supported: anthropic, openai, azure-openai, gemini, ollama, aws-bedrock, deepseek, groq, qwen, meta, perplexity`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { createAIProvider };
|
|
44
|
+
//# sourceMappingURL=ai-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-provider.js","sources":["../../../../src/ai/ai-provider.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;AAaM,SAAU,gBAAgB,CAAC,MAAgB,EAAA;AAC/C,IAAA,QAAQ,MAAM,CAAC,QAAQ;AACrB,QAAA,KAAK,WAAW;AACd,YAAA,OAAO,IAAI,iBAAiB,CAAC,MAAM,CAAC;AACtC,QAAA,KAAK,QAAQ;AACX,YAAA,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC;AACnC,QAAA,KAAK,cAAc;AACjB,YAAA,OAAO,IAAI,mBAAmB,CAAC,MAAM,CAAC;AACxC,QAAA,KAAK,QAAQ;AACX,YAAA,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC;AACnC,QAAA,KAAK,QAAQ;AACX,YAAA,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC;AACnC,QAAA,KAAK,aAAa;AAChB,YAAA,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC;AACpC,QAAA,KAAK,UAAU;AACb,YAAA,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC;AACrC,QAAA,KAAK,MAAM;AACT,YAAA,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC;AACjC,QAAA,KAAK,MAAM;AACT,YAAA,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC;AACjC,QAAA,KAAK,MAAM;AACT,YAAA,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC;AACjC,QAAA,KAAK,YAAY;AACf,YAAA,OAAO,IAAI,kBAAkB,CAAC,MAAM,CAAC;AACvC,QAAA;AACE,YAAA,MAAM,IAAI,KAAK,CACb,wCAAwC,MAAM,CAAC,QAAQ,CAAA,GAAA,CAAK;AAC5D,gBAAA,CAAA,+GAAA,CAAiH,CAClH;;AAEP;;;;"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { buildHealingPrompt, parseHealingResponse } from './prompt-templates.js';
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_MODEL = 'claude-sonnet-4-20250514';
|
|
5
|
+
const DEFAULT_MAX_TOKENS = 1024;
|
|
6
|
+
const DEFAULT_TEMPERATURE = 0;
|
|
7
|
+
const API_URL = 'https://api.anthropic.com/v1/messages';
|
|
8
|
+
const ANTHROPIC_VERSION = '2023-06-01';
|
|
9
|
+
const REQUEST_TIMEOUT_MS = 30000;
|
|
10
|
+
class AnthropicProvider {
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.name = 'anthropic';
|
|
13
|
+
if (!config.apiKey) {
|
|
14
|
+
throw new Error('[MindHeal] Anthropic API key is required');
|
|
15
|
+
}
|
|
16
|
+
this.apiKey = config.apiKey;
|
|
17
|
+
this.model = config.model ?? DEFAULT_MODEL;
|
|
18
|
+
this.maxTokens = config.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
19
|
+
this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;
|
|
20
|
+
}
|
|
21
|
+
async suggestLocator(request) {
|
|
22
|
+
const prompt = buildHealingPrompt(request);
|
|
23
|
+
const startTime = Date.now();
|
|
24
|
+
logger.debug('Anthropic API: sending healing request', {
|
|
25
|
+
model: this.model,
|
|
26
|
+
originalLocator: request.originalLocator.selector,
|
|
27
|
+
pageUrl: request.pageUrl,
|
|
28
|
+
});
|
|
29
|
+
const messages = [
|
|
30
|
+
{ role: 'user', content: prompt },
|
|
31
|
+
];
|
|
32
|
+
const body = JSON.stringify({
|
|
33
|
+
model: this.model,
|
|
34
|
+
max_tokens: this.maxTokens,
|
|
35
|
+
temperature: this.temperature,
|
|
36
|
+
messages,
|
|
37
|
+
});
|
|
38
|
+
let responseData;
|
|
39
|
+
try {
|
|
40
|
+
const controller = new AbortController();
|
|
41
|
+
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
42
|
+
const response = await fetch(API_URL, {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
headers: {
|
|
45
|
+
'content-type': 'application/json',
|
|
46
|
+
'x-api-key': this.apiKey,
|
|
47
|
+
'anthropic-version': ANTHROPIC_VERSION,
|
|
48
|
+
},
|
|
49
|
+
body,
|
|
50
|
+
signal: controller.signal,
|
|
51
|
+
});
|
|
52
|
+
clearTimeout(timeoutId);
|
|
53
|
+
if (response.status === 429) {
|
|
54
|
+
const retryAfter = response.headers.get('retry-after');
|
|
55
|
+
const waitSeconds = retryAfter ? parseInt(retryAfter, 10) : 5;
|
|
56
|
+
logger.warn(`Anthropic API: rate limited, retrying after ${waitSeconds}s`);
|
|
57
|
+
await sleep(waitSeconds * 1000);
|
|
58
|
+
return this.suggestLocator(request);
|
|
59
|
+
}
|
|
60
|
+
responseData = (await response.json());
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
const errorResp = responseData;
|
|
63
|
+
throw new Error(`Anthropic API error (${response.status}): ${errorResp.error?.message ?? response.statusText}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
68
|
+
throw new Error(`[MindHeal] Anthropic API request timed out after ${REQUEST_TIMEOUT_MS}ms`);
|
|
69
|
+
}
|
|
70
|
+
if (error instanceof Error && error.message.startsWith('Anthropic API error')) {
|
|
71
|
+
throw new Error(`[MindHeal] ${error.message}`);
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`[MindHeal] Anthropic API request failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
74
|
+
}
|
|
75
|
+
const successResp = responseData;
|
|
76
|
+
const textContent = successResp.content.find((c) => c.type === 'text');
|
|
77
|
+
if (!textContent?.text) {
|
|
78
|
+
throw new Error('[MindHeal] Anthropic API returned empty response');
|
|
79
|
+
}
|
|
80
|
+
const duration = Date.now() - startTime;
|
|
81
|
+
logger.debug('Anthropic API: received response', {
|
|
82
|
+
model: successResp.model,
|
|
83
|
+
duration: `${duration}ms`,
|
|
84
|
+
inputTokens: successResp.usage.input_tokens,
|
|
85
|
+
outputTokens: successResp.usage.output_tokens,
|
|
86
|
+
});
|
|
87
|
+
try {
|
|
88
|
+
return parseHealingResponse(textContent.text);
|
|
89
|
+
}
|
|
90
|
+
catch (parseError) {
|
|
91
|
+
logger.error('Anthropic API: failed to parse response', {
|
|
92
|
+
rawText: textContent.text.slice(0, 500),
|
|
93
|
+
error: parseError instanceof Error ? parseError.message : String(parseError),
|
|
94
|
+
});
|
|
95
|
+
throw parseError;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function sleep(ms) {
|
|
100
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export { AnthropicProvider };
|
|
104
|
+
//# sourceMappingURL=anthropic-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-provider.js","sources":["../../../../src/ai/anthropic-provider.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { buildHealingPrompt, parseHealingResponse } from './prompt-templates.js';
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_API_VERSION = '2024-02-01';
|
|
5
|
+
const DEFAULT_MAX_TOKENS = 1024;
|
|
6
|
+
const DEFAULT_TEMPERATURE = 0;
|
|
7
|
+
const REQUEST_TIMEOUT_MS = 30000;
|
|
8
|
+
class AzureOpenAIProvider {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.name = 'azure-openai';
|
|
11
|
+
if (!config.apiKey) {
|
|
12
|
+
throw new Error('[MindHeal] Azure OpenAI API key is required');
|
|
13
|
+
}
|
|
14
|
+
if (!config.baseUrl) {
|
|
15
|
+
throw new Error('[MindHeal] Azure OpenAI baseUrl is required (e.g., https://my-resource.openai.azure.com)');
|
|
16
|
+
}
|
|
17
|
+
if (!config.azureDeploymentName) {
|
|
18
|
+
throw new Error('[MindHeal] Azure OpenAI deployment name is required');
|
|
19
|
+
}
|
|
20
|
+
this.apiKey = config.apiKey;
|
|
21
|
+
this.deploymentName = config.azureDeploymentName;
|
|
22
|
+
this.apiVersion = config.azureApiVersion ?? DEFAULT_API_VERSION;
|
|
23
|
+
this.maxTokens = config.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
24
|
+
this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;
|
|
25
|
+
// Strip trailing slash for consistency
|
|
26
|
+
let baseUrl = config.baseUrl;
|
|
27
|
+
if (baseUrl.endsWith('/')) {
|
|
28
|
+
baseUrl = baseUrl.slice(0, -1);
|
|
29
|
+
}
|
|
30
|
+
this.baseUrl = baseUrl;
|
|
31
|
+
}
|
|
32
|
+
async suggestLocator(request) {
|
|
33
|
+
const fullPrompt = buildHealingPrompt(request);
|
|
34
|
+
const startTime = Date.now();
|
|
35
|
+
logger.debug('Azure OpenAI API: sending healing request', {
|
|
36
|
+
deploymentName: this.deploymentName,
|
|
37
|
+
apiVersion: this.apiVersion,
|
|
38
|
+
originalLocator: request.originalLocator.selector,
|
|
39
|
+
pageUrl: request.pageUrl,
|
|
40
|
+
});
|
|
41
|
+
// Split the combined prompt into system + user messages at the separator
|
|
42
|
+
const separatorIndex = fullPrompt.indexOf('\n\n---\n\n');
|
|
43
|
+
let systemContent;
|
|
44
|
+
let userContent;
|
|
45
|
+
if (separatorIndex !== -1) {
|
|
46
|
+
systemContent = fullPrompt.slice(0, separatorIndex);
|
|
47
|
+
userContent = fullPrompt.slice(separatorIndex + 7); // length of '\n\n---\n\n'
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
systemContent = 'You are an expert Playwright test engineer. Respond with only valid JSON.';
|
|
51
|
+
userContent = fullPrompt;
|
|
52
|
+
}
|
|
53
|
+
const messages = [
|
|
54
|
+
{ role: 'system', content: systemContent },
|
|
55
|
+
{ role: 'user', content: userContent },
|
|
56
|
+
];
|
|
57
|
+
const body = JSON.stringify({
|
|
58
|
+
max_tokens: this.maxTokens,
|
|
59
|
+
temperature: this.temperature,
|
|
60
|
+
messages,
|
|
61
|
+
});
|
|
62
|
+
const url = `${this.baseUrl}/openai/deployments/${this.deploymentName}/chat/completions?api-version=${this.apiVersion}`;
|
|
63
|
+
let responseData;
|
|
64
|
+
try {
|
|
65
|
+
const controller = new AbortController();
|
|
66
|
+
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
67
|
+
const response = await fetch(url, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers: {
|
|
70
|
+
'content-type': 'application/json',
|
|
71
|
+
'api-key': this.apiKey,
|
|
72
|
+
},
|
|
73
|
+
body,
|
|
74
|
+
signal: controller.signal,
|
|
75
|
+
});
|
|
76
|
+
clearTimeout(timeoutId);
|
|
77
|
+
if (response.status === 429) {
|
|
78
|
+
const retryAfter = response.headers.get('retry-after');
|
|
79
|
+
const waitSeconds = retryAfter ? parseInt(retryAfter, 10) : 5;
|
|
80
|
+
logger.warn(`Azure OpenAI API: rate limited, retrying after ${waitSeconds}s`);
|
|
81
|
+
await sleep(waitSeconds * 1000);
|
|
82
|
+
return this.suggestLocator(request);
|
|
83
|
+
}
|
|
84
|
+
responseData = (await response.json());
|
|
85
|
+
if (!response.ok) {
|
|
86
|
+
const errorResp = responseData;
|
|
87
|
+
throw new Error(`Azure OpenAI API error (${response.status}): ${errorResp.error?.message ?? response.statusText}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
92
|
+
throw new Error(`[MindHeal] Azure OpenAI API request timed out after ${REQUEST_TIMEOUT_MS}ms`);
|
|
93
|
+
}
|
|
94
|
+
if (error instanceof Error && error.message.startsWith('Azure OpenAI API error')) {
|
|
95
|
+
throw new Error(`[MindHeal] ${error.message}`);
|
|
96
|
+
}
|
|
97
|
+
throw new Error(`[MindHeal] Azure OpenAI API request failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
98
|
+
}
|
|
99
|
+
const successResp = responseData;
|
|
100
|
+
const choice = successResp.choices[0];
|
|
101
|
+
if (!choice?.message?.content) {
|
|
102
|
+
throw new Error('[MindHeal] Azure OpenAI API returned empty response');
|
|
103
|
+
}
|
|
104
|
+
const duration = Date.now() - startTime;
|
|
105
|
+
logger.debug('Azure OpenAI API: received response', {
|
|
106
|
+
model: successResp.model,
|
|
107
|
+
duration: `${duration}ms`,
|
|
108
|
+
promptTokens: successResp.usage.prompt_tokens,
|
|
109
|
+
completionTokens: successResp.usage.completion_tokens,
|
|
110
|
+
});
|
|
111
|
+
try {
|
|
112
|
+
return parseHealingResponse(choice.message.content);
|
|
113
|
+
}
|
|
114
|
+
catch (parseError) {
|
|
115
|
+
logger.error('Azure OpenAI API: failed to parse response', {
|
|
116
|
+
rawText: choice.message.content.slice(0, 500),
|
|
117
|
+
error: parseError instanceof Error ? parseError.message : String(parseError),
|
|
118
|
+
});
|
|
119
|
+
throw parseError;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function sleep(ms) {
|
|
124
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export { AzureOpenAIProvider };
|
|
128
|
+
//# sourceMappingURL=azure-openai-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"azure-openai-provider.js","sources":["../../../../src/ai/azure-openai-provider.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAIA,MAAM,mBAAmB,GAAG,YAAY;AACxC,MAAM,kBAAkB,GAAG,IAAI;AAC/B,MAAM,mBAAmB,GAAG,CAAC;AAC7B,MAAM,kBAAkB,GAAG,KAAM;MAyBpB,mBAAmB,CAAA;AAU9B,IAAA,WAAA,CAAY,MAAgB,EAAA;QATZ,IAAA,CAAA,IAAI,GAAG,cAAc;AAUnC,QAAA,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;AAClB,YAAA,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC;QAChE;AACA,QAAA,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;AACnB,YAAA,MAAM,IAAI,KAAK,CACb,0FAA0F,CAC3F;QACH;AACA,QAAA,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE;AAC/B,YAAA,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC;QACxE;AAEA,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM;AAC3B,QAAA,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,mBAAmB;QAChD,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,eAAe,IAAI,mBAAmB;QAC/D,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,kBAAkB;QACvD,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,mBAAmB;;AAG5D,QAAA,IAAI,OAAO,GAAG,MAAM,CAAC,OAAO;AAC5B,QAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;YACzB,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChC;AACA,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO;IACxB;IAEA,MAAM,cAAc,CAAC,OAAyB,EAAA;AAC5C,QAAA,MAAM,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAC;AAC9C,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE;AAE5B,QAAA,MAAM,CAAC,KAAK,CAAC,2CAA2C,EAAE;YACxD,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,UAAU,EAAE,IAAI,CAAC,UAAU;AAC3B,YAAA,eAAe,EAAE,OAAO,CAAC,eAAe,CAAC,QAAQ;YACjD,OAAO,EAAE,OAAO,CAAC,OAAO;AACzB,SAAA,CAAC;;QAGF,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC;AACxD,QAAA,IAAI,aAAqB;AACzB,QAAA,IAAI,WAAmB;AAEvB,QAAA,IAAI,cAAc,KAAK,EAAE,EAAE;YACzB,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC;YACnD,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC;QACrD;aAAO;YACL,aAAa,GAAG,2EAA2E;YAC3F,WAAW,GAAG,UAAU;QAC1B;AAEA,QAAA,MAAM,QAAQ,GAAuB;AACnC,YAAA,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE;AAC1C,YAAA,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE;SACvC;AAED,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,UAAU,EAAE,IAAI,CAAC,SAAS;YAC1B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ;AACT,SAAA,CAAC;AAEF,QAAA,MAAM,GAAG,GACP,CAAA,EAAG,IAAI,CAAC,OAAO,CAAA,oBAAA,EAAuB,IAAI,CAAC,cAAc,CAAA,8BAAA,EAAiC,IAAI,CAAC,UAAU,EAAE;AAE7G,QAAA,IAAI,YAAuD;AAE3D,QAAA,IAAI;AACF,YAAA,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;AACxC,YAAA,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,UAAU,CAAC,KAAK,EAAE,EAAE,kBAAkB,CAAC;AAE1E,YAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;AAChC,gBAAA,MAAM,EAAE,MAAM;AACd,gBAAA,OAAO,EAAE;AACP,oBAAA,cAAc,EAAE,kBAAkB;oBAClC,SAAS,EAAE,IAAI,CAAC,MAAM;AACvB,iBAAA;gBACD,IAAI;gBACJ,MAAM,EAAE,UAAU,CAAC,MAAM;AAC1B,aAAA,CAAC;YAEF,YAAY,CAAC,SAAS,CAAC;AAEvB,YAAA,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE;gBAC3B,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;AACtD,gBAAA,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,CAAC;AAC7D,gBAAA,MAAM,CAAC,IAAI,CAAC,kDAAkD,WAAW,CAAA,CAAA,CAAG,CAAC;AAC7E,gBAAA,MAAM,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;AAC/B,gBAAA,OAAO,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;YACrC;YAEA,YAAY,IAAI,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA8C;AAEnF,YAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;gBAChB,MAAM,SAAS,GAAG,YAAkC;AACpD,gBAAA,MAAM,IAAI,KAAK,CACb,2BAA2B,QAAQ,CAAC,MAAM,CAAA,GAAA,EAAM,SAAS,CAAC,KAAK,EAAE,OAAO,IAAI,QAAQ,CAAC,UAAU,CAAA,CAAE,CAClG;YACH;QACF;QAAE,OAAO,KAAc,EAAE;YACvB,IAAI,KAAK,YAAY,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE;AAChE,gBAAA,MAAM,IAAI,KAAK,CACb,uDAAuD,kBAAkB,CAAA,EAAA,CAAI,CAC9E;YACH;AACA,YAAA,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,wBAAwB,CAAC,EAAE;gBAChF,MAAM,IAAI,KAAK,CAAC,CAAA,WAAA,EAAc,KAAK,CAAC,OAAO,CAAA,CAAE,CAAC;YAChD;YACA,MAAM,IAAI,KAAK,CACb,CAAA,4CAAA,EAA+C,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA,CAAE,CACxG;QACH;QAEA,MAAM,WAAW,GAAG,YAAoC;QACxD,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;AAErC,QAAA,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE;AAC7B,YAAA,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC;QACxE;QAEA,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;AACvC,QAAA,MAAM,CAAC,KAAK,CAAC,qCAAqC,EAAE;YAClD,KAAK,EAAE,WAAW,CAAC,KAAK;YACxB,QAAQ,EAAE,CAAA,EAAG,QAAQ,CAAA,EAAA,CAAI;AACzB,YAAA,YAAY,EAAE,WAAW,CAAC,KAAK,CAAC,aAAa;AAC7C,YAAA,gBAAgB,EAAE,WAAW,CAAC,KAAK,CAAC,iBAAiB;AACtD,SAAA,CAAC;AAEF,QAAA,IAAI;YACF,OAAO,oBAAoB,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;QACrD;QAAE,OAAO,UAAmB,EAAE;AAC5B,YAAA,MAAM,CAAC,KAAK,CAAC,4CAA4C,EAAE;AACzD,gBAAA,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;AAC7C,gBAAA,KAAK,EAAE,UAAU,YAAY,KAAK,GAAG,UAAU,CAAC,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC;AAC7E,aAAA,CAAC;AACF,YAAA,MAAM,UAAU;QAClB;IACF;AACD;AAED,SAAS,KAAK,CAAC,EAAU,EAAA;AACvB,IAAA,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAC1D;;;;"}
|