hedgequantx 2.7.99 → 2.8.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/package.json +1 -1
- package/src/pages/ai-agents-ui.js +46 -1
- package/src/pages/ai-agents.js +84 -54
- package/src/pages/algo/algo-executor.js +61 -19
- package/src/pages/algo/copy-executor.js +331 -0
- package/src/pages/algo/copy-trading.js +44 -263
- package/src/pages/algo/custom-strategy.js +27 -2
- package/src/pages/algo/one-account.js +48 -1
- package/src/services/ai-supervision/consensus.js +284 -0
- package/src/services/ai-supervision/context.js +275 -0
- package/src/services/ai-supervision/directive.js +167 -0
- package/src/services/ai-supervision/health.js +288 -0
- package/src/services/ai-supervision/index.js +309 -0
- package/src/services/ai-supervision/parser.js +278 -0
- package/src/services/ai-supervision/symbols.js +259 -0
- package/src/services/cliproxy/index.js +32 -1
- package/src/services/index.js +5 -1
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Supervision Directive - The 7 Phases
|
|
3
|
+
*
|
|
4
|
+
* This directive is sent to ALL AI agents for trading supervision.
|
|
5
|
+
* Each agent receives the same instructions and analyzes signals in parallel.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const DIRECTIVE_PHASES = {
|
|
9
|
+
phase1_strategy: `
|
|
10
|
+
## PHASE 1: MAÎTRISER LA STRATÉGIE
|
|
11
|
+
Tu connais cette stratégie par coeur. Tu sais exactement:
|
|
12
|
+
- Les conditions d'entrée (setup patterns, confirmations requises)
|
|
13
|
+
- Les règles de sortie (targets, stops, trailing)
|
|
14
|
+
- La gestion du risque (sizing, max loss, drawdown limits)
|
|
15
|
+
- Les filtres de marché (sessions, volatilité, corrélations)
|
|
16
|
+
Tu ne devines jamais. Tu appliques la stratégie avec précision chirurgicale.
|
|
17
|
+
`,
|
|
18
|
+
|
|
19
|
+
phase2_role: `
|
|
20
|
+
## PHASE 2: TON RÔLE
|
|
21
|
+
Tu es une arme de précision intégrée à l'algo de trading.
|
|
22
|
+
Tu n'es PAS un conseiller - tu es un avantage décisif.
|
|
23
|
+
Ton job: optimiser chaque signal pour maximiser le edge.
|
|
24
|
+
Tu travailles EN TEMPS RÉEL avec latence minimale.
|
|
25
|
+
Chaque milliseconde compte. Chaque tick compte.
|
|
26
|
+
`,
|
|
27
|
+
|
|
28
|
+
phase3_analysis: `
|
|
29
|
+
## PHASE 3: CE QUE TU ANALYSES
|
|
30
|
+
Pour chaque signal reçu, tu analyses:
|
|
31
|
+
- DOM (Depth of Market): déséquilibres bid/ask, absorption, spoofing
|
|
32
|
+
- Order Flow: delta, CVD, volume profile, footprint
|
|
33
|
+
- Manipulations: stop hunts, fakeouts, liquidity grabs
|
|
34
|
+
- Patterns: structure de marché, S/R, pivots, VWAP
|
|
35
|
+
- Historique: trades récents, winrate par setup, performance horaire
|
|
36
|
+
- Corrélations: autres symboles liés (ES/NQ, GC/SI, etc.)
|
|
37
|
+
`,
|
|
38
|
+
|
|
39
|
+
phase4_output: `
|
|
40
|
+
## PHASE 4: CE QUE TU FOURNIS
|
|
41
|
+
Pour chaque signal, tu retournes:
|
|
42
|
+
1. DECISION: approve/reject/modify
|
|
43
|
+
2. CONFIDENCE: score 0-100
|
|
44
|
+
3. OPTIMIZATIONS (si approve/modify):
|
|
45
|
+
- entry: prix d'entrée optimisé (ou null)
|
|
46
|
+
- stopLoss: stop optimisé (ou null)
|
|
47
|
+
- takeProfit: target optimisé (ou null)
|
|
48
|
+
- size: ajustement de taille (-50% à +50%)
|
|
49
|
+
- timing: "now" | "wait" | "cancel"
|
|
50
|
+
4. REASON: explication courte (max 50 chars)
|
|
51
|
+
5. ALERTS: warnings importants (optionnel)
|
|
52
|
+
`,
|
|
53
|
+
|
|
54
|
+
phase5_restrictions: `
|
|
55
|
+
## PHASE 5: CE QUE TU NE FAIS JAMAIS
|
|
56
|
+
- Tu ne BLOQUES jamais l'algo sans raison valide
|
|
57
|
+
- Tu ne RALENTIS jamais l'exécution (réponse < 2 secondes)
|
|
58
|
+
- Tu ne fais pas de VAGUE - décision claire et directe
|
|
59
|
+
- Tu n'INVENTES pas de données - utilise uniquement ce qui est fourni
|
|
60
|
+
- Tu ne CHANGES pas la stratégie - tu l'optimises dans ses règles
|
|
61
|
+
`,
|
|
62
|
+
|
|
63
|
+
phase6_symbols: `
|
|
64
|
+
## PHASE 6: CONNAISSANCE DES SYMBOLES
|
|
65
|
+
Tu trades ces symboles avec leurs caractéristiques:
|
|
66
|
+
- NQ (Nasdaq): volatile, tech-driven, corrélé ES
|
|
67
|
+
- ES (S&P500): référence, plus stable, leader
|
|
68
|
+
- YM (Dow): value stocks, moins volatile
|
|
69
|
+
- RTY (Russell): small caps, plus volatile que ES
|
|
70
|
+
- GC (Gold): safe haven, inverse USD, sessions Asia/London
|
|
71
|
+
- SI (Silver): suit GC avec plus de volatilité
|
|
72
|
+
- CL (Crude): news-driven, inventories, géopolitique
|
|
73
|
+
|
|
74
|
+
Sessions importantes:
|
|
75
|
+
- Asia: 18:00-03:00 ET (GC/SI actifs)
|
|
76
|
+
- London: 03:00-08:00 ET (préparation US)
|
|
77
|
+
- US Open: 09:30-11:30 ET (max volatilité)
|
|
78
|
+
- US Close: 15:00-16:00 ET (rebalancing)
|
|
79
|
+
`,
|
|
80
|
+
|
|
81
|
+
phase7_mindset: `
|
|
82
|
+
## PHASE 7: TA MENTALITÉ
|
|
83
|
+
- OBJECTIF: Gagner. Pas "essayer". Gagner.
|
|
84
|
+
- PRÉCISION: Chaque décision compte
|
|
85
|
+
- RAPIDITÉ: Temps = argent. Sois rapide.
|
|
86
|
+
- RESPONSABILITÉ: Tu assumes tes recommandations
|
|
87
|
+
- ADAPTATION: Le marché change, tu t'adaptes
|
|
88
|
+
- DISCIPLINE: Les règles sont les règles
|
|
89
|
+
`
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Build the complete directive string
|
|
94
|
+
*/
|
|
95
|
+
const buildDirective = () => {
|
|
96
|
+
return Object.values(DIRECTIVE_PHASES).join('\n');
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Expected output format from AI agents
|
|
101
|
+
*/
|
|
102
|
+
const OUTPUT_FORMAT = {
|
|
103
|
+
schema: {
|
|
104
|
+
decision: 'approve | reject | modify',
|
|
105
|
+
confidence: 'number 0-100',
|
|
106
|
+
optimizations: {
|
|
107
|
+
entry: 'number | null',
|
|
108
|
+
stopLoss: 'number | null',
|
|
109
|
+
takeProfit: 'number | null',
|
|
110
|
+
size: 'number (-0.5 to 0.5) | null',
|
|
111
|
+
timing: 'now | wait | cancel'
|
|
112
|
+
},
|
|
113
|
+
reason: 'string (max 50 chars)',
|
|
114
|
+
alerts: 'string[] | null'
|
|
115
|
+
},
|
|
116
|
+
example: {
|
|
117
|
+
decision: 'modify',
|
|
118
|
+
confidence: 85,
|
|
119
|
+
optimizations: {
|
|
120
|
+
entry: 21450.25,
|
|
121
|
+
stopLoss: 21445.00,
|
|
122
|
+
takeProfit: 21462.50,
|
|
123
|
+
size: 0,
|
|
124
|
+
timing: 'now'
|
|
125
|
+
},
|
|
126
|
+
reason: 'Strong bid stack, tighten stop',
|
|
127
|
+
alerts: null
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Build the output format instructions
|
|
133
|
+
*/
|
|
134
|
+
const buildOutputInstructions = () => {
|
|
135
|
+
return `
|
|
136
|
+
## OUTPUT FORMAT (JSON STRICT)
|
|
137
|
+
Tu dois TOUJOURS répondre en JSON valide avec ce format exact:
|
|
138
|
+
|
|
139
|
+
\`\`\`json
|
|
140
|
+
${JSON.stringify(OUTPUT_FORMAT.example, null, 2)}
|
|
141
|
+
\`\`\`
|
|
142
|
+
|
|
143
|
+
IMPORTANT:
|
|
144
|
+
- decision: "approve" (exécuter tel quel), "reject" (ne pas exécuter), "modify" (exécuter avec optimisations)
|
|
145
|
+
- confidence: 0-100, ton niveau de confiance dans la décision
|
|
146
|
+
- optimizations: null si decision="reject", sinon les ajustements
|
|
147
|
+
- size: 0 = garder la taille, -0.5 = réduire de 50%, +0.5 = augmenter de 50%
|
|
148
|
+
- timing: "now" = exécuter immédiatement, "wait" = attendre meilleur prix, "cancel" = annuler
|
|
149
|
+
- reason: TOUJOURS fournir une raison courte
|
|
150
|
+
- Pas de texte avant ou après le JSON
|
|
151
|
+
`;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get the complete directive with output format
|
|
156
|
+
*/
|
|
157
|
+
const getFullDirective = () => {
|
|
158
|
+
return buildDirective() + '\n' + buildOutputInstructions();
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
module.exports = {
|
|
162
|
+
DIRECTIVE_PHASES,
|
|
163
|
+
OUTPUT_FORMAT,
|
|
164
|
+
buildDirective,
|
|
165
|
+
buildOutputInstructions,
|
|
166
|
+
getFullDirective
|
|
167
|
+
};
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Supervision Health Check
|
|
3
|
+
*
|
|
4
|
+
* Verifies that AI agents are properly connected and responding
|
|
5
|
+
* before allowing algo trading with AI supervision.
|
|
6
|
+
*
|
|
7
|
+
* Two verification points:
|
|
8
|
+
* 1. [T] TEST in AI Agents menu - manual verification
|
|
9
|
+
* 2. Pre-check before algo launch - automatic verification
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const cliproxy = require('../cliproxy');
|
|
13
|
+
|
|
14
|
+
/** Test prompt to verify agent understands directive format */
|
|
15
|
+
const TEST_PROMPT = `You are being tested. Respond ONLY with this exact JSON, nothing else:
|
|
16
|
+
{"decision":"approve","confidence":100,"reason":"test-ok"}`;
|
|
17
|
+
|
|
18
|
+
/** Timeout for agent response (agents should respond in < 1 second) */
|
|
19
|
+
const AGENT_TIMEOUT = 2000;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Check if CLIProxy is running and responding
|
|
23
|
+
* @returns {Promise<Object>} { success, latency, error }
|
|
24
|
+
*/
|
|
25
|
+
const checkCliproxyRunning = async () => {
|
|
26
|
+
const startTime = Date.now();
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const status = await cliproxy.isRunning();
|
|
30
|
+
const latency = Date.now() - startTime;
|
|
31
|
+
|
|
32
|
+
if (status.running) {
|
|
33
|
+
return { success: true, latency, error: null };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return { success: false, latency, error: 'CLIProxy not running' };
|
|
37
|
+
} catch (error) {
|
|
38
|
+
return { success: false, latency: Date.now() - startTime, error: error.message };
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Test a single agent connection and response format
|
|
44
|
+
* @param {Object} agent - Agent config { id, provider, modelId, connectionType, ... }
|
|
45
|
+
* @returns {Promise<Object>} { success, latency, formatValid, error }
|
|
46
|
+
*/
|
|
47
|
+
const testAgentConnection = async (agent) => {
|
|
48
|
+
const startTime = Date.now();
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
// Only test CLIProxy connections for now
|
|
52
|
+
if (agent.connectionType !== 'cliproxy') {
|
|
53
|
+
// For API key connections, we would need different logic
|
|
54
|
+
// For now, mark as needing CLIProxy
|
|
55
|
+
return {
|
|
56
|
+
success: false,
|
|
57
|
+
latency: 0,
|
|
58
|
+
formatValid: false,
|
|
59
|
+
error: 'Only CLIProxy connections supported for pre-check'
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Send test prompt with short timeout
|
|
64
|
+
const result = await cliproxy.chat(agent.provider, agent.modelId, TEST_PROMPT, AGENT_TIMEOUT);
|
|
65
|
+
const latency = Date.now() - startTime;
|
|
66
|
+
|
|
67
|
+
if (!result.success) {
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
latency,
|
|
71
|
+
formatValid: false,
|
|
72
|
+
error: result.error || 'No response from agent'
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Validate response format
|
|
77
|
+
const formatResult = validateResponseFormat(result.content);
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
success: formatResult.valid,
|
|
81
|
+
latency,
|
|
82
|
+
formatValid: formatResult.valid,
|
|
83
|
+
error: formatResult.valid ? null : formatResult.error,
|
|
84
|
+
response: result.content
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
} catch (error) {
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
latency: Date.now() - startTime,
|
|
91
|
+
formatValid: false,
|
|
92
|
+
error: error.message || 'Connection failed'
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Validate that response matches expected JSON format
|
|
99
|
+
* @param {string} content - Response content from agent
|
|
100
|
+
* @returns {Object} { valid, error }
|
|
101
|
+
*/
|
|
102
|
+
const validateResponseFormat = (content) => {
|
|
103
|
+
if (!content) {
|
|
104
|
+
return { valid: false, error: 'Empty response' };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
// Try to extract JSON from response
|
|
109
|
+
let json;
|
|
110
|
+
|
|
111
|
+
// Direct parse
|
|
112
|
+
try {
|
|
113
|
+
json = JSON.parse(content.trim());
|
|
114
|
+
} catch (e) {
|
|
115
|
+
// Try to find JSON in response
|
|
116
|
+
const match = content.match(/\{[\s\S]*\}/);
|
|
117
|
+
if (match) {
|
|
118
|
+
json = JSON.parse(match[0]);
|
|
119
|
+
} else {
|
|
120
|
+
return { valid: false, error: 'No JSON in response' };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Check required fields
|
|
125
|
+
if (!json.decision) {
|
|
126
|
+
return { valid: false, error: 'Missing "decision" field' };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (json.confidence === undefined) {
|
|
130
|
+
return { valid: false, error: 'Missing "confidence" field' };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!json.reason) {
|
|
134
|
+
return { valid: false, error: 'Missing "reason" field' };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Validate decision value
|
|
138
|
+
const validDecisions = ['approve', 'reject', 'modify'];
|
|
139
|
+
if (!validDecisions.includes(json.decision)) {
|
|
140
|
+
return { valid: false, error: `Invalid decision: ${json.decision}` };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Validate confidence is number 0-100
|
|
144
|
+
const conf = Number(json.confidence);
|
|
145
|
+
if (isNaN(conf) || conf < 0 || conf > 100) {
|
|
146
|
+
return { valid: false, error: `Invalid confidence: ${json.confidence}` };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return { valid: true, error: null };
|
|
150
|
+
|
|
151
|
+
} catch (error) {
|
|
152
|
+
return { valid: false, error: `Parse error: ${error.message}` };
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Run pre-flight check on all agents
|
|
158
|
+
* @param {Array} agents - Array of agent configs
|
|
159
|
+
* @returns {Promise<Object>} { success, cliproxy, agents, summary }
|
|
160
|
+
*/
|
|
161
|
+
const runPreflightCheck = async (agents) => {
|
|
162
|
+
const results = {
|
|
163
|
+
success: false,
|
|
164
|
+
cliproxy: null,
|
|
165
|
+
agents: [],
|
|
166
|
+
summary: { total: 0, passed: 0, failed: 0 }
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Step 1: Check CLIProxy
|
|
170
|
+
results.cliproxy = await checkCliproxyRunning();
|
|
171
|
+
|
|
172
|
+
if (!results.cliproxy.success) {
|
|
173
|
+
results.summary.total = agents.length;
|
|
174
|
+
results.summary.failed = agents.length;
|
|
175
|
+
return results;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Step 2: Test each agent
|
|
179
|
+
results.summary.total = agents.length;
|
|
180
|
+
|
|
181
|
+
for (const agent of agents) {
|
|
182
|
+
const agentResult = await testAgentConnection(agent);
|
|
183
|
+
|
|
184
|
+
results.agents.push({
|
|
185
|
+
id: agent.id,
|
|
186
|
+
name: agent.name,
|
|
187
|
+
provider: agent.provider,
|
|
188
|
+
modelId: agent.modelId,
|
|
189
|
+
...agentResult
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
if (agentResult.success) {
|
|
193
|
+
results.summary.passed++;
|
|
194
|
+
} else {
|
|
195
|
+
results.summary.failed++;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Success only if ALL agents pass
|
|
200
|
+
results.success = results.summary.failed === 0 && results.summary.passed > 0;
|
|
201
|
+
|
|
202
|
+
return results;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Format pre-flight results for console display
|
|
207
|
+
* @param {Object} results - Results from runPreflightCheck
|
|
208
|
+
* @param {number} boxWidth - Width for formatting
|
|
209
|
+
* @returns {Array<string>} Lines to display
|
|
210
|
+
*/
|
|
211
|
+
const formatPreflightResults = (results, boxWidth) => {
|
|
212
|
+
const chalk = require('chalk');
|
|
213
|
+
const lines = [];
|
|
214
|
+
const W = boxWidth - 2;
|
|
215
|
+
|
|
216
|
+
// CLIProxy status
|
|
217
|
+
if (results.cliproxy.success) {
|
|
218
|
+
lines.push(chalk.white(' CLIProxy Status') + chalk.gray('.'.repeat(Math.max(1, W - 35))) + chalk.green(' ✓ RUNNING'));
|
|
219
|
+
} else {
|
|
220
|
+
lines.push(chalk.white(' CLIProxy Status') + chalk.gray('.'.repeat(Math.max(1, W - 35))) + chalk.red(' ✗ NOT RUNNING'));
|
|
221
|
+
lines.push(chalk.red(` Error: ${results.cliproxy.error}`));
|
|
222
|
+
return lines;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
lines.push('');
|
|
226
|
+
lines.push(chalk.white(` Testing ${results.summary.total} agent(s):`));
|
|
227
|
+
lines.push('');
|
|
228
|
+
|
|
229
|
+
// Each agent
|
|
230
|
+
for (let i = 0; i < results.agents.length; i++) {
|
|
231
|
+
const agent = results.agents[i];
|
|
232
|
+
const num = `[${i + 1}/${results.summary.total}]`;
|
|
233
|
+
|
|
234
|
+
lines.push(chalk.cyan(` ${num} ${agent.name} (${agent.modelId || agent.provider})`));
|
|
235
|
+
|
|
236
|
+
if (agent.success) {
|
|
237
|
+
const latencyStr = `${agent.latency}ms`;
|
|
238
|
+
lines.push(chalk.gray(' Connection') + chalk.gray('.'.repeat(Math.max(1, W - 40))) + chalk.green(` ✓ OK ${latencyStr}`));
|
|
239
|
+
lines.push(chalk.gray(' Format') + chalk.gray('.'.repeat(Math.max(1, W - 36))) + chalk.green(' ✓ VALID'));
|
|
240
|
+
} else {
|
|
241
|
+
lines.push(chalk.gray(' Connection') + chalk.gray('.'.repeat(Math.max(1, W - 38))) + chalk.red(' ✗ FAILED'));
|
|
242
|
+
lines.push(chalk.red(` Error: ${agent.error}`));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
lines.push('');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return lines;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Get summary line for pre-flight results
|
|
253
|
+
* @param {Object} results - Results from runPreflightCheck
|
|
254
|
+
* @returns {Object} { text, success }
|
|
255
|
+
*/
|
|
256
|
+
const getPreflightSummary = (results) => {
|
|
257
|
+
const chalk = require('chalk');
|
|
258
|
+
|
|
259
|
+
if (!results.cliproxy.success) {
|
|
260
|
+
return {
|
|
261
|
+
text: chalk.red('✗ CLIProxy not running - cannot verify agents'),
|
|
262
|
+
success: false
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (results.success) {
|
|
267
|
+
return {
|
|
268
|
+
text: chalk.green(`✓ ALL SYSTEMS GO - ${results.summary.passed}/${results.summary.total} agents ready`),
|
|
269
|
+
success: true
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
text: chalk.red(`✗ FAILED - ${results.summary.passed}/${results.summary.total} agents passed (all must pass)`),
|
|
275
|
+
success: false
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
module.exports = {
|
|
280
|
+
checkCliproxyRunning,
|
|
281
|
+
testAgentConnection,
|
|
282
|
+
validateResponseFormat,
|
|
283
|
+
runPreflightCheck,
|
|
284
|
+
formatPreflightResults,
|
|
285
|
+
getPreflightSummary,
|
|
286
|
+
TEST_PROMPT,
|
|
287
|
+
AGENT_TIMEOUT
|
|
288
|
+
};
|