import type { ClassifiedSection, ClassifierOutput, OrphanCandidate } from "../lib/section-types.js"; import { type ConversationSource } from "../lib/conversation-normalisers/types.js"; import type { InlineRewriteCandidate, InlineRewriteDeferred } from "../lib/compiled-truth-revision.js"; export declare function deriveSectionBodies(sections: ReadonlyArray>, cachedText: string, sourceKey?: string): string[]; export declare const RESERVED_SECTION_PROPERTY_KEYS: ReadonlySet; /** * Drop reserved writer-owned keys from an agent-supplied `section.properties` * bag. When any keys are stripped, emit one grep-able log line naming the * keys and the context (attachmentId or conversationIdentity:archiveSha256) * so the operator can attribute the smuggle attempt to a specific ingest. * * Mirrors the Task 465 `agent body suppressed` log shape — a quiet strip * with a loud trail. Returns a new object; never mutates the input. */ export declare function stripReservedSectionProperties(properties: Record, ctx: { kind: string; identity: string; }): Record; export interface IngestParams { accountId: string; /** * Document-path identity. Set when the parent is a file/URL/obsidian page — * the writer takes the document path (anchor edges, related entities, * extract cache, first-ingest semantics). * * Exactly one of `attachmentId` or `conversationIdentity` must be set. */ attachmentId?: string; /** * Conversation-path identity. Set when the parent is a chat transcript — * the writer takes the conversation-document path (delta-append after * cursor lookup, :PARTICIPANT_IN edges, archiveSha256 cleanup-on-rebuild, * no anchor / related discovery). * * Exactly one of `attachmentId` or `conversationIdentity` must be set. * The presence of `conversationIdentity` selects the conversation path, * which MERGEs the parent under `:ConversationArchive` (Task 397). The * `attachmentId` path MERGEs under `:KnowledgeDocument`. */ conversationIdentity?: string; documentSummary: string; /** * Element ID of the anchor node (UserProfile / LocalBusiness / Person / * Organization). Anchor identity is parameter input — never inferred. * Unused on the conversation-document path (chat participants attach via * :PARTICIPANT_IN, not via anchor edges) — pass any non-empty string. */ anchorNodeId: string; /** Anchor's primary label, used in the per-section MATCH for edge creation. */ anchorLabel: string; /** Sections returned by memory-classify, in reading order. */ sections: ClassifiedSection[]; /** Document-level edges (e.g. PARTY edges off KnowledgeDocument). */ documentEdges?: ClassifierOutput["documentEdges"]; /** Orphan candidates: nodes the classifier could not edge naturally. */ orphanCandidates?: OrphanCandidate[]; /** Visibility scope for all created nodes. Required. */ scope: string; /** Original URL for web-sourced documents. Absent for file uploads. */ sourceUrl?: string; /** Provenance discriminator: "upload" (default) or "web". */ sourceType?: string; /** LLM-extracted topic keywords (from memory-classify). */ documentKeywords?: string[]; /** User-supplied keywords (verbatim, normalised, deduplicated with documentKeywords). */ userKeywords?: string[]; /** Session UUID for provenance stamping. */ sessionId?: string; /** SHA-256 of THIS export's transcript bytes. Cleanup discriminator: only * chunks stamped with this sha256 are dropped on re-ingest, so delta * re-imports of newer exports leave prior chunks untouched. */ archiveSha256?: string; /** Original archive filename (basename, e.g. `_chat.txt`). Stamped on the * parent + every chunk for operator audit. */ archiveSourceFile?: string; /** Content hash of the LAST message ingested in this run (cursor advance). * Stamped on the :ConversationArchive parent so the next delta-append run * finds the cursor. */ lastIngestedMessageHash?: string; /** ISO 8601 dateSent of the last message ingested. Stamped on the parent * for the noop-reason message ("no new messages since "). */ lastIngestedMessageAt?: string; /** Operator-confirmed participant elementIds (:Person / :AdminUser) for * this conversation. Used to MERGE :PARTICIPANT_IN edges off the parent * on every ingest (idempotent). */ participantElementIds?: string[]; /** Conversation source enum. Required when `conversationIdentity` is set; * ignored on the document path. Stamped on the :ConversationArchive parent * and every :Section chunk so downstream queries can filter by source * without inferring from archiveSourceFile. The set is closed — see * `CONVERSATION_SOURCES`. */ source?: ConversationSource; /** sub-scope E — per-session checkpointing. * * When the bin calls `memoryIngest` once per session (instead of once per * archive), the cleanup-by-archiveSha256 step must run only on the FIRST * session of a run. Otherwise session N+1's call would delete session N's * just-written chunks (same conversationIdentity + same archiveSha256). * * sub-scope B — additionally gated on the bin's `--rebuild` * flag. Without `--rebuild`, re-issuing the bin on the same export bytes * is a no-op; the bin sets `cleanupPriorChunks=false` for every session. * With `--rebuild`, the bin sets `cleanupPriorChunks=true` only on the * first session. Ignored on the document path. */ cleanupPriorChunks?: boolean; /** Task 468 — per-session index used by the conversation-archive path to * locate the per-session turnText tempfile written by the bin * (`conversation-archive-ingest.mjs`). The writer constructs the file path * via `turnTextCachePath({ conversationIdentity, archiveSha256, * sessionIndex })`, reads it, and slices `:Section.body` server-side from * the loaded text. Required on the conversation-document path; ignored on * the document path. Integer >= 1. */ sessionIndex?: number; /** sub-scope A — stable title for the conversation-document parent. * Computed once per ingest by the bin from `(source, ownerName, * otherParticipantNames, firstMessageAt, lastMessageAt)`. Written ON * CREATE; on MATCH the existing `title` is preserved (COALESCE) so * re-ingests never overwrite a stable label. UI display-helpers prefer * `title` over `summary` for conversation-document rows — the per-session * counter strings that used to lock `summary` to "Session 1/N: …" are * gone. Ignored on the document path. */ archiveTitle?: string; /** * When true, after writing sections and edges, run the inline * compiled-truth reconciliation gate: count MENTIONS/REFERENCES edges * from the new document (KD and its sections) to existing entities * that have `compiledTruth`. Entities above `inlineRewriteThreshold` * and outside the 7-day cooldown are returned as `inlineRewriteCandidates` * in the result. Disabled by default. */ inlineRewrite?: boolean; /** * When `inlineRewrite` is true, bypass the 7-day per-entity cooldown on * `compiledTruthUpdatedAt`. All entities above threshold are returned as * candidates regardless of when their truth was last rewritten. */ forceRewrite?: boolean; /** * Minimum count of MENTIONS or REFERENCES edges from the new source * (KnowledgeDocument + its sections) to an existing entity for that * entity to qualify as an inline-rewrite candidate. Default: 2. */ inlineRewriteThreshold?: number; /** * Task 1555 — per-embed-POST progress callback. Passed straight to * `embedBatch` as its `onProgress`, so the tool handler can emit an MCP * `notifications/progress` per sub-batch POST during the embedding phase. * Those notifications reset Claude Code's ~30-minute stdio idle timer, so a * document whose embedding runs past that window still commits instead of * aborting mid-write. Absent for every non-MCP caller. */ reportProgress?: (done: number, total: number) => void; } /** Per-kind count breakdown the writer returns to the skill. */ export interface KindBreakdown { /** Section kind → count (e.g. {"Position": 4, "Chapter": 12, "Other": 1}). */ [kind: string]: number; } /** Per-edge-type count breakdown for anchor edges. */ export interface EdgeBreakdown { /** Edge type → count (e.g. {"HAS_POSITION": 4, "ATTENDED": 1, "PARTY": 2}). */ [edgeType: string]: number; } export interface IngestResult { documentNodeId: string; /** Total :Section nodes written. */ sectionCount: number; /** Per-section-kind count breakdown — drives the post-write chat narrative. */ kindBreakdown: KindBreakdown; /** Per-anchor-edge-type count breakdown — drives the post-write chat narrative. */ edgeBreakdown: EdgeBreakdown; /** Related entities created or merged (Organization, Person, DefinedTerm). */ relatedCount: number; /** Standalone nodes created (Project). */ standaloneCount: number; /** Orphan candidates surfaced from the classifier — NOT written, just relayed. */ orphanCandidates: OrphanCandidate[]; documentSummary: string; keywords?: string[]; /** sub-scope E — count of prior conversation-document :Section chunks * deleted by the cleanup-by-archiveSha256 step. Always 0 unless the * caller passed `cleanupPriorChunks=true`. The bin surfaces this as a * heartbeat WARN line so a destructive `--rebuild` is operator-visible * (defence-in-depth — `--rebuild` is the only legitimate trigger). */ cleanedPriorChunks?: number; /** * Entities above the MENTIONS/REFERENCES threshold that qualify for * inline compiled-truth rewrite. Populated only when `inlineRewrite=true`. * Dispatch the `compiled-truth-rewriter` specialist for each entity * before the calling skill returns — pass `nodeId` and optionally * an `operatorHint` if the document suggests a correction. */ inlineRewriteCandidates?: InlineRewriteCandidate[]; /** * Entities above threshold that were skipped because their * `compiledTruthUpdatedAt` is within the 7-day cooldown and * `forceRewrite` was not set. These remain candidates for the next * dream-cycle run. */ inlineRewriteDeferred?: InlineRewriteDeferred[]; } export declare function memoryIngest(params: IngestParams): Promise; //# sourceMappingURL=memory-ingest.d.ts.map