| 630 | } |
| 631 | |
| 632 | export function buildHistoryCompactBlockFromSummary(input: { |
| 633 | sessionId: string; |
| 634 | foldedRuntimeEvents: readonly RuntimeEvent[]; |
| 635 | summary: string; |
| 636 | highWaterName?: string; |
| 637 | highWaterSeq?: number; |
| 638 | maxSummaryEstimatedTokens?: number; |
| 639 | sourceArchiveRefs?: readonly HistoryCompactSourceArchiveRef[]; |
| 640 | requestShapeHashBefore?: string; |
| 641 | requestShapeHashAfter?: string; |
| 642 | now?: number; |
| 643 | charsPerToken?: number; |
| 644 | }): HistoryCompactBlock { |
| 645 | const charsPerToken = input.charsPerToken ?? 4; |
| 646 | const highWaterName = input.highWaterName ?? 'history-compact-high-water'; |
| 647 | const createdAt = Math.max(input.now ?? 1, ...input.foldedRuntimeEvents.map((event) => event.ts)); |
| 648 | const highWaterSeq = input.highWaterSeq ?? createdAt; |
| 649 | const coverage = deriveHistoryCompactCoverage(input.foldedRuntimeEvents); |
| 650 | const sourceRefs: SynthesisSourceRef[] = input.foldedRuntimeEvents.map((event) => ({ |
| 651 | kind: 'runtime_event', |
| 652 | sessionId: event.sessionId, |
| 653 | turnId: turnKey(event), |
| 654 | runtimeEventId: event.id, |
| 655 | role: event.role, |
| 656 | contentKind: event.content?.kind ?? 'none', |
| 657 | })); |
| 658 | const maxSummaryTokens = finitePositive(input.maxSummaryEstimatedTokens) ?? 768; |
| 659 | const summary = boundText( |
| 660 | input.summary, |
| 661 | Math.max(80, maxSummaryTokens * Math.max(1, charsPerToken)), |
| 662 | ); |
| 663 | const blockDraft = { |
| 664 | version: 1, |
| 665 | sessionId: input.sessionId, |
| 666 | highWaterName, |
| 667 | highWaterSeq, |
| 668 | coverage, |
| 669 | summary, |
| 670 | }; |
| 671 | const sourceArchiveRefs = |
| 672 | input.sourceArchiveRefs?.filter(isValidHistoryCompactSourceArchiveRef) ?? []; |
| 673 | const block: HistoryCompactBlock = { |
| 674 | kind: 'maka.history_compact_block', |
| 675 | version: 1, |
| 676 | blockId: stableHistoryCompactBlockId(blockDraft), |
| 677 | sessionId: input.sessionId, |
| 678 | createdAt, |
| 679 | highWaterName, |
| 680 | highWaterSeq, |
| 681 | coverage, |
| 682 | summary, |
| 683 | limitations: [ |
| 684 | 'Host-owned replay-time summary of older RuntimeEvents.', |
| 685 | 'Original RuntimeEvents are not mutated; request raw evidence or history search when exact wording matters.', |
| 686 | ...(sourceArchiveRefs.length === 0 |
| 687 | ? [ |
| 688 | 'No archive refs are attached; source coverage is by RuntimeEvent ids and content hashes.', |
| 689 | ] |