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-prompt"
|
||||||
export * from "./council-orchestrator"
|
export * from "./council-orchestrator"
|
||||||
export * from "./council-result-collector"
|
export * from "./council-result-collector"
|
||||||
|
export * from "./synthesis-types"
|
||||||
|
export * from "./synthesis-prompt"
|
||||||
|
export * from "./synthesis-formatter"
|
||||||
export * from "../../config/schema/athena"
|
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