agentic-qe 3.7.19 → 3.7.21
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/.claude/agents/v3/qe-deployment-advisor.md +14 -0
- package/.claude/agents/v3/qe-gap-detector.md +8 -0
- package/.claude/agents/v3/qe-impact-analyzer.md +11 -0
- package/.claude/agents/v3/qe-queen-coordinator.md +45 -0
- package/.claude/agents/v3/qe-root-cause-analyzer.md +11 -0
- package/.claude/agents/v3/qe-security-scanner.md +25 -16
- package/.claude/helpers/brain-checkpoint.cjs +3 -3
- package/.claude/helpers/statusline-v3.cjs +4 -3
- package/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +27 -0
- package/assets/agents/v3/qe-deployment-advisor.md +14 -0
- package/assets/agents/v3/qe-gap-detector.md +8 -0
- package/assets/agents/v3/qe-impact-analyzer.md +11 -0
- package/assets/agents/v3/qe-queen-coordinator.md +45 -0
- package/assets/agents/v3/qe-root-cause-analyzer.md +11 -0
- package/assets/agents/v3/qe-security-scanner.md +25 -16
- package/assets/helpers/statusline-v3.cjs +4 -3
- package/dist/adapters/claude-flow/model-router-bridge.d.ts +0 -6
- package/dist/adapters/claude-flow/model-router-bridge.js +4 -17
- package/dist/adapters/claude-flow/pretrain-bridge.d.ts +0 -6
- package/dist/adapters/claude-flow/pretrain-bridge.js +6 -19
- package/dist/adapters/claude-flow/trajectory-bridge.d.ts +0 -6
- package/dist/adapters/claude-flow/trajectory-bridge.js +21 -23
- package/dist/cli/bundle.js +1821 -986
- package/dist/coordination/protocols/security-audit.d.ts +3 -6
- package/dist/coordination/protocols/security-audit.js +8 -88
- package/dist/coordination/queen-coordinator.d.ts +13 -0
- package/dist/coordination/queen-coordinator.js +76 -0
- package/dist/coordination/queen-task-management.d.ts +2 -0
- package/dist/coordination/queen-task-management.js +10 -0
- package/dist/coordination/queen-types.d.ts +3 -0
- package/dist/coordination/task-executor.js +7 -5
- package/dist/domains/security-compliance/services/scanners/sast-scanner.d.ts +25 -1
- package/dist/domains/security-compliance/services/scanners/sast-scanner.js +140 -11
- package/dist/domains/security-compliance/services/scanners/scanner-types.d.ts +2 -0
- package/dist/domains/security-compliance/services/scanners/scanner-types.js +1 -0
- package/dist/domains/test-execution/services/mincut-test-optimizer.js +2 -0
- package/dist/governance/continue-gate-integration.js +1 -1
- package/dist/governance/feature-flags.js +2 -2
- package/dist/init/agents-installer.d.ts +2 -0
- package/dist/init/agents-installer.js +13 -0
- package/dist/init/enhancements/claude-flow-adapter.js +51 -24
- package/dist/init/init-wizard.js +1 -1
- package/dist/init/phases/07-hooks.js +6 -6
- package/dist/init/settings-merge.js +2 -0
- package/dist/integrations/ruvector/brain-rvf-exporter.js +14 -2
- package/dist/learning/experience-capture-middleware.js +3 -1
- package/dist/learning/qe-reasoning-bank.js +3 -3
- package/dist/learning/sqlite-persistence.js +16 -0
- package/dist/learning/token-tracker.js +4 -2
- package/dist/mcp/bundle.js +1183 -504
- package/dist/routing/agent-dependency-graph.d.ts +77 -0
- package/dist/routing/agent-dependency-graph.js +359 -0
- package/dist/routing/co-execution-repository.d.ts +68 -0
- package/dist/routing/co-execution-repository.js +184 -0
- package/dist/routing/index.d.ts +6 -0
- package/dist/routing/index.js +6 -0
- package/dist/routing/qe-task-router.d.ts +7 -0
- package/dist/routing/qe-task-router.js +63 -1
- package/dist/routing/signal-merger.d.ts +81 -0
- package/dist/routing/signal-merger.js +136 -0
- package/dist/routing/types.d.ts +1 -0
- package/dist/shared/llm/providers/azure-openai.js +3 -2
- package/dist/shared/llm/providers/bedrock.js +3 -2
- package/dist/shared/llm/providers/claude.js +3 -2
- package/dist/shared/llm/providers/gemini.js +3 -2
- package/dist/shared/llm/providers/openai.js +3 -2
- package/dist/shared/llm/providers/openrouter.js +3 -2
- package/dist/shared/llm/retry.d.ts +10 -0
- package/dist/shared/llm/retry.js +16 -0
- package/dist/shared/llm/router/agent-router-config.d.ts +2 -1
- package/dist/shared/llm/router/agent-router-config.js +38 -88
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.js +4 -0
- package/dist/validation/steps/agent-mcp-validator.d.ts +88 -0
- package/dist/validation/steps/agent-mcp-validator.js +254 -0
- package/package.json +1 -1
|
@@ -263,6 +263,8 @@ export class MinCutTestOptimizerImpl {
|
|
|
263
263
|
criticalTests.add(promotedId);
|
|
264
264
|
skippableTests.delete(promotedId);
|
|
265
265
|
const promotedTest = testMap.get(promotedId);
|
|
266
|
+
if (!promotedTest)
|
|
267
|
+
continue;
|
|
266
268
|
for (const file of promotedTest.coveredFiles) {
|
|
267
269
|
covered.add(file);
|
|
268
270
|
}
|
|
@@ -153,7 +153,7 @@ export class ContinueGateIntegration {
|
|
|
153
153
|
budgetRemaining: {
|
|
154
154
|
tokens: Math.max(0, (flags.maxConsecutiveRetries * 10 * 500) - (history.length * 500)),
|
|
155
155
|
toolCalls: Math.max(0, (flags.maxConsecutiveRetries * 10) - history.length),
|
|
156
|
-
timeMs: Math.max(0, flags.idleTimeoutMs - (history.length > 0 ? Date.now() - history[
|
|
156
|
+
timeMs: Math.max(0, flags.idleTimeoutMs - (history.length > 0 ? Date.now() - history[history.length - 1].timestamp : 0)),
|
|
157
157
|
},
|
|
158
158
|
recentDecisions: [],
|
|
159
159
|
};
|
|
@@ -16,7 +16,7 @@ export const DEFAULT_GOVERNANCE_FLAGS = {
|
|
|
16
16
|
enabled: true,
|
|
17
17
|
maxConsecutiveRetries: 3,
|
|
18
18
|
reworkRatioThreshold: 0.5,
|
|
19
|
-
idleTimeoutMs:
|
|
19
|
+
idleTimeoutMs: 15 * 60 * 1000, // 15 minutes
|
|
20
20
|
throttleOnExceed: true,
|
|
21
21
|
},
|
|
22
22
|
memoryWriteGate: {
|
|
@@ -124,7 +124,7 @@ export function loadFlagsFromEnv() {
|
|
|
124
124
|
enabled: env.GOVERNANCE_CONTINUE_GATE !== 'false',
|
|
125
125
|
maxConsecutiveRetries: parseInt(env.GOVERNANCE_MAX_RETRIES || '3', 10),
|
|
126
126
|
reworkRatioThreshold: parseFloat(env.GOVERNANCE_REWORK_THRESHOLD || '0.5'),
|
|
127
|
-
idleTimeoutMs: parseInt(env.GOVERNANCE_IDLE_TIMEOUT || '
|
|
127
|
+
idleTimeoutMs: parseInt(env.GOVERNANCE_IDLE_TIMEOUT || '900000', 10),
|
|
128
128
|
throttleOnExceed: env.GOVERNANCE_THROTTLE !== 'false',
|
|
129
129
|
},
|
|
130
130
|
memoryWriteGate: {
|
|
@@ -21,6 +21,8 @@ export interface AgentsInstallResult {
|
|
|
21
21
|
overlaysApplied?: string[];
|
|
22
22
|
/** Warnings from overlay loading */
|
|
23
23
|
overlayWarnings?: string[];
|
|
24
|
+
/** MCP dependency validation warnings (advisory only) */
|
|
25
|
+
mcpValidationWarnings?: string[];
|
|
24
26
|
}
|
|
25
27
|
export interface AgentsInstallerOptions {
|
|
26
28
|
/** Project root directory */
|
|
@@ -10,6 +10,7 @@ import { join, dirname } from 'path';
|
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
11
|
import { toErrorMessage } from '../shared/error-utils.js';
|
|
12
12
|
import { loadOverlays, applyOverlayToContent } from '../agents/overlay-loader.js';
|
|
13
|
+
import { validateFleetMcpDeps } from '../validation/steps/agent-mcp-validator.js';
|
|
13
14
|
// ============================================================================
|
|
14
15
|
// Agent Categories
|
|
15
16
|
// ============================================================================
|
|
@@ -298,6 +299,18 @@ export class AgentsInstaller {
|
|
|
298
299
|
if (result.overlaysApplied.length > 0) {
|
|
299
300
|
console.error(`[AgentsInstaller] Applied ${result.overlaysApplied.length} agent overlay(s): ${result.overlaysApplied.join(', ')}`);
|
|
300
301
|
}
|
|
302
|
+
// Validate MCP dependencies (advisory only -- Issue #342 Item 1)
|
|
303
|
+
const mcpValidation = validateFleetMcpDeps(targetAgentsDir, this.projectRoot);
|
|
304
|
+
result.mcpValidationWarnings = mcpValidation.warnings;
|
|
305
|
+
if (mcpValidation.warnings.length > 0) {
|
|
306
|
+
console.error(`[AgentsInstaller] MCP dependency warnings (${mcpValidation.agentsWithMissingDeps.length} agents affected):`);
|
|
307
|
+
for (const warning of mcpValidation.warnings.slice(0, 10)) {
|
|
308
|
+
console.error(` ${warning}`);
|
|
309
|
+
}
|
|
310
|
+
if (mcpValidation.warnings.length > 10) {
|
|
311
|
+
console.error(` ... and ${mcpValidation.warnings.length - 10} more warnings`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
301
314
|
// Create agents index file
|
|
302
315
|
await this.createAgentsIndex(targetAgentsDir, result.installed);
|
|
303
316
|
return result;
|
|
@@ -11,9 +11,18 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { detectClaudeFlow } from '../../adapters/claude-flow/detect.js';
|
|
13
13
|
import { safeJsonParse } from '../../shared/safe-json.js';
|
|
14
|
-
/** Shared
|
|
15
|
-
const
|
|
16
|
-
|
|
14
|
+
/** Shared execFileSync options */
|
|
15
|
+
const EXEC_OPTS = { encoding: 'utf-8' };
|
|
16
|
+
/**
|
|
17
|
+
* Build args array for npx @claude-flow/cli calls.
|
|
18
|
+
* Using execFileSync with explicit args prevents shell injection.
|
|
19
|
+
*/
|
|
20
|
+
function cfCliArgs(...subcommand) {
|
|
21
|
+
return {
|
|
22
|
+
bin: 'npx',
|
|
23
|
+
args: ['--no-install', '@claude-flow/cli', ...subcommand],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
17
26
|
/**
|
|
18
27
|
* Claude Flow Adapter Implementation
|
|
19
28
|
* Falls back gracefully when Claude Flow is not available
|
|
@@ -86,9 +95,12 @@ export class ClaudeFlowAdapterImpl {
|
|
|
86
95
|
return `aqe-trajectory-${Date.now()}`;
|
|
87
96
|
}
|
|
88
97
|
try {
|
|
89
|
-
const {
|
|
90
|
-
const
|
|
91
|
-
|
|
98
|
+
const { execFileSync } = await import('child_process');
|
|
99
|
+
const { bin, args } = cfCliArgs('hooks', 'intelligence', 'trajectory-start', '--task', task);
|
|
100
|
+
if (agent) {
|
|
101
|
+
args.push('--agent', agent);
|
|
102
|
+
}
|
|
103
|
+
const result = execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
|
|
92
104
|
// Parse trajectory ID from result
|
|
93
105
|
const match = result.match(/trajectoryId[:\s]+["']?([^"'\s]+)/i);
|
|
94
106
|
return match?.[1] || `cf-trajectory-${Date.now()}`;
|
|
@@ -104,10 +116,15 @@ export class ClaudeFlowAdapterImpl {
|
|
|
104
116
|
if (!this.available)
|
|
105
117
|
return;
|
|
106
118
|
try {
|
|
107
|
-
const {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
119
|
+
const { execFileSync } = await import('child_process');
|
|
120
|
+
const { bin, args } = cfCliArgs('hooks', 'intelligence', 'trajectory-step', '--trajectory-id', trajectoryId, '--action', action);
|
|
121
|
+
if (result) {
|
|
122
|
+
args.push('--result', result);
|
|
123
|
+
}
|
|
124
|
+
if (quality !== undefined) {
|
|
125
|
+
args.push('--quality', String(quality));
|
|
126
|
+
}
|
|
127
|
+
execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
|
|
111
128
|
}
|
|
112
129
|
catch (error) {
|
|
113
130
|
// Non-critical: trajectory tracking is optional
|
|
@@ -121,9 +138,12 @@ export class ClaudeFlowAdapterImpl {
|
|
|
121
138
|
if (!this.available)
|
|
122
139
|
return;
|
|
123
140
|
try {
|
|
124
|
-
const {
|
|
125
|
-
const
|
|
126
|
-
|
|
141
|
+
const { execFileSync } = await import('child_process');
|
|
142
|
+
const { bin, args } = cfCliArgs('hooks', 'intelligence', 'trajectory-end', '--trajectory-id', trajectoryId, '--success', String(success));
|
|
143
|
+
if (feedback) {
|
|
144
|
+
args.push('--feedback', feedback);
|
|
145
|
+
}
|
|
146
|
+
execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
|
|
127
147
|
}
|
|
128
148
|
catch (error) {
|
|
129
149
|
// Non-critical: trajectory end is optional
|
|
@@ -139,8 +159,9 @@ export class ClaudeFlowAdapterImpl {
|
|
|
139
159
|
return { model: 'sonnet', confidence: 0.5 };
|
|
140
160
|
}
|
|
141
161
|
try {
|
|
142
|
-
const {
|
|
143
|
-
const
|
|
162
|
+
const { execFileSync } = await import('child_process');
|
|
163
|
+
const { bin, args } = cfCliArgs('hooks', 'model-route', '--task', task);
|
|
164
|
+
const result = execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
|
|
144
165
|
// Parse result
|
|
145
166
|
const modelMatch = result.match(/model[:\s]+["']?(haiku|sonnet|opus)/i);
|
|
146
167
|
const confMatch = result.match(/confidence[:\s]+([0-9.]+)/i);
|
|
@@ -162,8 +183,9 @@ export class ClaudeFlowAdapterImpl {
|
|
|
162
183
|
if (!this.available)
|
|
163
184
|
return;
|
|
164
185
|
try {
|
|
165
|
-
const {
|
|
166
|
-
|
|
186
|
+
const { execFileSync } = await import('child_process');
|
|
187
|
+
const { bin, args } = cfCliArgs('hooks', 'model-outcome', '--task', task, '--model', model, '--outcome', outcome);
|
|
188
|
+
execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
|
|
167
189
|
}
|
|
168
190
|
catch (error) {
|
|
169
191
|
// Non-critical: outcome recording is optional
|
|
@@ -178,8 +200,9 @@ export class ClaudeFlowAdapterImpl {
|
|
|
178
200
|
return { success: false, reason: 'Claude Flow not available' };
|
|
179
201
|
}
|
|
180
202
|
try {
|
|
181
|
-
const {
|
|
182
|
-
const
|
|
203
|
+
const { execFileSync } = await import('child_process');
|
|
204
|
+
const { bin, args } = cfCliArgs('hooks', 'pretrain', '--path', path, '--depth', depth);
|
|
205
|
+
const result = execFileSync(bin, args, { ...EXEC_OPTS, timeout: 60000 });
|
|
183
206
|
// Try to parse JSON result
|
|
184
207
|
try {
|
|
185
208
|
return safeJsonParse(result);
|
|
@@ -199,9 +222,12 @@ export class ClaudeFlowAdapterImpl {
|
|
|
199
222
|
if (!this.available)
|
|
200
223
|
return;
|
|
201
224
|
try {
|
|
202
|
-
const {
|
|
203
|
-
const
|
|
204
|
-
|
|
225
|
+
const { execFileSync } = await import('child_process');
|
|
226
|
+
const { bin, args } = cfCliArgs('hooks', 'intelligence', 'pattern-store', '--pattern', pattern, '--type', type, '--confidence', String(confidence));
|
|
227
|
+
if (metadata) {
|
|
228
|
+
args.push('--metadata', JSON.stringify(metadata));
|
|
229
|
+
}
|
|
230
|
+
execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
|
|
205
231
|
}
|
|
206
232
|
catch (error) {
|
|
207
233
|
// Non-critical: pattern storage is optional
|
|
@@ -216,8 +242,9 @@ export class ClaudeFlowAdapterImpl {
|
|
|
216
242
|
return [];
|
|
217
243
|
}
|
|
218
244
|
try {
|
|
219
|
-
const {
|
|
220
|
-
const
|
|
245
|
+
const { execFileSync } = await import('child_process');
|
|
246
|
+
const { bin, args } = cfCliArgs('hooks', 'intelligence', 'pattern-search', '--query', query, '--top-k', String(topK));
|
|
247
|
+
const result = execFileSync(bin, args, { ...EXEC_OPTS, timeout: 10000 });
|
|
221
248
|
// Try to parse JSON result
|
|
222
249
|
try {
|
|
223
250
|
const parsed = safeJsonParse(result);
|
package/dist/init/init-wizard.js
CHANGED
|
@@ -272,7 +272,7 @@ export class InitOrchestrator {
|
|
|
272
272
|
if (this.options.autoMigrate) {
|
|
273
273
|
console.log('Auto-migrate mode enabled. Running migration...\n');
|
|
274
274
|
// Fire and forget - the caller will await initialize() which runs migration inline
|
|
275
|
-
runV2Migration(this.projectRoot, v2Detection).catch(() => { });
|
|
275
|
+
runV2Migration(this.projectRoot, v2Detection).catch((e) => { console.warn('[InitWizard] V2 migration failed:', e instanceof Error ? e.message : e); });
|
|
276
276
|
return null;
|
|
277
277
|
}
|
|
278
278
|
// Warn and suggest migration
|
|
@@ -285,9 +285,9 @@ export class HooksPhase extends BasePhase {
|
|
|
285
285
|
*/
|
|
286
286
|
const fs = require('fs');
|
|
287
287
|
const path = require('path');
|
|
288
|
-
const {
|
|
288
|
+
const { execFileSync } = require('child_process');
|
|
289
289
|
|
|
290
|
-
function q(
|
|
290
|
+
function q(bin, args, d) { try { return execFileSync(bin, args, { encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'] }).trim(); } catch { return d || ''; } }
|
|
291
291
|
|
|
292
292
|
const dir = process.cwd();
|
|
293
293
|
const dbPath = path.join(dir, '.agentic-qe', 'memory.db');
|
|
@@ -301,7 +301,7 @@ try {
|
|
|
301
301
|
}
|
|
302
302
|
} catch { /* ignore */ }
|
|
303
303
|
|
|
304
|
-
const branch = q('git branch --show-current
|
|
304
|
+
const branch = q('git', ['branch', '--show-current']);
|
|
305
305
|
const branchStr = branch ? \` \\x1b[34m⎇ \${branch}\\x1b[0m\` : '';
|
|
306
306
|
const patStr = patterns > 0 ? \` \\x1b[35m🎓 \${patterns} patterns\\x1b[0m\` : '';
|
|
307
307
|
|
|
@@ -321,7 +321,7 @@ console.log(\`\\x1b[1m\\x1b[35m▊ Agentic QE v3\\x1b[0m\${branchStr}\${patStr}\
|
|
|
321
321
|
* node brain-checkpoint.cjs export # Export brain to aqe.rvf (session-end)
|
|
322
322
|
* node brain-checkpoint.cjs verify # Verify aqe.rvf exists (session-start)
|
|
323
323
|
*/
|
|
324
|
-
const {
|
|
324
|
+
const { execFileSync } = require('child_process');
|
|
325
325
|
const fs = require('fs');
|
|
326
326
|
const path = require('path');
|
|
327
327
|
|
|
@@ -338,8 +338,8 @@ function exportBrain() {
|
|
|
338
338
|
if (fs.existsSync(RVF_PATH)) fs.unlinkSync(RVF_PATH);
|
|
339
339
|
const idmap = RVF_PATH + '.idmap.json';
|
|
340
340
|
if (fs.existsSync(idmap)) fs.unlinkSync(idmap);
|
|
341
|
-
const result =
|
|
342
|
-
'npx agentic-qe brain export -o
|
|
341
|
+
const result = execFileSync(
|
|
342
|
+
'npx', ['agentic-qe', 'brain', 'export', '-o', RVF_PATH, '--format', 'rvf'],
|
|
343
343
|
{ timeout: 60000, encoding: 'utf-8' }
|
|
344
344
|
);
|
|
345
345
|
const m = result.match(/Patterns:\\s+(\\d+)/);
|
|
@@ -195,7 +195,13 @@ export function importBrainFromRvf(db, rvfPath, options) {
|
|
|
195
195
|
if (!kernel || !kernel.image) {
|
|
196
196
|
throw new Error('No brain data found in RVF file (missing kernel segment)');
|
|
197
197
|
}
|
|
198
|
-
|
|
198
|
+
let brainData;
|
|
199
|
+
try {
|
|
200
|
+
brainData = JSON.parse(kernel.image.toString('utf-8'));
|
|
201
|
+
}
|
|
202
|
+
catch (parseErr) {
|
|
203
|
+
throw new Error(`Failed to parse brain kernel data as JSON: ${parseErr instanceof Error ? parseErr.message : parseErr}`);
|
|
204
|
+
}
|
|
199
205
|
if (options.dryRun) {
|
|
200
206
|
let total = 0;
|
|
201
207
|
if (brainData.tables) {
|
|
@@ -296,7 +302,13 @@ export function brainInfoFromRvf(rvfPath) {
|
|
|
296
302
|
throw new Error('No brain data found in RVF file');
|
|
297
303
|
}
|
|
298
304
|
const brainJson = kernel.image.toString('utf-8');
|
|
299
|
-
|
|
305
|
+
let brainData;
|
|
306
|
+
try {
|
|
307
|
+
brainData = JSON.parse(brainJson);
|
|
308
|
+
}
|
|
309
|
+
catch (parseErr) {
|
|
310
|
+
throw new Error(`Failed to parse brain kernel data as JSON: ${parseErr instanceof Error ? parseErr.message : parseErr}`);
|
|
311
|
+
}
|
|
300
312
|
const status = rvf.status();
|
|
301
313
|
const fileSize = statSync(filePath).size;
|
|
302
314
|
const t = brainData.tables;
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
import { v4 as uuidv4 } from 'uuid';
|
|
15
15
|
import { getUnifiedMemory } from '../kernel/unified-memory.js';
|
|
16
16
|
import { toErrorMessage } from '../shared/error-utils.js';
|
|
17
|
+
import { createLogger } from '../logging/logger-factory.js';
|
|
18
|
+
const ecLogger = createLogger('ExperienceCapture');
|
|
17
19
|
// ============================================================================
|
|
18
20
|
// Active Experience Tracking
|
|
19
21
|
// ============================================================================
|
|
@@ -269,7 +271,7 @@ async function persistExperience(context, outcome) {
|
|
|
269
271
|
`);
|
|
270
272
|
stmt.run(outcome.id, context.task, context.agent, context.domain, outcome.success ? 1 : 0, outcome.quality, outcome.durationMs, context.modelTier || null, safeJsonStringify(context.routing), safeJsonStringify(outcome.steps), safeJsonStringify(outcome.result), outcome.error || null, context.startedAt.toISOString(), 'middleware');
|
|
271
273
|
// Fire-and-forget: compute and store embedding for this experience
|
|
272
|
-
computeExperienceEmbedding(db, outcome.id, context.task, context.domain).catch(() => { });
|
|
274
|
+
computeExperienceEmbedding(db, outcome.id, context.task, context.domain).catch((e) => { ecLogger.warn('Embedding computation failed', { error: e instanceof Error ? e.message : String(e), experienceId: outcome.id, domain: context.domain }); });
|
|
273
275
|
}
|
|
274
276
|
catch (error) {
|
|
275
277
|
console.error('[ExperienceCaptureMiddleware] Failed to persist experience:', error);
|
|
@@ -1059,7 +1059,7 @@ On promotion:
|
|
|
1059
1059
|
const result = await this.patternStore.create(options);
|
|
1060
1060
|
// ADR-070: Record pattern creation in witness chain
|
|
1061
1061
|
if (result.success) {
|
|
1062
|
-
getWitnessChain().then(wc => wc.append('PATTERN_CREATE', { patternId: result.value.id, domain: result.value.qeDomain, confidence: result.value.confidence, name: result.value.name }, 'reasoning-bank')).catch(() => { });
|
|
1062
|
+
getWitnessChain().then(wc => wc.append('PATTERN_CREATE', { patternId: result.value.id, domain: result.value.qeDomain, confidence: result.value.confidence, name: result.value.name }, 'reasoning-bank')).catch((e) => { logger.warn('Witness chain PATTERN_CREATE failed', { error: toErrorMessage(e) }); });
|
|
1063
1063
|
// Phase 3: Best-effort RVF dual-write for vector replication
|
|
1064
1064
|
if (this.rvfDualWriter && result.value.embedding && result.value.embedding.length > 0) {
|
|
1065
1065
|
try {
|
|
@@ -1137,7 +1137,7 @@ On promotion:
|
|
|
1137
1137
|
this.stats.successfulOutcomes++;
|
|
1138
1138
|
}
|
|
1139
1139
|
// ADR-070: Record pattern update in witness chain
|
|
1140
|
-
getWitnessChain().then(wc => wc.append('PATTERN_UPDATE', { patternId: outcome.patternId, success: outcome.success }, 'reasoning-bank')).catch(() => { });
|
|
1140
|
+
getWitnessChain().then(wc => wc.append('PATTERN_UPDATE', { patternId: outcome.patternId, success: outcome.success }, 'reasoning-bank')).catch((e) => { logger.warn('Witness chain PATTERN_UPDATE failed', { error: toErrorMessage(e) }); });
|
|
1141
1141
|
// Check if pattern should be promoted (with coherence gate)
|
|
1142
1142
|
const pattern = await this.getPattern(outcome.patternId);
|
|
1143
1143
|
if (pattern && await this.checkPatternPromotionWithCoherence(pattern)) {
|
|
@@ -1240,7 +1240,7 @@ On promotion:
|
|
|
1240
1240
|
}
|
|
1241
1241
|
}
|
|
1242
1242
|
// ADR-070: Record pattern promotion in witness chain
|
|
1243
|
-
getWitnessChain().then(wc => wc.append('PATTERN_PROMOTE', { patternId }, 'reasoning-bank')).catch(() => { });
|
|
1243
|
+
getWitnessChain().then(wc => wc.append('PATTERN_PROMOTE', { patternId }, 'reasoning-bank')).catch((e) => { logger.warn('Witness chain PATTERN_PROMOTE failed', { error: toErrorMessage(e) }); });
|
|
1244
1244
|
logger.info('Promoted pattern to long-term', { patternId });
|
|
1245
1245
|
if (this.eventBus) {
|
|
1246
1246
|
await this.eventBus.publish({
|
|
@@ -183,6 +183,22 @@ export class SQLitePatternStore {
|
|
|
183
183
|
FOREIGN KEY (pattern_id) REFERENCES qe_patterns(id) ON DELETE CASCADE
|
|
184
184
|
);
|
|
185
185
|
|
|
186
|
+
-- Agent co-execution tracking (Issue #342 Item 3)
|
|
187
|
+
CREATE TABLE IF NOT EXISTS qe_agent_co_execution (
|
|
188
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
189
|
+
agent_a TEXT NOT NULL,
|
|
190
|
+
agent_b TEXT NOT NULL,
|
|
191
|
+
domain TEXT NOT NULL,
|
|
192
|
+
success INTEGER NOT NULL DEFAULT 0,
|
|
193
|
+
task_description TEXT,
|
|
194
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
CREATE INDEX IF NOT EXISTS idx_co_exec_agents
|
|
198
|
+
ON qe_agent_co_execution(agent_a, agent_b);
|
|
199
|
+
CREATE INDEX IF NOT EXISTS idx_co_exec_domain
|
|
200
|
+
ON qe_agent_co_execution(domain);
|
|
201
|
+
|
|
186
202
|
-- Unique constraint to prevent duplicate patterns
|
|
187
203
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_patterns_unique_name_domain_type
|
|
188
204
|
ON qe_patterns(name, qe_domain, pattern_type);
|
|
@@ -34,6 +34,8 @@ import { randomUUID } from 'crypto';
|
|
|
34
34
|
import { getUnifiedMemory } from '../kernel/unified-memory.js';
|
|
35
35
|
import { toErrorMessage } from '../shared/error-utils.js';
|
|
36
36
|
import { safeJsonParse } from '../shared/safe-json.js';
|
|
37
|
+
import { createLogger } from '../logging/logger-factory.js';
|
|
38
|
+
const ttLogger = createLogger('TokenTracker');
|
|
37
39
|
const DEFAULT_COST_CONFIG = {
|
|
38
40
|
costPerInputToken: 0.003 / 1000, // $3 per 1M input tokens
|
|
39
41
|
costPerOutputToken: 0.015 / 1000, // $15 per 1M output tokens
|
|
@@ -84,7 +86,7 @@ class TokenMetricsCollectorImpl {
|
|
|
84
86
|
this.costConfig = { ...DEFAULT_COST_CONFIG, ...config };
|
|
85
87
|
}
|
|
86
88
|
// Activate DB-backed persistence and auto-save timer
|
|
87
|
-
this.initializeDb().catch(() => { });
|
|
89
|
+
this.initializeDb().catch((e) => { ttLogger.warn('DB initialization failed', { error: e instanceof Error ? e.message : String(e) }); });
|
|
88
90
|
this.startAutoSave();
|
|
89
91
|
}
|
|
90
92
|
/**
|
|
@@ -601,7 +603,7 @@ class TokenMetricsCollectorImpl {
|
|
|
601
603
|
this.kvPersistCount++;
|
|
602
604
|
if (this.kvPersistCount >= TokenMetricsCollectorImpl.KV_PERSIST_INTERVAL) {
|
|
603
605
|
this.kvPersistCount = 0;
|
|
604
|
-
this.persistToKv().catch(() => { });
|
|
606
|
+
this.persistToKv().catch((e) => { ttLogger.warn('KV persist failed', { error: e instanceof Error ? e.message : String(e) }); });
|
|
605
607
|
}
|
|
606
608
|
}
|
|
607
609
|
// ============================================================================
|