feat(councils): add deterministic councils engine and council.run tool
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const COUNCIL_SCHEMA_VERSION = '1.0.0';
|
||||
export const COUNCIL_PIPELINE_VERSION = '1.0.0';
|
||||
|
||||
export const councilGroupSchema = z.enum(['D', 'P']);
|
||||
export type CouncilGroup = z.infer<typeof councilGroupSchema>;
|
||||
|
||||
export const stopReasonSchema = z.enum([
|
||||
'max_rounds',
|
||||
'convergence',
|
||||
'bridge_validation_failed',
|
||||
'grounding_failed',
|
||||
'meta_validation_failed',
|
||||
]);
|
||||
|
||||
export const validationFailureReasonSchema = z.enum([
|
||||
'schema_invalid',
|
||||
'unknown_id',
|
||||
'cap_exceeded',
|
||||
'repair_failed',
|
||||
'parse_failed',
|
||||
]);
|
||||
|
||||
export const droppedReasonSchema = z.enum([
|
||||
'cap_top_ideas',
|
||||
'cap_field_bullets',
|
||||
'cap_entry_chars',
|
||||
'cap_total_chars',
|
||||
'invalid_reference',
|
||||
'grounding_failed',
|
||||
]);
|
||||
|
||||
export const rejectionReasonCodeSchema = z.enum([
|
||||
'low_score',
|
||||
'high_risk',
|
||||
'insufficient_grounding',
|
||||
'duplicate',
|
||||
'out_of_scope',
|
||||
'unknown_id',
|
||||
'other',
|
||||
]);
|
||||
|
||||
const schemaVersionField = z.literal(COUNCIL_SCHEMA_VERSION);
|
||||
|
||||
export const ideaContentSchema = z.object({
|
||||
title: z.string().min(1),
|
||||
hypothesis: z.string().min(1),
|
||||
mechanism: z.string().min(1),
|
||||
expected_outcome: z.string().min(1),
|
||||
}).strict();
|
||||
|
||||
export const ideaGroundingSchema = z.object({
|
||||
mve: z.string().min(1),
|
||||
constraints: z.array(z.string().min(1)).min(1),
|
||||
falsifiability_checks: z.array(z.string().min(1)).min(1),
|
||||
}).strict();
|
||||
|
||||
export const ideaCardSchema = z.object({
|
||||
schema_version: schemaVersionField,
|
||||
idea_id: z.string().min(1),
|
||||
group: councilGroupSchema,
|
||||
round: z.number().int().min(1),
|
||||
content: ideaContentSchema,
|
||||
grounding: ideaGroundingSchema.optional(),
|
||||
grounding_failed: z.boolean().optional(),
|
||||
}).strict();
|
||||
|
||||
export const scoreSetSchema = z.object({
|
||||
novelty: z.number().int().min(0).max(100),
|
||||
feasibility: z.number().int().min(0).max(100),
|
||||
impact: z.number().int().min(0).max(100),
|
||||
testability: z.number().int().min(0).max(100),
|
||||
}).strict();
|
||||
|
||||
export const ideaAssessmentSchema = z.object({
|
||||
schema_version: schemaVersionField,
|
||||
idea_id: z.string().min(1),
|
||||
scores: scoreSetSchema,
|
||||
decision: z.enum(['shortlist', 'hold', 'reject']),
|
||||
notes: z.string().min(1),
|
||||
}).strict();
|
||||
|
||||
export const bridgeIdeaSchema = z.object({
|
||||
idea_id: z.string().min(1),
|
||||
mechanism: z.string().min(1),
|
||||
rationale: z.string().min(1),
|
||||
}).strict();
|
||||
|
||||
export const bridgePacketSchema = z.object({
|
||||
schema_version: schemaVersionField,
|
||||
from_group: councilGroupSchema,
|
||||
to_group: councilGroupSchema,
|
||||
round: z.number().int().min(1),
|
||||
top_ideas: z.array(bridgeIdeaSchema),
|
||||
assumptions: z.array(z.string().min(1)),
|
||||
risks: z.array(z.string().min(1)),
|
||||
asks: z.array(z.string().min(1)),
|
||||
what_to_steal: z.array(z.string().min(1)),
|
||||
}).strict();
|
||||
|
||||
export const councilBriefSchema = z.object({
|
||||
schema_version: schemaVersionField,
|
||||
group: councilGroupSchema,
|
||||
round: z.number().int().min(1),
|
||||
ideas: z.array(ideaCardSchema),
|
||||
assessments: z.array(ideaAssessmentSchema),
|
||||
shortlist: z.array(z.string().min(1)),
|
||||
assumptions: z.array(z.string().min(1)),
|
||||
risks: z.array(z.string().min(1)),
|
||||
asks: z.array(z.string().min(1)),
|
||||
what_to_steal: z.array(z.string().min(1)),
|
||||
convergence_signal: z.boolean(),
|
||||
novelty_score: z.number().int().min(0).max(100),
|
||||
repetition_rate: z.number().int().min(0).max(100),
|
||||
}).strict();
|
||||
|
||||
export const councilDiffSchema = z.object({
|
||||
schema_version: schemaVersionField,
|
||||
group: councilGroupSchema,
|
||||
from_round: z.number().int().min(1),
|
||||
to_round: z.number().int().min(1),
|
||||
idea_added: z.array(z.string().min(1)),
|
||||
idea_removed: z.array(z.string().min(1)),
|
||||
shortlist_added: z.array(z.string().min(1)),
|
||||
shortlist_removed: z.array(z.string().min(1)),
|
||||
score_changes: z.array(z.object({
|
||||
idea_id: z.string().min(1),
|
||||
from_total: z.number().int(),
|
||||
to_total: z.number().int(),
|
||||
}).strict()),
|
||||
assumptions_added: z.array(z.string().min(1)),
|
||||
assumptions_removed: z.array(z.string().min(1)),
|
||||
mve_changed: z.array(z.string().min(1)),
|
||||
}).strict();
|
||||
|
||||
export const mergeRecordSchema = z.object({
|
||||
sources: z.array(z.string().min(1)).min(2),
|
||||
result_title: z.string().min(1),
|
||||
rationale: z.string().min(1),
|
||||
}).strict();
|
||||
|
||||
export const metaSelectionSchema = z.object({
|
||||
schema_version: schemaVersionField,
|
||||
selected_primary: z.array(z.string().min(1)),
|
||||
selected_secondary: z.array(z.string().min(1)),
|
||||
merges: z.array(mergeRecordSchema).optional(),
|
||||
rejections: z.array(z.object({
|
||||
idea_id: z.string().min(1),
|
||||
reason_code: rejectionReasonCodeSchema,
|
||||
}).strict()),
|
||||
open_questions: z.array(z.string().min(1)),
|
||||
next_experiments: z.array(z.string().min(1)),
|
||||
}).strict();
|
||||
|
||||
export const councilTraceEventSchema = z.object({
|
||||
schema_version: schemaVersionField,
|
||||
event_id: z.string().min(1),
|
||||
phase_index: z.number().int().min(1),
|
||||
call_id: z.string().min(1),
|
||||
group: councilGroupSchema.optional(),
|
||||
round: z.number().int().min(1).optional(),
|
||||
prompt_payload_hash: z.string().length(64),
|
||||
artifact_hash: z.string().length(64).optional(),
|
||||
token_usage: z.object({
|
||||
inputTokens: z.number().int().min(0),
|
||||
outputTokens: z.number().int().min(0),
|
||||
}).strict().optional(),
|
||||
dropped_reason: droppedReasonSchema.optional(),
|
||||
validation_failure: validationFailureReasonSchema.optional(),
|
||||
}).strict();
|
||||
|
||||
export const stopSnapshotSchema = z.object({
|
||||
stop_reason: stopReasonSchema,
|
||||
round_reached: z.number().int().min(1),
|
||||
final_shortlist_D: z.array(z.string().min(1)),
|
||||
final_shortlist_P: z.array(z.string().min(1)),
|
||||
bridge_validated: z.boolean(),
|
||||
grounding_failures_count: z.number().int().min(0),
|
||||
}).strict();
|
||||
|
||||
export const councilRunResultSchema = z.object({
|
||||
pipeline_version: z.literal(COUNCIL_PIPELINE_VERSION),
|
||||
input_hash: z.string().length(64),
|
||||
brief_D_v1: councilBriefSchema,
|
||||
brief_P_v1: councilBriefSchema,
|
||||
brief_D_v2: councilBriefSchema,
|
||||
brief_P_v2: councilBriefSchema,
|
||||
diff_D: councilDiffSchema,
|
||||
diff_P: councilDiffSchema,
|
||||
bridge_D_to_P: bridgePacketSchema,
|
||||
bridge_P_to_D: bridgePacketSchema,
|
||||
meta: metaSelectionSchema,
|
||||
stop_snapshot: stopSnapshotSchema,
|
||||
trace: z.array(councilTraceEventSchema),
|
||||
}).strict();
|
||||
|
||||
export const councilRunInputSchema = z.object({
|
||||
task: z.string().min(1),
|
||||
constraints: z.union([z.string().min(1), z.record(z.string(), z.unknown())]).optional(),
|
||||
success_definition: z.string().min(1).optional(),
|
||||
budget: z.record(z.string(), z.unknown()).optional(),
|
||||
timebox: z.union([z.string().min(1), z.number().positive()]).optional(),
|
||||
output_format: z.string().min(1).optional(),
|
||||
max_rounds: z.number().int().min(1).max(6).optional(),
|
||||
session_id: z.string().min(1).optional(),
|
||||
}).strict();
|
||||
|
||||
export const ideationOutputSchema = z.object({
|
||||
ideas: z.array(ideaContentSchema).min(1),
|
||||
}).strict();
|
||||
|
||||
export const assessmentOutputSchema = z.object({
|
||||
assessments: z.array(z.object({
|
||||
idea_id: z.string().min(1),
|
||||
scores: scoreSetSchema,
|
||||
decision: z.enum(['shortlist', 'hold', 'reject']),
|
||||
notes: z.string().min(1),
|
||||
}).strict()),
|
||||
assumptions: z.array(z.string().min(1)),
|
||||
risks: z.array(z.string().min(1)),
|
||||
asks: z.array(z.string().min(1)),
|
||||
what_to_steal: z.array(z.string().min(1)),
|
||||
convergence_signal: z.boolean(),
|
||||
novelty_score: z.number().int().min(0).max(100),
|
||||
repetition_rate: z.number().int().min(0).max(100),
|
||||
}).strict();
|
||||
|
||||
export const groundingOutputSchema = z.object({
|
||||
grounded: z.array(z.object({
|
||||
idea_id: z.string().min(1),
|
||||
mve: z.string().min(1),
|
||||
constraints: z.array(z.string().min(1)).min(1),
|
||||
falsifiability_checks: z.array(z.string().min(1)).min(1),
|
||||
}).strict()),
|
||||
}).strict();
|
||||
|
||||
export type StopReason = z.infer<typeof stopReasonSchema>;
|
||||
export type ValidationFailureReason = z.infer<typeof validationFailureReasonSchema>;
|
||||
export type DroppedReason = z.infer<typeof droppedReasonSchema>;
|
||||
export type IdeaCard = z.infer<typeof ideaCardSchema>;
|
||||
export type IdeaAssessment = z.infer<typeof ideaAssessmentSchema>;
|
||||
export type BridgePacket = z.infer<typeof bridgePacketSchema>;
|
||||
export type CouncilBrief = z.infer<typeof councilBriefSchema>;
|
||||
export type CouncilDiff = z.infer<typeof councilDiffSchema>;
|
||||
export type CouncilRunInput = z.infer<typeof councilRunInputSchema>;
|
||||
export type CouncilRunResult = z.infer<typeof councilRunResultSchema>;
|
||||
export type CouncilTraceEvent = z.infer<typeof councilTraceEventSchema>;
|
||||
export type MetaSelection = z.infer<typeof metaSelectionSchema>;
|
||||
Reference in New Issue
Block a user