import { z } from "zod"; import { canonicalJson, sha256, type JsonObject } from "../core/json.js"; export const OBSERVATION_OUTPUT_CONTRACT_ID = "stream.thought.output.observation"; export const OBSERVATION_OUTPUT_CONTRACT_VERSION = 1; export const CONCEPTUALIZATION_OUTPUT_CONTRACT_ID = "stream.thought.output.conceptualization"; export const CONCEPTUALIZATION_OUTPUT_CONTRACT_VERSION = 1; export const REVIEW_RESPONSE_OUTPUT_CONTRACT_ID = "stream.thought.output.review-response"; export const REVIEW_RESPONSE_OUTPUT_CONTRACT_VERSION = 1; export const CONVERSATION_COMPACTION_OUTPUT_CONTRACT_ID = "stream.thought.output.conversation-compaction"; export const CONVERSATION_COMPACTION_OUTPUT_CONTRACT_VERSION = 1; export const PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_ID = "stream.thought.output.public-knowledge-recommendation"; export const PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_V1_VERSION = 1; export const PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_VERSION = 2; export const PUBLIC_KNOWLEDGE_PROPOSED_DIFF_OUTPUT_CONTRACT_ID = "stream.thought.output.public-knowledge-proposed-diff"; export const PUBLIC_KNOWLEDGE_PROPOSED_DIFF_OUTPUT_CONTRACT_VERSION = 1; const recommendationSchema = z.object({ target: z.string().min(1).max(200), reason: z.string().min(1).max(2_000), proposedAction: z.string().min(1).max(2_000), }).strict(); export const observationOutputSchema = z.object({ summary: z.string().min(1).max(2_000), tags: z.array(z.string().min(1).max(100)).max(20), importance: z.enum(["low", "normal", "high"]), confidence: z.number().min(0).max(1), recommendation: recommendationSchema.optional(), }).strict(); export type ObservationOutput = z.infer; const compactionListItemSchema = z.string().min(1).max(300); export const conversationCompactionOutputSchema = z.object({ summary: z.string().min(1).max(2_000), boundary: z.string().min(1).max(24_000), openLoops: z.array(compactionListItemSchema).max(16), decisions: z.array(compactionListItemSchema).max(16), exactReferences: z.array(compactionListItemSchema).max(32), unresolved: z.array(compactionListItemSchema).max(16), lookupHints: z.array(z.string().min(1).max(200)).max(32), confidence: z.number().min(0).max(1), }).strict(); export type ConversationCompactionOutput = z.infer; const conceptRelationshipEnum = z.enum([ "RELATES_TO", "DESCRIBES", "MENTIONS", "EXEMPLIFIES", "CONTRADICTS", "QUESTIONS", "SUPPORTS", "CRITIQUES", ]); const conceptItemSchema = z.object({ text: z.string().min(1).max(60).regex(/^[a-z0-9]+( [a-z0-9]+){0,2}$/, "Concept text must be lowercase 1-3 words with spaces"), relationship: conceptRelationshipEnum, }).strict(); const conceptLinkSchema = z.object({ fromIndex: z.number().int().nonnegative(), toIndex: z.number().int().nonnegative(), relationship: conceptRelationshipEnum, }).strict(); export const conceptualizationOutputSchema = z.object({ summary: z.string().min(1).max(2_000), concepts: z.array(conceptItemSchema).min(0).max(20), links: z.array(conceptLinkSchema).max(20).optional(), confidence: z.number().min(0).max(1), }).strict().superRefine((value, context) => { for (let index = 0; index < (value.links?.length ?? 0); index += 1) { const link = value.links![index]!; if (link.fromIndex >= value.concepts.length) { context.addIssue({ code: "custom", path: ["links", index, "fromIndex"], message: "Link source is outside the concept array" }); } if (link.toIndex >= value.concepts.length) { context.addIssue({ code: "custom", path: ["links", index, "toIndex"], message: "Link target is outside the concept array" }); } } }); export type ConceptualizationOutput = z.infer; export function reviewResponseSummary(response: string): string { return response.length <= 2_000 ? response : `${response.slice(0, 1_999)}…`; } export const reviewResponseOutputSchema = z.object({ response: z.string().min(1).max(60_000), summary: z.string().min(1).max(2_000).optional(), confidence: z.number().min(0).max(1).optional(), }).strict().superRefine((value, context) => { if (value.summary !== undefined && value.summary !== reviewResponseSummary(value.response)) { context.addIssue({ code: "custom", path: ["summary"], message: "Summary must be the canonical bounded response preview" }); } if (value.confidence !== undefined && value.confidence !== 1) { context.addIssue({ code: "custom", path: ["confidence"], message: "Review response confidence is deterministic" }); } }).transform((value) => ({ response: value.response, summary: reviewResponseSummary(value.response), confidence: 1, })); export type ReviewResponseOutput = z.infer; const publicKnowledgeCandidateSchemaV1 = z.object({ slug: z.string().min(1).max(160).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/), title: z.string().min(1).max(240), summary: z.string().min(1).max(1_600), outline: z.array(z.string().min(1).max(240)).min(1).max(24), }).strict(); export const publicKnowledgeRecommendationOutputSchemaV1 = z.object({ decision: z.enum(["propose-new", "revise-existing", "skip"]), summary: z.string().min(1).max(1_600), rationale: z.string().min(1).max(4_000), candidate: publicKnowledgeCandidateSchemaV1.nullable(), targetSlugs: z.array(z.string().min(1).max(160)).max(24), publicSourcesToVerify: z.array(z.string().min(1).max(500)).max(24), privacy: z.object({ status: z.enum(["clear", "review", "block"]), findings: z.array(z.string().min(1).max(500)).max(20), }).strict(), confidence: z.number().min(0).max(1), }).strict().superRefine((value, context) => { if (value.decision === "propose-new") { if (!value.candidate) { context.addIssue({ code: "custom", path: ["candidate"], message: "A new entry proposal requires a candidate" }); } if (value.targetSlugs.length > 0) { context.addIssue({ code: "custom", path: ["targetSlugs"], message: "A new entry proposal cannot name revision targets" }); } } if (value.decision === "revise-existing" && value.targetSlugs.length === 0) { context.addIssue({ code: "custom", path: ["targetSlugs"], message: "A revision requires at least one existing target" }); } if (value.decision === "revise-existing" && value.candidate) { context.addIssue({ code: "custom", path: ["candidate"], message: "A revision names targets rather than creating a candidate" }); } if (value.decision === "skip" && (value.candidate || value.targetSlugs.length > 0)) { context.addIssue({ code: "custom", path: ["decision"], message: "A skipped recommendation cannot include a candidate or targets" }); } }); const publicKnowledgeCandidateSchema = z.object({ slug: z.string().min(1).max(160).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/), title: z.string().min(1).max(240), summary: z.string().min(1).max(1_600), kind: z.string().min(1).max(100), claimOutline: z.array(z.string().min(1).max(500)).min(1).max(24), publicSourcesNeeded: z.array(z.string().min(1).max(500)).max(24), privateDependencies: z.array(z.string().min(1).max(500)).max(24), relatedSlugs: z.array(z.string().min(1).max(160)).max(24), }).strict(); export const publicKnowledgeRecommendationOutputSchema = z.object({ decision: z.enum(["propose-new", "revise-existing", "skip"]), summary: z.string().min(1).max(1_600), rationale: z.array(z.string().min(1).max(1_000)).min(1).max(20), candidate: publicKnowledgeCandidateSchema.nullable(), targetSlugs: z.array(z.string().min(1).max(160)).max(24), publicSourcesToVerify: z.array(z.string().min(1).max(500)).max(24), privacy: z.object({ status: z.enum(["clear", "review", "blocked"]), findings: z.array(z.string().min(1).max(500)).max(20), }).strict(), confidence: z.enum(["low", "medium", "high"]), }).strict().superRefine((value, context) => { if (value.decision === "propose-new") { if (!value.candidate) { context.addIssue({ code: "custom", path: ["candidate"], message: "A new entry proposal requires a candidate" }); } if (value.targetSlugs.length > 0) { context.addIssue({ code: "custom", path: ["targetSlugs"], message: "A new entry proposal cannot name revision targets" }); } } if (value.decision === "revise-existing" && value.targetSlugs.length === 0) { context.addIssue({ code: "custom", path: ["targetSlugs"], message: "A revision requires at least one existing target" }); } if (value.decision === "revise-existing" && value.candidate) { context.addIssue({ code: "custom", path: ["candidate"], message: "A revision names targets rather than creating a candidate" }); } if (value.decision === "skip" && (value.candidate || value.targetSlugs.length > 0)) { context.addIssue({ code: "custom", path: ["decision"], message: "A skipped recommendation cannot include a candidate or targets" }); } }); export type PublicKnowledgeRecommendationOutput = z.infer; const publicKnowledgeProposalTargetSchema = z.object({ kind: z.enum(["new", "replacement"]), slug: z.string().min(1).max(160).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/), baseSha256: z.string().regex(/^[a-f0-9]{64}$/).nullable(), }).strict(); const publicKnowledgeDraftSchema = z.object({ title: z.string().min(1).max(240), summary: z.string().min(1).max(1_600), kind: z.string().min(1).max(100), topics: z.array(z.string().min(1).max(100).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)).max(20), relatedSlugs: z.array(z.string().min(1).max(160).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)).max(24), bodyMarkdown: z.string().min(1).max(40_000).refine( (value) => !value.trimStart().startsWith("---"), "Draft body must not contain YAML frontmatter", ), }).strict(); const publicKnowledgeDiffProposalSchema = z.object({ target: publicKnowledgeProposalTargetSchema, draft: publicKnowledgeDraftSchema, }).strict(); export const publicKnowledgeProposedDiffOutputSchema = z.object({ proposalState: z.literal("agent-proposed"), decision: z.enum(["propose-new", "revise-existing", "skip"]), summary: z.string().min(1).max(1_600), rationale: z.array(z.string().min(1).max(1_000)).min(1).max(20), proposal: publicKnowledgeDiffProposalSchema.nullable(), publicSourcesToVerify: z.array(z.string().min(1).max(500)).max(24), privateDependencies: z.array(z.string().min(1).max(500)).max(24), privacy: z.object({ status: z.enum(["clear", "review", "blocked"]), findings: z.array(z.string().min(1).max(500)).max(20), }).strict(), confidence: z.enum(["low", "medium", "high"]), publicationEligible: z.literal(false), }).strict().superRefine((value, context) => { if (value.decision === "propose-new") { if (!value.proposal) { context.addIssue({ code: "custom", path: ["proposal"], message: "A new document proposal requires a draft" }); } else { if (value.proposal.target.kind !== "new") { context.addIssue({ code: "custom", path: ["proposal", "target", "kind"], message: "A new document proposal requires a new target" }); } if (value.proposal.target.baseSha256 !== null) { context.addIssue({ code: "custom", path: ["proposal", "target", "baseSha256"], message: "A new target cannot name a base hash" }); } } } if (value.decision === "revise-existing") { if (!value.proposal) { context.addIssue({ code: "custom", path: ["proposal"], message: "A replacement proposal requires a draft" }); } else if (value.proposal.target.kind !== "replacement" || value.proposal.target.baseSha256 === null) { context.addIssue({ code: "custom", path: ["proposal", "target"], message: "A replacement target requires an exact base hash" }); } } if (value.decision === "skip" && value.proposal !== null) { context.addIssue({ code: "custom", path: ["proposal"], message: "A skipped document cannot include a draft" }); } if (value.privacy.status === "blocked" && (value.decision !== "skip" || value.proposal !== null)) { context.addIssue({ code: "custom", path: ["privacy", "status"], message: "Blocked privacy requires a skipped proposal" }); } }); export type PublicKnowledgeProposedDiffOutput = z.infer; export type SemanticOutput = ObservationOutput | ConceptualizationOutput | ReviewResponseOutput | ConversationCompactionOutput | PublicKnowledgeRecommendationOutput | PublicKnowledgeProposedDiffOutput; export interface OutputContractIdentity { id: string; version: number; sha256: string; } export interface SanitizedOutputIssue { code: string; path: Array; } export interface OutputContractDefinition { identity: OutputContractIdentity; definition: JsonObject; prompt: string; schema: z.ZodType; } const observationDefinition: JsonObject = { id: OBSERVATION_OUTPUT_CONTRACT_ID, version: OBSERVATION_OUTPUT_CONTRACT_VERSION, type: "object", unknownFields: "reject", fields: { summary: { type: "string", minChars: 1, maxChars: 2_000, required: true }, tags: { type: "array", items: { type: "string", minChars: 1, maxChars: 100 }, maxItems: 20, required: true }, importance: { type: "enum", values: ["low", "normal", "high"], required: true }, confidence: { type: "number", minimum: 0, maximum: 1, required: true }, recommendation: { type: "object", required: false, unknownFields: "reject", fields: { target: { type: "string", minChars: 1, maxChars: 200, required: true }, reason: { type: "string", minChars: 1, maxChars: 2_000, required: true }, proposedAction: { type: "string", minChars: 1, maxChars: 2_000, required: true }, }, }, }, }; const observationIdentity: OutputContractIdentity = { id: OBSERVATION_OUTPUT_CONTRACT_ID, version: OBSERVATION_OUTPUT_CONTRACT_VERSION, sha256: sha256(canonicalJson(observationDefinition)), }; export const OBSERVATION_OUTPUT_CONTRACT: OutputContractDefinition = { identity: observationIdentity, definition: observationDefinition, prompt: "Return exactly one raw JSON object and nothing else. Use only the required top-level keys summary, tags, importance, confidence, plus optional recommendation. Minimal valid example: {\"summary\":\"One concise observation\",\"tags\":[],\"importance\":\"low\",\"confidence\":0.5}. The importance value must be exactly one of \"low\", \"normal\", or \"high\"; \"medium\" is invalid. The optional recommendation object may contain only target, reason, and proposedAction. Do not wrap the object, add unknown fields, use Markdown fences, or write text before or after it.", schema: observationOutputSchema, }; const conversationCompactionDefinition: JsonObject = { id: CONVERSATION_COMPACTION_OUTPUT_CONTRACT_ID, version: CONVERSATION_COMPACTION_OUTPUT_CONTRACT_VERSION, type: "object", unknownFields: "reject", invariants: [ "boundary summarizes only the supplied frozen history prefix", "openLoops, decisions, exactReferences, unresolved, and lookupHints contain no invented facts", "the output does not answer or continue the conversation", ], fields: { summary: { type: "string", minChars: 1, maxChars: 2_000, required: true }, boundary: { type: "string", minChars: 1, maxChars: 24_000, required: true }, openLoops: { type: "array", maxItems: 16, items: { type: "string", minChars: 1, maxChars: 300 }, required: true }, decisions: { type: "array", maxItems: 16, items: { type: "string", minChars: 1, maxChars: 300 }, required: true }, exactReferences: { type: "array", maxItems: 32, items: { type: "string", minChars: 1, maxChars: 300 }, required: true }, unresolved: { type: "array", maxItems: 16, items: { type: "string", minChars: 1, maxChars: 300 }, required: true }, lookupHints: { type: "array", maxItems: 32, items: { type: "string", minChars: 1, maxChars: 200 }, required: true }, confidence: { type: "number", minimum: 0, maximum: 1, required: true }, }, }; const conversationCompactionIdentity: OutputContractIdentity = { id: CONVERSATION_COMPACTION_OUTPUT_CONTRACT_ID, version: CONVERSATION_COMPACTION_OUTPUT_CONTRACT_VERSION, sha256: sha256(canonicalJson(conversationCompactionDefinition)), }; export const CONVERSATION_COMPACTION_OUTPUT_CONTRACT: OutputContractDefinition = { identity: conversationCompactionIdentity, definition: conversationCompactionDefinition, prompt: "Return exactly one raw JSON object with the required keys summary, boundary, openLoops, decisions, exactReferences, unresolved, lookupHints, and confidence. Compact only the frozen historical messages supplied before the current compaction request. Preserve user requests, corrections, decisions, rejected options when relevant, open obligations, exact names, paths, ids, commands, URLs, errors, and lookup hints. Incorporate the prior compaction boundary when present. Do not answer the conversation, continue its latest topic, call tools, invent facts, add Markdown fences, add unknown fields, or write text outside the JSON object.", schema: conversationCompactionOutputSchema, }; const publicKnowledgeRecommendationDefinitionV1: JsonObject = { id: PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_ID, version: PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_V1_VERSION, type: "object", unknownFields: "reject", invariants: [ "propose-new requires candidate and forbids targetSlugs", "revise-existing requires one or more targetSlugs and candidate null", "skip forbids candidate and targetSlugs", ], fields: { decision: { type: "enum", values: ["propose-new", "revise-existing", "skip"], required: true }, summary: { type: "string", minChars: 1, maxChars: 1_600, required: true }, rationale: { type: "string", minChars: 1, maxChars: 4_000, required: true }, candidate: { type: ["object", "null"], required: true, unknownFields: "reject", fields: { slug: { type: "string", minChars: 1, maxChars: 160, pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$", required: true }, title: { type: "string", minChars: 1, maxChars: 240, required: true }, summary: { type: "string", minChars: 1, maxChars: 1_600, required: true }, outline: { type: "array", minItems: 1, maxItems: 24, required: true }, }, }, targetSlugs: { type: "array", maxItems: 24, required: true }, publicSourcesToVerify: { type: "array", maxItems: 24, required: true }, privacy: { type: "object", required: true, unknownFields: "reject", fields: { status: { type: "enum", values: ["clear", "review", "block"], required: true }, findings: { type: "array", maxItems: 20, required: true }, }, }, confidence: { type: "number", minimum: 0, maximum: 1, required: true }, }, }; const publicKnowledgeRecommendationIdentityV1: OutputContractIdentity = { id: PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_ID, version: PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_V1_VERSION, sha256: sha256(canonicalJson(publicKnowledgeRecommendationDefinitionV1)), }; export const PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_V1: OutputContractDefinition> = { identity: publicKnowledgeRecommendationIdentityV1, definition: publicKnowledgeRecommendationDefinitionV1, prompt: "Return exactly one raw JSON object with the required keys decision, summary, rationale, candidate, targetSlugs, publicSourcesToVerify, privacy, and confidence. decision is propose-new, revise-existing, or skip. propose-new requires a complete candidate and no targetSlugs. revise-existing requires existing targetSlugs and candidate null. skip requires candidate null and no targetSlugs. privacy has exactly status and findings. Do not include source content, private names, personal details, Markdown fences, unknown fields, or text outside the JSON object.", schema: publicKnowledgeRecommendationOutputSchemaV1, }; const publicKnowledgeRecommendationDefinition: JsonObject = { id: PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_ID, version: PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_VERSION, type: "object", unknownFields: "reject", invariants: [ "propose-new requires candidate and forbids targetSlugs", "revise-existing requires one or more targetSlugs and candidate null", "skip forbids candidate and targetSlugs", ], fields: { decision: { type: "enum", values: ["propose-new", "revise-existing", "skip"], required: true }, summary: { type: "string", minChars: 1, maxChars: 1_600, required: true }, rationale: { type: "array", minItems: 1, maxItems: 20, required: true }, candidate: { type: ["object", "null"], required: true, unknownFields: "reject", fields: { slug: { type: "string", minChars: 1, maxChars: 160, pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$", required: true }, title: { type: "string", minChars: 1, maxChars: 240, required: true }, summary: { type: "string", minChars: 1, maxChars: 1_600, required: true }, kind: { type: "string", minChars: 1, maxChars: 100, required: true }, claimOutline: { type: "array", minItems: 1, maxItems: 24, required: true }, publicSourcesNeeded: { type: "array", maxItems: 24, required: true }, privateDependencies: { type: "array", maxItems: 24, required: true }, relatedSlugs: { type: "array", maxItems: 24, required: true }, }, }, targetSlugs: { type: "array", maxItems: 24, required: true }, publicSourcesToVerify: { type: "array", maxItems: 24, required: true }, privacy: { type: "object", required: true, unknownFields: "reject", fields: { status: { type: "enum", values: ["clear", "review", "blocked"], required: true }, findings: { type: "array", maxItems: 20, required: true }, }, }, confidence: { type: "enum", values: ["low", "medium", "high"], required: true }, }, }; const publicKnowledgeRecommendationIdentity: OutputContractIdentity = { id: PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_ID, version: PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_VERSION, sha256: sha256(canonicalJson(publicKnowledgeRecommendationDefinition)), }; export const PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT: OutputContractDefinition = { identity: publicKnowledgeRecommendationIdentity, definition: publicKnowledgeRecommendationDefinition, prompt: "Return exactly one raw JSON object with the required keys decision, summary, rationale, candidate, targetSlugs, publicSourcesToVerify, privacy, and confidence. rationale is an array of concise strings. confidence is exactly low, medium, or high. decision is propose-new, revise-existing, or skip. propose-new requires a complete candidate with slug, title, summary, kind, claimOutline, publicSourcesNeeded, privateDependencies, and relatedSlugs, and no targetSlugs. revise-existing requires existing targetSlugs and candidate null. skip requires candidate null and no targetSlugs. privacy has exactly status (clear, review, or blocked) and findings. Do not include source content, private names, personal details, Markdown fences, unknown fields, or text outside the JSON object.", schema: publicKnowledgeRecommendationOutputSchema, }; const publicKnowledgeProposedDiffDefinition: JsonObject = { id: PUBLIC_KNOWLEDGE_PROPOSED_DIFF_OUTPUT_CONTRACT_ID, version: PUBLIC_KNOWLEDGE_PROPOSED_DIFF_OUTPUT_CONTRACT_VERSION, type: "object", unknownFields: "reject", invariants: [ "propose-new requires a new target, null baseSha256, and one draft", "revise-existing requires a replacement target, exact baseSha256, and one draft", "skip requires proposal null", "blocked privacy requires skip and proposal null", "publicationEligible is always false", ], fields: { proposalState: { type: "literal", value: "agent-proposed", required: true }, decision: { type: "enum", values: ["propose-new", "revise-existing", "skip"], required: true }, summary: { type: "string", minChars: 1, maxChars: 1_600, required: true }, rationale: { type: "array", minItems: 1, maxItems: 20, required: true }, proposal: { type: ["object", "null"], required: true, unknownFields: "reject", fields: { target: { type: "object", required: true, unknownFields: "reject", fields: { kind: { type: "enum", values: ["new", "replacement"], required: true }, slug: { type: "string", minChars: 1, maxChars: 160, pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$", required: true }, baseSha256: { type: ["string", "null"], pattern: "^[a-f0-9]{64}$", required: true }, }, }, draft: { type: "object", required: true, unknownFields: "reject", fields: { title: { type: "string", minChars: 1, maxChars: 240, required: true }, summary: { type: "string", minChars: 1, maxChars: 1_600, required: true }, kind: { type: "string", minChars: 1, maxChars: 100, required: true }, topics: { type: "array", maxItems: 20, required: true }, relatedSlugs: { type: "array", maxItems: 24, required: true }, bodyMarkdown: { type: "string", minChars: 1, maxChars: 40_000, frontmatter: "forbidden", required: true }, }, }, }, }, publicSourcesToVerify: { type: "array", maxItems: 24, required: true }, privateDependencies: { type: "array", maxItems: 24, required: true }, privacy: { type: "object", required: true, unknownFields: "reject", fields: { status: { type: "enum", values: ["clear", "review", "blocked"], required: true }, findings: { type: "array", maxItems: 20, required: true }, }, }, confidence: { type: "enum", values: ["low", "medium", "high"], required: true }, publicationEligible: { type: "literal", value: false, required: true }, }, }; const publicKnowledgeProposedDiffIdentity: OutputContractIdentity = { id: PUBLIC_KNOWLEDGE_PROPOSED_DIFF_OUTPUT_CONTRACT_ID, version: PUBLIC_KNOWLEDGE_PROPOSED_DIFF_OUTPUT_CONTRACT_VERSION, sha256: sha256(canonicalJson(publicKnowledgeProposedDiffDefinition)), }; export const PUBLIC_KNOWLEDGE_PROPOSED_DIFF_OUTPUT_CONTRACT: OutputContractDefinition = { identity: publicKnowledgeProposedDiffIdentity, definition: publicKnowledgeProposedDiffDefinition, prompt: "Return exactly one raw JSON object with the required keys proposalState, decision, summary, rationale, proposal, publicSourcesToVerify, privateDependencies, privacy, confidence, and publicationEligible. proposalState is exactly agent-proposed and publicationEligible is exactly false. decision is propose-new, revise-existing, or skip. propose-new requires target.kind new, an absent slug, baseSha256 null, and one complete draft. revise-existing requires target.kind replacement, one admitted target slug, its exact baseSha256, and one complete draft. skip requires proposal null. A blocked privacy status requires skip. Draft bodyMarkdown contains the document body only and must not include YAML frontmatter. Do not add unknown fields, Markdown fences around the JSON object, tool calls, or text outside the JSON object.", schema: publicKnowledgeProposedDiffOutputSchema, }; export class OutputContractValidationError extends Error { readonly identity: OutputContractIdentity; readonly issues: SanitizedOutputIssue[]; constructor(identity: OutputContractIdentity, issues: SanitizedOutputIssue[]) { super(`Output does not satisfy ${identity.id}@${identity.version}`); this.name = "OutputContractValidationError"; this.identity = identity; this.issues = issues; } } export class OutputContractRegistry { private readonly contracts = new Map(); register(contract: OutputContractDefinition): this { const key = outputContractKey(contract.identity.id, contract.identity.version); if (this.contracts.has(key)) throw new Error(`Output contract already registered: ${key}`); const expectedHash = sha256(canonicalJson(contract.definition)); if (contract.identity.sha256 !== expectedHash) throw new Error(`Output contract definition hash mismatch: ${key}`); this.contracts.set(key, contract as unknown as OutputContractDefinition); return this; } get(id: string, version: number): OutputContractDefinition { const key = outputContractKey(id, version); const contract = this.contracts.get(key); if (!contract) throw new Error(`Unknown output contract: ${key}`); return contract; } resolve(identity: OutputContractIdentity): OutputContractDefinition { const contract = this.get(identity.id, identity.version); const key = outputContractKey(identity.id, identity.version); if (identity.sha256 !== contract.identity.sha256) throw new Error(`Output contract identity hash mismatch: ${key}`); return contract; } validate(identity: OutputContractIdentity, value: unknown): SemanticOutput { const contract = this.resolve(identity); const result = contract.schema.safeParse(value); if (!result.success) throw new OutputContractValidationError(contract.identity, sanitizeOutputIssues(result.error.issues)); return result.data as SemanticOutput; } canonicalize(identity: OutputContractIdentity, value: unknown): JsonObject { const contract = this.resolve(identity); const result = contract.schema.safeParse(value); if (!result.success) throw new OutputContractValidationError(contract.identity, sanitizeOutputIssues(result.error.issues)); return JSON.parse(canonicalJson(result.data as JsonObject)) as JsonObject; } } const conceptualizationDefinition: JsonObject = { id: CONCEPTUALIZATION_OUTPUT_CONTRACT_ID, version: CONCEPTUALIZATION_OUTPUT_CONTRACT_VERSION, type: "object", unknownFields: "reject", canonicalizer: { id: "stream.thought.canonical-json-after-schema", version: 1 }, invariants: [ "links[].fromIndex and links[].toIndex are integers", "0 <= links[].fromIndex < concepts.length", "0 <= links[].toIndex < concepts.length", ], fields: { summary: { type: "string", minChars: 1, maxChars: 2_000, required: true }, concepts: { type: "array", maxItems: 20, required: true, items: { type: "object", unknownFields: "reject", fields: { text: { type: "string", minChars: 1, maxChars: 60, pattern: "^[a-z0-9]+( [a-z0-9]+){0,2}$", required: true }, relationship: { type: "enum", values: ["RELATES_TO", "DESCRIBES", "MENTIONS", "EXEMPLIFIES", "CONTRADICTS", "QUESTIONS", "SUPPORTS", "CRITIQUES"], required: true }, }, }, }, links: { type: "array", maxItems: 20, required: false, items: { type: "object", unknownFields: "reject", fields: { fromIndex: { type: "integer", minimum: 0, maximumExclusivePath: "concepts.length", required: true }, toIndex: { type: "integer", minimum: 0, maximumExclusivePath: "concepts.length", required: true }, relationship: { type: "enum", values: ["RELATES_TO", "DESCRIBES", "MENTIONS", "EXEMPLIFIES", "CONTRADICTS", "QUESTIONS", "SUPPORTS", "CRITIQUES"], required: true }, }, }, }, confidence: { type: "number", minimum: 0, maximum: 1, required: true }, }, }; const conceptualizationIdentity: OutputContractIdentity = { id: CONCEPTUALIZATION_OUTPUT_CONTRACT_ID, version: CONCEPTUALIZATION_OUTPUT_CONTRACT_VERSION, sha256: sha256(canonicalJson(conceptualizationDefinition)), }; export const CONCEPTUALIZATION_OUTPUT_JSON_SCHEMA: JsonObject = { type: "object", additionalProperties: false, required: ["summary", "concepts", "links", "confidence"], properties: { summary: { type: "string", minLength: 1, maxLength: 2_000 }, concepts: { type: "array", maxItems: 20, items: { type: "object", additionalProperties: false, required: ["text", "relationship"], properties: { text: { type: "string", minLength: 1, maxLength: 60, pattern: "^[a-z0-9]+( [a-z0-9]+){0,2}$" }, relationship: { type: "string", enum: ["RELATES_TO", "DESCRIBES", "MENTIONS", "EXEMPLIFIES", "CONTRADICTS", "QUESTIONS", "SUPPORTS", "CRITIQUES"] }, }, }, }, links: { type: "array", maxItems: 20, items: { type: "object", additionalProperties: false, required: ["fromIndex", "toIndex", "relationship"], properties: { fromIndex: { type: "integer", minimum: 0, maximum: 19 }, toIndex: { type: "integer", minimum: 0, maximum: 19 }, relationship: { type: "string", enum: ["RELATES_TO", "DESCRIBES", "MENTIONS", "EXEMPLIFIES", "CONTRADICTS", "QUESTIONS", "SUPPORTS", "CRITIQUES"] }, }, }, }, confidence: { type: "number", minimum: 0, maximum: 1 }, }, }; export const CONCEPTUALIZATION_OUTPUT_CONTRACT: OutputContractDefinition = { identity: conceptualizationIdentity, definition: conceptualizationDefinition, prompt: "Return exactly one raw JSON object and nothing else. Use only the required top-level keys summary, concepts, links, and confidence. The concepts array must contain objects with exactly the keys text and relationship; strings are invalid. Each concept text must be lowercase 1-3 words (letters, numbers, spaces only). Each relationship must be exactly one of: RELATES_TO, DESCRIBES, MENTIONS, EXEMPLIFIES, CONTRADICTS, QUESTIONS, SUPPORTS, CRITIQUES. Links use zero-based fromIndex/toIndex into the concepts array and the same relationship enum. Minimal valid example: {\"summary\":\"Execution receipts support durable agent memory\",\"concepts\":[{\"text\":\"agent memory\",\"relationship\":\"DESCRIBES\"},{\"text\":\"execution receipts\",\"relationship\":\"SUPPORTS\"}],\"links\":[{\"fromIndex\":1,\"toIndex\":0,\"relationship\":\"SUPPORTS\"}],\"confidence\":0.5}. Do not wrap the object, add unknown fields, use Markdown fences, or write text before or after it.", schema: conceptualizationOutputSchema, }; const reviewResponseDefinition: JsonObject = { id: REVIEW_RESPONSE_OUTPUT_CONTRACT_ID, version: REVIEW_RESPONSE_OUTPUT_CONTRACT_VERSION, type: "object", unknownFields: "reject", fields: { response: { type: "string", minChars: 1, maxChars: 60_000, required: true }, summary: { type: "string", minChars: 1, maxChars: 2_000, required: false, deterministic: "bounded response preview" }, confidence: { type: "number", minimum: 1, maximum: 1, required: false, deterministic: true }, }, }; const reviewResponseIdentity: OutputContractIdentity = { id: REVIEW_RESPONSE_OUTPUT_CONTRACT_ID, version: REVIEW_RESPONSE_OUTPUT_CONTRACT_VERSION, sha256: sha256(canonicalJson(reviewResponseDefinition)), }; export const REVIEW_RESPONSE_OUTPUT_CONTRACT: OutputContractDefinition = { identity: reviewResponseIdentity, definition: reviewResponseDefinition, prompt: "Return exactly one raw JSON object with the single key response and nothing else. Put the complete response to the review prompt in that string. Do not add unknown fields, Markdown fences around the JSON object, or text before or after it.", schema: reviewResponseOutputSchema, }; export function createOutputContractRegistry(): OutputContractRegistry { return new OutputContractRegistry() .register(OBSERVATION_OUTPUT_CONTRACT) .register(CONVERSATION_COMPACTION_OUTPUT_CONTRACT) .register(CONCEPTUALIZATION_OUTPUT_CONTRACT) .register(REVIEW_RESPONSE_OUTPUT_CONTRACT) .register(PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT_V1) .register(PUBLIC_KNOWLEDGE_RECOMMENDATION_OUTPUT_CONTRACT) .register(PUBLIC_KNOWLEDGE_PROPOSED_DIFF_OUTPUT_CONTRACT); } export function defaultOutputContractIdentity(): OutputContractIdentity { return { ...OBSERVATION_OUTPUT_CONTRACT.identity }; } export function outputContractIdentityJson(identity: OutputContractIdentity): JsonObject { return { id: identity.id, version: identity.version, sha256: identity.sha256 }; } export function parseOutputContractIdentity(value: unknown): OutputContractIdentity { if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Missing output contract identity"); const record = value as Record; if (typeof record.id !== "string" || !record.id) throw new Error("Output contract id is invalid"); if (!Number.isSafeInteger(record.version) || Number(record.version) <= 0) throw new Error("Output contract version is invalid"); if (typeof record.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(record.sha256)) throw new Error("Output contract hash is invalid"); return { id: record.id, version: Number(record.version), sha256: record.sha256 }; } export function outputContractForDeclaration(declaration: { outputContract?: OutputContractIdentity | undefined }): OutputContractIdentity { return declaration.outputContract ? { ...declaration.outputContract } : defaultOutputContractIdentity(); } export function sanitizeOutputIssues(issues: z.core.$ZodIssue[], limit = 20): SanitizedOutputIssue[] { return issues.slice(0, limit).map((issue) => ({ code: issue.code, path: issue.path.slice(0, 12).map((part) => typeof part === "number" ? part : String(part)), })); } export function canonicalStructuredOutput( registry: OutputContractRegistry, identity: OutputContractIdentity, value: unknown, ): JsonObject { return registry.canonicalize(identity, value); } export function outputContractKey(id: string, version: number): string { return `${id}@${version}`; }