feat(03-01): implement synthesis contracts and formatter pipeline
- Add synthesis result contracts with agreement, provenance, and Athena assessment fields\n- Add synthesis prompt builder and council-response formatter with failure-aware provenance output
This commit is contained in:
parent
d4e20b9311
commit
95f133ff63
@ -3,4 +3,7 @@ export * from "./model-parser"
|
||||
export * from "./council-prompt"
|
||||
export * from "./council-orchestrator"
|
||||
export * from "./council-result-collector"
|
||||
export * from "./synthesis-types"
|
||||
export * from "./synthesis-prompt"
|
||||
export * from "./synthesis-formatter"
|
||||
export * from "../../config/schema/athena"
|
||||
|
||||
48
src/agents/athena/synthesis-formatter.ts
Normal file
48
src/agents/athena/synthesis-formatter.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import type { CouncilExecutionResult } from "./types"
|
||||
|
||||
export function formatCouncilResultsForSynthesis(result: CouncilExecutionResult): string {
|
||||
const completedResponses = result.responses.filter((response) => response.status === "completed")
|
||||
|
||||
if (completedResponses.length === 0) {
|
||||
return [
|
||||
"# Council Responses for Synthesis",
|
||||
`Question: ${result.question}`,
|
||||
"No successful responses from council members.",
|
||||
"Review failed member details below for provenance.",
|
||||
...result.responses.map((response) => {
|
||||
const memberName = response.member.name ?? response.member.model
|
||||
return [
|
||||
`## Member: ${memberName} (${response.status})`,
|
||||
`Model: ${response.member.model}`,
|
||||
`Status: ${response.status}`,
|
||||
`Duration: ${response.durationMs}ms`,
|
||||
`Error: ${response.error ?? "No error message provided"}`,
|
||||
].join("\n")
|
||||
}),
|
||||
].join("\n\n")
|
||||
}
|
||||
|
||||
const sections = result.responses.map((response) => {
|
||||
const memberName = response.member.name ?? response.member.model
|
||||
const header = [
|
||||
`## Member: ${memberName} (${response.status})`,
|
||||
`Model: ${response.member.model}`,
|
||||
`Status: ${response.status}`,
|
||||
`Duration: ${response.durationMs}ms`,
|
||||
]
|
||||
|
||||
if (response.status === "completed") {
|
||||
const responseBody = response.response?.trim() ? response.response : "No response content provided"
|
||||
return [...header, "Response:", responseBody].join("\n")
|
||||
}
|
||||
|
||||
return [...header, `Error: ${response.error ?? "No error message provided"}`].join("\n")
|
||||
})
|
||||
|
||||
return [
|
||||
"# Council Responses for Synthesis",
|
||||
`Question: ${result.question}`,
|
||||
`Completed responses: ${result.completedCount}/${result.totalMembers}`,
|
||||
...sections,
|
||||
].join("\n\n")
|
||||
}
|
||||
44
src/agents/athena/synthesis-prompt.ts
Normal file
44
src/agents/athena/synthesis-prompt.ts
Normal file
@ -0,0 +1,44 @@
|
||||
export function buildSynthesisPrompt(formattedResponses: string, question: string, completedCount: number): string {
|
||||
return `You are Athena, the synthesis lead for a multi-model council. Your job is to merge independent model outputs into a single, evidence-grounded synthesis.
|
||||
|
||||
## Original Question
|
||||
${question}
|
||||
|
||||
## Council Responses
|
||||
${formattedResponses}
|
||||
|
||||
## Your Responsibilities
|
||||
1. Identify distinct findings across all completed member responses.
|
||||
2. Group findings that refer to the same underlying issue (semantic similarity, not exact wording).
|
||||
3. Classify agreementLevel for each finding using ${completedCount} completed member(s):
|
||||
- unanimous: all completed members reported the finding
|
||||
- majority: more than 50% of completed members reported the finding
|
||||
- minority: 2 or more members reported it, but not a majority
|
||||
- solo: only 1 member reported it
|
||||
4. Add AthenaAssessment for each finding:
|
||||
- agrees: whether you agree with the finding
|
||||
- rationale: concise reason for agreement or disagreement
|
||||
5. Set isFalsePositiveRisk:
|
||||
- true for solo findings (likely false positives unless strongly supported)
|
||||
- false for findings reported by multiple members
|
||||
|
||||
## Output Contract
|
||||
Return JSON only with this shape:
|
||||
{
|
||||
"findings": [
|
||||
{
|
||||
"summary": "string",
|
||||
"details": "string",
|
||||
"agreementLevel": "unanimous | majority | minority | solo",
|
||||
"reportedBy": ["model/name"],
|
||||
"assessment": {
|
||||
"agrees": true,
|
||||
"rationale": "string"
|
||||
},
|
||||
"isFalsePositiveRisk": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
The finding object must match the SynthesizedFinding type exactly. Keep findings concise, concrete, and tied to source responses.`
|
||||
}
|
||||
31
src/agents/athena/synthesis-types.ts
Normal file
31
src/agents/athena/synthesis-types.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import type { AgreementLevel, CouncilMemberConfig, CouncilMemberStatus } from "./types"
|
||||
|
||||
export interface AthenaAssessment {
|
||||
agrees: boolean
|
||||
rationale: string
|
||||
}
|
||||
|
||||
export interface SynthesizedFinding {
|
||||
summary: string
|
||||
details: string
|
||||
agreementLevel: AgreementLevel
|
||||
reportedBy: string[]
|
||||
assessment: AthenaAssessment
|
||||
isFalsePositiveRisk: boolean
|
||||
}
|
||||
|
||||
export interface MemberProvenance {
|
||||
member: CouncilMemberConfig
|
||||
status: CouncilMemberStatus
|
||||
rawResponse?: string
|
||||
durationMs: number
|
||||
}
|
||||
|
||||
export interface SynthesisResult {
|
||||
question: string
|
||||
findings: SynthesizedFinding[]
|
||||
memberProvenance: MemberProvenance[]
|
||||
totalFindings: number
|
||||
consensusCount: number
|
||||
outlierCount: number
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user