konsilio 0.3.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/LICENSE.md +24 -0
- package/README.md +170 -0
- package/build/cli/history.d.ts +2 -0
- package/build/cli/history.js +179 -0
- package/build/cli/history.js.map +1 -0
- package/build/config.d.ts +38 -0
- package/build/config.js +118 -0
- package/build/config.js.map +1 -0
- package/build/container.d.ts +32 -0
- package/build/container.js +102 -0
- package/build/container.js.map +1 -0
- package/build/db/schema.d.ts +1 -0
- package/build/db/schema.js +67 -0
- package/build/db/schema.js.map +1 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +140 -0
- package/build/index.js.map +1 -0
- package/build/konsilio.json +25 -0
- package/build/konsilio.schema.json +140 -0
- package/build/logger.d.ts +84 -0
- package/build/logger.js +121 -0
- package/build/logger.js.map +1 -0
- package/build/personas/expert.d.ts +33 -0
- package/build/personas/expert.js +46 -0
- package/build/personas/expert.js.map +1 -0
- package/build/personas/index.d.ts +9 -0
- package/build/personas/index.js +11 -0
- package/build/personas/index.js.map +1 -0
- package/build/personas/lead.d.ts +33 -0
- package/build/personas/lead.js +51 -0
- package/build/personas/lead.js.map +1 -0
- package/build/personas/schemas.d.ts +313 -0
- package/build/personas/schemas.js +97 -0
- package/build/personas/schemas.js.map +1 -0
- package/build/prompts/consolidation/critique.md +59 -0
- package/build/prompts/consolidation/decision.md +51 -0
- package/build/prompts/consolidation/extraction.md +46 -0
- package/build/prompts/consolidation/synthesis.md +42 -0
- package/build/prompts/expert-rules.md +50 -0
- package/build/prompts/personas/dev-tooling.md +27 -0
- package/build/prompts/personas/devops.md +26 -0
- package/build/prompts/personas/distributed-systems.md +28 -0
- package/build/prompts/personas/graph-dba.md +27 -0
- package/build/prompts/personas/node-fullstack.md +27 -0
- package/build/prompts/personas/performance.md +26 -0
- package/build/prompts/personas/security.md +26 -0
- package/build/prompts/personas/test-architect.md +29 -0
- package/build/prompts/personas/test-quoted.md +14 -0
- package/build/prompts/personas/typescript.md +26 -0
- package/build/prompts/personas/ux-dx.md +29 -0
- package/build/prompts/workflow-rules.md +3 -0
- package/build/server.d.ts +24 -0
- package/build/server.js +181 -0
- package/build/server.js.map +1 -0
- package/build/services/cache.service.d.ts +49 -0
- package/build/services/cache.service.js +85 -0
- package/build/services/cache.service.js.map +1 -0
- package/build/services/council.service.d.ts +111 -0
- package/build/services/council.service.js +361 -0
- package/build/services/council.service.js.map +1 -0
- package/build/services/database.service.d.ts +70 -0
- package/build/services/database.service.js +221 -0
- package/build/services/database.service.js.map +1 -0
- package/build/services/formatter.service.d.ts +52 -0
- package/build/services/formatter.service.js +133 -0
- package/build/services/formatter.service.js.map +1 -0
- package/build/services/index.d.ts +18 -0
- package/build/services/index.js +13 -0
- package/build/services/index.js.map +1 -0
- package/build/services/openrouter.service.d.ts +58 -0
- package/build/services/openrouter.service.js +128 -0
- package/build/services/openrouter.service.js.map +1 -0
- package/build/services/persona.service.d.ts +43 -0
- package/build/services/persona.service.js +93 -0
- package/build/services/persona.service.js.map +1 -0
- package/build/services/prompt.service.d.ts +59 -0
- package/build/services/prompt.service.js +209 -0
- package/build/services/prompt.service.js.map +1 -0
- package/konsilio.schema.json +140 -0
- package/package.json +68 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Council Service - Two-Stage Consulting Pipeline
|
|
3
|
+
*
|
|
4
|
+
* Stage 1: Expert Analysis (parallel, prose output)
|
|
5
|
+
* Stage 2: Formatting (convert prose to structured JSON via FormatterService)
|
|
6
|
+
* Stage 3: Extraction (extract claims from expert reports)
|
|
7
|
+
* Stage 4: Critique (identify contradictions and weaknesses)
|
|
8
|
+
* Stage 5: Decision (accept/reject findings)
|
|
9
|
+
* Stage 6: Synthesis (assemble final blueprint)
|
|
10
|
+
*/
|
|
11
|
+
import { randomUUID } from 'node:crypto';
|
|
12
|
+
import { ExtractionPhaseOutputSchema, CritiquePhaseOutputSchema, DecisionPhaseOutputSchema } from '../personas/schemas.js';
|
|
13
|
+
/**
|
|
14
|
+
* CouncilService - Orchestrates two-stage expert analysis and consolidation
|
|
15
|
+
*/
|
|
16
|
+
export class CouncilService {
|
|
17
|
+
deps;
|
|
18
|
+
constructor(deps) {
|
|
19
|
+
this.deps = deps;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the model for a specific persona using 3-tier resolution:
|
|
23
|
+
* 1. Per-run override (personaModelsOverride)
|
|
24
|
+
* 2. Persona-level default (config.personaModels)
|
|
25
|
+
* 3. Global default (config.models.experts)
|
|
26
|
+
*/
|
|
27
|
+
resolvePersonaModel(personaId, options) {
|
|
28
|
+
// Tier 1: Per-run override
|
|
29
|
+
if (options?.personaModelsOverride?.[personaId]) {
|
|
30
|
+
return options.personaModelsOverride[personaId];
|
|
31
|
+
}
|
|
32
|
+
// Tier 2: Persona-level default in config
|
|
33
|
+
if (this.deps.config.personaModels?.[personaId]) {
|
|
34
|
+
return this.deps.config.personaModels[personaId];
|
|
35
|
+
}
|
|
36
|
+
// Tier 3: Global default
|
|
37
|
+
return this.deps.config.models.experts;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the effective token limit for a role
|
|
41
|
+
*/
|
|
42
|
+
resolveMaxTokens(role, options) {
|
|
43
|
+
if (role === 'experts' && options?.maxTokensOverride?.experts) {
|
|
44
|
+
return options.maxTokensOverride.experts;
|
|
45
|
+
}
|
|
46
|
+
if (role === 'lead' && options?.maxTokensOverride?.lead) {
|
|
47
|
+
return options.maxTokensOverride.lead;
|
|
48
|
+
}
|
|
49
|
+
return this.deps.config.maxTokens[role];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Run a council analysis with two-stage consolidation
|
|
53
|
+
*/
|
|
54
|
+
async run(params, options, correlationId) {
|
|
55
|
+
const log = correlationId ? this.deps.logger.withCorrelationId(correlationId) : this.deps.logger;
|
|
56
|
+
const totalStart = Date.now();
|
|
57
|
+
const sessionId = correlationId ?? randomUUID();
|
|
58
|
+
log.info('Starting council session', { sessionId, draftPlanLength: params.draftPlan.length });
|
|
59
|
+
if (!params.draftPlan.trim())
|
|
60
|
+
throw new Error('draft_plan cannot be empty');
|
|
61
|
+
if (params.draftPlan.length > this.deps.config.maxDraftPlanLength) {
|
|
62
|
+
throw new Error(`draft_plan too long (${params.draftPlan.length}/${this.deps.config.maxDraftPlanLength} chars)`);
|
|
63
|
+
}
|
|
64
|
+
// Resolve effective personas: per-run override or config defaults
|
|
65
|
+
const effectivePersonaIds = options?.personaOverride ?? this.deps.config.enabledPersonaIds;
|
|
66
|
+
// Resolve consolidation model: per-run override or config default
|
|
67
|
+
const consolidationModel = options?.consolidationModelOverride ?? this.deps.config.models.lead;
|
|
68
|
+
// Create personas with per-persona model resolution (3-tier)
|
|
69
|
+
const personas = effectivePersonaIds.map((id) => {
|
|
70
|
+
const model = this.resolvePersonaModel(id, options);
|
|
71
|
+
return this.deps.personaService.createExpert(id, model);
|
|
72
|
+
});
|
|
73
|
+
if (personas.length < 2)
|
|
74
|
+
throw new Error(`At least 2 personas required. Found: ${effectivePersonaIds.join(', ')}`);
|
|
75
|
+
// Stage 1: Expert Analysis (parallel, prose output)
|
|
76
|
+
log.debug('Stage 1: Expert Analysis (prose)');
|
|
77
|
+
const userMessage = this.buildUserMessage(params);
|
|
78
|
+
const expertPromises = personas.map((p) => {
|
|
79
|
+
const model = this.resolvePersonaModel(p.id, options);
|
|
80
|
+
const maxTokens = this.resolveMaxTokens('experts', options);
|
|
81
|
+
return this.callExpert(p, model, userMessage, this.deps.config.timeouts.expertMs, maxTokens, log);
|
|
82
|
+
});
|
|
83
|
+
const expertResults = await Promise.allSettled(expertPromises);
|
|
84
|
+
const successfulProseReports = [];
|
|
85
|
+
const failedExperts = [];
|
|
86
|
+
for (let i = 0; i < expertResults.length; i++) {
|
|
87
|
+
const result = expertResults[i];
|
|
88
|
+
if (result.status === 'fulfilled')
|
|
89
|
+
successfulProseReports.push(result.value);
|
|
90
|
+
else
|
|
91
|
+
failedExperts.push(`${personas[i].emoji} ${personas[i].name}: ${result.reason}`);
|
|
92
|
+
}
|
|
93
|
+
if (successfulProseReports.length < 2)
|
|
94
|
+
throw new Error(`Too many expert failures. ${failedExperts.join('\n')}`);
|
|
95
|
+
log.debug('Expert prose analysis complete', { succeeded: successfulProseReports.length, failed: failedExperts.length });
|
|
96
|
+
// Stage 2: Format prose to structured JSON
|
|
97
|
+
log.debug('Stage 2: Formatting prose to structured JSON');
|
|
98
|
+
const formatStart = Date.now();
|
|
99
|
+
const formatResults = await Promise.allSettled(successfulProseReports.map((r) => this.deps.formatterService.formatProse(r.prose, r.persona.id, correlationId)));
|
|
100
|
+
const successfulReports = [];
|
|
101
|
+
const formattingErrors = [];
|
|
102
|
+
let formatSuccessCount = 0;
|
|
103
|
+
for (let i = 0; i < formatResults.length; i++) {
|
|
104
|
+
const result = formatResults[i];
|
|
105
|
+
const proseReport = successfulProseReports[i];
|
|
106
|
+
if (result.status === 'fulfilled') {
|
|
107
|
+
const formatResult = result.value;
|
|
108
|
+
successfulReports.push({
|
|
109
|
+
personaId: proseReport.persona.id,
|
|
110
|
+
personaName: proseReport.persona.name,
|
|
111
|
+
personaEmoji: proseReport.persona.emoji,
|
|
112
|
+
structuredOutput: formatResult.output,
|
|
113
|
+
rawContent: formatResult.originalProse,
|
|
114
|
+
durationMs: proseReport.durationMs + formatResult.durationMs,
|
|
115
|
+
modelUsed: this.deps.config.models.formatter
|
|
116
|
+
});
|
|
117
|
+
formatSuccessCount++;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
formattingErrors.push(`${proseReport.persona.name}: ${result.reason}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const totalFormattingTimeMs = Date.now() - formatStart;
|
|
124
|
+
const formattingDetails = {
|
|
125
|
+
totalFormattingTimeMs,
|
|
126
|
+
formattingSuccessRate: formatSuccessCount / successfulProseReports.length,
|
|
127
|
+
formattingErrors
|
|
128
|
+
};
|
|
129
|
+
log.debug('Formatting complete', { successRate: formattingDetails.formattingSuccessRate, errors: formattingErrors.length });
|
|
130
|
+
if (successfulReports.length < 2)
|
|
131
|
+
throw new Error(`Too many expert failures after formatting. ${failedExperts.join('\n')}`);
|
|
132
|
+
log.info('Expert analysis complete', { succeeded: successfulReports.length, failed: failedExperts.length });
|
|
133
|
+
// Stage 3: Extraction
|
|
134
|
+
log.debug('Stage 3: Extraction');
|
|
135
|
+
const extractionOutput = await this.runExtractionPhase(successfulReports, consolidationModel, log);
|
|
136
|
+
// Stage 4: Critique
|
|
137
|
+
log.debug('Stage 4: Critique');
|
|
138
|
+
const critiqueOutput = await this.runCritiquePhase(successfulReports, extractionOutput, params, consolidationModel, log);
|
|
139
|
+
// Stage 5: Decision
|
|
140
|
+
log.debug('Stage 5: Decision');
|
|
141
|
+
const decisionOutput = await this.runDecisionPhase(successfulReports, critiqueOutput, consolidationModel, log);
|
|
142
|
+
// Stage 6: Synthesis
|
|
143
|
+
log.debug('Stage 6: Synthesis');
|
|
144
|
+
const synthesisOutput = await this.runSynthesisPhase(successfulReports, decisionOutput, params, consolidationModel, log);
|
|
145
|
+
// Build model summary: show which models were used per persona
|
|
146
|
+
const modelSummary = personas.map(p => {
|
|
147
|
+
const model = this.resolvePersonaModel(p.id, options);
|
|
148
|
+
return `${p.id}:${model}`;
|
|
149
|
+
}).join(', ');
|
|
150
|
+
const totalDurationMs = Date.now() - totalStart;
|
|
151
|
+
let output = failedExperts.length > 0 ? `> ⚠️ ${failedExperts.length} expert(s) failed\n\n` : '';
|
|
152
|
+
output += `> 📝 Formatted: ${(formattingDetails.formattingSuccessRate * 100).toFixed(0)}% success (${(formattingDetails.totalFormattingTimeMs / 1000).toFixed(1)}s)\n`;
|
|
153
|
+
output += `> 👑 Council: ${successfulReports.length} experts [${modelSummary}] → 4-phase consolidation (${consolidationModel})\n`;
|
|
154
|
+
output += `> ⏱️ ${(totalDurationMs / 1000).toFixed(1)}s | Accepted: ${decisionOutput.acceptedCount} | Rejected: ${decisionOutput.rejectedCount}\n\n---\n\n`;
|
|
155
|
+
output += synthesisOutput.blueprint;
|
|
156
|
+
const result = {
|
|
157
|
+
sessionId,
|
|
158
|
+
expertReports: successfulReports,
|
|
159
|
+
extractionOutput,
|
|
160
|
+
critiqueOutput,
|
|
161
|
+
decisionOutput,
|
|
162
|
+
synthesisOutput,
|
|
163
|
+
finalBlueprint: output,
|
|
164
|
+
consolidationModel,
|
|
165
|
+
totalDurationMs,
|
|
166
|
+
formattingDetails
|
|
167
|
+
};
|
|
168
|
+
try {
|
|
169
|
+
this.deps.databaseService.saveCouncilResult(result, params.draftPlan, params.techStack, params.contextConstraints, correlationId);
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
log.warn('Failed to save to database', { error: err instanceof Error ? err.message : String(err) });
|
|
173
|
+
}
|
|
174
|
+
log.info('Council session complete', { sessionId, totalDurationMs });
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Call an expert persona for prose analysis
|
|
179
|
+
*/
|
|
180
|
+
async callExpert(persona, model, userMessage, timeoutMs, maxTokens, log) {
|
|
181
|
+
const start = Date.now();
|
|
182
|
+
const messages = [
|
|
183
|
+
{ role: 'system', content: persona.systemPrompt },
|
|
184
|
+
{ role: 'user', content: userMessage }
|
|
185
|
+
];
|
|
186
|
+
try {
|
|
187
|
+
const rawContent = await this.deps.openRouterService.call({
|
|
188
|
+
model,
|
|
189
|
+
messages,
|
|
190
|
+
maxTokens,
|
|
191
|
+
temperature: 0.3,
|
|
192
|
+
timeoutMs
|
|
193
|
+
});
|
|
194
|
+
log.debug('Expert prose analysis complete', { personaId: persona.id, model, contentLength: rawContent.length });
|
|
195
|
+
return { persona, prose: rawContent, durationMs: Date.now() - start };
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
log.error('Expert analysis failed', { personaId: persona.id, model, error: err instanceof Error ? err.message : String(err) });
|
|
199
|
+
throw new Error(`${persona.name} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Stage 3: Extraction - Extract structured claims from expert reports
|
|
204
|
+
*/
|
|
205
|
+
async runExtractionPhase(reports, model, log) {
|
|
206
|
+
const lead = this.deps.personaService.createLead('extraction');
|
|
207
|
+
const expertReportsText = reports.map(r => `## ${r.personaEmoji} ${r.personaName}\n\n${JSON.stringify(r.structuredOutput, null, 2)}`).join('\n\n---\n\n');
|
|
208
|
+
const messages = [
|
|
209
|
+
{ role: 'system', content: lead.systemPrompt },
|
|
210
|
+
{ role: 'user', content: `Extract all findings from these expert reports:\n\n${expertReportsText}` }
|
|
211
|
+
];
|
|
212
|
+
const rawOutput = await this.deps.openRouterService.call({
|
|
213
|
+
model,
|
|
214
|
+
messages,
|
|
215
|
+
maxTokens: this.deps.config.maxTokens.lead,
|
|
216
|
+
temperature: 0.2,
|
|
217
|
+
timeoutMs: this.deps.config.timeouts.leadMs
|
|
218
|
+
});
|
|
219
|
+
const cleaned = this.cleanJsonOutput(rawOutput);
|
|
220
|
+
try {
|
|
221
|
+
const parsed = JSON.parse(cleaned);
|
|
222
|
+
const output = ExtractionPhaseOutputSchema.parse(parsed);
|
|
223
|
+
log.debug('Extraction complete', { totalFindings: output.totalFindings });
|
|
224
|
+
return output;
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
log.error('Failed to parse extraction JSON', {
|
|
228
|
+
rawLength: rawOutput.length,
|
|
229
|
+
cleanedLength: cleaned.length,
|
|
230
|
+
rawPreview: rawOutput.slice(0, 500),
|
|
231
|
+
error: err instanceof Error ? err.message : String(err)
|
|
232
|
+
});
|
|
233
|
+
throw new Error(`Extraction phase: failed to parse JSON. ${err instanceof Error ? err.message : String(err)}`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Stage 4: Critique - Analyze for contradictions and weaknesses
|
|
238
|
+
*/
|
|
239
|
+
async runCritiquePhase(reports, extraction, params, model, log) {
|
|
240
|
+
const lead = this.deps.personaService.createLead('critique');
|
|
241
|
+
const context = `## Original Draft Plan\n\n${params.draftPlan}\n\n## Extracted Claims\n\n${JSON.stringify(extraction, null, 2)}`;
|
|
242
|
+
const messages = [
|
|
243
|
+
{ role: 'system', content: lead.systemPrompt },
|
|
244
|
+
{ role: 'user', content: context }
|
|
245
|
+
];
|
|
246
|
+
const rawOutput = await this.deps.openRouterService.call({
|
|
247
|
+
model,
|
|
248
|
+
messages,
|
|
249
|
+
maxTokens: this.deps.config.maxTokens.lead,
|
|
250
|
+
temperature: 0.3,
|
|
251
|
+
timeoutMs: this.deps.config.timeouts.leadMs
|
|
252
|
+
});
|
|
253
|
+
const cleaned = this.cleanJsonOutput(rawOutput);
|
|
254
|
+
try {
|
|
255
|
+
const parsed = JSON.parse(cleaned);
|
|
256
|
+
const output = CritiquePhaseOutputSchema.parse(parsed);
|
|
257
|
+
log.debug('Critique complete', { contradictions: output.contradictions.length, unsupportedClaims: output.unsupportedClaims.length });
|
|
258
|
+
return output;
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
log.error('Failed to parse critique JSON', {
|
|
262
|
+
rawLength: rawOutput.length,
|
|
263
|
+
cleanedLength: cleaned.length,
|
|
264
|
+
rawPreview: rawOutput.slice(0, 500),
|
|
265
|
+
error: err instanceof Error ? err.message : String(err)
|
|
266
|
+
});
|
|
267
|
+
throw new Error(`Critique phase: failed to parse JSON. ${err instanceof Error ? err.message : String(err)}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Stage 5: Decision - Accept/reject findings explicitly
|
|
272
|
+
*/
|
|
273
|
+
async runDecisionPhase(reports, critique, model, log) {
|
|
274
|
+
const lead = this.deps.personaService.createLead('decision');
|
|
275
|
+
const allFindings = reports.flatMap(r => r.structuredOutput.findings);
|
|
276
|
+
const context = `## All Findings\n\n${JSON.stringify(allFindings, null, 2)}\n\n## Critique Analysis\n\n${JSON.stringify(critique, null, 2)}`;
|
|
277
|
+
const messages = [
|
|
278
|
+
{ role: 'system', content: lead.systemPrompt },
|
|
279
|
+
{ role: 'user', content: context }
|
|
280
|
+
];
|
|
281
|
+
const rawOutput = await this.deps.openRouterService.call({
|
|
282
|
+
model,
|
|
283
|
+
messages,
|
|
284
|
+
maxTokens: this.deps.config.maxTokens.lead,
|
|
285
|
+
temperature: 0.2,
|
|
286
|
+
timeoutMs: this.deps.config.timeouts.leadMs
|
|
287
|
+
});
|
|
288
|
+
const cleaned = this.cleanJsonOutput(rawOutput);
|
|
289
|
+
try {
|
|
290
|
+
const parsed = JSON.parse(cleaned);
|
|
291
|
+
const output = DecisionPhaseOutputSchema.parse(parsed);
|
|
292
|
+
log.debug('Decision complete', { accepted: output.acceptedCount, rejected: output.rejectedCount });
|
|
293
|
+
return output;
|
|
294
|
+
}
|
|
295
|
+
catch (err) {
|
|
296
|
+
log.error('Failed to parse decision JSON', {
|
|
297
|
+
rawLength: rawOutput.length,
|
|
298
|
+
cleanedLength: cleaned.length,
|
|
299
|
+
rawPreview: rawOutput.slice(0, 500),
|
|
300
|
+
error: err instanceof Error ? err.message : String(err)
|
|
301
|
+
});
|
|
302
|
+
throw new Error(`Decision phase: failed to parse JSON. ${err instanceof Error ? err.message : String(err)}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Stage 6: Synthesis - Assemble final blueprint from accepted findings
|
|
307
|
+
*/
|
|
308
|
+
async runSynthesisPhase(reports, decision, params, model, log) {
|
|
309
|
+
const lead = this.deps.personaService.createLead('synthesis');
|
|
310
|
+
const acceptedFindingIds = new Set(decision.decisions.filter(d => d.action === 'ACCEPT').map(d => d.findingId));
|
|
311
|
+
const acceptedFindings = [];
|
|
312
|
+
const attributions = {};
|
|
313
|
+
for (const report of reports) {
|
|
314
|
+
for (const finding of report.structuredOutput.findings) {
|
|
315
|
+
if (acceptedFindingIds.has(finding.id)) {
|
|
316
|
+
acceptedFindings.push(finding);
|
|
317
|
+
attributions[finding.id] = report.personaId;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
const context = `## Original Draft Plan\n\n${params.draftPlan}\n\n${params.techStack ? `## Tech Stack\n\n${params.techStack}\n\n` : ''}## Accepted Findings\n\n${JSON.stringify(acceptedFindings, null, 2)}\n\n## Attributions\n\n${JSON.stringify(attributions, null, 2)}`;
|
|
322
|
+
const messages = [
|
|
323
|
+
{ role: 'system', content: lead.systemPrompt },
|
|
324
|
+
{ role: 'user', content: context }
|
|
325
|
+
];
|
|
326
|
+
const blueprint = await this.deps.openRouterService.call({
|
|
327
|
+
model,
|
|
328
|
+
messages,
|
|
329
|
+
maxTokens: 8192,
|
|
330
|
+
temperature: 0.4,
|
|
331
|
+
timeoutMs: this.deps.config.timeouts.leadMs
|
|
332
|
+
});
|
|
333
|
+
log.debug('Synthesis complete', { acceptedFindings: acceptedFindings.length });
|
|
334
|
+
return { blueprint, acceptedFindings, attributions };
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Build user message for expert analysis
|
|
338
|
+
*/
|
|
339
|
+
buildUserMessage(params) {
|
|
340
|
+
let msg = `## Draft Plan\n\n${params.draftPlan}`;
|
|
341
|
+
if (params.techStack)
|
|
342
|
+
msg += `\n\n## Tech Stack\n\n${params.techStack}`;
|
|
343
|
+
if (params.contextConstraints)
|
|
344
|
+
msg += `\n\n## Context Constraints\n\n${params.contextConstraints}`;
|
|
345
|
+
return msg;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Clean JSON output from LLM responses (strip markdown code fences)
|
|
349
|
+
*/
|
|
350
|
+
cleanJsonOutput(raw) {
|
|
351
|
+
let cleaned = raw.trim();
|
|
352
|
+
if (cleaned.startsWith('```json')) {
|
|
353
|
+
cleaned = cleaned.replace(/^```json\s*/, '').replace(/\s*```$/, '');
|
|
354
|
+
}
|
|
355
|
+
else if (cleaned.startsWith('```')) {
|
|
356
|
+
cleaned = cleaned.replace(/^```\s*/, '').replace(/\s*```$/, '');
|
|
357
|
+
}
|
|
358
|
+
return cleaned;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
//# sourceMappingURL=council.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"council.service.js","sourceRoot":"","sources":["../../src/services/council.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Service
|
|
3
|
+
*
|
|
4
|
+
* Provides SQLite database operations for session persistence using sql.js (WASM).
|
|
5
|
+
* Designed for dependency injection to enable testing.
|
|
6
|
+
*/
|
|
7
|
+
import type { Logger } from '../logger.js';
|
|
8
|
+
import type { CouncilResult } from '../personas/schemas.js';
|
|
9
|
+
export interface DatabaseServiceConfig {
|
|
10
|
+
dbPath: string;
|
|
11
|
+
maxHistorySessions?: number;
|
|
12
|
+
}
|
|
13
|
+
export interface SessionSummary {
|
|
14
|
+
id: string;
|
|
15
|
+
created_at: string;
|
|
16
|
+
draft_plan_summary: string | null;
|
|
17
|
+
tech_stack: string | null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* DatabaseService - Handles SQLite persistence via sql.js (WASM)
|
|
21
|
+
*
|
|
22
|
+
* Uses an in-memory database that is loaded from / saved to disk.
|
|
23
|
+
* All queries run against the in-memory copy; changes are persisted
|
|
24
|
+
* explicitly after writes.
|
|
25
|
+
*/
|
|
26
|
+
export declare class DatabaseService {
|
|
27
|
+
private db;
|
|
28
|
+
private readonly dbPath;
|
|
29
|
+
private readonly maxHistorySessions;
|
|
30
|
+
private readonly logger;
|
|
31
|
+
private constructor();
|
|
32
|
+
/**
|
|
33
|
+
* Factory method to create and initialize the DatabaseService.
|
|
34
|
+
* Async because sql.js WASM loading and DB file reading are async.
|
|
35
|
+
*/
|
|
36
|
+
static create(config: DatabaseServiceConfig, logger: Logger, schema: string): Promise<DatabaseService>;
|
|
37
|
+
/**
|
|
38
|
+
* Initialize database: load WASM, read existing DB file (or create new), apply schema
|
|
39
|
+
*/
|
|
40
|
+
private initialize;
|
|
41
|
+
/**
|
|
42
|
+
* Persist the in-memory database to disk
|
|
43
|
+
*/
|
|
44
|
+
private save;
|
|
45
|
+
/**
|
|
46
|
+
* Check database health
|
|
47
|
+
*/
|
|
48
|
+
checkHealth(): {
|
|
49
|
+
status: 'healthy' | 'unhealthy';
|
|
50
|
+
latencyMs: number;
|
|
51
|
+
error?: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Save a council session result
|
|
55
|
+
*/
|
|
56
|
+
saveCouncilResult(result: CouncilResult, draftPlan: string, techStack?: string, constraints?: string, correlationId?: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Get recent sessions
|
|
59
|
+
*/
|
|
60
|
+
getRecentSessions(limit?: number): SessionSummary[];
|
|
61
|
+
/**
|
|
62
|
+
* Get a session's blueprint
|
|
63
|
+
*/
|
|
64
|
+
getSessionBlueprint(sessionId: string): string | null;
|
|
65
|
+
/**
|
|
66
|
+
* Close database (no-op for sql.js, but we clear the reference)
|
|
67
|
+
*/
|
|
68
|
+
close(): void;
|
|
69
|
+
private pruneOldSessions;
|
|
70
|
+
}
|