Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 172 additions & 2 deletions packages/evolution/src/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,61 @@ export interface EvolutionInputSnapshot {
export interface EvidenceCorpusDocument {
readonly documentId: string;
readonly sourceId: string;
readonly materializationId: string;
readonly contentDigest: string;
readonly materializedInvocationVersion: number;
readonly traceId: string | null;
readonly integrity: MaterializationIntegrity;
readonly terminationStatus: MaterializedTerminationStatus;
readonly evidenceIds: readonly string[];
readonly semanticUnits: readonly EvidenceSemanticUnit[];
readonly diagnostics: readonly EvidenceCorpusDiagnostic[];
readonly orderingAmbiguity: readonly string[];
}

export type EvidenceSemanticUnitKind =
| "message"
| "span"
| "terminal-outcome"
| "tool-exchange"
| "trace-record"
| "turn";

export interface EvidenceSourceCursor {
readonly traceSequence: number;
readonly timestamp: string | null;
readonly sessionPosition: number | null;
readonly parentSpanId: number | null;
readonly causalIdentifiers: readonly MaterializedCausalLink[];
readonly session: {
readonly bindingId: string;
readonly entryId: string | null;
readonly entryOrdinal: number | null;
readonly sessionSequence: number | null;
} | null;
}

export interface MaterializedCausalLink {
readonly name: string;
readonly value: string;
}

export interface EvidenceSemanticUnit {
readonly unitId: string;
readonly ordinal: number;
readonly kind: EvidenceSemanticUnitKind;
readonly evidenceIds: readonly string[];
readonly contentDigest: string;
readonly sourceCursor: EvidenceSourceCursor;
}

export interface EvidenceCorpusDiagnostic {
readonly code: string;
readonly message: string;
readonly recoverable: boolean;
readonly traceSequence: number | null;
readonly bindingId: string | null;
readonly sourceCode: string | null;
}

export interface ExcludedEvidenceSource {
Expand All @@ -195,29 +244,107 @@ export interface InstructionSnapshot {
readonly documents: readonly InstructionDocumentSnapshot[];
}

export interface EvidenceSliceCursor {
readonly documentId: string;
readonly startUnitId: string;
readonly endUnitId: string;
readonly startOrdinal: number;
readonly endOrdinal: number;
readonly digest: string;
}

export type EvidenceSliceOpenReason =
| "error-without-workaround"
| "new-turn-near-end"
| "tool-call-without-result"
| "tool-result-without-call";

export interface EvidenceSliceEdge {
readonly status: "closed" | "open";
readonly reasons: readonly EvidenceSliceOpenReason[];
readonly evidenceIds: readonly string[];
}

export interface EvidenceSliceContinuation {
readonly previousSliceId: string | null;
readonly nextSliceId: string | null;
}

export interface EvidenceSlice {
readonly sliceId: string;
readonly manifestDigest: string;
readonly cursor: EvidenceSliceCursor;
readonly unitIds: readonly string[];
readonly evidenceIds: readonly string[];
readonly contentDigest: string;
readonly leftEdge: EvidenceSliceEdge;
readonly rightEdge: EvidenceSliceEdge;
readonly continuation: EvidenceSliceContinuation;
}

export type EvidenceCoverageDisposition = "analyzed" | "corrupt" | "skipped" | "unreadable";

export interface EvidenceCoverageEntry {
readonly documentId: string;
readonly evidenceId: string;
readonly disposition: EvidenceCoverageDisposition;
readonly sliceIds: readonly string[];
readonly overlaps: readonly string[];
readonly continuationSliceIds: readonly string[];
readonly diagnosticCodes: readonly string[];
}

export interface EvidenceCoverageMap {
readonly metadata: EvolutionArtifactMetadata;
readonly manifestDigest: string;
readonly entries: readonly EvidenceCoverageEntry[];
readonly rootNodeIds: readonly string[];
readonly finalLessonIds: readonly string[];
}

export type ReflectionNodeStatus = "pending" | "complete" | "failed";

export interface ReflectionNode {
readonly metadata: EvolutionArtifactMetadata;
readonly nodeId: string;
readonly kind: "leaf" | "synthesis";
readonly depth: number;
readonly parentNodeId: string | null;
readonly childNodeIds: readonly string[];
readonly sliceIds: readonly string[];
readonly evidenceIds: readonly string[];
readonly lessonIds: readonly string[];
readonly resultDigest: string;
readonly status: ReflectionNodeStatus;
}

export type LessonKind = "constraint" | "failure" | "instruction" | "strategy" | "unresolved";
export type LessonKind =
| "counterexample"
| "direct-instruction"
| "failure-workaround"
| "harmful-memory"
| "incorrect-source-of-truth"
| "missing-capability"
| "missing-verification"
| "orchestration-inefficiency"
| "repository-constraint"
| "successful-strategy"
| "tool-behavior"
| "unresolved-work";

export interface Lesson {
readonly metadata: EvolutionArtifactMetadata;
readonly lessonId: string;
readonly kind: LessonKind;
readonly summary: string;
readonly preconditions: readonly string[];
readonly observedOutcome: string;
readonly evidenceIds: readonly string[];
readonly counterevidenceIds: readonly string[];
readonly scope: EvolutionScope;
readonly applicabilityBoundaries: readonly string[];
readonly uncertainty: string | null;
readonly actionableTakeaway: string;
}

export interface EvolutionMemoryTarget {
Expand Down Expand Up @@ -358,6 +485,8 @@ export type EvolutionFailureReasonCode =
| "lease-lost"
| "model-call-failed"
| "pipeline-invariant"
| "reflection-budget-exhausted"
| "reflection-invalid-response"
| "shutdown"
| "snapshot-invalid"
| "stage-failed"
Expand Down Expand Up @@ -492,11 +621,52 @@ export interface ProposalRolledBackLedgerEvent extends EvolutionLedgerEventBase
readonly toHarnessVersion: HarnessVersion;
}

export interface ReflectorBudgetCharge {
readonly modelCalls: number;
readonly reflectionRounds: number;
readonly toolCalls: number;
}

export interface ReflectorToolCallLedgerEvent extends EvolutionLedgerEventBase {
readonly type: "reflector-tool-call";
readonly toolCallId: string;
readonly toolName: string;
readonly manifestDigest: string;
readonly requestDigest: string;
readonly requestedSliceId: string | null;
readonly resolvedEvidenceIds: readonly string[];
readonly resultDigest: string | null;
readonly denialCode: string | null;
readonly budgetCharge: ReflectorBudgetCharge;
}

export interface ReflectorModelCallLedgerEvent extends EvolutionLedgerEventBase {
readonly type: "reflector-model-call";
readonly modelCallId: string;
readonly nodeId: string;
readonly attempt: number;
readonly reflectionRound: number;
readonly manifestDigest: string;
readonly idempotencyKey: string;
readonly budgetCharge: ReflectorBudgetCharge;
}

export interface ReflectionNodeCheckpointedLedgerEvent extends EvolutionLedgerEventBase {
readonly type: "reflection-node-checkpointed";
readonly nodeId: string;
readonly manifestDigest: string;
readonly node: EvolutionArtifactReference;
readonly lessons: readonly EvolutionArtifactReference[];
}

export type EvolutionLedgerEvent =
| JobCreatedLedgerEvent
| CheckpointSavedLedgerEvent
| ProposalDispositionLedgerEvent
| MutationWrittenLedgerEvent
| JobCompletedLedgerEvent
| JobFailedLedgerEvent
| ProposalRolledBackLedgerEvent;
| ProposalRolledBackLedgerEvent
| ReflectionNodeCheckpointedLedgerEvent
| ReflectorModelCallLedgerEvent
| ReflectorToolCallLedgerEvent;
83 changes: 83 additions & 0 deletions packages/evolution/src/evidence-corpus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import type { MaterializedEvidence } from "@earendil-works/diffex-harness-trace";
import type {
EvidenceCorpusDocument,
EvidenceSemanticUnit,
EvidenceSemanticUnitKind,
EvolutionEvidenceSource,
} from "./contracts.ts";
import { computeEvolutionContentDigest } from "./provenance.ts";

function isRecord(value: unknown): value is Readonly<Record<string, unknown>> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}

function containsToolCall(value: unknown): boolean {
if (Array.isArray(value)) return value.some(containsToolCall);
if (!isRecord(value)) return false;
if (value.type === "toolCall" || value.role === "toolResult") return true;
return Object.values(value).some(containsToolCall);
}

function semanticKind(evidence: MaterializedEvidence): EvidenceSemanticUnitKind {
if (evidence.kind === "span") return "span";
if (evidence.kind === "trace_record") {
return evidence.payload.type === "trace_footer" ? "terminal-outcome" : "trace-record";
}
if (containsToolCall(evidence.payload)) return "tool-exchange";
if (isRecord(evidence.payload.message) && evidence.payload.message.role === "user") return "turn";
return "message";
}

export function buildEvidenceCorpusDocument(
documentId: string,
source: EvolutionEvidenceSource,
): EvidenceCorpusDocument {
const semanticUnits: EvidenceSemanticUnit[] = source.invocation.evidence.map((evidence, ordinal) => ({
unitId: `unit-${computeEvolutionContentDigest({
materializationId: source.materializationId,
evidenceId: evidence.evidenceId,
ordinal,
}).slice("sha256:".length, "sha256:".length + 32)}`,
ordinal,
kind: semanticKind(evidence),
evidenceIds: [evidence.evidenceId],
contentDigest: computeEvolutionContentDigest(evidence),
sourceCursor: {
traceSequence: evidence.order.traceSequence,
timestamp: evidence.order.timestamp,
sessionPosition: evidence.order.sessionPosition ?? null,
parentSpanId: evidence.order.parentSpanId ?? null,
causalIdentifiers: evidence.order.causalIdentifiers.map((identifier) => ({ ...identifier })),
session:
evidence.sessionSource === undefined
? null
: {
bindingId: evidence.sessionSource.bindingId,
entryId: evidence.sessionSource.entryId ?? null,
entryOrdinal: evidence.sessionSource.entryOrdinal ?? null,
sessionSequence: evidence.sessionSource.sessionSequence ?? null,
},
},
}));
return {
documentId,
sourceId: source.sourceId,
materializationId: source.materializationId,
contentDigest: source.contentDigest,
materializedInvocationVersion: source.invocation.version,
traceId: source.invocation.traceId,
integrity: source.invocation.integrity,
terminationStatus: source.invocation.terminationStatus,
evidenceIds: semanticUnits.flatMap((unit) => unit.evidenceIds),
semanticUnits,
diagnostics: source.invocation.diagnostics.map((diagnostic) => ({
code: diagnostic.code,
message: diagnostic.message,
recoverable: diagnostic.recoverable,
traceSequence: diagnostic.traceSequence ?? null,
bindingId: diagnostic.bindingId ?? null,
sourceCode: diagnostic.sourceCode ?? null,
})),
orderingAmbiguity: [...source.invocation.ordering.ambiguity],
};
}
29 changes: 29 additions & 0 deletions packages/evolution/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,20 @@ export {
type CounterSignalSource,
EVOLUTION_MEMORY_ITEM_SCHEMA_VERSION,
EVOLUTION_SCHEMA_VERSION,
type EvidenceCorpusDiagnostic,
type EvidenceCorpusDocument,
type EvidenceCorpusManifest,
type EvidenceCoverageDisposition,
type EvidenceCoverageEntry,
type EvidenceCoverageMap,
type EvidenceSemanticUnit,
type EvidenceSemanticUnitKind,
type EvidenceSlice,
type EvidenceSliceContinuation,
type EvidenceSliceCursor,
type EvidenceSliceEdge,
type EvidenceSliceOpenReason,
type EvidenceSourceCursor,
type EvolutionArtifactMetadata,
type EvolutionArtifactProducer,
type EvolutionArtifactReference,
Expand Down Expand Up @@ -60,6 +72,7 @@ export {
type JsonValue,
type Lesson,
type LessonKind,
type MaterializedCausalLink,
type MutationBatch,
type MutationWriteReceipt,
type MutationWriteResult,
Expand All @@ -69,7 +82,11 @@ export {
type ProposalRolledBackLedgerEvent,
type ProposalValidationResult,
type ReflectionNode,
type ReflectionNodeCheckpointedLedgerEvent,
type ReflectionNodeStatus,
type ReflectorBudgetCharge,
type ReflectorModelCallLedgerEvent,
type ReflectorToolCallLedgerEvent,
type ScoredProposal,
type ScoredProposalDisposition,
type SkillTarget,
Expand Down Expand Up @@ -111,6 +128,7 @@ export type {
EvolutionModelExecutor,
EvolutionModelRequest,
EvolutionModelResponse,
EvolutionModelTool,
EvolutionProgressEvent,
EvolutionSnapshotContext,
EvolutionSnapshotSource,
Expand Down Expand Up @@ -143,6 +161,17 @@ export {
type EvolutionRetentionPolicy,
planEvolutionRetention,
} from "./recovery.ts";
export {
RecursiveReflector,
type RecursiveReflectorDependencies,
type RecursiveReflectorOptions,
} from "./reflector.ts";
export {
type ReflectorToolAudit,
type ReflectorToolName,
ReflectorToolRegistry,
type ReflectorToolRegistryOptions,
} from "./reflector-tools.ts";
export {
EvolutionTargetAdapterRegistry,
type EvolutionTargetAdapterRegistryOptions,
Expand Down
Loading