@martian-engineering/lossless-claw 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +22 -19
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -497,7 +497,7 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
497
497
|
LIMIT ?`).all(...args);return rows.map(row=>{const normalizedContent=normalizeMessageContentForFullTextIndex(row.content)??row.content;const haystack=normalizedContent.toLowerCase();const matchesAllTerms=plan.terms.every(term=>haystack.includes(term));if(!matchesAllTerms){return null}return{messageId:row.message_id,conversationId:row.conversation_id,role:row.role,snippet:createFallbackSnippet(normalizedContent,plan.terms),createdAt:parseUtcTimestamp(row.created_at),rank:0}}).filter(row=>row!==null)}searchRegex(pattern,limit,conversationId,since,before){if(pattern.length>500||/(\+|\*|\?)\)(\+|\*|\?|\{\d)/.test(pattern)){return[]}let re;try{re=new RegExp(pattern)}catch{return[]}const where=[];const args=[];if(conversationId!=null){where.push("conversation_id = ?");args.push(conversationId)}if(since){where.push("julianday(created_at) >= julianday(?)");args.push(since.toISOString())}if(before){where.push("julianday(created_at) < julianday(?)");args.push(before.toISOString())}const whereClause=where.length>0?`WHERE ${where.join(" AND ")}`:"";const rows=this.db.prepare(`SELECT message_id, conversation_id, seq, role, content, token_count, created_at
|
|
498
498
|
FROM messages
|
|
499
499
|
${whereClause}
|
|
500
|
-
ORDER BY created_at DESC`).all(...args);const MAX_ROW_SCAN=1e4;const results=[];let scanned=0;for(const row of rows){if(results.length>=limit||scanned>=MAX_ROW_SCAN){break}scanned++;const match=re.exec(row.content);if(match){results.push({messageId:row.message_id,conversationId:row.conversation_id,role:row.role,snippet:match[0],createdAt:parseUtcTimestamp(row.created_at),rank:0})}}return results}};var CJK_QUERY_SEGMENT_RE=/[\u2E80-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\uAC00-\uD7AF\u3040-\u309F\u30A0-\u30FF]+/g;var LATIN_QUERY_TOKEN_RE=/[a-zA-Z0-9][\w./-]*/g;function toSummaryRecord(row){let fileIds=[];try{fileIds=JSON.parse(row.file_ids)}catch{}return{summaryId:row.summary_id,conversationId:row.conversation_id,kind:row.kind,depth:row.depth,content:row.content,tokenCount:row.token_count,fileIds,earliestAt:parseUtcTimestampOrNull(row.earliest_at),latestAt:parseUtcTimestampOrNull(row.latest_at),descendantCount:typeof row.descendant_count==="number"&&Number.isFinite(row.descendant_count)&&row.descendant_count>=0?Math.floor(row.descendant_count):0,descendantTokenCount:typeof row.descendant_token_count==="number"&&Number.isFinite(row.descendant_token_count)&&row.descendant_token_count>=0?Math.floor(row.descendant_token_count):0,sourceMessageTokenCount:typeof row.source_message_token_count==="number"&&Number.isFinite(row.source_message_token_count)&&row.source_message_token_count>=0?Math.floor(row.source_message_token_count):0,model:typeof row.model==="string"?row.model:"unknown",createdAt:parseUtcTimestamp(row.created_at)}}function toContextItemRecord(row){return{conversationId:row.conversation_id,ordinal:row.ordinal,itemType:row.item_type,messageId:row.message_id,summaryId:row.summary_id,createdAt:parseUtcTimestamp(row.created_at)}}function toSearchResult2(row){return{summaryId:row.summary_id,conversationId:row.conversation_id,kind:row.kind,snippet:row.snippet,createdAt:parseUtcTimestamp(row.created_at),rank:row.rank}}function toLargeFileRecord(row){return{fileId:row.file_id,conversationId:row.conversation_id,fileName:row.file_name,mimeType:row.mime_type,byteSize:row.byte_size,storageUri:row.storage_uri,explorationSummary:row.exploration_summary,createdAt:parseUtcTimestamp(row.created_at)}}function toConversationBootstrapStateRecord(row){return{conversationId:row.conversation_id,sessionFilePath:row.session_file_path,lastSeenSize:row.last_seen_size,lastSeenMtimeMs:row.last_seen_mtime_ms,lastProcessedOffset:row.last_processed_offset,lastProcessedEntryHash:row.last_processed_entry_hash,updatedAt:parseUtcTimestamp(row.updated_at)}}function toTranscriptGcCandidateRecord(row){if(typeof row.tool_call_id!=="string"||row.tool_call_id.length===0){return null}let metadata=null;try{metadata=typeof row.metadata==="string"&&row.metadata.length>0?JSON.parse(row.metadata):null}catch{metadata=null}if(!metadata||metadata.toolOutputExternalized!==true){return null}return{messageId:row.message_id,conversationId:row.conversation_id,seq:row.seq,toolCallId:row.tool_call_id,toolName:row.tool_name,externalizedFileId:typeof metadata.externalizedFileId==="string"?metadata.externalizedFileId:null,originalByteSize:typeof metadata.originalByteSize==="number"&&Number.isFinite(metadata.originalByteSize)?Math.max(0,Math.floor(metadata.originalByteSize)):null}}var SummaryStore=class{constructor(db,options){this.db=db;this.fts5Available=options?.fts5Available??true}db;fts5Available;async insertSummary(input){const fileIds=JSON.stringify(input.fileIds??[]);const earliestAt=input.earliestAt instanceof Date?input.earliestAt.toISOString():null;const latestAt=input.latestAt instanceof Date?input.latestAt.toISOString():null;const descendantCount=typeof input.descendantCount==="number"&&Number.isFinite(input.descendantCount)&&input.descendantCount>=0?Math.floor(input.descendantCount):0;const descendantTokenCount=typeof input.descendantTokenCount==="number"&&Number.isFinite(input.descendantTokenCount)&&input.descendantTokenCount>=0?Math.floor(input.descendantTokenCount):0;const sourceMessageTokenCount=typeof input.sourceMessageTokenCount==="number"&&Number.isFinite(input.sourceMessageTokenCount)&&input.sourceMessageTokenCount>=0?Math.floor(input.sourceMessageTokenCount):0;const depth=typeof input.depth==="number"&&Number.isFinite(input.depth)&&input.depth>=0?Math.floor(input.depth):input.kind==="leaf"?0:1;this.db.prepare(`INSERT INTO summaries (
|
|
500
|
+
ORDER BY created_at DESC`).all(...args);const MAX_ROW_SCAN=1e4;const results=[];let scanned=0;for(const row of rows){if(results.length>=limit||scanned>=MAX_ROW_SCAN){break}scanned++;const match=re.exec(row.content);if(match){results.push({messageId:row.message_id,conversationId:row.conversation_id,role:row.role,snippet:match[0],createdAt:parseUtcTimestamp(row.created_at),rank:0})}}return results}};var SUMMARY_SEARCH_TIME_EXPR="COALESCE(s.latest_at, s.created_at)";var SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED="COALESCE(latest_at, created_at)";var CJK_QUERY_SEGMENT_RE=/[\u2E80-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\uAC00-\uD7AF\u3040-\u309F\u30A0-\u30FF]+/g;var LATIN_QUERY_TOKEN_RE=/[a-zA-Z0-9][\w./-]*/g;function toSummaryRecord(row){let fileIds=[];try{fileIds=JSON.parse(row.file_ids)}catch{}return{summaryId:row.summary_id,conversationId:row.conversation_id,kind:row.kind,depth:row.depth,content:row.content,tokenCount:row.token_count,fileIds,earliestAt:parseUtcTimestampOrNull(row.earliest_at),latestAt:parseUtcTimestampOrNull(row.latest_at),descendantCount:typeof row.descendant_count==="number"&&Number.isFinite(row.descendant_count)&&row.descendant_count>=0?Math.floor(row.descendant_count):0,descendantTokenCount:typeof row.descendant_token_count==="number"&&Number.isFinite(row.descendant_token_count)&&row.descendant_token_count>=0?Math.floor(row.descendant_token_count):0,sourceMessageTokenCount:typeof row.source_message_token_count==="number"&&Number.isFinite(row.source_message_token_count)&&row.source_message_token_count>=0?Math.floor(row.source_message_token_count):0,model:typeof row.model==="string"?row.model:"unknown",createdAt:parseUtcTimestamp(row.created_at)}}function toContextItemRecord(row){return{conversationId:row.conversation_id,ordinal:row.ordinal,itemType:row.item_type,messageId:row.message_id,summaryId:row.summary_id,createdAt:parseUtcTimestamp(row.created_at)}}function toSearchResult2(row){return{summaryId:row.summary_id,conversationId:row.conversation_id,kind:row.kind,snippet:row.snippet,createdAt:parseUtcTimestamp(row.created_at),rank:row.rank}}function toLargeFileRecord(row){return{fileId:row.file_id,conversationId:row.conversation_id,fileName:row.file_name,mimeType:row.mime_type,byteSize:row.byte_size,storageUri:row.storage_uri,explorationSummary:row.exploration_summary,createdAt:parseUtcTimestamp(row.created_at)}}function toConversationBootstrapStateRecord(row){return{conversationId:row.conversation_id,sessionFilePath:row.session_file_path,lastSeenSize:row.last_seen_size,lastSeenMtimeMs:row.last_seen_mtime_ms,lastProcessedOffset:row.last_processed_offset,lastProcessedEntryHash:row.last_processed_entry_hash,updatedAt:parseUtcTimestamp(row.updated_at)}}function toTranscriptGcCandidateRecord(row){if(typeof row.tool_call_id!=="string"||row.tool_call_id.length===0){return null}let metadata=null;try{metadata=typeof row.metadata==="string"&&row.metadata.length>0?JSON.parse(row.metadata):null}catch{metadata=null}if(!metadata||metadata.toolOutputExternalized!==true){return null}return{messageId:row.message_id,conversationId:row.conversation_id,seq:row.seq,toolCallId:row.tool_call_id,toolName:row.tool_name,externalizedFileId:typeof metadata.externalizedFileId==="string"?metadata.externalizedFileId:null,originalByteSize:typeof metadata.originalByteSize==="number"&&Number.isFinite(metadata.originalByteSize)?Math.max(0,Math.floor(metadata.originalByteSize)):null}}var SummaryStore=class{constructor(db,options){this.db=db;this.fts5Available=options?.fts5Available??true}db;fts5Available;async insertSummary(input){const fileIds=JSON.stringify(input.fileIds??[]);const earliestAt=input.earliestAt instanceof Date?input.earliestAt.toISOString():null;const latestAt=input.latestAt instanceof Date?input.latestAt.toISOString():null;const descendantCount=typeof input.descendantCount==="number"&&Number.isFinite(input.descendantCount)&&input.descendantCount>=0?Math.floor(input.descendantCount):0;const descendantTokenCount=typeof input.descendantTokenCount==="number"&&Number.isFinite(input.descendantTokenCount)&&input.descendantTokenCount>=0?Math.floor(input.descendantTokenCount):0;const sourceMessageTokenCount=typeof input.sourceMessageTokenCount==="number"&&Number.isFinite(input.sourceMessageTokenCount)&&input.sourceMessageTokenCount>=0?Math.floor(input.sourceMessageTokenCount):0;const depth=typeof input.depth==="number"&&Number.isFinite(input.depth)&&input.depth>=0?Math.floor(input.depth):input.kind==="leaf"?0:1;this.db.prepare(`INSERT INTO summaries (
|
|
501
501
|
summary_id,
|
|
502
502
|
conversation_id,
|
|
503
503
|
kind,
|
|
@@ -668,46 +668,49 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
668
668
|
JOIN summaries s ON s.summary_id = ci.summary_id
|
|
669
669
|
WHERE ci.conversation_id = ?
|
|
670
670
|
AND ci.item_type = 'summary'
|
|
671
|
-
) sub`).get(conversationId,conversationId);return row?.total??0}async searchSummaries(input){const limit=input.limit??50;if(input.mode==="full_text"){if(containsCjk(input.query)){const cjkSegments=this.extractCjkSegments(input.query);const hasShortCjkSegment=cjkSegments.some(segment=>segment.length<3);if(!hasShortCjkSegment){try{const trigramResults=this.searchCjkTrigram(input.query,limit,input.conversationId,input.since,input.before);if(trigramResults.length>0){return trigramResults}}catch{}}return this.searchLikeCjk(input.query,limit,input.conversationId,input.since,input.before)}if(this.fts5Available){try{return this.searchFullText(input.query,limit,input.conversationId,input.since,input.before,input.sort)}catch{return this.searchLike(input.query,limit,input.conversationId,input.since,input.before)}}return this.searchLike(input.query,limit,input.conversationId,input.since,input.before)}return this.searchRegex(input.query,limit,input.conversationId,input.since,input.before)}searchFullText(query,limit,conversationId,since,before,sort){const where=["summaries_fts MATCH ?"];const args=[sanitizeFts5Query(query)];if(conversationId!=null){where.push("s.conversation_id = ?");args.push(conversationId)}if(since){where.push(
|
|
671
|
+
) sub`).get(conversationId,conversationId);return row?.total??0}async searchSummaries(input){const limit=input.limit??50;if(input.mode==="full_text"){if(containsCjk(input.query)){const cjkSegments=this.extractCjkSegments(input.query);const hasShortCjkSegment=cjkSegments.some(segment=>segment.length<3);if(!hasShortCjkSegment){try{const trigramResults=this.searchCjkTrigram(input.query,limit,input.conversationId,input.since,input.before,input.sort);if(trigramResults.length>0){return trigramResults}}catch{}}return this.searchLikeCjk(input.query,limit,input.conversationId,input.since,input.before)}if(this.fts5Available){try{return this.searchFullText(input.query,limit,input.conversationId,input.since,input.before,input.sort)}catch{return this.searchLike(input.query,limit,input.conversationId,input.since,input.before)}}return this.searchLike(input.query,limit,input.conversationId,input.since,input.before)}return this.searchRegex(input.query,limit,input.conversationId,input.since,input.before)}searchFullText(query,limit,conversationId,since,before,sort){const where=["summaries_fts MATCH ?"];const args=[sanitizeFts5Query(query)];if(conversationId!=null){where.push("s.conversation_id = ?");args.push(conversationId)}if(since){where.push(`julianday(${SUMMARY_SEARCH_TIME_EXPR}) >= julianday(?)`);args.push(since.toISOString())}if(before){where.push(`julianday(${SUMMARY_SEARCH_TIME_EXPR}) < julianday(?)`);args.push(before.toISOString())}args.push(limit);const orderBy=buildFtsOrderBy(sort,SUMMARY_SEARCH_TIME_EXPR);const sql=`SELECT
|
|
672
672
|
summaries_fts.summary_id,
|
|
673
673
|
s.conversation_id,
|
|
674
674
|
s.kind,
|
|
675
675
|
snippet(summaries_fts, 1, '', '', '...', 32) AS snippet,
|
|
676
676
|
rank,
|
|
677
|
-
|
|
677
|
+
${SUMMARY_SEARCH_TIME_EXPR} AS created_at
|
|
678
678
|
FROM summaries_fts
|
|
679
679
|
JOIN summaries s ON s.summary_id = summaries_fts.summary_id
|
|
680
680
|
WHERE ${where.join(" AND ")}
|
|
681
681
|
ORDER BY ${orderBy}
|
|
682
|
-
LIMIT ?`;const rows=this.db.prepare(sql).all(...args);return rows.map(toSearchResult2)}searchLike(query,limit,conversationId,since,before){const plan=buildLikeSearchPlan("content",query);if(plan.terms.length===0){return[]}const where=[...plan.where];const args=[...plan.args];if(conversationId!=null){where.push("conversation_id = ?");args.push(conversationId)}if(since){where.push(
|
|
682
|
+
LIMIT ?`;const rows=this.db.prepare(sql).all(...args);return rows.map(toSearchResult2)}searchLike(query,limit,conversationId,since,before){const plan=buildLikeSearchPlan("content",query);if(plan.terms.length===0){return[]}const where=[...plan.where];const args=[...plan.args];if(conversationId!=null){where.push("conversation_id = ?");args.push(conversationId)}if(since){where.push(`julianday(${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED}) >= julianday(?)`);args.push(since.toISOString())}if(before){where.push(`julianday(${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED}) < julianday(?)`);args.push(before.toISOString())}args.push(limit);const whereClause=where.length>0?`WHERE ${where.join(" AND ")}`:"";const rows=this.db.prepare(`SELECT summary_id, conversation_id, kind, depth, content, token_count, file_ids,
|
|
683
683
|
earliest_at, latest_at, descendant_count, descendant_token_count,
|
|
684
|
-
source_message_token_count, model,
|
|
684
|
+
source_message_token_count, model,
|
|
685
|
+
${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED} AS created_at
|
|
685
686
|
FROM summaries
|
|
686
687
|
${whereClause}
|
|
687
|
-
ORDER BY
|
|
688
|
-
LIMIT ?`).all(...args);return rows.map(row=>({summaryId:row.summary_id,conversationId:row.conversation_id,kind:row.kind,snippet:createFallbackSnippet(row.content,plan.terms),createdAt:parseUtcTimestamp(row.created_at),rank:0}))}extractCjkSegments(query){return query.match(CJK_QUERY_SEGMENT_RE)??[]}extractLatinTokens(query){const tokens=query.match(LATIN_QUERY_TOKEN_RE)??[];return[...new Set(tokens.map(token=>token.toLowerCase()))]}escapeLikeTerm(term){return term.replace(/([\\%_])/g,"\\$1")}splitCjkChunks(text,size){const chunks=[];for(let i=0;i<=text.length-size;i++){const chunk=text.slice(i,i+size);if(!chunks.includes(chunk)){chunks.push(chunk)}}return chunks}searchCjkTrigram(query,limit,conversationId,since,before){const cjkSegments=this.extractCjkSegments(query).filter(segment=>segment.length>=3);if(cjkSegments.length===0){return[]}const latinTokens=this.extractLatinTokens(query);const cjkGroups=[];for(const segment of cjkSegments){const segmentTerms=segment.length<=4?[segment]:this.splitCjkChunks(segment,4);const groupExpr=[...new Set(segmentTerms)].map(term=>`"${term.replace(/"/g,'""')}"`).join(" OR ");cjkGroups.push(`(${groupExpr})`)}const where=["summaries_fts_cjk MATCH ?"];const args=[cjkGroups.join(" AND ")];for(const token of latinTokens){where.push("LOWER(s.content) LIKE ? ESCAPE '\\'");args.push(`%${this.escapeLikeTerm(token)}%`)}if(conversationId!=null){where.push("s.conversation_id = ?");args.push(conversationId)}if(since){where.push(
|
|
688
|
+
ORDER BY ${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED} DESC
|
|
689
|
+
LIMIT ?`).all(...args);return rows.map(row=>({summaryId:row.summary_id,conversationId:row.conversation_id,kind:row.kind,snippet:createFallbackSnippet(row.content,plan.terms),createdAt:parseUtcTimestamp(row.created_at),rank:0}))}extractCjkSegments(query){return query.match(CJK_QUERY_SEGMENT_RE)??[]}extractLatinTokens(query){const tokens=query.match(LATIN_QUERY_TOKEN_RE)??[];return[...new Set(tokens.map(token=>token.toLowerCase()))]}escapeLikeTerm(term){return term.replace(/([\\%_])/g,"\\$1")}splitCjkChunks(text,size){const chunks=[];for(let i=0;i<=text.length-size;i++){const chunk=text.slice(i,i+size);if(!chunks.includes(chunk)){chunks.push(chunk)}}return chunks}searchCjkTrigram(query,limit,conversationId,since,before,sort){const cjkSegments=this.extractCjkSegments(query).filter(segment=>segment.length>=3);if(cjkSegments.length===0){return[]}const latinTokens=this.extractLatinTokens(query);const cjkGroups=[];for(const segment of cjkSegments){const segmentTerms=segment.length<=4?[segment]:this.splitCjkChunks(segment,4);const groupExpr=[...new Set(segmentTerms)].map(term=>`"${term.replace(/"/g,'""')}"`).join(" OR ");cjkGroups.push(`(${groupExpr})`)}const where=["summaries_fts_cjk MATCH ?"];const args=[cjkGroups.join(" AND ")];for(const token of latinTokens){where.push("LOWER(s.content) LIKE ? ESCAPE '\\'");args.push(`%${this.escapeLikeTerm(token)}%`)}if(conversationId!=null){where.push("s.conversation_id = ?");args.push(conversationId)}if(since){where.push(`julianday(${SUMMARY_SEARCH_TIME_EXPR}) >= julianday(?)`);args.push(since.toISOString())}if(before){where.push(`julianday(${SUMMARY_SEARCH_TIME_EXPR}) < julianday(?)`);args.push(before.toISOString())}args.push(limit);const orderBy=buildFtsOrderBy(sort,SUMMARY_SEARCH_TIME_EXPR);const sql=`SELECT
|
|
689
690
|
f.summary_id,
|
|
690
691
|
s.conversation_id,
|
|
691
692
|
s.kind,
|
|
692
693
|
snippet(summaries_fts_cjk, 1, '', '', '...', 32) AS snippet,
|
|
693
694
|
rank,
|
|
694
|
-
|
|
695
|
+
${SUMMARY_SEARCH_TIME_EXPR} AS created_at
|
|
695
696
|
FROM summaries_fts_cjk f
|
|
696
697
|
JOIN summaries s ON s.summary_id = f.summary_id
|
|
697
698
|
WHERE ${where.join(" AND ")}
|
|
698
|
-
ORDER BY
|
|
699
|
-
LIMIT ?`;const rows=this.db.prepare(sql).all(...args);return rows.map(toSearchResult2)}searchLikeCjk(query,limit,conversationId,since,before){const cjkSegments=this.extractCjkSegments(query);const latinTokens=this.extractLatinTokens(query);if(cjkSegments.length===0&&latinTokens.length===0){return[]}const cjkTerms=[];const cjkClauses=[];const cjkArgs=[];for(const segment of cjkSegments){const segmentTerms=segment.length===1?[segment]:segment.length===2?[segment]:this.splitCjkChunks(segment,2);const uniqueTerms=[...new Set(segmentTerms)];cjkTerms.push(...uniqueTerms);cjkClauses.push(`(${uniqueTerms.map(()=>`LOWER(content) LIKE ? ESCAPE '\\'`).join(" OR ")})`);cjkArgs.push(...uniqueTerms.map(term=>`%${this.escapeLikeTerm(term.toLowerCase())}%`))}const latinClauses=latinTokens.map(()=>`LOWER(content) LIKE ? ESCAPE '\\'`);const latinArgs=latinTokens.map(token=>`%${this.escapeLikeTerm(token)}%`);const where=[...cjkClauses,...latinClauses];const args=[...cjkArgs,...latinArgs];if(conversationId!=null){where.push("conversation_id = ?");args.push(conversationId)}if(since){where.push(
|
|
699
|
+
ORDER BY ${orderBy}
|
|
700
|
+
LIMIT ?`;const rows=this.db.prepare(sql).all(...args);return rows.map(toSearchResult2)}searchLikeCjk(query,limit,conversationId,since,before){const cjkSegments=this.extractCjkSegments(query);const latinTokens=this.extractLatinTokens(query);if(cjkSegments.length===0&&latinTokens.length===0){return[]}const cjkTerms=[];const cjkClauses=[];const cjkArgs=[];for(const segment of cjkSegments){const segmentTerms=segment.length===1?[segment]:segment.length===2?[segment]:this.splitCjkChunks(segment,2);const uniqueTerms=[...new Set(segmentTerms)];cjkTerms.push(...uniqueTerms);cjkClauses.push(`(${uniqueTerms.map(()=>`LOWER(content) LIKE ? ESCAPE '\\'`).join(" OR ")})`);cjkArgs.push(...uniqueTerms.map(term=>`%${this.escapeLikeTerm(term.toLowerCase())}%`))}const latinClauses=latinTokens.map(()=>`LOWER(content) LIKE ? ESCAPE '\\'`);const latinArgs=latinTokens.map(token=>`%${this.escapeLikeTerm(token)}%`);const where=[...cjkClauses,...latinClauses];const args=[...cjkArgs,...latinArgs];if(conversationId!=null){where.push("conversation_id = ?");args.push(conversationId)}if(since){where.push(`julianday(${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED}) >= julianday(?)`);args.push(since.toISOString())}if(before){where.push(`julianday(${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED}) < julianday(?)`);args.push(before.toISOString())}args.push(limit);const rows=this.db.prepare(`SELECT summary_id, conversation_id, kind, depth, content, token_count, file_ids,
|
|
700
701
|
earliest_at, latest_at, descendant_count, descendant_token_count,
|
|
701
|
-
source_message_token_count, model,
|
|
702
|
+
source_message_token_count, model,
|
|
703
|
+
${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED} AS created_at
|
|
702
704
|
FROM summaries
|
|
703
705
|
WHERE ${where.join(" AND ")}
|
|
704
|
-
ORDER BY
|
|
705
|
-
LIMIT ?`).all(...args);const snippetTerms=cjkTerms.length>0?[...new Set([...cjkTerms,...latinTokens])]:latinTokens;return rows.map(row=>({summaryId:row.summary_id,conversationId:row.conversation_id,kind:row.kind,snippet:createFallbackSnippet(row.content,snippetTerms),createdAt:new Date(row.created_at),rank:0}))}searchRegex(pattern,limit,conversationId,since,before){if(pattern.length>500||/(\+|\*|\?)\)(\+|\*|\?|\{\d)/.test(pattern)){return[]}let re;try{re=new RegExp(pattern)}catch{return[]}const where=[];const args=[];if(conversationId!=null){where.push("conversation_id = ?");args.push(conversationId)}if(since){where.push(
|
|
706
|
+
ORDER BY ${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED} DESC
|
|
707
|
+
LIMIT ?`).all(...args);const snippetTerms=cjkTerms.length>0?[...new Set([...cjkTerms,...latinTokens])]:latinTokens;return rows.map(row=>({summaryId:row.summary_id,conversationId:row.conversation_id,kind:row.kind,snippet:createFallbackSnippet(row.content,snippetTerms),createdAt:new Date(row.created_at),rank:0}))}searchRegex(pattern,limit,conversationId,since,before){if(pattern.length>500||/(\+|\*|\?)\)(\+|\*|\?|\{\d)/.test(pattern)){return[]}let re;try{re=new RegExp(pattern)}catch{return[]}const where=[];const args=[];if(conversationId!=null){where.push("conversation_id = ?");args.push(conversationId)}if(since){where.push(`julianday(${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED}) >= julianday(?)`);args.push(since.toISOString())}if(before){where.push(`julianday(${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED}) < julianday(?)`);args.push(before.toISOString())}const whereClause=where.length>0?`WHERE ${where.join(" AND ")}`:"";const rows=this.db.prepare(`SELECT summary_id, conversation_id, kind, depth, content, token_count, file_ids,
|
|
706
708
|
earliest_at, latest_at, descendant_count, descendant_token_count,
|
|
707
|
-
source_message_token_count, model,
|
|
709
|
+
source_message_token_count, model,
|
|
710
|
+
${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED} AS created_at
|
|
708
711
|
FROM summaries
|
|
709
712
|
${whereClause}
|
|
710
|
-
ORDER BY
|
|
713
|
+
ORDER BY ${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED} DESC`).all(...args);const MAX_ROW_SCAN=1e4;const results=[];let scanned=0;for(const row of rows){if(results.length>=limit||scanned>=MAX_ROW_SCAN){break}scanned++;const match=re.exec(row.content);if(match){results.push({summaryId:row.summary_id,conversationId:row.conversation_id,kind:row.kind,snippet:match[0],createdAt:parseUtcTimestamp(row.created_at),rank:0})}}return results}async insertLargeFile(input){this.db.prepare(`INSERT INTO large_files (file_id, conversation_id, file_name, mime_type, byte_size, storage_uri, exploration_summary)
|
|
711
714
|
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(input.fileId,input.conversationId,input.fileName??null,input.mimeType??null,input.byteSize??null,input.storageUri,input.explorationSummary??null);const row=this.db.prepare(`SELECT file_id, conversation_id, file_name, mime_type, byte_size, storage_uri, exploration_summary, created_at
|
|
712
715
|
FROM large_files WHERE file_id = ?`).get(input.fileId);return toLargeFileRecord(row)}async getLargeFile(fileId){const row=this.db.prepare(`SELECT file_id, conversation_id, file_name, mime_type, byte_size, storage_uri, exploration_summary, created_at
|
|
713
716
|
FROM large_files WHERE file_id = ?`).get(fileId);return row?toLargeFileRecord(row):null}async getLargeFilesByConversation(conversationId){const rows=this.db.prepare(`SELECT file_id, conversation_id, file_name, mime_type, byte_size, storage_uri, exploration_summary, created_at
|
|
@@ -734,12 +737,12 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
734
737
|
updated_at = datetime('now')`).run(input.conversationId,input.sessionFilePath,Math.max(0,Math.floor(input.lastSeenSize)),Math.max(0,Math.floor(input.lastSeenMtimeMs)),Math.max(0,Math.floor(input.lastProcessedOffset)),input.lastProcessedEntryHash??null);const row=this.db.prepare(`SELECT conversation_id, session_file_path, last_seen_size, last_seen_mtime_ms,
|
|
735
738
|
last_processed_offset, last_processed_entry_hash, updated_at
|
|
736
739
|
FROM conversation_bootstrap_state
|
|
737
|
-
WHERE conversation_id = ?`).get(input.conversationId);return toConversationBootstrapStateRecord(row)}};import{rmSync,renameSync}from"node:fs";import{basename,dirname as dirname2,join as join2}from"node:path";function quoteSqlString(value){return`'${value.replaceAll("'","''")}'`}function normalizeBackupLabel(label){const normalized=label.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");return normalized||"backup"}function buildLcmDatabaseBackupPath(databasePath,label){const fileBackedDatabasePath=getFileBackedDatabasePath(databasePath);if(!fileBackedDatabasePath){return null}const timestamp=new Date().toISOString().replace(/[-:.]/g,"");const suffix=Math.random().toString(36).slice(2,8);return join2(dirname2(fileBackedDatabasePath),`${basename(fileBackedDatabasePath)}.${normalizeBackupLabel(label)}-${timestamp}-${suffix}.bak`)}function buildLcmDatabaseLatestBackupPath(databasePath,label){const fileBackedDatabasePath=getFileBackedDatabasePath(databasePath);if(!fileBackedDatabasePath){return null}return join2(dirname2(fileBackedDatabasePath),`${basename(fileBackedDatabasePath)}.${normalizeBackupLabel(label)}-latest.bak`)}function writeLcmDatabaseBackup(db,backupPath){db.exec(`VACUUM INTO ${quoteSqlString(backupPath)}`)}function createLcmDatabaseBackup(db,options){if(options.replaceLatest){const latestBackupPath=buildLcmDatabaseLatestBackupPath(options.databasePath,options.label);const tempBackupPath=buildLcmDatabaseBackupPath(options.databasePath,`${options.label}-tmp`);if(!latestBackupPath||!tempBackupPath){return null}try{writeLcmDatabaseBackup(db,tempBackupPath);rmSync(latestBackupPath,{force:true});renameSync(tempBackupPath,latestBackupPath);return latestBackupPath}catch(error){rmSync(tempBackupPath,{force:true});throw error}}const backupPath=buildLcmDatabaseBackupPath(options.databasePath,options.label);if(!backupPath){return null}writeLcmDatabaseBackup(db,backupPath);return backupPath}var TRANSCRIPT_GC_BATCH_SIZE=12;var HOT_CACHE_HYSTERESIS_TURNS=2;var DYNAMIC_LEAF_CHUNK_MEDIUM_MULTIPLIER=1.5;var DYNAMIC_LEAF_CHUNK_HIGH_MULTIPLIER=2;var DYNAMIC_ACTIVITY_MEDIUM_UPSHIFT_FACTOR=.5;var DYNAMIC_ACTIVITY_MEDIUM_DOWNSHIFT_FACTOR=.35;var DYNAMIC_ACTIVITY_HIGH_UPSHIFT_FACTOR=1;var DYNAMIC_ACTIVITY_HIGH_DOWNSHIFT_FACTOR=.75;function toJson(value){const encoded=JSON.stringify(value);return typeof encoded==="string"?encoded:""}function safeString(value){return typeof value==="string"?value:void 0}function formatDurationMs(durationMs){return`${durationMs}ms`}function asRecord(value){return value&&typeof value==="object"&&!Array.isArray(value)?value:void 0}function safeBoolean(value){return typeof value==="boolean"?value:void 0}function extractTranscriptToolCallId(message){const topLevel=message;const direct=safeString(topLevel.toolCallId)??safeString(topLevel.tool_call_id)??safeString(topLevel.toolUseId)??safeString(topLevel.tool_use_id)??safeString(topLevel.call_id)??safeString(topLevel.id);if(direct){return direct}if(!Array.isArray(topLevel.content)){return void 0}for(const item of topLevel.content){const record=asRecord(item);if(!record){continue}const nested=safeString(record.toolCallId)??safeString(record.tool_call_id)??safeString(record.toolUseId)??safeString(record.tool_use_id)??safeString(record.call_id)??safeString(record.id);if(nested){return nested}}return void 0}function listTranscriptToolResultEntryIdsByCallId(sessionFile){const sessionManager=SessionManager.open(sessionFile);const branch=sessionManager.getBranch();const entryIdsByCallId=new Map;const duplicateCallIds=new Set;for(const entry of branch){if(entry.type!=="message"||entry.message.role!=="toolResult"){continue}const toolCallId=extractTranscriptToolCallId(entry.message);if(!toolCallId){continue}if(entryIdsByCallId.has(toolCallId)){duplicateCallIds.add(toolCallId);continue}entryIdsByCallId.set(toolCallId,entry.id)}for(const duplicateCallId of duplicateCallIds){entryIdsByCallId.delete(duplicateCallId)}return entryIdsByCallId}function isRotatePreservedEntryType(type){return type==="message"||type==="model_change"||type==="thinking_level_change"||type==="session_info"}function normalizeRotateTailMessageCount(value,branchMessageCount){if(branchMessageCount<=0){return 0}if(!Number.isFinite(value)){return 1}return Math.max(1,Math.min(branchMessageCount,Math.floor(value)))}function appendTextValue2(value,out){if(typeof value==="string"){out.push(value);return}if(Array.isArray(value)){for(const entry of value){appendTextValue2(entry,out)}return}if(!value||typeof value!=="object"){return}const record=value;appendTextValue2(record.text,out);appendTextValue2(record.value,out)}var STRUCTURED_TEXT_FIELD_KEYS=["text","transcript","transcription","message","summary"];var STRUCTURED_ARRAY_FIELD_KEYS=["segments","utterances","paragraphs","alternatives","words","items","results"];var STRUCTURED_NESTED_FIELD_KEYS=["content","output","result","payload","data","value"];var MAX_STRUCTURED_TEXT_DEPTH=6;var TOOL_RAW_TYPES=new Set(["tool_use","toolUse","tool-use","toolCall","tool_call","functionCall","function_call","function_call_output","tool_result","toolResult","tool_use_result"]);function looksLikeJsonPayload(value){const trimmed=value.trim();if(!trimmed){return false}return trimmed.startsWith("{")&&trimmed.endsWith("}")||trimmed.startsWith("[")&&trimmed.endsWith("]")}function extractStructuredText(value,depth=0){if(value==null||depth>MAX_STRUCTURED_TEXT_DEPTH){return void 0}if(typeof value==="string"){if(looksLikeJsonPayload(value)){try{const parsed=JSON.parse(value.trim());const parsedText=extractStructuredText(parsed,depth+1);if(typeof parsedText==="string"&&parsedText.length>0){return parsedText}}catch{}}return value}if(Array.isArray(value)){const texts=[];for(const entry of value){const text=extractStructuredText(entry,depth+1);if(typeof text==="string"&&text.trim().length>0){texts.push(text)}}return texts.length>0?texts.join("\n"):void 0}if(typeof value!=="object"){return void 0}const record=value;if(typeof record.type==="string"&&TOOL_RAW_TYPES.has(record.type)){if(safeBoolean(record.toolOutputExternalized)){const externalizedText=extractStructuredText(record.output,depth+1)??extractStructuredText(record.content,depth+1)??extractStructuredText(record.result,depth+1);if(typeof externalizedText==="string"&&externalizedText.trim().length>0){return externalizedText}}return void 0}for(const key of STRUCTURED_TEXT_FIELD_KEYS){const candidate=record[key];if(typeof candidate==="string"&&candidate.trim().length>0){return candidate}}for(const key of STRUCTURED_ARRAY_FIELD_KEYS){const candidate=record[key];if(Array.isArray(candidate)){const texts=[];for(const entry of candidate){const text=extractStructuredText(entry,depth+1);if(typeof text==="string"&&text.trim().length>0){texts.push(text)}}if(texts.length>0){return texts.join("\n")}}}for(const key of STRUCTURED_NESTED_FIELD_KEYS){const nested=record[key];const nestedText=extractStructuredText(nested,depth+1);if(typeof nestedText==="string"&&nestedText.trim().length>0){return nestedText}}return void 0}function extractReasoningText(record){const chunks=[];appendTextValue2(record.summary,chunks);if(chunks.length===0){return void 0}const normalized=chunks.map(chunk=>chunk.trim()).filter((chunk,idx,arr)=>chunk.length>0&&arr.indexOf(chunk)===idx);return normalized.length>0?normalized.join("\n"):void 0}function normalizeUnknownBlock(value){if(!value||typeof value!=="object"||Array.isArray(value)){return{type:"agent",metadata:{raw:value}}}const record=value;const rawType=safeString(record.type);return{type:rawType??"agent",text:safeString(record.text)??safeString(record.thinking)??(rawType==="reasoning"||rawType==="thinking"?extractReasoningText(record):void 0),metadata:{raw:record}}}function toPartType(type){switch(type){case"text":return"text";case"thinking":case"reasoning":return"reasoning";case"tool_use":case"toolUse":case"tool-use":case"toolCall":case"functionCall":case"function_call":case"function_call_output":case"tool_result":case"toolResult":case"tool":return"tool";case"patch":return"patch";case"file":case"image":return"file";case"subtask":return"subtask";case"compaction":return"compaction";case"step_start":case"step-start":return"step_start";case"step_finish":case"step-finish":return"step_finish";case"snapshot":return"snapshot";case"retry":return"retry";case"agent":return"agent";default:return"agent"}}function extractMessageContent(content){const extracted=extractStructuredText(content);if(typeof extracted==="string"){return extracted}if(content==null){return""}if(Array.isArray(content)&&content.length===0){return""}if(Array.isArray(content)&&content.length>0&&content.every(item=>typeof item==="object"&&item!==null&&!Array.isArray(item)&&typeof item.type==="string"&&TOOL_RAW_TYPES.has(item.type))){return""}const serialized=JSON.stringify(content);return typeof serialized==="string"?serialized:""}function toRuntimeRoleForTokenEstimate(role){if(role==="tool"||role==="toolResult"){return"toolResult"}if(role==="user"||role==="system"){return"user"}return"assistant"}function isTextBlock(value){if(!value||typeof value!=="object"||Array.isArray(value)){return false}const record=value;return record.type==="text"&&typeof record.text==="string"}function toSyntheticMessagePartRecord(part,messageId){return{partId:`estimate-part-${part.ordinal}`,messageId,sessionId:part.sessionId,partType:part.partType,ordinal:part.ordinal,textContent:part.textContent??null,toolCallId:part.toolCallId??null,toolName:part.toolName??null,toolInput:part.toolInput??null,toolOutput:part.toolOutput??null,metadata:part.metadata??null}}function normalizeMessageContentForStorage(params){const{message,fallbackContent}=params;if(!("content"in message)){return fallbackContent}const role=toRuntimeRoleForTokenEstimate(message.role);const parts=buildMessageParts({sessionId:"storage-estimate",message,fallbackContent}).map(part=>toSyntheticMessagePartRecord(part,0));if(parts.length===0){if(role==="assistant"){return fallbackContent?[{type:"text",text:fallbackContent}]:[]}if(role==="toolResult"){return[{type:"text",text:fallbackContent}]}return fallbackContent}const blocks=parts.map(blockFromPart);if(role==="user"&&blocks.length===1&&isTextBlock(blocks[0])){return blocks[0].text}return blocks}function estimateContentTokensForRole(params){const{role,content,fallbackContent}=params;if(typeof content==="string"){return estimateTokens(content)}if(Array.isArray(content)){if(content.length===0){return estimateTokens(fallbackContent)}if(role==="user"&&content.length===1&&isTextBlock(content[0])){return estimateTokens(content[0].text)}const serialized=JSON.stringify(content);return estimateTokens(typeof serialized==="string"?serialized:"")}if(content&&typeof content==="object"){if(role==="user"&&isTextBlock(content)){return estimateTokens(content.text)}const serialized=JSON.stringify([content]);return estimateTokens(typeof serialized==="string"?serialized:"")}return estimateTokens(fallbackContent)}function buildMessageParts(params){const{sessionId,message,fallbackContent}=params;const role=typeof message.role==="string"?message.role:"unknown";const topLevel=message;const topLevelToolCallId=safeString(topLevel.toolCallId)??safeString(topLevel.tool_call_id)??safeString(topLevel.toolUseId)??safeString(topLevel.tool_use_id)??safeString(topLevel.call_id)??safeString(topLevel.id);const topLevelToolName=safeString(topLevel.toolName)??safeString(topLevel.tool_name);const topLevelIsError=safeBoolean(topLevel.isError)??safeBoolean(topLevel.is_error);if(!("content"in message)&&"command"in message&&"output"in message){return[{sessionId,partType:"text",ordinal:0,textContent:fallbackContent,metadata:toJson({originalRole:role,source:"bash-exec",command:safeString(message.command)})}]}if(!("content"in message)){return[{sessionId,partType:"agent",ordinal:0,textContent:fallbackContent||null,metadata:toJson({originalRole:role,source:"unknown-message-shape",raw:message})}]}if(typeof message.content==="string"){return[{sessionId,partType:"text",ordinal:0,textContent:message.content,metadata:toJson({originalRole:role,toolCallId:topLevelToolCallId,toolName:topLevelToolName,isError:topLevelIsError})}]}if(!Array.isArray(message.content)){return[{sessionId,partType:"agent",ordinal:0,textContent:fallbackContent||null,metadata:toJson({originalRole:role,source:"non-array-content",raw:message.content})}]}const parts=[];for(let ordinal=0;ordinal<message.content.length;ordinal++){const block=normalizeUnknownBlock(message.content[ordinal]);const metadataRecord=block.metadata.raw;const rawBlockType=safeString(metadataRecord?.rawType)??block.type;const partType=toPartType(rawBlockType);const rawBlock=metadataRecord&&rawBlockType!==block.type?{...metadataRecord,type:rawBlockType}:metadataRecord??message.content[ordinal];const toolCallId=safeString(metadataRecord?.toolCallId)??safeString(metadataRecord?.tool_call_id)??safeString(metadataRecord?.toolUseId)??safeString(metadataRecord?.tool_use_id)??safeString(metadataRecord?.call_id)??(partType==="tool"?safeString(metadataRecord?.id):void 0)??topLevelToolCallId;parts.push({sessionId,partType,ordinal,textContent:block.text??null,toolCallId,toolName:safeString(metadataRecord?.name)??safeString(metadataRecord?.toolName)??safeString(metadataRecord?.tool_name)??topLevelToolName,toolInput:metadataRecord?.input!==void 0?toJson(metadataRecord.input):metadataRecord?.arguments!==void 0?toJson(metadataRecord.arguments):metadataRecord?.toolInput!==void 0?toJson(metadataRecord.toolInput):safeString(metadataRecord?.tool_input)??null,toolOutput:metadataRecord?.output!==void 0?toJson(metadataRecord.output):metadataRecord?.toolOutput!==void 0?toJson(metadataRecord.toolOutput):safeString(metadataRecord?.tool_output)??null,metadata:toJson({originalRole:role,toolCallId:topLevelToolCallId,toolName:topLevelToolName,isError:topLevelIsError,externalizedFileId:safeString(metadataRecord?.externalizedFileId),originalByteSize:typeof metadataRecord?.originalByteSize==="number"?metadataRecord.originalByteSize:void 0,toolOutputExternalized:safeBoolean(metadataRecord?.toolOutputExternalized),externalizationReason:safeString(metadataRecord?.externalizationReason),rawType:rawBlockType,raw:rawBlock})})}return parts}function toDbRole(role){if(role==="tool"||role==="toolResult"){return"tool"}if(role==="system"){return"system"}if(role==="user"){return"user"}if(role==="assistant"){return"assistant"}return"assistant"}function toStoredMessage(message){const content="content"in message?extractMessageContent(message.content):"output"in message?`$ ${message.command}
|
|
740
|
+
WHERE conversation_id = ?`).get(input.conversationId);return toConversationBootstrapStateRecord(row)}};import{rmSync,renameSync}from"node:fs";import{basename,dirname as dirname2,join as join2}from"node:path";function quoteSqlString(value){return`'${value.replaceAll("'","''")}'`}function normalizeBackupLabel(label){const normalized=label.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");return normalized||"backup"}function buildLcmDatabaseBackupPath(databasePath,label){const fileBackedDatabasePath=getFileBackedDatabasePath(databasePath);if(!fileBackedDatabasePath){return null}const timestamp=new Date().toISOString().replace(/[-:.]/g,"");const suffix=Math.random().toString(36).slice(2,8);return join2(dirname2(fileBackedDatabasePath),`${basename(fileBackedDatabasePath)}.${normalizeBackupLabel(label)}-${timestamp}-${suffix}.bak`)}function buildLcmDatabaseLatestBackupPath(databasePath,label){const fileBackedDatabasePath=getFileBackedDatabasePath(databasePath);if(!fileBackedDatabasePath){return null}return join2(dirname2(fileBackedDatabasePath),`${basename(fileBackedDatabasePath)}.${normalizeBackupLabel(label)}-latest.bak`)}function writeLcmDatabaseBackup(db,backupPath){db.exec(`VACUUM INTO ${quoteSqlString(backupPath)}`)}function createLcmDatabaseBackup(db,options){if(options.replaceLatest){const latestBackupPath=buildLcmDatabaseLatestBackupPath(options.databasePath,options.label);const tempBackupPath=buildLcmDatabaseBackupPath(options.databasePath,`${options.label}-tmp`);if(!latestBackupPath||!tempBackupPath){return null}try{writeLcmDatabaseBackup(db,tempBackupPath);rmSync(latestBackupPath,{force:true});renameSync(tempBackupPath,latestBackupPath);return latestBackupPath}catch(error){rmSync(tempBackupPath,{force:true});throw error}}const backupPath=buildLcmDatabaseBackupPath(options.databasePath,options.label);if(!backupPath){return null}writeLcmDatabaseBackup(db,backupPath);return backupPath}var DEFERRED_COMPACTION_STILL_NEEDED_REASON="deferred compaction still needed";var MAX_BUDGET_TRIGGER_CATCHUP_PASSES=10;var TRANSCRIPT_GC_BATCH_SIZE=12;var HOT_CACHE_HYSTERESIS_TURNS=2;var DYNAMIC_LEAF_CHUNK_MEDIUM_MULTIPLIER=1.5;var DYNAMIC_LEAF_CHUNK_HIGH_MULTIPLIER=2;var DYNAMIC_ACTIVITY_MEDIUM_UPSHIFT_FACTOR=.5;var DYNAMIC_ACTIVITY_MEDIUM_DOWNSHIFT_FACTOR=.35;var DYNAMIC_ACTIVITY_HIGH_UPSHIFT_FACTOR=1;var DYNAMIC_ACTIVITY_HIGH_DOWNSHIFT_FACTOR=.75;function toJson(value){const encoded=JSON.stringify(value);return typeof encoded==="string"?encoded:""}function safeString(value){return typeof value==="string"?value:void 0}function formatDurationMs(durationMs){return`${durationMs}ms`}function asRecord(value){return value&&typeof value==="object"&&!Array.isArray(value)?value:void 0}function safeBoolean(value){return typeof value==="boolean"?value:void 0}function extractTranscriptToolCallId(message){const topLevel=message;const direct=safeString(topLevel.toolCallId)??safeString(topLevel.tool_call_id)??safeString(topLevel.toolUseId)??safeString(topLevel.tool_use_id)??safeString(topLevel.call_id)??safeString(topLevel.id);if(direct){return direct}if(!Array.isArray(topLevel.content)){return void 0}for(const item of topLevel.content){const record=asRecord(item);if(!record){continue}const nested=safeString(record.toolCallId)??safeString(record.tool_call_id)??safeString(record.toolUseId)??safeString(record.tool_use_id)??safeString(record.call_id)??safeString(record.id);if(nested){return nested}}return void 0}function listTranscriptToolResultEntryIdsByCallId(sessionFile){const sessionManager=SessionManager.open(sessionFile);const branch=sessionManager.getBranch();const entryIdsByCallId=new Map;const duplicateCallIds=new Set;for(const entry of branch){if(entry.type!=="message"||entry.message.role!=="toolResult"){continue}const toolCallId=extractTranscriptToolCallId(entry.message);if(!toolCallId){continue}if(entryIdsByCallId.has(toolCallId)){duplicateCallIds.add(toolCallId);continue}entryIdsByCallId.set(toolCallId,entry.id)}for(const duplicateCallId of duplicateCallIds){entryIdsByCallId.delete(duplicateCallId)}return entryIdsByCallId}function isRotatePreservedEntryType(type){return type==="message"||type==="model_change"||type==="thinking_level_change"||type==="session_info"}function normalizeRotateTailMessageCount(value,branchMessageCount){if(branchMessageCount<=0){return 0}if(!Number.isFinite(value)){return 1}return Math.max(1,Math.min(branchMessageCount,Math.floor(value)))}function appendTextValue2(value,out){if(typeof value==="string"){out.push(value);return}if(Array.isArray(value)){for(const entry of value){appendTextValue2(entry,out)}return}if(!value||typeof value!=="object"){return}const record=value;appendTextValue2(record.text,out);appendTextValue2(record.value,out)}var STRUCTURED_TEXT_FIELD_KEYS=["text","transcript","transcription","message","summary"];var STRUCTURED_ARRAY_FIELD_KEYS=["segments","utterances","paragraphs","alternatives","words","items","results"];var STRUCTURED_NESTED_FIELD_KEYS=["content","output","result","payload","data","value"];var MAX_STRUCTURED_TEXT_DEPTH=6;var TOOL_RAW_TYPES=new Set(["tool_use","toolUse","tool-use","toolCall","tool_call","functionCall","function_call","function_call_output","tool_result","toolResult","tool_use_result"]);function looksLikeJsonPayload(value){const trimmed=value.trim();if(!trimmed){return false}return trimmed.startsWith("{")&&trimmed.endsWith("}")||trimmed.startsWith("[")&&trimmed.endsWith("]")}function extractStructuredText(value,depth=0){if(value==null||depth>MAX_STRUCTURED_TEXT_DEPTH){return void 0}if(typeof value==="string"){if(looksLikeJsonPayload(value)){try{const parsed=JSON.parse(value.trim());const parsedText=extractStructuredText(parsed,depth+1);if(typeof parsedText==="string"&&parsedText.length>0){return parsedText}}catch{}}return value}if(Array.isArray(value)){const texts=[];for(const entry of value){const text=extractStructuredText(entry,depth+1);if(typeof text==="string"&&text.trim().length>0){texts.push(text)}}return texts.length>0?texts.join("\n"):void 0}if(typeof value!=="object"){return void 0}const record=value;if(typeof record.type==="string"&&TOOL_RAW_TYPES.has(record.type)){if(safeBoolean(record.toolOutputExternalized)){const externalizedText=extractStructuredText(record.output,depth+1)??extractStructuredText(record.content,depth+1)??extractStructuredText(record.result,depth+1);if(typeof externalizedText==="string"&&externalizedText.trim().length>0){return externalizedText}}return void 0}for(const key of STRUCTURED_TEXT_FIELD_KEYS){const candidate=record[key];if(typeof candidate==="string"&&candidate.trim().length>0){return candidate}}for(const key of STRUCTURED_ARRAY_FIELD_KEYS){const candidate=record[key];if(Array.isArray(candidate)){const texts=[];for(const entry of candidate){const text=extractStructuredText(entry,depth+1);if(typeof text==="string"&&text.trim().length>0){texts.push(text)}}if(texts.length>0){return texts.join("\n")}}}for(const key of STRUCTURED_NESTED_FIELD_KEYS){const nested=record[key];const nestedText=extractStructuredText(nested,depth+1);if(typeof nestedText==="string"&&nestedText.trim().length>0){return nestedText}}return void 0}function extractReasoningText(record){const chunks=[];appendTextValue2(record.summary,chunks);if(chunks.length===0){return void 0}const normalized=chunks.map(chunk=>chunk.trim()).filter((chunk,idx,arr)=>chunk.length>0&&arr.indexOf(chunk)===idx);return normalized.length>0?normalized.join("\n"):void 0}function normalizeUnknownBlock(value){if(!value||typeof value!=="object"||Array.isArray(value)){return{type:"agent",metadata:{raw:value}}}const record=value;const rawType=safeString(record.type);return{type:rawType??"agent",text:safeString(record.text)??safeString(record.thinking)??(rawType==="reasoning"||rawType==="thinking"?extractReasoningText(record):void 0),metadata:{raw:record}}}function toPartType(type){switch(type){case"text":return"text";case"thinking":case"reasoning":return"reasoning";case"tool_use":case"toolUse":case"tool-use":case"toolCall":case"functionCall":case"function_call":case"function_call_output":case"tool_result":case"toolResult":case"tool":return"tool";case"patch":return"patch";case"file":case"image":return"file";case"subtask":return"subtask";case"compaction":return"compaction";case"step_start":case"step-start":return"step_start";case"step_finish":case"step-finish":return"step_finish";case"snapshot":return"snapshot";case"retry":return"retry";case"agent":return"agent";default:return"agent"}}function extractMessageContent(content){const extracted=extractStructuredText(content);if(typeof extracted==="string"){return extracted}if(content==null){return""}if(Array.isArray(content)&&content.length===0){return""}if(Array.isArray(content)&&content.length>0&&content.every(item=>typeof item==="object"&&item!==null&&!Array.isArray(item)&&typeof item.type==="string"&&TOOL_RAW_TYPES.has(item.type))){return""}const serialized=JSON.stringify(content);return typeof serialized==="string"?serialized:""}function toRuntimeRoleForTokenEstimate(role){if(role==="tool"||role==="toolResult"){return"toolResult"}if(role==="user"||role==="system"){return"user"}return"assistant"}function isTextBlock(value){if(!value||typeof value!=="object"||Array.isArray(value)){return false}const record=value;return record.type==="text"&&typeof record.text==="string"}function toSyntheticMessagePartRecord(part,messageId){return{partId:`estimate-part-${part.ordinal}`,messageId,sessionId:part.sessionId,partType:part.partType,ordinal:part.ordinal,textContent:part.textContent??null,toolCallId:part.toolCallId??null,toolName:part.toolName??null,toolInput:part.toolInput??null,toolOutput:part.toolOutput??null,metadata:part.metadata??null}}function normalizeMessageContentForStorage(params){const{message,fallbackContent}=params;if(!("content"in message)){return fallbackContent}const role=toRuntimeRoleForTokenEstimate(message.role);const parts=buildMessageParts({sessionId:"storage-estimate",message,fallbackContent}).map(part=>toSyntheticMessagePartRecord(part,0));if(parts.length===0){if(role==="assistant"){return fallbackContent?[{type:"text",text:fallbackContent}]:[]}if(role==="toolResult"){return[{type:"text",text:fallbackContent}]}return fallbackContent}const blocks=parts.map(blockFromPart);if(role==="user"&&blocks.length===1&&isTextBlock(blocks[0])){return blocks[0].text}return blocks}function estimateContentTokensForRole(params){const{role,content,fallbackContent}=params;if(typeof content==="string"){return estimateTokens(content)}if(Array.isArray(content)){if(content.length===0){return estimateTokens(fallbackContent)}if(role==="user"&&content.length===1&&isTextBlock(content[0])){return estimateTokens(content[0].text)}const serialized=JSON.stringify(content);return estimateTokens(typeof serialized==="string"?serialized:"")}if(content&&typeof content==="object"){if(role==="user"&&isTextBlock(content)){return estimateTokens(content.text)}const serialized=JSON.stringify([content]);return estimateTokens(typeof serialized==="string"?serialized:"")}return estimateTokens(fallbackContent)}function buildMessageParts(params){const{sessionId,message,fallbackContent}=params;const role=typeof message.role==="string"?message.role:"unknown";const topLevel=message;const topLevelToolCallId=safeString(topLevel.toolCallId)??safeString(topLevel.tool_call_id)??safeString(topLevel.toolUseId)??safeString(topLevel.tool_use_id)??safeString(topLevel.call_id)??safeString(topLevel.id);const topLevelToolName=safeString(topLevel.toolName)??safeString(topLevel.tool_name);const topLevelIsError=safeBoolean(topLevel.isError)??safeBoolean(topLevel.is_error);if(!("content"in message)&&"command"in message&&"output"in message){return[{sessionId,partType:"text",ordinal:0,textContent:fallbackContent,metadata:toJson({originalRole:role,source:"bash-exec",command:safeString(message.command)})}]}if(!("content"in message)){return[{sessionId,partType:"agent",ordinal:0,textContent:fallbackContent||null,metadata:toJson({originalRole:role,source:"unknown-message-shape",raw:message})}]}if(typeof message.content==="string"){return[{sessionId,partType:"text",ordinal:0,textContent:message.content,metadata:toJson({originalRole:role,toolCallId:topLevelToolCallId,toolName:topLevelToolName,isError:topLevelIsError})}]}if(!Array.isArray(message.content)){return[{sessionId,partType:"agent",ordinal:0,textContent:fallbackContent||null,metadata:toJson({originalRole:role,source:"non-array-content",raw:message.content})}]}const parts=[];for(let ordinal=0;ordinal<message.content.length;ordinal++){const block=normalizeUnknownBlock(message.content[ordinal]);const metadataRecord=block.metadata.raw;const rawBlockType=safeString(metadataRecord?.rawType)??block.type;const partType=toPartType(rawBlockType);const rawBlock=metadataRecord&&rawBlockType!==block.type?{...metadataRecord,type:rawBlockType}:metadataRecord??message.content[ordinal];const toolCallId=safeString(metadataRecord?.toolCallId)??safeString(metadataRecord?.tool_call_id)??safeString(metadataRecord?.toolUseId)??safeString(metadataRecord?.tool_use_id)??safeString(metadataRecord?.call_id)??(partType==="tool"?safeString(metadataRecord?.id):void 0)??topLevelToolCallId;parts.push({sessionId,partType,ordinal,textContent:block.text??null,toolCallId,toolName:safeString(metadataRecord?.name)??safeString(metadataRecord?.toolName)??safeString(metadataRecord?.tool_name)??topLevelToolName,toolInput:metadataRecord?.input!==void 0?toJson(metadataRecord.input):metadataRecord?.arguments!==void 0?toJson(metadataRecord.arguments):metadataRecord?.toolInput!==void 0?toJson(metadataRecord.toolInput):safeString(metadataRecord?.tool_input)??null,toolOutput:metadataRecord?.output!==void 0?toJson(metadataRecord.output):metadataRecord?.toolOutput!==void 0?toJson(metadataRecord.toolOutput):safeString(metadataRecord?.tool_output)??null,metadata:toJson({originalRole:role,toolCallId:topLevelToolCallId,toolName:topLevelToolName,isError:topLevelIsError,externalizedFileId:safeString(metadataRecord?.externalizedFileId),originalByteSize:typeof metadataRecord?.originalByteSize==="number"?metadataRecord.originalByteSize:void 0,toolOutputExternalized:safeBoolean(metadataRecord?.toolOutputExternalized),externalizationReason:safeString(metadataRecord?.externalizationReason),rawType:rawBlockType,raw:rawBlock})})}return parts}function toDbRole(role){if(role==="tool"||role==="toolResult"){return"tool"}if(role==="system"){return"system"}if(role==="user"){return"user"}if(role==="assistant"){return"assistant"}return"assistant"}function toStoredMessage(message){const content="content"in message?extractMessageContent(message.content):"output"in message?`$ ${message.command}
|
|
738
741
|
${message.output}`:"";const runtimeRole=toRuntimeRoleForTokenEstimate(message.role);const normalizedContent="content"in message?normalizeMessageContentForStorage({message,fallbackContent:content}):content;const tokenCount="content"in message?estimateContentTokensForRole({role:runtimeRole,content:normalizedContent,fallbackContent:content}):estimateTokens(content);return{role:toDbRole(message.role),content,tokenCount}}function createBootstrapEntryHash(message){if(!message){return null}return createHash3("sha256").update(JSON.stringify({role:message.role,content:message.content})).digest("hex")}function estimateMessageContentTokensForAfterTurn(content){if(typeof content==="string"){return estimateTokens(content)}if(Array.isArray(content)){let total=0;for(const part of content){if(!part||typeof part!=="object"){continue}const record=part;const text=typeof record.text==="string"?record.text:typeof record.thinking==="string"?record.thinking:"";if(text){total+=estimateTokens(text)}}return total}if(content==null){return 0}const serialized=JSON.stringify(content);return estimateTokens(typeof serialized==="string"?serialized:"")}function estimateSessionTokenCountForAfterTurn(messages){let total=0;for(const message of messages){if("content"in message){total+=estimateMessageContentTokensForAfterTurn(message.content);continue}if("command"in message||"output"in message){const commandText=typeof message.command==="string"?message.command:"";const outputText=typeof message.output==="string"?message.output:"";total+=estimateTokens(`${commandText}
|
|
739
742
|
${outputText}`)}}return total}function isBootstrapMessage(value){if(!value||typeof value!=="object"){return false}const msg=value;if(typeof msg.role!=="string"){return false}return"content"in msg||"command"in msg&&"output"in msg}function extractCanonicalBootstrapMessage(value){if(isBootstrapMessage(value)){return value}if(!value||typeof value!=="object"||Array.isArray(value)){return null}const entry=value;if("message"in entry){if(entry.type!==void 0&&entry.type!=="message"){return null}return isBootstrapMessage(entry.message)?entry.message:null}return null}function extractBootstrapMessageCandidate(value){return extractCanonicalBootstrapMessage(value)}function parseBootstrapJsonl(raw,options){const messages=[];const lines=raw.split(/\r?\n/);let sawNonWhitespace=false;let hadMalformedLine=false;for(const line of lines){const item=line.trim();if(!item){continue}sawNonWhitespace=true;try{const parsed=JSON.parse(item);const candidate=extractBootstrapMessageCandidate(parsed);if(candidate){messages.push(candidate);continue}}catch{if(options?.strict){hadMalformedLine=true}}}return{messages,sawNonWhitespace,hadMalformedLine}}async function readLeafPathMessages(sessionFile){try{let sawNonWhitespace=false;let jsonArrayMode=false;let jsonArrayBuffer="";const messages=[];const stream=createReadStream(sessionFile,{encoding:"utf8"});const lines=createInterface({input:stream,crlfDelay:Infinity});for await(const line of lines){if(!sawNonWhitespace){const trimmed=line.trim();if(trimmed){sawNonWhitespace=true;if(trimmed.startsWith("[")){jsonArrayMode=true}}}if(jsonArrayMode){jsonArrayBuffer+=`${line}
|
|
740
|
-
`;continue}const parsed=parseBootstrapJsonl(line);if(parsed.messages.length>0){messages.push(...parsed.messages)}}if(jsonArrayMode){const trimmed=jsonArrayBuffer.trim();if(!trimmed){return[]}try{const parsed=JSON.parse(trimmed);if(!Array.isArray(parsed)){return[]}return parsed.filter(isBootstrapMessage)}catch{return[]}}return messages}catch{return[]}}function resolveBootstrapMaxTokens(config){if(typeof config.bootstrapMaxTokens==="number"&&Number.isFinite(config.bootstrapMaxTokens)&&config.bootstrapMaxTokens>0){return Math.floor(config.bootstrapMaxTokens)}const leafChunkTokens=typeof config.leafChunkTokens==="number"&&Number.isFinite(config.leafChunkTokens)&&config.leafChunkTokens>0?Math.floor(config.leafChunkTokens):2e4;return Math.max(6e3,Math.floor(leafChunkTokens*.3))}function trimBootstrapMessagesToBudget(messages,maxTokens){if(messages.length===0){return[]}const safeMaxTokens=Number.isFinite(maxTokens)?Math.floor(maxTokens):0;if(safeMaxTokens<=0){return[messages[messages.length-1]]}const kept=[];let totalTokens=0;for(let index=messages.length-1;index>=0;index-=1){const message=messages[index];const tokenCount=toStoredMessage(message).tokenCount;if(kept.length>0&&totalTokens+tokenCount>safeMaxTokens){break}kept.push(message);totalTokens+=tokenCount}if(kept.length===1&&totalTokens>safeMaxTokens){return[]}kept.reverse();return kept}async function readFileSegment(sessionFile,offset){let fh=null;try{fh=await open(sessionFile,"r");const stats=await fh.stat();const safeOffset=Math.max(0,Math.min(Math.floor(offset),stats.size));const length=stats.size-safeOffset;if(length<=0){return""}const buffer=Buffer.alloc(length);await fh.read(buffer,0,length,safeOffset);return buffer.toString("utf8")}catch{return null}finally{await fh?.close()}}async function readLastJsonlEntryBeforeOffset(sessionFile,offset,messageOnly=false,matcher){const chunkSize=16384;const safeOffset=Math.max(0,Math.floor(offset));if(safeOffset<=0){return null}let fh=null;try{fh=await open(sessionFile,"r");let cursor=safeOffset;let carry="";while(true){const trimmedEnd=carry.replace(/\s+$/u,"");if(trimmedEnd){const newlineIndex=Math.max(trimmedEnd.lastIndexOf("\n"),trimmedEnd.lastIndexOf("\r"));if(newlineIndex>=0){const candidate=trimmedEnd.slice(newlineIndex+1).trim();if(candidate){if(messageOnly){let matchedMessage=null;try{matchedMessage=extractBootstrapMessageCandidate(JSON.parse(candidate))}catch{}if(!matchedMessage||matcher&&!matcher(matchedMessage)){carry=trimmedEnd.slice(0,newlineIndex);continue}}return candidate}carry=trimmedEnd.slice(0,newlineIndex);continue}}if(cursor<=0){const firstLine=trimmedEnd.trim()||null;if(!firstLine)return null;if(messageOnly){let matchedMessage=null;try{matchedMessage=extractBootstrapMessageCandidate(JSON.parse(firstLine))}catch{}if(!matchedMessage||matcher&&!matcher(matchedMessage))return null}return firstLine}const start=Math.max(0,cursor-chunkSize);const length=cursor-start;const buffer=Buffer.alloc(length);await fh.read(buffer,0,length,start);carry=buffer.toString("utf8")+carry;cursor=start}}catch{return null}finally{await fh?.close()}}async function readAppendedLeafPathMessages(params){const raw=await readFileSegment(params.sessionFile,params.offset);if(raw==null){return{messages:[],canUseAppendOnly:false,sawNonWhitespace:false}}const trimmed=raw.trim();if(!trimmed){return{messages:[],canUseAppendOnly:true,sawNonWhitespace:false}}if(trimmed.startsWith("[")){return{messages:[],canUseAppendOnly:false,sawNonWhitespace:true}}const parsed=parseBootstrapJsonl(raw,{strict:true});if(parsed.hadMalformedLine){return{messages:[],canUseAppendOnly:false,sawNonWhitespace:parsed.sawNonWhitespace}}return{messages:parsed.messages,canUseAppendOnly:true,sawNonWhitespace:parsed.sawNonWhitespace}}function readBootstrapMessageFromJsonLine(line){if(!line){return null}try{return extractBootstrapMessageCandidate(JSON.parse(line))}catch{return null}}function messageIdentity(role,content){return`${role}\0${content}`}var LcmContextEngine=class _LcmContextEngine{info;config;get timezone(){return this.config.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone}conversationStore;summaryStore;compactionTelemetryStore;compactionMaintenanceStore;assembler;compaction;retrieval;db;migrated=false;fts5Available;ignoreSessionPatterns;statelessSessionPatterns;sessionOperationQueues=new Map;largeFileTextSummarizerResolved=false;largeFileTextSummarizer;deps;circuitBreakerStates=new Map;constructor(deps,database){this.deps=deps;this.config=deps.config;this.ignoreSessionPatterns=compileSessionPatterns(this.config.ignoreSessionPatterns);this.statelessSessionPatterns=compileSessionPatterns(this.config.statelessSessionPatterns);this.db=database;let migrationOk=false;const migrationStartedAt=Date.now();try{runLcmMigrations(this.db,{log:this.deps.log});this.migrated=true;const tables=this.db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();if(tables.length===0){this.deps.log.warn("[lcm] Migration completed but database has zero tables \u2014 DB may be non-functional")}else{migrationOk=true;this.deps.log.info(`[lcm] Migration run completed during engine init: duration=${formatDurationMs(Date.now()-migrationStartedAt)} fts5=${this.fts5Available}`);this.deps.log.debug(`[lcm] Migration successful \u2014 ${tables.length} tables: ${tables.map(t=>t.name).join(", ")}`)}}catch(err){this.deps.log.error(`[lcm] Migration failed after ${formatDurationMs(Date.now()-migrationStartedAt)}: ${err instanceof Error?err.message:String(err)}`)}this.fts5Available=getLcmDbFeatures(this.db).fts5Available;this.info={id:"lossless-claw",name:"Lossless Context Management Engine",version:"0.1.0",ownsCompaction:migrationOk,turnMaintenanceMode:"background"};this.conversationStore=new ConversationStore(this.db,{fts5Available:this.fts5Available});this.summaryStore=new SummaryStore(this.db,{fts5Available:this.fts5Available});this.compactionTelemetryStore=new CompactionTelemetryStore(this.db);this.compactionMaintenanceStore=new CompactionMaintenanceStore(this.db);if(!this.fts5Available){this.deps.log.warn("[lcm] FTS5 unavailable in the current Node runtime; full_text search will fall back to LIKE and indexing is disabled")}if(this.config.ignoreSessionPatterns.length>0){const source=describeLcmConfigSource(this.deps.configDiagnostics?.ignoreSessionPatternsSource??"default");logStartupBannerOnce({key:"ignore-session-patterns",log:message=>this.deps.log.info(message),message:`[lcm] Ignoring sessions matching ${this.config.ignoreSessionPatterns.length} pattern(s) from ${source}: ${this.config.ignoreSessionPatterns.join(", ")}`})}if(this.config.statelessSessionPatterns.length>0){const source=describeLcmConfigSource(this.deps.configDiagnostics?.statelessSessionPatternsSource??"default");const enforcement=this.config.skipStatelessSessions?"":" (skipStatelessSessions=false)";logStartupBannerOnce({key:"stateless-session-patterns",log:message=>this.deps.log.info(message),message:`[lcm] Stateless session patterns${enforcement} from ${source}: ${this.config.statelessSessionPatterns.length} pattern(s): ${this.config.statelessSessionPatterns.join(", ")}`})}this.assembler=new ContextAssembler(this.conversationStore,this.summaryStore,this.config.timezone);const compactionConfig={contextThreshold:this.config.contextThreshold,freshTailCount:this.config.freshTailCount,freshTailMaxTokens:this.config.freshTailMaxTokens,leafMinFanout:this.config.leafMinFanout,condensedMinFanout:this.config.condensedMinFanout,condensedMinFanoutHard:this.config.condensedMinFanoutHard,incrementalMaxDepth:this.config.incrementalMaxDepth,leafChunkTokens:this.config.leafChunkTokens,leafTargetTokens:this.config.leafTargetTokens,condensedTargetTokens:this.config.condensedTargetTokens,maxRounds:10,timezone:this.config.timezone,summaryMaxOverageFactor:this.config.summaryMaxOverageFactor};this.compaction=new CompactionEngine(this.conversationStore,this.summaryStore,compactionConfig,this.deps.log);this.retrieval=new RetrievalEngine(this.conversationStore,this.summaryStore)}shouldIgnoreSession(params){if(this.ignoreSessionPatterns.length===0){return false}const candidate=typeof params.sessionKey==="string"&¶ms.sessionKey.trim()?params.sessionKey.trim():params.sessionId?.trim()??"";if(!candidate){return false}return matchesSessionPattern(candidate,this.ignoreSessionPatterns)}isStatelessSession(sessionKey){const trimmedKey=typeof sessionKey==="string"?sessionKey.trim():"";if(!this.config.skipStatelessSessions||!trimmedKey||this.statelessSessionPatterns.length===0){return false}return matchesSessionPattern(trimmedKey,this.statelessSessionPatterns)}getCircuitBreakerState(key){let state=this.circuitBreakerStates.get(key);if(!state){state={failures:0,openSince:null};this.circuitBreakerStates.set(key,state)}return state}isCircuitBreakerOpen(key){const state=this.circuitBreakerStates.get(key);if(!state||state.openSince===null)return false;const elapsed=Date.now()-state.openSince;if(elapsed>=this.config.circuitBreakerCooldownMs){this.resetCircuitBreaker(key);return false}return true}recordCompactionAuthFailure(key){const state=this.getCircuitBreakerState(key);state.failures++;const halfThreshold=Math.ceil(this.config.circuitBreakerThreshold/2);if(state.failures===halfThreshold&&state.failures<this.config.circuitBreakerThreshold){this.deps.log.warn(`[lcm] WARNING: compaction degraded \u2014 ${state.failures}/${this.config.circuitBreakerThreshold} consecutive auth failures for ${key}`)}if(state.failures>=this.config.circuitBreakerThreshold){state.openSince=Date.now();const cooldownMin=Math.round(this.config.circuitBreakerCooldownMs/6e4);this.deps.log.warn(`[lcm] CIRCUIT BREAKER OPEN: compaction disabled for ${key}. Auto-retry in ${cooldownMin}m. LCM is operating in degraded mode.`)}}recordCompactionSuccess(key){const state=this.circuitBreakerStates.get(key);if(!state){return}if(state.failures>0||state.openSince!==null){this.deps.log.info(`[lcm] compaction circuit breaker CLOSED: successful compaction for ${key} after ${state.failures} prior failures.`)}this.resetCircuitBreaker(key)}resetCircuitBreaker(key){this.circuitBreakerStates.delete(key)}ensureMigrated(){if(this.migrated){return}const migrationStartedAt=Date.now();this.deps.log.info("[lcm] ensureMigrated: running migrations lazily");runLcmMigrations(this.db,{log:this.deps.log});this.migrated=true;this.deps.log.info(`[lcm] ensureMigrated: completed in ${formatDurationMs(Date.now()-migrationStartedAt)}`)}async withSessionQueue(queueKey,operation,options){const entry=this.sessionOperationQueues.get(queueKey);const previous=entry?.promise??Promise.resolve();const queuedAhead=entry?.refCount??0;let releaseQueue=()=>{};const current=new Promise(resolve2=>{releaseQueue=resolve2});const next=previous.catch(()=>{}).then(()=>current);if(entry){entry.promise=next;entry.refCount++}else{this.sessionOperationQueues.set(queueKey,{promise:next,refCount:1})}const waitStartedAt=Date.now();await previous.catch(()=>{});const waitMs=Date.now()-waitStartedAt;if(options?.operationName){const detail=options.context?` ${options.context}`:"";this.deps.log.info(`[lcm] ${options.operationName}: session queue acquired queueKey=${queueKey} queuedAhead=${queuedAhead} wait=${formatDurationMs(waitMs)}${detail}`)}try{return await operation()}finally{releaseQueue();const cur=this.sessionOperationQueues.get(queueKey);if(cur&&--cur.refCount===0){this.sessionOperationQueues.delete(queueKey)}}}resolveSessionQueueKey(sessionId,sessionKey){const normalizedSessionKey=sessionKey?.trim();const normalizedSessionId=sessionId?.trim();return normalizedSessionKey||normalizedSessionId||"__lcm__"}normalizeObservedTokenCount(value){if(typeof value!=="number"||!Number.isFinite(value)||value<=0){return void 0}return Math.floor(value)}resolveTokenBudget(params){const lp=asRecord(params.runtimeContext)??params.legacyParams??{};if(typeof params.tokenBudget==="number"&&Number.isFinite(params.tokenBudget)&¶ms.tokenBudget>0){return Math.floor(params.tokenBudget)}if(typeof lp.tokenBudget==="number"&&Number.isFinite(lp.tokenBudget)&&lp.tokenBudget>0){return Math.floor(lp.tokenBudget)}return void 0}applyAssemblyBudgetCap(budget){const cap=this.config.maxAssemblyTokenBudget;return cap!=null&&cap>0?Math.min(budget,cap):budget}normalizeOptionalCount(value){if(typeof value!=="number"||!Number.isFinite(value)||value<0){return void 0}return Math.floor(value)}shouldApplyHotCacheHysteresis(telemetry){if(!telemetry?.lastObservedCacheHitAt){return false}if(telemetry.lastObservedCacheBreakAt&&telemetry.lastObservedCacheBreakAt>=telemetry.lastObservedCacheHitAt){return false}return telemetry.turnsSinceLeafCompaction<=HOT_CACHE_HYSTERESIS_TURNS}resolveCacheAwareState(telemetry){if(!telemetry){return"unknown"}if(telemetry.cacheState==="hot"){return"hot"}if(this.shouldApplyHotCacheHysteresis(telemetry)){return"hot"}if(telemetry.lastObservedCacheBreakAt&&(!telemetry.lastObservedCacheHitAt||telemetry.lastObservedCacheBreakAt>=telemetry.lastObservedCacheHitAt)){return"cold"}if(telemetry.consecutiveColdObservations>=this.config.cacheAwareCompaction.coldCacheObservationThreshold){return"cold"}if(telemetry.lastObservedCacheHitAt){return"hot"}if(telemetry.cacheState==="cold"){return"unknown"}return telemetry.cacheState}resolvePromptCacheTtlMs(retention){const normalized=retention?.trim().toLowerCase();if(normalized==="none"){return null}if(normalized==="long"||normalized==="1h"){return 60*60*1e3}return Math.max(1,this.config.cacheAwareCompaction.cacheTTLSeconds)*1e3}isAnthropicPromptCacheFamily(telemetry){const provider=telemetry?.provider?.trim().toLowerCase()??"";const model=telemetry?.model?.trim().toLowerCase()??"";return provider.includes("anthropic")||model.includes("claude")}isPromptCacheStillHot(telemetry,now=new Date){const ttlMs=this.resolvePromptCacheTtlMs(telemetry?.retention??null);if(!ttlMs){return false}const touchAt=telemetry?.lastCacheTouchAt??telemetry?.lastObservedCacheHitAt??telemetry?.lastApiCallAt??null;if(!touchAt){return false}return now.getTime()-touchAt.getTime()<ttlMs}shouldDelayPromptMutatingDeferredCompaction(telemetry,now=new Date){return this.isAnthropicPromptCacheFamily(telemetry)&&this.isPromptCacheStillHot(telemetry,now)}isComfortablyUnderTokenBudget(params){if(typeof params.currentTokenCount!=="number"||!Number.isFinite(params.currentTokenCount)||params.currentTokenCount<0){return false}const budget=Math.max(1,Math.floor(params.tokenBudget));const safeBudget=Math.floor(budget*(1-this.config.cacheAwareCompaction.hotCacheBudgetHeadroomRatio));return params.currentTokenCount<=safeBudget}resolveDynamicLeafChunkBounds(tokenBudget){const floor=Math.max(1,Math.floor(this.config.leafChunkTokens));const configuredMax=this.config.dynamicLeafChunkTokens.enabled?Math.max(floor,Math.floor(this.config.dynamicLeafChunkTokens.max)):floor;const budgetCap=typeof tokenBudget==="number"&&Number.isFinite(tokenBudget)&&tokenBudget>0?Math.max(floor,Math.floor(tokenBudget*this.config.contextThreshold)):configuredMax;const max=Math.max(floor,Math.min(configuredMax,budgetCap));const medium=Math.max(floor,Math.min(max,Math.floor(floor*DYNAMIC_LEAF_CHUNK_MEDIUM_MULTIPLIER)));const high=Math.max(floor,Math.min(max,Math.floor(floor*DYNAMIC_LEAF_CHUNK_HIGH_MULTIPLIER)));return{floor,medium,high,max}}classifyDynamicLeafActivityBand(params){const turns=Math.max(1,params.turnsSinceLeafCompaction);const tokensPerTurn=params.tokensAccumulatedSinceLeafCompaction/turns;const mediumUpshift=params.floor*DYNAMIC_ACTIVITY_MEDIUM_UPSHIFT_FACTOR;const mediumDownshift=params.floor*DYNAMIC_ACTIVITY_MEDIUM_DOWNSHIFT_FACTOR;const highUpshift=params.floor*DYNAMIC_ACTIVITY_HIGH_UPSHIFT_FACTOR;const highDownshift=params.floor*DYNAMIC_ACTIVITY_HIGH_DOWNSHIFT_FACTOR;const lastBand=params.lastActivityBand??"low";if(lastBand==="high"){if(tokensPerTurn>=highDownshift){return"high"}return tokensPerTurn>=mediumDownshift?"medium":"low"}if(lastBand==="medium"){if(tokensPerTurn>=highUpshift){return"high"}if(tokensPerTurn<mediumDownshift){return"low"}return"medium"}if(tokensPerTurn>=highUpshift){return"high"}if(tokensPerTurn>=mediumUpshift){return"medium"}return"low"}resolveLeafChunkTokensForBand(band,bounds){switch(band){case"high":return bounds.high;case"medium":return bounds.medium;default:return bounds.floor}}buildLeafChunkFallbacks(params){const ordered=[params.preferred,params.bounds.max,params.bounds.high,params.bounds.medium,params.bounds.floor];const seen=new Set;const fallbacks=[];for(const value of ordered){const normalized=Math.max(params.bounds.floor,Math.floor(value));if(seen.has(normalized)){continue}seen.add(normalized);fallbacks.push(normalized)}return fallbacks.sort((a,b)=>b-a)}isRecoverableLeafChunkOverflowError(error){const message=(error instanceof Error?error.message:String(error)).toLowerCase();if(!message){return false}return["context length","context window","maximum context","max context","too many tokens","too many input tokens","input tokens","token limit","context limit","input is too large","input too large","prompt is too long","request too large","exceeds the model","exceeds context"].some(fragment=>message.includes(fragment))}readPromptCacheSnapshot(runtimeContext){const promptCache=asRecord(runtimeContext?.promptCache);const provider=safeString(runtimeContext?.provider)?.trim()??safeString(runtimeContext?.providerId)?.trim();const model=safeString(runtimeContext?.model)?.trim()??safeString(runtimeContext?.modelId)?.trim();if(!promptCache&&!provider&&!model){return null}const lastCallUsage=asRecord(promptCache?.lastCallUsage);const observation=asRecord(promptCache?.observation);const cacheRead=this.normalizeOptionalCount(lastCallUsage?.cacheRead);const cacheWrite=this.normalizeOptionalCount(lastCallUsage?.cacheWrite);const sawExplicitBreak=safeBoolean(observation?.broke)===true;const retention=safeString(promptCache?.retention)?.trim();const lastCacheTouchAtRaw=promptCache?.lastCacheTouchAt;const lastCacheTouchAt=typeof lastCacheTouchAtRaw==="number"&&Number.isFinite(lastCacheTouchAtRaw)?new Date(lastCacheTouchAtRaw):void 0;const hasUsageSignal=cacheRead!==void 0||cacheWrite!==void 0;const hasObservationSignal=typeof observation?.cacheRead==="number"||typeof observation?.previousCacheRead==="number"||sawExplicitBreak;let cacheState="unknown";if(sawExplicitBreak){cacheState="cold"}else if(typeof cacheRead==="number"&&cacheRead>0){cacheState="hot"}else if(hasUsageSignal||hasObservationSignal){cacheState="cold"}return{...cacheRead!==void 0?{lastObservedCacheRead:cacheRead}:{},...cacheWrite!==void 0?{lastObservedCacheWrite:cacheWrite}:{},cacheState,...retention?{retention}:{},sawExplicitBreak,...lastCacheTouchAt?{lastCacheTouchAt}:{},...provider?{provider}:{},...model?{model}:{}}}async updateCompactionTelemetry(params){const snapshot=this.readPromptCacheSnapshot(params.runtimeContext);const existing=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);if(!snapshot&¶ms.rawTokensOutsideTail===void 0){return existing}const now=new Date;const bounds=this.resolveDynamicLeafChunkBounds(params.tokenBudget);const turnsSinceLeafCompaction=(existing?.turnsSinceLeafCompaction??0)+1;const tokensAccumulatedSinceLeafCompaction=params.rawTokensOutsideTail??existing?.tokensAccumulatedSinceLeafCompaction??0;const touchedPromptCache=snapshot?.lastCacheTouchAt??(snapshot&&(snapshot.lastObservedCacheRead!==void 0||snapshot.lastObservedCacheWrite!==void 0)?now:existing?.lastCacheTouchAt??null);const consecutiveColdObservations=snapshot?.sawExplicitBreak?Math.max(existing?.consecutiveColdObservations??0,this.config.cacheAwareCompaction.coldCacheObservationThreshold):snapshot?.cacheState==="hot"?0:snapshot?.cacheState==="cold"?(existing?.consecutiveColdObservations??0)+1:existing?.consecutiveColdObservations??0;const lastActivityBand=this.classifyDynamicLeafActivityBand({lastActivityBand:existing?.lastActivityBand,tokensAccumulatedSinceLeafCompaction,turnsSinceLeafCompaction,floor:bounds.floor});await this.compactionTelemetryStore.upsertConversationCompactionTelemetry({conversationId:params.conversationId,lastObservedCacheRead:snapshot?.lastObservedCacheRead??existing?.lastObservedCacheRead??null,lastObservedCacheWrite:snapshot?.lastObservedCacheWrite??existing?.lastObservedCacheWrite??null,lastObservedCacheHitAt:snapshot?.cacheState==="hot"?now:existing?.lastObservedCacheHitAt??null,lastObservedCacheBreakAt:snapshot?.sawExplicitBreak?now:existing?.lastObservedCacheBreakAt??null,cacheState:snapshot?.cacheState??existing?.cacheState??"unknown",consecutiveColdObservations,retention:snapshot?.retention??existing?.retention??null,lastLeafCompactionAt:existing?.lastLeafCompactionAt??null,turnsSinceLeafCompaction,tokensAccumulatedSinceLeafCompaction,lastActivityBand,lastApiCallAt:now,lastCacheTouchAt:touchedPromptCache,provider:snapshot?.provider??existing?.provider??null,model:snapshot?.model??existing?.model??null});const updated=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);if(updated){this.deps.log.debug(`[lcm] compaction telemetry updated: conversation=${params.conversationId} cacheState=${updated.cacheState} coldObservationStreak=${updated.consecutiveColdObservations} cacheRead=${updated.lastObservedCacheRead??"null"} cacheWrite=${updated.lastObservedCacheWrite??"null"} retention=${updated.retention??"null"} lastApiCallAt=${updated.lastApiCallAt?.toISOString()??"null"} lastCacheTouchAt=${updated.lastCacheTouchAt?.toISOString()??"null"} provider=${updated.provider??"null"} model=${updated.model??"null"} turnsSinceLeafCompaction=${updated.turnsSinceLeafCompaction} tokensSinceLeafCompaction=${updated.tokensAccumulatedSinceLeafCompaction} activityBand=${updated.lastActivityBand} rawTokensOutsideTail=${params.rawTokensOutsideTail??"null"} tokenBudget=${params.tokenBudget??"null"}`)}return updated}async markLeafCompactionTelemetrySuccess(params){const existing=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);await this.compactionTelemetryStore.upsertConversationCompactionTelemetry({conversationId:params.conversationId,lastObservedCacheRead:existing?.lastObservedCacheRead??null,lastObservedCacheWrite:existing?.lastObservedCacheWrite??null,lastObservedCacheHitAt:existing?.lastObservedCacheHitAt??null,lastObservedCacheBreakAt:existing?.lastObservedCacheBreakAt??null,cacheState:existing?.cacheState??"unknown",consecutiveColdObservations:existing?.consecutiveColdObservations??0,retention:existing?.retention??null,lastLeafCompactionAt:new Date,turnsSinceLeafCompaction:0,tokensAccumulatedSinceLeafCompaction:0,lastActivityBand:params.activityBand??existing?.lastActivityBand??"low",lastApiCallAt:existing?.lastApiCallAt??null,lastCacheTouchAt:existing?.lastCacheTouchAt??null,provider:existing?.provider??null,model:existing?.model??null});this.deps.log.debug(`[lcm] compaction telemetry reset after leaf compaction: conversation=${params.conversationId} cacheState=${existing?.cacheState??"unknown"} activityBand=${params.activityBand??existing?.lastActivityBand??"low"}`)}logIncrementalCompactionDecision(params){this.deps.log.info(`[lcm] incremental compaction decision: conversation=${params.conversationId} cacheState=${params.cacheState} activityBand=${params.activityBand} triggerLeafChunkTokens=${params.triggerLeafChunkTokens} preferredLeafChunkTokens=${params.preferredLeafChunkTokens} fallbackLeafChunkTokens=${params.fallbackLeafChunkTokens.join(",")} rawTokensOutsideTail=${params.rawTokensOutsideTail} threshold=${params.threshold} shouldCompact=${params.shouldCompact} maxPasses=${params.maxPasses} allowCondensedPasses=${params.allowCondensedPasses} reason=${params.reason}`);return{shouldCompact:params.shouldCompact,cacheState:params.cacheState,maxPasses:params.maxPasses,rawTokensOutsideTail:params.rawTokensOutsideTail,threshold:params.threshold,reason:params.reason,leafChunkTokens:params.preferredLeafChunkTokens,fallbackLeafChunkTokens:params.fallbackLeafChunkTokens,activityBand:params.activityBand,allowCondensedPasses:params.allowCondensedPasses}}async evaluateIncrementalCompaction(params){const telemetry=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);const cacheState=this.config.cacheAwareCompaction.enabled?this.resolveCacheAwareState(telemetry):"unknown";const bounds=this.resolveDynamicLeafChunkBounds(params.tokenBudget);const activityBand=this.config.dynamicLeafChunkTokens.enabled?this.classifyDynamicLeafActivityBand({lastActivityBand:telemetry?.lastActivityBand,tokensAccumulatedSinceLeafCompaction:telemetry?.tokensAccumulatedSinceLeafCompaction??0,turnsSinceLeafCompaction:telemetry?.turnsSinceLeafCompaction??0,floor:bounds.floor}):"low";const triggerLeafChunkTokens=this.config.dynamicLeafChunkTokens.enabled&&cacheState==="hot"?bounds.max:this.config.dynamicLeafChunkTokens.enabled?this.resolveLeafChunkTokensForBand(activityBand,bounds):bounds.floor;const preferredLeafChunkTokens=this.config.cacheAwareCompaction.enabled&&(cacheState==="cold"||cacheState==="hot")?bounds.max:triggerLeafChunkTokens;const fallbackLeafChunkTokens=this.buildLeafChunkFallbacks({preferred:preferredLeafChunkTokens,bounds});const leafTrigger=await this.compaction.evaluateLeafTrigger(params.conversationId,triggerLeafChunkTokens);if(!leafTrigger.shouldCompact){return this.logIncrementalCompactionDecision({conversationId:params.conversationId,cacheState,activityBand,triggerLeafChunkTokens,preferredLeafChunkTokens,fallbackLeafChunkTokens,rawTokensOutsideTail:leafTrigger.rawTokensOutsideTail,threshold:leafTrigger.threshold,shouldCompact:false,maxPasses:1,allowCondensedPasses:false,reason:"below-leaf-trigger"})}const budgetDecision=await this.compaction.evaluate(params.conversationId,params.tokenBudget,params.currentTokenCount);if(budgetDecision.shouldCompact){return this.logIncrementalCompactionDecision({conversationId:params.conversationId,cacheState,activityBand,triggerLeafChunkTokens,preferredLeafChunkTokens,fallbackLeafChunkTokens,rawTokensOutsideTail:leafTrigger.rawTokensOutsideTail,threshold:leafTrigger.threshold,shouldCompact:true,maxPasses:1,allowCondensedPasses:true,reason:"budget-trigger"})}if(cacheState==="hot"&&this.isComfortablyUnderTokenBudget({currentTokenCount:params.currentTokenCount,tokenBudget:params.tokenBudget})){return this.logIncrementalCompactionDecision({conversationId:params.conversationId,cacheState,activityBand,triggerLeafChunkTokens,preferredLeafChunkTokens,fallbackLeafChunkTokens,rawTokensOutsideTail:leafTrigger.rawTokensOutsideTail,threshold:leafTrigger.threshold,shouldCompact:false,maxPasses:1,allowCondensedPasses:false,reason:"hot-cache-budget-headroom"})}if(cacheState==="hot"&&leafTrigger.rawTokensOutsideTail<Math.floor(leafTrigger.threshold*this.config.cacheAwareCompaction.hotCachePressureFactor)){return this.logIncrementalCompactionDecision({conversationId:params.conversationId,cacheState,activityBand,triggerLeafChunkTokens,preferredLeafChunkTokens,fallbackLeafChunkTokens,rawTokensOutsideTail:leafTrigger.rawTokensOutsideTail,threshold:leafTrigger.threshold,shouldCompact:false,maxPasses:1,allowCondensedPasses:false,reason:"hot-cache-defer"})}const maxPasses=cacheState==="cold"?Math.max(1,this.config.cacheAwareCompaction.maxColdCacheCatchupPasses):1;return this.logIncrementalCompactionDecision({conversationId:params.conversationId,cacheState,activityBand,triggerLeafChunkTokens,preferredLeafChunkTokens,fallbackLeafChunkTokens,rawTokensOutsideTail:leafTrigger.rawTokensOutsideTail,threshold:leafTrigger.threshold,shouldCompact:true,maxPasses,allowCondensedPasses:cacheState!=="hot",reason:cacheState==="cold"?"cold-cache-catchup":"leaf-trigger"})}async recordDeferredCompactionDebt(params){await this.compactionMaintenanceStore.requestProactiveCompactionDebt({conversationId:params.conversationId,reason:params.reason,tokenBudget:params.tokenBudget,currentTokenCount:params.currentTokenCount??null});this.deps.log.info(`[lcm] deferred compaction debt recorded: conversation=${params.conversationId} reason=${params.reason} tokenBudget=${params.tokenBudget} currentTokenCount=${params.currentTokenCount??"null"}`)}async consumeDeferredCompactionDebt(params){const maintenance=await this.compactionMaintenanceStore.getConversationCompactionMaintenance(params.conversationId);if(!maintenance?.pending&&!maintenance?.running){return null}const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");await this.compactionMaintenanceStore.markProactiveCompactionRunning({conversationId:params.conversationId,startedAt:new Date});try{const recordedTokenBudget=maintenance.tokenBudget&&maintenance.tokenBudget>0?maintenance.tokenBudget:null;const resolvedTokenBudget=this.applyAssemblyBudgetCap(recordedTokenBudget!=null?Math.min(params.tokenBudget,recordedTokenBudget):params.tokenBudget);const resolvedCurrentTokenCount=this.normalizeObservedTokenCount(params.currentTokenCount??maintenance.currentTokenCount??void 0);const result=maintenance.reason?.trim()==="threshold"?await this.executeCompactionCore({conversationId:params.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:resolvedTokenBudget,currentTokenCount:resolvedCurrentTokenCount,compactionTarget:"threshold",runtimeContext:params.runtimeContext,legacyParams:params.legacyParams}):await(async()=>{const leafDecision=await this.evaluateIncrementalCompaction({conversationId:params.conversationId,tokenBudget:resolvedTokenBudget,currentTokenCount:resolvedCurrentTokenCount});if(!leafDecision.shouldCompact){return{ok:true,compacted:false,reason:"deferred compaction no longer needed"}}return this.executeLeafCompactionCore({conversationId:params.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:resolvedTokenBudget,currentTokenCount:resolvedCurrentTokenCount,runtimeContext:params.runtimeContext,legacyParams:params.legacyParams,maxPasses:leafDecision.maxPasses,leafChunkTokens:leafDecision.leafChunkTokens,fallbackLeafChunkTokens:leafDecision.fallbackLeafChunkTokens,activityBand:leafDecision.activityBand,allowCondensedPasses:leafDecision.allowCondensedPasses})})();await this.compactionMaintenanceStore.markProactiveCompactionFinished({conversationId:params.conversationId,finishedAt:new Date,failureSummary:result.ok?null:result.reason??"deferred compaction failed",keepPending:!result.ok});this.deps.log.info(`[lcm] maintain: deferred compaction ${result.compacted?"completed":"skipped"} conversation=${params.conversationId} ${sessionLabel} changed=${result.compacted} ok=${result.ok} reason=${result.reason??"none"}`);return{changed:result.compacted,bytesFreed:0,rewrittenEntries:0,...result.reason?{reason:result.reason}:{}}}catch(error){await this.compactionMaintenanceStore.markProactiveCompactionFinished({conversationId:params.conversationId,finishedAt:new Date,failureSummary:error instanceof Error?error.message:String(error),keepPending:true});this.deps.log.warn(`[lcm] maintain: deferred compaction failed conversation=${params.conversationId} ${sessionLabel}: ${describeLogError(error)}`);return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:error instanceof Error?error.message:"deferred compaction failed"}}}async maybeConsumeDeferredCompactionDebtForAssemble(params){const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");await this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{const maintenance=await this.compactionMaintenanceStore.getConversationCompactionMaintenance(params.conversationId);if(!maintenance?.pending&&!maintenance?.running){return}const telemetry=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);const promptOverflowEmergency=(params.currentTokenCount??0)>params.tokenBudget;if(promptOverflowEmergency||!this.shouldDelayPromptMutatingDeferredCompaction(telemetry)){const deferredLegacyParams=telemetry?.provider||telemetry?.model?{...telemetry.provider?{provider:telemetry.provider}:{},...telemetry.model?{model:telemetry.model}:{}}:void 0;await this.consumeDeferredCompactionDebt({conversationId:params.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:params.tokenBudget,currentTokenCount:params.currentTokenCount,legacyParams:deferredLegacyParams});return}this.deps.log.info(`[lcm] assemble: deferred compaction still cache-hot for conversation=${params.conversationId} ${sessionLabel} retention=${telemetry?.retention??"null"} lastCacheTouchAt=${telemetry?.lastCacheTouchAt?.toISOString()??"null"}`)},{operationName:"assembleDeferredCompaction",context:sessionLabel})}async executeCompactionCore(params){const{force=false}=params;const legacyParams=asRecord(params.runtimeContext)??params.legacyParams;const lp=legacyParams??{};const manualCompactionRequested=lp.manualCompaction===true;const forceCompaction=force||manualCompactionRequested;const resolvedTokenBudget=this.resolveTokenBudget({tokenBudget:params.tokenBudget,runtimeContext:params.runtimeContext,legacyParams});const tokenBudget=resolvedTokenBudget?this.applyAssemblyBudgetCap(resolvedTokenBudget):resolvedTokenBudget;if(!tokenBudget){return{ok:false,compacted:false,reason:"missing token budget in compact params"}}const{summarize,summaryModel,breakerKey}=await this.resolveSummarize({legacyParams,customInstructions:params.customInstructions,breakerScope:this.resolveSessionQueueKey(params.sessionId,params.sessionKey)});if(breakerKey&&this.isCircuitBreakerOpen(breakerKey)){return{ok:true,compacted:false,reason:"circuit breaker open"}}const conversationId=params.conversationId;const observedTokens=this.normalizeObservedTokenCount(params.currentTokenCount??lp.currentTokenCount);const decision=observedTokens!==void 0?await this.compaction.evaluate(conversationId,tokenBudget,observedTokens):await this.compaction.evaluate(conversationId,tokenBudget);const targetTokens=params.compactionTarget==="threshold"?decision.threshold:tokenBudget;const liveContextStillExceedsTarget=observedTokens!==void 0&&observedTokens>=targetTokens;if(!forceCompaction&&!decision.shouldCompact){return{ok:true,compacted:false,reason:"below threshold",result:{tokensBefore:decision.currentTokens}}}const useSweep=manualCompactionRequested||params.compactionTarget==="threshold";if(useSweep){const sweepResult=await this.compaction.compact({conversationId,tokenBudget,summarize,force:forceCompaction,hardTrigger:false,summaryModel});if(sweepResult.authFailure&&breakerKey){this.recordCompactionAuthFailure(breakerKey)}else if(sweepResult.actionTaken&&breakerKey){this.recordCompactionSuccess(breakerKey)}if(sweepResult.actionTaken){await this.markLeafCompactionTelemetrySuccess({conversationId})}return{ok:!sweepResult.authFailure&&(sweepResult.actionTaken||!liveContextStillExceedsTarget),compacted:sweepResult.actionTaken,reason:sweepResult.authFailure?sweepResult.actionTaken?"provider auth failure after partial compaction":"provider auth failure":sweepResult.actionTaken?"compacted":manualCompactionRequested?"nothing to compact":liveContextStillExceedsTarget?"live context still exceeds target":"already under target",result:{tokensBefore:decision.currentTokens,tokensAfter:sweepResult.tokensAfter,details:{rounds:sweepResult.actionTaken?1:0,targetTokens}}}}const convergenceTargetTokens=forceCompaction?tokenBudget:params.compactionTarget==="threshold"?decision.threshold:tokenBudget;const effectiveCurrentTokens=observedTokens!==void 0?observedTokens:forceCompaction?tokenBudget:void 0;const compactResult=await this.compaction.compactUntilUnder({conversationId,tokenBudget,targetTokens:convergenceTargetTokens,...effectiveCurrentTokens!==void 0?{currentTokens:effectiveCurrentTokens}:{},summarize,summaryModel});if(compactResult.authFailure&&breakerKey){this.recordCompactionAuthFailure(breakerKey)}else if(compactResult.rounds>0&&breakerKey){this.recordCompactionSuccess(breakerKey)}const didCompact=compactResult.rounds>0;if(didCompact){await this.markLeafCompactionTelemetrySuccess({conversationId})}return{ok:compactResult.success,compacted:didCompact,reason:compactResult.authFailure?didCompact?"provider auth failure after partial compaction":"provider auth failure":compactResult.success?didCompact?"compacted":"already under target":"could not reach target",result:{tokensBefore:decision.currentTokens,tokensAfter:compactResult.finalTokens,details:{rounds:compactResult.rounds,targetTokens:convergenceTargetTokens}}}}async resolveConversationIdForSessionKey(sessionKey){const trimmedKey=sessionKey.trim();if(!trimmedKey){return void 0}try{const bySessionKey=await this.conversationStore.getConversationForSession({sessionKey:trimmedKey});if(bySessionKey){return bySessionKey.conversationId}const runtimeSessionId=await this.deps.resolveSessionIdFromSessionKey(trimmedKey);if(!runtimeSessionId){return void 0}const conversation=await this.conversationStore.getConversationForSession({sessionId:runtimeSessionId});return conversation?.conversationId}catch{return void 0}}formatSessionLogContext(params){const parts=[`conversation=${params.conversationId}`,`session=${params.sessionId}`];const trimmedSessionKey=params.sessionKey?.trim();if(trimmedSessionKey){parts.push(`sessionKey=${trimmedSessionKey}`)}return parts.join(" ")}async resolveSummarize(params){const lp=params.legacyParams??{};if(typeof lp.summarize==="function"){return{summarize:lp.summarize,summaryModel:"unknown",breakerKey:`custom:${params.breakerScope}`}}try{const customInstructions=params.customInstructions!==void 0?params.customInstructions:this.config.customInstructions||void 0;const runtimeSummarizer=await createLcmSummarizeFromLegacyParams({deps:this.deps,legacyParams:lp,customInstructions});if(runtimeSummarizer){return{summarize:runtimeSummarizer.fn,summaryModel:runtimeSummarizer.model,breakerKey:runtimeSummarizer.breakerKey}}this.deps.log.error(`[lcm] resolveSummarize: createLcmSummarizeFromLegacyParams returned undefined`)}catch(err){this.deps.log.error(`[lcm] resolveSummarize failed, using emergency fallback: ${describeLogError(err)}`)}this.deps.log.error(`[lcm] resolveSummarize: FALLING BACK TO EMERGENCY TRUNCATION`);return{summarize:createEmergencyFallbackSummarize(),summaryModel:"unknown"}}async resolveLargeFileTextSummarizer(){if(this.largeFileTextSummarizerResolved){return this.largeFileTextSummarizer}this.largeFileTextSummarizerResolved=true;const provider=this.deps.config.largeFileSummaryProvider;const model=this.deps.config.largeFileSummaryModel;if(!provider||!model){return void 0}try{const result=await createLcmSummarizeFromLegacyParams({deps:this.deps,legacyParams:{provider,model},customInstructions:this.config.customInstructions||void 0});if(!result){return void 0}this.largeFileTextSummarizer=async prompt=>{let summary;try{summary=await result.fn(prompt,false)}catch(err){if(err instanceof LcmProviderAuthError){return null}throw err}if(typeof summary!=="string"){return null}const trimmed=summary.trim();return trimmed.length>0?trimmed:null};return this.largeFileTextSummarizer}catch{return void 0}}static BASE64_IMAGE_MAGIC=[{prefix:"/9j/",extension:"jpg",mimeType:"image/jpeg"},{prefix:"iVBOR",extension:"png",mimeType:"image/png"},{prefix:"R0lGOD",extension:"gif",mimeType:"image/gif"},{prefix:"UklGR",extension:"webp",mimeType:"image/webp"},{prefix:"PHN2Zy",extension:"svg",mimeType:"image/svg+xml"}];static detectBase64ImageType(base64Data){for(const sig of _LcmContextEngine.BASE64_IMAGE_MAGIC){if(base64Data.startsWith(sig.prefix)){return{extension:sig.extension,mimeType:sig.mimeType}}}return null}static isExternalizedImageReference(value){return/^\[(?:User|Tool|Assistant|Image) image: .*LCM file: file_[a-f0-9]{16}\]$/.test(value.trim())}largeFilesDirForConversation(conversationId){return join3(this.config.largeFilesDir,String(conversationId))}async storeImageFileContent(params){const dir=this.largeFilesDirForConversation(params.conversationId);await mkdir(dir,{recursive:true});const normalized=params.extension.replace(/[^a-z0-9]/gi,"").toLowerCase()||"bin";const filePath=join3(dir,`${params.fileId}.${normalized}`);const buffer=Buffer.from(params.base64Data,"base64");await writeFile(filePath,buffer);return filePath}async externalizeImage(params){const fileId=`file_${randomUUID2().replace(/-/g,"").slice(0,16)}`;const byteSize=Buffer.from(params.base64Data,"base64").byteLength;const storageUri=await this.storeImageFileContent({conversationId:params.conversationId,fileId,extension:params.extension,base64Data:params.base64Data});const fileName=params.fileName??`image.${params.extension}`;const summary=`Image file (${params.extension.toUpperCase()}, ${byteSize.toLocaleString("en-US")} bytes)${params.fileName?` \u2014 ${params.fileName}`:""}`;await this.summaryStore.insertLargeFile({fileId,conversationId:params.conversationId,fileName,mimeType:params.mimeType,byteSize,storageUri,explorationSummary:summary});const reference=`[${params.label}: ${fileName} (${params.mimeType}, ${byteSize.toLocaleString("en-US")} bytes) | LCM file: ${fileId}]`;return{fileId,byteSize,summary,reference}}async interceptInlineImages(params){const mediaResult=await this.interceptUserMediaBase64(params);if(mediaResult){return mediaResult}return this.interceptPureBase64Image(params)}async interceptUserMediaBase64(params){const prefix="[media attached:";if(!params.content.startsWith(prefix)){return null}const base64LineRe=/\n([A-Za-z0-9+/]{20,}={0,2})\n/m;const base64Match=base64LineRe.exec(params.content);if(!base64Match){return null}const headerEnd=base64Match.index+1;const header=params.content.slice(0,headerEnd).trim();const base64Data=params.content.slice(headerEnd);if(estimateTokens(base64Data)<100){return null}const detected=_LcmContextEngine.detectBase64ImageType(base64Data);if(!detected){return null}const pathMatch=header.match(/\[media attached:\s*([^\s(]+)/);const fileName=pathMatch?pathMatch[1]:`user-image.${detected.extension}`;const externalized=await this.externalizeImage({conversationId:params.conversationId,base64Data,fileName,extension:detected.extension,mimeType:detected.mimeType,label:"User image"});return{rewrittenContent:`${header}
|
|
743
|
+
`;continue}const parsed=parseBootstrapJsonl(line);if(parsed.messages.length>0){messages.push(...parsed.messages)}}if(jsonArrayMode){const trimmed=jsonArrayBuffer.trim();if(!trimmed){return[]}try{const parsed=JSON.parse(trimmed);if(!Array.isArray(parsed)){return[]}return parsed.filter(isBootstrapMessage)}catch{return[]}}return messages}catch{return[]}}function resolveBootstrapMaxTokens(config){if(typeof config.bootstrapMaxTokens==="number"&&Number.isFinite(config.bootstrapMaxTokens)&&config.bootstrapMaxTokens>0){return Math.floor(config.bootstrapMaxTokens)}const leafChunkTokens=typeof config.leafChunkTokens==="number"&&Number.isFinite(config.leafChunkTokens)&&config.leafChunkTokens>0?Math.floor(config.leafChunkTokens):2e4;return Math.max(6e3,Math.floor(leafChunkTokens*.3))}function trimBootstrapMessagesToBudget(messages,maxTokens){if(messages.length===0){return[]}const safeMaxTokens=Number.isFinite(maxTokens)?Math.floor(maxTokens):0;if(safeMaxTokens<=0){return[messages[messages.length-1]]}const kept=[];let totalTokens=0;for(let index=messages.length-1;index>=0;index-=1){const message=messages[index];const tokenCount=toStoredMessage(message).tokenCount;if(kept.length>0&&totalTokens+tokenCount>safeMaxTokens){break}kept.push(message);totalTokens+=tokenCount}if(kept.length===1&&totalTokens>safeMaxTokens){return[]}kept.reverse();return kept}async function readFileSegment(sessionFile,offset){let fh=null;try{fh=await open(sessionFile,"r");const stats=await fh.stat();const safeOffset=Math.max(0,Math.min(Math.floor(offset),stats.size));const length=stats.size-safeOffset;if(length<=0){return""}const buffer=Buffer.alloc(length);await fh.read(buffer,0,length,safeOffset);return buffer.toString("utf8")}catch{return null}finally{await fh?.close()}}async function readLastJsonlEntryBeforeOffset(sessionFile,offset,messageOnly=false,matcher){const chunkSize=16384;const safeOffset=Math.max(0,Math.floor(offset));if(safeOffset<=0){return null}let fh=null;try{fh=await open(sessionFile,"r");let cursor=safeOffset;let carry="";while(true){const trimmedEnd=carry.replace(/\s+$/u,"");if(trimmedEnd){const newlineIndex=Math.max(trimmedEnd.lastIndexOf("\n"),trimmedEnd.lastIndexOf("\r"));if(newlineIndex>=0){const candidate=trimmedEnd.slice(newlineIndex+1).trim();if(candidate){if(messageOnly){let matchedMessage=null;try{matchedMessage=extractBootstrapMessageCandidate(JSON.parse(candidate))}catch{}if(!matchedMessage||matcher&&!matcher(matchedMessage)){carry=trimmedEnd.slice(0,newlineIndex);continue}}return candidate}carry=trimmedEnd.slice(0,newlineIndex);continue}}if(cursor<=0){const firstLine=trimmedEnd.trim()||null;if(!firstLine)return null;if(messageOnly){let matchedMessage=null;try{matchedMessage=extractBootstrapMessageCandidate(JSON.parse(firstLine))}catch{}if(!matchedMessage||matcher&&!matcher(matchedMessage))return null}return firstLine}const start=Math.max(0,cursor-chunkSize);const length=cursor-start;const buffer=Buffer.alloc(length);await fh.read(buffer,0,length,start);carry=buffer.toString("utf8")+carry;cursor=start}}catch{return null}finally{await fh?.close()}}async function readAppendedLeafPathMessages(params){const raw=await readFileSegment(params.sessionFile,params.offset);if(raw==null){return{messages:[],canUseAppendOnly:false,sawNonWhitespace:false}}const trimmed=raw.trim();if(!trimmed){return{messages:[],canUseAppendOnly:true,sawNonWhitespace:false}}if(trimmed.startsWith("[")){return{messages:[],canUseAppendOnly:false,sawNonWhitespace:true}}const parsed=parseBootstrapJsonl(raw,{strict:true});if(parsed.hadMalformedLine){return{messages:[],canUseAppendOnly:false,sawNonWhitespace:parsed.sawNonWhitespace}}return{messages:parsed.messages,canUseAppendOnly:true,sawNonWhitespace:parsed.sawNonWhitespace}}function readBootstrapMessageFromJsonLine(line){if(!line){return null}try{return extractBootstrapMessageCandidate(JSON.parse(line))}catch{return null}}function messageIdentity(role,content){return`${role}\0${content}`}var LcmContextEngine=class _LcmContextEngine{info;config;get timezone(){return this.config.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone}conversationStore;summaryStore;compactionTelemetryStore;compactionMaintenanceStore;assembler;compaction;retrieval;db;migrated=false;fts5Available;ignoreSessionPatterns;statelessSessionPatterns;sessionOperationQueues=new Map;largeFileTextSummarizerResolved=false;largeFileTextSummarizer;deps;lastFullReadFileState=new Map;circuitBreakerStates=new Map;constructor(deps,database){this.deps=deps;this.config=deps.config;this.ignoreSessionPatterns=compileSessionPatterns(this.config.ignoreSessionPatterns);this.statelessSessionPatterns=compileSessionPatterns(this.config.statelessSessionPatterns);this.db=database;let migrationOk=false;const migrationStartedAt=Date.now();try{runLcmMigrations(this.db,{log:this.deps.log});this.migrated=true;const tables=this.db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();if(tables.length===0){this.deps.log.warn("[lcm] Migration completed but database has zero tables \u2014 DB may be non-functional")}else{migrationOk=true;this.deps.log.info(`[lcm] Migration run completed during engine init: duration=${formatDurationMs(Date.now()-migrationStartedAt)} fts5=${this.fts5Available}`);this.deps.log.debug(`[lcm] Migration successful \u2014 ${tables.length} tables: ${tables.map(t=>t.name).join(", ")}`)}}catch(err){this.deps.log.error(`[lcm] Migration failed after ${formatDurationMs(Date.now()-migrationStartedAt)}: ${err instanceof Error?err.message:String(err)}`)}this.fts5Available=getLcmDbFeatures(this.db).fts5Available;this.info={id:"lossless-claw",name:"Lossless Context Management Engine",version:"0.1.0",ownsCompaction:migrationOk,turnMaintenanceMode:"background"};this.conversationStore=new ConversationStore(this.db,{fts5Available:this.fts5Available});this.summaryStore=new SummaryStore(this.db,{fts5Available:this.fts5Available});this.compactionTelemetryStore=new CompactionTelemetryStore(this.db);this.compactionMaintenanceStore=new CompactionMaintenanceStore(this.db);if(!this.fts5Available){this.deps.log.warn("[lcm] FTS5 unavailable in the current Node runtime; full_text search will fall back to LIKE and indexing is disabled")}if(this.config.ignoreSessionPatterns.length>0){const source=describeLcmConfigSource(this.deps.configDiagnostics?.ignoreSessionPatternsSource??"default");logStartupBannerOnce({key:"ignore-session-patterns",log:message=>this.deps.log.info(message),message:`[lcm] Ignoring sessions matching ${this.config.ignoreSessionPatterns.length} pattern(s) from ${source}: ${this.config.ignoreSessionPatterns.join(", ")}`})}if(this.config.statelessSessionPatterns.length>0){const source=describeLcmConfigSource(this.deps.configDiagnostics?.statelessSessionPatternsSource??"default");const enforcement=this.config.skipStatelessSessions?"":" (skipStatelessSessions=false)";logStartupBannerOnce({key:"stateless-session-patterns",log:message=>this.deps.log.info(message),message:`[lcm] Stateless session patterns${enforcement} from ${source}: ${this.config.statelessSessionPatterns.length} pattern(s): ${this.config.statelessSessionPatterns.join(", ")}`})}this.assembler=new ContextAssembler(this.conversationStore,this.summaryStore,this.config.timezone);const compactionConfig={contextThreshold:this.config.contextThreshold,freshTailCount:this.config.freshTailCount,freshTailMaxTokens:this.config.freshTailMaxTokens,leafMinFanout:this.config.leafMinFanout,condensedMinFanout:this.config.condensedMinFanout,condensedMinFanoutHard:this.config.condensedMinFanoutHard,incrementalMaxDepth:this.config.incrementalMaxDepth,leafChunkTokens:this.config.leafChunkTokens,leafTargetTokens:this.config.leafTargetTokens,condensedTargetTokens:this.config.condensedTargetTokens,maxRounds:10,timezone:this.config.timezone,summaryMaxOverageFactor:this.config.summaryMaxOverageFactor};this.compaction=new CompactionEngine(this.conversationStore,this.summaryStore,compactionConfig,this.deps.log);this.retrieval=new RetrievalEngine(this.conversationStore,this.summaryStore)}shouldIgnoreSession(params){if(this.ignoreSessionPatterns.length===0){return false}const candidate=typeof params.sessionKey==="string"&¶ms.sessionKey.trim()?params.sessionKey.trim():params.sessionId?.trim()??"";if(!candidate){return false}return matchesSessionPattern(candidate,this.ignoreSessionPatterns)}isStatelessSession(sessionKey){const trimmedKey=typeof sessionKey==="string"?sessionKey.trim():"";if(!this.config.skipStatelessSessions||!trimmedKey||this.statelessSessionPatterns.length===0){return false}return matchesSessionPattern(trimmedKey,this.statelessSessionPatterns)}getCircuitBreakerState(key){let state=this.circuitBreakerStates.get(key);if(!state){state={failures:0,openSince:null};this.circuitBreakerStates.set(key,state)}return state}isCircuitBreakerOpen(key){const state=this.circuitBreakerStates.get(key);if(!state||state.openSince===null)return false;const elapsed=Date.now()-state.openSince;if(elapsed>=this.config.circuitBreakerCooldownMs){this.resetCircuitBreaker(key);return false}return true}recordCompactionAuthFailure(key){const state=this.getCircuitBreakerState(key);state.failures++;const halfThreshold=Math.ceil(this.config.circuitBreakerThreshold/2);if(state.failures===halfThreshold&&state.failures<this.config.circuitBreakerThreshold){this.deps.log.warn(`[lcm] WARNING: compaction degraded \u2014 ${state.failures}/${this.config.circuitBreakerThreshold} consecutive auth failures for ${key}`)}if(state.failures>=this.config.circuitBreakerThreshold){state.openSince=Date.now();const cooldownMin=Math.round(this.config.circuitBreakerCooldownMs/6e4);this.deps.log.warn(`[lcm] CIRCUIT BREAKER OPEN: compaction disabled for ${key}. Auto-retry in ${cooldownMin}m. LCM is operating in degraded mode.`)}}recordCompactionSuccess(key){const state=this.circuitBreakerStates.get(key);if(!state){return}if(state.failures>0||state.openSince!==null){this.deps.log.info(`[lcm] compaction circuit breaker CLOSED: successful compaction for ${key} after ${state.failures} prior failures.`)}this.resetCircuitBreaker(key)}resetCircuitBreaker(key){this.circuitBreakerStates.delete(key)}ensureMigrated(){if(this.migrated){return}const migrationStartedAt=Date.now();this.deps.log.info("[lcm] ensureMigrated: running migrations lazily");runLcmMigrations(this.db,{log:this.deps.log});this.migrated=true;this.deps.log.info(`[lcm] ensureMigrated: completed in ${formatDurationMs(Date.now()-migrationStartedAt)}`)}async withSessionQueue(queueKey,operation,options){const entry=this.sessionOperationQueues.get(queueKey);const previous=entry?.promise??Promise.resolve();const queuedAhead=entry?.refCount??0;let releaseQueue=()=>{};const current=new Promise(resolve2=>{releaseQueue=resolve2});const next=previous.catch(()=>{}).then(()=>current);if(entry){entry.promise=next;entry.refCount++}else{this.sessionOperationQueues.set(queueKey,{promise:next,refCount:1})}const waitStartedAt=Date.now();await previous.catch(()=>{});const waitMs=Date.now()-waitStartedAt;if(options?.operationName){const detail=options.context?` ${options.context}`:"";this.deps.log.info(`[lcm] ${options.operationName}: session queue acquired queueKey=${queueKey} queuedAhead=${queuedAhead} wait=${formatDurationMs(waitMs)}${detail}`)}try{return await operation()}finally{releaseQueue();const cur=this.sessionOperationQueues.get(queueKey);if(cur&&--cur.refCount===0){this.sessionOperationQueues.delete(queueKey)}}}resolveSessionQueueKey(sessionId,sessionKey){const normalizedSessionKey=sessionKey?.trim();const normalizedSessionId=sessionId?.trim();return normalizedSessionKey||normalizedSessionId||"__lcm__"}normalizeObservedTokenCount(value){if(typeof value!=="number"||!Number.isFinite(value)||value<=0){return void 0}return Math.floor(value)}resolveTokenBudget(params){const lp=asRecord(params.runtimeContext)??params.legacyParams??{};if(typeof params.tokenBudget==="number"&&Number.isFinite(params.tokenBudget)&¶ms.tokenBudget>0){return Math.floor(params.tokenBudget)}if(typeof lp.tokenBudget==="number"&&Number.isFinite(lp.tokenBudget)&&lp.tokenBudget>0){return Math.floor(lp.tokenBudget)}return void 0}applyAssemblyBudgetCap(budget){const cap=this.config.maxAssemblyTokenBudget;return cap!=null&&cap>0?Math.min(budget,cap):budget}normalizeOptionalCount(value){if(typeof value!=="number"||!Number.isFinite(value)||value<0){return void 0}return Math.floor(value)}shouldApplyHotCacheHysteresis(telemetry){if(!telemetry?.lastObservedCacheHitAt){return false}if(telemetry.lastObservedCacheBreakAt&&telemetry.lastObservedCacheBreakAt>=telemetry.lastObservedCacheHitAt){return false}return telemetry.turnsSinceLeafCompaction<=HOT_CACHE_HYSTERESIS_TURNS}resolveCacheAwareState(telemetry){if(!telemetry){return"unknown"}if(telemetry.cacheState==="hot"){return"hot"}if(this.shouldApplyHotCacheHysteresis(telemetry)){return"hot"}if(telemetry.lastObservedCacheBreakAt&&(!telemetry.lastObservedCacheHitAt||telemetry.lastObservedCacheBreakAt>=telemetry.lastObservedCacheHitAt)){return"cold"}if(telemetry.consecutiveColdObservations>=this.config.cacheAwareCompaction.coldCacheObservationThreshold){return"cold"}if(telemetry.lastObservedCacheHitAt){return"hot"}if(telemetry.cacheState==="cold"){return"unknown"}return telemetry.cacheState}resolvePromptCacheTtlMs(retention){const normalized=retention?.trim().toLowerCase();if(normalized==="none"){return null}if(normalized==="long"||normalized==="1h"){return 60*60*1e3}return Math.max(1,this.config.cacheAwareCompaction.cacheTTLSeconds)*1e3}isAnthropicPromptCacheFamily(telemetry){const provider=telemetry?.provider?.trim().toLowerCase()??"";const model=telemetry?.model?.trim().toLowerCase()??"";return provider.includes("anthropic")||model.includes("claude")}isPromptCacheStillHot(telemetry,now=new Date){const ttlMs=this.resolvePromptCacheTtlMs(telemetry?.retention??null);if(!ttlMs){return false}const touchAt=telemetry?.lastCacheTouchAt??telemetry?.lastObservedCacheHitAt??telemetry?.lastApiCallAt??null;if(!touchAt){return false}return now.getTime()-touchAt.getTime()<ttlMs}shouldDelayPromptMutatingDeferredCompaction(telemetry,now=new Date){return this.isAnthropicPromptCacheFamily(telemetry)&&this.isPromptCacheStillHot(telemetry,now)}shouldForceDeferredAnthropicLeafCompaction(telemetry,leafDecision){if(leafDecision.shouldCompact){return false}if(leafDecision.reason!=="hot-cache-budget-headroom"&&leafDecision.reason!=="hot-cache-defer"){return false}if(!this.isAnthropicPromptCacheFamily(telemetry)){return false}return!this.shouldDelayPromptMutatingDeferredCompaction(telemetry)}resolveDeferredLeafCompactionExecutionDecision(params){if(!this.shouldForceDeferredAnthropicLeafCompaction(params.telemetry,params.leafDecision)){return params.leafDecision}return{...params.leafDecision,maxPasses:Math.max(1,this.config.cacheAwareCompaction.maxColdCacheCatchupPasses),allowCondensedPasses:true}}isComfortablyUnderTokenBudget(params){if(typeof params.currentTokenCount!=="number"||!Number.isFinite(params.currentTokenCount)||params.currentTokenCount<0){return false}const budget=Math.max(1,Math.floor(params.tokenBudget));const safeBudget=Math.floor(budget*(1-this.config.cacheAwareCompaction.hotCacheBudgetHeadroomRatio));return params.currentTokenCount<=safeBudget}resolveBudgetTriggerCatchupPasses(params){const overage=Math.max(0,params.currentTokens-params.threshold);if(overage<=0){return 1}const chunkTokens=Math.max(1,Math.floor(params.leafChunkTokens));return Math.max(1,Math.min(MAX_BUDGET_TRIGGER_CATCHUP_PASSES,Math.ceil(overage/chunkTokens)))}resolveDynamicLeafChunkBounds(tokenBudget){const floor=Math.max(1,Math.floor(this.config.leafChunkTokens));const configuredMax=this.config.dynamicLeafChunkTokens.enabled?Math.max(floor,Math.floor(this.config.dynamicLeafChunkTokens.max)):floor;const budgetCap=typeof tokenBudget==="number"&&Number.isFinite(tokenBudget)&&tokenBudget>0?Math.max(floor,Math.floor(tokenBudget*this.config.contextThreshold)):configuredMax;const max=Math.max(floor,Math.min(configuredMax,budgetCap));const medium=Math.max(floor,Math.min(max,Math.floor(floor*DYNAMIC_LEAF_CHUNK_MEDIUM_MULTIPLIER)));const high=Math.max(floor,Math.min(max,Math.floor(floor*DYNAMIC_LEAF_CHUNK_HIGH_MULTIPLIER)));return{floor,medium,high,max}}classifyDynamicLeafActivityBand(params){const turns=Math.max(1,params.turnsSinceLeafCompaction);const tokensPerTurn=params.tokensAccumulatedSinceLeafCompaction/turns;const mediumUpshift=params.floor*DYNAMIC_ACTIVITY_MEDIUM_UPSHIFT_FACTOR;const mediumDownshift=params.floor*DYNAMIC_ACTIVITY_MEDIUM_DOWNSHIFT_FACTOR;const highUpshift=params.floor*DYNAMIC_ACTIVITY_HIGH_UPSHIFT_FACTOR;const highDownshift=params.floor*DYNAMIC_ACTIVITY_HIGH_DOWNSHIFT_FACTOR;const lastBand=params.lastActivityBand??"low";if(lastBand==="high"){if(tokensPerTurn>=highDownshift){return"high"}return tokensPerTurn>=mediumDownshift?"medium":"low"}if(lastBand==="medium"){if(tokensPerTurn>=highUpshift){return"high"}if(tokensPerTurn<mediumDownshift){return"low"}return"medium"}if(tokensPerTurn>=highUpshift){return"high"}if(tokensPerTurn>=mediumUpshift){return"medium"}return"low"}resolveLeafChunkTokensForBand(band,bounds){switch(band){case"high":return bounds.high;case"medium":return bounds.medium;default:return bounds.floor}}buildLeafChunkFallbacks(params){const ordered=[params.preferred,params.bounds.max,params.bounds.high,params.bounds.medium,params.bounds.floor];const seen=new Set;const fallbacks=[];for(const value of ordered){const normalized=Math.max(params.bounds.floor,Math.floor(value));if(seen.has(normalized)){continue}seen.add(normalized);fallbacks.push(normalized)}return fallbacks.sort((a,b)=>b-a)}isRecoverableLeafChunkOverflowError(error){const message=(error instanceof Error?error.message:String(error)).toLowerCase();if(!message){return false}return["context length","context window","maximum context","max context","too many tokens","too many input tokens","input tokens","token limit","context limit","input is too large","input too large","prompt is too long","request too large","exceeds the model","exceeds context"].some(fragment=>message.includes(fragment))}readPromptCacheSnapshot(runtimeContext){const promptCache=asRecord(runtimeContext?.promptCache);const provider=safeString(runtimeContext?.provider)?.trim()??safeString(runtimeContext?.providerId)?.trim();const model=safeString(runtimeContext?.model)?.trim()??safeString(runtimeContext?.modelId)?.trim();if(!promptCache&&!provider&&!model){return null}const lastCallUsage=asRecord(promptCache?.lastCallUsage);const observation=asRecord(promptCache?.observation);const cacheRead=this.normalizeOptionalCount(lastCallUsage?.cacheRead);const cacheWrite=this.normalizeOptionalCount(lastCallUsage?.cacheWrite);const sawExplicitBreak=safeBoolean(observation?.broke)===true;const retention=safeString(promptCache?.retention)?.trim();const lastCacheTouchAtRaw=promptCache?.lastCacheTouchAt;const lastCacheTouchAt=typeof lastCacheTouchAtRaw==="number"&&Number.isFinite(lastCacheTouchAtRaw)?new Date(lastCacheTouchAtRaw):void 0;const hasUsageSignal=cacheRead!==void 0||cacheWrite!==void 0;const hasObservationSignal=typeof observation?.cacheRead==="number"||typeof observation?.previousCacheRead==="number"||sawExplicitBreak;let cacheState="unknown";if(sawExplicitBreak){cacheState="cold"}else if(typeof cacheRead==="number"&&cacheRead>0){cacheState="hot"}else if(hasUsageSignal||hasObservationSignal){cacheState="cold"}return{...cacheRead!==void 0?{lastObservedCacheRead:cacheRead}:{},...cacheWrite!==void 0?{lastObservedCacheWrite:cacheWrite}:{},cacheState,...retention?{retention}:{},sawExplicitBreak,...lastCacheTouchAt?{lastCacheTouchAt}:{},...provider?{provider}:{},...model?{model}:{}}}async updateCompactionTelemetry(params){const snapshot=this.readPromptCacheSnapshot(params.runtimeContext);const existing=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);if(!snapshot&¶ms.rawTokensOutsideTail===void 0){return existing}const now=new Date;const bounds=this.resolveDynamicLeafChunkBounds(params.tokenBudget);const turnsSinceLeafCompaction=(existing?.turnsSinceLeafCompaction??0)+1;const tokensAccumulatedSinceLeafCompaction=params.rawTokensOutsideTail??existing?.tokensAccumulatedSinceLeafCompaction??0;const touchedPromptCache=snapshot?.lastCacheTouchAt??(snapshot&&(snapshot.lastObservedCacheRead!==void 0||snapshot.lastObservedCacheWrite!==void 0)?now:existing?.lastCacheTouchAt??null);const consecutiveColdObservations=snapshot?.sawExplicitBreak?Math.max(existing?.consecutiveColdObservations??0,this.config.cacheAwareCompaction.coldCacheObservationThreshold):snapshot?.cacheState==="hot"?0:snapshot?.cacheState==="cold"?(existing?.consecutiveColdObservations??0)+1:existing?.consecutiveColdObservations??0;const lastActivityBand=this.classifyDynamicLeafActivityBand({lastActivityBand:existing?.lastActivityBand,tokensAccumulatedSinceLeafCompaction,turnsSinceLeafCompaction,floor:bounds.floor});await this.compactionTelemetryStore.upsertConversationCompactionTelemetry({conversationId:params.conversationId,lastObservedCacheRead:snapshot?.lastObservedCacheRead??existing?.lastObservedCacheRead??null,lastObservedCacheWrite:snapshot?.lastObservedCacheWrite??existing?.lastObservedCacheWrite??null,lastObservedCacheHitAt:snapshot?.cacheState==="hot"?now:existing?.lastObservedCacheHitAt??null,lastObservedCacheBreakAt:snapshot?.sawExplicitBreak?now:existing?.lastObservedCacheBreakAt??null,cacheState:snapshot?.cacheState??existing?.cacheState??"unknown",consecutiveColdObservations,retention:snapshot?.retention??existing?.retention??null,lastLeafCompactionAt:existing?.lastLeafCompactionAt??null,turnsSinceLeafCompaction,tokensAccumulatedSinceLeafCompaction,lastActivityBand,lastApiCallAt:now,lastCacheTouchAt:touchedPromptCache,provider:snapshot?.provider??existing?.provider??null,model:snapshot?.model??existing?.model??null});const updated=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);if(updated){this.deps.log.debug(`[lcm] compaction telemetry updated: conversation=${params.conversationId} cacheState=${updated.cacheState} coldObservationStreak=${updated.consecutiveColdObservations} cacheRead=${updated.lastObservedCacheRead??"null"} cacheWrite=${updated.lastObservedCacheWrite??"null"} retention=${updated.retention??"null"} lastApiCallAt=${updated.lastApiCallAt?.toISOString()??"null"} lastCacheTouchAt=${updated.lastCacheTouchAt?.toISOString()??"null"} provider=${updated.provider??"null"} model=${updated.model??"null"} turnsSinceLeafCompaction=${updated.turnsSinceLeafCompaction} tokensSinceLeafCompaction=${updated.tokensAccumulatedSinceLeafCompaction} activityBand=${updated.lastActivityBand} rawTokensOutsideTail=${params.rawTokensOutsideTail??"null"} tokenBudget=${params.tokenBudget??"null"}`)}return updated}async markLeafCompactionTelemetrySuccess(params){const existing=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);await this.compactionTelemetryStore.upsertConversationCompactionTelemetry({conversationId:params.conversationId,lastObservedCacheRead:existing?.lastObservedCacheRead??null,lastObservedCacheWrite:existing?.lastObservedCacheWrite??null,lastObservedCacheHitAt:existing?.lastObservedCacheHitAt??null,lastObservedCacheBreakAt:existing?.lastObservedCacheBreakAt??null,cacheState:existing?.cacheState??"unknown",consecutiveColdObservations:existing?.consecutiveColdObservations??0,retention:existing?.retention??null,lastLeafCompactionAt:new Date,turnsSinceLeafCompaction:0,tokensAccumulatedSinceLeafCompaction:0,lastActivityBand:params.activityBand??existing?.lastActivityBand??"low",lastApiCallAt:existing?.lastApiCallAt??null,lastCacheTouchAt:existing?.lastCacheTouchAt??null,provider:existing?.provider??null,model:existing?.model??null});this.deps.log.debug(`[lcm] compaction telemetry reset after leaf compaction: conversation=${params.conversationId} cacheState=${existing?.cacheState??"unknown"} activityBand=${params.activityBand??existing?.lastActivityBand??"low"}`)}logIncrementalCompactionDecision(params){this.deps.log.info(`[lcm] incremental compaction decision: conversation=${params.conversationId} cacheState=${params.cacheState} activityBand=${params.activityBand} triggerLeafChunkTokens=${params.triggerLeafChunkTokens} preferredLeafChunkTokens=${params.preferredLeafChunkTokens} fallbackLeafChunkTokens=${params.fallbackLeafChunkTokens.join(",")} rawTokensOutsideTail=${params.rawTokensOutsideTail} threshold=${params.threshold} shouldCompact=${params.shouldCompact} maxPasses=${params.maxPasses} allowCondensedPasses=${params.allowCondensedPasses} reason=${params.reason}`);return{shouldCompact:params.shouldCompact,cacheState:params.cacheState,maxPasses:params.maxPasses,rawTokensOutsideTail:params.rawTokensOutsideTail,threshold:params.threshold,reason:params.reason,leafChunkTokens:params.preferredLeafChunkTokens,fallbackLeafChunkTokens:params.fallbackLeafChunkTokens,activityBand:params.activityBand,allowCondensedPasses:params.allowCondensedPasses}}async evaluateIncrementalCompaction(params){const telemetry=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);const cacheState=this.config.cacheAwareCompaction.enabled?this.resolveCacheAwareState(telemetry):"unknown";const bounds=this.resolveDynamicLeafChunkBounds(params.tokenBudget);const activityBand=this.config.dynamicLeafChunkTokens.enabled?this.classifyDynamicLeafActivityBand({lastActivityBand:telemetry?.lastActivityBand,tokensAccumulatedSinceLeafCompaction:telemetry?.tokensAccumulatedSinceLeafCompaction??0,turnsSinceLeafCompaction:telemetry?.turnsSinceLeafCompaction??0,floor:bounds.floor}):"low";const triggerLeafChunkTokens=this.config.dynamicLeafChunkTokens.enabled&&cacheState==="hot"?bounds.max:this.config.dynamicLeafChunkTokens.enabled?this.resolveLeafChunkTokensForBand(activityBand,bounds):bounds.floor;const preferredLeafChunkTokens=this.config.cacheAwareCompaction.enabled&&(cacheState==="cold"||cacheState==="hot")?bounds.max:triggerLeafChunkTokens;const fallbackLeafChunkTokens=this.buildLeafChunkFallbacks({preferred:preferredLeafChunkTokens,bounds});const leafTrigger=await this.compaction.evaluateLeafTrigger(params.conversationId,triggerLeafChunkTokens);if(!leafTrigger.shouldCompact){return this.logIncrementalCompactionDecision({conversationId:params.conversationId,cacheState,activityBand,triggerLeafChunkTokens,preferredLeafChunkTokens,fallbackLeafChunkTokens,rawTokensOutsideTail:leafTrigger.rawTokensOutsideTail,threshold:leafTrigger.threshold,shouldCompact:false,maxPasses:1,allowCondensedPasses:false,reason:"below-leaf-trigger"})}const budgetDecision=await this.compaction.evaluate(params.conversationId,params.tokenBudget,params.currentTokenCount);if(budgetDecision.shouldCompact){const maxPasses2=this.resolveBudgetTriggerCatchupPasses({currentTokens:budgetDecision.currentTokens,threshold:budgetDecision.threshold,leafChunkTokens:preferredLeafChunkTokens});return this.logIncrementalCompactionDecision({conversationId:params.conversationId,cacheState,activityBand,triggerLeafChunkTokens,preferredLeafChunkTokens,fallbackLeafChunkTokens,rawTokensOutsideTail:leafTrigger.rawTokensOutsideTail,threshold:leafTrigger.threshold,shouldCompact:true,maxPasses:maxPasses2,allowCondensedPasses:true,reason:"budget-trigger"})}if(cacheState==="hot"&&this.isComfortablyUnderTokenBudget({currentTokenCount:params.currentTokenCount,tokenBudget:params.tokenBudget})){return this.logIncrementalCompactionDecision({conversationId:params.conversationId,cacheState,activityBand,triggerLeafChunkTokens,preferredLeafChunkTokens,fallbackLeafChunkTokens,rawTokensOutsideTail:leafTrigger.rawTokensOutsideTail,threshold:leafTrigger.threshold,shouldCompact:false,maxPasses:1,allowCondensedPasses:false,reason:"hot-cache-budget-headroom"})}if(cacheState==="hot"&&leafTrigger.rawTokensOutsideTail<Math.floor(leafTrigger.threshold*this.config.cacheAwareCompaction.hotCachePressureFactor)){return this.logIncrementalCompactionDecision({conversationId:params.conversationId,cacheState,activityBand,triggerLeafChunkTokens,preferredLeafChunkTokens,fallbackLeafChunkTokens,rawTokensOutsideTail:leafTrigger.rawTokensOutsideTail,threshold:leafTrigger.threshold,shouldCompact:false,maxPasses:1,allowCondensedPasses:false,reason:"hot-cache-defer"})}const maxPasses=cacheState==="cold"?Math.max(1,this.config.cacheAwareCompaction.maxColdCacheCatchupPasses):1;return this.logIncrementalCompactionDecision({conversationId:params.conversationId,cacheState,activityBand,triggerLeafChunkTokens,preferredLeafChunkTokens,fallbackLeafChunkTokens,rawTokensOutsideTail:leafTrigger.rawTokensOutsideTail,threshold:leafTrigger.threshold,shouldCompact:true,maxPasses,allowCondensedPasses:cacheState!=="hot",reason:cacheState==="cold"?"cold-cache-catchup":"leaf-trigger"})}async recordDeferredCompactionDebt(params){await this.compactionMaintenanceStore.requestProactiveCompactionDebt({conversationId:params.conversationId,reason:params.reason,tokenBudget:params.tokenBudget,currentTokenCount:params.currentTokenCount??null});this.deps.log.info(`[lcm] deferred compaction debt recorded: conversation=${params.conversationId} reason=${params.reason} tokenBudget=${params.tokenBudget} currentTokenCount=${params.currentTokenCount??"null"}`)}async consumeDeferredCompactionDebt(params){const maintenance=await this.compactionMaintenanceStore.getConversationCompactionMaintenance(params.conversationId);if(!maintenance?.pending&&!maintenance?.running){return null}const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");await this.compactionMaintenanceStore.markProactiveCompactionRunning({conversationId:params.conversationId,startedAt:new Date});try{const recordedTokenBudget=maintenance.tokenBudget&&maintenance.tokenBudget>0?maintenance.tokenBudget:null;const resolvedTokenBudget=this.applyAssemblyBudgetCap(recordedTokenBudget!=null?Math.min(params.tokenBudget,recordedTokenBudget):params.tokenBudget);const resolvedCurrentTokenCount=this.normalizeObservedTokenCount(params.currentTokenCount??maintenance.currentTokenCount??void 0);const result=maintenance.reason?.trim()==="threshold"?await this.executeCompactionCore({conversationId:params.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:resolvedTokenBudget,currentTokenCount:resolvedCurrentTokenCount,compactionTarget:"threshold",runtimeContext:params.runtimeContext,legacyParams:params.legacyParams}):await(async()=>{const telemetry=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);const leafDecision=await this.evaluateIncrementalCompaction({conversationId:params.conversationId,tokenBudget:resolvedTokenBudget,currentTokenCount:resolvedCurrentTokenCount});const executionLeafDecision=this.resolveDeferredLeafCompactionExecutionDecision({telemetry,leafDecision});if(!leafDecision.shouldCompact){const deferredLeafStillNeeded=leafDecision.rawTokensOutsideTail>=leafDecision.threshold;if(executionLeafDecision===leafDecision){return{ok:true,compacted:false,reason:deferredLeafStillNeeded?DEFERRED_COMPACTION_STILL_NEEDED_REASON:"deferred compaction no longer needed"}}this.deps.log.info(`[lcm] maintain: deferred Anthropic leaf debt ignoring effective hot-cache state after TTL expiry conversation=${params.conversationId} ${sessionLabel} reason=${leafDecision.reason} retention=${telemetry?.retention??"null"} lastCacheTouchAt=${telemetry?.lastCacheTouchAt?.toISOString()??"null"}`)}return this.executeLeafCompactionCore({conversationId:params.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:resolvedTokenBudget,currentTokenCount:resolvedCurrentTokenCount,runtimeContext:params.runtimeContext,legacyParams:params.legacyParams,maxPasses:executionLeafDecision.maxPasses,leafChunkTokens:executionLeafDecision.leafChunkTokens,fallbackLeafChunkTokens:executionLeafDecision.fallbackLeafChunkTokens,activityBand:executionLeafDecision.activityBand,allowCondensedPasses:executionLeafDecision.allowCondensedPasses})})();await this.compactionMaintenanceStore.markProactiveCompactionFinished({conversationId:params.conversationId,finishedAt:new Date,failureSummary:result.ok?null:result.reason??"deferred compaction failed",keepPending:!result.ok||result.reason===DEFERRED_COMPACTION_STILL_NEEDED_REASON});this.deps.log.info(`[lcm] maintain: deferred compaction ${result.compacted?"completed":"skipped"} conversation=${params.conversationId} ${sessionLabel} changed=${result.compacted} ok=${result.ok} reason=${result.reason??"none"}`);return{changed:result.compacted,bytesFreed:0,rewrittenEntries:0,...result.reason?{reason:result.reason}:{}}}catch(error){await this.compactionMaintenanceStore.markProactiveCompactionFinished({conversationId:params.conversationId,finishedAt:new Date,failureSummary:error instanceof Error?error.message:String(error),keepPending:true});this.deps.log.warn(`[lcm] maintain: deferred compaction failed conversation=${params.conversationId} ${sessionLabel}: ${describeLogError(error)}`);return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:error instanceof Error?error.message:"deferred compaction failed"}}}async maybeConsumeDeferredCompactionDebtForAssemble(params){const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");await this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{const maintenance=await this.compactionMaintenanceStore.getConversationCompactionMaintenance(params.conversationId);if(!maintenance?.pending&&!maintenance?.running){return}const telemetry=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);const promptOverflowEmergency=(params.currentTokenCount??0)>params.tokenBudget;if(promptOverflowEmergency||!this.shouldDelayPromptMutatingDeferredCompaction(telemetry)){const deferredLegacyParams=telemetry?.provider||telemetry?.model?{...telemetry.provider?{provider:telemetry.provider}:{},...telemetry.model?{model:telemetry.model}:{}}:void 0;await this.consumeDeferredCompactionDebt({conversationId:params.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:params.tokenBudget,currentTokenCount:params.currentTokenCount,legacyParams:deferredLegacyParams});return}this.deps.log.info(`[lcm] assemble: deferred compaction still cache-hot for conversation=${params.conversationId} ${sessionLabel} retention=${telemetry?.retention??"null"} lastCacheTouchAt=${telemetry?.lastCacheTouchAt?.toISOString()??"null"}`)},{operationName:"assembleDeferredCompaction",context:sessionLabel})}async executeCompactionCore(params){const{force=false}=params;const legacyParams=asRecord(params.runtimeContext)??params.legacyParams;const lp=legacyParams??{};const manualCompactionRequested=lp.manualCompaction===true;const forceCompaction=force||manualCompactionRequested;const resolvedTokenBudget=this.resolveTokenBudget({tokenBudget:params.tokenBudget,runtimeContext:params.runtimeContext,legacyParams});const tokenBudget=resolvedTokenBudget?this.applyAssemblyBudgetCap(resolvedTokenBudget):resolvedTokenBudget;if(!tokenBudget){return{ok:false,compacted:false,reason:"missing token budget in compact params"}}const{summarize,summaryModel,breakerKey}=await this.resolveSummarize({legacyParams,customInstructions:params.customInstructions,breakerScope:this.resolveSessionQueueKey(params.sessionId,params.sessionKey)});if(breakerKey&&this.isCircuitBreakerOpen(breakerKey)){return{ok:true,compacted:false,reason:"circuit breaker open"}}const conversationId=params.conversationId;const observedTokens=this.normalizeObservedTokenCount(params.currentTokenCount??lp.currentTokenCount);const decision=observedTokens!==void 0?await this.compaction.evaluate(conversationId,tokenBudget,observedTokens):await this.compaction.evaluate(conversationId,tokenBudget);const targetTokens=params.compactionTarget==="threshold"?decision.threshold:tokenBudget;const liveContextStillExceedsTarget=observedTokens!==void 0&&observedTokens>=targetTokens;if(!forceCompaction&&!decision.shouldCompact){return{ok:true,compacted:false,reason:"below threshold",result:{tokensBefore:decision.currentTokens}}}const useSweep=manualCompactionRequested||params.compactionTarget==="threshold";if(useSweep){const sweepResult=await this.compaction.compact({conversationId,tokenBudget,summarize,force:forceCompaction,hardTrigger:false,summaryModel});if(sweepResult.authFailure&&breakerKey){this.recordCompactionAuthFailure(breakerKey)}else if(sweepResult.actionTaken&&breakerKey){this.recordCompactionSuccess(breakerKey)}if(sweepResult.actionTaken){await this.markLeafCompactionTelemetrySuccess({conversationId})}return{ok:!sweepResult.authFailure&&(sweepResult.actionTaken||!liveContextStillExceedsTarget),compacted:sweepResult.actionTaken,reason:sweepResult.authFailure?sweepResult.actionTaken?"provider auth failure after partial compaction":"provider auth failure":sweepResult.actionTaken?"compacted":manualCompactionRequested?"nothing to compact":liveContextStillExceedsTarget?"live context still exceeds target":"already under target",result:{tokensBefore:decision.currentTokens,tokensAfter:sweepResult.tokensAfter,details:{rounds:sweepResult.actionTaken?1:0,targetTokens}}}}const convergenceTargetTokens=forceCompaction?tokenBudget:params.compactionTarget==="threshold"?decision.threshold:tokenBudget;const effectiveCurrentTokens=observedTokens!==void 0?observedTokens:forceCompaction?tokenBudget:void 0;const compactResult=await this.compaction.compactUntilUnder({conversationId,tokenBudget,targetTokens:convergenceTargetTokens,...effectiveCurrentTokens!==void 0?{currentTokens:effectiveCurrentTokens}:{},summarize,summaryModel});if(compactResult.authFailure&&breakerKey){this.recordCompactionAuthFailure(breakerKey)}else if(compactResult.rounds>0&&breakerKey){this.recordCompactionSuccess(breakerKey)}const didCompact=compactResult.rounds>0;if(didCompact){await this.markLeafCompactionTelemetrySuccess({conversationId})}return{ok:compactResult.success,compacted:didCompact,reason:compactResult.authFailure?didCompact?"provider auth failure after partial compaction":"provider auth failure":compactResult.success?didCompact?"compacted":"already under target":"could not reach target",result:{tokensBefore:decision.currentTokens,tokensAfter:compactResult.finalTokens,details:{rounds:compactResult.rounds,targetTokens:convergenceTargetTokens}}}}async resolveConversationIdForSessionKey(sessionKey){const trimmedKey=sessionKey.trim();if(!trimmedKey){return void 0}try{const bySessionKey=await this.conversationStore.getConversationForSession({sessionKey:trimmedKey});if(bySessionKey){return bySessionKey.conversationId}const runtimeSessionId=await this.deps.resolveSessionIdFromSessionKey(trimmedKey);if(!runtimeSessionId){return void 0}const conversation=await this.conversationStore.getConversationForSession({sessionId:runtimeSessionId});return conversation?.conversationId}catch{return void 0}}formatSessionLogContext(params){const parts=[`conversation=${params.conversationId}`,`session=${params.sessionId}`];const trimmedSessionKey=params.sessionKey?.trim();if(trimmedSessionKey){parts.push(`sessionKey=${trimmedSessionKey}`)}return parts.join(" ")}async resolveSummarize(params){const lp=params.legacyParams??{};if(typeof lp.summarize==="function"){return{summarize:lp.summarize,summaryModel:"unknown",breakerKey:`custom:${params.breakerScope}`}}try{const customInstructions=params.customInstructions!==void 0?params.customInstructions:this.config.customInstructions||void 0;const runtimeSummarizer=await createLcmSummarizeFromLegacyParams({deps:this.deps,legacyParams:lp,customInstructions});if(runtimeSummarizer){return{summarize:runtimeSummarizer.fn,summaryModel:runtimeSummarizer.model,breakerKey:runtimeSummarizer.breakerKey}}this.deps.log.error(`[lcm] resolveSummarize: createLcmSummarizeFromLegacyParams returned undefined`)}catch(err){this.deps.log.error(`[lcm] resolveSummarize failed, using emergency fallback: ${describeLogError(err)}`)}this.deps.log.error(`[lcm] resolveSummarize: FALLING BACK TO EMERGENCY TRUNCATION`);return{summarize:createEmergencyFallbackSummarize(),summaryModel:"unknown"}}async resolveLargeFileTextSummarizer(){if(this.largeFileTextSummarizerResolved){return this.largeFileTextSummarizer}this.largeFileTextSummarizerResolved=true;const provider=this.deps.config.largeFileSummaryProvider;const model=this.deps.config.largeFileSummaryModel;if(!provider||!model){return void 0}try{const result=await createLcmSummarizeFromLegacyParams({deps:this.deps,legacyParams:{provider,model},customInstructions:this.config.customInstructions||void 0});if(!result){return void 0}this.largeFileTextSummarizer=async prompt=>{let summary;try{summary=await result.fn(prompt,false)}catch(err){if(err instanceof LcmProviderAuthError){return null}throw err}if(typeof summary!=="string"){return null}const trimmed=summary.trim();return trimmed.length>0?trimmed:null};return this.largeFileTextSummarizer}catch{return void 0}}static BASE64_IMAGE_MAGIC=[{prefix:"/9j/",extension:"jpg",mimeType:"image/jpeg"},{prefix:"iVBOR",extension:"png",mimeType:"image/png"},{prefix:"R0lGOD",extension:"gif",mimeType:"image/gif"},{prefix:"UklGR",extension:"webp",mimeType:"image/webp"},{prefix:"PHN2Zy",extension:"svg",mimeType:"image/svg+xml"}];static detectBase64ImageType(base64Data){for(const sig of _LcmContextEngine.BASE64_IMAGE_MAGIC){if(base64Data.startsWith(sig.prefix)){return{extension:sig.extension,mimeType:sig.mimeType}}}return null}static isExternalizedImageReference(value){return/^\[(?:User|Tool|Assistant|Image) image: .*LCM file: file_[a-f0-9]{16}\]$/.test(value.trim())}largeFilesDirForConversation(conversationId){return join3(this.config.largeFilesDir,String(conversationId))}async storeImageFileContent(params){const dir=this.largeFilesDirForConversation(params.conversationId);await mkdir(dir,{recursive:true});const normalized=params.extension.replace(/[^a-z0-9]/gi,"").toLowerCase()||"bin";const filePath=join3(dir,`${params.fileId}.${normalized}`);const buffer=Buffer.from(params.base64Data,"base64");await writeFile(filePath,buffer);return filePath}async externalizeImage(params){const fileId=`file_${randomUUID2().replace(/-/g,"").slice(0,16)}`;const byteSize=Buffer.from(params.base64Data,"base64").byteLength;const storageUri=await this.storeImageFileContent({conversationId:params.conversationId,fileId,extension:params.extension,base64Data:params.base64Data});const fileName=params.fileName??`image.${params.extension}`;const summary=`Image file (${params.extension.toUpperCase()}, ${byteSize.toLocaleString("en-US")} bytes)${params.fileName?` \u2014 ${params.fileName}`:""}`;await this.summaryStore.insertLargeFile({fileId,conversationId:params.conversationId,fileName,mimeType:params.mimeType,byteSize,storageUri,explorationSummary:summary});const reference=`[${params.label}: ${fileName} (${params.mimeType}, ${byteSize.toLocaleString("en-US")} bytes) | LCM file: ${fileId}]`;return{fileId,byteSize,summary,reference}}async interceptInlineImages(params){const mediaResult=await this.interceptUserMediaBase64(params);if(mediaResult){return mediaResult}return this.interceptPureBase64Image(params)}async interceptUserMediaBase64(params){const prefix="[media attached:";if(!params.content.startsWith(prefix)){return null}const base64LineRe=/\n([A-Za-z0-9+/]{20,}={0,2})\n/m;const base64Match=base64LineRe.exec(params.content);if(!base64Match){return null}const headerEnd=base64Match.index+1;const header=params.content.slice(0,headerEnd).trim();const base64Data=params.content.slice(headerEnd);if(estimateTokens(base64Data)<100){return null}const detected=_LcmContextEngine.detectBase64ImageType(base64Data);if(!detected){return null}const pathMatch=header.match(/\[media attached:\s*([^\s(]+)/);const fileName=pathMatch?pathMatch[1]:`user-image.${detected.extension}`;const externalized=await this.externalizeImage({conversationId:params.conversationId,base64Data,fileName,extension:detected.extension,mimeType:detected.mimeType,label:"User image"});return{rewrittenContent:`${header}
|
|
741
744
|
|
|
742
|
-
${externalized.reference}`,fileIds:[externalized.fileId]}}async interceptPureBase64Image(params){const trimmed=params.content.trim();if(estimateTokens(trimmed)<100){return null}const detected=_LcmContextEngine.detectBase64ImageType(trimmed);if(!detected){return null}const b64Chars=trimmed.replace(/[^A-Za-z0-9+/=\s]/g,"");if(b64Chars.length/trimmed.length<.8){return null}const label=params.role==="tool"?"Tool image":params.role==="assistant"?"Assistant image":"Image";const fileName=`${params.role}-image.${detected.extension}`;const externalized=await this.externalizeImage({conversationId:params.conversationId,base64Data:trimmed,fileName,extension:detected.extension,mimeType:detected.mimeType,label});return{rewrittenContent:externalized.reference,fileIds:[externalized.fileId]}}async rewriteToolInlineImageValue(params){if(typeof params.value==="string"){const intercepted=await this.interceptPureBase64Image({conversationId:params.conversationId,content:params.value,role:"tool"});if(!intercepted){return{rewrittenValue:params.value,fileIds:[],changed:false}}return{rewrittenValue:intercepted.rewrittenContent,fileIds:intercepted.fileIds,changed:true}}if(Array.isArray(params.value)){const rewrittenValues=[];const fileIds2=[];let changed2=false;for(const entry of params.value){const rewritten=await this.rewriteToolInlineImageValue({conversationId:params.conversationId,value:entry});rewrittenValues.push(rewritten.rewrittenValue);fileIds2.push(...rewritten.fileIds);changed2||=rewritten.changed}return changed2?{rewrittenValue:rewrittenValues,fileIds:fileIds2,changed:true}:{rewrittenValue:params.value,fileIds:[],changed:false}}if(!params.value||typeof params.value!=="object"){return{rewrittenValue:params.value,fileIds:[],changed:false}}const record=params.value;if(record.type==="text"&&typeof record.text==="string"){const intercepted=await this.interceptPureBase64Image({conversationId:params.conversationId,content:record.text,role:"tool"});if(!intercepted){return{rewrittenValue:params.value,fileIds:[],changed:false}}return{rewrittenValue:{...record,text:intercepted.rewrittenContent},fileIds:intercepted.fileIds,changed:true}}const nestedKeys=["output","content","result"];const rewrittenRecord={...record};const fileIds=[];let changed=false;for(const key of nestedKeys){if(!(key in record)){continue}const rewritten=await this.rewriteToolInlineImageValue({conversationId:params.conversationId,value:record[key]});if(!rewritten.changed){continue}rewrittenRecord[key]=rewritten.rewrittenValue;fileIds.push(...rewritten.fileIds);changed=true}return changed?{rewrittenValue:rewrittenRecord,fileIds,changed:true}:{rewrittenValue:params.value,fileIds:[],changed:false}}async interceptInlineImagesInToolMessage(params){if(params.message.role!=="toolResult"&¶ms.message.role!=="tool"||!("content"in params.message)){return null}if(typeof params.message.content==="string"){const intercepted=await this.interceptPureBase64Image({conversationId:params.conversationId,content:params.message.content,role:"tool"});if(!intercepted){return null}return{rewrittenMessage:{...params.message,content:intercepted.rewrittenContent},fileIds:intercepted.fileIds}}if(!Array.isArray(params.message.content)){return null}const rewrittenContent=[];const fileIds=[];let changed=false;for(const item of params.message.content){const rewritten=await this.rewriteToolInlineImageValue({conversationId:params.conversationId,value:item});rewrittenContent.push(rewritten.rewrittenValue);fileIds.push(...rewritten.fileIds);changed||=rewritten.changed}if(!changed){return null}return{rewrittenMessage:{...params.message,content:rewrittenContent},fileIds}}async storeLargeFileContent(params){const dir=this.largeFilesDirForConversation(params.conversationId);await mkdir(dir,{recursive:true});const normalizedExtension=params.extension.replace(/[^a-z0-9]/gi,"").toLowerCase()||"txt";const filePath=join3(dir,`${params.fileId}.${normalizedExtension}`);await writeFile(filePath,params.content,"utf8");return filePath}async externalizeLargeTextPayload(params){const summarizeText=await this.resolveLargeFileTextSummarizer();const fileId=`file_${randomUUID2().replace(/-/g,"").slice(0,16)}`;const extension=extensionFromNameOrMime(params.fileName,params.mimeType);const storageUri=await this.storeLargeFileContent({conversationId:params.conversationId,fileId,extension,content:params.content});const byteSize=Buffer.byteLength(params.content,"utf8");const explorationSummary=await generateExplorationSummary({content:params.content,fileName:params.fileName,mimeType:params.mimeType,summarizeText});await this.summaryStore.insertLargeFile({fileId,conversationId:params.conversationId,fileName:params.fileName,mimeType:params.mimeType,byteSize,storageUri,explorationSummary});return{fileId,byteSize,summary:explorationSummary,reference:params.formatReference({fileId,byteSize,summary:explorationSummary})}}async interceptLargeFiles(params){const blocks=parseFileBlocks(params.content);if(blocks.length===0){return null}const threshold=Math.max(1,this.config.largeFileTokenThreshold);const fileIds=[];const rewrittenSegments=[];let cursor=0;let interceptedAny=false;for(const block of blocks){const blockTokens=estimateTokens(block.text);if(blockTokens<threshold){continue}interceptedAny=true;const externalized=await this.externalizeLargeTextPayload({conversationId:params.conversationId,content:block.text,fileName:block.fileName,mimeType:block.mimeType,formatReference:({fileId,byteSize,summary})=>formatFileReference({fileId,fileName:block.fileName,mimeType:block.mimeType,byteSize,summary})});rewrittenSegments.push(params.content.slice(cursor,block.start));rewrittenSegments.push(externalized.reference);cursor=block.end;fileIds.push(externalized.fileId)}if(!interceptedAny){return null}rewrittenSegments.push(params.content.slice(cursor));return{rewrittenContent:rewrittenSegments.join(""),fileIds}}async interceptLargeToolResults(params){if(params.message.role!=="toolResult"&¶ms.message.role!=="tool"||!("content"in params.message)){return null}if(typeof params.message.content==="string"){params={...params,message:{...params.message,content:[{type:"text",text:params.message.content}]}}}if(!Array.isArray(params.message.content)){return null}const threshold=Math.max(1,this.config.largeFileTokenThreshold);const rewrittenContent=[];const fileIds=[];let interceptedAny=false;const topLevel=params.message;const topLevelToolCallId=safeString(topLevel.toolCallId)??safeString(topLevel.tool_call_id)??safeString(topLevel.toolUseId)??safeString(topLevel.tool_use_id)??safeString(topLevel.call_id)??safeString(topLevel.id);const topLevelToolName=safeString(topLevel.toolName)??safeString(topLevel.tool_name);const topLevelIsError=safeBoolean(topLevel.isError)??safeBoolean(topLevel.is_error);for(const item of params.message.content){if(!item||typeof item!=="object"||Array.isArray(item)){rewrittenContent.push(item);continue}const record=item;const rawType=safeString(record.type);const isStructuredToolResult=rawType!=="tool_result"&&rawType!=="toolResult"&&rawType!=="function_call_output";const isPlainTextToolResult=rawType==="text"&&typeof record.text==="string";if(isStructuredToolResult&&!isPlainTextToolResult){rewrittenContent.push(item);continue}const textSource=isPlainTextToolResult?record.text:record.output!==void 0?record.output:record.content!==void 0?record.content:record;const extractedText=extractStructuredText(textSource);if(typeof extractedText==="string"&&_LcmContextEngine.isExternalizedImageReference(extractedText)){rewrittenContent.push(item);continue}if(typeof extractedText!=="string"||estimateTokens(extractedText)<threshold){rewrittenContent.push(item);continue}interceptedAny=true;const toolName=safeString(record.name)??topLevelToolName??"tool-result";const externalized=await this.externalizeLargeTextPayload({conversationId:params.conversationId,content:extractedText,fileName:`${toolName}.txt`,mimeType:"text/plain",formatReference:({fileId,byteSize,summary})=>formatToolOutputReference({fileId,toolName,byteSize,summary})});const normalizedRawType=rawType==="function_call_output"?"function_call_output":"tool_result";const compactBlock=isPlainTextToolResult?{type:"text",text:externalized.reference,rawType:normalizedRawType,externalizedFileId:externalized.fileId,originalByteSize:externalized.byteSize,toolOutputExternalized:true,externalizationReason:"large_tool_result"}:{type:normalizedRawType,output:externalized.reference,externalizedFileId:externalized.fileId,originalByteSize:externalized.byteSize,toolOutputExternalized:true,externalizationReason:"large_tool_result"};const callId=safeString(record.tool_use_id)??safeString(record.toolUseId)??safeString(record.tool_call_id)??safeString(record.toolCallId)??safeString(record.call_id)??safeString(record.id)??topLevelToolCallId;if(callId){if(normalizedRawType==="function_call_output"){compactBlock.call_id=callId}else{compactBlock.tool_use_id=callId}}if(typeof record.is_error==="boolean"){compactBlock.is_error=record.is_error}else if(typeof record.isError==="boolean"){compactBlock.isError=record.isError}else if(typeof topLevelIsError==="boolean"){compactBlock.isError=topLevelIsError}if(toolName){compactBlock.name=toolName}rewrittenContent.push(compactBlock);fileIds.push(externalized.fileId)}if(!interceptedAny){return null}return{rewrittenMessage:{...params.message,content:rewrittenContent},fileIds}}async reconcileSessionTail(params){const{sessionId,conversationId,historicalMessages}=params;const startedAt=Date.now();const sessionContext=this.formatSessionLogContext({conversationId,sessionId,sessionKey:params.sessionKey});if(historicalMessages.length===0){this.deps.log.info(`[lcm] reconcileSessionTail: skipped for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=0 reason=empty-history`);return{blockedByImportCap:false,importedMessages:0,hasOverlap:false}}const latestDbMessage=await this.conversationStore.getLastMessage(conversationId);if(!latestDbMessage){this.deps.log.info(`[lcm] reconcileSessionTail: skipped for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} reason=no-db-tail`);return{blockedByImportCap:false,importedMessages:0,hasOverlap:false}}const storedHistoricalMessages=historicalMessages.map(message=>toStoredMessage(message));const latestHistorical=storedHistoricalMessages[storedHistoricalMessages.length-1];const latestIdentity=messageIdentity(latestDbMessage.role,latestDbMessage.content);if(latestIdentity===messageIdentity(latestHistorical.role,latestHistorical.content)){const dbOccurrences=await this.conversationStore.countMessagesByIdentity(conversationId,latestDbMessage.role,latestDbMessage.content);let historicalOccurrences=0;for(const stored of storedHistoricalMessages){if(messageIdentity(stored.role,stored.content)===latestIdentity){historicalOccurrences+=1}}if(dbOccurrences===historicalOccurrences){this.deps.log.info(`[lcm] reconcileSessionTail: fast path for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} importedMessages=0 overlap=true`);return{blockedByImportCap:false,importedMessages:0,hasOverlap:true}}}let anchorIndex=-1;const historicalIdentityTotals=new Map;for(const stored of storedHistoricalMessages){const identity=messageIdentity(stored.role,stored.content);historicalIdentityTotals.set(identity,(historicalIdentityTotals.get(identity)??0)+1)}const historicalIdentityCountsAfterIndex=new Map;const dbIdentityCounts=new Map;for(let index=storedHistoricalMessages.length-1;index>=0;index--){const stored=storedHistoricalMessages[index];const identity=messageIdentity(stored.role,stored.content);const seenAfter=historicalIdentityCountsAfterIndex.get(identity)??0;const total=historicalIdentityTotals.get(identity)??0;const occurrencesThroughIndex=total-seenAfter;const exists=await this.conversationStore.hasMessage(conversationId,stored.role,stored.content);historicalIdentityCountsAfterIndex.set(identity,seenAfter+1);if(!exists){continue}let dbCountForIdentity=dbIdentityCounts.get(identity);if(dbCountForIdentity===void 0){dbCountForIdentity=await this.conversationStore.countMessagesByIdentity(conversationId,stored.role,stored.content);dbIdentityCounts.set(identity,dbCountForIdentity)}if(dbCountForIdentity!==occurrencesThroughIndex){continue}anchorIndex=index;break}if(anchorIndex<0){this.deps.log.info(`[lcm] reconcileSessionTail: no anchor for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} importedMessages=0 overlap=false`);return{blockedByImportCap:false,importedMessages:0,hasOverlap:false}}if(anchorIndex>=historicalMessages.length-1){this.deps.log.info(`[lcm] reconcileSessionTail: anchor at tip for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} importedMessages=0 overlap=true`);return{blockedByImportCap:false,importedMessages:0,hasOverlap:true}}const missingTail=historicalMessages.slice(anchorIndex+1);const existingDbCount=await this.conversationStore.getMessageCount(conversationId);if(existingDbCount>0&&missingTail.length>Math.max(existingDbCount*.2,50)){this.deps.log.warn(`[lcm] reconcileSessionTail: import cap exceeded for ${sessionContext} \u2014 would import ${missingTail.length} messages (existing: ${existingDbCount}). Aborting to prevent flood.`);this.deps.log.info(`[lcm] reconcileSessionTail: blocked for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} missingTail=${missingTail.length} existingDbCount=${existingDbCount}`);return{blockedByImportCap:true,importedMessages:0,hasOverlap:true}}let importedMessages=0;for(const message of missingTail){const result=await this.ingestSingle({sessionId,sessionKey:params.sessionKey,message});if(result.ingested){importedMessages+=1}}this.deps.log.info(`[lcm] reconcileSessionTail: slow path for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} anchorIndex=${anchorIndex} missingTail=${missingTail.length} importedMessages=${importedMessages}`);return{blockedByImportCap:false,importedMessages,hasOverlap:true}}async refreshBootstrapState(params){const latestDbMessage=await this.conversationStore.getLastMessage(params.conversationId);const fileStats=params.fileStats??await stat(params.sessionFile);await this.summaryStore.upsertConversationBootstrapState({conversationId:params.conversationId,sessionFilePath:params.sessionFile,lastSeenSize:fileStats.size,lastSeenMtimeMs:Math.trunc(fileStats.mtimeMs),lastProcessedOffset:fileStats.size,lastProcessedEntryHash:latestDbMessage?createBootstrapEntryHash({role:latestDbMessage.role,content:latestDbMessage.content,tokenCount:latestDbMessage.tokenCount}):null})}async bootstrap(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{bootstrapped:false,importedMessages:0,reason:"session excluded by pattern"}}if(this.isStatelessSession(params.sessionKey)){return{bootstrapped:false,importedMessages:0,reason:"stateless session"}}this.ensureMigrated();const startedAt=Date.now();const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");const sessionFileStats=await stat(params.sessionFile);const sessionFileSize=sessionFileStats.size;const sessionFileMtimeMs=Math.trunc(sessionFileStats.mtimeMs);const result=await this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>this.conversationStore.withTransaction(async()=>{const persistBootstrapState=async conversationId2=>{await this.refreshBootstrapState({conversationId:conversationId2,sessionFile:params.sessionFile,fileStats:{size:sessionFileSize,mtimeMs:sessionFileMtimeMs}})};const conversation=await this.conversationStore.getOrCreateConversation(params.sessionId,{sessionKey:params.sessionKey});const conversationId=conversation.conversationId;let existingCount=await this.conversationStore.getMessageCount(conversationId);let bootstrapState=await this.summaryStore.getConversationBootstrapState(conversationId);if(bootstrapState&&bootstrapState.sessionFilePath!==params.sessionFile){this.deps.log.warn(`[lcm] bootstrap: session file rotated conversation=${conversationId} ${sessionLabel} oldFile=${bootstrapState.sessionFilePath} newFile=${params.sessionFile}`);bootstrapState=null}if(bootstrapState&&bootstrapState.sessionFilePath===params.sessionFile&&bootstrapState.lastSeenSize===sessionFileSize&&bootstrapState.lastSeenMtimeMs===sessionFileMtimeMs){if(!conversation.bootstrappedAt){await this.conversationStore.markConversationBootstrapped(conversationId)}this.deps.log.info(`[lcm] bootstrap: checkpoint hit conversation=${conversationId} ${sessionLabel} existingCount=${existingCount} duration=${formatDurationMs(Date.now()-startedAt)}`);return{bootstrapped:false,importedMessages:0,reason:conversation.bootstrappedAt?"already bootstrapped":"conversation already up to date"}}if(bootstrapState&&bootstrapState.sessionFilePath===params.sessionFile&&sessionFileSize>bootstrapState.lastSeenSize&&sessionFileMtimeMs>=bootstrapState.lastSeenMtimeMs){const latestDbMessage=await this.conversationStore.getLastMessage(conversationId);const latestDbHash=latestDbMessage?createBootstrapEntryHash({role:latestDbMessage.role,content:latestDbMessage.content,tokenCount:latestDbMessage.tokenCount}):null;const frontierHash=latestDbHash??bootstrapState.lastProcessedEntryHash;const canTryAppendOnlyFastPath=frontierHash!==null&&frontierHash===bootstrapState.lastProcessedEntryHash;const tailEntryRaw=canTryAppendOnlyFastPath?await readLastJsonlEntryBeforeOffset(params.sessionFile,bootstrapState.lastProcessedOffset,true,message=>createBootstrapEntryHash(toStoredMessage(message))===frontierHash):null;const tailEntryMessage=readBootstrapMessageFromJsonLine(tailEntryRaw);const tailEntryHash=tailEntryMessage?createBootstrapEntryHash(toStoredMessage(tailEntryMessage)):null;if(canTryAppendOnlyFastPath&&tailEntryHash&&tailEntryHash===bootstrapState.lastProcessedEntryHash){const appended=await readAppendedLeafPathMessages({sessionFile:params.sessionFile,offset:bootstrapState.lastProcessedOffset});if(appended.canUseAppendOnly){if(!conversation.bootstrappedAt){await this.conversationStore.markConversationBootstrapped(conversationId)}let importedMessages=0;for(const message of appended.messages){const ingestResult=await this.ingestSingle({sessionId:params.sessionId,sessionKey:params.sessionKey,message});if(ingestResult.ingested){importedMessages+=1}}await persistBootstrapState(conversationId);this.deps.log.info(`[lcm] bootstrap: append-only conversation=${conversationId} ${sessionLabel} existingCount=${existingCount} appendedMessages=${appended.messages.length} importedMessages=${importedMessages} duration=${formatDurationMs(Date.now()-startedAt)}`);if(importedMessages>0){return{bootstrapped:true,importedMessages,reason:"reconciled missing session messages"}}return{bootstrapped:false,importedMessages:0,reason:conversation.bootstrappedAt?"already bootstrapped":"conversation already up to date"}}}}const historicalMessages=await readLeafPathMessages(params.sessionFile);this.deps.log.info(`[lcm] bootstrap: full transcript read conversation=${conversationId} ${sessionLabel} existingCount=${existingCount} historicalMessages=${historicalMessages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);if(existingCount===0){const bootstrapMessages=trimBootstrapMessagesToBudget(historicalMessages,resolveBootstrapMaxTokens(this.config));if(bootstrapMessages.length===0){await this.conversationStore.markConversationBootstrapped(conversationId);await persistBootstrapState(conversationId);return{bootstrapped:false,importedMessages:0,reason:"no leaf-path messages in session"}}const nextSeq=await this.conversationStore.getMaxSeq(conversationId)+1;const bulkInput=bootstrapMessages.map((message,index)=>{const stored=toStoredMessage(message);return{conversationId,seq:nextSeq+index,role:stored.role,content:stored.content,tokenCount:stored.tokenCount}});const inserted=await this.conversationStore.createMessagesBulk(bulkInput);await this.summaryStore.appendContextMessages(conversationId,inserted.map(record=>record.messageId));await this.conversationStore.markConversationBootstrapped(conversationId);if(this.config.pruneHeartbeatOk){const pruned=await this.pruneHeartbeatOkTurns(conversationId);if(pruned>0){this.deps.log.info(`[lcm] bootstrap: pruned ${pruned} HEARTBEAT_OK messages from conversation ${conversationId}`)}}await persistBootstrapState(conversationId);this.deps.log.info(`[lcm] bootstrap: initial import conversation=${conversationId} ${sessionLabel} importedMessages=${inserted.length} sourceMessages=${historicalMessages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return{bootstrapped:true,importedMessages:inserted.length}}const reconcile=await this.reconcileSessionTail({sessionId:params.sessionId,sessionKey:params.sessionKey,conversationId,historicalMessages});this.deps.log.info(`[lcm] bootstrap: reconcile finished conversation=${conversationId} ${sessionLabel} importedMessages=${reconcile.importedMessages} overlap=${reconcile.hasOverlap} blockedByImportCap=${reconcile.blockedByImportCap} duration=${formatDurationMs(Date.now()-startedAt)}`);if(reconcile.blockedByImportCap){return{bootstrapped:false,importedMessages:0,reason:"reconcile import capped"}}if(!conversation.bootstrappedAt){await this.conversationStore.markConversationBootstrapped(conversationId)}if(reconcile.importedMessages>0){await persistBootstrapState(conversationId);return{bootstrapped:true,importedMessages:reconcile.importedMessages,reason:"reconciled missing session messages"}}if(reconcile.hasOverlap){await persistBootstrapState(conversationId)}if(conversation.bootstrappedAt){return{bootstrapped:false,importedMessages:0,reason:"already bootstrapped"}}return{bootstrapped:false,importedMessages:0,reason:reconcile.hasOverlap?"conversation already up to date":"conversation already has messages"}}),{operationName:"bootstrap",context:sessionLabel});if(this.config.pruneHeartbeatOk&&result.bootstrapped===false){try{const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(conversation){const pruned=await this.pruneHeartbeatOkTurns(conversation.conversationId);if(pruned>0){await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile});this.deps.log.info(`[lcm] bootstrap: retroactively pruned ${pruned} HEARTBEAT_OK messages from conversation ${conversation.conversationId}`)}}}catch(err){this.deps.log.warn(`[lcm] bootstrap: heartbeat pruning failed: ${describeLogError(err)}`)}}this.deps.log.info(`[lcm] bootstrap: done ${sessionLabel} bootstrapped=${result.bootstrapped} importedMessages=${result.importedMessages} reason=${result.reason??"none"} duration=${formatDurationMs(Date.now()-startedAt)}`);return result}async deduplicateAfterTurnBatch(sessionId,sessionKey,batch){if(batch.length===0)return batch;const conversation=await this.conversationStore.getConversationForSession({sessionId,sessionKey});if(!conversation)return batch;const conversationId=conversation.conversationId;const storedMessageCount=await this.conversationStore.getMessageCount(conversationId);if(storedMessageCount===0||storedMessageCount>batch.length){return batch}const lastDbMessage=await this.conversationStore.getLastMessage(conversationId);if(!lastDbMessage)return batch;const storedBatch=batch.map(m=>toStoredMessage(m));const batchAtBoundary=storedBatch[storedMessageCount-1];if(messageIdentity(lastDbMessage.role,lastDbMessage.content)!==messageIdentity(batchAtBoundary.role,batchAtBoundary.content)){return batch}const storedMessages=await this.conversationStore.getMessages(conversationId,{limit:storedMessageCount});if(storedMessages.length!==storedMessageCount){return batch}for(let i=0;i<storedMessageCount;i+=1){const storedConversationMessage=storedMessages[i];const incomingMessage=storedBatch[i];if(messageIdentity(storedConversationMessage.role,storedConversationMessage.content)!==messageIdentity(incomingMessage.role,incomingMessage.content)){return batch}}return batch.slice(storedMessageCount)}async buildTranscriptGcReplacementMessage(messageId){const message=await this.conversationStore.getMessageById(messageId);if(!message){return null}const parts=await this.conversationStore.getMessageParts(messageId);const toolCallId=pickToolCallId(parts);if(!toolCallId){return null}const content=contentFromParts(parts,"toolResult",message.content);const toolName=pickToolName(parts)??"unknown";const isError=pickToolIsError(parts);return{role:"toolResult",toolCallId,toolName,content,...isError!==void 0?{isError}:{}}}async maintain(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"session excluded by pattern"}}if(this.isStatelessSession(params.sessionKey)){return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"stateless session"}}const startedAt=Date.now();const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");return this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"conversation not found"}}let deferredCompactionResult=null;const maintenance=await this.compactionMaintenanceStore.getConversationCompactionMaintenance(conversation.conversationId);const telemetry=await this.compactionTelemetryStore.getConversationCompactionTelemetry(conversation.conversationId);if(params.runtimeContext?.allowDeferredCompactionExecution===true){const runtimeTokenBudget=(()=>{const tokenBudget=asRecord(params.runtimeContext)?.tokenBudget;if(typeof tokenBudget==="number"&&Number.isFinite(tokenBudget)&&tokenBudget>0){return Math.floor(tokenBudget)}return 128e3})();if((maintenance?.pending||maintenance?.running)&&this.shouldDelayPromptMutatingDeferredCompaction(telemetry)){this.deps.log.info(`[lcm] maintain: deferred compaction debt still hot-cache deferred conversation=${conversation.conversationId} ${sessionLabel} retention=${telemetry?.retention??"null"} lastCacheTouchAt=${telemetry?.lastCacheTouchAt?.toISOString()??"null"}`)}else{deferredCompactionResult=await this.consumeDeferredCompactionDebt({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:this.applyAssemblyBudgetCap(runtimeTokenBudget),currentTokenCount:typeof params.runtimeContext?.currentTokenCount==="number"?Math.floor(params.runtimeContext.currentTokenCount):void 0,runtimeContext:params.runtimeContext,legacyParams:asRecord(params.runtimeContext)})}}else if(maintenance?.pending||maintenance?.running){this.deps.log.info(`[lcm] maintain: deferred compaction debt pending conversation=${conversation.conversationId} ${sessionLabel} but host runtimeContext.allowDeferredCompactionExecution is disabled`)}if(!this.config.transcriptGcEnabled){return deferredCompactionResult??{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"transcript GC disabled"}}if(typeof params.runtimeContext?.rewriteTranscriptEntries!=="function"){return deferredCompactionResult??{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"runtime rewrite helper unavailable"}}const rewriteTranscriptEntries=params.runtimeContext.rewriteTranscriptEntries;const candidates=await this.summaryStore.listTranscriptGcCandidates(conversation.conversationId,{limit:TRANSCRIPT_GC_BATCH_SIZE});if(candidates.length===0){this.deps.log.info(`[lcm] maintain: no transcript GC candidates conversation=${conversation.conversationId} ${sessionLabel} duration=${formatDurationMs(Date.now()-startedAt)}`);return deferredCompactionResult??{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"no transcript GC candidates"}}const transcriptEntryIdsByCallId=listTranscriptToolResultEntryIdsByCallId(params.sessionFile);const replacements=[];const seenEntryIds=new Set;for(const candidate of candidates){const entryId=transcriptEntryIdsByCallId.get(candidate.toolCallId);if(!entryId||seenEntryIds.has(entryId)){continue}const replacementMessage=await this.buildTranscriptGcReplacementMessage(candidate.messageId);if(!replacementMessage){continue}seenEntryIds.add(entryId);replacements.push({entryId,message:replacementMessage})}if(replacements.length===0){this.deps.log.info(`[lcm] maintain: no matching transcript entries conversation=${conversation.conversationId} ${sessionLabel} candidates=${candidates.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return deferredCompactionResult??{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"no matching transcript entries"}}const result=await rewriteTranscriptEntries({replacements});if(result.changed){try{await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile})}catch(e){this.deps.log.warn(`[lcm] Failed to update bootstrap checkpoint after maintain: ${describeLogError(e)}`)}}const combinedResult=deferredCompactionResult?{changed:deferredCompactionResult.changed||result.changed,bytesFreed:result.bytesFreed,rewrittenEntries:result.rewrittenEntries,reason:result.reason??deferredCompactionResult.reason}:result;this.deps.log.info(`[lcm] maintain: done conversation=${conversation.conversationId} ${sessionLabel} candidates=${candidates.length} replacements=${replacements.length} changed=${combinedResult.changed} rewrittenEntries=${combinedResult.rewrittenEntries} bytesFreed=${combinedResult.bytesFreed} duration=${formatDurationMs(Date.now()-startedAt)}`);return combinedResult},{operationName:"maintain",context:sessionLabel})}async ingestSingle(params){const{sessionId,sessionKey,message,isHeartbeat}=params;if(isHeartbeat){return{ingested:false}}if(message.role==="assistant"){const topLevel=message;const stopReason=typeof topLevel.stopReason==="string"?topLevel.stopReason:typeof topLevel.stop_reason==="string"?topLevel.stop_reason:void 0;if(stopReason==="error"||stopReason==="aborted"){const content=topLevel.content;const isEmpty=content===void 0||content===null||content===""||Array.isArray(content)&&content.length===0;if(isEmpty){return{ingested:false}}}}let stored=toStoredMessage(message);const conversation=await this.conversationStore.getOrCreateConversation(sessionId,{sessionKey});const conversationId=conversation.conversationId;let messageForParts=message;if(stored.role==="tool"){const imageIntercepted=await this.interceptInlineImagesInToolMessage({conversationId,message:messageForParts});if(imageIntercepted){messageForParts=imageIntercepted.rewrittenMessage;stored=toStoredMessage(messageForParts)}}else{const imageIntercepted=await this.interceptInlineImages({conversationId,content:stored.content,role:stored.role});if(imageIntercepted){stored.content=imageIntercepted.rewrittenContent;stored.tokenCount=estimateTokens(stored.content);if("content"in message){messageForParts={...message,content:stored.content}}}}if(stored.role==="user"){const intercepted=await this.interceptLargeFiles({conversationId,content:stored.content});if(intercepted){stored.content=intercepted.rewrittenContent;stored.tokenCount=estimateTokens(stored.content);if("content"in message){messageForParts={...message,content:stored.content}}}}else if(stored.role==="tool"){const intercepted=await this.interceptLargeToolResults({conversationId,message:messageForParts});if(intercepted){messageForParts=intercepted.rewrittenMessage;const rewrittenStored=toStoredMessage(intercepted.rewrittenMessage);stored.content=rewrittenStored.content;stored.tokenCount=rewrittenStored.tokenCount}}const maxSeq=await this.conversationStore.getMaxSeq(conversationId);const seq=maxSeq+1;const msgRecord=await this.conversationStore.createMessage({conversationId,seq,role:stored.role,content:stored.content,tokenCount:stored.tokenCount});await this.conversationStore.createMessageParts(msgRecord.messageId,buildMessageParts({sessionId,message:messageForParts,fallbackContent:stored.content}));await this.summaryStore.appendContextMessage(conversationId,msgRecord.messageId);return{ingested:true}}async ingest(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{ingested:false}}if(this.isStatelessSession(params.sessionKey)){return{ingested:false}}this.ensureMigrated();return this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),()=>this.ingestSingle(params),{operationName:"ingest",context:[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ")})}async ingestBatch(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{ingestedCount:0}}if(this.isStatelessSession(params.sessionKey)){return{ingestedCount:0}}this.ensureMigrated();if(params.messages.length===0){return{ingestedCount:0}}return this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{let ingestedCount=0;for(const message of params.messages){const result=await this.ingestSingle({sessionId:params.sessionId,sessionKey:params.sessionKey,message,isHeartbeat:params.isHeartbeat});if(result.ingested){ingestedCount+=1}}return{ingestedCount}},{operationName:"ingestBatch",context:[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[],`messages=${params.messages.length}`].join(" ")})}async runAfterTurnInlineLeafCompaction(params){try{await this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{const recordAfterTurnCompactionRetry=async()=>{try{await this.recordDeferredCompactionDebt({conversationId:params.conversationId,reason:params.leafDecision.reason,tokenBudget:params.tokenBudget,currentTokenCount:params.currentTokenCount})}catch(err){this.deps.log.warn(`[lcm] afterTurn: failed to persist deferred compaction retry for ${params.sessionLabel}: ${describeLogError(err)}`)}};try{const compactResult=await this.executeLeafCompactionCore({conversationId:params.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:params.tokenBudget,currentTokenCount:params.currentTokenCount,legacyParams:params.legacyParams,maxPasses:params.leafDecision.maxPasses,leafChunkTokens:params.leafDecision.leafChunkTokens,fallbackLeafChunkTokens:params.leafDecision.fallbackLeafChunkTokens,activityBand:params.leafDecision.activityBand,allowCondensedPasses:params.leafDecision.allowCondensedPasses});if(compactResult.ok){try{await this.refreshBootstrapState({conversationId:params.conversationId,sessionFile:params.sessionFile})}catch(err){this.deps.log.warn(`[lcm] afterTurn: bootstrap checkpoint refresh failed for ${params.sessionLabel}: ${describeLogError(err)}`)}return}await recordAfterTurnCompactionRetry()}catch(err){await recordAfterTurnCompactionRetry();this.deps.log.warn(`[lcm] afterTurn: inline leaf compaction failed for ${params.sessionLabel}: ${describeLogError(err)}`)}},{operationName:"afterTurnLeafCompaction",context:params.sessionLabel})}catch(err){this.deps.log.warn(`[lcm] afterTurn: failed to queue inline leaf compaction for ${params.sessionLabel}: ${describeLogError(err)}`)}}async afterTurn(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return}if(this.isStatelessSession(params.sessionKey)){return}this.ensureMigrated();const startedAt=Date.now();const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");const newMessages=params.messages.slice(params.prePromptMessageCount);const dedupedNewMessages=await this.deduplicateAfterTurnBatch(params.sessionId,params.sessionKey,newMessages);const ingestBatch=[];if(params.autoCompactionSummary){ingestBatch.push({role:"user",content:params.autoCompactionSummary})}ingestBatch.push(...dedupedNewMessages);if(ingestBatch.length===0){this.deps.log.info(`[lcm] afterTurn: nothing to ingest ${sessionLabel} newMessages=${newMessages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return}try{await this.ingestBatch({sessionId:params.sessionId,sessionKey:params.sessionKey,messages:ingestBatch,isHeartbeat:params.isHeartbeat===true})}catch(err){this.deps.log.error(`[lcm] afterTurn: ingest failed, skipping compaction: ${describeLogError(err)}`);return}if(batchLooksLikeHeartbeatAckTurn(ingestBatch)){try{const conversation2=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(conversation2){const pruned=await this.pruneHeartbeatOkTurns(conversation2.conversationId);if(pruned>0){const sessionContext=this.formatSessionLogContext({conversationId:conversation2.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey});try{await this.refreshBootstrapState({conversationId:conversation2.conversationId,sessionFile:params.sessionFile})}catch(err){this.deps.log.warn(`[lcm] afterTurn: heartbeat pruning checkpoint refresh failed for ${sessionContext}: ${describeLogError(err)}`)}this.deps.log.info(`[lcm] afterTurn: pruned ${pruned} heartbeat ack messages for ${sessionContext}`);return}}}catch(err){this.deps.log.warn(`[lcm] afterTurn: heartbeat pruning failed: ${describeLogError(err)}`)}}const legacyParams=asRecord(params.runtimeContext)??asRecord(params.legacyCompactionParams);const DEFAULT_AFTER_TURN_TOKEN_BUDGET=128e3;const resolvedTokenBudget=this.resolveTokenBudget({tokenBudget:params.tokenBudget,runtimeContext:params.runtimeContext,legacyParams});const tokenBudget=this.applyAssemblyBudgetCap(resolvedTokenBudget??DEFAULT_AFTER_TURN_TOKEN_BUDGET);if(resolvedTokenBudget===void 0){this.deps.log.warn(`[lcm] afterTurn: tokenBudget not provided; using default ${DEFAULT_AFTER_TURN_TOKEN_BUDGET}`)}const liveContextTokens=estimateSessionTokenCountForAfterTurn(params.messages);const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){this.deps.log.info(`[lcm] afterTurn: conversation lookup missed ${sessionLabel} ingestBatch=${ingestBatch.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return}const refreshAfterTurnBootstrapState=async()=>{try{await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile})}catch(err){this.deps.log.warn(`[lcm] afterTurn: bootstrap checkpoint refresh failed for ${sessionLabel}: ${describeLogError(err)}`)}};const recordAfterTurnCompactionRetry=async reason=>{try{await this.recordDeferredCompactionDebt({conversationId:conversation.conversationId,reason,tokenBudget,currentTokenCount:liveContextTokens})}catch(err){this.deps.log.warn(`[lcm] afterTurn: failed to persist deferred compaction retry for ${sessionLabel}: ${describeLogError(err)}`)}};let shouldRefreshBootstrapState=true;try{const rawLeafTrigger=await this.compaction.evaluateLeafTrigger(conversation.conversationId);await this.updateCompactionTelemetry({conversationId:conversation.conversationId,runtimeContext:legacyParams,tokenBudget,rawTokensOutsideTail:rawLeafTrigger.rawTokensOutsideTail})}catch(err){this.deps.log.warn(`[lcm] afterTurn: compaction telemetry update failed: ${describeLogError(err)}`)}try{const leafDecision=await this.evaluateIncrementalCompaction({conversationId:conversation.conversationId,tokenBudget,currentTokenCount:liveContextTokens});const thresholdDecision=await this.compaction.evaluate(conversation.conversationId,tokenBudget,liveContextTokens);if(this.config.proactiveThresholdCompactionMode==="inline"){let leafCompactionScheduled=false;if(leafDecision.shouldCompact){leafCompactionScheduled=true;shouldRefreshBootstrapState=false;void this.runAfterTurnInlineLeafCompaction({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile,tokenBudget,currentTokenCount:liveContextTokens,legacyParams,leafDecision,sessionLabel})}else{shouldRefreshBootstrapState=true}if(!leafCompactionScheduled){const compactResult=await this.compact({sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile,tokenBudget,currentTokenCount:liveContextTokens,compactionTarget:"threshold",legacyParams});const retryReason=thresholdDecision.shouldCompact?"threshold":null;if(!compactResult.ok&&retryReason){shouldRefreshBootstrapState=false;await recordAfterTurnCompactionRetry(retryReason)}}}else if(thresholdDecision.shouldCompact||leafDecision.shouldCompact){await this.recordDeferredCompactionDebt({conversationId:conversation.conversationId,reason:thresholdDecision.shouldCompact?"threshold":leafDecision.reason,tokenBudget,currentTokenCount:liveContextTokens})}}catch(err){this.deps.log.warn(`[lcm] afterTurn: compaction policy check failed for ${sessionLabel}: ${describeLogError(err)}`)}if(shouldRefreshBootstrapState){await refreshAfterTurnBootstrapState()}this.deps.log.info(`[lcm] afterTurn: done conversation=${conversation.conversationId} ${sessionLabel} newMessages=${newMessages.length} dedupedMessages=${dedupedNewMessages.length} ingestedMessages=${ingestBatch.length} duration=${formatDurationMs(Date.now()-startedAt)}`)}async assemble(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{messages:params.messages,estimatedTokens:0}}try{this.ensureMigrated();const startedAt=Date.now();const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){this.deps.log.info(`[lcm] assemble: conversation lookup missed ${sessionLabel} duration=${formatDurationMs(Date.now()-startedAt)}`);return{messages:params.messages,estimatedTokens:0}}const tokenBudget=this.applyAssemblyBudgetCap(typeof params.tokenBudget==="number"&&Number.isFinite(params.tokenBudget)&¶ms.tokenBudget>0?Math.floor(params.tokenBudget):128e3);const liveContextTokens=estimateSessionTokenCountForAfterTurn(params.messages);const maintenance=await this.compactionMaintenanceStore.getConversationCompactionMaintenance(conversation.conversationId);if(maintenance?.pending||maintenance?.running){try{await this.maybeConsumeDeferredCompactionDebtForAssemble({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget,currentTokenCount:liveContextTokens})}catch(error){this.deps.log.warn(`[lcm] assemble: deferred compaction execution failed for ${sessionLabel}: ${describeLogError(error)}`)}}const contextItems=await this.summaryStore.getContextItems(conversation.conversationId);if(contextItems.length===0){this.deps.log.info(`[lcm] assemble: no context items conversation=${conversation.conversationId} ${sessionLabel} duration=${formatDurationMs(Date.now()-startedAt)}`);return{messages:params.messages,estimatedTokens:0}}const hasSummaryItems=contextItems.some(item=>item.itemType==="summary");if(!hasSummaryItems&&contextItems.length<params.messages.length){this.deps.log.info(`[lcm] assemble: falling back to live context conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} liveMessages=${params.messages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return{messages:params.messages,estimatedTokens:0}}const assembled=await this.assembler.assemble({conversationId:conversation.conversationId,tokenBudget,freshTailCount:this.config.freshTailCount,freshTailMaxTokens:this.config.freshTailMaxTokens,prompt:params.prompt});if(assembled.messages.length===0&¶ms.messages.length>0){this.deps.log.info(`[lcm] assemble: empty assembled output, using live context conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} tokenBudget=${tokenBudget} duration=${formatDurationMs(Date.now()-startedAt)}`);return{messages:params.messages,estimatedTokens:0}}this.deps.log.info(`[lcm] assemble: done conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} hasSummaryItems=${hasSummaryItems} inputMessages=${params.messages.length} outputMessages=${assembled.messages.length} tokenBudget=${tokenBudget} estimatedTokens=${assembled.estimatedTokens} duration=${formatDurationMs(Date.now()-startedAt)}`);const result={messages:assembled.messages,estimatedTokens:assembled.estimatedTokens,...assembled.systemPromptAddition?{systemPromptAddition:assembled.systemPromptAddition}:{}};return result}catch(err){this.deps.log.info(`[lcm] assemble: failed for session=${params.sessionId}${params.sessionKey?.trim()?` sessionKey=${params.sessionKey.trim()}`:""} error=${describeLogError(err)}`);return{messages:params.messages,estimatedTokens:0}}}async evaluateLeafTrigger(sessionId,sessionKey){this.ensureMigrated();const conversation=await this.conversationStore.getConversationForSession({sessionId,sessionKey});if(!conversation){const fallbackThreshold=typeof this.config.leafChunkTokens==="number"&&Number.isFinite(this.config.leafChunkTokens)&&this.config.leafChunkTokens>0?Math.floor(this.config.leafChunkTokens):2e4;return{shouldCompact:false,rawTokensOutsideTail:0,threshold:fallbackThreshold}}return this.compaction.evaluateLeafTrigger(conversation.conversationId)}async executeLeafCompactionCore(params){const legacyParams=asRecord(params.runtimeContext)??params.legacyParams;const observedTokens=this.normalizeObservedTokenCount(params.currentTokenCount??(legacyParams??{}).currentTokenCount);const{summarize,summaryModel,breakerKey}=await this.resolveSummarize({legacyParams,customInstructions:params.customInstructions,breakerScope:this.resolveSessionQueueKey(params.sessionId,params.sessionKey)});if(breakerKey&&this.isCircuitBreakerOpen(breakerKey)){return{ok:true,compacted:false,reason:"circuit breaker open"}}const storedTokensBefore=await this.summaryStore.getContextTokenCount(params.conversationId);const maxPasses=typeof params.maxPasses==="number"&&Number.isFinite(params.maxPasses)&¶ms.maxPasses>0?Math.floor(params.maxPasses):1;const fallbackLeafChunkTokens=Array.isArray(params.fallbackLeafChunkTokens)?[...new Set(params.fallbackLeafChunkTokens.filter(value=>typeof value==="number"&&Number.isFinite(value)&&value>0).map(value=>Math.floor(value)))].sort((a,b)=>b-a):[];let activeLeafChunkTokens=typeof params.leafChunkTokens==="number"&&Number.isFinite(params.leafChunkTokens)&¶ms.leafChunkTokens>0?Math.floor(params.leafChunkTokens):fallbackLeafChunkTokens[0];this.deps.log.info(`[lcm] compactLeafAsync start: conversation=${params.conversationId} session=${params.sessionId} leafChunkTokens=${activeLeafChunkTokens??"null"} fallbackLeafChunkTokens=${fallbackLeafChunkTokens.join(",")} maxPasses=${maxPasses} activityBand=${params.activityBand??"unknown"} allowCondensedPasses=${params.allowCondensedPasses!==false}`);let rounds=0;let finalTokens=observedTokens??storedTokensBefore;let authFailure=false;for(let pass=0;pass<maxPasses;pass+=1){let leafResult;while(true){try{leafResult=await this.compaction.compactLeaf({conversationId:params.conversationId,tokenBudget:params.tokenBudget,summarize,...activeLeafChunkTokens!==void 0?{leafChunkTokens:activeLeafChunkTokens}:{},force:params.force,previousSummaryContent:pass===0?params.previousSummaryContent:void 0,summaryModel,allowCondensedPasses:params.allowCondensedPasses});break}catch(err){const nextLeafChunkTokens=fallbackLeafChunkTokens.find(value=>activeLeafChunkTokens!==void 0&&value<activeLeafChunkTokens);if(!this.isRecoverableLeafChunkOverflowError(err)||nextLeafChunkTokens===void 0){throw err}this.deps.log.warn(`[lcm] compactLeafAsync: retrying with smaller leafChunkTokens=${nextLeafChunkTokens} after provider token-limit error: ${err instanceof Error?err.message:String(err)}`);activeLeafChunkTokens=nextLeafChunkTokens}}if(!leafResult){break}finalTokens=leafResult.tokensAfter;if(leafResult.authFailure){authFailure=true;break}if(!leafResult.actionTaken){break}rounds+=1;if(leafResult.tokensAfter>=leafResult.tokensBefore){break}}if(authFailure&&breakerKey){this.recordCompactionAuthFailure(breakerKey)}else if(rounds>0&&breakerKey){this.recordCompactionSuccess(breakerKey)}if(rounds>0){await this.markLeafCompactionTelemetrySuccess({conversationId:params.conversationId,activityBand:params.activityBand})}const tokensBefore=observedTokens??storedTokensBefore;this.deps.log.debug(`[lcm] compactLeafAsync result: conversation=${params.conversationId} session=${params.sessionId} rounds=${rounds} compacted=${rounds>0} authFailure=${authFailure} finalLeafChunkTokens=${activeLeafChunkTokens??"null"} finalTokens=${finalTokens}`);return{ok:!authFailure,compacted:rounds>0,reason:authFailure?"provider auth failure":rounds>0?"compacted":"below threshold",result:{tokensBefore,tokensAfter:finalTokens,details:{rounds,targetTokens:params.tokenBudget,mode:"leaf",maxPasses}}}}async compactLeafAsync(params){if(this.isStatelessSession(params.sessionKey)){return{ok:true,compacted:false,reason:"stateless session"}}this.ensureMigrated();return this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){return{ok:true,compacted:false,reason:"no conversation found for session"}}const legacyParams=asRecord(params.runtimeContext)??params.legacyParams;const resolvedTokenBudget=this.resolveTokenBudget({tokenBudget:params.tokenBudget,runtimeContext:params.runtimeContext,legacyParams});const tokenBudget=resolvedTokenBudget?this.applyAssemblyBudgetCap(resolvedTokenBudget):resolvedTokenBudget;if(!tokenBudget){return{ok:false,compacted:false,reason:"missing token budget in compact params"}}return this.executeLeafCompactionCore({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget,currentTokenCount:params.currentTokenCount,customInstructions:params.customInstructions,runtimeContext:params.runtimeContext,legacyParams:params.legacyParams,force:params.force,previousSummaryContent:params.previousSummaryContent,maxPasses:params.maxPasses,leafChunkTokens:params.leafChunkTokens,fallbackLeafChunkTokens:params.fallbackLeafChunkTokens,activityBand:params.activityBand,allowCondensedPasses:params.allowCondensedPasses})})}async compact(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{ok:true,compacted:false,reason:"session excluded"}}if(this.isStatelessSession(params.sessionKey)){return{ok:true,compacted:false,reason:"stateless session"}}this.ensureMigrated();return this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){return{ok:true,compacted:false,reason:"no conversation found for session"}}return this.executeCompactionCore({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:params.tokenBudget,currentTokenCount:params.currentTokenCount,compactionTarget:params.compactionTarget,customInstructions:params.customInstructions,runtimeContext:params.runtimeContext,legacyParams:params.legacyParams,force:params.force})})}async prepareSubagentSpawn(params){if(this.shouldIgnoreSession({sessionKey:params.parentSessionKey})||this.shouldIgnoreSession({sessionKey:params.childSessionKey})||this.isStatelessSession(params.parentSessionKey)||this.isStatelessSession(params.childSessionKey)){return void 0}this.ensureMigrated();const childSessionKey=params.childSessionKey.trim();const parentSessionKey=params.parentSessionKey.trim();if(!childSessionKey||!parentSessionKey){return void 0}const conversationId=await this.resolveConversationIdForSessionKey(parentSessionKey);if(typeof conversationId!=="number"){return void 0}const ttlMs=typeof params.ttlMs==="number"&&Number.isFinite(params.ttlMs)&¶ms.ttlMs>0?Math.floor(params.ttlMs):void 0;const parentGrantId=resolveDelegatedExpansionGrantId(parentSessionKey);const parentGrant=parentGrantId?getRuntimeExpansionAuthManager().getGrant(parentGrantId):null;const childTokenCap=parentGrant?Math.min(getRuntimeExpansionAuthManager().getRemainingTokenBudget(parentGrantId)??this.config.maxExpandTokens,this.config.maxExpandTokens):this.config.maxExpandTokens;const childMaxDepth=parentGrant?Math.max(0,parentGrant.maxDepth-1):void 0;const childAllowedSummaryIds=parentGrant?.allowedSummaryIds.length?parentGrant.allowedSummaryIds:void 0;createDelegatedExpansionGrant({delegatedSessionKey:childSessionKey,issuerSessionId:parentSessionKey,allowedConversationIds:[conversationId],allowedSummaryIds:childAllowedSummaryIds,tokenCap:childTokenCap,maxDepth:childMaxDepth,ttlMs});return{rollback:()=>{revokeDelegatedExpansionGrantForSession(childSessionKey,{removeBinding:true})}}}async onSubagentEnded(params){if(this.shouldIgnoreSession({sessionKey:params.childSessionKey})||this.isStatelessSession(params.childSessionKey)){return}const childSessionKey=params.childSessionKey.trim();if(!childSessionKey){return}switch(params.reason){case"deleted":revokeDelegatedExpansionGrantForSession(childSessionKey,{removeBinding:true});break;case"completed":revokeDelegatedExpansionGrantForSession(childSessionKey);break;case"released":case"swept":removeDelegatedExpansionGrantForSession(childSessionKey);break}}async dispose(){}async isFreshLifecycleConversation(conversation){const currentMessageCount=await this.conversationStore.getMessageCount(conversation.conversationId);if(currentMessageCount!==0){return false}const currentContextItems=await this.summaryStore.getContextItems(conversation.conversationId);return currentContextItems.length===0&&!conversation.bootstrappedAt}async applySessionReplacement(params){const current=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!current&&!params.createReplacementWhenMissing){return}if(current?.active){if(params.createReplacement&&await this.isFreshLifecycleConversation(current)){this.deps.log.info(`[lcm] ${params.reason} lifecycle no-op for already fresh conversation ${current.conversationId}`);return}await this.conversationStore.archiveConversation(current.conversationId)}if(!params.createReplacement){this.deps.log.info(`[lcm] ${params.reason} lifecycle archived conversation ${current?.conversationId??"(none)"}`);return}const nextSessionId=params.nextSessionId?.trim()||params.sessionId?.trim()||current?.sessionId;if(!nextSessionId){this.deps.log.warn(`[lcm] ${params.reason} lifecycle skipped: no session identity available`);return}const nextSessionKey=params.nextSessionKey?.trim()||params.sessionKey?.trim()||current?.sessionKey;const freshConversation=await this.conversationStore.createConversation({sessionId:nextSessionId,...nextSessionKey?{sessionKey:nextSessionKey}:{}});this.deps.log.info(`[lcm] ${params.reason} lifecycle archived prior conversation and created ${freshConversation.conversationId}`)}async handleBeforeReset(params){const reason=params.reason?.trim();if(reason!=="new"&&reason!=="reset"){return}if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return}if(this.isStatelessSession(params.sessionKey)){return}this.ensureMigrated();await this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>this.conversationStore.withTransaction(async()=>{if(reason==="new"){const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){return}const retainDepth=typeof this.config.newSessionRetainDepth==="number"&&Number.isFinite(this.config.newSessionRetainDepth)?this.config.newSessionRetainDepth:2;await this.summaryStore.pruneForNewSession(conversation.conversationId,retainDepth);this.deps.log.info(`[lcm] /new pruned conversation ${conversation.conversationId} to retain depth ${retainDepth}`);return}await this.applySessionReplacement({reason:"/reset",sessionId:params.sessionId,sessionKey:params.sessionKey,createReplacement:true,createReplacementWhenMissing:true})}))}async handleSessionEnd(params){const reason=params.reason?.trim();if(!reason||reason==="new"||reason==="unknown"){return}if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return}if(this.isStatelessSession(params.sessionKey??params.nextSessionKey)){return}const createReplacement=reason!=="deleted";this.ensureMigrated();await this.withSessionQueue(this.resolveSessionQueueKey(params.nextSessionId??params.sessionId,params.sessionKey??params.nextSessionKey),async()=>this.conversationStore.withTransaction(async()=>{await this.applySessionReplacement({reason:`session_end:${reason}`,sessionId:params.sessionId,sessionKey:params.sessionKey??params.nextSessionKey,nextSessionId:params.nextSessionId,nextSessionKey:params.nextSessionKey,createReplacement})}))}async rewriteTranscriptForRotate(params){const sessionManager=SessionManager.open(params.sessionFile);const header=sessionManager.getHeader();const branch=sessionManager.getBranch();const originalStats=await stat(params.sessionFile);const messageIndices=[];for(let index=0;index<branch.length;index+=1){if(branch[index]?.type==="message"){messageIndices.push(index)}}const keepTailMessageCount=normalizeRotateTailMessageCount(this.config.freshTailCount,messageIndices.length);const anchorIndex=keepTailMessageCount>0?messageIndices[messageIndices.length-keepTailMessageCount]??branch.length:branch.length;const latestPreludeEntries=new Map;for(let index=0;index<anchorIndex;index+=1){const entry=branch[index];if(entry&&isRotatePreservedEntryType(entry.type)&&entry.type!=="message"){latestPreludeEntries.set(entry.type,entry)}}const entriesToKeep=[];for(const type of["session_info","model_change","thinking_level_change"]){const entry=latestPreludeEntries.get(type);if(entry){entriesToKeep.push({...entry})}}for(let index=anchorIndex;index<branch.length;index+=1){const entry=branch[index];if(entry&&isRotatePreservedEntryType(entry.type)){entriesToKeep.push({...entry})}}while(entriesToKeep.length>0&&entriesToKeep[entriesToKeep.length-1]?.type!=="message"){entriesToKeep.pop()}let previousEntryId=null;const linearizedEntries=entriesToKeep.map(entry=>{const nextEntry={...entry,parentId:previousEntryId};previousEntryId=typeof nextEntry.id==="string"?nextEntry.id:previousEntryId;return nextEntry});const serialized=[JSON.stringify(header),...linearizedEntries.map(entry=>JSON.stringify(entry))].join("\n")+"\n";await writeFile(params.sessionFile,serialized,"utf8");const rewrittenStats=await stat(params.sessionFile);await this.refreshBootstrapState({conversationId:params.conversationId,sessionFile:params.sessionFile,fileStats:{size:rewrittenStats.size,mtimeMs:rewrittenStats.mtimeMs}});return{checkpointSize:rewrittenStats.size,bytesRemoved:Math.max(0,originalStats.size-rewrittenStats.size),preservedTailMessageCount:keepTailMessageCount}}async rotateSessionStorageInActiveTransaction(params){const{sessionId,sessionKey}=params;const current=await this.conversationStore.getConversationForSession({sessionId,sessionKey});if(!current?.active){return{kind:"unavailable",reason:"No active Lossless Claw conversation is stored for the current session."}}try{const rewriteResult=await this.rewriteTranscriptForRotate({conversationId:current.conversationId,sessionFile:params.sessionFile});this.deps.log.info(`[lcm] rotate: rewrote transcript for conversation=${current.conversationId} session=${sessionId} sessionKey=${sessionKey} preservedTailMessages=${rewriteResult.preservedTailMessageCount} checkpointSize=${rewriteResult.checkpointSize} bytesRemoved=${rewriteResult.bytesRemoved}`);return{kind:"rotated",conversationId:current.conversationId,preservedTailMessageCount:rewriteResult.preservedTailMessageCount,checkpointSize:rewriteResult.checkpointSize,bytesRemoved:rewriteResult.bytesRemoved}}catch(error){return{kind:"unavailable",reason:`Lossless Claw could not rotate the current session transcript: ${describeLogError(error)}`}}}async rotateSessionStorage(params){const sessionId=params.sessionId?.trim();const sessionKey=params.sessionKey?.trim();if(!sessionId||!sessionKey){return{kind:"unavailable",reason:"Lossless Claw needs both the current session id and session key to rotate storage safely."}}if(this.shouldIgnoreSession({sessionId,sessionKey})){return{kind:"unavailable",reason:"The current session is excluded by ignoreSessionPatterns, so there is no active LCM conversation to rotate."}}if(this.isStatelessSession(sessionKey)){return{kind:"unavailable",reason:"The current session is stateless in Lossless Claw, so there is no writable active LCM conversation to rotate."}}this.ensureMigrated();return this.withSessionQueue(this.resolveSessionQueueKey(sessionId,sessionKey),async()=>this.conversationStore.withTransaction(()=>this.rotateSessionStorageInActiveTransaction({sessionId,sessionKey,sessionFile:params.sessionFile})))}async rotateSessionStorageWhileHoldingDatabaseLock(params){const sessionId=params.sessionId?.trim();const sessionKey=params.sessionKey?.trim();if(!sessionId||!sessionKey){return{kind:"unavailable",reason:"Lossless Claw needs both the current session id and session key to rotate storage safely."}}if(this.shouldIgnoreSession({sessionId,sessionKey})){return{kind:"unavailable",reason:"The current session is excluded by ignoreSessionPatterns, so there is no active LCM conversation to rotate."}}if(this.isStatelessSession(sessionKey)){return{kind:"unavailable",reason:"The current session is stateless in Lossless Claw, so there is no writable active LCM conversation to rotate."}}this.ensureMigrated();if(this.db.isTransaction){return{kind:"unavailable",reason:"Lossless Claw obtained exclusive rotate access, but the shared database connection is still inside another transaction."}}let transactionActive=false;try{this.db.exec("BEGIN IMMEDIATE");transactionActive=true;const result=await this.rotateSessionStorageInActiveTransaction({sessionId,sessionKey,sessionFile:params.sessionFile});this.db.exec("COMMIT");transactionActive=false;return result}catch(error){if(transactionActive){this.db.exec("ROLLBACK")}throw error}}async rotateSessionStorageWithBackup(params){const sessionId=params.sessionId?.trim();const sessionKey=params.sessionKey?.trim();if(!sessionId||!sessionKey){return{kind:"unavailable",reason:"Lossless Claw needs both the current session id and session key to rotate storage safely."}}if(this.shouldIgnoreSession({sessionId,sessionKey})){return{kind:"unavailable",reason:"The current session is excluded by ignoreSessionPatterns, so there is no active LCM conversation to rotate."}}if(this.isStatelessSession(sessionKey)){return{kind:"unavailable",reason:"The current session is stateless in Lossless Claw, so there is no writable active LCM conversation to rotate."}}this.ensureMigrated();return this.withSessionQueue(this.resolveSessionQueueKey(sessionId,sessionKey),async()=>{try{return await withExclusiveDatabaseLock(this.db,{timeoutMs:params.lockTimeoutMs},async()=>{if(this.db.isTransaction){return{kind:"unavailable",reason:"Lossless Claw obtained exclusive rotate access, but the shared database connection is still inside another transaction."}}const current=await this.conversationStore.getConversationForSession({sessionId,sessionKey});if(!current?.active){return{kind:"unavailable",reason:"No active Lossless Claw conversation is stored for the current session."}}const currentMessageCount=await this.conversationStore.getMessageCount(current.conversationId);let backupPath=null;try{backupPath=createLcmDatabaseBackup(this.db,{databasePath:this.config.databasePath,label:"rotate",replaceLatest:true})}catch(error){return{kind:"backup_failed",currentConversationId:current.conversationId,currentMessageCount,reason:describeLogError(error)}}if(!backupPath){return{kind:"unavailable",currentConversationId:current.conversationId,currentMessageCount,reason:"Lossless Claw could not create the rotate backup."}}let rotateResult;try{rotateResult=await this.rotateSessionStorageWhileHoldingDatabaseLock({sessionId,sessionKey,sessionFile:params.sessionFile})}catch(error){return{kind:"rotate_failed",currentConversationId:current.conversationId,currentMessageCount,backupPath,reason:describeLogError(error)}}if(rotateResult.kind==="unavailable"){return{kind:"unavailable",currentConversationId:current.conversationId,currentMessageCount,backupPath,reason:rotateResult.reason}}return{kind:"rotated",currentConversationId:current.conversationId,currentMessageCount,backupPath,preservedTailMessageCount:rotateResult.preservedTailMessageCount,checkpointSize:rotateResult.checkpointSize,bytesRemoved:rotateResult.bytesRemoved}})}catch(error){if(error instanceof DatabaseTransactionTimeoutError){return{kind:"unavailable",reason:`Lossless Claw waited ${Math.floor(params.lockTimeoutMs/1e3)}s for the database to become idle, but another transaction never finished.`}}throw error}})}getRetrieval(){return this.retrieval}getConversationStore(){return this.conversationStore}getSummaryStore(){return this.summaryStore}getCompactionTelemetryStore(){return this.compactionTelemetryStore}getCompactionMaintenanceStore(){return this.compactionMaintenanceStore}async pruneHeartbeatOkTurns(conversationId){const allMessages=await this.conversationStore.getMessages(conversationId);if(allMessages.length===0){return 0}const toDelete=[];for(let i=0;i<allMessages.length;i++){const msg=allMessages[i];if(msg.role!=="assistant"){continue}if(!isHeartbeatOkContent(msg.content)){continue}const turnMessages=[msg];for(let j=i-1;j>=0;j--){const prev=allMessages[j];turnMessages.push(prev);if(prev.role==="user"){break}}if(!turnMessages.some(record=>record.role==="user")){continue}if(!turnLooksLikeHeartbeatTurn(turnMessages)){continue}toDelete.push(...turnMessages.map(record=>record.messageId))}if(toDelete.length===0){return 0}const uniqueIds=[...new Set(toDelete)];return this.conversationStore.deleteMessages(uniqueIds)}};var HEARTBEAT_OK_TOKEN="heartbeat_ok";var HEARTBEAT_TURN_MARKER="heartbeat.md";function isHeartbeatOkContent(content){return content.trim().toLowerCase()===HEARTBEAT_OK_TOKEN}function batchLooksLikeHeartbeatAckTurn(messages){let sawHeartbeatMarker=false;let sawHeartbeatAck=false;for(const message of messages){const stored=toStoredMessage(message);if(!sawHeartbeatMarker&&stored.content.toLowerCase().includes(HEARTBEAT_TURN_MARKER)){sawHeartbeatMarker=true}if(!sawHeartbeatAck&&stored.role==="assistant"&&isHeartbeatOkContent(stored.content)){sawHeartbeatAck=true}if(sawHeartbeatMarker&&sawHeartbeatAck){return true}}return false}function turnLooksLikeHeartbeatTurn(turnMessages){return turnMessages.some(message=>message.content.toLowerCase().includes(HEARTBEAT_TURN_MARKER))}function createEmergencyFallbackSummarize(){return async(text,aggressive)=>{const maxChars=aggressive?600*4:900*4;if(text.length<=maxChars){return text}return text.slice(0,maxChars)+"\n[Truncated for context management]"}}var SHARED_KEY=Symbol.for("@martian-engineering/lossless-claw/shared-init");function getStore(){const g=globalThis;if(!g[SHARED_KEY]){g[SHARED_KEY]=new Map}return g[SHARED_KEY]}function getSharedInit(dbPath){return getStore().get(dbPath)}function setSharedInit(dbPath,init){getStore().set(dbPath,init)}function removeSharedInit(dbPath){getStore().delete(dbPath)}var value_exports={};__export(value_exports,{HasPropertyKey:()=>HasPropertyKey,IsArray:()=>IsArray,IsAsyncIterator:()=>IsAsyncIterator,IsBigInt:()=>IsBigInt,IsBoolean:()=>IsBoolean,IsDate:()=>IsDate,IsFunction:()=>IsFunction,IsIterator:()=>IsIterator,IsNull:()=>IsNull,IsNumber:()=>IsNumber,IsObject:()=>IsObject,IsRegExp:()=>IsRegExp,IsString:()=>IsString,IsSymbol:()=>IsSymbol,IsUint8Array:()=>IsUint8Array,IsUndefined:()=>IsUndefined});function HasPropertyKey(value,key){return key in value}function IsAsyncIterator(value){return IsObject(value)&&!IsArray(value)&&!IsUint8Array(value)&&Symbol.asyncIterator in value}function IsArray(value){return Array.isArray(value)}function IsBigInt(value){return typeof value==="bigint"}function IsBoolean(value){return typeof value==="boolean"}function IsDate(value){return value instanceof globalThis.Date}function IsFunction(value){return typeof value==="function"}function IsIterator(value){return IsObject(value)&&!IsArray(value)&&!IsUint8Array(value)&&Symbol.iterator in value}function IsNull(value){return value===null}function IsNumber(value){return typeof value==="number"}function IsObject(value){return typeof value==="object"&&value!==null}function IsRegExp(value){return value instanceof globalThis.RegExp}function IsString(value){return typeof value==="string"}function IsSymbol(value){return typeof value==="symbol"}function IsUint8Array(value){return value instanceof globalThis.Uint8Array}function IsUndefined(value){return value===void 0}function ArrayType(value){return value.map(value2=>Visit(value2))}function DateType(value){return new Date(value.getTime())}function Uint8ArrayType(value){return new Uint8Array(value)}function RegExpType(value){return new RegExp(value.source,value.flags)}function ObjectType(value){const result={};for(const key of Object.getOwnPropertyNames(value)){result[key]=Visit(value[key])}for(const key of Object.getOwnPropertySymbols(value)){result[key]=Visit(value[key])}return result}function Visit(value){return IsArray(value)?ArrayType(value):IsDate(value)?DateType(value):IsUint8Array(value)?Uint8ArrayType(value):IsRegExp(value)?RegExpType(value):IsObject(value)?ObjectType(value):value}function Clone(value){return Visit(value)}function CloneType(schema,options){return options===void 0?Clone(schema):Clone({...options,...schema})}function IsObject2(value){return value!==null&&typeof value==="object"}function IsArray2(value){return globalThis.Array.isArray(value)&&!globalThis.ArrayBuffer.isView(value)}function IsUndefined2(value){return value===void 0}function IsNumber2(value){return typeof value==="number"}var TypeSystemPolicy;(function(TypeSystemPolicy2){TypeSystemPolicy2.InstanceMode="default";TypeSystemPolicy2.ExactOptionalPropertyTypes=false;TypeSystemPolicy2.AllowArrayObject=false;TypeSystemPolicy2.AllowNaN=false;TypeSystemPolicy2.AllowNullVoid=false;function IsExactOptionalProperty(value,key){return TypeSystemPolicy2.ExactOptionalPropertyTypes?key in value:value[key]!==void 0}TypeSystemPolicy2.IsExactOptionalProperty=IsExactOptionalProperty;function IsObjectLike(value){const isObject=IsObject2(value);return TypeSystemPolicy2.AllowArrayObject?isObject:isObject&&!IsArray2(value)}TypeSystemPolicy2.IsObjectLike=IsObjectLike;function IsRecordLike(value){return IsObjectLike(value)&&!(value instanceof Date)&&!(value instanceof Uint8Array)}TypeSystemPolicy2.IsRecordLike=IsRecordLike;function IsNumberLike(value){return TypeSystemPolicy2.AllowNaN?IsNumber2(value):Number.isFinite(value)}TypeSystemPolicy2.IsNumberLike=IsNumberLike;function IsVoidLike(value){const isUndefined=IsUndefined2(value);return TypeSystemPolicy2.AllowNullVoid?isUndefined||value===null:isUndefined}TypeSystemPolicy2.IsVoidLike=IsVoidLike})(TypeSystemPolicy||(TypeSystemPolicy={}));function ImmutableArray(value){return globalThis.Object.freeze(value).map(value2=>Immutable(value2))}function ImmutableDate(value){return value}function ImmutableUint8Array(value){return value}function ImmutableRegExp(value){return value}function ImmutableObject(value){const result={};for(const key of Object.getOwnPropertyNames(value)){result[key]=Immutable(value[key])}for(const key of Object.getOwnPropertySymbols(value)){result[key]=Immutable(value[key])}return globalThis.Object.freeze(result)}function Immutable(value){return IsArray(value)?ImmutableArray(value):IsDate(value)?ImmutableDate(value):IsUint8Array(value)?ImmutableUint8Array(value):IsRegExp(value)?ImmutableRegExp(value):IsObject(value)?ImmutableObject(value):value}function CreateType(schema,options){const result=options!==void 0?{...options,...schema}:schema;switch(TypeSystemPolicy.InstanceMode){case"freeze":return Immutable(result);case"clone":return Clone(result);default:return result}}var TypeBoxError=class extends Error{constructor(message){super(message)}};var TransformKind=Symbol.for("TypeBox.Transform");var ReadonlyKind=Symbol.for("TypeBox.Readonly");var OptionalKind=Symbol.for("TypeBox.Optional");var Hint=Symbol.for("TypeBox.Hint");var Kind=Symbol.for("TypeBox.Kind");function IsReadonly(value){return IsObject(value)&&value[ReadonlyKind]==="Readonly"}function IsOptional(value){return IsObject(value)&&value[OptionalKind]==="Optional"}function IsAny(value){return IsKindOf(value,"Any")}function IsArgument(value){return IsKindOf(value,"Argument")}function IsArray3(value){return IsKindOf(value,"Array")}function IsAsyncIterator2(value){return IsKindOf(value,"AsyncIterator")}function IsBigInt2(value){return IsKindOf(value,"BigInt")}function IsBoolean2(value){return IsKindOf(value,"Boolean")}function IsComputed(value){return IsKindOf(value,"Computed")}function IsConstructor(value){return IsKindOf(value,"Constructor")}function IsDate2(value){return IsKindOf(value,"Date")}function IsFunction2(value){return IsKindOf(value,"Function")}function IsInteger(value){return IsKindOf(value,"Integer")}function IsIntersect(value){return IsKindOf(value,"Intersect")}function IsIterator2(value){return IsKindOf(value,"Iterator")}function IsKindOf(value,kind){return IsObject(value)&&Kind in value&&value[Kind]===kind}function IsLiteralValue(value){return IsBoolean(value)||IsNumber(value)||IsString(value)}function IsLiteral(value){return IsKindOf(value,"Literal")}function IsMappedKey(value){return IsKindOf(value,"MappedKey")}function IsMappedResult(value){return IsKindOf(value,"MappedResult")}function IsNever(value){return IsKindOf(value,"Never")}function IsNot(value){return IsKindOf(value,"Not")}function IsNull2(value){return IsKindOf(value,"Null")}function IsNumber3(value){return IsKindOf(value,"Number")}function IsObject3(value){return IsKindOf(value,"Object")}function IsPromise(value){return IsKindOf(value,"Promise")}function IsRecord(value){return IsKindOf(value,"Record")}function IsRef(value){return IsKindOf(value,"Ref")}function IsRegExp2(value){return IsKindOf(value,"RegExp")}function IsString2(value){return IsKindOf(value,"String")}function IsSymbol2(value){return IsKindOf(value,"Symbol")}function IsTemplateLiteral(value){return IsKindOf(value,"TemplateLiteral")}function IsThis(value){return IsKindOf(value,"This")}function IsTransform(value){return IsObject(value)&&TransformKind in value}function IsTuple(value){return IsKindOf(value,"Tuple")}function IsUndefined3(value){return IsKindOf(value,"Undefined")}function IsUnion(value){return IsKindOf(value,"Union")}function IsUint8Array2(value){return IsKindOf(value,"Uint8Array")}function IsUnknown(value){return IsKindOf(value,"Unknown")}function IsUnsafe(value){return IsKindOf(value,"Unsafe")}function IsVoid(value){return IsKindOf(value,"Void")}function IsKind(value){return IsObject(value)&&Kind in value&&IsString(value[Kind])}function IsSchema(value){return IsAny(value)||IsArgument(value)||IsArray3(value)||IsBoolean2(value)||IsBigInt2(value)||IsAsyncIterator2(value)||IsComputed(value)||IsConstructor(value)||IsDate2(value)||IsFunction2(value)||IsInteger(value)||IsIntersect(value)||IsIterator2(value)||IsLiteral(value)||IsMappedKey(value)||IsMappedResult(value)||IsNever(value)||IsNot(value)||IsNull2(value)||IsNumber3(value)||IsObject3(value)||IsPromise(value)||IsRecord(value)||IsRef(value)||IsRegExp2(value)||IsString2(value)||IsSymbol2(value)||IsTemplateLiteral(value)||IsThis(value)||IsTuple(value)||IsUndefined3(value)||IsUnion(value)||IsUint8Array2(value)||IsUnknown(value)||IsUnsafe(value)||IsVoid(value)||IsKind(value)}var type_exports={};__export(type_exports,{IsAny:()=>IsAny2,IsArgument:()=>IsArgument2,IsArray:()=>IsArray4,IsAsyncIterator:()=>IsAsyncIterator3,IsBigInt:()=>IsBigInt3,IsBoolean:()=>IsBoolean3,IsComputed:()=>IsComputed2,IsConstructor:()=>IsConstructor2,IsDate:()=>IsDate3,IsFunction:()=>IsFunction3,IsImport:()=>IsImport,IsInteger:()=>IsInteger2,IsIntersect:()=>IsIntersect2,IsIterator:()=>IsIterator3,IsKind:()=>IsKind2,IsKindOf:()=>IsKindOf2,IsLiteral:()=>IsLiteral2,IsLiteralBoolean:()=>IsLiteralBoolean,IsLiteralNumber:()=>IsLiteralNumber,IsLiteralString:()=>IsLiteralString,IsLiteralValue:()=>IsLiteralValue2,IsMappedKey:()=>IsMappedKey2,IsMappedResult:()=>IsMappedResult2,IsNever:()=>IsNever2,IsNot:()=>IsNot2,IsNull:()=>IsNull3,IsNumber:()=>IsNumber4,IsObject:()=>IsObject4,IsOptional:()=>IsOptional2,IsPromise:()=>IsPromise2,IsProperties:()=>IsProperties,IsReadonly:()=>IsReadonly2,IsRecord:()=>IsRecord2,IsRecursive:()=>IsRecursive,IsRef:()=>IsRef2,IsRegExp:()=>IsRegExp3,IsSchema:()=>IsSchema2,IsString:()=>IsString3,IsSymbol:()=>IsSymbol3,IsTemplateLiteral:()=>IsTemplateLiteral2,IsThis:()=>IsThis2,IsTransform:()=>IsTransform2,IsTuple:()=>IsTuple2,IsUint8Array:()=>IsUint8Array3,IsUndefined:()=>IsUndefined4,IsUnion:()=>IsUnion2,IsUnionLiteral:()=>IsUnionLiteral,IsUnknown:()=>IsUnknown2,IsUnsafe:()=>IsUnsafe2,IsVoid:()=>IsVoid2,TypeGuardUnknownTypeError:()=>TypeGuardUnknownTypeError});var TypeGuardUnknownTypeError=class extends TypeBoxError{};var KnownTypes=["Argument","Any","Array","AsyncIterator","BigInt","Boolean","Computed","Constructor","Date","Enum","Function","Integer","Intersect","Iterator","Literal","MappedKey","MappedResult","Not","Null","Number","Object","Promise","Record","Ref","RegExp","String","Symbol","TemplateLiteral","This","Tuple","Undefined","Union","Uint8Array","Unknown","Void"];function IsPattern(value){try{new RegExp(value);return true}catch{return false}}function IsControlCharacterFree(value){if(!IsString(value))return false;for(let i=0;i<value.length;i++){const code=value.charCodeAt(i);if(code>=7&&code<=13||code===27||code===127){return false}}return true}function IsAdditionalProperties(value){return IsOptionalBoolean(value)||IsSchema2(value)}function IsOptionalBigInt(value){return IsUndefined(value)||IsBigInt(value)}function IsOptionalNumber(value){return IsUndefined(value)||IsNumber(value)}function IsOptionalBoolean(value){return IsUndefined(value)||IsBoolean(value)}function IsOptionalString(value){return IsUndefined(value)||IsString(value)}function IsOptionalPattern(value){return IsUndefined(value)||IsString(value)&&IsControlCharacterFree(value)&&IsPattern(value)}function IsOptionalFormat(value){return IsUndefined(value)||IsString(value)&&IsControlCharacterFree(value)}function IsOptionalSchema(value){return IsUndefined(value)||IsSchema2(value)}function IsReadonly2(value){return IsObject(value)&&value[ReadonlyKind]==="Readonly"}function IsOptional2(value){return IsObject(value)&&value[OptionalKind]==="Optional"}function IsAny2(value){return IsKindOf2(value,"Any")&&IsOptionalString(value.$id)}function IsArgument2(value){return IsKindOf2(value,"Argument")&&IsNumber(value.index)}function IsArray4(value){return IsKindOf2(value,"Array")&&value.type==="array"&&IsOptionalString(value.$id)&&IsSchema2(value.items)&&IsOptionalNumber(value.minItems)&&IsOptionalNumber(value.maxItems)&&IsOptionalBoolean(value.uniqueItems)&&IsOptionalSchema(value.contains)&&IsOptionalNumber(value.minContains)&&IsOptionalNumber(value.maxContains)}function IsAsyncIterator3(value){return IsKindOf2(value,"AsyncIterator")&&value.type==="AsyncIterator"&&IsOptionalString(value.$id)&&IsSchema2(value.items)}function IsBigInt3(value){return IsKindOf2(value,"BigInt")&&value.type==="bigint"&&IsOptionalString(value.$id)&&IsOptionalBigInt(value.exclusiveMaximum)&&IsOptionalBigInt(value.exclusiveMinimum)&&IsOptionalBigInt(value.maximum)&&IsOptionalBigInt(value.minimum)&&IsOptionalBigInt(value.multipleOf)}function IsBoolean3(value){return IsKindOf2(value,"Boolean")&&value.type==="boolean"&&IsOptionalString(value.$id)}function IsComputed2(value){return IsKindOf2(value,"Computed")&&IsString(value.target)&&IsArray(value.parameters)&&value.parameters.every(schema=>IsSchema2(schema))}function IsConstructor2(value){return IsKindOf2(value,"Constructor")&&value.type==="Constructor"&&IsOptionalString(value.$id)&&IsArray(value.parameters)&&value.parameters.every(schema=>IsSchema2(schema))&&IsSchema2(value.returns)}function IsDate3(value){return IsKindOf2(value,"Date")&&value.type==="Date"&&IsOptionalString(value.$id)&&IsOptionalNumber(value.exclusiveMaximumTimestamp)&&IsOptionalNumber(value.exclusiveMinimumTimestamp)&&IsOptionalNumber(value.maximumTimestamp)&&IsOptionalNumber(value.minimumTimestamp)&&IsOptionalNumber(value.multipleOfTimestamp)}function IsFunction3(value){return IsKindOf2(value,"Function")&&value.type==="Function"&&IsOptionalString(value.$id)&&IsArray(value.parameters)&&value.parameters.every(schema=>IsSchema2(schema))&&IsSchema2(value.returns)}function IsImport(value){return IsKindOf2(value,"Import")&&HasPropertyKey(value,"$defs")&&IsObject(value.$defs)&&IsProperties(value.$defs)&&HasPropertyKey(value,"$ref")&&IsString(value.$ref)&&value.$ref in value.$defs}function IsInteger2(value){return IsKindOf2(value,"Integer")&&value.type==="integer"&&IsOptionalString(value.$id)&&IsOptionalNumber(value.exclusiveMaximum)&&IsOptionalNumber(value.exclusiveMinimum)&&IsOptionalNumber(value.maximum)&&IsOptionalNumber(value.minimum)&&IsOptionalNumber(value.multipleOf)}function IsProperties(value){return IsObject(value)&&Object.entries(value).every(([key,schema])=>IsControlCharacterFree(key)&&IsSchema2(schema))}function IsIntersect2(value){return IsKindOf2(value,"Intersect")&&(IsString(value.type)&&value.type!=="object"?false:true)&&IsArray(value.allOf)&&value.allOf.every(schema=>IsSchema2(schema)&&!IsTransform2(schema))&&IsOptionalString(value.type)&&(IsOptionalBoolean(value.unevaluatedProperties)||IsOptionalSchema(value.unevaluatedProperties))&&IsOptionalString(value.$id)}function IsIterator3(value){return IsKindOf2(value,"Iterator")&&value.type==="Iterator"&&IsOptionalString(value.$id)&&IsSchema2(value.items)}function IsKindOf2(value,kind){return IsObject(value)&&Kind in value&&value[Kind]===kind}function IsLiteralString(value){return IsLiteral2(value)&&IsString(value.const)}function IsLiteralNumber(value){return IsLiteral2(value)&&IsNumber(value.const)}function IsLiteralBoolean(value){return IsLiteral2(value)&&IsBoolean(value.const)}function IsLiteral2(value){return IsKindOf2(value,"Literal")&&IsOptionalString(value.$id)&&IsLiteralValue2(value.const)}function IsLiteralValue2(value){return IsBoolean(value)||IsNumber(value)||IsString(value)}function IsMappedKey2(value){return IsKindOf2(value,"MappedKey")&&IsArray(value.keys)&&value.keys.every(key=>IsNumber(key)||IsString(key))}function IsMappedResult2(value){return IsKindOf2(value,"MappedResult")&&IsProperties(value.properties)}function IsNever2(value){return IsKindOf2(value,"Never")&&IsObject(value.not)&&Object.getOwnPropertyNames(value.not).length===0}function IsNot2(value){return IsKindOf2(value,"Not")&&IsSchema2(value.not)}function IsNull3(value){return IsKindOf2(value,"Null")&&value.type==="null"&&IsOptionalString(value.$id)}function IsNumber4(value){return IsKindOf2(value,"Number")&&value.type==="number"&&IsOptionalString(value.$id)&&IsOptionalNumber(value.exclusiveMaximum)&&IsOptionalNumber(value.exclusiveMinimum)&&IsOptionalNumber(value.maximum)&&IsOptionalNumber(value.minimum)&&IsOptionalNumber(value.multipleOf)}function IsObject4(value){return IsKindOf2(value,"Object")&&value.type==="object"&&IsOptionalString(value.$id)&&IsProperties(value.properties)&&IsAdditionalProperties(value.additionalProperties)&&IsOptionalNumber(value.minProperties)&&IsOptionalNumber(value.maxProperties)}function IsPromise2(value){return IsKindOf2(value,"Promise")&&value.type==="Promise"&&IsOptionalString(value.$id)&&IsSchema2(value.item)}function IsRecord2(value){return IsKindOf2(value,"Record")&&value.type==="object"&&IsOptionalString(value.$id)&&IsAdditionalProperties(value.additionalProperties)&&IsObject(value.patternProperties)&&(schema=>{const keys=Object.getOwnPropertyNames(schema.patternProperties);return keys.length===1&&IsPattern(keys[0])&&IsObject(schema.patternProperties)&&IsSchema2(schema.patternProperties[keys[0]])})(value)}function IsRecursive(value){return IsObject(value)&&Hint in value&&value[Hint]==="Recursive"}function IsRef2(value){return IsKindOf2(value,"Ref")&&IsOptionalString(value.$id)&&IsString(value.$ref)}function IsRegExp3(value){return IsKindOf2(value,"RegExp")&&IsOptionalString(value.$id)&&IsString(value.source)&&IsString(value.flags)&&IsOptionalNumber(value.maxLength)&&IsOptionalNumber(value.minLength)}function IsString3(value){return IsKindOf2(value,"String")&&value.type==="string"&&IsOptionalString(value.$id)&&IsOptionalNumber(value.minLength)&&IsOptionalNumber(value.maxLength)&&IsOptionalPattern(value.pattern)&&IsOptionalFormat(value.format)}function IsSymbol3(value){return IsKindOf2(value,"Symbol")&&value.type==="symbol"&&IsOptionalString(value.$id)}function IsTemplateLiteral2(value){return IsKindOf2(value,"TemplateLiteral")&&value.type==="string"&&IsString(value.pattern)&&value.pattern[0]==="^"&&value.pattern[value.pattern.length-1]==="$"}function IsThis2(value){return IsKindOf2(value,"This")&&IsOptionalString(value.$id)&&IsString(value.$ref)}function IsTransform2(value){return IsObject(value)&&TransformKind in value}function IsTuple2(value){return IsKindOf2(value,"Tuple")&&value.type==="array"&&IsOptionalString(value.$id)&&IsNumber(value.minItems)&&IsNumber(value.maxItems)&&value.minItems===value.maxItems&&(IsUndefined(value.items)&&IsUndefined(value.additionalItems)&&value.minItems===0||IsArray(value.items)&&value.items.every(schema=>IsSchema2(schema)))}function IsUndefined4(value){return IsKindOf2(value,"Undefined")&&value.type==="undefined"&&IsOptionalString(value.$id)}function IsUnionLiteral(value){return IsUnion2(value)&&value.anyOf.every(schema=>IsLiteralString(schema)||IsLiteralNumber(schema))}function IsUnion2(value){return IsKindOf2(value,"Union")&&IsOptionalString(value.$id)&&IsObject(value)&&IsArray(value.anyOf)&&value.anyOf.every(schema=>IsSchema2(schema))}function IsUint8Array3(value){return IsKindOf2(value,"Uint8Array")&&value.type==="Uint8Array"&&IsOptionalString(value.$id)&&IsOptionalNumber(value.minByteLength)&&IsOptionalNumber(value.maxByteLength)}function IsUnknown2(value){return IsKindOf2(value,"Unknown")&&IsOptionalString(value.$id)}function IsUnsafe2(value){return IsKindOf2(value,"Unsafe")}function IsVoid2(value){return IsKindOf2(value,"Void")&&value.type==="void"&&IsOptionalString(value.$id)}function IsKind2(value){return IsObject(value)&&Kind in value&&IsString(value[Kind])&&!KnownTypes.includes(value[Kind])}function IsSchema2(value){return IsObject(value)&&(IsAny2(value)||IsArgument2(value)||IsArray4(value)||IsBoolean3(value)||IsBigInt3(value)||IsAsyncIterator3(value)||IsComputed2(value)||IsConstructor2(value)||IsDate3(value)||IsFunction3(value)||IsInteger2(value)||IsIntersect2(value)||IsIterator3(value)||IsLiteral2(value)||IsMappedKey2(value)||IsMappedResult2(value)||IsNever2(value)||IsNot2(value)||IsNull3(value)||IsNumber4(value)||IsObject4(value)||IsPromise2(value)||IsRecord2(value)||IsRef2(value)||IsRegExp3(value)||IsString3(value)||IsSymbol3(value)||IsTemplateLiteral2(value)||IsThis2(value)||IsTuple2(value)||IsUndefined4(value)||IsUnion2(value)||IsUint8Array3(value)||IsUnknown2(value)||IsUnsafe2(value)||IsVoid2(value)||IsKind2(value))}var PatternBoolean="(true|false)";var PatternNumber="(0|[1-9][0-9]*)";var PatternString="(.*)";var PatternNever="(?!.*)";var PatternBooleanExact=`^${PatternBoolean}$`;var PatternNumberExact=`^${PatternNumber}$`;var PatternStringExact=`^${PatternString}$`;var PatternNeverExact=`^${PatternNever}$`;function SetIncludes(T,S){return T.includes(S)}function SetDistinct(T){return[...new Set(T)]}function SetIntersect(T,S){return T.filter(L=>S.includes(L))}function SetIntersectManyResolve(T,Init){return T.reduce((Acc,L)=>{return SetIntersect(Acc,L)},Init)}function SetIntersectMany(T){return T.length===1?T[0]:T.length>1?SetIntersectManyResolve(T.slice(1),T[0]):[]}function SetUnionMany(T){const Acc=[];for(const L of T)Acc.push(...L);return Acc}function Any(options){return CreateType({[Kind]:"Any"},options)}function Array2(items,options){return CreateType({[Kind]:"Array",type:"array",items},options)}function Argument(index){return CreateType({[Kind]:"Argument",index})}function AsyncIterator(items,options){return CreateType({[Kind]:"AsyncIterator",type:"AsyncIterator",items},options)}function Computed(target,parameters,options){return CreateType({[Kind]:"Computed",target,parameters},options)}function DiscardKey(value,key){const{[key]:_,...rest}=value;return rest}function Discard(value,keys){return keys.reduce((acc,key)=>DiscardKey(acc,key),value)}function Never(options){return CreateType({[Kind]:"Never",not:{}},options)}function MappedResult(properties){return CreateType({[Kind]:"MappedResult",properties})}function Constructor(parameters,returns,options){return CreateType({[Kind]:"Constructor",type:"Constructor",parameters,returns},options)}function Function(parameters,returns,options){return CreateType({[Kind]:"Function",type:"Function",parameters,returns},options)}function UnionCreate(T,options){return CreateType({[Kind]:"Union",anyOf:T},options)}function IsUnionOptional(types){return types.some(type=>IsOptional(type))}function RemoveOptionalFromRest(types){return types.map(left=>IsOptional(left)?RemoveOptionalFromType(left):left)}function RemoveOptionalFromType(T){return Discard(T,[OptionalKind])}function ResolveUnion(types,options){const isOptional=IsUnionOptional(types);return isOptional?Optional(UnionCreate(RemoveOptionalFromRest(types),options)):UnionCreate(RemoveOptionalFromRest(types),options)}function UnionEvaluated(T,options){return T.length===1?CreateType(T[0],options):T.length===0?Never(options):ResolveUnion(T,options)}function Union(types,options){return types.length===0?Never(options):types.length===1?CreateType(types[0],options):UnionCreate(types,options)}var TemplateLiteralParserError=class extends TypeBoxError{};function Unescape(pattern){return pattern.replace(/\\\$/g,"$").replace(/\\\*/g,"*").replace(/\\\^/g,"^").replace(/\\\|/g,"|").replace(/\\\(/g,"(").replace(/\\\)/g,")")}function IsNonEscaped(pattern,index,char){return pattern[index]===char&&pattern.charCodeAt(index-1)!==92}function IsOpenParen(pattern,index){return IsNonEscaped(pattern,index,"(")}function IsCloseParen(pattern,index){return IsNonEscaped(pattern,index,")")}function IsSeparator(pattern,index){return IsNonEscaped(pattern,index,"|")}function IsGroup(pattern){if(!(IsOpenParen(pattern,0)&&IsCloseParen(pattern,pattern.length-1)))return false;let count=0;for(let index=0;index<pattern.length;index++){if(IsOpenParen(pattern,index))count+=1;if(IsCloseParen(pattern,index))count-=1;if(count===0&&index!==pattern.length-1)return false}return true}function InGroup(pattern){return pattern.slice(1,pattern.length-1)}function IsPrecedenceOr(pattern){let count=0;for(let index=0;index<pattern.length;index++){if(IsOpenParen(pattern,index))count+=1;if(IsCloseParen(pattern,index))count-=1;if(IsSeparator(pattern,index)&&count===0)return true}return false}function IsPrecedenceAnd(pattern){for(let index=0;index<pattern.length;index++){if(IsOpenParen(pattern,index))return true}return false}function Or(pattern){let[count,start]=[0,0];const expressions=[];for(let index=0;index<pattern.length;index++){if(IsOpenParen(pattern,index))count+=1;if(IsCloseParen(pattern,index))count-=1;if(IsSeparator(pattern,index)&&count===0){const range2=pattern.slice(start,index);if(range2.length>0)expressions.push(TemplateLiteralParse(range2));start=index+1}}const range=pattern.slice(start);if(range.length>0)expressions.push(TemplateLiteralParse(range));if(expressions.length===0)return{type:"const",const:""};if(expressions.length===1)return expressions[0];return{type:"or",expr:expressions}}function And(pattern){function Group(value,index){if(!IsOpenParen(value,index))throw new TemplateLiteralParserError(`TemplateLiteralParser: Index must point to open parens`);let count=0;for(let scan=index;scan<value.length;scan++){if(IsOpenParen(value,scan))count+=1;if(IsCloseParen(value,scan))count-=1;if(count===0)return[index,scan]}throw new TemplateLiteralParserError(`TemplateLiteralParser: Unclosed group parens in expression`)}function Range(pattern2,index){for(let scan=index;scan<pattern2.length;scan++){if(IsOpenParen(pattern2,scan))return[index,scan]}return[index,pattern2.length]}const expressions=[];for(let index=0;index<pattern.length;index++){if(IsOpenParen(pattern,index)){const[start,end]=Group(pattern,index);const range=pattern.slice(start,end+1);expressions.push(TemplateLiteralParse(range));index=end}else{const[start,end]=Range(pattern,index);const range=pattern.slice(start,end);if(range.length>0)expressions.push(TemplateLiteralParse(range));index=end-1}}return expressions.length===0?{type:"const",const:""}:expressions.length===1?expressions[0]:{type:"and",expr:expressions}}function TemplateLiteralParse(pattern){return IsGroup(pattern)?TemplateLiteralParse(InGroup(pattern)):IsPrecedenceOr(pattern)?Or(pattern):IsPrecedenceAnd(pattern)?And(pattern):{type:"const",const:Unescape(pattern)}}function TemplateLiteralParseExact(pattern){return TemplateLiteralParse(pattern.slice(1,pattern.length-1))}var TemplateLiteralFiniteError=class extends TypeBoxError{};function IsNumberExpression(expression){return expression.type==="or"&&expression.expr.length===2&&expression.expr[0].type==="const"&&expression.expr[0].const==="0"&&expression.expr[1].type==="const"&&expression.expr[1].const==="[1-9][0-9]*"}function IsBooleanExpression(expression){return expression.type==="or"&&expression.expr.length===2&&expression.expr[0].type==="const"&&expression.expr[0].const==="true"&&expression.expr[1].type==="const"&&expression.expr[1].const==="false"}function IsStringExpression(expression){return expression.type==="const"&&expression.const===".*"}function IsTemplateLiteralExpressionFinite(expression){return IsNumberExpression(expression)||IsStringExpression(expression)?false:IsBooleanExpression(expression)?true:expression.type==="and"?expression.expr.every(expr=>IsTemplateLiteralExpressionFinite(expr)):expression.type==="or"?expression.expr.every(expr=>IsTemplateLiteralExpressionFinite(expr)):expression.type==="const"?true:(()=>{throw new TemplateLiteralFiniteError(`Unknown expression type`)})()}function IsTemplateLiteralFinite(schema){const expression=TemplateLiteralParseExact(schema.pattern);return IsTemplateLiteralExpressionFinite(expression)}var TemplateLiteralGenerateError=class extends TypeBoxError{};function*GenerateReduce(buffer){if(buffer.length===1)return yield*buffer[0];for(const left of buffer[0]){for(const right of GenerateReduce(buffer.slice(1))){yield`${left}${right}`}}}function*GenerateAnd(expression){return yield*GenerateReduce(expression.expr.map(expr=>[...TemplateLiteralExpressionGenerate(expr)]))}function*GenerateOr(expression){for(const expr of expression.expr)yield*TemplateLiteralExpressionGenerate(expr)}function*GenerateConst(expression){return yield expression.const}function*TemplateLiteralExpressionGenerate(expression){return expression.type==="and"?yield*GenerateAnd(expression):expression.type==="or"?yield*GenerateOr(expression):expression.type==="const"?yield*GenerateConst(expression):(()=>{throw new TemplateLiteralGenerateError("Unknown expression")})()}function TemplateLiteralGenerate(schema){const expression=TemplateLiteralParseExact(schema.pattern);return IsTemplateLiteralExpressionFinite(expression)?[...TemplateLiteralExpressionGenerate(expression)]:[]}function Literal(value,options){return CreateType({[Kind]:"Literal",const:value,type:typeof value},options)}function Boolean2(options){return CreateType({[Kind]:"Boolean",type:"boolean"},options)}function BigInt(options){return CreateType({[Kind]:"BigInt",type:"bigint"},options)}function Number2(options){return CreateType({[Kind]:"Number",type:"number"},options)}function String2(options){return CreateType({[Kind]:"String",type:"string"},options)}function*FromUnion(syntax){const trim=syntax.trim().replace(/"|'/g,"");return trim==="boolean"?yield Boolean2():trim==="number"?yield Number2():trim==="bigint"?yield BigInt():trim==="string"?yield String2():yield(()=>{const literals=trim.split("|").map(literal=>Literal(literal.trim()));return literals.length===0?Never():literals.length===1?literals[0]:UnionEvaluated(literals)})()}function*FromTerminal(syntax){if(syntax[1]!=="{"){const L=Literal("$");const R=FromSyntax(syntax.slice(1));return yield*[L,...R]}for(let i=2;i<syntax.length;i++){if(syntax[i]==="}"){const L=FromUnion(syntax.slice(2,i));const R=FromSyntax(syntax.slice(i+1));return yield*[...L,...R]}}yield Literal(syntax)}function*FromSyntax(syntax){for(let i=0;i<syntax.length;i++){if(syntax[i]==="$"){const L=Literal(syntax.slice(0,i));const R=FromTerminal(syntax.slice(i));return yield*[L,...R]}}yield Literal(syntax)}function TemplateLiteralSyntax(syntax){return[...FromSyntax(syntax)]}var TemplateLiteralPatternError=class extends TypeBoxError{};function Escape(value){return value.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Visit2(schema,acc){return IsTemplateLiteral(schema)?schema.pattern.slice(1,schema.pattern.length-1):IsUnion(schema)?`(${schema.anyOf.map(schema2=>Visit2(schema2,acc)).join("|")})`:IsNumber3(schema)?`${acc}${PatternNumber}`:IsInteger(schema)?`${acc}${PatternNumber}`:IsBigInt2(schema)?`${acc}${PatternNumber}`:IsString2(schema)?`${acc}${PatternString}`:IsLiteral(schema)?`${acc}${Escape(schema.const.toString())}`:IsBoolean2(schema)?`${acc}${PatternBoolean}`:(()=>{throw new TemplateLiteralPatternError(`Unexpected Kind '${schema[Kind]}'`)})()}function TemplateLiteralPattern(kinds){return`^${kinds.map(schema=>Visit2(schema,"")).join("")}$`}function TemplateLiteralToUnion(schema){const R=TemplateLiteralGenerate(schema);const L=R.map(S=>Literal(S));return UnionEvaluated(L)}function TemplateLiteral(unresolved,options){const pattern=IsString(unresolved)?TemplateLiteralPattern(TemplateLiteralSyntax(unresolved)):TemplateLiteralPattern(unresolved);return CreateType({[Kind]:"TemplateLiteral",type:"string",pattern},options)}function FromTemplateLiteral(templateLiteral){const keys=TemplateLiteralGenerate(templateLiteral);return keys.map(key=>key.toString())}function FromUnion2(types){const result=[];for(const type of types)result.push(...IndexPropertyKeys(type));return result}function FromLiteral(literalValue){return[literalValue.toString()]}function IndexPropertyKeys(type){return[...new Set(IsTemplateLiteral(type)?FromTemplateLiteral(type):IsUnion(type)?FromUnion2(type.anyOf):IsLiteral(type)?FromLiteral(type.const):IsNumber3(type)?["[number]"]:IsInteger(type)?["[number]"]:[])]}function FromProperties(type,properties,options){const result={};for(const K2 of Object.getOwnPropertyNames(properties)){result[K2]=Index(type,IndexPropertyKeys(properties[K2]),options)}return result}function FromMappedResult(type,mappedResult,options){return FromProperties(type,mappedResult.properties,options)}function IndexFromMappedResult(type,mappedResult,options){const properties=FromMappedResult(type,mappedResult,options);return MappedResult(properties)}function FromRest(types,key){return types.map(type=>IndexFromPropertyKey(type,key))}function FromIntersectRest(types){return types.filter(type=>!IsNever(type))}function FromIntersect(types,key){return IntersectEvaluated(FromIntersectRest(FromRest(types,key)))}function FromUnionRest(types){return types.some(L=>IsNever(L))?[]:types}function FromUnion3(types,key){return UnionEvaluated(FromUnionRest(FromRest(types,key)))}function FromTuple(types,key){return key in types?types[key]:key==="[number]"?UnionEvaluated(types):Never()}function FromArray(type,key){return key==="[number]"?type:Never()}function FromProperty(properties,propertyKey){return propertyKey in properties?properties[propertyKey]:Never()}function IndexFromPropertyKey(type,propertyKey){return IsIntersect(type)?FromIntersect(type.allOf,propertyKey):IsUnion(type)?FromUnion3(type.anyOf,propertyKey):IsTuple(type)?FromTuple(type.items??[],propertyKey):IsArray3(type)?FromArray(type.items,propertyKey):IsObject3(type)?FromProperty(type.properties,propertyKey):Never()}function IndexFromPropertyKeys(type,propertyKeys){return propertyKeys.map(propertyKey=>IndexFromPropertyKey(type,propertyKey))}function FromSchema(type,propertyKeys){return UnionEvaluated(IndexFromPropertyKeys(type,propertyKeys))}function Index(type,key,options){if(IsRef(type)||IsRef(key)){const error=`Index types using Ref parameters require both Type and Key to be of TSchema`;if(!IsSchema(type)||!IsSchema(key))throw new TypeBoxError(error);return Computed("Index",[type,key])}if(IsMappedResult(key))return IndexFromMappedResult(type,key,options);if(IsMappedKey(key))return IndexFromMappedKey(type,key,options);return CreateType(IsSchema(key)?FromSchema(type,IndexPropertyKeys(key)):FromSchema(type,key),options)}function MappedIndexPropertyKey(type,key,options){return{[key]:Index(type,[key],Clone(options))}}function MappedIndexPropertyKeys(type,propertyKeys,options){return propertyKeys.reduce((result,left)=>{return{...result,...MappedIndexPropertyKey(type,left,options)}},{})}function MappedIndexProperties(type,mappedKey,options){return MappedIndexPropertyKeys(type,mappedKey.keys,options)}function IndexFromMappedKey(type,mappedKey,options){const properties=MappedIndexProperties(type,mappedKey,options);return MappedResult(properties)}function Iterator(items,options){return CreateType({[Kind]:"Iterator",type:"Iterator",items},options)}function RequiredArray(properties){return globalThis.Object.keys(properties).filter(key=>!IsOptional(properties[key]))}function _Object(properties,options){const required=RequiredArray(properties);const schema=required.length>0?{[Kind]:"Object",type:"object",required,properties}:{[Kind]:"Object",type:"object",properties};return CreateType(schema,options)}var Object2=_Object;function Promise2(item,options){return CreateType({[Kind]:"Promise",type:"Promise",item},options)}function RemoveReadonly(schema){return CreateType(Discard(schema,[ReadonlyKind]))}function AddReadonly(schema){return CreateType({...schema,[ReadonlyKind]:"Readonly"})}function ReadonlyWithFlag(schema,F){return F===false?RemoveReadonly(schema):AddReadonly(schema)}function Readonly(schema,enable){const F=enable??true;return IsMappedResult(schema)?ReadonlyFromMappedResult(schema,F):ReadonlyWithFlag(schema,F)}function FromProperties2(K,F){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(K))Acc[K2]=Readonly(K[K2],F);return Acc}function FromMappedResult2(R,F){return FromProperties2(R.properties,F)}function ReadonlyFromMappedResult(R,F){const P=FromMappedResult2(R,F);return MappedResult(P)}function Tuple(types,options){return CreateType(types.length>0?{[Kind]:"Tuple",type:"array",items:types,additionalItems:false,minItems:types.length,maxItems:types.length}:{[Kind]:"Tuple",type:"array",minItems:types.length,maxItems:types.length},options)}function FromMappedResult3(K,P){return K in P?FromSchemaType(K,P[K]):MappedResult(P)}function MappedKeyToKnownMappedResultProperties(K){return{[K]:Literal(K)}}function MappedKeyToUnknownMappedResultProperties(P){const Acc={};for(const L of P)Acc[L]=Literal(L);return Acc}function MappedKeyToMappedResultProperties(K,P){return SetIncludes(P,K)?MappedKeyToKnownMappedResultProperties(K):MappedKeyToUnknownMappedResultProperties(P)}function FromMappedKey(K,P){const R=MappedKeyToMappedResultProperties(K,P);return FromMappedResult3(K,R)}function FromRest2(K,T){return T.map(L=>FromSchemaType(K,L))}function FromProperties3(K,T){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(T))Acc[K2]=FromSchemaType(K,T[K2]);return Acc}function FromSchemaType(K,T){const options={...T};return IsOptional(T)?Optional(FromSchemaType(K,Discard(T,[OptionalKind]))):IsReadonly(T)?Readonly(FromSchemaType(K,Discard(T,[ReadonlyKind]))):IsMappedResult(T)?FromMappedResult3(K,T.properties):IsMappedKey(T)?FromMappedKey(K,T.keys):IsConstructor(T)?Constructor(FromRest2(K,T.parameters),FromSchemaType(K,T.returns),options):IsFunction2(T)?Function(FromRest2(K,T.parameters),FromSchemaType(K,T.returns),options):IsAsyncIterator2(T)?AsyncIterator(FromSchemaType(K,T.items),options):IsIterator2(T)?Iterator(FromSchemaType(K,T.items),options):IsIntersect(T)?Intersect(FromRest2(K,T.allOf),options):IsUnion(T)?Union(FromRest2(K,T.anyOf),options):IsTuple(T)?Tuple(FromRest2(K,T.items??[]),options):IsObject3(T)?Object2(FromProperties3(K,T.properties),options):IsArray3(T)?Array2(FromSchemaType(K,T.items),options):IsPromise(T)?Promise2(FromSchemaType(K,T.item),options):T}function MappedFunctionReturnType(K,T){const Acc={};for(const L of K)Acc[L]=FromSchemaType(L,T);return Acc}function Mapped(key,map,options){const K=IsSchema(key)?IndexPropertyKeys(key):key;const RT=map({[Kind]:"MappedKey",keys:K});const R=MappedFunctionReturnType(K,RT);return Object2(R,options)}function RemoveOptional(schema){return CreateType(Discard(schema,[OptionalKind]))}function AddOptional(schema){return CreateType({...schema,[OptionalKind]:"Optional"})}function OptionalWithFlag(schema,F){return F===false?RemoveOptional(schema):AddOptional(schema)}function Optional(schema,enable){const F=enable??true;return IsMappedResult(schema)?OptionalFromMappedResult(schema,F):OptionalWithFlag(schema,F)}function FromProperties4(P,F){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(P))Acc[K2]=Optional(P[K2],F);return Acc}function FromMappedResult4(R,F){return FromProperties4(R.properties,F)}function OptionalFromMappedResult(R,F){const P=FromMappedResult4(R,F);return MappedResult(P)}function IntersectCreate(T,options={}){const allObjects=T.every(schema=>IsObject3(schema));const clonedUnevaluatedProperties=IsSchema(options.unevaluatedProperties)?{unevaluatedProperties:options.unevaluatedProperties}:{};return CreateType(options.unevaluatedProperties===false||IsSchema(options.unevaluatedProperties)||allObjects?{...clonedUnevaluatedProperties,[Kind]:"Intersect",type:"object",allOf:T}:{...clonedUnevaluatedProperties,[Kind]:"Intersect",allOf:T},options)}function IsIntersectOptional(types){return types.every(left=>IsOptional(left))}function RemoveOptionalFromType2(type){return Discard(type,[OptionalKind])}function RemoveOptionalFromRest2(types){return types.map(left=>IsOptional(left)?RemoveOptionalFromType2(left):left)}function ResolveIntersect(types,options){return IsIntersectOptional(types)?Optional(IntersectCreate(RemoveOptionalFromRest2(types),options)):IntersectCreate(RemoveOptionalFromRest2(types),options)}function IntersectEvaluated(types,options={}){if(types.length===1)return CreateType(types[0],options);if(types.length===0)return Never(options);if(types.some(schema=>IsTransform(schema)))throw new Error("Cannot intersect transform types");return ResolveIntersect(types,options)}function Intersect(types,options){if(types.length===1)return CreateType(types[0],options);if(types.length===0)return Never(options);if(types.some(schema=>IsTransform(schema)))throw new Error("Cannot intersect transform types");return IntersectCreate(types,options)}function Ref(...args){const[$ref,options]=typeof args[0]==="string"?[args[0],args[1]]:[args[0].$id,args[1]];if(typeof $ref!=="string")throw new TypeBoxError("Ref: $ref must be a string");return CreateType({[Kind]:"Ref",$ref},options)}function FromComputed(target,parameters){return Computed("Awaited",[Computed(target,parameters)])}function FromRef($ref){return Computed("Awaited",[Ref($ref)])}function FromIntersect2(types){return Intersect(FromRest3(types))}function FromUnion4(types){return Union(FromRest3(types))}function FromPromise(type){return Awaited(type)}function FromRest3(types){return types.map(type=>Awaited(type))}function Awaited(type,options){return CreateType(IsComputed(type)?FromComputed(type.target,type.parameters):IsIntersect(type)?FromIntersect2(type.allOf):IsUnion(type)?FromUnion4(type.anyOf):IsPromise(type)?FromPromise(type.item):IsRef(type)?FromRef(type.$ref):type,options)}function FromRest4(types){const result=[];for(const L of types)result.push(KeyOfPropertyKeys(L));return result}function FromIntersect3(types){const propertyKeysArray=FromRest4(types);const propertyKeys=SetUnionMany(propertyKeysArray);return propertyKeys}function FromUnion5(types){const propertyKeysArray=FromRest4(types);const propertyKeys=SetIntersectMany(propertyKeysArray);return propertyKeys}function FromTuple2(types){return types.map((_,indexer)=>indexer.toString())}function FromArray2(_){return["[number]"]}function FromProperties5(T){return globalThis.Object.getOwnPropertyNames(T)}function FromPatternProperties(patternProperties){if(!includePatternProperties)return[];const patternPropertyKeys=globalThis.Object.getOwnPropertyNames(patternProperties);return patternPropertyKeys.map(key=>{return key[0]==="^"&&key[key.length-1]==="$"?key.slice(1,key.length-1):key})}function KeyOfPropertyKeys(type){return IsIntersect(type)?FromIntersect3(type.allOf):IsUnion(type)?FromUnion5(type.anyOf):IsTuple(type)?FromTuple2(type.items??[]):IsArray3(type)?FromArray2(type.items):IsObject3(type)?FromProperties5(type.properties):IsRecord(type)?FromPatternProperties(type.patternProperties):[]}var includePatternProperties=false;function FromComputed2(target,parameters){return Computed("KeyOf",[Computed(target,parameters)])}function FromRef2($ref){return Computed("KeyOf",[Ref($ref)])}function KeyOfFromType(type,options){const propertyKeys=KeyOfPropertyKeys(type);const propertyKeyTypes=KeyOfPropertyKeysToRest(propertyKeys);const result=UnionEvaluated(propertyKeyTypes);return CreateType(result,options)}function KeyOfPropertyKeysToRest(propertyKeys){return propertyKeys.map(L=>L==="[number]"?Number2():Literal(L))}function KeyOf(type,options){return IsComputed(type)?FromComputed2(type.target,type.parameters):IsRef(type)?FromRef2(type.$ref):IsMappedResult(type)?KeyOfFromMappedResult(type,options):KeyOfFromType(type,options)}function FromProperties6(properties,options){const result={};for(const K2 of globalThis.Object.getOwnPropertyNames(properties))result[K2]=KeyOf(properties[K2],Clone(options));return result}function FromMappedResult5(mappedResult,options){return FromProperties6(mappedResult.properties,options)}function KeyOfFromMappedResult(mappedResult,options){const properties=FromMappedResult5(mappedResult,options);return MappedResult(properties)}function CompositeKeys(T){const Acc=[];for(const L of T)Acc.push(...KeyOfPropertyKeys(L));return SetDistinct(Acc)}function FilterNever(T){return T.filter(L=>!IsNever(L))}function CompositeProperty(T,K){const Acc=[];for(const L of T)Acc.push(...IndexFromPropertyKeys(L,[K]));return FilterNever(Acc)}function CompositeProperties(T,K){const Acc={};for(const L of K){Acc[L]=IntersectEvaluated(CompositeProperty(T,L))}return Acc}function Composite(T,options){const K=CompositeKeys(T);const P=CompositeProperties(T,K);const R=Object2(P,options);return R}function Date2(options){return CreateType({[Kind]:"Date",type:"Date"},options)}function Null(options){return CreateType({[Kind]:"Null",type:"null"},options)}function Symbol2(options){return CreateType({[Kind]:"Symbol",type:"symbol"},options)}function Undefined(options){return CreateType({[Kind]:"Undefined",type:"undefined"},options)}function Uint8Array2(options){return CreateType({[Kind]:"Uint8Array",type:"Uint8Array"},options)}function Unknown(options){return CreateType({[Kind]:"Unknown"},options)}function FromArray3(T){return T.map(L=>FromValue(L,false))}function FromProperties7(value){const Acc={};for(const K of globalThis.Object.getOwnPropertyNames(value))Acc[K]=Readonly(FromValue(value[K],false));return Acc}function ConditionalReadonly(T,root){return root===true?T:Readonly(T)}function FromValue(value,root){return IsAsyncIterator(value)?ConditionalReadonly(Any(),root):IsIterator(value)?ConditionalReadonly(Any(),root):IsArray(value)?Readonly(Tuple(FromArray3(value))):IsUint8Array(value)?Uint8Array2():IsDate(value)?Date2():IsObject(value)?ConditionalReadonly(Object2(FromProperties7(value)),root):IsFunction(value)?ConditionalReadonly(Function([],Unknown()),root):IsUndefined(value)?Undefined():IsNull(value)?Null():IsSymbol(value)?Symbol2():IsBigInt(value)?BigInt():IsNumber(value)?Literal(value):IsBoolean(value)?Literal(value):IsString(value)?Literal(value):Object2({})}function Const(T,options){return CreateType(FromValue(T,true),options)}function ConstructorParameters(schema,options){return IsConstructor(schema)?Tuple(schema.parameters,options):Never(options)}function Enum(item,options){if(IsUndefined(item))throw new Error("Enum undefined or empty");const values1=globalThis.Object.getOwnPropertyNames(item).filter(key=>isNaN(key)).map(key=>item[key]);const values2=[...new Set(values1)];const anyOf=values2.map(value=>Literal(value));return Union(anyOf,{...options,[Hint]:"Enum"})}var ExtendsResolverError=class extends TypeBoxError{};var ExtendsResult;(function(ExtendsResult2){ExtendsResult2[ExtendsResult2["Union"]=0]="Union";ExtendsResult2[ExtendsResult2["True"]=1]="True";ExtendsResult2[ExtendsResult2["False"]=2]="False"})(ExtendsResult||(ExtendsResult={}));function IntoBooleanResult(result){return result===ExtendsResult.False?result:ExtendsResult.True}function Throw(message){throw new ExtendsResolverError(message)}function IsStructuralRight(right){return type_exports.IsNever(right)||type_exports.IsIntersect(right)||type_exports.IsUnion(right)||type_exports.IsUnknown(right)||type_exports.IsAny(right)}function StructuralRight(left,right){return type_exports.IsNever(right)?FromNeverRight(left,right):type_exports.IsIntersect(right)?FromIntersectRight(left,right):type_exports.IsUnion(right)?FromUnionRight(left,right):type_exports.IsUnknown(right)?FromUnknownRight(left,right):type_exports.IsAny(right)?FromAnyRight(left,right):Throw("StructuralRight")}function FromAnyRight(left,right){return ExtendsResult.True}function FromAny(left,right){return type_exports.IsIntersect(right)?FromIntersectRight(left,right):type_exports.IsUnion(right)&&right.anyOf.some(schema=>type_exports.IsAny(schema)||type_exports.IsUnknown(schema))?ExtendsResult.True:type_exports.IsUnion(right)?ExtendsResult.Union:type_exports.IsUnknown(right)?ExtendsResult.True:type_exports.IsAny(right)?ExtendsResult.True:ExtendsResult.Union}function FromArrayRight(left,right){return type_exports.IsUnknown(left)?ExtendsResult.False:type_exports.IsAny(left)?ExtendsResult.Union:type_exports.IsNever(left)?ExtendsResult.True:ExtendsResult.False}function FromArray4(left,right){return type_exports.IsObject(right)&&IsObjectArrayLike(right)?ExtendsResult.True:IsStructuralRight(right)?StructuralRight(left,right):!type_exports.IsArray(right)?ExtendsResult.False:IntoBooleanResult(Visit3(left.items,right.items))}function FromAsyncIterator(left,right){return IsStructuralRight(right)?StructuralRight(left,right):!type_exports.IsAsyncIterator(right)?ExtendsResult.False:IntoBooleanResult(Visit3(left.items,right.items))}function FromBigInt(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsBigInt(right)?ExtendsResult.True:ExtendsResult.False}function FromBooleanRight(left,right){return type_exports.IsLiteralBoolean(left)?ExtendsResult.True:type_exports.IsBoolean(left)?ExtendsResult.True:ExtendsResult.False}function FromBoolean(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsBoolean(right)?ExtendsResult.True:ExtendsResult.False}function FromConstructor(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):!type_exports.IsConstructor(right)?ExtendsResult.False:left.parameters.length>right.parameters.length?ExtendsResult.False:!left.parameters.every((schema,index)=>IntoBooleanResult(Visit3(right.parameters[index],schema))===ExtendsResult.True)?ExtendsResult.False:IntoBooleanResult(Visit3(left.returns,right.returns))}function FromDate(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsDate(right)?ExtendsResult.True:ExtendsResult.False}function FromFunction(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):!type_exports.IsFunction(right)?ExtendsResult.False:left.parameters.length>right.parameters.length?ExtendsResult.False:!left.parameters.every((schema,index)=>IntoBooleanResult(Visit3(right.parameters[index],schema))===ExtendsResult.True)?ExtendsResult.False:IntoBooleanResult(Visit3(left.returns,right.returns))}function FromIntegerRight(left,right){return type_exports.IsLiteral(left)&&value_exports.IsNumber(left.const)?ExtendsResult.True:type_exports.IsNumber(left)||type_exports.IsInteger(left)?ExtendsResult.True:ExtendsResult.False}function FromInteger(left,right){return type_exports.IsInteger(right)||type_exports.IsNumber(right)?ExtendsResult.True:IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):ExtendsResult.False}function FromIntersectRight(left,right){return right.allOf.every(schema=>Visit3(left,schema)===ExtendsResult.True)?ExtendsResult.True:ExtendsResult.False}function FromIntersect4(left,right){return left.allOf.some(schema=>Visit3(schema,right)===ExtendsResult.True)?ExtendsResult.True:ExtendsResult.False}function FromIterator(left,right){return IsStructuralRight(right)?StructuralRight(left,right):!type_exports.IsIterator(right)?ExtendsResult.False:IntoBooleanResult(Visit3(left.items,right.items))}function FromLiteral2(left,right){return type_exports.IsLiteral(right)&&right.const===left.const?ExtendsResult.True:IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsString(right)?FromStringRight(left,right):type_exports.IsNumber(right)?FromNumberRight(left,right):type_exports.IsInteger(right)?FromIntegerRight(left,right):type_exports.IsBoolean(right)?FromBooleanRight(left,right):ExtendsResult.False}function FromNeverRight(left,right){return ExtendsResult.False}function FromNever(left,right){return ExtendsResult.True}function UnwrapTNot(schema){let[current,depth]=[schema,0];while(true){if(!type_exports.IsNot(current))break;current=current.not;depth+=1}return depth%2===0?current:Unknown()}function FromNot(left,right){return type_exports.IsNot(left)?Visit3(UnwrapTNot(left),right):type_exports.IsNot(right)?Visit3(left,UnwrapTNot(right)):Throw("Invalid fallthrough for Not")}function FromNull(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsNull(right)?ExtendsResult.True:ExtendsResult.False}function FromNumberRight(left,right){return type_exports.IsLiteralNumber(left)?ExtendsResult.True:type_exports.IsNumber(left)||type_exports.IsInteger(left)?ExtendsResult.True:ExtendsResult.False}function FromNumber(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsInteger(right)||type_exports.IsNumber(right)?ExtendsResult.True:ExtendsResult.False}function IsObjectPropertyCount(schema,count){return Object.getOwnPropertyNames(schema.properties).length===count}function IsObjectStringLike(schema){return IsObjectArrayLike(schema)}function IsObjectSymbolLike(schema){return IsObjectPropertyCount(schema,0)||IsObjectPropertyCount(schema,1)&&"description"in schema.properties&&type_exports.IsUnion(schema.properties.description)&&schema.properties.description.anyOf.length===2&&(type_exports.IsString(schema.properties.description.anyOf[0])&&type_exports.IsUndefined(schema.properties.description.anyOf[1])||type_exports.IsString(schema.properties.description.anyOf[1])&&type_exports.IsUndefined(schema.properties.description.anyOf[0]))}function IsObjectNumberLike(schema){return IsObjectPropertyCount(schema,0)}function IsObjectBooleanLike(schema){return IsObjectPropertyCount(schema,0)}function IsObjectBigIntLike(schema){return IsObjectPropertyCount(schema,0)}function IsObjectDateLike(schema){return IsObjectPropertyCount(schema,0)}function IsObjectUint8ArrayLike(schema){return IsObjectArrayLike(schema)}function IsObjectFunctionLike(schema){const length=Number2();return IsObjectPropertyCount(schema,0)||IsObjectPropertyCount(schema,1)&&"length"in schema.properties&&IntoBooleanResult(Visit3(schema.properties["length"],length))===ExtendsResult.True}function IsObjectConstructorLike(schema){return IsObjectPropertyCount(schema,0)}function IsObjectArrayLike(schema){const length=Number2();return IsObjectPropertyCount(schema,0)||IsObjectPropertyCount(schema,1)&&"length"in schema.properties&&IntoBooleanResult(Visit3(schema.properties["length"],length))===ExtendsResult.True}function IsObjectPromiseLike(schema){const then=Function([Any()],Any());return IsObjectPropertyCount(schema,0)||IsObjectPropertyCount(schema,1)&&"then"in schema.properties&&IntoBooleanResult(Visit3(schema.properties["then"],then))===ExtendsResult.True}function Property(left,right){return Visit3(left,right)===ExtendsResult.False?ExtendsResult.False:type_exports.IsOptional(left)&&!type_exports.IsOptional(right)?ExtendsResult.False:ExtendsResult.True}function FromObjectRight(left,right){return type_exports.IsUnknown(left)?ExtendsResult.False:type_exports.IsAny(left)?ExtendsResult.Union:type_exports.IsNever(left)||type_exports.IsLiteralString(left)&&IsObjectStringLike(right)||type_exports.IsLiteralNumber(left)&&IsObjectNumberLike(right)||type_exports.IsLiteralBoolean(left)&&IsObjectBooleanLike(right)||type_exports.IsSymbol(left)&&IsObjectSymbolLike(right)||type_exports.IsBigInt(left)&&IsObjectBigIntLike(right)||type_exports.IsString(left)&&IsObjectStringLike(right)||type_exports.IsSymbol(left)&&IsObjectSymbolLike(right)||type_exports.IsNumber(left)&&IsObjectNumberLike(right)||type_exports.IsInteger(left)&&IsObjectNumberLike(right)||type_exports.IsBoolean(left)&&IsObjectBooleanLike(right)||type_exports.IsUint8Array(left)&&IsObjectUint8ArrayLike(right)||type_exports.IsDate(left)&&IsObjectDateLike(right)||type_exports.IsConstructor(left)&&IsObjectConstructorLike(right)||type_exports.IsFunction(left)&&IsObjectFunctionLike(right)?ExtendsResult.True:type_exports.IsRecord(left)&&type_exports.IsString(RecordKey(left))?(()=>{return right[Hint]==="Record"?ExtendsResult.True:ExtendsResult.False})():type_exports.IsRecord(left)&&type_exports.IsNumber(RecordKey(left))?(()=>{return IsObjectPropertyCount(right,0)?ExtendsResult.True:ExtendsResult.False})():ExtendsResult.False}function FromObject(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):!type_exports.IsObject(right)?ExtendsResult.False:(()=>{for(const key of Object.getOwnPropertyNames(right.properties)){if(!(key in left.properties)&&!type_exports.IsOptional(right.properties[key])){return ExtendsResult.False}if(type_exports.IsOptional(right.properties[key])){return ExtendsResult.True}if(Property(left.properties[key],right.properties[key])===ExtendsResult.False){return ExtendsResult.False}}return ExtendsResult.True})()}function FromPromise2(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)&&IsObjectPromiseLike(right)?ExtendsResult.True:!type_exports.IsPromise(right)?ExtendsResult.False:IntoBooleanResult(Visit3(left.item,right.item))}function RecordKey(schema){return PatternNumberExact in schema.patternProperties?Number2():PatternStringExact in schema.patternProperties?String2():Throw("Unknown record key pattern")}function RecordValue(schema){return PatternNumberExact in schema.patternProperties?schema.patternProperties[PatternNumberExact]:PatternStringExact in schema.patternProperties?schema.patternProperties[PatternStringExact]:Throw("Unable to get record value schema")}function FromRecordRight(left,right){const[Key,Value]=[RecordKey(right),RecordValue(right)];return type_exports.IsLiteralString(left)&&type_exports.IsNumber(Key)&&IntoBooleanResult(Visit3(left,Value))===ExtendsResult.True?ExtendsResult.True:type_exports.IsUint8Array(left)&&type_exports.IsNumber(Key)?Visit3(left,Value):type_exports.IsString(left)&&type_exports.IsNumber(Key)?Visit3(left,Value):type_exports.IsArray(left)&&type_exports.IsNumber(Key)?Visit3(left,Value):type_exports.IsObject(left)?(()=>{for(const key of Object.getOwnPropertyNames(left.properties)){if(Property(Value,left.properties[key])===ExtendsResult.False){return ExtendsResult.False}}return ExtendsResult.True})():ExtendsResult.False}function FromRecord(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):!type_exports.IsRecord(right)?ExtendsResult.False:Visit3(RecordValue(left),RecordValue(right))}function FromRegExp(left,right){const L=type_exports.IsRegExp(left)?String2():left;const R=type_exports.IsRegExp(right)?String2():right;return Visit3(L,R)}function FromStringRight(left,right){return type_exports.IsLiteral(left)&&value_exports.IsString(left.const)?ExtendsResult.True:type_exports.IsString(left)?ExtendsResult.True:ExtendsResult.False}function FromString(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsString(right)?ExtendsResult.True:ExtendsResult.False}function FromSymbol(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsSymbol(right)?ExtendsResult.True:ExtendsResult.False}function FromTemplateLiteral2(left,right){return type_exports.IsTemplateLiteral(left)?Visit3(TemplateLiteralToUnion(left),right):type_exports.IsTemplateLiteral(right)?Visit3(left,TemplateLiteralToUnion(right)):Throw("Invalid fallthrough for TemplateLiteral")}function IsArrayOfTuple(left,right){return type_exports.IsArray(right)&&left.items!==void 0&&left.items.every(schema=>Visit3(schema,right.items)===ExtendsResult.True)}function FromTupleRight(left,right){return type_exports.IsNever(left)?ExtendsResult.True:type_exports.IsUnknown(left)?ExtendsResult.False:type_exports.IsAny(left)?ExtendsResult.Union:ExtendsResult.False}function FromTuple3(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)&&IsObjectArrayLike(right)?ExtendsResult.True:type_exports.IsArray(right)&&IsArrayOfTuple(left,right)?ExtendsResult.True:!type_exports.IsTuple(right)?ExtendsResult.False:value_exports.IsUndefined(left.items)&&!value_exports.IsUndefined(right.items)||!value_exports.IsUndefined(left.items)&&value_exports.IsUndefined(right.items)?ExtendsResult.False:value_exports.IsUndefined(left.items)&&!value_exports.IsUndefined(right.items)?ExtendsResult.True:left.items.every((schema,index)=>Visit3(schema,right.items[index])===ExtendsResult.True)?ExtendsResult.True:ExtendsResult.False}function FromUint8Array(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsUint8Array(right)?ExtendsResult.True:ExtendsResult.False}function FromUndefined(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsVoid(right)?FromVoidRight(left,right):type_exports.IsUndefined(right)?ExtendsResult.True:ExtendsResult.False}function FromUnionRight(left,right){return right.anyOf.some(schema=>Visit3(left,schema)===ExtendsResult.True)?ExtendsResult.True:ExtendsResult.False}function FromUnion6(left,right){return left.anyOf.every(schema=>Visit3(schema,right)===ExtendsResult.True)?ExtendsResult.True:ExtendsResult.False}function FromUnknownRight(left,right){return ExtendsResult.True}function FromUnknown(left,right){return type_exports.IsNever(right)?FromNeverRight(left,right):type_exports.IsIntersect(right)?FromIntersectRight(left,right):type_exports.IsUnion(right)?FromUnionRight(left,right):type_exports.IsAny(right)?FromAnyRight(left,right):type_exports.IsString(right)?FromStringRight(left,right):type_exports.IsNumber(right)?FromNumberRight(left,right):type_exports.IsInteger(right)?FromIntegerRight(left,right):type_exports.IsBoolean(right)?FromBooleanRight(left,right):type_exports.IsArray(right)?FromArrayRight(left,right):type_exports.IsTuple(right)?FromTupleRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsUnknown(right)?ExtendsResult.True:ExtendsResult.False}function FromVoidRight(left,right){return type_exports.IsUndefined(left)?ExtendsResult.True:type_exports.IsUndefined(left)?ExtendsResult.True:ExtendsResult.False}function FromVoid(left,right){return type_exports.IsIntersect(right)?FromIntersectRight(left,right):type_exports.IsUnion(right)?FromUnionRight(left,right):type_exports.IsUnknown(right)?FromUnknownRight(left,right):type_exports.IsAny(right)?FromAnyRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsVoid(right)?ExtendsResult.True:ExtendsResult.False}function Visit3(left,right){return type_exports.IsTemplateLiteral(left)||type_exports.IsTemplateLiteral(right)?FromTemplateLiteral2(left,right):type_exports.IsRegExp(left)||type_exports.IsRegExp(right)?FromRegExp(left,right):type_exports.IsNot(left)||type_exports.IsNot(right)?FromNot(left,right):type_exports.IsAny(left)?FromAny(left,right):type_exports.IsArray(left)?FromArray4(left,right):type_exports.IsBigInt(left)?FromBigInt(left,right):type_exports.IsBoolean(left)?FromBoolean(left,right):type_exports.IsAsyncIterator(left)?FromAsyncIterator(left,right):type_exports.IsConstructor(left)?FromConstructor(left,right):type_exports.IsDate(left)?FromDate(left,right):type_exports.IsFunction(left)?FromFunction(left,right):type_exports.IsInteger(left)?FromInteger(left,right):type_exports.IsIntersect(left)?FromIntersect4(left,right):type_exports.IsIterator(left)?FromIterator(left,right):type_exports.IsLiteral(left)?FromLiteral2(left,right):type_exports.IsNever(left)?FromNever(left,right):type_exports.IsNull(left)?FromNull(left,right):type_exports.IsNumber(left)?FromNumber(left,right):type_exports.IsObject(left)?FromObject(left,right):type_exports.IsRecord(left)?FromRecord(left,right):type_exports.IsString(left)?FromString(left,right):type_exports.IsSymbol(left)?FromSymbol(left,right):type_exports.IsTuple(left)?FromTuple3(left,right):type_exports.IsPromise(left)?FromPromise2(left,right):type_exports.IsUint8Array(left)?FromUint8Array(left,right):type_exports.IsUndefined(left)?FromUndefined(left,right):type_exports.IsUnion(left)?FromUnion6(left,right):type_exports.IsUnknown(left)?FromUnknown(left,right):type_exports.IsVoid(left)?FromVoid(left,right):Throw(`Unknown left type operand '${left[Kind]}'`)}function ExtendsCheck(left,right){return Visit3(left,right)}function FromProperties8(P,Right,True,False,options){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(P))Acc[K2]=Extends(P[K2],Right,True,False,Clone(options));return Acc}function FromMappedResult6(Left,Right,True,False,options){return FromProperties8(Left.properties,Right,True,False,options)}function ExtendsFromMappedResult(Left,Right,True,False,options){const P=FromMappedResult6(Left,Right,True,False,options);return MappedResult(P)}function ExtendsResolve(left,right,trueType,falseType){const R=ExtendsCheck(left,right);return R===ExtendsResult.Union?Union([trueType,falseType]):R===ExtendsResult.True?trueType:falseType}function Extends(L,R,T,F,options){return IsMappedResult(L)?ExtendsFromMappedResult(L,R,T,F,options):IsMappedKey(L)?CreateType(ExtendsFromMappedKey(L,R,T,F,options)):CreateType(ExtendsResolve(L,R,T,F),options)}function FromPropertyKey(K,U,L,R,options){return{[K]:Extends(Literal(K),U,L,R,Clone(options))}}function FromPropertyKeys(K,U,L,R,options){return K.reduce((Acc,LK)=>{return{...Acc,...FromPropertyKey(LK,U,L,R,options)}},{})}function FromMappedKey2(K,U,L,R,options){return FromPropertyKeys(K.keys,U,L,R,options)}function ExtendsFromMappedKey(T,U,L,R,options){const P=FromMappedKey2(T,U,L,R,options);return MappedResult(P)}function ExcludeFromTemplateLiteral(L,R){return Exclude(TemplateLiteralToUnion(L),R)}function ExcludeRest(L,R){const excluded=L.filter(inner=>ExtendsCheck(inner,R)===ExtendsResult.False);return excluded.length===1?excluded[0]:Union(excluded)}function Exclude(L,R,options={}){if(IsTemplateLiteral(L))return CreateType(ExcludeFromTemplateLiteral(L,R),options);if(IsMappedResult(L))return CreateType(ExcludeFromMappedResult(L,R),options);return CreateType(IsUnion(L)?ExcludeRest(L.anyOf,R):ExtendsCheck(L,R)!==ExtendsResult.False?Never():L,options)}function FromProperties9(P,U){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(P))Acc[K2]=Exclude(P[K2],U);return Acc}function FromMappedResult7(R,T){return FromProperties9(R.properties,T)}function ExcludeFromMappedResult(R,T){const P=FromMappedResult7(R,T);return MappedResult(P)}function ExtractFromTemplateLiteral(L,R){return Extract(TemplateLiteralToUnion(L),R)}function ExtractRest(L,R){const extracted=L.filter(inner=>ExtendsCheck(inner,R)!==ExtendsResult.False);return extracted.length===1?extracted[0]:Union(extracted)}function Extract(L,R,options){if(IsTemplateLiteral(L))return CreateType(ExtractFromTemplateLiteral(L,R),options);if(IsMappedResult(L))return CreateType(ExtractFromMappedResult(L,R),options);return CreateType(IsUnion(L)?ExtractRest(L.anyOf,R):ExtendsCheck(L,R)!==ExtendsResult.False?L:Never(),options)}function FromProperties10(P,T){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(P))Acc[K2]=Extract(P[K2],T);return Acc}function FromMappedResult8(R,T){return FromProperties10(R.properties,T)}function ExtractFromMappedResult(R,T){const P=FromMappedResult8(R,T);return MappedResult(P)}function InstanceType(schema,options){return IsConstructor(schema)?CreateType(schema.returns,options):Never(options)}function ReadonlyOptional(schema){return Readonly(Optional(schema))}function RecordCreateFromPattern(pattern,T,options){return CreateType({[Kind]:"Record",type:"object",patternProperties:{[pattern]:T}},options)}function RecordCreateFromKeys(K,T,options){const result={};for(const K2 of K)result[K2]=T;return Object2(result,{...options,[Hint]:"Record"})}function FromTemplateLiteralKey(K,T,options){return IsTemplateLiteralFinite(K)?RecordCreateFromKeys(IndexPropertyKeys(K),T,options):RecordCreateFromPattern(K.pattern,T,options)}function FromUnionKey(key,type,options){return RecordCreateFromKeys(IndexPropertyKeys(Union(key)),type,options)}function FromLiteralKey(key,type,options){return RecordCreateFromKeys([key.toString()],type,options)}function FromRegExpKey(key,type,options){return RecordCreateFromPattern(key.source,type,options)}function FromStringKey(key,type,options){const pattern=IsUndefined(key.pattern)?PatternStringExact:key.pattern;return RecordCreateFromPattern(pattern,type,options)}function FromAnyKey(_,type,options){return RecordCreateFromPattern(PatternStringExact,type,options)}function FromNeverKey(_key,type,options){return RecordCreateFromPattern(PatternNeverExact,type,options)}function FromBooleanKey(_key,type,options){return Object2({true:type,false:type},options)}function FromIntegerKey(_key,type,options){return RecordCreateFromPattern(PatternNumberExact,type,options)}function FromNumberKey(_,type,options){return RecordCreateFromPattern(PatternNumberExact,type,options)}function Record(key,type,options={}){return IsUnion(key)?FromUnionKey(key.anyOf,type,options):IsTemplateLiteral(key)?FromTemplateLiteralKey(key,type,options):IsLiteral(key)?FromLiteralKey(key.const,type,options):IsBoolean2(key)?FromBooleanKey(key,type,options):IsInteger(key)?FromIntegerKey(key,type,options):IsNumber3(key)?FromNumberKey(key,type,options):IsRegExp2(key)?FromRegExpKey(key,type,options):IsString2(key)?FromStringKey(key,type,options):IsAny(key)?FromAnyKey(key,type,options):IsNever(key)?FromNeverKey(key,type,options):Never(options)}function RecordPattern(record){return globalThis.Object.getOwnPropertyNames(record.patternProperties)[0]}function RecordKey2(type){const pattern=RecordPattern(type);return pattern===PatternStringExact?String2():pattern===PatternNumberExact?Number2():String2({pattern})}function RecordValue2(type){return type.patternProperties[RecordPattern(type)]}function FromConstructor2(args,type){type.parameters=FromTypes(args,type.parameters);type.returns=FromType(args,type.returns);return type}function FromFunction2(args,type){type.parameters=FromTypes(args,type.parameters);type.returns=FromType(args,type.returns);return type}function FromIntersect5(args,type){type.allOf=FromTypes(args,type.allOf);return type}function FromUnion7(args,type){type.anyOf=FromTypes(args,type.anyOf);return type}function FromTuple4(args,type){if(IsUndefined(type.items))return type;type.items=FromTypes(args,type.items);return type}function FromArray5(args,type){type.items=FromType(args,type.items);return type}function FromAsyncIterator2(args,type){type.items=FromType(args,type.items);return type}function FromIterator2(args,type){type.items=FromType(args,type.items);return type}function FromPromise3(args,type){type.item=FromType(args,type.item);return type}function FromObject2(args,type){const mappedProperties=FromProperties11(args,type.properties);return{...type,...Object2(mappedProperties)}}function FromRecord2(args,type){const mappedKey=FromType(args,RecordKey2(type));const mappedValue=FromType(args,RecordValue2(type));const result=Record(mappedKey,mappedValue);return{...type,...result}}function FromArgument(args,argument){return argument.index in args?args[argument.index]:Unknown()}function FromProperty2(args,type){const isReadonly=IsReadonly(type);const isOptional=IsOptional(type);const mapped=FromType(args,type);return isReadonly&&isOptional?ReadonlyOptional(mapped):isReadonly&&!isOptional?Readonly(mapped):!isReadonly&&isOptional?Optional(mapped):mapped}function FromProperties11(args,properties){return globalThis.Object.getOwnPropertyNames(properties).reduce((result,key)=>{return{...result,[key]:FromProperty2(args,properties[key])}},{})}function FromTypes(args,types){return types.map(type=>FromType(args,type))}function FromType(args,type){return IsConstructor(type)?FromConstructor2(args,type):IsFunction2(type)?FromFunction2(args,type):IsIntersect(type)?FromIntersect5(args,type):IsUnion(type)?FromUnion7(args,type):IsTuple(type)?FromTuple4(args,type):IsArray3(type)?FromArray5(args,type):IsAsyncIterator2(type)?FromAsyncIterator2(args,type):IsIterator2(type)?FromIterator2(args,type):IsPromise(type)?FromPromise3(args,type):IsObject3(type)?FromObject2(args,type):IsRecord(type)?FromRecord2(args,type):IsArgument(type)?FromArgument(args,type):type}function Instantiate(type,args){return FromType(args,CloneType(type))}function Integer(options){return CreateType({[Kind]:"Integer",type:"integer"},options)}function MappedIntrinsicPropertyKey(K,M,options){return{[K]:Intrinsic(Literal(K),M,Clone(options))}}function MappedIntrinsicPropertyKeys(K,M,options){const result=K.reduce((Acc,L)=>{return{...Acc,...MappedIntrinsicPropertyKey(L,M,options)}},{});return result}function MappedIntrinsicProperties(T,M,options){return MappedIntrinsicPropertyKeys(T["keys"],M,options)}function IntrinsicFromMappedKey(T,M,options){const P=MappedIntrinsicProperties(T,M,options);return MappedResult(P)}function ApplyUncapitalize(value){const[first,rest]=[value.slice(0,1),value.slice(1)];return[first.toLowerCase(),rest].join("")}function ApplyCapitalize(value){const[first,rest]=[value.slice(0,1),value.slice(1)];return[first.toUpperCase(),rest].join("")}function ApplyUppercase(value){return value.toUpperCase()}function ApplyLowercase(value){return value.toLowerCase()}function FromTemplateLiteral3(schema,mode,options){const expression=TemplateLiteralParseExact(schema.pattern);const finite=IsTemplateLiteralExpressionFinite(expression);if(!finite)return{...schema,pattern:FromLiteralValue(schema.pattern,mode)};const strings=[...TemplateLiteralExpressionGenerate(expression)];const literals=strings.map(value=>Literal(value));const mapped=FromRest5(literals,mode);const union=Union(mapped);return TemplateLiteral([union],options)}function FromLiteralValue(value,mode){return typeof value==="string"?mode==="Uncapitalize"?ApplyUncapitalize(value):mode==="Capitalize"?ApplyCapitalize(value):mode==="Uppercase"?ApplyUppercase(value):mode==="Lowercase"?ApplyLowercase(value):value:value.toString()}function FromRest5(T,M){return T.map(L=>Intrinsic(L,M))}function Intrinsic(schema,mode,options={}){return IsMappedKey(schema)?IntrinsicFromMappedKey(schema,mode,options):IsTemplateLiteral(schema)?FromTemplateLiteral3(schema,mode,options):IsUnion(schema)?Union(FromRest5(schema.anyOf,mode),options):IsLiteral(schema)?Literal(FromLiteralValue(schema.const,mode),options):CreateType(schema,options)}function Capitalize(T,options={}){return Intrinsic(T,"Capitalize",options)}function Lowercase(T,options={}){return Intrinsic(T,"Lowercase",options)}function Uncapitalize(T,options={}){return Intrinsic(T,"Uncapitalize",options)}function Uppercase(T,options={}){return Intrinsic(T,"Uppercase",options)}function FromProperties12(properties,propertyKeys,options){const result={};for(const K2 of globalThis.Object.getOwnPropertyNames(properties))result[K2]=Omit(properties[K2],propertyKeys,Clone(options));return result}function FromMappedResult9(mappedResult,propertyKeys,options){return FromProperties12(mappedResult.properties,propertyKeys,options)}function OmitFromMappedResult(mappedResult,propertyKeys,options){const properties=FromMappedResult9(mappedResult,propertyKeys,options);return MappedResult(properties)}function FromIntersect6(types,propertyKeys){return types.map(type=>OmitResolve(type,propertyKeys))}function FromUnion8(types,propertyKeys){return types.map(type=>OmitResolve(type,propertyKeys))}function FromProperty3(properties,key){const{[key]:_,...R}=properties;return R}function FromProperties13(properties,propertyKeys){return propertyKeys.reduce((T,K2)=>FromProperty3(T,K2),properties)}function FromObject3(type,propertyKeys,properties){const options=Discard(type,[TransformKind,"$id","required","properties"]);const mappedProperties=FromProperties13(properties,propertyKeys);return Object2(mappedProperties,options)}function UnionFromPropertyKeys(propertyKeys){const result=propertyKeys.reduce((result2,key)=>IsLiteralValue(key)?[...result2,Literal(key)]:result2,[]);return Union(result)}function OmitResolve(type,propertyKeys){return IsIntersect(type)?Intersect(FromIntersect6(type.allOf,propertyKeys)):IsUnion(type)?Union(FromUnion8(type.anyOf,propertyKeys)):IsObject3(type)?FromObject3(type,propertyKeys,type.properties):Object2({})}function Omit(type,key,options){const typeKey=IsArray(key)?UnionFromPropertyKeys(key):key;const propertyKeys=IsSchema(key)?IndexPropertyKeys(key):key;const isTypeRef=IsRef(type);const isKeyRef=IsRef(key);return IsMappedResult(type)?OmitFromMappedResult(type,propertyKeys,options):IsMappedKey(key)?OmitFromMappedKey(type,key,options):isTypeRef&&isKeyRef?Computed("Omit",[type,typeKey],options):!isTypeRef&&isKeyRef?Computed("Omit",[type,typeKey],options):isTypeRef&&!isKeyRef?Computed("Omit",[type,typeKey],options):CreateType({...OmitResolve(type,propertyKeys),...options})}function FromPropertyKey2(type,key,options){return{[key]:Omit(type,[key],Clone(options))}}function FromPropertyKeys2(type,propertyKeys,options){return propertyKeys.reduce((Acc,LK)=>{return{...Acc,...FromPropertyKey2(type,LK,options)}},{})}function FromMappedKey3(type,mappedKey,options){return FromPropertyKeys2(type,mappedKey.keys,options)}function OmitFromMappedKey(type,mappedKey,options){const properties=FromMappedKey3(type,mappedKey,options);return MappedResult(properties)}function FromProperties14(properties,propertyKeys,options){const result={};for(const K2 of globalThis.Object.getOwnPropertyNames(properties))result[K2]=Pick(properties[K2],propertyKeys,Clone(options));return result}function FromMappedResult10(mappedResult,propertyKeys,options){return FromProperties14(mappedResult.properties,propertyKeys,options)}function PickFromMappedResult(mappedResult,propertyKeys,options){const properties=FromMappedResult10(mappedResult,propertyKeys,options);return MappedResult(properties)}function FromIntersect7(types,propertyKeys){return types.map(type=>PickResolve(type,propertyKeys))}function FromUnion9(types,propertyKeys){return types.map(type=>PickResolve(type,propertyKeys))}function FromProperties15(properties,propertyKeys){const result={};for(const K2 of propertyKeys)if(K2 in properties)result[K2]=properties[K2];return result}function FromObject4(Type2,keys,properties){const options=Discard(Type2,[TransformKind,"$id","required","properties"]);const mappedProperties=FromProperties15(properties,keys);return Object2(mappedProperties,options)}function UnionFromPropertyKeys2(propertyKeys){const result=propertyKeys.reduce((result2,key)=>IsLiteralValue(key)?[...result2,Literal(key)]:result2,[]);return Union(result)}function PickResolve(type,propertyKeys){return IsIntersect(type)?Intersect(FromIntersect7(type.allOf,propertyKeys)):IsUnion(type)?Union(FromUnion9(type.anyOf,propertyKeys)):IsObject3(type)?FromObject4(type,propertyKeys,type.properties):Object2({})}function Pick(type,key,options){const typeKey=IsArray(key)?UnionFromPropertyKeys2(key):key;const propertyKeys=IsSchema(key)?IndexPropertyKeys(key):key;const isTypeRef=IsRef(type);const isKeyRef=IsRef(key);return IsMappedResult(type)?PickFromMappedResult(type,propertyKeys,options):IsMappedKey(key)?PickFromMappedKey(type,key,options):isTypeRef&&isKeyRef?Computed("Pick",[type,typeKey],options):!isTypeRef&&isKeyRef?Computed("Pick",[type,typeKey],options):isTypeRef&&!isKeyRef?Computed("Pick",[type,typeKey],options):CreateType({...PickResolve(type,propertyKeys),...options})}function FromPropertyKey3(type,key,options){return{[key]:Pick(type,[key],Clone(options))}}function FromPropertyKeys3(type,propertyKeys,options){return propertyKeys.reduce((result,leftKey)=>{return{...result,...FromPropertyKey3(type,leftKey,options)}},{})}function FromMappedKey4(type,mappedKey,options){return FromPropertyKeys3(type,mappedKey.keys,options)}function PickFromMappedKey(type,mappedKey,options){const properties=FromMappedKey4(type,mappedKey,options);return MappedResult(properties)}function FromComputed3(target,parameters){return Computed("Partial",[Computed(target,parameters)])}function FromRef3($ref){return Computed("Partial",[Ref($ref)])}function FromProperties16(properties){const partialProperties={};for(const K of globalThis.Object.getOwnPropertyNames(properties))partialProperties[K]=Optional(properties[K]);return partialProperties}function FromObject5(type,properties){const options=Discard(type,[TransformKind,"$id","required","properties"]);const mappedProperties=FromProperties16(properties);return Object2(mappedProperties,options)}function FromRest6(types){return types.map(type=>PartialResolve(type))}function PartialResolve(type){return IsComputed(type)?FromComputed3(type.target,type.parameters):IsRef(type)?FromRef3(type.$ref):IsIntersect(type)?Intersect(FromRest6(type.allOf)):IsUnion(type)?Union(FromRest6(type.anyOf)):IsObject3(type)?FromObject5(type,type.properties):IsBigInt2(type)?type:IsBoolean2(type)?type:IsInteger(type)?type:IsLiteral(type)?type:IsNull2(type)?type:IsNumber3(type)?type:IsString2(type)?type:IsSymbol2(type)?type:IsUndefined3(type)?type:Object2({})}function Partial(type,options){if(IsMappedResult(type)){return PartialFromMappedResult(type,options)}else{return CreateType({...PartialResolve(type),...options})}}function FromProperties17(K,options){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(K))Acc[K2]=Partial(K[K2],Clone(options));return Acc}function FromMappedResult11(R,options){return FromProperties17(R.properties,options)}function PartialFromMappedResult(R,options){const P=FromMappedResult11(R,options);return MappedResult(P)}function FromComputed4(target,parameters){return Computed("Required",[Computed(target,parameters)])}function FromRef4($ref){return Computed("Required",[Ref($ref)])}function FromProperties18(properties){const requiredProperties={};for(const K of globalThis.Object.getOwnPropertyNames(properties))requiredProperties[K]=Discard(properties[K],[OptionalKind]);return requiredProperties}function FromObject6(type,properties){const options=Discard(type,[TransformKind,"$id","required","properties"]);const mappedProperties=FromProperties18(properties);return Object2(mappedProperties,options)}function FromRest7(types){return types.map(type=>RequiredResolve(type))}function RequiredResolve(type){return IsComputed(type)?FromComputed4(type.target,type.parameters):IsRef(type)?FromRef4(type.$ref):IsIntersect(type)?Intersect(FromRest7(type.allOf)):IsUnion(type)?Union(FromRest7(type.anyOf)):IsObject3(type)?FromObject6(type,type.properties):IsBigInt2(type)?type:IsBoolean2(type)?type:IsInteger(type)?type:IsLiteral(type)?type:IsNull2(type)?type:IsNumber3(type)?type:IsString2(type)?type:IsSymbol2(type)?type:IsUndefined3(type)?type:Object2({})}function Required(type,options){if(IsMappedResult(type)){return RequiredFromMappedResult(type,options)}else{return CreateType({...RequiredResolve(type),...options})}}function FromProperties19(P,options){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(P))Acc[K2]=Required(P[K2],options);return Acc}function FromMappedResult12(R,options){return FromProperties19(R.properties,options)}function RequiredFromMappedResult(R,options){const P=FromMappedResult12(R,options);return MappedResult(P)}function DereferenceParameters(moduleProperties,types){return types.map(type=>{return IsRef(type)?Dereference(moduleProperties,type.$ref):FromType2(moduleProperties,type)})}function Dereference(moduleProperties,ref){return ref in moduleProperties?IsRef(moduleProperties[ref])?Dereference(moduleProperties,moduleProperties[ref].$ref):FromType2(moduleProperties,moduleProperties[ref]):Never()}function FromAwaited(parameters){return Awaited(parameters[0])}function FromIndex(parameters){return Index(parameters[0],parameters[1])}function FromKeyOf(parameters){return KeyOf(parameters[0])}function FromPartial(parameters){return Partial(parameters[0])}function FromOmit(parameters){return Omit(parameters[0],parameters[1])}function FromPick(parameters){return Pick(parameters[0],parameters[1])}function FromRequired(parameters){return Required(parameters[0])}function FromComputed5(moduleProperties,target,parameters){const dereferenced=DereferenceParameters(moduleProperties,parameters);return target==="Awaited"?FromAwaited(dereferenced):target==="Index"?FromIndex(dereferenced):target==="KeyOf"?FromKeyOf(dereferenced):target==="Partial"?FromPartial(dereferenced):target==="Omit"?FromOmit(dereferenced):target==="Pick"?FromPick(dereferenced):target==="Required"?FromRequired(dereferenced):Never()}function FromArray6(moduleProperties,type){return Array2(FromType2(moduleProperties,type))}function FromAsyncIterator3(moduleProperties,type){return AsyncIterator(FromType2(moduleProperties,type))}function FromConstructor3(moduleProperties,parameters,instanceType){return Constructor(FromTypes2(moduleProperties,parameters),FromType2(moduleProperties,instanceType))}function FromFunction3(moduleProperties,parameters,returnType){return Function(FromTypes2(moduleProperties,parameters),FromType2(moduleProperties,returnType))}function FromIntersect8(moduleProperties,types){return Intersect(FromTypes2(moduleProperties,types))}function FromIterator3(moduleProperties,type){return Iterator(FromType2(moduleProperties,type))}function FromObject7(moduleProperties,properties){return Object2(globalThis.Object.keys(properties).reduce((result,key)=>{return{...result,[key]:FromType2(moduleProperties,properties[key])}},{}))}function FromRecord3(moduleProperties,type){const[value,pattern]=[FromType2(moduleProperties,RecordValue2(type)),RecordPattern(type)];const result=CloneType(type);result.patternProperties[pattern]=value;return result}function FromTransform(moduleProperties,transform){return IsRef(transform)?{...Dereference(moduleProperties,transform.$ref),[TransformKind]:transform[TransformKind]}:transform}function FromTuple5(moduleProperties,types){return Tuple(FromTypes2(moduleProperties,types))}function FromUnion10(moduleProperties,types){return Union(FromTypes2(moduleProperties,types))}function FromTypes2(moduleProperties,types){return types.map(type=>FromType2(moduleProperties,type))}function FromType2(moduleProperties,type){return IsOptional(type)?CreateType(FromType2(moduleProperties,Discard(type,[OptionalKind])),type):IsReadonly(type)?CreateType(FromType2(moduleProperties,Discard(type,[ReadonlyKind])),type):IsTransform(type)?CreateType(FromTransform(moduleProperties,type),type):IsArray3(type)?CreateType(FromArray6(moduleProperties,type.items),type):IsAsyncIterator2(type)?CreateType(FromAsyncIterator3(moduleProperties,type.items),type):IsComputed(type)?CreateType(FromComputed5(moduleProperties,type.target,type.parameters)):IsConstructor(type)?CreateType(FromConstructor3(moduleProperties,type.parameters,type.returns),type):IsFunction2(type)?CreateType(FromFunction3(moduleProperties,type.parameters,type.returns),type):IsIntersect(type)?CreateType(FromIntersect8(moduleProperties,type.allOf),type):IsIterator2(type)?CreateType(FromIterator3(moduleProperties,type.items),type):IsObject3(type)?CreateType(FromObject7(moduleProperties,type.properties),type):IsRecord(type)?CreateType(FromRecord3(moduleProperties,type)):IsTuple(type)?CreateType(FromTuple5(moduleProperties,type.items||[]),type):IsUnion(type)?CreateType(FromUnion10(moduleProperties,type.anyOf),type):type}function ComputeType(moduleProperties,key){return key in moduleProperties?FromType2(moduleProperties,moduleProperties[key]):Never()}function ComputeModuleProperties(moduleProperties){return globalThis.Object.getOwnPropertyNames(moduleProperties).reduce((result,key)=>{return{...result,[key]:ComputeType(moduleProperties,key)}},{})}var TModule=class{constructor($defs){const computed=ComputeModuleProperties($defs);const identified=this.WithIdentifiers(computed);this.$defs=identified}Import(key,options){const $defs={...this.$defs,[key]:CreateType(this.$defs[key],options)};return CreateType({[Kind]:"Import",$defs,$ref:key})}WithIdentifiers($defs){return globalThis.Object.getOwnPropertyNames($defs).reduce((result,key)=>{return{...result,[key]:{...$defs[key],$id:key}}},{})}};function Module(properties){return new TModule(properties)}function Not(type,options){return CreateType({[Kind]:"Not",not:type},options)}function Parameters(schema,options){return IsFunction2(schema)?Tuple(schema.parameters,options):Never()}var Ordinal=0;function Recursive(callback,options={}){if(IsUndefined(options.$id))options.$id=`T${Ordinal++}`;const thisType=CloneType(callback({[Kind]:"This",$ref:`${options.$id}`}));thisType.$id=options.$id;return CreateType({[Hint]:"Recursive",...thisType},options)}function RegExp2(unresolved,options){const expr=IsString(unresolved)?new globalThis.RegExp(unresolved):unresolved;return CreateType({[Kind]:"RegExp",type:"RegExp",source:expr.source,flags:expr.flags},options)}function RestResolve(T){return IsIntersect(T)?T.allOf:IsUnion(T)?T.anyOf:IsTuple(T)?T.items??[]:[]}function Rest(T){return RestResolve(T)}function ReturnType(schema,options){return IsFunction2(schema)?CreateType(schema.returns,options):Never(options)}var TransformDecodeBuilder=class{constructor(schema){this.schema=schema}Decode(decode){return new TransformEncodeBuilder(this.schema,decode)}};var TransformEncodeBuilder=class{constructor(schema,decode){this.schema=schema;this.decode=decode}EncodeTransform(encode,schema){const Encode=value=>schema[TransformKind].Encode(encode(value));const Decode=value=>this.decode(schema[TransformKind].Decode(value));const Codec={Encode,Decode};return{...schema,[TransformKind]:Codec}}EncodeSchema(encode,schema){const Codec={Decode:this.decode,Encode:encode};return{...schema,[TransformKind]:Codec}}Encode(encode){return IsTransform(this.schema)?this.EncodeTransform(encode,this.schema):this.EncodeSchema(encode,this.schema)}};function Transform(schema){return new TransformDecodeBuilder(schema)}function Unsafe(options={}){return CreateType({[Kind]:options[Kind]??"Unsafe"},options)}function Void(options){return CreateType({[Kind]:"Void",type:"void"},options)}var type_exports2={};__export(type_exports2,{Any:()=>Any,Argument:()=>Argument,Array:()=>Array2,AsyncIterator:()=>AsyncIterator,Awaited:()=>Awaited,BigInt:()=>BigInt,Boolean:()=>Boolean2,Capitalize:()=>Capitalize,Composite:()=>Composite,Const:()=>Const,Constructor:()=>Constructor,ConstructorParameters:()=>ConstructorParameters,Date:()=>Date2,Enum:()=>Enum,Exclude:()=>Exclude,Extends:()=>Extends,Extract:()=>Extract,Function:()=>Function,Index:()=>Index,InstanceType:()=>InstanceType,Instantiate:()=>Instantiate,Integer:()=>Integer,Intersect:()=>Intersect,Iterator:()=>Iterator,KeyOf:()=>KeyOf,Literal:()=>Literal,Lowercase:()=>Lowercase,Mapped:()=>Mapped,Module:()=>Module,Never:()=>Never,Not:()=>Not,Null:()=>Null,Number:()=>Number2,Object:()=>Object2,Omit:()=>Omit,Optional:()=>Optional,Parameters:()=>Parameters,Partial:()=>Partial,Pick:()=>Pick,Promise:()=>Promise2,Readonly:()=>Readonly,ReadonlyOptional:()=>ReadonlyOptional,Record:()=>Record,Recursive:()=>Recursive,Ref:()=>Ref,RegExp:()=>RegExp2,Required:()=>Required,Rest:()=>Rest,ReturnType:()=>ReturnType,String:()=>String2,Symbol:()=>Symbol2,TemplateLiteral:()=>TemplateLiteral,Transform:()=>Transform,Tuple:()=>Tuple,Uint8Array:()=>Uint8Array2,Uncapitalize:()=>Uncapitalize,Undefined:()=>Undefined,Union:()=>Union,Unknown:()=>Unknown,Unsafe:()=>Unsafe,Uppercase:()=>Uppercase,Void:()=>Void});var Type=type_exports2;function jsonResult(payload){return{content:[{type:"text",text:JSON.stringify(payload,null,2)}],details:payload}}async function lookupConversationForSession(input){const store=input.lcm.getConversationStore();if(typeof store.getConversationForSession==="function"){return store.getConversationForSession({sessionId:input.sessionId,sessionKey:input.sessionKey})}const normalizedSessionKey=input.sessionKey?.trim();if(normalizedSessionKey&&typeof store.getConversationBySessionKey==="function"){const byKey=await store.getConversationBySessionKey(normalizedSessionKey);if(byKey){return byKey}}const normalizedSessionId=input.sessionId?.trim();if(!normalizedSessionId){return null}return store.getConversationBySessionId(normalizedSessionId)}function parseIsoTimestampParam(params,key){const raw=params[key];if(typeof raw!=="string"){return void 0}const value=raw.trim();if(!value){return void 0}const parsed=new Date(value);if(Number.isNaN(parsed.getTime())){throw new Error(`${key} must be a valid ISO timestamp.`)}return parsed}async function resolveLcmConversationScope(input){const{lcm,params}=input;const explicitConversationId=typeof params.conversationId==="number"&&Number.isFinite(params.conversationId)?Math.trunc(params.conversationId):void 0;if(explicitConversationId!=null){return{conversationId:explicitConversationId,allConversations:false}}if(params.allConversations===true){return{conversationId:void 0,allConversations:true}}const normalizedSessionKey=input.sessionKey?.trim();if(normalizedSessionKey){const bySessionKey=await lcm.getConversationStore().getConversationBySessionKey(normalizedSessionKey);if(bySessionKey){return{conversationId:bySessionKey.conversationId,allConversations:false}}}let normalizedSessionId=input.sessionId?.trim();if(!normalizedSessionId&&normalizedSessionKey&&input.deps){normalizedSessionId=await input.deps.resolveSessionIdFromSessionKey(normalizedSessionKey)}if(!normalizedSessionId&&!input.sessionKey?.trim()){return{conversationId:void 0,allConversations:false}}const conversation=await lookupConversationForSession({lcm,sessionId:normalizedSessionId,sessionKey:input.sessionKey});if(!conversation){return{conversationId:void 0,allConversations:false}}return{conversationId:conversation.conversationId,allConversations:false}}function formatDisplayTime(value,timezone){if(value==null){return"-"}const date=value instanceof Date?value:new Date(value);if(Number.isNaN(date.getTime())){return"-"}return formatTimestamp(date,timezone)}var LcmDescribeSchema=Type.Object({id:Type.String({description:"The LCM ID to look up. Use sum_xxx for summaries, file_xxx for files."}),conversationId:Type.Optional(Type.Number({description:"Conversation ID to scope describe lookups to. If omitted, uses the current session conversation."})),allConversations:Type.Optional(Type.Boolean({description:"Set true to explicitly allow lookups across all conversations. Ignored when conversationId is provided."})),tokenCap:Type.Optional(Type.Number({description:"Optional budget cap used for subtree manifest budget-fit annotations.",minimum:1}))});function normalizeRequestedTokenCap(value){if(typeof value!=="number"||!Number.isFinite(value)){return void 0}return Math.max(1,Math.trunc(value))}function createLcmDescribeTool(input){return{name:"lcm_describe",label:"LCM Describe",description:"Look up metadata and content for an LCM item by ID. Use this to inspect summaries (sum_xxx) or stored files (file_xxx) from compacted conversation history. Returns summary content, lineage, token counts, and file exploration results.",parameters:LcmDescribeSchema,async execute(_toolCallId,params){const lcm=input.lcm??await input.getLcm?.();if(!lcm){throw new Error("LCM engine is unavailable.")}const retrieval=lcm.getRetrieval();const timezone=lcm.timezone;const p=params;const id=p.id.trim();const conversationScope=await resolveLcmConversationScope({lcm,deps:input.deps,sessionId:input.sessionId,sessionKey:input.sessionKey,params:p});if(!conversationScope.allConversations&&conversationScope.conversationId==null){return jsonResult({error:"No LCM conversation found for this session. Provide conversationId or set allConversations=true."})}const result=await retrieval.describe(id);if(!result){return jsonResult({error:`Not found: ${id}`,hint:"Check the ID format (sum_xxx for summaries, file_xxx for files)."})}if(conversationScope.conversationId!=null){const itemConversationId=result.type==="summary"?result.summary?.conversationId:result.file?.conversationId;if(itemConversationId!=null&&itemConversationId!==conversationScope.conversationId){return jsonResult({error:`Not found in conversation ${conversationScope.conversationId}: ${id}`,hint:"Use allConversations=true for cross-conversation lookup."})}}if(result.type==="summary"&&result.summary){const s=result.summary;const requestedTokenCap=normalizeRequestedTokenCap(params.tokenCap);const sessionKey=(typeof input.sessionKey==="string"?input.sessionKey:input.sessionId)?.trim()??"";const delegatedGrantId=input.deps.isSubagentSessionKey(sessionKey)?resolveDelegatedExpansionGrantId(sessionKey)??"":"";const delegatedRemainingBudget=delegatedGrantId!==""?getRuntimeExpansionAuthManager().getRemainingTokenBudget(delegatedGrantId):null;const defaultTokenCap=Math.max(1,Math.trunc(input.deps.config.maxExpandTokens));const resolvedTokenCap=(()=>{const base=requestedTokenCap??(typeof delegatedRemainingBudget==="number"?delegatedRemainingBudget:defaultTokenCap);if(typeof delegatedRemainingBudget==="number"){return Math.max(0,Math.min(base,delegatedRemainingBudget))}return Math.max(1,base)})();const manifestNodes=s.subtree.map(node=>{const summariesOnlyCost=Math.max(0,node.tokenCount+node.descendantTokenCount);const withMessagesCost=Math.max(0,summariesOnlyCost+node.sourceMessageTokenCount);return{summaryId:node.summaryId,parentSummaryId:node.parentSummaryId,depthFromRoot:node.depthFromRoot,depth:node.depth,kind:node.kind,tokenCount:node.tokenCount,descendantCount:node.descendantCount,descendantTokenCount:node.descendantTokenCount,sourceMessageTokenCount:node.sourceMessageTokenCount,childCount:node.childCount,earliestAt:node.earliestAt,latestAt:node.latestAt,path:node.path,costs:{summariesOnly:summariesOnlyCost,withMessages:withMessagesCost},budgetFit:{summariesOnly:summariesOnlyCost<=resolvedTokenCap,withMessages:withMessagesCost<=resolvedTokenCap}}});const lines=[];lines.push(`LCM_SUMMARY ${id}`);lines.push(`meta conv=${s.conversationId} kind=${s.kind} depth=${s.depth} tok=${s.tokenCount} descTok=${s.descendantTokenCount} srcTok=${s.sourceMessageTokenCount} desc=${s.descendantCount} range=${formatDisplayTime(s.earliestAt,timezone)}..${formatDisplayTime(s.latestAt,timezone)} budgetCap=${resolvedTokenCap}`);if(s.parentIds.length>0){lines.push(`parents ${s.parentIds.join(" ")}`)}if(s.childIds.length>0){lines.push(`children ${s.childIds.join(" ")}`)}lines.push("manifest");for(const node of manifestNodes){lines.push(`d${node.depthFromRoot} ${node.summaryId} k=${node.kind} tok=${node.tokenCount} descTok=${node.descendantTokenCount} srcTok=${node.sourceMessageTokenCount} desc=${node.descendantCount} child=${node.childCount} range=${formatDisplayTime(node.earliestAt,timezone)}..${formatDisplayTime(node.latestAt,timezone)} cost[s=${node.costs.summariesOnly},m=${node.costs.withMessages}] budget[s=${node.budgetFit.summariesOnly?"in":"over"},m=${node.budgetFit.withMessages?"in":"over"}]`)}lines.push("content");lines.push(s.content);return{content:[{type:"text",text:lines.join("\n")}],details:{...result,manifest:{tokenCap:resolvedTokenCap,budgetSource:requestedTokenCap!=null?"request":typeof delegatedRemainingBudget==="number"?"delegated_grant_remaining":"config_default",nodes:manifestNodes}}}}if(result.type==="file"&&result.file){const f=result.file;const lines=[];lines.push(`## LCM File: ${id}`);lines.push("");lines.push(`**Conversation:** ${f.conversationId}`);lines.push(`**Name:** ${f.fileName??"(no name)"}`);lines.push(`**Type:** ${f.mimeType??"unknown"}`);if(f.byteSize!=null){lines.push(`**Size:** ${f.byteSize.toLocaleString()} bytes`)}lines.push(`**Created:** ${formatDisplayTime(f.createdAt,timezone)}`);if(f.explorationSummary){lines.push("");lines.push("## Exploration Summary");lines.push("");lines.push(f.explorationSummary)}else{lines.push("");lines.push("*No exploration summary available.*")}return{content:[{type:"text",text:lines.join("\n")}],details:result}}return jsonResult(result)}}}import crypto4 from"node:crypto";import crypto3 from"node:crypto";import crypto2 from"node:crypto";var EXPANSION_RECURSION_ERROR_CODE="EXPANSION_RECURSION_BLOCKED";var EXPANSION_CONCURRENCY_ERROR_CODE="EXPANSION_CONCURRENCY_BLOCKED";var EXPANSION_DELEGATION_DEPTH_CAP=1;var telemetryCounters={start:0,block:0,timeout:0,success:0};var delegatedContextBySessionKey=new Map;var blockedRequestIdsBySessionKey=new Map;var activeRequestIdByOriginSessionKey=new Map;function normalizeSessionKey(sessionKey){return typeof sessionKey==="string"?sessionKey.trim():""}function getOrInitBlockedRequestIds(sessionKey){const existing=blockedRequestIdsBySessionKey.get(sessionKey);if(existing){return existing}const created=new Set;blockedRequestIdsBySessionKey.set(sessionKey,created);return created}function resolveFallbackDelegatedContext(sessionKey,requestId){if(!sessionKey){return void 0}const grantId=resolveDelegatedExpansionGrantId(sessionKey);if(!grantId){return void 0}return{requestId,expansionDepth:EXPANSION_DELEGATION_DEPTH_CAP,originSessionKey:sessionKey,stampedBy:"delegated_grant",createdAt:new Date().toISOString()}}function buildExpansionRecursionRecoveryGuidance(originSessionKey){return`Recovery: In delegated sub-agent sessions, call \`lcm_expand\` directly and synthesize your answer from that result. Do NOT call \`lcm_expand_query\` from delegated context. If deeper delegation is required, return to the origin session (${originSessionKey}) and call \`lcm_expand_query\` there.`}function buildExpansionConcurrencyRecoveryGuidance(originSessionKey){return`Recovery: Wait for the active expansion to finish before retrying. If you need an immediate fallback, stay in the origin session (${originSessionKey}) and use \`lcm_grep\` or \`lcm_describe\` instead.`}function createExpansionRequestId(){return crypto2.randomUUID()}function resolveExpansionRequestId(sessionKey){const key=normalizeSessionKey(sessionKey);return delegatedContextBySessionKey.get(key)?.requestId??createExpansionRequestId()}function resolveNextExpansionDepth(sessionKey){const key=normalizeSessionKey(sessionKey);if(!key){return 1}const existing=delegatedContextBySessionKey.get(key);if(existing){return existing.expansionDepth+1}return resolveDelegatedExpansionGrantId(key)?EXPANSION_DELEGATION_DEPTH_CAP+1:1}function stampDelegatedExpansionContext(params){const sessionKey=normalizeSessionKey(params.sessionKey);const context={requestId:params.requestId,expansionDepth:Math.max(0,Math.trunc(params.expansionDepth)),originSessionKey:params.originSessionKey.trim()||"main",stampedBy:params.stampedBy,createdAt:new Date().toISOString()};if(sessionKey){delegatedContextBySessionKey.set(sessionKey,context)}return context}function clearDelegatedExpansionContext(sessionKey){const key=normalizeSessionKey(sessionKey);if(!key){return}delegatedContextBySessionKey.delete(key);blockedRequestIdsBySessionKey.delete(key)}function evaluateExpansionRecursionGuard(params){const sessionKey=normalizeSessionKey(params.sessionKey);const requestId=params.requestId.trim();const delegatedContext=delegatedContextBySessionKey.get(sessionKey)??resolveFallbackDelegatedContext(sessionKey,requestId||createExpansionRequestId());if(!delegatedContext){return{blocked:false,requestId,expansionDepth:0,originSessionKey:sessionKey||"main"}}if(delegatedContext.expansionDepth<EXPANSION_DELEGATION_DEPTH_CAP){return{blocked:false,requestId,expansionDepth:delegatedContext.expansionDepth,originSessionKey:delegatedContext.originSessionKey}}const seenRequestIds=getOrInitBlockedRequestIds(sessionKey);const isIdempotentReentry=seenRequestIds.has(requestId);seenRequestIds.add(requestId);const reason=isIdempotentReentry?"idempotent_reentry":"depth_cap";return{blocked:true,code:EXPANSION_RECURSION_ERROR_CODE,reason,message:`${EXPANSION_RECURSION_ERROR_CODE}: Expansion delegation blocked at depth ${delegatedContext.expansionDepth} (${reason}; requestId=${requestId}; origin=${delegatedContext.originSessionKey}). `+buildExpansionRecursionRecoveryGuidance(delegatedContext.originSessionKey),requestId,expansionDepth:delegatedContext.expansionDepth,originSessionKey:delegatedContext.originSessionKey}}function acquireExpansionConcurrencySlot(params){const originSessionKey=normalizeSessionKey(params.originSessionKey)||"main";const requestId=params.requestId.trim();const activeRequestId=activeRequestIdByOriginSessionKey.get(originSessionKey);if(activeRequestId&&activeRequestId!==requestId){return{blocked:true,code:EXPANSION_CONCURRENCY_ERROR_CODE,reason:"origin_session_in_flight",message:`${EXPANSION_CONCURRENCY_ERROR_CODE}: Another lcm_expand_query delegation is already in flight for origin session (${originSessionKey}; activeRequestId=${activeRequestId}). `+buildExpansionConcurrencyRecoveryGuidance(originSessionKey),requestId,originSessionKey}}if(!activeRequestId){activeRequestIdByOriginSessionKey.set(originSessionKey,requestId)}return{blocked:false,requestId,originSessionKey}}function releaseExpansionConcurrencySlot(params){const originSessionKey=normalizeSessionKey(params.originSessionKey);if(!originSessionKey){return}const activeRequestId=activeRequestIdByOriginSessionKey.get(originSessionKey);if(!activeRequestId){return}const requestId=params.requestId?.trim();if(requestId&&activeRequestId!==requestId){return}activeRequestIdByOriginSessionKey.delete(originSessionKey)}function recordExpansionDelegationTelemetry(params){telemetryCounters[params.event]+=1;const payload={component:params.component,event:params.event,requestId:params.requestId,sessionKey:normalizeSessionKey(params.sessionKey)||void 0,expansionDepth:params.expansionDepth,originSessionKey:params.originSessionKey,reason:params.reason,runId:params.runId,counters:{start:telemetryCounters.start,block:telemetryCounters.block,timeout:telemetryCounters.timeout,success:telemetryCounters.success}};const line=`[lcm][expansion_delegation] ${JSON.stringify(payload)}`;if(params.event==="start"||params.event==="success"){params.deps.log.info(line);return}params.deps.log.warn(line)}var MAX_GATEWAY_TIMEOUT_MS=2147483647;function normalizeSummaryIds(input){if(!Array.isArray(input)){return[]}const seen=new Set;const normalized=[];for(const value of input){if(typeof value!=="string"){continue}const trimmed=value.trim();if(!trimmed||seen.has(trimmed)){continue}seen.add(trimmed);normalized.push(trimmed)}return normalized}function parseDelegatedExpansionReply(rawReply){const fallback={summary:(rawReply??"").trim(),citedIds:[],followUpSummaryIds:[],totalTokens:0,truncated:false};const reply=rawReply?.trim();if(!reply){return fallback}const candidates=[reply];const fenced=reply.match(/```(?:json)?\s*([\s\S]*?)```/i);if(fenced?.[1]){candidates.unshift(fenced[1].trim())}for(const candidate of candidates){try{const parsed=JSON.parse(candidate);const summary=typeof parsed.summary==="string"?parsed.summary.trim():"";const citedIds=normalizeSummaryIds(Array.isArray(parsed.citedIds)?parsed.citedIds.filter(value=>typeof value==="string"):void 0);const followUpSummaryIds=normalizeSummaryIds(Array.isArray(parsed.followUpSummaryIds)?parsed.followUpSummaryIds.filter(value=>typeof value==="string"):void 0);const totalTokens=typeof parsed.totalTokens==="number"&&Number.isFinite(parsed.totalTokens)?Math.max(0,Math.floor(parsed.totalTokens)):0;const truncated=parsed.truncated===true;return{summary:summary||fallback.summary,citedIds,followUpSummaryIds,totalTokens,truncated}}catch{}}return fallback}function formatDelegatedExpansionText(passes){const lines=[];const allCitedIds=new Set;for(const pass of passes){for(const summaryId of pass.citedIds){allCitedIds.add(summaryId)}if(!pass.summary.trim()){continue}if(passes.length>1){lines.push(`Pass ${pass.pass}: ${pass.summary.trim()}`)}else{lines.push(pass.summary.trim())}}if(lines.length===0){lines.push("Delegated expansion completed with no textual summary.")}if(allCitedIds.size>0){lines.push("","Cited IDs:",...Array.from(allCitedIds).map(value=>`- ${value}`))}return lines.join("\n")}function buildDelegatedExpansionTask(params){const payload={summaryIds:params.summaryIds,conversationId:params.conversationId,maxDepth:params.maxDepth,includeMessages:params.includeMessages};if(typeof params.tokenCap==="number"&&Number.isFinite(params.tokenCap)){payload.tokenCap=params.tokenCap}return["Run LCM expansion and report distilled findings.",params.query?`Original query: ${params.query}`:void 0,`Pass ${params.pass}`,"","Call `lcm_expand` using exactly this JSON payload:",JSON.stringify(payload,null,2),"","Delegated expansion metadata (for tracing):",`- requestId: ${params.requestId}`,`- expansionDepth: ${params.expansionDepth}`,`- originSessionKey: ${params.originSessionKey}`,"","Then return ONLY JSON with this shape:","{",' "summary": "string concise findings",',' "citedIds": ["sum_xxx"],',' "followUpSummaryIds": ["sum_xxx"],',' "totalTokens": 0,',' "truncated": false',"}","","Rules:","- In delegated context, use `lcm_expand` directly for retrieval.","- DO NOT call `lcm_expand_query` from this delegated session.","- Keep summary concise and factual.","- Synthesize findings from the `lcm_expand` result before returning.","- citedIds/followUpSummaryIds must contain unique summary IDs only.","- If no follow-up is needed, return an empty followUpSummaryIds array."].filter(line=>line!==void 0).join("\n")}async function resolveRequesterConversationScopeId(params){const requesterSessionKey=params.requesterSessionKey.trim();if(!requesterSessionKey){return void 0}try{const store=params.lcm.getConversationStore();if(typeof store.getConversationForSession==="function"){const conversation2=await store.getConversationForSession({sessionKey:requesterSessionKey});if(conversation2){return conversation2.conversationId}}else if(typeof store.getConversationBySessionKey==="function"){const byKey=await store.getConversationBySessionKey(requesterSessionKey);if(byKey){return byKey.conversationId}}const runtimeSessionId=await params.deps.resolveSessionIdFromSessionKey(requesterSessionKey);if(!runtimeSessionId){return void 0}const conversation=await store.getConversationBySessionId(runtimeSessionId);return conversation?.conversationId}catch{return void 0}}async function runDelegatedExpansionPass(params){const requesterAgentId=params.deps.normalizeAgentId(params.deps.parseAgentSessionKey(params.requesterSessionKey)?.agentId);const childSessionKey=`agent:${requesterAgentId}:subagent:${crypto3.randomUUID()}`;let runId="";createDelegatedExpansionGrant({delegatedSessionKey:childSessionKey,issuerSessionId:params.requesterSessionKey,allowedConversationIds:[params.conversationId],tokenCap:params.tokenCap,ttlMs:MAX_GATEWAY_TIMEOUT_MS});stampDelegatedExpansionContext({sessionKey:childSessionKey,requestId:params.requestId,expansionDepth:params.parentExpansionDepth+1,originSessionKey:params.originSessionKey,stampedBy:"runDelegatedExpansionLoop"});try{const message=buildDelegatedExpansionTask({summaryIds:params.summaryIds,conversationId:params.conversationId,maxDepth:params.maxDepth,tokenCap:params.tokenCap,includeMessages:params.includeMessages,pass:params.pass,query:params.query,requestId:params.requestId,expansionDepth:params.parentExpansionDepth+1,originSessionKey:params.originSessionKey});const response=await params.deps.callGateway({method:"agent",params:{message,sessionKey:childSessionKey,deliver:false,lane:params.deps.agentLaneSubagent,extraSystemPrompt:params.deps.buildSubagentSystemPrompt({depth:1,maxDepth:8,taskSummary:"Run lcm_expand and return JSON findings"})},timeoutMs:1e4});runId=typeof response?.runId==="string"&&response.runId?response.runId:crypto3.randomUUID();const wait=await params.deps.callGateway({method:"agent.wait",params:{runId,timeoutMs:MAX_GATEWAY_TIMEOUT_MS},timeoutMs:MAX_GATEWAY_TIMEOUT_MS});const status=typeof wait?.status==="string"?wait.status:"error";if(status==="timeout"){return{pass:params.pass,status:"timeout",runId,childSessionKey,summary:"",citedIds:[],followUpSummaryIds:[],totalTokens:0,truncated:true,error:"delegated expansion pass timed out"}}if(status!=="ok"){return{pass:params.pass,status:"error",runId,childSessionKey,summary:"",citedIds:[],followUpSummaryIds:[],totalTokens:0,truncated:true,error:typeof wait?.error==="string"?wait.error:"delegated expansion pass failed"}}const replyPayload=await params.deps.callGateway({method:"sessions.get",params:{key:childSessionKey,limit:80},timeoutMs:1e4});const reply=params.deps.readLatestAssistantReply(Array.isArray(replyPayload.messages)?replyPayload.messages:[]);const parsed=parseDelegatedExpansionReply(reply);return{pass:params.pass,status:"ok",runId,childSessionKey,summary:parsed.summary,citedIds:parsed.citedIds,followUpSummaryIds:parsed.followUpSummaryIds,totalTokens:parsed.totalTokens,truncated:parsed.truncated,rawReply:reply}}catch(err){return{pass:params.pass,status:"error",runId:runId||crypto3.randomUUID(),childSessionKey,summary:"",citedIds:[],followUpSummaryIds:[],totalTokens:0,truncated:true,error:err instanceof Error?err.message:String(err)}}finally{try{await params.deps.callGateway({method:"sessions.delete",params:{key:childSessionKey,deleteTranscript:true},timeoutMs:1e4})}catch{}revokeDelegatedExpansionGrantForSession(childSessionKey,{removeBinding:true});clearDelegatedExpansionContext(childSessionKey)}}async function runDelegatedExpansionLoop(params){const requestId=params.requestId?.trim()||resolveExpansionRequestId(params.requesterSessionKey);const recursionCheck=evaluateExpansionRecursionGuard({sessionKey:params.requesterSessionKey,requestId});recordExpansionDelegationTelemetry({deps:params.deps,component:"runDelegatedExpansionLoop",event:"start",requestId,sessionKey:params.requesterSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey});if(recursionCheck.blocked){recordExpansionDelegationTelemetry({deps:params.deps,component:"runDelegatedExpansionLoop",event:"block",requestId,sessionKey:params.requesterSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey,reason:recursionCheck.reason});return{status:"error",passes:[],citedIds:[],totalTokens:0,truncated:true,text:"Delegated expansion blocked by recursion guard.",error:recursionCheck.message}}const passes=[];const visited=new Set;const cited=new Set;let queue=normalizeSummaryIds(params.summaryIds);let pass=1;while(queue.length>0){for(const summaryId of queue){visited.add(summaryId)}const result=await runDelegatedExpansionPass({deps:params.deps,requesterSessionKey:params.requesterSessionKey,conversationId:params.conversationId,summaryIds:queue,maxDepth:params.maxDepth,tokenCap:params.tokenCap,includeMessages:params.includeMessages,query:params.query,pass,requestId,parentExpansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey});passes.push(result);if(result.status!=="ok"){if(result.status==="timeout"){recordExpansionDelegationTelemetry({deps:params.deps,component:"runDelegatedExpansionLoop",event:"timeout",requestId,sessionKey:params.requesterSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey,runId:result.runId})}const okPasses=passes.filter(entry=>entry.status==="ok");for(const okPass of okPasses){for(const summaryId of okPass.citedIds){cited.add(summaryId)}}const text=okPasses.length>0?formatDelegatedExpansionText(okPasses):"Delegated expansion failed before any pass completed.";return{status:result.status,passes,citedIds:Array.from(cited),totalTokens:okPasses.reduce((sum,entry)=>sum+entry.totalTokens,0),truncated:true,text,error:result.error}}for(const summaryId of result.citedIds){cited.add(summaryId)}const nextQueue=result.followUpSummaryIds.filter(summaryId=>!visited.has(summaryId));queue=nextQueue;pass+=1}recordExpansionDelegationTelemetry({deps:params.deps,component:"runDelegatedExpansionLoop",event:"success",requestId,sessionKey:params.requesterSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey});return{status:"ok",passes,citedIds:Array.from(cited),totalTokens:passes.reduce((sum,entry)=>sum+entry.totalTokens,0),truncated:passes.some(entry=>entry.truncated),text:formatDelegatedExpansionText(passes)}}var DEFAULT_DELEGATED_WAIT_TIMEOUT_MS=12e4;var GATEWAY_TIMEOUT_MS=1e4;var DEFAULT_MAX_ANSWER_TOKENS=2e3;var DEFAULT_MAX_CONVERSATION_BUCKETS=3;var LcmExpandQuerySchema=Type.Object({summaryIds:Type.Optional(Type.Array(Type.String(),{description:"Summary IDs to expand (sum_xxx). Required when query is not provided."})),query:Type.Optional(Type.String({description:"FTS5 query used to find summaries via the same full-text search path as lcm_grep before expansion. Use 1-3 distinctive terms or a quoted phrase; FTS5 defaults to AND matching, so extra terms make matches stricter. Required when summaryIds is not provided."})),prompt:Type.String({description:"Natural-language question or task to answer using expanded context. Put the answer request here, not in query."}),conversationId:Type.Optional(Type.Number({description:"Conversation ID to scope expansion to. If omitted, uses the current session conversation."})),allConversations:Type.Optional(Type.Boolean({description:"Set true to explicitly allow cross-conversation lookup. Ignored when conversationId is provided."})),maxTokens:Type.Optional(Type.Number({description:`Maximum answer tokens to target (default: ${DEFAULT_MAX_ANSWER_TOKENS}).`,minimum:1})),tokenCap:Type.Optional(Type.Number({description:"Expansion retrieval token budget across all delegated lcm_expand calls for this query.",minimum:1}))});function collectExpansionFailureText(value,parts,depth=0){if(depth>3||value==null){return}if(typeof value==="string"){const trimmed=value.trim();if(trimmed){parts.push(trimmed)}return}if(typeof value==="number"||typeof value==="boolean"){parts.push(String(value));return}if(value instanceof Error){if(value.message.trim()){parts.push(value.message.trim())}collectExpansionFailureText(value.cause,parts,depth+1);return}if(Array.isArray(value)){for(const entry of value){collectExpansionFailureText(entry,parts,depth+1)}return}if(typeof value==="object"){const record=value;for(const key of["message","error","reason","details","response","cause","code"]){collectExpansionFailureText(record[key],parts,depth+1)}}}function formatExpansionFailure(error){const parts=[];collectExpansionFailureText(error,parts);const message=parts.join(" ").replace(/\s+/g," ").trim();if(message){return message}if(typeof error==="string"&&error.trim()){return error.trim()}return"Delegated expansion query failed."}function shouldRetryWithoutOverride(message){const normalized=message.toLowerCase();return["model.request","missing scopes","insufficient scope","unauthorized","not authorized","forbidden","provider/model overrides are not authorized","model override is not authorized","unknown model","model not found","invalid model","not available","not supported","401","403"].some(signal=>normalized.includes(signal))}function maxDate(left,right){if(!left){return right}if(!right){return left}return left.getTime()>=right.getTime()?left:right}function buildDelegatedExpandQueryTask(params){const seedSummaryIds=params.summaryIds.length>0?params.summaryIds.join(", "):"(none)";const messageBackedSummaryIds=params.messageBackedSummaryIds.length>0?params.messageBackedSummaryIds.join(", "):"(none)";return["You are an autonomous LCM retrieval navigator. Plan and execute retrieval before answering.","","Available tools: lcm_describe, lcm_expand, lcm_grep",`Conversation scope: ${params.conversationId}`,`Expansion token budget (total across this run): ${params.tokenCap}`,`Seed summary IDs: ${seedSummaryIds}`,`Seed summaries requiring raw message expansion: ${messageBackedSummaryIds}`,params.query?`Routing query: ${params.query}`:void 0,"","Strategy:","1. Start with `lcm_describe` on seed summaries to inspect subtree manifests and branch costs.",'2. If additional candidates are needed, use `lcm_grep` scoped to summaries. Prefer `mode: "full_text"`, quote exact multi-word phrases, use `sort: "relevance"` for older-topic recall, and `sort: "hybrid"` when recency should still matter.',"3. Select branches that fit remaining budget; prefer high-signal paths first.","4. Call `lcm_expand` selectively (do not expand everything blindly).","5. Keep includeMessages=false by default; use includeMessages=true for the message-backed seed summaries above and any other specific leaf evidence.",`6. Stay within ${params.tokenCap} total expansion tokens across all lcm_expand calls.`,"","User prompt to answer:",params.prompt,"","Delegated expansion metadata (for tracing):",`- requestId: ${params.requestId}`,`- expansionDepth: ${params.expansionDepth}`,`- originSessionKey: ${params.originSessionKey}`,"","Return ONLY JSON with this shape:","{",' "answer": "string",',' "citedIds": ["sum_xxx"],',' "expandedSummaryCount": 0,',' "totalSourceTokens": 0,',' "truncated": false',"}","","Rules:","- In delegated context, call `lcm_expand` directly for source retrieval.","- DO NOT call `lcm_expand_query` from this delegated session.","- Synthesize the final answer from retrieved evidence, not assumptions.",`- Keep answer concise and focused (target <= ${params.maxTokens} tokens).`,"- citedIds must be unique summary IDs.","- expandedSummaryCount should reflect how many summaries were expanded/used.","- totalSourceTokens should estimate total tokens consumed from expansion calls.","- truncated should indicate whether source expansion appears truncated."].filter(line=>typeof line==="string").join("\n")}function formatInvalidDelegatedReply(reply,reason){const compact=reply.replace(/\s+/g," ").trim();const snippet=compact.length<=240?compact:`${compact.slice(0,240)}...`;return`Delegated expansion query returned ${reason}: ${snippet}`}function buildConversationBuckets(candidates){const buckets=new Map;for(const candidate of candidates){const bucket=buckets.get(candidate.conversationId)??{conversationId:candidate.conversationId,summaryIds:[],messageBackedSummaryIds:[],summaryIdSet:new Set,explicitSummaryIdSet:new Set,messageBackedSummaryIdSet:new Set,newestMatchAt:void 0};if(!bucket.summaryIdSet.has(candidate.summaryId)){bucket.summaryIds.push(candidate.summaryId);bucket.summaryIdSet.add(candidate.summaryId)}if(candidate.isExplicit){bucket.explicitSummaryIdSet.add(candidate.summaryId)}if(candidate.requiresMessageExpansion&&!bucket.messageBackedSummaryIdSet.has(candidate.summaryId)){bucket.messageBackedSummaryIds.push(candidate.summaryId);bucket.messageBackedSummaryIdSet.add(candidate.summaryId)}bucket.newestMatchAt=maxDate(bucket.newestMatchAt,candidate.matchedAt);buckets.set(candidate.conversationId,bucket)}return Array.from(buckets.values()).map(bucket=>({conversationId:bucket.conversationId,summaryIds:normalizeSummaryIds(bucket.summaryIds),messageBackedSummaryIds:normalizeSummaryIds(bucket.messageBackedSummaryIds),candidateCount:bucket.summaryIds.length,explicitSummaryCount:bucket.explicitSummaryIdSet.size,messageBackedCount:bucket.messageBackedSummaryIds.length,newestMatchAt:bucket.newestMatchAt}))}function compareConversationBuckets(left,right){const explicitDelta=right.explicitSummaryCount-left.explicitSummaryCount;if(explicitDelta!==0){return explicitDelta}const candidateDelta=right.candidateCount-left.candidateCount;if(candidateDelta!==0){return candidateDelta}const recencyDelta=(right.newestMatchAt?.getTime()??0)-(left.newestMatchAt?.getTime()??0);if(recencyDelta!==0){return recencyDelta}const messageBackedDelta=right.messageBackedCount-left.messageBackedCount;if(messageBackedDelta!==0){return messageBackedDelta}return left.conversationId-right.conversationId}function buildExpandQueryReply(params){const sourceConversationIds=[...params.sourceConversationIds].sort((left,right)=>left-right);return{answer:params.answer,citedIds:normalizeSummaryIds(params.citedIds),sourceConversationIds,...sourceConversationIds.length===1?{sourceConversationId:sourceConversationIds[0]}:{},expandedSummaryCount:params.expandedSummaryCount,totalSourceTokens:params.totalSourceTokens,truncated:params.truncated,...params.conversationBreakdown?{conversationBreakdown:params.conversationBreakdown}:{}}}function synthesizeConversationAnswers(params){const successfulResults=params.results.filter(result=>result.status==="success");const failedResults=params.results.filter(result=>result.status==="failed");const skippedResults=params.results.filter(result=>result.status==="skipped");if(successfulResults.length===1&&failedResults.length===0&&skippedResults.length===0){return successfulResults[0].reply.answer}const lines=[];if(successfulResults.length>1){lines.push(`Merged findings across ${successfulResults.length} conversations:`);lines.push("")}for(const result of successfulResults){if(successfulResults.length>1){lines.push(`Conversation ${result.conversationId}:`)}lines.push(result.reply.answer);if(successfulResults.length>1){lines.push("")}}const notes=[];if(failedResults.length>0){notes.push(`failed conversations: ${failedResults.map(result=>`${result.conversationId} (${result.error})`).join("; ")}`)}if(skippedResults.length>0){notes.push(`skipped conversations: ${skippedResults.map(result=>`${result.conversationId} (${result.error})`).join("; ")}`)}if(notes.length>0){if(lines.length>0&&lines[lines.length-1]!==""){lines.push("")}lines.push(`Partial coverage for "${params.prompt}": ${notes.join("; ")}`)}return lines.join("\n").trim()}function parseDelegatedExpandQueryReply(rawReply,fallbackExpandedSummaryCount){const reply=rawReply?.trim();if(!reply){return{ok:false,error:"Delegated expansion query returned an empty reply."}}const candidates=[reply];const fenced=reply.match(/```(?:json)?\s*([\s\S]*?)```/i);if(fenced?.[1]){candidates.unshift(fenced[1].trim())}for(const candidate of candidates){try{const parsed=JSON.parse(candidate);const answer=typeof parsed.answer==="string"?parsed.answer.trim():"";if(!answer){return{ok:false,error:formatInvalidDelegatedReply(reply,'JSON without a non-empty "answer"')}}const citedIds=normalizeSummaryIds(Array.isArray(parsed.citedIds)?parsed.citedIds.filter(value=>typeof value==="string"):void 0);const expandedSummaryCount=typeof parsed.expandedSummaryCount==="number"&&Number.isFinite(parsed.expandedSummaryCount)?Math.max(0,Math.floor(parsed.expandedSummaryCount)):fallbackExpandedSummaryCount;const totalSourceTokens=typeof parsed.totalSourceTokens==="number"&&Number.isFinite(parsed.totalSourceTokens)?Math.max(0,Math.floor(parsed.totalSourceTokens)):0;const truncated=parsed.truncated===true;return{ok:true,value:{answer,citedIds,expandedSummaryCount,totalSourceTokens,truncated}}}catch{}}return{ok:false,error:formatInvalidDelegatedReply(reply,"non-JSON output")}}function resolveSourceConversationId(params){if(typeof params.scopedConversationId==="number"){const mismatched=params.candidates.filter(candidate=>candidate.conversationId!==params.scopedConversationId).map(candidate=>candidate.summaryId);if(mismatched.length>0){throw new Error(`Some summaryIds are outside conversation ${params.scopedConversationId}: ${mismatched.join(", ")}`)}return params.scopedConversationId}const conversationIds=Array.from(new Set(params.candidates.map(candidate=>candidate.conversationId)));if(conversationIds.length===1&&typeof conversationIds[0]==="number"){return conversationIds[0]}if(params.allConversations&&conversationIds.length>1){throw new Error("Query matched summaries from multiple conversations. Provide conversationId or narrow the query.")}throw new Error("Unable to resolve a single conversation scope. Provide conversationId or set a narrower summary scope.")}function selectSingleConversationBucket(params){const bucket=params.buckets.find(candidateBucket=>candidateBucket.conversationId===params.sourceConversationId);if(!bucket||bucket.summaryIds.length===0){throw new Error("No summaryIds available after applying conversation scope.")}return bucket}function upsertSummaryCandidate(candidates,candidate){const existing=candidates.get(candidate.summaryId);if(!existing){candidates.set(candidate.summaryId,candidate);return}candidates.set(candidate.summaryId,{...existing,requiresMessageExpansion:existing.requiresMessageExpansion||candidate.requiresMessageExpansion,isExplicit:existing.isExplicit||candidate.isExplicit,matchedAt:maxDate(existing.matchedAt,candidate.matchedAt)})}async function resolveSummaryCandidates2(params){const retrieval=params.lcm.getRetrieval();const candidates=new Map;for(const summaryId of params.explicitSummaryIds){const described=await retrieval.describe(summaryId);if(!described||described.type!=="summary"||!described.summary){throw new Error(`Summary not found: ${summaryId}`)}upsertSummaryCandidate(candidates,{summaryId,conversationId:described.summary.conversationId,requiresMessageExpansion:false,isExplicit:true,matchedAt:described.summary.latestAt??described.summary.createdAt})}if(params.query){const summaryStore=params.lcm.getSummaryStore();const grepResult=await retrieval.grep({query:params.query,mode:"full_text",scope:"summaries",conversationId:params.conversationId});for(const summary of grepResult.summaries){upsertSummaryCandidate(candidates,{summaryId:summary.summaryId,conversationId:summary.conversationId,requiresMessageExpansion:false,isExplicit:false,matchedAt:summary.createdAt})}if(grepResult.summaries.length===0&&typeof params.conversationId==="number"){const maxDepth=await summaryStore.getConversationMaxSummaryDepth(params.conversationId);if(typeof maxDepth==="number"&&maxDepth<=1){const messageResult=await retrieval.grep({query:params.query,mode:"full_text",scope:"messages",conversationId:params.conversationId});const messageIds=messageResult.messages.map(message=>message.messageId);const leafLinks=await summaryStore.getLeafSummaryLinksForMessageIds(params.conversationId,messageIds);const summaryIdsByMessageId=new Map;for(const link of leafLinks){const linkedSummaryIds=summaryIdsByMessageId.get(link.messageId)??[];if(!linkedSummaryIds.includes(link.summaryId)){linkedSummaryIds.push(link.summaryId);summaryIdsByMessageId.set(link.messageId,linkedSummaryIds)}}for(const message of messageResult.messages){for(const summaryId of summaryIdsByMessageId.get(message.messageId)??[]){upsertSummaryCandidate(candidates,{summaryId,conversationId:params.conversationId,requiresMessageExpansion:true,isExplicit:false,matchedAt:message.createdAt})}}}}}return Array.from(candidates.values())}async function runDelegatedExpandQuery(params){const task=buildDelegatedExpandQueryTask({summaryIds:params.bucket.summaryIds,messageBackedSummaryIds:params.bucket.messageBackedSummaryIds,conversationId:params.bucket.conversationId,query:params.query,prompt:params.prompt,maxTokens:params.maxTokens,tokenCap:params.tokenCap,requestId:params.requestId,expansionDepth:params.childExpansionDepth,originSessionKey:params.originSessionKey});const expansionProvider=params.deps.config.expansionProvider||void 0;const expansionModel=params.deps.config.expansionModel||void 0;const canonicalExpansionModel=expansionModel?.includes("/")?expansionModel:void 0;const delegatedOverrideProvider=canonicalExpansionModel?void 0:expansionProvider;const delegatedOverrideModel=canonicalExpansionModel||expansionModel;const configuredOverrideLabel=delegatedOverrideProvider&&delegatedOverrideModel?`${delegatedOverrideProvider}/${delegatedOverrideModel}`:delegatedOverrideModel||delegatedOverrideProvider||"configured override";const runDelegatedQuery=async(provider,model)=>{const childSessionKey=`agent:${params.requesterAgentId}:subagent:${crypto4.randomUUID()}`;const childIdem=crypto4.randomUUID();let grantCreated=false;try{createDelegatedExpansionGrant({delegatedSessionKey:childSessionKey,issuerSessionId:params.callerSessionKey||"main",allowedConversationIds:[params.bucket.conversationId],tokenCap:params.tokenCap,ttlMs:params.delegatedWaitTimeoutMs+3e4});stampDelegatedExpansionContext({sessionKey:childSessionKey,requestId:params.requestId,expansionDepth:params.childExpansionDepth,originSessionKey:params.originSessionKey,stampedBy:"lcm_expand_query"});grantCreated=true;const response=await params.deps.callGateway({method:"agent",params:{message:task,sessionKey:childSessionKey,deliver:false,lane:params.deps.agentLaneSubagent,idempotencyKey:childIdem,...provider?{provider}:{},...model?{model}:{},extraSystemPrompt:params.deps.buildSubagentSystemPrompt({depth:1,maxDepth:8,taskSummary:"Run lcm_expand and return prompt-focused JSON answer"})},timeoutMs:GATEWAY_TIMEOUT_MS});const runId=typeof response?.runId==="string"?response.runId.trim():"";if(!runId){throw new Error(formatExpansionFailure(response?.error??response)||"Delegated expansion did not return a runId.")}const wait=await params.deps.callGateway({method:"agent.wait",params:{runId,timeoutMs:params.delegatedWaitTimeoutMs},timeoutMs:params.delegatedWaitTimeoutMs});const status=typeof wait?.status==="string"?wait.status:"error";if(status==="timeout"){recordExpansionDelegationTelemetry({deps:params.deps,component:"lcm_expand_query",event:"timeout",requestId:params.requestId,sessionKey:params.callerSessionKey,expansionDepth:params.childExpansionDepth,originSessionKey:params.originSessionKey,runId});throw new Error(`lcm_expand_query timed out waiting for delegated expansion (${params.delegatedWaitTimeoutSeconds}s).`)}if(status!=="ok"){throw new Error(formatExpansionFailure(wait?.error))}const replyPayload=await params.deps.callGateway({method:"sessions.get",params:{key:childSessionKey,limit:80},timeoutMs:GATEWAY_TIMEOUT_MS});const reply=params.deps.readLatestAssistantReply(Array.isArray(replyPayload.messages)?replyPayload.messages:[]);const parsed=parseDelegatedExpandQueryReply(reply,params.bucket.summaryIds.length);if(!parsed.ok){throw new Error(parsed.error)}recordExpansionDelegationTelemetry({deps:params.deps,component:"lcm_expand_query",event:"success",requestId:params.requestId,sessionKey:params.callerSessionKey,expansionDepth:params.childExpansionDepth,originSessionKey:params.originSessionKey,runId});return parsed.value}finally{try{await params.deps.callGateway({method:"sessions.delete",params:{key:childSessionKey,deleteTranscript:true},timeoutMs:GATEWAY_TIMEOUT_MS})}catch{}if(grantCreated){revokeDelegatedExpansionGrantForSession(childSessionKey,{removeBinding:true})}clearDelegatedExpansionContext(childSessionKey)}};if(!expansionProvider&&!expansionModel){return await runDelegatedQuery()}try{return await runDelegatedQuery(delegatedOverrideProvider,delegatedOverrideModel)}catch(error){const failure=formatExpansionFailure(error);params.deps.log.warn(`[lcm] delegated expansion override failed (${configuredOverrideLabel}) for conversation ${params.bucket.conversationId}: ${failure}`);if(!shouldRetryWithoutOverride(failure)){throw new Error(failure)}params.deps.log.warn(`[lcm] retrying delegated expansion without provider/model override after: ${failure}`);return await runDelegatedQuery()}}function createLcmExpandQueryTool(input){const delegatedWaitTimeoutMs=input.deps.config.delegationTimeoutMs||DEFAULT_DELEGATED_WAIT_TIMEOUT_MS;const delegatedWaitTimeoutSeconds=Math.ceil(delegatedWaitTimeoutMs/1e3);return{name:"lcm_expand_query",label:"LCM Expand Query",description:"Answer a focused natural-language question using delegated LCM expansion. Find candidate summaries (by IDs or a short FTS5 query that follows the same full-text rules as lcm_grep), expand them in a delegated sub-agent, and return a compact prompt-focused answer. Tool output includes cited summary IDs for follow-up.",parameters:LcmExpandQuerySchema,async execute(_toolCallId,params){const lcm=input.lcm??await input.getLcm?.();if(!lcm){throw new Error("LCM engine is unavailable.")}const p=params;const explicitSummaryIds=normalizeSummaryIds(p.summaryIds);const query=typeof p.query==="string"?p.query.trim():"";const prompt=typeof p.prompt==="string"?p.prompt.trim():"";const requestedMaxTokens=typeof p.maxTokens==="number"?Math.trunc(p.maxTokens):void 0;const maxTokens=typeof requestedMaxTokens==="number"&&Number.isFinite(requestedMaxTokens)?Math.max(1,requestedMaxTokens):DEFAULT_MAX_ANSWER_TOKENS;const requestedTokenCap=typeof p.tokenCap==="number"?Math.trunc(p.tokenCap):void 0;const expansionTokenCap=typeof requestedTokenCap==="number"&&Number.isFinite(requestedTokenCap)?Math.max(1,requestedTokenCap):Math.max(1,Math.trunc(input.deps.config.maxExpandTokens));if(!prompt){return jsonResult({error:"prompt is required."})}if(explicitSummaryIds.length===0&&!query){return jsonResult({error:"Either summaryIds or query must be provided."})}const callerSessionKey=(typeof input.requesterSessionKey==="string"?input.requesterSessionKey:input.sessionId)?.trim()??"";const requestId=resolveExpansionRequestId(callerSessionKey);const recursionCheck=evaluateExpansionRecursionGuard({sessionKey:callerSessionKey,requestId});recordExpansionDelegationTelemetry({deps:input.deps,component:"lcm_expand_query",event:"start",requestId,sessionKey:callerSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey});if(recursionCheck.blocked){recordExpansionDelegationTelemetry({deps:input.deps,component:"lcm_expand_query",event:"block",requestId,sessionKey:callerSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey,reason:recursionCheck.reason});return jsonResult({errorCode:recursionCheck.code,error:recursionCheck.message,requestId:recursionCheck.requestId,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey,reason:recursionCheck.reason})}const originSessionKey=recursionCheck.originSessionKey||callerSessionKey||"main";try{const conversationScope=await resolveLcmConversationScope({lcm,deps:input.deps,sessionId:input.sessionId,sessionKey:input.sessionKey,params:p});let scopedConversationId=conversationScope.conversationId;if(!conversationScope.allConversations&&scopedConversationId==null&&callerSessionKey){scopedConversationId=await resolveRequesterConversationScopeId({deps:input.deps,requesterSessionKey:callerSessionKey,lcm})}if(!conversationScope.allConversations&&scopedConversationId==null){return jsonResult({error:"No LCM conversation found for this session. Provide conversationId or set allConversations=true."})}const candidates=await resolveSummaryCandidates2({lcm,explicitSummaryIds,query:query||void 0,conversationId:scopedConversationId});if(candidates.length===0){if(typeof scopedConversationId!=="number"){return jsonResult({error:"No matching summaries found."})}return jsonResult(buildExpandQueryReply({answer:"No matching summaries found for this scope.",citedIds:[],sourceConversationIds:[scopedConversationId],expandedSummaryCount:0,totalSourceTokens:0,truncated:false}))}const conversationBuckets=buildConversationBuckets(candidates);const concurrencyCheck=acquireExpansionConcurrencySlot({originSessionKey,requestId});if(concurrencyCheck.blocked){recordExpansionDelegationTelemetry({deps:input.deps,component:"lcm_expand_query",event:"block",requestId,sessionKey:callerSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:concurrencyCheck.originSessionKey,reason:concurrencyCheck.reason});return jsonResult({errorCode:concurrencyCheck.code,error:concurrencyCheck.message,requestId:concurrencyCheck.requestId,expansionDepth:recursionCheck.expansionDepth,originSessionKey:concurrencyCheck.originSessionKey,reason:concurrencyCheck.reason})}const requesterAgentId=input.deps.normalizeAgentId(input.deps.parseAgentSessionKey(callerSessionKey)?.agentId);const childExpansionDepth=resolveNextExpansionDepth(callerSessionKey);if(!conversationScope.allConversations){const sourceConversationId=resolveSourceConversationId({scopedConversationId,allConversations:conversationScope.allConversations,candidates});const bucket=selectSingleConversationBucket({sourceConversationId,buckets:conversationBuckets});const delegatedReply=await runDelegatedExpandQuery({deps:input.deps,callerSessionKey,requesterAgentId,bucket,query:query||void 0,prompt,maxTokens,tokenCap:expansionTokenCap,requestId,childExpansionDepth,originSessionKey,delegatedWaitTimeoutMs,delegatedWaitTimeoutSeconds});return jsonResult(buildExpandQueryReply({answer:delegatedReply.answer,citedIds:delegatedReply.citedIds,sourceConversationIds:[sourceConversationId],expandedSummaryCount:delegatedReply.expandedSummaryCount,totalSourceTokens:delegatedReply.totalSourceTokens,truncated:delegatedReply.truncated}))}const rankedBuckets=[...conversationBuckets].sort(compareConversationBuckets);const bucketResults=[];const bucketsToExpand=rankedBuckets.slice(0,DEFAULT_MAX_CONVERSATION_BUCKETS);const skippedBuckets=rankedBuckets.slice(DEFAULT_MAX_CONVERSATION_BUCKETS);let remainingTokenCap=expansionTokenCap;let firstFailure;for(const bucket of bucketsToExpand){if(remainingTokenCap<=0){bucketResults.push({conversationId:bucket.conversationId,status:"skipped",candidateCount:bucket.candidateCount,error:"global token budget exhausted"});continue}try{const delegatedReply=await runDelegatedExpandQuery({deps:input.deps,callerSessionKey,requesterAgentId,bucket,query:query||void 0,prompt,maxTokens,tokenCap:remainingTokenCap,requestId,childExpansionDepth,originSessionKey,delegatedWaitTimeoutMs,delegatedWaitTimeoutSeconds});bucketResults.push({conversationId:bucket.conversationId,status:"success",candidateCount:bucket.candidateCount,reply:delegatedReply});remainingTokenCap=Math.max(0,remainingTokenCap-Math.max(0,delegatedReply.totalSourceTokens))}catch(error){const failure=formatExpansionFailure(error);firstFailure??=failure;bucketResults.push({conversationId:bucket.conversationId,status:"failed",candidateCount:bucket.candidateCount,error:failure})}}for(const bucket of skippedBuckets){bucketResults.push({conversationId:bucket.conversationId,status:"skipped",candidateCount:bucket.candidateCount,error:`skipped after reaching max conversation bucket limit (${DEFAULT_MAX_CONVERSATION_BUCKETS})`})}const successfulResults=bucketResults.filter(result=>result.status==="success");if(successfulResults.length===0){throw new Error(firstFailure??"Delegated expansion query failed.")}const conversationBreakdown=bucketResults.map(result=>{if(result.status==="success"){return{conversationId:result.conversationId,expandedSummaryCount:result.reply.expandedSummaryCount,citedIds:result.reply.citedIds,totalSourceTokens:result.reply.totalSourceTokens,truncated:result.reply.truncated,status:"success"}}return{conversationId:result.conversationId,expandedSummaryCount:0,citedIds:[],totalSourceTokens:0,truncated:true,status:result.status,error:result.error}});return jsonResult(buildExpandQueryReply({answer:synthesizeConversationAnswers({prompt,results:bucketResults}),citedIds:successfulResults.flatMap(result=>result.reply.citedIds),sourceConversationIds:successfulResults.map(result=>result.conversationId),expandedSummaryCount:successfulResults.reduce((total,result)=>total+result.reply.expandedSummaryCount,0),totalSourceTokens:successfulResults.reduce((total,result)=>total+result.reply.totalSourceTokens,0),truncated:successfulResults.some(result=>result.reply.truncated)||bucketResults.some(result=>result.status!=="success"),conversationBreakdown}))}catch(error){const failure=formatExpansionFailure(error);input.deps.log.error(`[lcm] delegated expansion query failed: ${failure}`);return jsonResult({error:failure})}finally{releaseExpansionConcurrencySlot({originSessionKey,requestId})}}}}var EXPANSION_ROUTING_THRESHOLDS={defaultDepth:3,minDepth:1,maxDepth:10,directMaxDepth:2,directMaxCandidates:1,moderateTokenRiskRatio:.35,highTokenRiskRatio:.7,baseTokensPerSummary:220,includeMessagesTokenMultiplier:1.9,perDepthTokenGrowth:.65,broadTimeRangeTokenMultiplier:1.35,multiHopTokenMultiplier:1.25,multiHopDepthThreshold:3,multiHopCandidateThreshold:5};var BROAD_TIME_RANGE_PATTERNS=[/\b(last|past)\s+(month|months|quarter|quarters|year|years)\b/i,/\b(over|across|throughout)\s+(time|months|quarters|years)\b/i,/\b(timeline|chronology|history|long[-\s]?term)\b/i,/\bbetween\s+[^.]{0,40}\s+and\s+[^.]{0,40}\b/i];var MULTI_HOP_QUERY_PATTERNS=[/\b(root\s+cause|causal\s+chain|chain\s+of\s+events)\b/i,/\b(multi[-\s]?hop|multi[-\s]?step|cross[-\s]?summary)\b/i,/\bhow\s+did\b.+\blead\s+to\b/i];function normalizeDepth(requestedMaxDepth){if(typeof requestedMaxDepth!=="number"||!Number.isFinite(requestedMaxDepth)){return EXPANSION_ROUTING_THRESHOLDS.defaultDepth}const rounded=Math.trunc(requestedMaxDepth);return Math.max(EXPANSION_ROUTING_THRESHOLDS.minDepth,Math.min(EXPANSION_ROUTING_THRESHOLDS.maxDepth,rounded))}function normalizeTokenCap(tokenCap){if(!Number.isFinite(tokenCap)){return Number.MAX_SAFE_INTEGER}return Math.max(1,Math.trunc(tokenCap))}function detectBroadTimeRangeIndicator(query){if(!query){return false}const trimmed=query.trim();if(!trimmed){return false}if(BROAD_TIME_RANGE_PATTERNS.some(pattern=>pattern.test(trimmed))){return true}const years=Array.from(trimmed.matchAll(/\b(?:19|20)\d{2}\b/g),match=>Number(match[0]));if(years.length<2){return false}const earliest=Math.min(...years);const latest=Math.max(...years);return latest-earliest>=2}function detectMultiHopIndicator(input){const normalizedMaxDepth=normalizeDepth(input.requestedMaxDepth);const candidateSummaryCount=Math.max(0,Math.trunc(input.candidateSummaryCount));if(normalizedMaxDepth>=EXPANSION_ROUTING_THRESHOLDS.multiHopDepthThreshold){return true}if(candidateSummaryCount>=EXPANSION_ROUTING_THRESHOLDS.multiHopCandidateThreshold){return true}if(!input.query){return false}const trimmed=input.query.trim();if(!trimmed){return false}return MULTI_HOP_QUERY_PATTERNS.some(pattern=>pattern.test(trimmed))}function estimateExpansionTokens(input){const normalizedMaxDepth=normalizeDepth(input.requestedMaxDepth);const candidateSummaryCount=Math.max(0,Math.trunc(input.candidateSummaryCount));if(candidateSummaryCount===0){return 0}const includeMessagesMultiplier=input.includeMessages?EXPANSION_ROUTING_THRESHOLDS.includeMessagesTokenMultiplier:1;const depthMultiplier=1+(normalizedMaxDepth-1)*EXPANSION_ROUTING_THRESHOLDS.perDepthTokenGrowth;const timeRangeMultiplier=input.broadTimeRangeIndicator?EXPANSION_ROUTING_THRESHOLDS.broadTimeRangeTokenMultiplier:1;const multiHopMultiplier=input.multiHopIndicator?EXPANSION_ROUTING_THRESHOLDS.multiHopTokenMultiplier:1;const perSummaryEstimate=EXPANSION_ROUTING_THRESHOLDS.baseTokensPerSummary*includeMessagesMultiplier*depthMultiplier*timeRangeMultiplier*multiHopMultiplier;return Math.max(0,Math.ceil(perSummaryEstimate*candidateSummaryCount))}function classifyExpansionTokenRisk(input){const estimatedTokens=Math.max(0,Math.trunc(input.estimatedTokens));const tokenCap=normalizeTokenCap(input.tokenCap);const ratio=estimatedTokens/tokenCap;if(ratio>=EXPANSION_ROUTING_THRESHOLDS.highTokenRiskRatio){return{ratio,level:"high"}}if(ratio>=EXPANSION_ROUTING_THRESHOLDS.moderateTokenRiskRatio){return{ratio,level:"moderate"}}return{ratio,level:"low"}}function decideLcmExpansionRouting(input){const normalizedMaxDepth=normalizeDepth(input.requestedMaxDepth);const candidateSummaryCount=Math.max(0,Math.trunc(input.candidateSummaryCount));const tokenCap=normalizeTokenCap(input.tokenCap);const broadTimeRange=detectBroadTimeRangeIndicator(input.query);const multiHopRetrieval=detectMultiHopIndicator({query:input.query,requestedMaxDepth:normalizedMaxDepth,candidateSummaryCount});const estimatedTokens=estimateExpansionTokens({requestedMaxDepth:normalizedMaxDepth,candidateSummaryCount,includeMessages:input.includeMessages,broadTimeRangeIndicator:broadTimeRange,multiHopIndicator:multiHopRetrieval});const tokenRisk=classifyExpansionTokenRisk({estimatedTokens,tokenCap});const directByNoCandidates=candidateSummaryCount===0;const directByLowComplexityProbe=input.intent==="query_probe"&&!directByNoCandidates&&normalizedMaxDepth<=EXPANSION_ROUTING_THRESHOLDS.directMaxDepth&&candidateSummaryCount<=EXPANSION_ROUTING_THRESHOLDS.directMaxCandidates&&tokenRisk.level==="low"&&!broadTimeRange&&!multiHopRetrieval;const delegateByDepth=false;const delegateByCandidateCount=false;const delegateByTokenRisk=tokenRisk.level==="high";const delegateByBroadTimeRangeAndMultiHop=broadTimeRange&&multiHopRetrieval;const shouldDirect=directByNoCandidates||directByLowComplexityProbe;const shouldDelegate=!shouldDirect&&(delegateByTokenRisk||delegateByBroadTimeRangeAndMultiHop);const action=shouldDirect?"answer_directly":shouldDelegate?"delegate_traversal":"expand_shallow";const reasons=[];if(directByNoCandidates){reasons.push("No candidate summary IDs are available.")}if(directByLowComplexityProbe){reasons.push("Query probe is low complexity and below retrieval-risk thresholds.")}if(delegateByTokenRisk){reasons.push(`Estimated token risk ratio ${tokenRisk.ratio.toFixed(2)} meets delegate threshold ${EXPANSION_ROUTING_THRESHOLDS.highTokenRiskRatio.toFixed(2)}.`)}if(delegateByBroadTimeRangeAndMultiHop){reasons.push("Broad time-range request combined with multi-hop retrieval indicators.")}if(action==="expand_shallow"){reasons.push("Complexity is bounded; use direct/shallow expansion.")}return{action,normalizedMaxDepth,candidateSummaryCount,estimatedTokens,tokenCap,tokenRiskRatio:tokenRisk.ratio,tokenRiskLevel:tokenRisk.level,indicators:{broadTimeRange,multiHopRetrieval},triggers:{directByNoCandidates,directByLowComplexityProbe,delegateByDepth,delegateByCandidateCount,delegateByTokenRisk,delegateByBroadTimeRangeAndMultiHop},reasons}}var SNIPPET_MAX_CHARS=200;function truncateSnippet(content,maxChars=SNIPPET_MAX_CHARS){if(content.length<=maxChars){return content}return content.slice(0,maxChars)+"..."}function toExpansionEntry(summaryId,raw){return{summaryId,children:raw.children.map(c=>({summaryId:c.summaryId,kind:c.kind,snippet:truncateSnippet(c.content),tokenCount:c.tokenCount})),messages:raw.messages.map(m=>({messageId:m.messageId,role:m.role,snippet:truncateSnippet(m.content),tokenCount:m.tokenCount}))}}function collectCitedIds(entry){const ids=[entry.summaryId];for(const child of entry.children){ids.push(child.summaryId)}return ids}var ExpansionOrchestrator=class{constructor(retrieval){this.retrieval=retrieval}retrieval;async expand(request){const maxDepth=request.maxDepth??3;const tokenCap=request.tokenCap??Infinity;const includeMessages=request.includeMessages??false;const result={expansions:[],citedIds:[],totalTokens:0,truncated:false};const citedSet=new Set;for(const summaryId of request.summaryIds){if(result.truncated){break}const remainingBudget=tokenCap-result.totalTokens;if(remainingBudget<=0){result.truncated=true;break}const raw=await this.retrieval.expand({summaryId,depth:maxDepth,includeMessages,tokenCap:remainingBudget});const entry=toExpansionEntry(summaryId,raw);result.expansions.push(entry);result.totalTokens+=raw.estimatedTokens;for(const id of collectCitedIds(entry)){citedSet.add(id)}if(raw.truncated){result.truncated=true}}result.citedIds=[...citedSet];return result}async describeAndExpand(input){const grepResult=await this.retrieval.grep({query:input.query,mode:input.mode,scope:"summaries",conversationId:input.conversationId});const summaryIds=[...grepResult.summaries].sort((a,b)=>{const recencyDelta=b.createdAt.getTime()-a.createdAt.getTime();if(recencyDelta!==0){return recencyDelta}const aRank=a.rank??Number.POSITIVE_INFINITY;const bRank=b.rank??Number.POSITIVE_INFINITY;return aRank-bRank}).map(s=>s.summaryId);if(summaryIds.length===0){return{expansions:[],citedIds:[],totalTokens:0,truncated:false}}return this.expand({summaryIds,maxDepth:input.maxDepth,tokenCap:input.tokenCap,includeMessages:false,conversationId:input.conversationId??0})}};function distillForSubagent(result){const lines=[];lines.push(`## Expansion Results (${result.expansions.length} summaries, ${result.totalTokens} total tokens)`);lines.push("");for(const entry of result.expansions){const kind=entry.children.length>0?"condensed":"leaf";const tokenSum=entry.children.reduce((sum,c)=>sum+c.tokenCount,0)+entry.messages.reduce((sum,m)=>sum+m.tokenCount,0);lines.push(`### ${entry.summaryId} (${kind}, ${tokenSum} tokens)`);if(entry.children.length>0){lines.push(`Children: ${entry.children.map(c=>c.summaryId).join(", ")}`)}if(entry.messages.length>0){const msgParts=entry.messages.map(m=>`msg#${m.messageId} (${m.role}, ${m.tokenCount} tokens)`);lines.push(`Messages: ${msgParts.join(", ")}`)}for(const child of entry.children){if(child.snippet){lines.push(`[Snippet: ${truncateSnippet(child.snippet)}]`);break}}lines.push("")}if(result.citedIds.length>0){lines.push(`Cited IDs for follow-up: ${result.citedIds.join(", ")}`)}lines.push(`[Truncated: ${result.truncated?"yes":"no"}]`);return lines.join("\n")}var LcmExpansionSchema=Type.Object({summaryIds:Type.Optional(Type.Array(Type.String(),{description:"Summary IDs to expand (e.g. sum_abc123). Required if query is not provided."})),query:Type.Optional(Type.String({description:"Text query to grep for matching summaries before expanding. If provided, summaryIds is ignored and the top grep results are expanded instead."})),maxDepth:Type.Optional(Type.Number({description:"Max traversal depth per summary (default: 3).",minimum:1,maximum:10})),tokenCap:Type.Optional(Type.Number({description:"Max tokens across the entire expansion result.",minimum:1})),includeMessages:Type.Optional(Type.Boolean({description:"Whether to include raw source messages at leaf level (default: false)."}))});var LcmExpandSchema=Type.Object({summaryIds:Type.Optional(Type.Array(Type.String(),{description:"Summary IDs to expand (sum_xxx format). Required if query is not provided."})),query:Type.Optional(Type.String({description:"Text query to grep for matching summaries before expanding. If provided, summaryIds is ignored and the top grep results are expanded."})),maxDepth:Type.Optional(Type.Number({description:"Max traversal depth per summary (default: 3).",minimum:1})),tokenCap:Type.Optional(Type.Number({description:"Max tokens across the entire expansion result.",minimum:1})),includeMessages:Type.Optional(Type.Boolean({description:"Whether to include raw source messages at leaf level (default: false)."})),conversationId:Type.Optional(Type.Number({description:"Conversation ID to scope the expansion to. If omitted, uses the current session's conversation."})),allConversations:Type.Optional(Type.Boolean({description:"Set true to explicitly allow cross-conversation expansion. Ignored when conversationId is provided."}))});function makeEmptyExpansionResult(){return{expansions:[],citedIds:[],totalTokens:0,truncated:false}}function toDelegatedRunReferences(delegated){if(!delegated){return void 0}const refs=delegated.passes.map(pass=>({pass:pass.pass,status:pass.status,runId:pass.runId,childSessionKey:pass.childSessionKey}));return refs.length>0?refs:void 0}function buildOrchestrationObservability(input){return{decisionPath:{policyAction:input.policy.action,executionPath:input.executionPath},policyReasons:input.policy.reasons,delegatedRunRefs:toDelegatedRunReferences(input.delegated)}}function createLcmExpandTool(input){return{name:"lcm_expand",label:"LCM Expand",description:"Expand compacted conversation summaries from LCM (Lossless Context Management). Traverses the summary DAG to retrieve children and source messages. Use this to drill into previously-compacted context when you need detail that was summarised away. Provide either summaryIds (direct expansion) or query (grep-first, then expand top matches). Returns a compact text payload plus cited IDs in tool output for follow-up.",parameters:LcmExpandSchema,async execute(_toolCallId,params){const lcm=input.lcm??await input.getLcm?.();if(!lcm){throw new Error("LCM engine is unavailable.")}const retrieval=lcm.getRetrieval();const orchestrator=new ExpansionOrchestrator(retrieval);const runtimeAuthManager=getRuntimeExpansionAuthManager();const p=params;const summaryIds=p.summaryIds;const query=typeof p.query==="string"?p.query.trim():void 0;const maxDepth=typeof p.maxDepth==="number"?Math.trunc(p.maxDepth):void 0;const requestedTokenCap=typeof p.tokenCap==="number"?Math.trunc(p.tokenCap):void 0;const tokenCap=typeof requestedTokenCap==="number"&&Number.isFinite(requestedTokenCap)?Math.max(1,requestedTokenCap):void 0;const includeMessages=typeof p.includeMessages==="boolean"?p.includeMessages:false;const sessionKey=(typeof input.sessionKey==="string"?input.sessionKey:input.sessionId)?.trim()??"";if(!input.deps.isSubagentSessionKey(sessionKey)){return jsonResult({error:"lcm_expand is only available in sub-agent sessions. Use lcm_expand_query to ask a focused question against expanded summaries, or lcm_describe/lcm_grep for lighter lookups."})}const isDelegatedSession=input.deps.isSubagentSessionKey(sessionKey);const delegatedGrantId=isDelegatedSession?resolveDelegatedExpansionGrantId(sessionKey)??void 0:void 0;const delegatedGrant=delegatedGrantId!==void 0?runtimeAuthManager.getGrant(delegatedGrantId):null;const authorizedOrchestrator=delegatedGrantId!==void 0?wrapWithAuth(orchestrator,runtimeAuthManager):null;if(isDelegatedSession&&!delegatedGrantId){return jsonResult({error:"Delegated expansion requires a valid grant. This sub-agent session has no propagated expansion grant."})}const conversationScope=await resolveLcmConversationScope({lcm,deps:input.deps,sessionId:input.sessionId,sessionKey:input.sessionKey,params:p});const runExpand=async input2=>{if(!authorizedOrchestrator||!delegatedGrantId){return orchestrator.expand(input2)}return authorizedOrchestrator.expand(delegatedGrantId,input2)};const resolvedConversationId=conversationScope.conversationId??(delegatedGrant?.allowedConversationIds.length===1?delegatedGrant.allowedConversationIds[0]:void 0);if(query){try{if(resolvedConversationId==null){const result2=await orchestrator.describeAndExpand({query,mode:"full_text",conversationId:void 0,maxDepth,tokenCap});const text2=distillForSubagent(result2);const policy2=decideLcmExpansionRouting({intent:"query_probe",query,requestedMaxDepth:maxDepth,candidateSummaryCount:result2.expansions.length,tokenCap:tokenCap??Number.MAX_SAFE_INTEGER,includeMessages:false});return{content:[{type:"text",text:text2}],details:{expansionCount:result2.expansions.length,citedIds:result2.citedIds,totalTokens:result2.totalTokens,truncated:result2.truncated,policy:policy2,executionPath:"direct",observability:buildOrchestrationObservability({policy:policy2,executionPath:"direct"})}}}const grepResult=await retrieval.grep({query,mode:"full_text",scope:"summaries",conversationId:resolvedConversationId});const matchedSummaryIds=grepResult.summaries.map(entry=>entry.summaryId);const policy=decideLcmExpansionRouting({intent:"query_probe",query,requestedMaxDepth:maxDepth,candidateSummaryCount:matchedSummaryIds.length,tokenCap:tokenCap??Number.MAX_SAFE_INTEGER,includeMessages:false});const canDelegate=matchedSummaryIds.length>0&&policy.action==="delegate_traversal"&&!isDelegatedSession&&!!sessionKey;const delegated=canDelegate&&resolvedConversationId!=null?await runDelegatedExpansionLoop({deps:input.deps,requesterSessionKey:sessionKey,conversationId:resolvedConversationId,summaryIds:matchedSummaryIds,maxDepth,tokenCap,includeMessages:false,query}):void 0;if(delegated&&delegated.status==="ok"){return{content:[{type:"text",text:delegated.text}],details:{expansionCount:delegated.citedIds.length,citedIds:delegated.citedIds,totalTokens:delegated.totalTokens,truncated:delegated.truncated,policy,executionPath:"delegated",delegated,observability:buildOrchestrationObservability({policy,executionPath:"delegated",delegated})}}}const executionPath=delegated?"direct_fallback":"direct";const result=matchedSummaryIds.length===0?makeEmptyExpansionResult():await runExpand({summaryIds:matchedSummaryIds,maxDepth,tokenCap,includeMessages:false,conversationId:resolvedConversationId});const text=distillForSubagent(result);return{content:[{type:"text",text}],details:{expansionCount:result.expansions.length,citedIds:result.citedIds,totalTokens:result.totalTokens,truncated:result.truncated,policy,executionPath,delegated:delegated&&delegated.status!=="ok"?{status:delegated.status,error:delegated.error,passes:delegated.passes}:void 0,observability:buildOrchestrationObservability({policy,executionPath,delegated})}}}catch(err){const message=err instanceof Error?err.message:String(err);return jsonResult({error:message})}}if(summaryIds&&summaryIds.length>0){try{if(conversationScope.conversationId!=null){const outOfScope=[];for(const summaryId of summaryIds){const described=await retrieval.describe(summaryId);if(described?.type==="summary"&&described.summary?.conversationId!==conversationScope.conversationId){outOfScope.push(summaryId)}}if(outOfScope.length>0){return jsonResult({error:`Some summaryIds are outside conversation ${conversationScope.conversationId}: `+outOfScope.join(", "),hint:"Use allConversations=true for cross-conversation expansion."})}}const policy=decideLcmExpansionRouting({intent:"explicit_expand",requestedMaxDepth:maxDepth,candidateSummaryCount:summaryIds.length,tokenCap:tokenCap??Number.MAX_SAFE_INTEGER,includeMessages});const normalizedSummaryIds=normalizeSummaryIds(summaryIds);const canDelegate=normalizedSummaryIds.length>0&&policy.action==="delegate_traversal"&&!isDelegatedSession&&!!sessionKey&&resolvedConversationId!=null;const delegated=canDelegate?await runDelegatedExpansionLoop({deps:input.deps,requesterSessionKey:sessionKey,conversationId:resolvedConversationId,summaryIds:normalizedSummaryIds,maxDepth,tokenCap,includeMessages}):void 0;if(delegated&&delegated.status==="ok"){return{content:[{type:"text",text:delegated.text}],details:{expansionCount:delegated.citedIds.length,citedIds:delegated.citedIds,totalTokens:delegated.totalTokens,truncated:delegated.truncated,policy,executionPath:"delegated",delegated,observability:buildOrchestrationObservability({policy,executionPath:"delegated",delegated})}}}const executionPath=delegated?"direct_fallback":"direct";const result=await runExpand({summaryIds:normalizedSummaryIds,maxDepth,tokenCap,includeMessages,conversationId:resolvedConversationId??0});const text=distillForSubagent(result);return{content:[{type:"text",text}],details:{expansionCount:result.expansions.length,citedIds:result.citedIds,totalTokens:result.totalTokens,truncated:result.truncated,policy,executionPath,delegated:delegated&&delegated.status!=="ok"?{status:delegated.status,error:delegated.error,passes:delegated.passes}:void 0,observability:buildOrchestrationObservability({policy,executionPath,delegated})}}}catch(err){const message=err instanceof Error?err.message:String(err);return jsonResult({error:message})}}return jsonResult({error:"Either summaryIds or query must be provided."})}}}var MAX_RESULT_CHARS=4e4;function formatDisplayTime2(value,timezone){if(value==null){return"-"}const date=value instanceof Date?value:new Date(value);if(Number.isNaN(date.getTime())){return"-"}return formatTimestamp(date,timezone)}var LcmGrepSchema=Type.Object({pattern:Type.String({description:'Search pattern. Interpreted as regex when mode is "regex", or as an FTS5 text query when mode is "full_text". In full_text mode, FTS5 defaults to AND matching, so prefer 1-3 distinctive terms or one quoted multi-word phrase instead of padding with synonyms or extra keywords.'}),mode:Type.Optional(Type.String({description:'Search mode: "regex" for regular expression matching, "full_text" for text search. Default: "regex".',enum:["regex","full_text"]})),scope:Type.Optional(Type.String({description:'What to search: "messages" for raw messages, "summaries" for compacted summaries, "both" for all. Default: "both".',enum:["messages","summaries","both"]})),conversationId:Type.Optional(Type.Number({description:"Conversation ID to search within. If omitted, defaults to the current session conversation."})),allConversations:Type.Optional(Type.Boolean({description:"Set true to explicitly search across all conversations. Ignored when conversationId is provided."})),since:Type.Optional(Type.String({description:"Only return matches created at or after this ISO timestamp."})),before:Type.Optional(Type.String({description:"Only return matches created before this ISO timestamp."})),limit:Type.Optional(Type.Number({description:"Maximum number of results to return (default: 50).",minimum:1,maximum:200})),sort:Type.Optional(Type.String({description:'Sort order: "recency" (newest first, default), "relevance" (best FTS5 match first, full_text mode only), or "hybrid" (full_text mode only; balances relevance with recency). Applied before limit is enforced.',enum:["recency","relevance","hybrid"]}))});function truncateSnippet2(content,maxLen=200){const singleLine=content.replace(/\n/g," ").trim();if(singleLine.length<=maxLen){return singleLine}return singleLine.substring(0,maxLen-3)+"..."}function createLcmGrepTool(input){return{name:"lcm_grep",label:"LCM Grep",description:"Search compacted conversation history using regex or full-text search. Searches across messages and/or summaries stored by LCM. Use this to find specific content that may have been compacted away from active context. In full_text mode, queries use FTS5 AND semantics by default, so keep them short and focused; quoted phrases stay intact and optional sort modes can prioritize relevance for older topics. Returns matching snippets with their summary/message IDs for follow-up with lcm_expand or lcm_describe.",parameters:LcmGrepSchema,async execute(_toolCallId,params){const lcm=input.lcm??await input.getLcm?.();if(!lcm){throw new Error("LCM engine is unavailable.")}const retrieval=lcm.getRetrieval();const timezone=lcm.timezone;const p=params;const pattern=p.pattern.trim();const mode=p.mode??"regex";const scope=p.scope??"both";const limit=typeof p.limit==="number"?Math.trunc(p.limit):50;const requestedSort=p.sort??"recency";const effectiveSort=mode==="full_text"?requestedSort:"recency";let since;let before;try{since=parseIsoTimestampParam(p,"since");before=parseIsoTimestampParam(p,"before")}catch(error){return jsonResult({error:error instanceof Error?error.message:"Invalid timestamp filter."})}if(since&&before&&since.getTime()>=before.getTime()){return jsonResult({error:"`since` must be earlier than `before`."})}const conversationScope=await resolveLcmConversationScope({lcm,deps:input.deps,sessionId:input.sessionId,sessionKey:input.sessionKey,params:p});if(!conversationScope.allConversations&&conversationScope.conversationId==null){return jsonResult({error:"No LCM conversation found for this session. Provide conversationId or set allConversations=true."})}const result=await retrieval.grep({query:pattern,mode,scope,conversationId:conversationScope.conversationId,limit,since,before,sort:effectiveSort});const lines=[];lines.push("## LCM Grep Results");lines.push(`**Pattern:** \`${pattern}\``);lines.push(`**Mode:** ${mode} | **Scope:** ${scope} | **Sort:** ${effectiveSort}`);if(conversationScope.allConversations){lines.push("**Conversation scope:** all conversations")}else if(conversationScope.conversationId!=null){lines.push(`**Conversation scope:** ${conversationScope.conversationId}`)}if(since||before){lines.push(`**Time filter:** ${since?`since ${formatDisplayTime2(since,timezone)}`:"since -\u221E"} | ${before?`before ${formatDisplayTime2(before,timezone)}`:"before +\u221E"}`)}lines.push(`**Total matches:** ${result.totalMatches}`);lines.push("");let currentChars=lines.join("\n").length;if(result.messages.length>0){lines.push("### Messages");lines.push("");for(const msg of result.messages){const snippet=truncateSnippet2(msg.snippet);const line=`- [msg#${msg.messageId}] (${msg.role}, ${formatDisplayTime2(msg.createdAt,timezone)}): ${snippet}`;if(currentChars+line.length>MAX_RESULT_CHARS){lines.push("*(truncated \u2014 more results available)*");break}lines.push(line);currentChars+=line.length}lines.push("")}if(result.summaries.length>0){lines.push("### Summaries");lines.push("");for(const sum of result.summaries){const snippet=truncateSnippet2(sum.snippet);const line=`- [${sum.summaryId}] (${sum.kind}, ${formatDisplayTime2(sum.createdAt,timezone)}): ${snippet}`;if(currentChars+line.length>MAX_RESULT_CHARS){lines.push("*(truncated \u2014 more results available)*");break}lines.push(line);currentChars+=line.length}lines.push("")}if(result.totalMatches===0){lines.push("No matches found.")}return{content:[{type:"text",text:lines.join("\n")}],details:{messageCount:result.messages.length,summaryCount:result.summaries.length,totalMatches:result.totalMatches}}}}}import{existsSync,statSync as statSync2}from"node:fs";var package_default={name:"@martian-engineering/lossless-claw",version:"0.9.0",description:"Lossless Context Management plugin for OpenClaw \u2014 DAG-based conversation summarization with incremental compaction",type:"module",main:"dist/index.js",license:"MIT",author:"Josh Lehman <josh@martian.engineering>",keywords:["openclaw","openclaw-plugin","context-management","llm","summarization","conversation-memory","dag"],scripts:{build:'esbuild index.ts --bundle --platform=node --target=node22 --format=esm --outfile=dist/index.js --external:openclaw --external:"@mariozechner/*" --minify-whitespace',changeset:"changeset","release:verify":"npm run build && npm test && npm pack --dry-run",test:"vitest run --dir test","version-packages":"changeset version"},files:["dist/","skills/","openclaw.plugin.json","docs/","README.md","LICENSE"],dependencies:{"@mariozechner/pi-agent-core":"*","@mariozechner/pi-ai":"*","@sinclair/typebox":"0.34.48"},devDependencies:{"@changesets/changelog-github":"^0.6.0","@changesets/cli":"^2.30.0",esbuild:"^0.28.0",typescript:"^5.7.0",vitest:"^3.0.0"},peerDependencies:{openclaw:"*"},publishConfig:{access:"public"},openclaw:{extensions:["./dist/index.js"]},repository:{type:"git",url:"git+https://github.com/Martian-Engineering/lossless-claw.git"},homepage:"https://github.com/Martian-Engineering/lossless-claw#readme",bugs:{url:"https://github.com/Martian-Engineering/lossless-claw/issues"}};var FALLBACK_SUMMARY_MARKER="[LCM fallback summary; truncated for context management]";var TRUNCATED_SUMMARY_PREFIX="[Truncated from ";var TRUNCATED_SUMMARY_WINDOW=40;var FALLBACK_SUMMARY_WINDOW=80;function detectDoctorMarker(content){if(content.startsWith(FALLBACK_SUMMARY_MARKER)){return"old"}const truncatedIndex=content.indexOf(TRUNCATED_SUMMARY_PREFIX);if(truncatedIndex>=0&&content.length-truncatedIndex<TRUNCATED_SUMMARY_WINDOW){return"new"}const fallbackIndex=content.indexOf(FALLBACK_SUMMARY_MARKER);if(fallbackIndex>=0&&content.length-fallbackIndex<FALLBACK_SUMMARY_WINDOW){return"fallback"}return null}function loadDoctorTargets(db,conversationId){const statement=conversationId===void 0?db.prepare(`SELECT
|
|
745
|
+
${externalized.reference}`,fileIds:[externalized.fileId]}}async interceptPureBase64Image(params){const trimmed=params.content.trim();if(estimateTokens(trimmed)<100){return null}const detected=_LcmContextEngine.detectBase64ImageType(trimmed);if(!detected){return null}const b64Chars=trimmed.replace(/[^A-Za-z0-9+/=\s]/g,"");if(b64Chars.length/trimmed.length<.8){return null}const label=params.role==="tool"?"Tool image":params.role==="assistant"?"Assistant image":"Image";const fileName=`${params.role}-image.${detected.extension}`;const externalized=await this.externalizeImage({conversationId:params.conversationId,base64Data:trimmed,fileName,extension:detected.extension,mimeType:detected.mimeType,label});return{rewrittenContent:externalized.reference,fileIds:[externalized.fileId]}}async rewriteToolInlineImageValue(params){if(typeof params.value==="string"){const intercepted=await this.interceptPureBase64Image({conversationId:params.conversationId,content:params.value,role:"tool"});if(!intercepted){return{rewrittenValue:params.value,fileIds:[],changed:false}}return{rewrittenValue:intercepted.rewrittenContent,fileIds:intercepted.fileIds,changed:true}}if(Array.isArray(params.value)){const rewrittenValues=[];const fileIds2=[];let changed2=false;for(const entry of params.value){const rewritten=await this.rewriteToolInlineImageValue({conversationId:params.conversationId,value:entry});rewrittenValues.push(rewritten.rewrittenValue);fileIds2.push(...rewritten.fileIds);changed2||=rewritten.changed}return changed2?{rewrittenValue:rewrittenValues,fileIds:fileIds2,changed:true}:{rewrittenValue:params.value,fileIds:[],changed:false}}if(!params.value||typeof params.value!=="object"){return{rewrittenValue:params.value,fileIds:[],changed:false}}const record=params.value;if(record.type==="text"&&typeof record.text==="string"){const intercepted=await this.interceptPureBase64Image({conversationId:params.conversationId,content:record.text,role:"tool"});if(!intercepted){return{rewrittenValue:params.value,fileIds:[],changed:false}}return{rewrittenValue:{...record,text:intercepted.rewrittenContent},fileIds:intercepted.fileIds,changed:true}}const nestedKeys=["output","content","result"];const rewrittenRecord={...record};const fileIds=[];let changed=false;for(const key of nestedKeys){if(!(key in record)){continue}const rewritten=await this.rewriteToolInlineImageValue({conversationId:params.conversationId,value:record[key]});if(!rewritten.changed){continue}rewrittenRecord[key]=rewritten.rewrittenValue;fileIds.push(...rewritten.fileIds);changed=true}return changed?{rewrittenValue:rewrittenRecord,fileIds,changed:true}:{rewrittenValue:params.value,fileIds:[],changed:false}}async interceptInlineImagesInToolMessage(params){if(params.message.role!=="toolResult"&¶ms.message.role!=="tool"||!("content"in params.message)){return null}if(typeof params.message.content==="string"){const intercepted=await this.interceptPureBase64Image({conversationId:params.conversationId,content:params.message.content,role:"tool"});if(!intercepted){return null}return{rewrittenMessage:{...params.message,content:intercepted.rewrittenContent},fileIds:intercepted.fileIds}}if(!Array.isArray(params.message.content)){return null}const rewrittenContent=[];const fileIds=[];let changed=false;for(const item of params.message.content){const rewritten=await this.rewriteToolInlineImageValue({conversationId:params.conversationId,value:item});rewrittenContent.push(rewritten.rewrittenValue);fileIds.push(...rewritten.fileIds);changed||=rewritten.changed}if(!changed){return null}return{rewrittenMessage:{...params.message,content:rewrittenContent},fileIds}}async storeLargeFileContent(params){const dir=this.largeFilesDirForConversation(params.conversationId);await mkdir(dir,{recursive:true});const normalizedExtension=params.extension.replace(/[^a-z0-9]/gi,"").toLowerCase()||"txt";const filePath=join3(dir,`${params.fileId}.${normalizedExtension}`);await writeFile(filePath,params.content,"utf8");return filePath}async externalizeLargeTextPayload(params){const summarizeText=await this.resolveLargeFileTextSummarizer();const fileId=`file_${randomUUID2().replace(/-/g,"").slice(0,16)}`;const extension=extensionFromNameOrMime(params.fileName,params.mimeType);const storageUri=await this.storeLargeFileContent({conversationId:params.conversationId,fileId,extension,content:params.content});const byteSize=Buffer.byteLength(params.content,"utf8");const explorationSummary=await generateExplorationSummary({content:params.content,fileName:params.fileName,mimeType:params.mimeType,summarizeText});await this.summaryStore.insertLargeFile({fileId,conversationId:params.conversationId,fileName:params.fileName,mimeType:params.mimeType,byteSize,storageUri,explorationSummary});return{fileId,byteSize,summary:explorationSummary,reference:params.formatReference({fileId,byteSize,summary:explorationSummary})}}async interceptLargeFiles(params){const blocks=parseFileBlocks(params.content);if(blocks.length===0){return null}const threshold=Math.max(1,this.config.largeFileTokenThreshold);const fileIds=[];const rewrittenSegments=[];let cursor=0;let interceptedAny=false;for(const block of blocks){const blockTokens=estimateTokens(block.text);if(blockTokens<threshold){continue}interceptedAny=true;const externalized=await this.externalizeLargeTextPayload({conversationId:params.conversationId,content:block.text,fileName:block.fileName,mimeType:block.mimeType,formatReference:({fileId,byteSize,summary})=>formatFileReference({fileId,fileName:block.fileName,mimeType:block.mimeType,byteSize,summary})});rewrittenSegments.push(params.content.slice(cursor,block.start));rewrittenSegments.push(externalized.reference);cursor=block.end;fileIds.push(externalized.fileId)}if(!interceptedAny){return null}rewrittenSegments.push(params.content.slice(cursor));return{rewrittenContent:rewrittenSegments.join(""),fileIds}}async interceptLargeToolResults(params){if(params.message.role!=="toolResult"&¶ms.message.role!=="tool"||!("content"in params.message)){return null}if(typeof params.message.content==="string"){params={...params,message:{...params.message,content:[{type:"text",text:params.message.content}]}}}if(!Array.isArray(params.message.content)){return null}const threshold=Math.max(1,this.config.largeFileTokenThreshold);const rewrittenContent=[];const fileIds=[];let interceptedAny=false;const topLevel=params.message;const topLevelToolCallId=safeString(topLevel.toolCallId)??safeString(topLevel.tool_call_id)??safeString(topLevel.toolUseId)??safeString(topLevel.tool_use_id)??safeString(topLevel.call_id)??safeString(topLevel.id);const topLevelToolName=safeString(topLevel.toolName)??safeString(topLevel.tool_name);const topLevelIsError=safeBoolean(topLevel.isError)??safeBoolean(topLevel.is_error);for(const item of params.message.content){if(!item||typeof item!=="object"||Array.isArray(item)){rewrittenContent.push(item);continue}const record=item;const rawType=safeString(record.type);const isStructuredToolResult=rawType!=="tool_result"&&rawType!=="toolResult"&&rawType!=="function_call_output";const isPlainTextToolResult=rawType==="text"&&typeof record.text==="string";if(isStructuredToolResult&&!isPlainTextToolResult){rewrittenContent.push(item);continue}const textSource=isPlainTextToolResult?record.text:record.output!==void 0?record.output:record.content!==void 0?record.content:record;const extractedText=extractStructuredText(textSource);if(typeof extractedText==="string"&&_LcmContextEngine.isExternalizedImageReference(extractedText)){rewrittenContent.push(item);continue}if(typeof extractedText!=="string"||estimateTokens(extractedText)<threshold){rewrittenContent.push(item);continue}interceptedAny=true;const toolName=safeString(record.name)??topLevelToolName??"tool-result";const externalized=await this.externalizeLargeTextPayload({conversationId:params.conversationId,content:extractedText,fileName:`${toolName}.txt`,mimeType:"text/plain",formatReference:({fileId,byteSize,summary})=>formatToolOutputReference({fileId,toolName,byteSize,summary})});const normalizedRawType=rawType==="function_call_output"?"function_call_output":"tool_result";const compactBlock=isPlainTextToolResult?{type:"text",text:externalized.reference,rawType:normalizedRawType,externalizedFileId:externalized.fileId,originalByteSize:externalized.byteSize,toolOutputExternalized:true,externalizationReason:"large_tool_result"}:{type:normalizedRawType,output:externalized.reference,externalizedFileId:externalized.fileId,originalByteSize:externalized.byteSize,toolOutputExternalized:true,externalizationReason:"large_tool_result"};const callId=safeString(record.tool_use_id)??safeString(record.toolUseId)??safeString(record.tool_call_id)??safeString(record.toolCallId)??safeString(record.call_id)??safeString(record.id)??topLevelToolCallId;if(callId){if(normalizedRawType==="function_call_output"){compactBlock.call_id=callId}else{compactBlock.tool_use_id=callId}}if(typeof record.is_error==="boolean"){compactBlock.is_error=record.is_error}else if(typeof record.isError==="boolean"){compactBlock.isError=record.isError}else if(typeof topLevelIsError==="boolean"){compactBlock.isError=topLevelIsError}if(toolName){compactBlock.name=toolName}rewrittenContent.push(compactBlock);fileIds.push(externalized.fileId)}if(!interceptedAny){return null}return{rewrittenMessage:{...params.message,content:rewrittenContent},fileIds}}async reconcileSessionTail(params){const{sessionId,conversationId,historicalMessages}=params;const startedAt=Date.now();const sessionContext=this.formatSessionLogContext({conversationId,sessionId,sessionKey:params.sessionKey});if(historicalMessages.length===0){this.deps.log.info(`[lcm] reconcileSessionTail: skipped for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=0 reason=empty-history`);return{blockedByImportCap:false,importedMessages:0,hasOverlap:false}}const latestDbMessage=await this.conversationStore.getLastMessage(conversationId);if(!latestDbMessage){this.deps.log.info(`[lcm] reconcileSessionTail: skipped for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} reason=no-db-tail`);return{blockedByImportCap:false,importedMessages:0,hasOverlap:false}}const storedHistoricalMessages=historicalMessages.map(message=>toStoredMessage(message));const latestHistorical=storedHistoricalMessages[storedHistoricalMessages.length-1];const latestIdentity=messageIdentity(latestDbMessage.role,latestDbMessage.content);if(latestIdentity===messageIdentity(latestHistorical.role,latestHistorical.content)){const dbOccurrences=await this.conversationStore.countMessagesByIdentity(conversationId,latestDbMessage.role,latestDbMessage.content);let historicalOccurrences=0;for(const stored of storedHistoricalMessages){if(messageIdentity(stored.role,stored.content)===latestIdentity){historicalOccurrences+=1}}if(dbOccurrences===historicalOccurrences){this.deps.log.info(`[lcm] reconcileSessionTail: fast path for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} importedMessages=0 overlap=true`);return{blockedByImportCap:false,importedMessages:0,hasOverlap:true}}}let anchorIndex=-1;const historicalIdentityTotals=new Map;for(const stored of storedHistoricalMessages){const identity=messageIdentity(stored.role,stored.content);historicalIdentityTotals.set(identity,(historicalIdentityTotals.get(identity)??0)+1)}const historicalIdentityCountsAfterIndex=new Map;const dbIdentityCounts=new Map;for(let index=storedHistoricalMessages.length-1;index>=0;index--){const stored=storedHistoricalMessages[index];const identity=messageIdentity(stored.role,stored.content);const seenAfter=historicalIdentityCountsAfterIndex.get(identity)??0;const total=historicalIdentityTotals.get(identity)??0;const occurrencesThroughIndex=total-seenAfter;const exists=await this.conversationStore.hasMessage(conversationId,stored.role,stored.content);historicalIdentityCountsAfterIndex.set(identity,seenAfter+1);if(!exists){continue}let dbCountForIdentity=dbIdentityCounts.get(identity);if(dbCountForIdentity===void 0){dbCountForIdentity=await this.conversationStore.countMessagesByIdentity(conversationId,stored.role,stored.content);dbIdentityCounts.set(identity,dbCountForIdentity)}if(dbCountForIdentity!==occurrencesThroughIndex){continue}anchorIndex=index;break}if(anchorIndex<0){this.deps.log.info(`[lcm] reconcileSessionTail: no anchor for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} importedMessages=0 overlap=false`);return{blockedByImportCap:false,importedMessages:0,hasOverlap:false}}if(anchorIndex>=historicalMessages.length-1){this.deps.log.info(`[lcm] reconcileSessionTail: anchor at tip for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} importedMessages=0 overlap=true`);return{blockedByImportCap:false,importedMessages:0,hasOverlap:true}}const missingTail=historicalMessages.slice(anchorIndex+1);const existingDbCount=await this.conversationStore.getMessageCount(conversationId);if(existingDbCount>0&&missingTail.length>Math.max(existingDbCount*.2,50)){this.deps.log.warn(`[lcm] reconcileSessionTail: import cap exceeded for ${sessionContext} \u2014 would import ${missingTail.length} messages (existing: ${existingDbCount}). Aborting to prevent flood.`);this.deps.log.info(`[lcm] reconcileSessionTail: blocked for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} missingTail=${missingTail.length} existingDbCount=${existingDbCount}`);return{blockedByImportCap:true,importedMessages:0,hasOverlap:true}}let importedMessages=0;for(const message of missingTail){const result=await this.ingestSingle({sessionId,sessionKey:params.sessionKey,message});if(result.ingested){importedMessages+=1}}this.deps.log.info(`[lcm] reconcileSessionTail: slow path for ${sessionContext} duration=${formatDurationMs(Date.now()-startedAt)} historicalMessages=${historicalMessages.length} anchorIndex=${anchorIndex} missingTail=${missingTail.length} importedMessages=${importedMessages}`);return{blockedByImportCap:false,importedMessages,hasOverlap:true}}async refreshBootstrapState(params){const latestDbMessage=await this.conversationStore.getLastMessage(params.conversationId);const fileStats=params.fileStats??await stat(params.sessionFile);await this.summaryStore.upsertConversationBootstrapState({conversationId:params.conversationId,sessionFilePath:params.sessionFile,lastSeenSize:fileStats.size,lastSeenMtimeMs:Math.trunc(fileStats.mtimeMs),lastProcessedOffset:fileStats.size,lastProcessedEntryHash:latestDbMessage?createBootstrapEntryHash({role:latestDbMessage.role,content:latestDbMessage.content,tokenCount:latestDbMessage.tokenCount}):null})}async bootstrap(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{bootstrapped:false,importedMessages:0,reason:"session excluded by pattern"}}if(this.isStatelessSession(params.sessionKey)){return{bootstrapped:false,importedMessages:0,reason:"stateless session"}}this.ensureMigrated();const startedAt=Date.now();const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");const sessionFileStats=await stat(params.sessionFile);const sessionFileSize=sessionFileStats.size;const sessionFileMtimeMs=Math.trunc(sessionFileStats.mtimeMs);const result=await this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>this.conversationStore.withTransaction(async()=>{const persistBootstrapState=async conversationId2=>{await this.refreshBootstrapState({conversationId:conversationId2,sessionFile:params.sessionFile,fileStats:{size:sessionFileSize,mtimeMs:sessionFileMtimeMs}});this.lastFullReadFileState.set(conversationId2,{size:sessionFileSize,mtimeMs:sessionFileMtimeMs})};const conversation=await this.conversationStore.getOrCreateConversation(params.sessionId,{sessionKey:params.sessionKey});const conversationId=conversation.conversationId;let existingCount=await this.conversationStore.getMessageCount(conversationId);let bootstrapState=await this.summaryStore.getConversationBootstrapState(conversationId);if(bootstrapState&&bootstrapState.sessionFilePath!==params.sessionFile){this.deps.log.warn(`[lcm] bootstrap: session file rotated conversation=${conversationId} ${sessionLabel} oldFile=${bootstrapState.sessionFilePath} newFile=${params.sessionFile}`);this.lastFullReadFileState.delete(conversationId);bootstrapState=null}if(bootstrapState&&bootstrapState.sessionFilePath===params.sessionFile&&bootstrapState.lastSeenSize===sessionFileSize&&bootstrapState.lastSeenMtimeMs===sessionFileMtimeMs){if(!conversation.bootstrappedAt){await this.conversationStore.markConversationBootstrapped(conversationId)}this.deps.log.info(`[lcm] bootstrap: checkpoint hit conversation=${conversationId} ${sessionLabel} existingCount=${existingCount} duration=${formatDurationMs(Date.now()-startedAt)}`);return{bootstrapped:false,importedMessages:0,reason:conversation.bootstrappedAt?"already bootstrapped":"conversation already up to date"}}if(bootstrapState&&bootstrapState.sessionFilePath===params.sessionFile&&sessionFileSize>bootstrapState.lastSeenSize&&sessionFileMtimeMs>=bootstrapState.lastSeenMtimeMs){const latestDbMessage=await this.conversationStore.getLastMessage(conversationId);const latestDbHash=latestDbMessage?createBootstrapEntryHash({role:latestDbMessage.role,content:latestDbMessage.content,tokenCount:latestDbMessage.tokenCount}):null;const frontierHash=latestDbHash??bootstrapState.lastProcessedEntryHash;const canTryAppendOnlyFastPath=frontierHash!==null&&frontierHash===bootstrapState.lastProcessedEntryHash;const tailEntryRaw=canTryAppendOnlyFastPath?await readLastJsonlEntryBeforeOffset(params.sessionFile,bootstrapState.lastProcessedOffset,true,message=>createBootstrapEntryHash(toStoredMessage(message))===frontierHash):null;const tailEntryMessage=readBootstrapMessageFromJsonLine(tailEntryRaw);const tailEntryHash=tailEntryMessage?createBootstrapEntryHash(toStoredMessage(tailEntryMessage)):null;if(canTryAppendOnlyFastPath&&tailEntryHash&&tailEntryHash===bootstrapState.lastProcessedEntryHash){const appended=await readAppendedLeafPathMessages({sessionFile:params.sessionFile,offset:bootstrapState.lastProcessedOffset});if(appended.canUseAppendOnly){if(!conversation.bootstrappedAt){await this.conversationStore.markConversationBootstrapped(conversationId)}let importedMessages=0;for(const message of appended.messages){const ingestResult=await this.ingestSingle({sessionId:params.sessionId,sessionKey:params.sessionKey,message});if(ingestResult.ingested){importedMessages+=1}}await persistBootstrapState(conversationId);this.deps.log.info(`[lcm] bootstrap: append-only conversation=${conversationId} ${sessionLabel} existingCount=${existingCount} appendedMessages=${appended.messages.length} importedMessages=${importedMessages} duration=${formatDurationMs(Date.now()-startedAt)}`);if(importedMessages>0){return{bootstrapped:true,importedMessages,reason:"reconciled missing session messages"}}return{bootstrapped:false,importedMessages:0,reason:conversation.bootstrappedAt?"already bootstrapped":"conversation already up to date"}}}}if(conversation.bootstrappedAt&&existingCount>0){const cached=this.lastFullReadFileState.get(conversationId);if(cached&&cached.size===sessionFileSize&&cached.mtimeMs===sessionFileMtimeMs){await persistBootstrapState(conversationId);this.deps.log.info(`[lcm] bootstrap: skipped full read (file unchanged) conversation=${conversationId} ${sessionLabel} duration=${formatDurationMs(Date.now()-startedAt)}`);return{bootstrapped:false,importedMessages:0,reason:"already bootstrapped"}}}const historicalMessages=await readLeafPathMessages(params.sessionFile);this.deps.log.info(`[lcm] bootstrap: full transcript read conversation=${conversationId} ${sessionLabel} existingCount=${existingCount} historicalMessages=${historicalMessages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);if(existingCount===0){const bootstrapMessages=trimBootstrapMessagesToBudget(historicalMessages,resolveBootstrapMaxTokens(this.config));if(bootstrapMessages.length===0){await this.conversationStore.markConversationBootstrapped(conversationId);await persistBootstrapState(conversationId);return{bootstrapped:false,importedMessages:0,reason:"no leaf-path messages in session"}}const nextSeq=await this.conversationStore.getMaxSeq(conversationId)+1;const bulkInput=bootstrapMessages.map((message,index)=>{const stored=toStoredMessage(message);return{conversationId,seq:nextSeq+index,role:stored.role,content:stored.content,tokenCount:stored.tokenCount}});const inserted=await this.conversationStore.createMessagesBulk(bulkInput);await this.summaryStore.appendContextMessages(conversationId,inserted.map(record=>record.messageId));await this.conversationStore.markConversationBootstrapped(conversationId);if(this.config.pruneHeartbeatOk){const pruned=await this.pruneHeartbeatOkTurns(conversationId);if(pruned>0){this.deps.log.info(`[lcm] bootstrap: pruned ${pruned} HEARTBEAT_OK messages from conversation ${conversationId}`)}}await persistBootstrapState(conversationId);this.deps.log.info(`[lcm] bootstrap: initial import conversation=${conversationId} ${sessionLabel} importedMessages=${inserted.length} sourceMessages=${historicalMessages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return{bootstrapped:true,importedMessages:inserted.length}}const reconcile=await this.reconcileSessionTail({sessionId:params.sessionId,sessionKey:params.sessionKey,conversationId,historicalMessages});this.deps.log.info(`[lcm] bootstrap: reconcile finished conversation=${conversationId} ${sessionLabel} importedMessages=${reconcile.importedMessages} overlap=${reconcile.hasOverlap} blockedByImportCap=${reconcile.blockedByImportCap} duration=${formatDurationMs(Date.now()-startedAt)}`);if(reconcile.blockedByImportCap){return{bootstrapped:false,importedMessages:0,reason:"reconcile import capped"}}if(!conversation.bootstrappedAt){await this.conversationStore.markConversationBootstrapped(conversationId)}if(reconcile.importedMessages>0){await persistBootstrapState(conversationId);return{bootstrapped:true,importedMessages:reconcile.importedMessages,reason:"reconciled missing session messages"}}if(reconcile.hasOverlap){await persistBootstrapState(conversationId)}if(conversation.bootstrappedAt){return{bootstrapped:false,importedMessages:0,reason:"already bootstrapped"}}return{bootstrapped:false,importedMessages:0,reason:reconcile.hasOverlap?"conversation already up to date":"conversation already has messages"}}),{operationName:"bootstrap",context:sessionLabel});if(this.config.pruneHeartbeatOk&&result.bootstrapped===false){try{const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(conversation){const pruned=await this.pruneHeartbeatOkTurns(conversation.conversationId);if(pruned>0){await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile});this.deps.log.info(`[lcm] bootstrap: retroactively pruned ${pruned} HEARTBEAT_OK messages from conversation ${conversation.conversationId}`)}}}catch(err){this.deps.log.warn(`[lcm] bootstrap: heartbeat pruning failed: ${describeLogError(err)}`)}}this.deps.log.info(`[lcm] bootstrap: done ${sessionLabel} bootstrapped=${result.bootstrapped} importedMessages=${result.importedMessages} reason=${result.reason??"none"} duration=${formatDurationMs(Date.now()-startedAt)}`);return result}async deduplicateAfterTurnBatch(sessionId,sessionKey,batch){if(batch.length===0)return batch;const conversation=await this.conversationStore.getConversationForSession({sessionId,sessionKey});if(!conversation)return batch;const conversationId=conversation.conversationId;const storedMessageCount=await this.conversationStore.getMessageCount(conversationId);if(storedMessageCount===0||storedMessageCount>batch.length){return batch}const lastDbMessage=await this.conversationStore.getLastMessage(conversationId);if(!lastDbMessage)return batch;const storedBatch=batch.map(m=>toStoredMessage(m));const batchAtBoundary=storedBatch[storedMessageCount-1];if(messageIdentity(lastDbMessage.role,lastDbMessage.content)!==messageIdentity(batchAtBoundary.role,batchAtBoundary.content)){return batch}const storedMessages=await this.conversationStore.getMessages(conversationId,{limit:storedMessageCount});if(storedMessages.length!==storedMessageCount){return batch}for(let i=0;i<storedMessageCount;i+=1){const storedConversationMessage=storedMessages[i];const incomingMessage=storedBatch[i];if(messageIdentity(storedConversationMessage.role,storedConversationMessage.content)!==messageIdentity(incomingMessage.role,incomingMessage.content)){return batch}}return batch.slice(storedMessageCount)}async buildTranscriptGcReplacementMessage(messageId){const message=await this.conversationStore.getMessageById(messageId);if(!message){return null}const parts=await this.conversationStore.getMessageParts(messageId);const toolCallId=pickToolCallId(parts);if(!toolCallId){return null}const content=contentFromParts(parts,"toolResult",message.content);const toolName=pickToolName(parts)??"unknown";const isError=pickToolIsError(parts);return{role:"toolResult",toolCallId,toolName,content,...isError!==void 0?{isError}:{}}}async maintain(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"session excluded by pattern"}}if(this.isStatelessSession(params.sessionKey)){return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"stateless session"}}const startedAt=Date.now();const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");return this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"conversation not found"}}let deferredCompactionResult=null;const maintenance=await this.compactionMaintenanceStore.getConversationCompactionMaintenance(conversation.conversationId);const telemetry=await this.compactionTelemetryStore.getConversationCompactionTelemetry(conversation.conversationId);if(params.runtimeContext?.allowDeferredCompactionExecution===true){const runtimeTokenBudget=(()=>{const tokenBudget=asRecord(params.runtimeContext)?.tokenBudget;if(typeof tokenBudget==="number"&&Number.isFinite(tokenBudget)&&tokenBudget>0){return Math.floor(tokenBudget)}return 128e3})();if((maintenance?.pending||maintenance?.running)&&this.shouldDelayPromptMutatingDeferredCompaction(telemetry)){this.deps.log.info(`[lcm] maintain: deferred compaction debt still hot-cache deferred conversation=${conversation.conversationId} ${sessionLabel} retention=${telemetry?.retention??"null"} lastCacheTouchAt=${telemetry?.lastCacheTouchAt?.toISOString()??"null"}`)}else{deferredCompactionResult=await this.consumeDeferredCompactionDebt({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:this.applyAssemblyBudgetCap(runtimeTokenBudget),currentTokenCount:typeof params.runtimeContext?.currentTokenCount==="number"?Math.floor(params.runtimeContext.currentTokenCount):void 0,runtimeContext:params.runtimeContext,legacyParams:asRecord(params.runtimeContext)})}}else if(maintenance?.pending||maintenance?.running){this.deps.log.info(`[lcm] maintain: deferred compaction debt pending conversation=${conversation.conversationId} ${sessionLabel} but host runtimeContext.allowDeferredCompactionExecution is disabled`)}if(!this.config.transcriptGcEnabled){return deferredCompactionResult??{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"transcript GC disabled"}}if(typeof params.runtimeContext?.rewriteTranscriptEntries!=="function"){return deferredCompactionResult??{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"runtime rewrite helper unavailable"}}const rewriteTranscriptEntries=params.runtimeContext.rewriteTranscriptEntries;const candidates=await this.summaryStore.listTranscriptGcCandidates(conversation.conversationId,{limit:TRANSCRIPT_GC_BATCH_SIZE});if(candidates.length===0){this.deps.log.info(`[lcm] maintain: no transcript GC candidates conversation=${conversation.conversationId} ${sessionLabel} duration=${formatDurationMs(Date.now()-startedAt)}`);return deferredCompactionResult??{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"no transcript GC candidates"}}const transcriptEntryIdsByCallId=listTranscriptToolResultEntryIdsByCallId(params.sessionFile);const replacements=[];const seenEntryIds=new Set;for(const candidate of candidates){const entryId=transcriptEntryIdsByCallId.get(candidate.toolCallId);if(!entryId||seenEntryIds.has(entryId)){continue}const replacementMessage=await this.buildTranscriptGcReplacementMessage(candidate.messageId);if(!replacementMessage){continue}seenEntryIds.add(entryId);replacements.push({entryId,message:replacementMessage})}if(replacements.length===0){this.deps.log.info(`[lcm] maintain: no matching transcript entries conversation=${conversation.conversationId} ${sessionLabel} candidates=${candidates.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return deferredCompactionResult??{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"no matching transcript entries"}}const result=await rewriteTranscriptEntries({replacements});if(result.changed){try{await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile})}catch(e){this.deps.log.warn(`[lcm] Failed to update bootstrap checkpoint after maintain: ${describeLogError(e)}`)}}const combinedResult=deferredCompactionResult?{changed:deferredCompactionResult.changed||result.changed,bytesFreed:result.bytesFreed,rewrittenEntries:result.rewrittenEntries,reason:result.reason??deferredCompactionResult.reason}:result;this.deps.log.info(`[lcm] maintain: done conversation=${conversation.conversationId} ${sessionLabel} candidates=${candidates.length} replacements=${replacements.length} changed=${combinedResult.changed} rewrittenEntries=${combinedResult.rewrittenEntries} bytesFreed=${combinedResult.bytesFreed} duration=${formatDurationMs(Date.now()-startedAt)}`);return combinedResult},{operationName:"maintain",context:sessionLabel})}async ingestSingle(params){const{sessionId,sessionKey,message,isHeartbeat}=params;if(isHeartbeat){return{ingested:false}}if(message.role==="assistant"){const topLevel=message;const stopReason=typeof topLevel.stopReason==="string"?topLevel.stopReason:typeof topLevel.stop_reason==="string"?topLevel.stop_reason:void 0;if(stopReason==="error"||stopReason==="aborted"){const content=topLevel.content;const isEmpty=content===void 0||content===null||content===""||Array.isArray(content)&&content.length===0;if(isEmpty){return{ingested:false}}}}let stored=toStoredMessage(message);const conversation=await this.conversationStore.getOrCreateConversation(sessionId,{sessionKey});const conversationId=conversation.conversationId;let messageForParts=message;if(stored.role==="tool"){const imageIntercepted=await this.interceptInlineImagesInToolMessage({conversationId,message:messageForParts});if(imageIntercepted){messageForParts=imageIntercepted.rewrittenMessage;stored=toStoredMessage(messageForParts)}}else{const imageIntercepted=await this.interceptInlineImages({conversationId,content:stored.content,role:stored.role});if(imageIntercepted){stored.content=imageIntercepted.rewrittenContent;stored.tokenCount=estimateTokens(stored.content);if("content"in message){messageForParts={...message,content:stored.content}}}}if(stored.role==="user"){const intercepted=await this.interceptLargeFiles({conversationId,content:stored.content});if(intercepted){stored.content=intercepted.rewrittenContent;stored.tokenCount=estimateTokens(stored.content);if("content"in message){messageForParts={...message,content:stored.content}}}}else if(stored.role==="tool"){const intercepted=await this.interceptLargeToolResults({conversationId,message:messageForParts});if(intercepted){messageForParts=intercepted.rewrittenMessage;const rewrittenStored=toStoredMessage(intercepted.rewrittenMessage);stored.content=rewrittenStored.content;stored.tokenCount=rewrittenStored.tokenCount}}const maxSeq=await this.conversationStore.getMaxSeq(conversationId);const seq=maxSeq+1;const msgRecord=await this.conversationStore.createMessage({conversationId,seq,role:stored.role,content:stored.content,tokenCount:stored.tokenCount});await this.conversationStore.createMessageParts(msgRecord.messageId,buildMessageParts({sessionId,message:messageForParts,fallbackContent:stored.content}));await this.summaryStore.appendContextMessage(conversationId,msgRecord.messageId);return{ingested:true}}async ingest(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{ingested:false}}if(this.isStatelessSession(params.sessionKey)){return{ingested:false}}this.ensureMigrated();return this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),()=>this.ingestSingle(params),{operationName:"ingest",context:[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ")})}async ingestBatch(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{ingestedCount:0}}if(this.isStatelessSession(params.sessionKey)){return{ingestedCount:0}}this.ensureMigrated();if(params.messages.length===0){return{ingestedCount:0}}return this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{let ingestedCount=0;for(const message of params.messages){const result=await this.ingestSingle({sessionId:params.sessionId,sessionKey:params.sessionKey,message,isHeartbeat:params.isHeartbeat});if(result.ingested){ingestedCount+=1}}return{ingestedCount}},{operationName:"ingestBatch",context:[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[],`messages=${params.messages.length}`].join(" ")})}async runAfterTurnInlineLeafCompaction(params){try{await this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{const recordAfterTurnCompactionRetry=async()=>{try{await this.recordDeferredCompactionDebt({conversationId:params.conversationId,reason:params.leafDecision.reason,tokenBudget:params.tokenBudget,currentTokenCount:params.currentTokenCount})}catch(err){this.deps.log.warn(`[lcm] afterTurn: failed to persist deferred compaction retry for ${params.sessionLabel}: ${describeLogError(err)}`)}};try{const compactResult=await this.executeLeafCompactionCore({conversationId:params.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:params.tokenBudget,currentTokenCount:params.currentTokenCount,legacyParams:params.legacyParams,maxPasses:params.leafDecision.maxPasses,leafChunkTokens:params.leafDecision.leafChunkTokens,fallbackLeafChunkTokens:params.leafDecision.fallbackLeafChunkTokens,activityBand:params.leafDecision.activityBand,allowCondensedPasses:params.leafDecision.allowCondensedPasses});if(compactResult.ok){try{await this.refreshBootstrapState({conversationId:params.conversationId,sessionFile:params.sessionFile})}catch(err){this.deps.log.warn(`[lcm] afterTurn: bootstrap checkpoint refresh failed for ${params.sessionLabel}: ${describeLogError(err)}`)}return}await recordAfterTurnCompactionRetry()}catch(err){await recordAfterTurnCompactionRetry();this.deps.log.warn(`[lcm] afterTurn: inline leaf compaction failed for ${params.sessionLabel}: ${describeLogError(err)}`)}},{operationName:"afterTurnLeafCompaction",context:params.sessionLabel})}catch(err){this.deps.log.warn(`[lcm] afterTurn: failed to queue inline leaf compaction for ${params.sessionLabel}: ${describeLogError(err)}`)}}async afterTurn(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return}if(this.isStatelessSession(params.sessionKey)){return}this.ensureMigrated();const startedAt=Date.now();const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");const newMessages=params.messages.slice(params.prePromptMessageCount);const dedupedNewMessages=await this.deduplicateAfterTurnBatch(params.sessionId,params.sessionKey,newMessages);const ingestBatch=[];if(params.autoCompactionSummary){ingestBatch.push({role:"user",content:params.autoCompactionSummary})}ingestBatch.push(...dedupedNewMessages);if(ingestBatch.length===0){this.deps.log.info(`[lcm] afterTurn: nothing to ingest ${sessionLabel} newMessages=${newMessages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return}try{await this.ingestBatch({sessionId:params.sessionId,sessionKey:params.sessionKey,messages:ingestBatch,isHeartbeat:params.isHeartbeat===true})}catch(err){this.deps.log.error(`[lcm] afterTurn: ingest failed, skipping compaction: ${describeLogError(err)}`);return}if(batchLooksLikeHeartbeatAckTurn(ingestBatch)){try{const conversation2=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(conversation2){const pruned=await this.pruneHeartbeatOkTurns(conversation2.conversationId);if(pruned>0){const sessionContext=this.formatSessionLogContext({conversationId:conversation2.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey});try{await this.refreshBootstrapState({conversationId:conversation2.conversationId,sessionFile:params.sessionFile})}catch(err){this.deps.log.warn(`[lcm] afterTurn: heartbeat pruning checkpoint refresh failed for ${sessionContext}: ${describeLogError(err)}`)}this.deps.log.info(`[lcm] afterTurn: pruned ${pruned} heartbeat ack messages for ${sessionContext}`);return}}}catch(err){this.deps.log.warn(`[lcm] afterTurn: heartbeat pruning failed: ${describeLogError(err)}`)}}const legacyParams=asRecord(params.runtimeContext)??asRecord(params.legacyCompactionParams);const DEFAULT_AFTER_TURN_TOKEN_BUDGET=128e3;const resolvedTokenBudget=this.resolveTokenBudget({tokenBudget:params.tokenBudget,runtimeContext:params.runtimeContext,legacyParams});const tokenBudget=this.applyAssemblyBudgetCap(resolvedTokenBudget??DEFAULT_AFTER_TURN_TOKEN_BUDGET);if(resolvedTokenBudget===void 0){this.deps.log.warn(`[lcm] afterTurn: tokenBudget not provided; using default ${DEFAULT_AFTER_TURN_TOKEN_BUDGET}`)}const liveContextTokens=estimateSessionTokenCountForAfterTurn(params.messages);const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){this.deps.log.info(`[lcm] afterTurn: conversation lookup missed ${sessionLabel} ingestBatch=${ingestBatch.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return}const refreshAfterTurnBootstrapState=async()=>{try{await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile})}catch(err){this.deps.log.warn(`[lcm] afterTurn: bootstrap checkpoint refresh failed for ${sessionLabel}: ${describeLogError(err)}`)}};const recordAfterTurnCompactionRetry=async reason=>{try{await this.recordDeferredCompactionDebt({conversationId:conversation.conversationId,reason,tokenBudget,currentTokenCount:liveContextTokens})}catch(err){this.deps.log.warn(`[lcm] afterTurn: failed to persist deferred compaction retry for ${sessionLabel}: ${describeLogError(err)}`)}};let shouldRefreshBootstrapState=true;let rawLeafTrigger=null;try{rawLeafTrigger=await this.compaction.evaluateLeafTrigger(conversation.conversationId);await this.updateCompactionTelemetry({conversationId:conversation.conversationId,runtimeContext:legacyParams,tokenBudget,rawTokensOutsideTail:rawLeafTrigger.rawTokensOutsideTail})}catch(err){this.deps.log.warn(`[lcm] afterTurn: compaction telemetry update failed: ${describeLogError(err)}`)}try{const leafDecision=await this.evaluateIncrementalCompaction({conversationId:conversation.conversationId,tokenBudget,currentTokenCount:liveContextTokens});const thresholdDecision=await this.compaction.evaluate(conversation.conversationId,tokenBudget,liveContextTokens);if(this.config.proactiveThresholdCompactionMode==="inline"){let leafCompactionScheduled=false;if(leafDecision.shouldCompact){leafCompactionScheduled=true;shouldRefreshBootstrapState=false;void this.runAfterTurnInlineLeafCompaction({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile,tokenBudget,currentTokenCount:liveContextTokens,legacyParams,leafDecision,sessionLabel})}else{shouldRefreshBootstrapState=true}if(!leafCompactionScheduled){const compactResult=await this.compact({sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile,tokenBudget,currentTokenCount:liveContextTokens,compactionTarget:"threshold",legacyParams});const retryReason=thresholdDecision.shouldCompact?"threshold":null;if(!compactResult.ok&&retryReason){shouldRefreshBootstrapState=false;await recordAfterTurnCompactionRetry(retryReason)}}}else if(thresholdDecision.shouldCompact||rawLeafTrigger?.shouldCompact){await this.recordDeferredCompactionDebt({conversationId:conversation.conversationId,reason:thresholdDecision.shouldCompact?"threshold":leafDecision.shouldCompact?leafDecision.reason:"leaf-trigger",tokenBudget,currentTokenCount:liveContextTokens})}}catch(err){this.deps.log.warn(`[lcm] afterTurn: compaction policy check failed for ${sessionLabel}: ${describeLogError(err)}`)}if(shouldRefreshBootstrapState){await refreshAfterTurnBootstrapState()}this.deps.log.info(`[lcm] afterTurn: done conversation=${conversation.conversationId} ${sessionLabel} newMessages=${newMessages.length} dedupedMessages=${dedupedNewMessages.length} ingestedMessages=${ingestBatch.length} duration=${formatDurationMs(Date.now()-startedAt)}`)}async assemble(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{messages:params.messages,estimatedTokens:0}}try{this.ensureMigrated();const startedAt=Date.now();const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){this.deps.log.info(`[lcm] assemble: conversation lookup missed ${sessionLabel} duration=${formatDurationMs(Date.now()-startedAt)}`);return{messages:params.messages,estimatedTokens:0}}const tokenBudget=this.applyAssemblyBudgetCap(typeof params.tokenBudget==="number"&&Number.isFinite(params.tokenBudget)&¶ms.tokenBudget>0?Math.floor(params.tokenBudget):128e3);const liveContextTokens=estimateSessionTokenCountForAfterTurn(params.messages);const maintenance=await this.compactionMaintenanceStore.getConversationCompactionMaintenance(conversation.conversationId);if(maintenance?.pending||maintenance?.running){try{await this.maybeConsumeDeferredCompactionDebtForAssemble({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget,currentTokenCount:liveContextTokens})}catch(error){this.deps.log.warn(`[lcm] assemble: deferred compaction execution failed for ${sessionLabel}: ${describeLogError(error)}`)}}const contextItems=await this.summaryStore.getContextItems(conversation.conversationId);if(contextItems.length===0){this.deps.log.info(`[lcm] assemble: no context items conversation=${conversation.conversationId} ${sessionLabel} duration=${formatDurationMs(Date.now()-startedAt)}`);return{messages:params.messages,estimatedTokens:0}}const hasSummaryItems=contextItems.some(item=>item.itemType==="summary");if(!hasSummaryItems&&contextItems.length<params.messages.length){this.deps.log.info(`[lcm] assemble: falling back to live context conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} liveMessages=${params.messages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return{messages:params.messages,estimatedTokens:0}}const assembled=await this.assembler.assemble({conversationId:conversation.conversationId,tokenBudget,freshTailCount:this.config.freshTailCount,freshTailMaxTokens:this.config.freshTailMaxTokens,prompt:params.prompt});if(assembled.messages.length===0&¶ms.messages.length>0){this.deps.log.info(`[lcm] assemble: empty assembled output, using live context conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} tokenBudget=${tokenBudget} duration=${formatDurationMs(Date.now()-startedAt)}`);return{messages:params.messages,estimatedTokens:0}}this.deps.log.info(`[lcm] assemble: done conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} hasSummaryItems=${hasSummaryItems} inputMessages=${params.messages.length} outputMessages=${assembled.messages.length} tokenBudget=${tokenBudget} estimatedTokens=${assembled.estimatedTokens} duration=${formatDurationMs(Date.now()-startedAt)}`);const result={messages:assembled.messages,estimatedTokens:assembled.estimatedTokens,...assembled.systemPromptAddition?{systemPromptAddition:assembled.systemPromptAddition}:{}};return result}catch(err){this.deps.log.info(`[lcm] assemble: failed for session=${params.sessionId}${params.sessionKey?.trim()?` sessionKey=${params.sessionKey.trim()}`:""} error=${describeLogError(err)}`);return{messages:params.messages,estimatedTokens:0}}}async evaluateLeafTrigger(sessionId,sessionKey){this.ensureMigrated();const conversation=await this.conversationStore.getConversationForSession({sessionId,sessionKey});if(!conversation){const fallbackThreshold=typeof this.config.leafChunkTokens==="number"&&Number.isFinite(this.config.leafChunkTokens)&&this.config.leafChunkTokens>0?Math.floor(this.config.leafChunkTokens):2e4;return{shouldCompact:false,rawTokensOutsideTail:0,threshold:fallbackThreshold}}return this.compaction.evaluateLeafTrigger(conversation.conversationId)}async executeLeafCompactionCore(params){const legacyParams=asRecord(params.runtimeContext)??params.legacyParams;const observedTokens=this.normalizeObservedTokenCount(params.currentTokenCount??(legacyParams??{}).currentTokenCount);const{summarize,summaryModel,breakerKey}=await this.resolveSummarize({legacyParams,customInstructions:params.customInstructions,breakerScope:this.resolveSessionQueueKey(params.sessionId,params.sessionKey)});if(breakerKey&&this.isCircuitBreakerOpen(breakerKey)){return{ok:true,compacted:false,reason:"circuit breaker open"}}const storedTokensBefore=await this.summaryStore.getContextTokenCount(params.conversationId);const maxPasses=typeof params.maxPasses==="number"&&Number.isFinite(params.maxPasses)&¶ms.maxPasses>0?Math.floor(params.maxPasses):1;const fallbackLeafChunkTokens=Array.isArray(params.fallbackLeafChunkTokens)?[...new Set(params.fallbackLeafChunkTokens.filter(value=>typeof value==="number"&&Number.isFinite(value)&&value>0).map(value=>Math.floor(value)))].sort((a,b)=>b-a):[];let activeLeafChunkTokens=typeof params.leafChunkTokens==="number"&&Number.isFinite(params.leafChunkTokens)&¶ms.leafChunkTokens>0?Math.floor(params.leafChunkTokens):fallbackLeafChunkTokens[0];this.deps.log.info(`[lcm] compactLeafAsync start: conversation=${params.conversationId} session=${params.sessionId} leafChunkTokens=${activeLeafChunkTokens??"null"} fallbackLeafChunkTokens=${fallbackLeafChunkTokens.join(",")} maxPasses=${maxPasses} activityBand=${params.activityBand??"unknown"} allowCondensedPasses=${params.allowCondensedPasses!==false}`);let rounds=0;let finalTokens=observedTokens??storedTokensBefore;let authFailure=false;for(let pass=0;pass<maxPasses;pass+=1){let leafResult;while(true){try{leafResult=await this.compaction.compactLeaf({conversationId:params.conversationId,tokenBudget:params.tokenBudget,summarize,...activeLeafChunkTokens!==void 0?{leafChunkTokens:activeLeafChunkTokens}:{},force:params.force,previousSummaryContent:pass===0?params.previousSummaryContent:void 0,summaryModel,allowCondensedPasses:params.allowCondensedPasses});break}catch(err){const nextLeafChunkTokens=fallbackLeafChunkTokens.find(value=>activeLeafChunkTokens!==void 0&&value<activeLeafChunkTokens);if(!this.isRecoverableLeafChunkOverflowError(err)||nextLeafChunkTokens===void 0){throw err}this.deps.log.warn(`[lcm] compactLeafAsync: retrying with smaller leafChunkTokens=${nextLeafChunkTokens} after provider token-limit error: ${err instanceof Error?err.message:String(err)}`);activeLeafChunkTokens=nextLeafChunkTokens}}if(!leafResult){break}finalTokens=leafResult.tokensAfter;if(leafResult.authFailure){authFailure=true;break}if(!leafResult.actionTaken){break}rounds+=1;if(leafResult.tokensAfter>=leafResult.tokensBefore){break}}if(authFailure&&breakerKey){this.recordCompactionAuthFailure(breakerKey)}else if(rounds>0&&breakerKey){this.recordCompactionSuccess(breakerKey)}if(rounds>0){await this.markLeafCompactionTelemetrySuccess({conversationId:params.conversationId,activityBand:params.activityBand})}const tokensBefore=observedTokens??storedTokensBefore;this.deps.log.debug(`[lcm] compactLeafAsync result: conversation=${params.conversationId} session=${params.sessionId} rounds=${rounds} compacted=${rounds>0} authFailure=${authFailure} finalLeafChunkTokens=${activeLeafChunkTokens??"null"} finalTokens=${finalTokens}`);return{ok:!authFailure,compacted:rounds>0,reason:authFailure?"provider auth failure":rounds>0?"compacted":"below threshold",result:{tokensBefore,tokensAfter:finalTokens,details:{rounds,targetTokens:params.tokenBudget,mode:"leaf",maxPasses}}}}async compactLeafAsync(params){if(this.isStatelessSession(params.sessionKey)){return{ok:true,compacted:false,reason:"stateless session"}}this.ensureMigrated();return this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){return{ok:true,compacted:false,reason:"no conversation found for session"}}const legacyParams=asRecord(params.runtimeContext)??params.legacyParams;const resolvedTokenBudget=this.resolveTokenBudget({tokenBudget:params.tokenBudget,runtimeContext:params.runtimeContext,legacyParams});const tokenBudget=resolvedTokenBudget?this.applyAssemblyBudgetCap(resolvedTokenBudget):resolvedTokenBudget;if(!tokenBudget){return{ok:false,compacted:false,reason:"missing token budget in compact params"}}return this.executeLeafCompactionCore({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget,currentTokenCount:params.currentTokenCount,customInstructions:params.customInstructions,runtimeContext:params.runtimeContext,legacyParams:params.legacyParams,force:params.force,previousSummaryContent:params.previousSummaryContent,maxPasses:params.maxPasses,leafChunkTokens:params.leafChunkTokens,fallbackLeafChunkTokens:params.fallbackLeafChunkTokens,activityBand:params.activityBand,allowCondensedPasses:params.allowCondensedPasses})})}async compact(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return{ok:true,compacted:false,reason:"session excluded"}}if(this.isStatelessSession(params.sessionKey)){return{ok:true,compacted:false,reason:"stateless session"}}this.ensureMigrated();return this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>{const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){return{ok:true,compacted:false,reason:"no conversation found for session"}}return this.executeCompactionCore({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:params.tokenBudget,currentTokenCount:params.currentTokenCount,compactionTarget:params.compactionTarget,customInstructions:params.customInstructions,runtimeContext:params.runtimeContext,legacyParams:params.legacyParams,force:params.force})})}async prepareSubagentSpawn(params){if(this.shouldIgnoreSession({sessionKey:params.parentSessionKey})||this.shouldIgnoreSession({sessionKey:params.childSessionKey})||this.isStatelessSession(params.parentSessionKey)||this.isStatelessSession(params.childSessionKey)){return void 0}this.ensureMigrated();const childSessionKey=params.childSessionKey.trim();const parentSessionKey=params.parentSessionKey.trim();if(!childSessionKey||!parentSessionKey){return void 0}const conversationId=await this.resolveConversationIdForSessionKey(parentSessionKey);if(typeof conversationId!=="number"){return void 0}const ttlMs=typeof params.ttlMs==="number"&&Number.isFinite(params.ttlMs)&¶ms.ttlMs>0?Math.floor(params.ttlMs):void 0;const parentGrantId=resolveDelegatedExpansionGrantId(parentSessionKey);const parentGrant=parentGrantId?getRuntimeExpansionAuthManager().getGrant(parentGrantId):null;const childTokenCap=parentGrant?Math.min(getRuntimeExpansionAuthManager().getRemainingTokenBudget(parentGrantId)??this.config.maxExpandTokens,this.config.maxExpandTokens):this.config.maxExpandTokens;const childMaxDepth=parentGrant?Math.max(0,parentGrant.maxDepth-1):void 0;const childAllowedSummaryIds=parentGrant?.allowedSummaryIds.length?parentGrant.allowedSummaryIds:void 0;createDelegatedExpansionGrant({delegatedSessionKey:childSessionKey,issuerSessionId:parentSessionKey,allowedConversationIds:[conversationId],allowedSummaryIds:childAllowedSummaryIds,tokenCap:childTokenCap,maxDepth:childMaxDepth,ttlMs});return{rollback:()=>{revokeDelegatedExpansionGrantForSession(childSessionKey,{removeBinding:true})}}}async onSubagentEnded(params){if(this.shouldIgnoreSession({sessionKey:params.childSessionKey})||this.isStatelessSession(params.childSessionKey)){return}const childSessionKey=params.childSessionKey.trim();if(!childSessionKey){return}switch(params.reason){case"deleted":revokeDelegatedExpansionGrantForSession(childSessionKey,{removeBinding:true});break;case"completed":revokeDelegatedExpansionGrantForSession(childSessionKey);break;case"released":case"swept":removeDelegatedExpansionGrantForSession(childSessionKey);break}}async dispose(){}async isFreshLifecycleConversation(conversation){const currentMessageCount=await this.conversationStore.getMessageCount(conversation.conversationId);if(currentMessageCount!==0){return false}const currentContextItems=await this.summaryStore.getContextItems(conversation.conversationId);return currentContextItems.length===0&&!conversation.bootstrappedAt}async applySessionReplacement(params){const current=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!current&&!params.createReplacementWhenMissing){return}if(current?.active){if(params.createReplacement&&await this.isFreshLifecycleConversation(current)){this.deps.log.info(`[lcm] ${params.reason} lifecycle no-op for already fresh conversation ${current.conversationId}`);return}await this.conversationStore.archiveConversation(current.conversationId)}if(!params.createReplacement){this.deps.log.info(`[lcm] ${params.reason} lifecycle archived conversation ${current?.conversationId??"(none)"}`);return}const nextSessionId=params.nextSessionId?.trim()||params.sessionId?.trim()||current?.sessionId;if(!nextSessionId){this.deps.log.warn(`[lcm] ${params.reason} lifecycle skipped: no session identity available`);return}const nextSessionKey=params.nextSessionKey?.trim()||params.sessionKey?.trim()||current?.sessionKey;const freshConversation=await this.conversationStore.createConversation({sessionId:nextSessionId,...nextSessionKey?{sessionKey:nextSessionKey}:{}});this.deps.log.info(`[lcm] ${params.reason} lifecycle archived prior conversation and created ${freshConversation.conversationId}`)}async handleBeforeReset(params){const reason=params.reason?.trim();if(reason!=="new"&&reason!=="reset"){return}if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return}if(this.isStatelessSession(params.sessionKey)){return}this.ensureMigrated();await this.withSessionQueue(this.resolveSessionQueueKey(params.sessionId,params.sessionKey),async()=>this.conversationStore.withTransaction(async()=>{if(reason==="new"){const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){return}const retainDepth=typeof this.config.newSessionRetainDepth==="number"&&Number.isFinite(this.config.newSessionRetainDepth)?this.config.newSessionRetainDepth:2;await this.summaryStore.pruneForNewSession(conversation.conversationId,retainDepth);this.deps.log.info(`[lcm] /new pruned conversation ${conversation.conversationId} to retain depth ${retainDepth}`);return}await this.applySessionReplacement({reason:"/reset",sessionId:params.sessionId,sessionKey:params.sessionKey,createReplacement:true,createReplacementWhenMissing:true})}))}async handleSessionEnd(params){const reason=params.reason?.trim();if(!reason||reason==="new"||reason==="unknown"){return}if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return}if(this.isStatelessSession(params.sessionKey??params.nextSessionKey)){return}const createReplacement=reason!=="deleted";this.ensureMigrated();await this.withSessionQueue(this.resolveSessionQueueKey(params.nextSessionId??params.sessionId,params.sessionKey??params.nextSessionKey),async()=>this.conversationStore.withTransaction(async()=>{await this.applySessionReplacement({reason:`session_end:${reason}`,sessionId:params.sessionId,sessionKey:params.sessionKey??params.nextSessionKey,nextSessionId:params.nextSessionId,nextSessionKey:params.nextSessionKey,createReplacement})}))}async rewriteTranscriptForRotate(params){const sessionManager=SessionManager.open(params.sessionFile);const header=sessionManager.getHeader();const branch=sessionManager.getBranch();const originalStats=await stat(params.sessionFile);const messageIndices=[];for(let index=0;index<branch.length;index+=1){if(branch[index]?.type==="message"){messageIndices.push(index)}}const keepTailMessageCount=normalizeRotateTailMessageCount(this.config.freshTailCount,messageIndices.length);const anchorIndex=keepTailMessageCount>0?messageIndices[messageIndices.length-keepTailMessageCount]??branch.length:branch.length;const latestPreludeEntries=new Map;for(let index=0;index<anchorIndex;index+=1){const entry=branch[index];if(entry&&isRotatePreservedEntryType(entry.type)&&entry.type!=="message"){latestPreludeEntries.set(entry.type,entry)}}const entriesToKeep=[];for(const type of["session_info","model_change","thinking_level_change"]){const entry=latestPreludeEntries.get(type);if(entry){entriesToKeep.push({...entry})}}for(let index=anchorIndex;index<branch.length;index+=1){const entry=branch[index];if(entry&&isRotatePreservedEntryType(entry.type)){entriesToKeep.push({...entry})}}while(entriesToKeep.length>0&&entriesToKeep[entriesToKeep.length-1]?.type!=="message"){entriesToKeep.pop()}let previousEntryId=null;const linearizedEntries=entriesToKeep.map(entry=>{const nextEntry={...entry,parentId:previousEntryId};previousEntryId=typeof nextEntry.id==="string"?nextEntry.id:previousEntryId;return nextEntry});const serialized=[JSON.stringify(header),...linearizedEntries.map(entry=>JSON.stringify(entry))].join("\n")+"\n";await writeFile(params.sessionFile,serialized,"utf8");const rewrittenStats=await stat(params.sessionFile);await this.refreshBootstrapState({conversationId:params.conversationId,sessionFile:params.sessionFile,fileStats:{size:rewrittenStats.size,mtimeMs:rewrittenStats.mtimeMs}});return{checkpointSize:rewrittenStats.size,bytesRemoved:Math.max(0,originalStats.size-rewrittenStats.size),preservedTailMessageCount:keepTailMessageCount}}async rotateSessionStorageInActiveTransaction(params){const{sessionId,sessionKey}=params;const current=await this.conversationStore.getConversationForSession({sessionId,sessionKey});if(!current?.active){return{kind:"unavailable",reason:"No active Lossless Claw conversation is stored for the current session."}}try{const rewriteResult=await this.rewriteTranscriptForRotate({conversationId:current.conversationId,sessionFile:params.sessionFile});this.deps.log.info(`[lcm] rotate: rewrote transcript for conversation=${current.conversationId} session=${sessionId} sessionKey=${sessionKey} preservedTailMessages=${rewriteResult.preservedTailMessageCount} checkpointSize=${rewriteResult.checkpointSize} bytesRemoved=${rewriteResult.bytesRemoved}`);return{kind:"rotated",conversationId:current.conversationId,preservedTailMessageCount:rewriteResult.preservedTailMessageCount,checkpointSize:rewriteResult.checkpointSize,bytesRemoved:rewriteResult.bytesRemoved}}catch(error){return{kind:"unavailable",reason:`Lossless Claw could not rotate the current session transcript: ${describeLogError(error)}`}}}async rotateSessionStorage(params){const sessionId=params.sessionId?.trim();const sessionKey=params.sessionKey?.trim();if(!sessionId||!sessionKey){return{kind:"unavailable",reason:"Lossless Claw needs both the current session id and session key to rotate storage safely."}}if(this.shouldIgnoreSession({sessionId,sessionKey})){return{kind:"unavailable",reason:"The current session is excluded by ignoreSessionPatterns, so there is no active LCM conversation to rotate."}}if(this.isStatelessSession(sessionKey)){return{kind:"unavailable",reason:"The current session is stateless in Lossless Claw, so there is no writable active LCM conversation to rotate."}}this.ensureMigrated();return this.withSessionQueue(this.resolveSessionQueueKey(sessionId,sessionKey),async()=>this.conversationStore.withTransaction(()=>this.rotateSessionStorageInActiveTransaction({sessionId,sessionKey,sessionFile:params.sessionFile})))}async rotateSessionStorageWhileHoldingDatabaseLock(params){const sessionId=params.sessionId?.trim();const sessionKey=params.sessionKey?.trim();if(!sessionId||!sessionKey){return{kind:"unavailable",reason:"Lossless Claw needs both the current session id and session key to rotate storage safely."}}if(this.shouldIgnoreSession({sessionId,sessionKey})){return{kind:"unavailable",reason:"The current session is excluded by ignoreSessionPatterns, so there is no active LCM conversation to rotate."}}if(this.isStatelessSession(sessionKey)){return{kind:"unavailable",reason:"The current session is stateless in Lossless Claw, so there is no writable active LCM conversation to rotate."}}this.ensureMigrated();if(this.db.isTransaction){return{kind:"unavailable",reason:"Lossless Claw obtained exclusive rotate access, but the shared database connection is still inside another transaction."}}let transactionActive=false;try{this.db.exec("BEGIN IMMEDIATE");transactionActive=true;const result=await this.rotateSessionStorageInActiveTransaction({sessionId,sessionKey,sessionFile:params.sessionFile});this.db.exec("COMMIT");transactionActive=false;return result}catch(error){if(transactionActive){this.db.exec("ROLLBACK")}throw error}}async rotateSessionStorageWithBackup(params){const sessionId=params.sessionId?.trim();const sessionKey=params.sessionKey?.trim();if(!sessionId||!sessionKey){return{kind:"unavailable",reason:"Lossless Claw needs both the current session id and session key to rotate storage safely."}}if(this.shouldIgnoreSession({sessionId,sessionKey})){return{kind:"unavailable",reason:"The current session is excluded by ignoreSessionPatterns, so there is no active LCM conversation to rotate."}}if(this.isStatelessSession(sessionKey)){return{kind:"unavailable",reason:"The current session is stateless in Lossless Claw, so there is no writable active LCM conversation to rotate."}}this.ensureMigrated();return this.withSessionQueue(this.resolveSessionQueueKey(sessionId,sessionKey),async()=>{try{return await withExclusiveDatabaseLock(this.db,{timeoutMs:params.lockTimeoutMs},async()=>{if(this.db.isTransaction){return{kind:"unavailable",reason:"Lossless Claw obtained exclusive rotate access, but the shared database connection is still inside another transaction."}}const current=await this.conversationStore.getConversationForSession({sessionId,sessionKey});if(!current?.active){return{kind:"unavailable",reason:"No active Lossless Claw conversation is stored for the current session."}}const currentMessageCount=await this.conversationStore.getMessageCount(current.conversationId);let backupPath=null;try{backupPath=createLcmDatabaseBackup(this.db,{databasePath:this.config.databasePath,label:"rotate",replaceLatest:true})}catch(error){return{kind:"backup_failed",currentConversationId:current.conversationId,currentMessageCount,reason:describeLogError(error)}}if(!backupPath){return{kind:"unavailable",currentConversationId:current.conversationId,currentMessageCount,reason:"Lossless Claw could not create the rotate backup."}}let rotateResult;try{rotateResult=await this.rotateSessionStorageWhileHoldingDatabaseLock({sessionId,sessionKey,sessionFile:params.sessionFile})}catch(error){return{kind:"rotate_failed",currentConversationId:current.conversationId,currentMessageCount,backupPath,reason:describeLogError(error)}}if(rotateResult.kind==="unavailable"){return{kind:"unavailable",currentConversationId:current.conversationId,currentMessageCount,backupPath,reason:rotateResult.reason}}return{kind:"rotated",currentConversationId:current.conversationId,currentMessageCount,backupPath,preservedTailMessageCount:rotateResult.preservedTailMessageCount,checkpointSize:rotateResult.checkpointSize,bytesRemoved:rotateResult.bytesRemoved}})}catch(error){if(error instanceof DatabaseTransactionTimeoutError){return{kind:"unavailable",reason:`Lossless Claw waited ${Math.floor(params.lockTimeoutMs/1e3)}s for the database to become idle, but another transaction never finished.`}}throw error}})}getRetrieval(){return this.retrieval}getConversationStore(){return this.conversationStore}getSummaryStore(){return this.summaryStore}getCompactionTelemetryStore(){return this.compactionTelemetryStore}getCompactionMaintenanceStore(){return this.compactionMaintenanceStore}async pruneHeartbeatOkTurns(conversationId){const allMessages=await this.conversationStore.getMessages(conversationId);if(allMessages.length===0){return 0}const toDelete=[];for(let i=0;i<allMessages.length;i++){const msg=allMessages[i];if(msg.role!=="assistant"){continue}if(!isHeartbeatOkContent(msg.content)){continue}const turnMessages=[msg];for(let j=i-1;j>=0;j--){const prev=allMessages[j];turnMessages.push(prev);if(prev.role==="user"){break}}if(!turnMessages.some(record=>record.role==="user")){continue}if(!turnLooksLikeHeartbeatTurn(turnMessages)){continue}toDelete.push(...turnMessages.map(record=>record.messageId))}if(toDelete.length===0){return 0}const uniqueIds=[...new Set(toDelete)];return this.conversationStore.deleteMessages(uniqueIds)}};var HEARTBEAT_OK_TOKEN="heartbeat_ok";var HEARTBEAT_TURN_MARKER="heartbeat.md";function isHeartbeatOkContent(content){return content.trim().toLowerCase()===HEARTBEAT_OK_TOKEN}function batchLooksLikeHeartbeatAckTurn(messages){let sawHeartbeatMarker=false;let sawHeartbeatAck=false;for(const message of messages){const stored=toStoredMessage(message);if(!sawHeartbeatMarker&&stored.content.toLowerCase().includes(HEARTBEAT_TURN_MARKER)){sawHeartbeatMarker=true}if(!sawHeartbeatAck&&stored.role==="assistant"&&isHeartbeatOkContent(stored.content)){sawHeartbeatAck=true}if(sawHeartbeatMarker&&sawHeartbeatAck){return true}}return false}function turnLooksLikeHeartbeatTurn(turnMessages){return turnMessages.some(message=>message.content.toLowerCase().includes(HEARTBEAT_TURN_MARKER))}function createEmergencyFallbackSummarize(){return async(text,aggressive)=>{const maxChars=aggressive?600*4:900*4;if(text.length<=maxChars){return text}return text.slice(0,maxChars)+"\n[Truncated for context management]"}}var SHARED_KEY=Symbol.for("@martian-engineering/lossless-claw/shared-init");function getStore(){const g=globalThis;if(!g[SHARED_KEY]){g[SHARED_KEY]=new Map}return g[SHARED_KEY]}function getSharedInit(dbPath){return getStore().get(dbPath)}function setSharedInit(dbPath,init){getStore().set(dbPath,init)}function removeSharedInit(dbPath){getStore().delete(dbPath)}var value_exports={};__export(value_exports,{HasPropertyKey:()=>HasPropertyKey,IsArray:()=>IsArray,IsAsyncIterator:()=>IsAsyncIterator,IsBigInt:()=>IsBigInt,IsBoolean:()=>IsBoolean,IsDate:()=>IsDate,IsFunction:()=>IsFunction,IsIterator:()=>IsIterator,IsNull:()=>IsNull,IsNumber:()=>IsNumber,IsObject:()=>IsObject,IsRegExp:()=>IsRegExp,IsString:()=>IsString,IsSymbol:()=>IsSymbol,IsUint8Array:()=>IsUint8Array,IsUndefined:()=>IsUndefined});function HasPropertyKey(value,key){return key in value}function IsAsyncIterator(value){return IsObject(value)&&!IsArray(value)&&!IsUint8Array(value)&&Symbol.asyncIterator in value}function IsArray(value){return Array.isArray(value)}function IsBigInt(value){return typeof value==="bigint"}function IsBoolean(value){return typeof value==="boolean"}function IsDate(value){return value instanceof globalThis.Date}function IsFunction(value){return typeof value==="function"}function IsIterator(value){return IsObject(value)&&!IsArray(value)&&!IsUint8Array(value)&&Symbol.iterator in value}function IsNull(value){return value===null}function IsNumber(value){return typeof value==="number"}function IsObject(value){return typeof value==="object"&&value!==null}function IsRegExp(value){return value instanceof globalThis.RegExp}function IsString(value){return typeof value==="string"}function IsSymbol(value){return typeof value==="symbol"}function IsUint8Array(value){return value instanceof globalThis.Uint8Array}function IsUndefined(value){return value===void 0}function ArrayType(value){return value.map(value2=>Visit(value2))}function DateType(value){return new Date(value.getTime())}function Uint8ArrayType(value){return new Uint8Array(value)}function RegExpType(value){return new RegExp(value.source,value.flags)}function ObjectType(value){const result={};for(const key of Object.getOwnPropertyNames(value)){result[key]=Visit(value[key])}for(const key of Object.getOwnPropertySymbols(value)){result[key]=Visit(value[key])}return result}function Visit(value){return IsArray(value)?ArrayType(value):IsDate(value)?DateType(value):IsUint8Array(value)?Uint8ArrayType(value):IsRegExp(value)?RegExpType(value):IsObject(value)?ObjectType(value):value}function Clone(value){return Visit(value)}function CloneType(schema,options){return options===void 0?Clone(schema):Clone({...options,...schema})}function IsObject2(value){return value!==null&&typeof value==="object"}function IsArray2(value){return globalThis.Array.isArray(value)&&!globalThis.ArrayBuffer.isView(value)}function IsUndefined2(value){return value===void 0}function IsNumber2(value){return typeof value==="number"}var TypeSystemPolicy;(function(TypeSystemPolicy2){TypeSystemPolicy2.InstanceMode="default";TypeSystemPolicy2.ExactOptionalPropertyTypes=false;TypeSystemPolicy2.AllowArrayObject=false;TypeSystemPolicy2.AllowNaN=false;TypeSystemPolicy2.AllowNullVoid=false;function IsExactOptionalProperty(value,key){return TypeSystemPolicy2.ExactOptionalPropertyTypes?key in value:value[key]!==void 0}TypeSystemPolicy2.IsExactOptionalProperty=IsExactOptionalProperty;function IsObjectLike(value){const isObject=IsObject2(value);return TypeSystemPolicy2.AllowArrayObject?isObject:isObject&&!IsArray2(value)}TypeSystemPolicy2.IsObjectLike=IsObjectLike;function IsRecordLike(value){return IsObjectLike(value)&&!(value instanceof Date)&&!(value instanceof Uint8Array)}TypeSystemPolicy2.IsRecordLike=IsRecordLike;function IsNumberLike(value){return TypeSystemPolicy2.AllowNaN?IsNumber2(value):Number.isFinite(value)}TypeSystemPolicy2.IsNumberLike=IsNumberLike;function IsVoidLike(value){const isUndefined=IsUndefined2(value);return TypeSystemPolicy2.AllowNullVoid?isUndefined||value===null:isUndefined}TypeSystemPolicy2.IsVoidLike=IsVoidLike})(TypeSystemPolicy||(TypeSystemPolicy={}));function ImmutableArray(value){return globalThis.Object.freeze(value).map(value2=>Immutable(value2))}function ImmutableDate(value){return value}function ImmutableUint8Array(value){return value}function ImmutableRegExp(value){return value}function ImmutableObject(value){const result={};for(const key of Object.getOwnPropertyNames(value)){result[key]=Immutable(value[key])}for(const key of Object.getOwnPropertySymbols(value)){result[key]=Immutable(value[key])}return globalThis.Object.freeze(result)}function Immutable(value){return IsArray(value)?ImmutableArray(value):IsDate(value)?ImmutableDate(value):IsUint8Array(value)?ImmutableUint8Array(value):IsRegExp(value)?ImmutableRegExp(value):IsObject(value)?ImmutableObject(value):value}function CreateType(schema,options){const result=options!==void 0?{...options,...schema}:schema;switch(TypeSystemPolicy.InstanceMode){case"freeze":return Immutable(result);case"clone":return Clone(result);default:return result}}var TypeBoxError=class extends Error{constructor(message){super(message)}};var TransformKind=Symbol.for("TypeBox.Transform");var ReadonlyKind=Symbol.for("TypeBox.Readonly");var OptionalKind=Symbol.for("TypeBox.Optional");var Hint=Symbol.for("TypeBox.Hint");var Kind=Symbol.for("TypeBox.Kind");function IsReadonly(value){return IsObject(value)&&value[ReadonlyKind]==="Readonly"}function IsOptional(value){return IsObject(value)&&value[OptionalKind]==="Optional"}function IsAny(value){return IsKindOf(value,"Any")}function IsArgument(value){return IsKindOf(value,"Argument")}function IsArray3(value){return IsKindOf(value,"Array")}function IsAsyncIterator2(value){return IsKindOf(value,"AsyncIterator")}function IsBigInt2(value){return IsKindOf(value,"BigInt")}function IsBoolean2(value){return IsKindOf(value,"Boolean")}function IsComputed(value){return IsKindOf(value,"Computed")}function IsConstructor(value){return IsKindOf(value,"Constructor")}function IsDate2(value){return IsKindOf(value,"Date")}function IsFunction2(value){return IsKindOf(value,"Function")}function IsInteger(value){return IsKindOf(value,"Integer")}function IsIntersect(value){return IsKindOf(value,"Intersect")}function IsIterator2(value){return IsKindOf(value,"Iterator")}function IsKindOf(value,kind){return IsObject(value)&&Kind in value&&value[Kind]===kind}function IsLiteralValue(value){return IsBoolean(value)||IsNumber(value)||IsString(value)}function IsLiteral(value){return IsKindOf(value,"Literal")}function IsMappedKey(value){return IsKindOf(value,"MappedKey")}function IsMappedResult(value){return IsKindOf(value,"MappedResult")}function IsNever(value){return IsKindOf(value,"Never")}function IsNot(value){return IsKindOf(value,"Not")}function IsNull2(value){return IsKindOf(value,"Null")}function IsNumber3(value){return IsKindOf(value,"Number")}function IsObject3(value){return IsKindOf(value,"Object")}function IsPromise(value){return IsKindOf(value,"Promise")}function IsRecord(value){return IsKindOf(value,"Record")}function IsRef(value){return IsKindOf(value,"Ref")}function IsRegExp2(value){return IsKindOf(value,"RegExp")}function IsString2(value){return IsKindOf(value,"String")}function IsSymbol2(value){return IsKindOf(value,"Symbol")}function IsTemplateLiteral(value){return IsKindOf(value,"TemplateLiteral")}function IsThis(value){return IsKindOf(value,"This")}function IsTransform(value){return IsObject(value)&&TransformKind in value}function IsTuple(value){return IsKindOf(value,"Tuple")}function IsUndefined3(value){return IsKindOf(value,"Undefined")}function IsUnion(value){return IsKindOf(value,"Union")}function IsUint8Array2(value){return IsKindOf(value,"Uint8Array")}function IsUnknown(value){return IsKindOf(value,"Unknown")}function IsUnsafe(value){return IsKindOf(value,"Unsafe")}function IsVoid(value){return IsKindOf(value,"Void")}function IsKind(value){return IsObject(value)&&Kind in value&&IsString(value[Kind])}function IsSchema(value){return IsAny(value)||IsArgument(value)||IsArray3(value)||IsBoolean2(value)||IsBigInt2(value)||IsAsyncIterator2(value)||IsComputed(value)||IsConstructor(value)||IsDate2(value)||IsFunction2(value)||IsInteger(value)||IsIntersect(value)||IsIterator2(value)||IsLiteral(value)||IsMappedKey(value)||IsMappedResult(value)||IsNever(value)||IsNot(value)||IsNull2(value)||IsNumber3(value)||IsObject3(value)||IsPromise(value)||IsRecord(value)||IsRef(value)||IsRegExp2(value)||IsString2(value)||IsSymbol2(value)||IsTemplateLiteral(value)||IsThis(value)||IsTuple(value)||IsUndefined3(value)||IsUnion(value)||IsUint8Array2(value)||IsUnknown(value)||IsUnsafe(value)||IsVoid(value)||IsKind(value)}var type_exports={};__export(type_exports,{IsAny:()=>IsAny2,IsArgument:()=>IsArgument2,IsArray:()=>IsArray4,IsAsyncIterator:()=>IsAsyncIterator3,IsBigInt:()=>IsBigInt3,IsBoolean:()=>IsBoolean3,IsComputed:()=>IsComputed2,IsConstructor:()=>IsConstructor2,IsDate:()=>IsDate3,IsFunction:()=>IsFunction3,IsImport:()=>IsImport,IsInteger:()=>IsInteger2,IsIntersect:()=>IsIntersect2,IsIterator:()=>IsIterator3,IsKind:()=>IsKind2,IsKindOf:()=>IsKindOf2,IsLiteral:()=>IsLiteral2,IsLiteralBoolean:()=>IsLiteralBoolean,IsLiteralNumber:()=>IsLiteralNumber,IsLiteralString:()=>IsLiteralString,IsLiteralValue:()=>IsLiteralValue2,IsMappedKey:()=>IsMappedKey2,IsMappedResult:()=>IsMappedResult2,IsNever:()=>IsNever2,IsNot:()=>IsNot2,IsNull:()=>IsNull3,IsNumber:()=>IsNumber4,IsObject:()=>IsObject4,IsOptional:()=>IsOptional2,IsPromise:()=>IsPromise2,IsProperties:()=>IsProperties,IsReadonly:()=>IsReadonly2,IsRecord:()=>IsRecord2,IsRecursive:()=>IsRecursive,IsRef:()=>IsRef2,IsRegExp:()=>IsRegExp3,IsSchema:()=>IsSchema2,IsString:()=>IsString3,IsSymbol:()=>IsSymbol3,IsTemplateLiteral:()=>IsTemplateLiteral2,IsThis:()=>IsThis2,IsTransform:()=>IsTransform2,IsTuple:()=>IsTuple2,IsUint8Array:()=>IsUint8Array3,IsUndefined:()=>IsUndefined4,IsUnion:()=>IsUnion2,IsUnionLiteral:()=>IsUnionLiteral,IsUnknown:()=>IsUnknown2,IsUnsafe:()=>IsUnsafe2,IsVoid:()=>IsVoid2,TypeGuardUnknownTypeError:()=>TypeGuardUnknownTypeError});var TypeGuardUnknownTypeError=class extends TypeBoxError{};var KnownTypes=["Argument","Any","Array","AsyncIterator","BigInt","Boolean","Computed","Constructor","Date","Enum","Function","Integer","Intersect","Iterator","Literal","MappedKey","MappedResult","Not","Null","Number","Object","Promise","Record","Ref","RegExp","String","Symbol","TemplateLiteral","This","Tuple","Undefined","Union","Uint8Array","Unknown","Void"];function IsPattern(value){try{new RegExp(value);return true}catch{return false}}function IsControlCharacterFree(value){if(!IsString(value))return false;for(let i=0;i<value.length;i++){const code=value.charCodeAt(i);if(code>=7&&code<=13||code===27||code===127){return false}}return true}function IsAdditionalProperties(value){return IsOptionalBoolean(value)||IsSchema2(value)}function IsOptionalBigInt(value){return IsUndefined(value)||IsBigInt(value)}function IsOptionalNumber(value){return IsUndefined(value)||IsNumber(value)}function IsOptionalBoolean(value){return IsUndefined(value)||IsBoolean(value)}function IsOptionalString(value){return IsUndefined(value)||IsString(value)}function IsOptionalPattern(value){return IsUndefined(value)||IsString(value)&&IsControlCharacterFree(value)&&IsPattern(value)}function IsOptionalFormat(value){return IsUndefined(value)||IsString(value)&&IsControlCharacterFree(value)}function IsOptionalSchema(value){return IsUndefined(value)||IsSchema2(value)}function IsReadonly2(value){return IsObject(value)&&value[ReadonlyKind]==="Readonly"}function IsOptional2(value){return IsObject(value)&&value[OptionalKind]==="Optional"}function IsAny2(value){return IsKindOf2(value,"Any")&&IsOptionalString(value.$id)}function IsArgument2(value){return IsKindOf2(value,"Argument")&&IsNumber(value.index)}function IsArray4(value){return IsKindOf2(value,"Array")&&value.type==="array"&&IsOptionalString(value.$id)&&IsSchema2(value.items)&&IsOptionalNumber(value.minItems)&&IsOptionalNumber(value.maxItems)&&IsOptionalBoolean(value.uniqueItems)&&IsOptionalSchema(value.contains)&&IsOptionalNumber(value.minContains)&&IsOptionalNumber(value.maxContains)}function IsAsyncIterator3(value){return IsKindOf2(value,"AsyncIterator")&&value.type==="AsyncIterator"&&IsOptionalString(value.$id)&&IsSchema2(value.items)}function IsBigInt3(value){return IsKindOf2(value,"BigInt")&&value.type==="bigint"&&IsOptionalString(value.$id)&&IsOptionalBigInt(value.exclusiveMaximum)&&IsOptionalBigInt(value.exclusiveMinimum)&&IsOptionalBigInt(value.maximum)&&IsOptionalBigInt(value.minimum)&&IsOptionalBigInt(value.multipleOf)}function IsBoolean3(value){return IsKindOf2(value,"Boolean")&&value.type==="boolean"&&IsOptionalString(value.$id)}function IsComputed2(value){return IsKindOf2(value,"Computed")&&IsString(value.target)&&IsArray(value.parameters)&&value.parameters.every(schema=>IsSchema2(schema))}function IsConstructor2(value){return IsKindOf2(value,"Constructor")&&value.type==="Constructor"&&IsOptionalString(value.$id)&&IsArray(value.parameters)&&value.parameters.every(schema=>IsSchema2(schema))&&IsSchema2(value.returns)}function IsDate3(value){return IsKindOf2(value,"Date")&&value.type==="Date"&&IsOptionalString(value.$id)&&IsOptionalNumber(value.exclusiveMaximumTimestamp)&&IsOptionalNumber(value.exclusiveMinimumTimestamp)&&IsOptionalNumber(value.maximumTimestamp)&&IsOptionalNumber(value.minimumTimestamp)&&IsOptionalNumber(value.multipleOfTimestamp)}function IsFunction3(value){return IsKindOf2(value,"Function")&&value.type==="Function"&&IsOptionalString(value.$id)&&IsArray(value.parameters)&&value.parameters.every(schema=>IsSchema2(schema))&&IsSchema2(value.returns)}function IsImport(value){return IsKindOf2(value,"Import")&&HasPropertyKey(value,"$defs")&&IsObject(value.$defs)&&IsProperties(value.$defs)&&HasPropertyKey(value,"$ref")&&IsString(value.$ref)&&value.$ref in value.$defs}function IsInteger2(value){return IsKindOf2(value,"Integer")&&value.type==="integer"&&IsOptionalString(value.$id)&&IsOptionalNumber(value.exclusiveMaximum)&&IsOptionalNumber(value.exclusiveMinimum)&&IsOptionalNumber(value.maximum)&&IsOptionalNumber(value.minimum)&&IsOptionalNumber(value.multipleOf)}function IsProperties(value){return IsObject(value)&&Object.entries(value).every(([key,schema])=>IsControlCharacterFree(key)&&IsSchema2(schema))}function IsIntersect2(value){return IsKindOf2(value,"Intersect")&&(IsString(value.type)&&value.type!=="object"?false:true)&&IsArray(value.allOf)&&value.allOf.every(schema=>IsSchema2(schema)&&!IsTransform2(schema))&&IsOptionalString(value.type)&&(IsOptionalBoolean(value.unevaluatedProperties)||IsOptionalSchema(value.unevaluatedProperties))&&IsOptionalString(value.$id)}function IsIterator3(value){return IsKindOf2(value,"Iterator")&&value.type==="Iterator"&&IsOptionalString(value.$id)&&IsSchema2(value.items)}function IsKindOf2(value,kind){return IsObject(value)&&Kind in value&&value[Kind]===kind}function IsLiteralString(value){return IsLiteral2(value)&&IsString(value.const)}function IsLiteralNumber(value){return IsLiteral2(value)&&IsNumber(value.const)}function IsLiteralBoolean(value){return IsLiteral2(value)&&IsBoolean(value.const)}function IsLiteral2(value){return IsKindOf2(value,"Literal")&&IsOptionalString(value.$id)&&IsLiteralValue2(value.const)}function IsLiteralValue2(value){return IsBoolean(value)||IsNumber(value)||IsString(value)}function IsMappedKey2(value){return IsKindOf2(value,"MappedKey")&&IsArray(value.keys)&&value.keys.every(key=>IsNumber(key)||IsString(key))}function IsMappedResult2(value){return IsKindOf2(value,"MappedResult")&&IsProperties(value.properties)}function IsNever2(value){return IsKindOf2(value,"Never")&&IsObject(value.not)&&Object.getOwnPropertyNames(value.not).length===0}function IsNot2(value){return IsKindOf2(value,"Not")&&IsSchema2(value.not)}function IsNull3(value){return IsKindOf2(value,"Null")&&value.type==="null"&&IsOptionalString(value.$id)}function IsNumber4(value){return IsKindOf2(value,"Number")&&value.type==="number"&&IsOptionalString(value.$id)&&IsOptionalNumber(value.exclusiveMaximum)&&IsOptionalNumber(value.exclusiveMinimum)&&IsOptionalNumber(value.maximum)&&IsOptionalNumber(value.minimum)&&IsOptionalNumber(value.multipleOf)}function IsObject4(value){return IsKindOf2(value,"Object")&&value.type==="object"&&IsOptionalString(value.$id)&&IsProperties(value.properties)&&IsAdditionalProperties(value.additionalProperties)&&IsOptionalNumber(value.minProperties)&&IsOptionalNumber(value.maxProperties)}function IsPromise2(value){return IsKindOf2(value,"Promise")&&value.type==="Promise"&&IsOptionalString(value.$id)&&IsSchema2(value.item)}function IsRecord2(value){return IsKindOf2(value,"Record")&&value.type==="object"&&IsOptionalString(value.$id)&&IsAdditionalProperties(value.additionalProperties)&&IsObject(value.patternProperties)&&(schema=>{const keys=Object.getOwnPropertyNames(schema.patternProperties);return keys.length===1&&IsPattern(keys[0])&&IsObject(schema.patternProperties)&&IsSchema2(schema.patternProperties[keys[0]])})(value)}function IsRecursive(value){return IsObject(value)&&Hint in value&&value[Hint]==="Recursive"}function IsRef2(value){return IsKindOf2(value,"Ref")&&IsOptionalString(value.$id)&&IsString(value.$ref)}function IsRegExp3(value){return IsKindOf2(value,"RegExp")&&IsOptionalString(value.$id)&&IsString(value.source)&&IsString(value.flags)&&IsOptionalNumber(value.maxLength)&&IsOptionalNumber(value.minLength)}function IsString3(value){return IsKindOf2(value,"String")&&value.type==="string"&&IsOptionalString(value.$id)&&IsOptionalNumber(value.minLength)&&IsOptionalNumber(value.maxLength)&&IsOptionalPattern(value.pattern)&&IsOptionalFormat(value.format)}function IsSymbol3(value){return IsKindOf2(value,"Symbol")&&value.type==="symbol"&&IsOptionalString(value.$id)}function IsTemplateLiteral2(value){return IsKindOf2(value,"TemplateLiteral")&&value.type==="string"&&IsString(value.pattern)&&value.pattern[0]==="^"&&value.pattern[value.pattern.length-1]==="$"}function IsThis2(value){return IsKindOf2(value,"This")&&IsOptionalString(value.$id)&&IsString(value.$ref)}function IsTransform2(value){return IsObject(value)&&TransformKind in value}function IsTuple2(value){return IsKindOf2(value,"Tuple")&&value.type==="array"&&IsOptionalString(value.$id)&&IsNumber(value.minItems)&&IsNumber(value.maxItems)&&value.minItems===value.maxItems&&(IsUndefined(value.items)&&IsUndefined(value.additionalItems)&&value.minItems===0||IsArray(value.items)&&value.items.every(schema=>IsSchema2(schema)))}function IsUndefined4(value){return IsKindOf2(value,"Undefined")&&value.type==="undefined"&&IsOptionalString(value.$id)}function IsUnionLiteral(value){return IsUnion2(value)&&value.anyOf.every(schema=>IsLiteralString(schema)||IsLiteralNumber(schema))}function IsUnion2(value){return IsKindOf2(value,"Union")&&IsOptionalString(value.$id)&&IsObject(value)&&IsArray(value.anyOf)&&value.anyOf.every(schema=>IsSchema2(schema))}function IsUint8Array3(value){return IsKindOf2(value,"Uint8Array")&&value.type==="Uint8Array"&&IsOptionalString(value.$id)&&IsOptionalNumber(value.minByteLength)&&IsOptionalNumber(value.maxByteLength)}function IsUnknown2(value){return IsKindOf2(value,"Unknown")&&IsOptionalString(value.$id)}function IsUnsafe2(value){return IsKindOf2(value,"Unsafe")}function IsVoid2(value){return IsKindOf2(value,"Void")&&value.type==="void"&&IsOptionalString(value.$id)}function IsKind2(value){return IsObject(value)&&Kind in value&&IsString(value[Kind])&&!KnownTypes.includes(value[Kind])}function IsSchema2(value){return IsObject(value)&&(IsAny2(value)||IsArgument2(value)||IsArray4(value)||IsBoolean3(value)||IsBigInt3(value)||IsAsyncIterator3(value)||IsComputed2(value)||IsConstructor2(value)||IsDate3(value)||IsFunction3(value)||IsInteger2(value)||IsIntersect2(value)||IsIterator3(value)||IsLiteral2(value)||IsMappedKey2(value)||IsMappedResult2(value)||IsNever2(value)||IsNot2(value)||IsNull3(value)||IsNumber4(value)||IsObject4(value)||IsPromise2(value)||IsRecord2(value)||IsRef2(value)||IsRegExp3(value)||IsString3(value)||IsSymbol3(value)||IsTemplateLiteral2(value)||IsThis2(value)||IsTuple2(value)||IsUndefined4(value)||IsUnion2(value)||IsUint8Array3(value)||IsUnknown2(value)||IsUnsafe2(value)||IsVoid2(value)||IsKind2(value))}var PatternBoolean="(true|false)";var PatternNumber="(0|[1-9][0-9]*)";var PatternString="(.*)";var PatternNever="(?!.*)";var PatternBooleanExact=`^${PatternBoolean}$`;var PatternNumberExact=`^${PatternNumber}$`;var PatternStringExact=`^${PatternString}$`;var PatternNeverExact=`^${PatternNever}$`;function SetIncludes(T,S){return T.includes(S)}function SetDistinct(T){return[...new Set(T)]}function SetIntersect(T,S){return T.filter(L=>S.includes(L))}function SetIntersectManyResolve(T,Init){return T.reduce((Acc,L)=>{return SetIntersect(Acc,L)},Init)}function SetIntersectMany(T){return T.length===1?T[0]:T.length>1?SetIntersectManyResolve(T.slice(1),T[0]):[]}function SetUnionMany(T){const Acc=[];for(const L of T)Acc.push(...L);return Acc}function Any(options){return CreateType({[Kind]:"Any"},options)}function Array2(items,options){return CreateType({[Kind]:"Array",type:"array",items},options)}function Argument(index){return CreateType({[Kind]:"Argument",index})}function AsyncIterator(items,options){return CreateType({[Kind]:"AsyncIterator",type:"AsyncIterator",items},options)}function Computed(target,parameters,options){return CreateType({[Kind]:"Computed",target,parameters},options)}function DiscardKey(value,key){const{[key]:_,...rest}=value;return rest}function Discard(value,keys){return keys.reduce((acc,key)=>DiscardKey(acc,key),value)}function Never(options){return CreateType({[Kind]:"Never",not:{}},options)}function MappedResult(properties){return CreateType({[Kind]:"MappedResult",properties})}function Constructor(parameters,returns,options){return CreateType({[Kind]:"Constructor",type:"Constructor",parameters,returns},options)}function Function(parameters,returns,options){return CreateType({[Kind]:"Function",type:"Function",parameters,returns},options)}function UnionCreate(T,options){return CreateType({[Kind]:"Union",anyOf:T},options)}function IsUnionOptional(types){return types.some(type=>IsOptional(type))}function RemoveOptionalFromRest(types){return types.map(left=>IsOptional(left)?RemoveOptionalFromType(left):left)}function RemoveOptionalFromType(T){return Discard(T,[OptionalKind])}function ResolveUnion(types,options){const isOptional=IsUnionOptional(types);return isOptional?Optional(UnionCreate(RemoveOptionalFromRest(types),options)):UnionCreate(RemoveOptionalFromRest(types),options)}function UnionEvaluated(T,options){return T.length===1?CreateType(T[0],options):T.length===0?Never(options):ResolveUnion(T,options)}function Union(types,options){return types.length===0?Never(options):types.length===1?CreateType(types[0],options):UnionCreate(types,options)}var TemplateLiteralParserError=class extends TypeBoxError{};function Unescape(pattern){return pattern.replace(/\\\$/g,"$").replace(/\\\*/g,"*").replace(/\\\^/g,"^").replace(/\\\|/g,"|").replace(/\\\(/g,"(").replace(/\\\)/g,")")}function IsNonEscaped(pattern,index,char){return pattern[index]===char&&pattern.charCodeAt(index-1)!==92}function IsOpenParen(pattern,index){return IsNonEscaped(pattern,index,"(")}function IsCloseParen(pattern,index){return IsNonEscaped(pattern,index,")")}function IsSeparator(pattern,index){return IsNonEscaped(pattern,index,"|")}function IsGroup(pattern){if(!(IsOpenParen(pattern,0)&&IsCloseParen(pattern,pattern.length-1)))return false;let count=0;for(let index=0;index<pattern.length;index++){if(IsOpenParen(pattern,index))count+=1;if(IsCloseParen(pattern,index))count-=1;if(count===0&&index!==pattern.length-1)return false}return true}function InGroup(pattern){return pattern.slice(1,pattern.length-1)}function IsPrecedenceOr(pattern){let count=0;for(let index=0;index<pattern.length;index++){if(IsOpenParen(pattern,index))count+=1;if(IsCloseParen(pattern,index))count-=1;if(IsSeparator(pattern,index)&&count===0)return true}return false}function IsPrecedenceAnd(pattern){for(let index=0;index<pattern.length;index++){if(IsOpenParen(pattern,index))return true}return false}function Or(pattern){let[count,start]=[0,0];const expressions=[];for(let index=0;index<pattern.length;index++){if(IsOpenParen(pattern,index))count+=1;if(IsCloseParen(pattern,index))count-=1;if(IsSeparator(pattern,index)&&count===0){const range2=pattern.slice(start,index);if(range2.length>0)expressions.push(TemplateLiteralParse(range2));start=index+1}}const range=pattern.slice(start);if(range.length>0)expressions.push(TemplateLiteralParse(range));if(expressions.length===0)return{type:"const",const:""};if(expressions.length===1)return expressions[0];return{type:"or",expr:expressions}}function And(pattern){function Group(value,index){if(!IsOpenParen(value,index))throw new TemplateLiteralParserError(`TemplateLiteralParser: Index must point to open parens`);let count=0;for(let scan=index;scan<value.length;scan++){if(IsOpenParen(value,scan))count+=1;if(IsCloseParen(value,scan))count-=1;if(count===0)return[index,scan]}throw new TemplateLiteralParserError(`TemplateLiteralParser: Unclosed group parens in expression`)}function Range(pattern2,index){for(let scan=index;scan<pattern2.length;scan++){if(IsOpenParen(pattern2,scan))return[index,scan]}return[index,pattern2.length]}const expressions=[];for(let index=0;index<pattern.length;index++){if(IsOpenParen(pattern,index)){const[start,end]=Group(pattern,index);const range=pattern.slice(start,end+1);expressions.push(TemplateLiteralParse(range));index=end}else{const[start,end]=Range(pattern,index);const range=pattern.slice(start,end);if(range.length>0)expressions.push(TemplateLiteralParse(range));index=end-1}}return expressions.length===0?{type:"const",const:""}:expressions.length===1?expressions[0]:{type:"and",expr:expressions}}function TemplateLiteralParse(pattern){return IsGroup(pattern)?TemplateLiteralParse(InGroup(pattern)):IsPrecedenceOr(pattern)?Or(pattern):IsPrecedenceAnd(pattern)?And(pattern):{type:"const",const:Unescape(pattern)}}function TemplateLiteralParseExact(pattern){return TemplateLiteralParse(pattern.slice(1,pattern.length-1))}var TemplateLiteralFiniteError=class extends TypeBoxError{};function IsNumberExpression(expression){return expression.type==="or"&&expression.expr.length===2&&expression.expr[0].type==="const"&&expression.expr[0].const==="0"&&expression.expr[1].type==="const"&&expression.expr[1].const==="[1-9][0-9]*"}function IsBooleanExpression(expression){return expression.type==="or"&&expression.expr.length===2&&expression.expr[0].type==="const"&&expression.expr[0].const==="true"&&expression.expr[1].type==="const"&&expression.expr[1].const==="false"}function IsStringExpression(expression){return expression.type==="const"&&expression.const===".*"}function IsTemplateLiteralExpressionFinite(expression){return IsNumberExpression(expression)||IsStringExpression(expression)?false:IsBooleanExpression(expression)?true:expression.type==="and"?expression.expr.every(expr=>IsTemplateLiteralExpressionFinite(expr)):expression.type==="or"?expression.expr.every(expr=>IsTemplateLiteralExpressionFinite(expr)):expression.type==="const"?true:(()=>{throw new TemplateLiteralFiniteError(`Unknown expression type`)})()}function IsTemplateLiteralFinite(schema){const expression=TemplateLiteralParseExact(schema.pattern);return IsTemplateLiteralExpressionFinite(expression)}var TemplateLiteralGenerateError=class extends TypeBoxError{};function*GenerateReduce(buffer){if(buffer.length===1)return yield*buffer[0];for(const left of buffer[0]){for(const right of GenerateReduce(buffer.slice(1))){yield`${left}${right}`}}}function*GenerateAnd(expression){return yield*GenerateReduce(expression.expr.map(expr=>[...TemplateLiteralExpressionGenerate(expr)]))}function*GenerateOr(expression){for(const expr of expression.expr)yield*TemplateLiteralExpressionGenerate(expr)}function*GenerateConst(expression){return yield expression.const}function*TemplateLiteralExpressionGenerate(expression){return expression.type==="and"?yield*GenerateAnd(expression):expression.type==="or"?yield*GenerateOr(expression):expression.type==="const"?yield*GenerateConst(expression):(()=>{throw new TemplateLiteralGenerateError("Unknown expression")})()}function TemplateLiteralGenerate(schema){const expression=TemplateLiteralParseExact(schema.pattern);return IsTemplateLiteralExpressionFinite(expression)?[...TemplateLiteralExpressionGenerate(expression)]:[]}function Literal(value,options){return CreateType({[Kind]:"Literal",const:value,type:typeof value},options)}function Boolean2(options){return CreateType({[Kind]:"Boolean",type:"boolean"},options)}function BigInt(options){return CreateType({[Kind]:"BigInt",type:"bigint"},options)}function Number2(options){return CreateType({[Kind]:"Number",type:"number"},options)}function String2(options){return CreateType({[Kind]:"String",type:"string"},options)}function*FromUnion(syntax){const trim=syntax.trim().replace(/"|'/g,"");return trim==="boolean"?yield Boolean2():trim==="number"?yield Number2():trim==="bigint"?yield BigInt():trim==="string"?yield String2():yield(()=>{const literals=trim.split("|").map(literal=>Literal(literal.trim()));return literals.length===0?Never():literals.length===1?literals[0]:UnionEvaluated(literals)})()}function*FromTerminal(syntax){if(syntax[1]!=="{"){const L=Literal("$");const R=FromSyntax(syntax.slice(1));return yield*[L,...R]}for(let i=2;i<syntax.length;i++){if(syntax[i]==="}"){const L=FromUnion(syntax.slice(2,i));const R=FromSyntax(syntax.slice(i+1));return yield*[...L,...R]}}yield Literal(syntax)}function*FromSyntax(syntax){for(let i=0;i<syntax.length;i++){if(syntax[i]==="$"){const L=Literal(syntax.slice(0,i));const R=FromTerminal(syntax.slice(i));return yield*[L,...R]}}yield Literal(syntax)}function TemplateLiteralSyntax(syntax){return[...FromSyntax(syntax)]}var TemplateLiteralPatternError=class extends TypeBoxError{};function Escape(value){return value.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Visit2(schema,acc){return IsTemplateLiteral(schema)?schema.pattern.slice(1,schema.pattern.length-1):IsUnion(schema)?`(${schema.anyOf.map(schema2=>Visit2(schema2,acc)).join("|")})`:IsNumber3(schema)?`${acc}${PatternNumber}`:IsInteger(schema)?`${acc}${PatternNumber}`:IsBigInt2(schema)?`${acc}${PatternNumber}`:IsString2(schema)?`${acc}${PatternString}`:IsLiteral(schema)?`${acc}${Escape(schema.const.toString())}`:IsBoolean2(schema)?`${acc}${PatternBoolean}`:(()=>{throw new TemplateLiteralPatternError(`Unexpected Kind '${schema[Kind]}'`)})()}function TemplateLiteralPattern(kinds){return`^${kinds.map(schema=>Visit2(schema,"")).join("")}$`}function TemplateLiteralToUnion(schema){const R=TemplateLiteralGenerate(schema);const L=R.map(S=>Literal(S));return UnionEvaluated(L)}function TemplateLiteral(unresolved,options){const pattern=IsString(unresolved)?TemplateLiteralPattern(TemplateLiteralSyntax(unresolved)):TemplateLiteralPattern(unresolved);return CreateType({[Kind]:"TemplateLiteral",type:"string",pattern},options)}function FromTemplateLiteral(templateLiteral){const keys=TemplateLiteralGenerate(templateLiteral);return keys.map(key=>key.toString())}function FromUnion2(types){const result=[];for(const type of types)result.push(...IndexPropertyKeys(type));return result}function FromLiteral(literalValue){return[literalValue.toString()]}function IndexPropertyKeys(type){return[...new Set(IsTemplateLiteral(type)?FromTemplateLiteral(type):IsUnion(type)?FromUnion2(type.anyOf):IsLiteral(type)?FromLiteral(type.const):IsNumber3(type)?["[number]"]:IsInteger(type)?["[number]"]:[])]}function FromProperties(type,properties,options){const result={};for(const K2 of Object.getOwnPropertyNames(properties)){result[K2]=Index(type,IndexPropertyKeys(properties[K2]),options)}return result}function FromMappedResult(type,mappedResult,options){return FromProperties(type,mappedResult.properties,options)}function IndexFromMappedResult(type,mappedResult,options){const properties=FromMappedResult(type,mappedResult,options);return MappedResult(properties)}function FromRest(types,key){return types.map(type=>IndexFromPropertyKey(type,key))}function FromIntersectRest(types){return types.filter(type=>!IsNever(type))}function FromIntersect(types,key){return IntersectEvaluated(FromIntersectRest(FromRest(types,key)))}function FromUnionRest(types){return types.some(L=>IsNever(L))?[]:types}function FromUnion3(types,key){return UnionEvaluated(FromUnionRest(FromRest(types,key)))}function FromTuple(types,key){return key in types?types[key]:key==="[number]"?UnionEvaluated(types):Never()}function FromArray(type,key){return key==="[number]"?type:Never()}function FromProperty(properties,propertyKey){return propertyKey in properties?properties[propertyKey]:Never()}function IndexFromPropertyKey(type,propertyKey){return IsIntersect(type)?FromIntersect(type.allOf,propertyKey):IsUnion(type)?FromUnion3(type.anyOf,propertyKey):IsTuple(type)?FromTuple(type.items??[],propertyKey):IsArray3(type)?FromArray(type.items,propertyKey):IsObject3(type)?FromProperty(type.properties,propertyKey):Never()}function IndexFromPropertyKeys(type,propertyKeys){return propertyKeys.map(propertyKey=>IndexFromPropertyKey(type,propertyKey))}function FromSchema(type,propertyKeys){return UnionEvaluated(IndexFromPropertyKeys(type,propertyKeys))}function Index(type,key,options){if(IsRef(type)||IsRef(key)){const error=`Index types using Ref parameters require both Type and Key to be of TSchema`;if(!IsSchema(type)||!IsSchema(key))throw new TypeBoxError(error);return Computed("Index",[type,key])}if(IsMappedResult(key))return IndexFromMappedResult(type,key,options);if(IsMappedKey(key))return IndexFromMappedKey(type,key,options);return CreateType(IsSchema(key)?FromSchema(type,IndexPropertyKeys(key)):FromSchema(type,key),options)}function MappedIndexPropertyKey(type,key,options){return{[key]:Index(type,[key],Clone(options))}}function MappedIndexPropertyKeys(type,propertyKeys,options){return propertyKeys.reduce((result,left)=>{return{...result,...MappedIndexPropertyKey(type,left,options)}},{})}function MappedIndexProperties(type,mappedKey,options){return MappedIndexPropertyKeys(type,mappedKey.keys,options)}function IndexFromMappedKey(type,mappedKey,options){const properties=MappedIndexProperties(type,mappedKey,options);return MappedResult(properties)}function Iterator(items,options){return CreateType({[Kind]:"Iterator",type:"Iterator",items},options)}function RequiredArray(properties){return globalThis.Object.keys(properties).filter(key=>!IsOptional(properties[key]))}function _Object(properties,options){const required=RequiredArray(properties);const schema=required.length>0?{[Kind]:"Object",type:"object",required,properties}:{[Kind]:"Object",type:"object",properties};return CreateType(schema,options)}var Object2=_Object;function Promise2(item,options){return CreateType({[Kind]:"Promise",type:"Promise",item},options)}function RemoveReadonly(schema){return CreateType(Discard(schema,[ReadonlyKind]))}function AddReadonly(schema){return CreateType({...schema,[ReadonlyKind]:"Readonly"})}function ReadonlyWithFlag(schema,F){return F===false?RemoveReadonly(schema):AddReadonly(schema)}function Readonly(schema,enable){const F=enable??true;return IsMappedResult(schema)?ReadonlyFromMappedResult(schema,F):ReadonlyWithFlag(schema,F)}function FromProperties2(K,F){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(K))Acc[K2]=Readonly(K[K2],F);return Acc}function FromMappedResult2(R,F){return FromProperties2(R.properties,F)}function ReadonlyFromMappedResult(R,F){const P=FromMappedResult2(R,F);return MappedResult(P)}function Tuple(types,options){return CreateType(types.length>0?{[Kind]:"Tuple",type:"array",items:types,additionalItems:false,minItems:types.length,maxItems:types.length}:{[Kind]:"Tuple",type:"array",minItems:types.length,maxItems:types.length},options)}function FromMappedResult3(K,P){return K in P?FromSchemaType(K,P[K]):MappedResult(P)}function MappedKeyToKnownMappedResultProperties(K){return{[K]:Literal(K)}}function MappedKeyToUnknownMappedResultProperties(P){const Acc={};for(const L of P)Acc[L]=Literal(L);return Acc}function MappedKeyToMappedResultProperties(K,P){return SetIncludes(P,K)?MappedKeyToKnownMappedResultProperties(K):MappedKeyToUnknownMappedResultProperties(P)}function FromMappedKey(K,P){const R=MappedKeyToMappedResultProperties(K,P);return FromMappedResult3(K,R)}function FromRest2(K,T){return T.map(L=>FromSchemaType(K,L))}function FromProperties3(K,T){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(T))Acc[K2]=FromSchemaType(K,T[K2]);return Acc}function FromSchemaType(K,T){const options={...T};return IsOptional(T)?Optional(FromSchemaType(K,Discard(T,[OptionalKind]))):IsReadonly(T)?Readonly(FromSchemaType(K,Discard(T,[ReadonlyKind]))):IsMappedResult(T)?FromMappedResult3(K,T.properties):IsMappedKey(T)?FromMappedKey(K,T.keys):IsConstructor(T)?Constructor(FromRest2(K,T.parameters),FromSchemaType(K,T.returns),options):IsFunction2(T)?Function(FromRest2(K,T.parameters),FromSchemaType(K,T.returns),options):IsAsyncIterator2(T)?AsyncIterator(FromSchemaType(K,T.items),options):IsIterator2(T)?Iterator(FromSchemaType(K,T.items),options):IsIntersect(T)?Intersect(FromRest2(K,T.allOf),options):IsUnion(T)?Union(FromRest2(K,T.anyOf),options):IsTuple(T)?Tuple(FromRest2(K,T.items??[]),options):IsObject3(T)?Object2(FromProperties3(K,T.properties),options):IsArray3(T)?Array2(FromSchemaType(K,T.items),options):IsPromise(T)?Promise2(FromSchemaType(K,T.item),options):T}function MappedFunctionReturnType(K,T){const Acc={};for(const L of K)Acc[L]=FromSchemaType(L,T);return Acc}function Mapped(key,map,options){const K=IsSchema(key)?IndexPropertyKeys(key):key;const RT=map({[Kind]:"MappedKey",keys:K});const R=MappedFunctionReturnType(K,RT);return Object2(R,options)}function RemoveOptional(schema){return CreateType(Discard(schema,[OptionalKind]))}function AddOptional(schema){return CreateType({...schema,[OptionalKind]:"Optional"})}function OptionalWithFlag(schema,F){return F===false?RemoveOptional(schema):AddOptional(schema)}function Optional(schema,enable){const F=enable??true;return IsMappedResult(schema)?OptionalFromMappedResult(schema,F):OptionalWithFlag(schema,F)}function FromProperties4(P,F){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(P))Acc[K2]=Optional(P[K2],F);return Acc}function FromMappedResult4(R,F){return FromProperties4(R.properties,F)}function OptionalFromMappedResult(R,F){const P=FromMappedResult4(R,F);return MappedResult(P)}function IntersectCreate(T,options={}){const allObjects=T.every(schema=>IsObject3(schema));const clonedUnevaluatedProperties=IsSchema(options.unevaluatedProperties)?{unevaluatedProperties:options.unevaluatedProperties}:{};return CreateType(options.unevaluatedProperties===false||IsSchema(options.unevaluatedProperties)||allObjects?{...clonedUnevaluatedProperties,[Kind]:"Intersect",type:"object",allOf:T}:{...clonedUnevaluatedProperties,[Kind]:"Intersect",allOf:T},options)}function IsIntersectOptional(types){return types.every(left=>IsOptional(left))}function RemoveOptionalFromType2(type){return Discard(type,[OptionalKind])}function RemoveOptionalFromRest2(types){return types.map(left=>IsOptional(left)?RemoveOptionalFromType2(left):left)}function ResolveIntersect(types,options){return IsIntersectOptional(types)?Optional(IntersectCreate(RemoveOptionalFromRest2(types),options)):IntersectCreate(RemoveOptionalFromRest2(types),options)}function IntersectEvaluated(types,options={}){if(types.length===1)return CreateType(types[0],options);if(types.length===0)return Never(options);if(types.some(schema=>IsTransform(schema)))throw new Error("Cannot intersect transform types");return ResolveIntersect(types,options)}function Intersect(types,options){if(types.length===1)return CreateType(types[0],options);if(types.length===0)return Never(options);if(types.some(schema=>IsTransform(schema)))throw new Error("Cannot intersect transform types");return IntersectCreate(types,options)}function Ref(...args){const[$ref,options]=typeof args[0]==="string"?[args[0],args[1]]:[args[0].$id,args[1]];if(typeof $ref!=="string")throw new TypeBoxError("Ref: $ref must be a string");return CreateType({[Kind]:"Ref",$ref},options)}function FromComputed(target,parameters){return Computed("Awaited",[Computed(target,parameters)])}function FromRef($ref){return Computed("Awaited",[Ref($ref)])}function FromIntersect2(types){return Intersect(FromRest3(types))}function FromUnion4(types){return Union(FromRest3(types))}function FromPromise(type){return Awaited(type)}function FromRest3(types){return types.map(type=>Awaited(type))}function Awaited(type,options){return CreateType(IsComputed(type)?FromComputed(type.target,type.parameters):IsIntersect(type)?FromIntersect2(type.allOf):IsUnion(type)?FromUnion4(type.anyOf):IsPromise(type)?FromPromise(type.item):IsRef(type)?FromRef(type.$ref):type,options)}function FromRest4(types){const result=[];for(const L of types)result.push(KeyOfPropertyKeys(L));return result}function FromIntersect3(types){const propertyKeysArray=FromRest4(types);const propertyKeys=SetUnionMany(propertyKeysArray);return propertyKeys}function FromUnion5(types){const propertyKeysArray=FromRest4(types);const propertyKeys=SetIntersectMany(propertyKeysArray);return propertyKeys}function FromTuple2(types){return types.map((_,indexer)=>indexer.toString())}function FromArray2(_){return["[number]"]}function FromProperties5(T){return globalThis.Object.getOwnPropertyNames(T)}function FromPatternProperties(patternProperties){if(!includePatternProperties)return[];const patternPropertyKeys=globalThis.Object.getOwnPropertyNames(patternProperties);return patternPropertyKeys.map(key=>{return key[0]==="^"&&key[key.length-1]==="$"?key.slice(1,key.length-1):key})}function KeyOfPropertyKeys(type){return IsIntersect(type)?FromIntersect3(type.allOf):IsUnion(type)?FromUnion5(type.anyOf):IsTuple(type)?FromTuple2(type.items??[]):IsArray3(type)?FromArray2(type.items):IsObject3(type)?FromProperties5(type.properties):IsRecord(type)?FromPatternProperties(type.patternProperties):[]}var includePatternProperties=false;function FromComputed2(target,parameters){return Computed("KeyOf",[Computed(target,parameters)])}function FromRef2($ref){return Computed("KeyOf",[Ref($ref)])}function KeyOfFromType(type,options){const propertyKeys=KeyOfPropertyKeys(type);const propertyKeyTypes=KeyOfPropertyKeysToRest(propertyKeys);const result=UnionEvaluated(propertyKeyTypes);return CreateType(result,options)}function KeyOfPropertyKeysToRest(propertyKeys){return propertyKeys.map(L=>L==="[number]"?Number2():Literal(L))}function KeyOf(type,options){return IsComputed(type)?FromComputed2(type.target,type.parameters):IsRef(type)?FromRef2(type.$ref):IsMappedResult(type)?KeyOfFromMappedResult(type,options):KeyOfFromType(type,options)}function FromProperties6(properties,options){const result={};for(const K2 of globalThis.Object.getOwnPropertyNames(properties))result[K2]=KeyOf(properties[K2],Clone(options));return result}function FromMappedResult5(mappedResult,options){return FromProperties6(mappedResult.properties,options)}function KeyOfFromMappedResult(mappedResult,options){const properties=FromMappedResult5(mappedResult,options);return MappedResult(properties)}function CompositeKeys(T){const Acc=[];for(const L of T)Acc.push(...KeyOfPropertyKeys(L));return SetDistinct(Acc)}function FilterNever(T){return T.filter(L=>!IsNever(L))}function CompositeProperty(T,K){const Acc=[];for(const L of T)Acc.push(...IndexFromPropertyKeys(L,[K]));return FilterNever(Acc)}function CompositeProperties(T,K){const Acc={};for(const L of K){Acc[L]=IntersectEvaluated(CompositeProperty(T,L))}return Acc}function Composite(T,options){const K=CompositeKeys(T);const P=CompositeProperties(T,K);const R=Object2(P,options);return R}function Date2(options){return CreateType({[Kind]:"Date",type:"Date"},options)}function Null(options){return CreateType({[Kind]:"Null",type:"null"},options)}function Symbol2(options){return CreateType({[Kind]:"Symbol",type:"symbol"},options)}function Undefined(options){return CreateType({[Kind]:"Undefined",type:"undefined"},options)}function Uint8Array2(options){return CreateType({[Kind]:"Uint8Array",type:"Uint8Array"},options)}function Unknown(options){return CreateType({[Kind]:"Unknown"},options)}function FromArray3(T){return T.map(L=>FromValue(L,false))}function FromProperties7(value){const Acc={};for(const K of globalThis.Object.getOwnPropertyNames(value))Acc[K]=Readonly(FromValue(value[K],false));return Acc}function ConditionalReadonly(T,root){return root===true?T:Readonly(T)}function FromValue(value,root){return IsAsyncIterator(value)?ConditionalReadonly(Any(),root):IsIterator(value)?ConditionalReadonly(Any(),root):IsArray(value)?Readonly(Tuple(FromArray3(value))):IsUint8Array(value)?Uint8Array2():IsDate(value)?Date2():IsObject(value)?ConditionalReadonly(Object2(FromProperties7(value)),root):IsFunction(value)?ConditionalReadonly(Function([],Unknown()),root):IsUndefined(value)?Undefined():IsNull(value)?Null():IsSymbol(value)?Symbol2():IsBigInt(value)?BigInt():IsNumber(value)?Literal(value):IsBoolean(value)?Literal(value):IsString(value)?Literal(value):Object2({})}function Const(T,options){return CreateType(FromValue(T,true),options)}function ConstructorParameters(schema,options){return IsConstructor(schema)?Tuple(schema.parameters,options):Never(options)}function Enum(item,options){if(IsUndefined(item))throw new Error("Enum undefined or empty");const values1=globalThis.Object.getOwnPropertyNames(item).filter(key=>isNaN(key)).map(key=>item[key]);const values2=[...new Set(values1)];const anyOf=values2.map(value=>Literal(value));return Union(anyOf,{...options,[Hint]:"Enum"})}var ExtendsResolverError=class extends TypeBoxError{};var ExtendsResult;(function(ExtendsResult2){ExtendsResult2[ExtendsResult2["Union"]=0]="Union";ExtendsResult2[ExtendsResult2["True"]=1]="True";ExtendsResult2[ExtendsResult2["False"]=2]="False"})(ExtendsResult||(ExtendsResult={}));function IntoBooleanResult(result){return result===ExtendsResult.False?result:ExtendsResult.True}function Throw(message){throw new ExtendsResolverError(message)}function IsStructuralRight(right){return type_exports.IsNever(right)||type_exports.IsIntersect(right)||type_exports.IsUnion(right)||type_exports.IsUnknown(right)||type_exports.IsAny(right)}function StructuralRight(left,right){return type_exports.IsNever(right)?FromNeverRight(left,right):type_exports.IsIntersect(right)?FromIntersectRight(left,right):type_exports.IsUnion(right)?FromUnionRight(left,right):type_exports.IsUnknown(right)?FromUnknownRight(left,right):type_exports.IsAny(right)?FromAnyRight(left,right):Throw("StructuralRight")}function FromAnyRight(left,right){return ExtendsResult.True}function FromAny(left,right){return type_exports.IsIntersect(right)?FromIntersectRight(left,right):type_exports.IsUnion(right)&&right.anyOf.some(schema=>type_exports.IsAny(schema)||type_exports.IsUnknown(schema))?ExtendsResult.True:type_exports.IsUnion(right)?ExtendsResult.Union:type_exports.IsUnknown(right)?ExtendsResult.True:type_exports.IsAny(right)?ExtendsResult.True:ExtendsResult.Union}function FromArrayRight(left,right){return type_exports.IsUnknown(left)?ExtendsResult.False:type_exports.IsAny(left)?ExtendsResult.Union:type_exports.IsNever(left)?ExtendsResult.True:ExtendsResult.False}function FromArray4(left,right){return type_exports.IsObject(right)&&IsObjectArrayLike(right)?ExtendsResult.True:IsStructuralRight(right)?StructuralRight(left,right):!type_exports.IsArray(right)?ExtendsResult.False:IntoBooleanResult(Visit3(left.items,right.items))}function FromAsyncIterator(left,right){return IsStructuralRight(right)?StructuralRight(left,right):!type_exports.IsAsyncIterator(right)?ExtendsResult.False:IntoBooleanResult(Visit3(left.items,right.items))}function FromBigInt(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsBigInt(right)?ExtendsResult.True:ExtendsResult.False}function FromBooleanRight(left,right){return type_exports.IsLiteralBoolean(left)?ExtendsResult.True:type_exports.IsBoolean(left)?ExtendsResult.True:ExtendsResult.False}function FromBoolean(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsBoolean(right)?ExtendsResult.True:ExtendsResult.False}function FromConstructor(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):!type_exports.IsConstructor(right)?ExtendsResult.False:left.parameters.length>right.parameters.length?ExtendsResult.False:!left.parameters.every((schema,index)=>IntoBooleanResult(Visit3(right.parameters[index],schema))===ExtendsResult.True)?ExtendsResult.False:IntoBooleanResult(Visit3(left.returns,right.returns))}function FromDate(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsDate(right)?ExtendsResult.True:ExtendsResult.False}function FromFunction(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):!type_exports.IsFunction(right)?ExtendsResult.False:left.parameters.length>right.parameters.length?ExtendsResult.False:!left.parameters.every((schema,index)=>IntoBooleanResult(Visit3(right.parameters[index],schema))===ExtendsResult.True)?ExtendsResult.False:IntoBooleanResult(Visit3(left.returns,right.returns))}function FromIntegerRight(left,right){return type_exports.IsLiteral(left)&&value_exports.IsNumber(left.const)?ExtendsResult.True:type_exports.IsNumber(left)||type_exports.IsInteger(left)?ExtendsResult.True:ExtendsResult.False}function FromInteger(left,right){return type_exports.IsInteger(right)||type_exports.IsNumber(right)?ExtendsResult.True:IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):ExtendsResult.False}function FromIntersectRight(left,right){return right.allOf.every(schema=>Visit3(left,schema)===ExtendsResult.True)?ExtendsResult.True:ExtendsResult.False}function FromIntersect4(left,right){return left.allOf.some(schema=>Visit3(schema,right)===ExtendsResult.True)?ExtendsResult.True:ExtendsResult.False}function FromIterator(left,right){return IsStructuralRight(right)?StructuralRight(left,right):!type_exports.IsIterator(right)?ExtendsResult.False:IntoBooleanResult(Visit3(left.items,right.items))}function FromLiteral2(left,right){return type_exports.IsLiteral(right)&&right.const===left.const?ExtendsResult.True:IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsString(right)?FromStringRight(left,right):type_exports.IsNumber(right)?FromNumberRight(left,right):type_exports.IsInteger(right)?FromIntegerRight(left,right):type_exports.IsBoolean(right)?FromBooleanRight(left,right):ExtendsResult.False}function FromNeverRight(left,right){return ExtendsResult.False}function FromNever(left,right){return ExtendsResult.True}function UnwrapTNot(schema){let[current,depth]=[schema,0];while(true){if(!type_exports.IsNot(current))break;current=current.not;depth+=1}return depth%2===0?current:Unknown()}function FromNot(left,right){return type_exports.IsNot(left)?Visit3(UnwrapTNot(left),right):type_exports.IsNot(right)?Visit3(left,UnwrapTNot(right)):Throw("Invalid fallthrough for Not")}function FromNull(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsNull(right)?ExtendsResult.True:ExtendsResult.False}function FromNumberRight(left,right){return type_exports.IsLiteralNumber(left)?ExtendsResult.True:type_exports.IsNumber(left)||type_exports.IsInteger(left)?ExtendsResult.True:ExtendsResult.False}function FromNumber(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsInteger(right)||type_exports.IsNumber(right)?ExtendsResult.True:ExtendsResult.False}function IsObjectPropertyCount(schema,count){return Object.getOwnPropertyNames(schema.properties).length===count}function IsObjectStringLike(schema){return IsObjectArrayLike(schema)}function IsObjectSymbolLike(schema){return IsObjectPropertyCount(schema,0)||IsObjectPropertyCount(schema,1)&&"description"in schema.properties&&type_exports.IsUnion(schema.properties.description)&&schema.properties.description.anyOf.length===2&&(type_exports.IsString(schema.properties.description.anyOf[0])&&type_exports.IsUndefined(schema.properties.description.anyOf[1])||type_exports.IsString(schema.properties.description.anyOf[1])&&type_exports.IsUndefined(schema.properties.description.anyOf[0]))}function IsObjectNumberLike(schema){return IsObjectPropertyCount(schema,0)}function IsObjectBooleanLike(schema){return IsObjectPropertyCount(schema,0)}function IsObjectBigIntLike(schema){return IsObjectPropertyCount(schema,0)}function IsObjectDateLike(schema){return IsObjectPropertyCount(schema,0)}function IsObjectUint8ArrayLike(schema){return IsObjectArrayLike(schema)}function IsObjectFunctionLike(schema){const length=Number2();return IsObjectPropertyCount(schema,0)||IsObjectPropertyCount(schema,1)&&"length"in schema.properties&&IntoBooleanResult(Visit3(schema.properties["length"],length))===ExtendsResult.True}function IsObjectConstructorLike(schema){return IsObjectPropertyCount(schema,0)}function IsObjectArrayLike(schema){const length=Number2();return IsObjectPropertyCount(schema,0)||IsObjectPropertyCount(schema,1)&&"length"in schema.properties&&IntoBooleanResult(Visit3(schema.properties["length"],length))===ExtendsResult.True}function IsObjectPromiseLike(schema){const then=Function([Any()],Any());return IsObjectPropertyCount(schema,0)||IsObjectPropertyCount(schema,1)&&"then"in schema.properties&&IntoBooleanResult(Visit3(schema.properties["then"],then))===ExtendsResult.True}function Property(left,right){return Visit3(left,right)===ExtendsResult.False?ExtendsResult.False:type_exports.IsOptional(left)&&!type_exports.IsOptional(right)?ExtendsResult.False:ExtendsResult.True}function FromObjectRight(left,right){return type_exports.IsUnknown(left)?ExtendsResult.False:type_exports.IsAny(left)?ExtendsResult.Union:type_exports.IsNever(left)||type_exports.IsLiteralString(left)&&IsObjectStringLike(right)||type_exports.IsLiteralNumber(left)&&IsObjectNumberLike(right)||type_exports.IsLiteralBoolean(left)&&IsObjectBooleanLike(right)||type_exports.IsSymbol(left)&&IsObjectSymbolLike(right)||type_exports.IsBigInt(left)&&IsObjectBigIntLike(right)||type_exports.IsString(left)&&IsObjectStringLike(right)||type_exports.IsSymbol(left)&&IsObjectSymbolLike(right)||type_exports.IsNumber(left)&&IsObjectNumberLike(right)||type_exports.IsInteger(left)&&IsObjectNumberLike(right)||type_exports.IsBoolean(left)&&IsObjectBooleanLike(right)||type_exports.IsUint8Array(left)&&IsObjectUint8ArrayLike(right)||type_exports.IsDate(left)&&IsObjectDateLike(right)||type_exports.IsConstructor(left)&&IsObjectConstructorLike(right)||type_exports.IsFunction(left)&&IsObjectFunctionLike(right)?ExtendsResult.True:type_exports.IsRecord(left)&&type_exports.IsString(RecordKey(left))?(()=>{return right[Hint]==="Record"?ExtendsResult.True:ExtendsResult.False})():type_exports.IsRecord(left)&&type_exports.IsNumber(RecordKey(left))?(()=>{return IsObjectPropertyCount(right,0)?ExtendsResult.True:ExtendsResult.False})():ExtendsResult.False}function FromObject(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):!type_exports.IsObject(right)?ExtendsResult.False:(()=>{for(const key of Object.getOwnPropertyNames(right.properties)){if(!(key in left.properties)&&!type_exports.IsOptional(right.properties[key])){return ExtendsResult.False}if(type_exports.IsOptional(right.properties[key])){return ExtendsResult.True}if(Property(left.properties[key],right.properties[key])===ExtendsResult.False){return ExtendsResult.False}}return ExtendsResult.True})()}function FromPromise2(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)&&IsObjectPromiseLike(right)?ExtendsResult.True:!type_exports.IsPromise(right)?ExtendsResult.False:IntoBooleanResult(Visit3(left.item,right.item))}function RecordKey(schema){return PatternNumberExact in schema.patternProperties?Number2():PatternStringExact in schema.patternProperties?String2():Throw("Unknown record key pattern")}function RecordValue(schema){return PatternNumberExact in schema.patternProperties?schema.patternProperties[PatternNumberExact]:PatternStringExact in schema.patternProperties?schema.patternProperties[PatternStringExact]:Throw("Unable to get record value schema")}function FromRecordRight(left,right){const[Key,Value]=[RecordKey(right),RecordValue(right)];return type_exports.IsLiteralString(left)&&type_exports.IsNumber(Key)&&IntoBooleanResult(Visit3(left,Value))===ExtendsResult.True?ExtendsResult.True:type_exports.IsUint8Array(left)&&type_exports.IsNumber(Key)?Visit3(left,Value):type_exports.IsString(left)&&type_exports.IsNumber(Key)?Visit3(left,Value):type_exports.IsArray(left)&&type_exports.IsNumber(Key)?Visit3(left,Value):type_exports.IsObject(left)?(()=>{for(const key of Object.getOwnPropertyNames(left.properties)){if(Property(Value,left.properties[key])===ExtendsResult.False){return ExtendsResult.False}}return ExtendsResult.True})():ExtendsResult.False}function FromRecord(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):!type_exports.IsRecord(right)?ExtendsResult.False:Visit3(RecordValue(left),RecordValue(right))}function FromRegExp(left,right){const L=type_exports.IsRegExp(left)?String2():left;const R=type_exports.IsRegExp(right)?String2():right;return Visit3(L,R)}function FromStringRight(left,right){return type_exports.IsLiteral(left)&&value_exports.IsString(left.const)?ExtendsResult.True:type_exports.IsString(left)?ExtendsResult.True:ExtendsResult.False}function FromString(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsString(right)?ExtendsResult.True:ExtendsResult.False}function FromSymbol(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsSymbol(right)?ExtendsResult.True:ExtendsResult.False}function FromTemplateLiteral2(left,right){return type_exports.IsTemplateLiteral(left)?Visit3(TemplateLiteralToUnion(left),right):type_exports.IsTemplateLiteral(right)?Visit3(left,TemplateLiteralToUnion(right)):Throw("Invalid fallthrough for TemplateLiteral")}function IsArrayOfTuple(left,right){return type_exports.IsArray(right)&&left.items!==void 0&&left.items.every(schema=>Visit3(schema,right.items)===ExtendsResult.True)}function FromTupleRight(left,right){return type_exports.IsNever(left)?ExtendsResult.True:type_exports.IsUnknown(left)?ExtendsResult.False:type_exports.IsAny(left)?ExtendsResult.Union:ExtendsResult.False}function FromTuple3(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)&&IsObjectArrayLike(right)?ExtendsResult.True:type_exports.IsArray(right)&&IsArrayOfTuple(left,right)?ExtendsResult.True:!type_exports.IsTuple(right)?ExtendsResult.False:value_exports.IsUndefined(left.items)&&!value_exports.IsUndefined(right.items)||!value_exports.IsUndefined(left.items)&&value_exports.IsUndefined(right.items)?ExtendsResult.False:value_exports.IsUndefined(left.items)&&!value_exports.IsUndefined(right.items)?ExtendsResult.True:left.items.every((schema,index)=>Visit3(schema,right.items[index])===ExtendsResult.True)?ExtendsResult.True:ExtendsResult.False}function FromUint8Array(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsUint8Array(right)?ExtendsResult.True:ExtendsResult.False}function FromUndefined(left,right){return IsStructuralRight(right)?StructuralRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsRecord(right)?FromRecordRight(left,right):type_exports.IsVoid(right)?FromVoidRight(left,right):type_exports.IsUndefined(right)?ExtendsResult.True:ExtendsResult.False}function FromUnionRight(left,right){return right.anyOf.some(schema=>Visit3(left,schema)===ExtendsResult.True)?ExtendsResult.True:ExtendsResult.False}function FromUnion6(left,right){return left.anyOf.every(schema=>Visit3(schema,right)===ExtendsResult.True)?ExtendsResult.True:ExtendsResult.False}function FromUnknownRight(left,right){return ExtendsResult.True}function FromUnknown(left,right){return type_exports.IsNever(right)?FromNeverRight(left,right):type_exports.IsIntersect(right)?FromIntersectRight(left,right):type_exports.IsUnion(right)?FromUnionRight(left,right):type_exports.IsAny(right)?FromAnyRight(left,right):type_exports.IsString(right)?FromStringRight(left,right):type_exports.IsNumber(right)?FromNumberRight(left,right):type_exports.IsInteger(right)?FromIntegerRight(left,right):type_exports.IsBoolean(right)?FromBooleanRight(left,right):type_exports.IsArray(right)?FromArrayRight(left,right):type_exports.IsTuple(right)?FromTupleRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsUnknown(right)?ExtendsResult.True:ExtendsResult.False}function FromVoidRight(left,right){return type_exports.IsUndefined(left)?ExtendsResult.True:type_exports.IsUndefined(left)?ExtendsResult.True:ExtendsResult.False}function FromVoid(left,right){return type_exports.IsIntersect(right)?FromIntersectRight(left,right):type_exports.IsUnion(right)?FromUnionRight(left,right):type_exports.IsUnknown(right)?FromUnknownRight(left,right):type_exports.IsAny(right)?FromAnyRight(left,right):type_exports.IsObject(right)?FromObjectRight(left,right):type_exports.IsVoid(right)?ExtendsResult.True:ExtendsResult.False}function Visit3(left,right){return type_exports.IsTemplateLiteral(left)||type_exports.IsTemplateLiteral(right)?FromTemplateLiteral2(left,right):type_exports.IsRegExp(left)||type_exports.IsRegExp(right)?FromRegExp(left,right):type_exports.IsNot(left)||type_exports.IsNot(right)?FromNot(left,right):type_exports.IsAny(left)?FromAny(left,right):type_exports.IsArray(left)?FromArray4(left,right):type_exports.IsBigInt(left)?FromBigInt(left,right):type_exports.IsBoolean(left)?FromBoolean(left,right):type_exports.IsAsyncIterator(left)?FromAsyncIterator(left,right):type_exports.IsConstructor(left)?FromConstructor(left,right):type_exports.IsDate(left)?FromDate(left,right):type_exports.IsFunction(left)?FromFunction(left,right):type_exports.IsInteger(left)?FromInteger(left,right):type_exports.IsIntersect(left)?FromIntersect4(left,right):type_exports.IsIterator(left)?FromIterator(left,right):type_exports.IsLiteral(left)?FromLiteral2(left,right):type_exports.IsNever(left)?FromNever(left,right):type_exports.IsNull(left)?FromNull(left,right):type_exports.IsNumber(left)?FromNumber(left,right):type_exports.IsObject(left)?FromObject(left,right):type_exports.IsRecord(left)?FromRecord(left,right):type_exports.IsString(left)?FromString(left,right):type_exports.IsSymbol(left)?FromSymbol(left,right):type_exports.IsTuple(left)?FromTuple3(left,right):type_exports.IsPromise(left)?FromPromise2(left,right):type_exports.IsUint8Array(left)?FromUint8Array(left,right):type_exports.IsUndefined(left)?FromUndefined(left,right):type_exports.IsUnion(left)?FromUnion6(left,right):type_exports.IsUnknown(left)?FromUnknown(left,right):type_exports.IsVoid(left)?FromVoid(left,right):Throw(`Unknown left type operand '${left[Kind]}'`)}function ExtendsCheck(left,right){return Visit3(left,right)}function FromProperties8(P,Right,True,False,options){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(P))Acc[K2]=Extends(P[K2],Right,True,False,Clone(options));return Acc}function FromMappedResult6(Left,Right,True,False,options){return FromProperties8(Left.properties,Right,True,False,options)}function ExtendsFromMappedResult(Left,Right,True,False,options){const P=FromMappedResult6(Left,Right,True,False,options);return MappedResult(P)}function ExtendsResolve(left,right,trueType,falseType){const R=ExtendsCheck(left,right);return R===ExtendsResult.Union?Union([trueType,falseType]):R===ExtendsResult.True?trueType:falseType}function Extends(L,R,T,F,options){return IsMappedResult(L)?ExtendsFromMappedResult(L,R,T,F,options):IsMappedKey(L)?CreateType(ExtendsFromMappedKey(L,R,T,F,options)):CreateType(ExtendsResolve(L,R,T,F),options)}function FromPropertyKey(K,U,L,R,options){return{[K]:Extends(Literal(K),U,L,R,Clone(options))}}function FromPropertyKeys(K,U,L,R,options){return K.reduce((Acc,LK)=>{return{...Acc,...FromPropertyKey(LK,U,L,R,options)}},{})}function FromMappedKey2(K,U,L,R,options){return FromPropertyKeys(K.keys,U,L,R,options)}function ExtendsFromMappedKey(T,U,L,R,options){const P=FromMappedKey2(T,U,L,R,options);return MappedResult(P)}function ExcludeFromTemplateLiteral(L,R){return Exclude(TemplateLiteralToUnion(L),R)}function ExcludeRest(L,R){const excluded=L.filter(inner=>ExtendsCheck(inner,R)===ExtendsResult.False);return excluded.length===1?excluded[0]:Union(excluded)}function Exclude(L,R,options={}){if(IsTemplateLiteral(L))return CreateType(ExcludeFromTemplateLiteral(L,R),options);if(IsMappedResult(L))return CreateType(ExcludeFromMappedResult(L,R),options);return CreateType(IsUnion(L)?ExcludeRest(L.anyOf,R):ExtendsCheck(L,R)!==ExtendsResult.False?Never():L,options)}function FromProperties9(P,U){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(P))Acc[K2]=Exclude(P[K2],U);return Acc}function FromMappedResult7(R,T){return FromProperties9(R.properties,T)}function ExcludeFromMappedResult(R,T){const P=FromMappedResult7(R,T);return MappedResult(P)}function ExtractFromTemplateLiteral(L,R){return Extract(TemplateLiteralToUnion(L),R)}function ExtractRest(L,R){const extracted=L.filter(inner=>ExtendsCheck(inner,R)!==ExtendsResult.False);return extracted.length===1?extracted[0]:Union(extracted)}function Extract(L,R,options){if(IsTemplateLiteral(L))return CreateType(ExtractFromTemplateLiteral(L,R),options);if(IsMappedResult(L))return CreateType(ExtractFromMappedResult(L,R),options);return CreateType(IsUnion(L)?ExtractRest(L.anyOf,R):ExtendsCheck(L,R)!==ExtendsResult.False?L:Never(),options)}function FromProperties10(P,T){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(P))Acc[K2]=Extract(P[K2],T);return Acc}function FromMappedResult8(R,T){return FromProperties10(R.properties,T)}function ExtractFromMappedResult(R,T){const P=FromMappedResult8(R,T);return MappedResult(P)}function InstanceType(schema,options){return IsConstructor(schema)?CreateType(schema.returns,options):Never(options)}function ReadonlyOptional(schema){return Readonly(Optional(schema))}function RecordCreateFromPattern(pattern,T,options){return CreateType({[Kind]:"Record",type:"object",patternProperties:{[pattern]:T}},options)}function RecordCreateFromKeys(K,T,options){const result={};for(const K2 of K)result[K2]=T;return Object2(result,{...options,[Hint]:"Record"})}function FromTemplateLiteralKey(K,T,options){return IsTemplateLiteralFinite(K)?RecordCreateFromKeys(IndexPropertyKeys(K),T,options):RecordCreateFromPattern(K.pattern,T,options)}function FromUnionKey(key,type,options){return RecordCreateFromKeys(IndexPropertyKeys(Union(key)),type,options)}function FromLiteralKey(key,type,options){return RecordCreateFromKeys([key.toString()],type,options)}function FromRegExpKey(key,type,options){return RecordCreateFromPattern(key.source,type,options)}function FromStringKey(key,type,options){const pattern=IsUndefined(key.pattern)?PatternStringExact:key.pattern;return RecordCreateFromPattern(pattern,type,options)}function FromAnyKey(_,type,options){return RecordCreateFromPattern(PatternStringExact,type,options)}function FromNeverKey(_key,type,options){return RecordCreateFromPattern(PatternNeverExact,type,options)}function FromBooleanKey(_key,type,options){return Object2({true:type,false:type},options)}function FromIntegerKey(_key,type,options){return RecordCreateFromPattern(PatternNumberExact,type,options)}function FromNumberKey(_,type,options){return RecordCreateFromPattern(PatternNumberExact,type,options)}function Record(key,type,options={}){return IsUnion(key)?FromUnionKey(key.anyOf,type,options):IsTemplateLiteral(key)?FromTemplateLiteralKey(key,type,options):IsLiteral(key)?FromLiteralKey(key.const,type,options):IsBoolean2(key)?FromBooleanKey(key,type,options):IsInteger(key)?FromIntegerKey(key,type,options):IsNumber3(key)?FromNumberKey(key,type,options):IsRegExp2(key)?FromRegExpKey(key,type,options):IsString2(key)?FromStringKey(key,type,options):IsAny(key)?FromAnyKey(key,type,options):IsNever(key)?FromNeverKey(key,type,options):Never(options)}function RecordPattern(record){return globalThis.Object.getOwnPropertyNames(record.patternProperties)[0]}function RecordKey2(type){const pattern=RecordPattern(type);return pattern===PatternStringExact?String2():pattern===PatternNumberExact?Number2():String2({pattern})}function RecordValue2(type){return type.patternProperties[RecordPattern(type)]}function FromConstructor2(args,type){type.parameters=FromTypes(args,type.parameters);type.returns=FromType(args,type.returns);return type}function FromFunction2(args,type){type.parameters=FromTypes(args,type.parameters);type.returns=FromType(args,type.returns);return type}function FromIntersect5(args,type){type.allOf=FromTypes(args,type.allOf);return type}function FromUnion7(args,type){type.anyOf=FromTypes(args,type.anyOf);return type}function FromTuple4(args,type){if(IsUndefined(type.items))return type;type.items=FromTypes(args,type.items);return type}function FromArray5(args,type){type.items=FromType(args,type.items);return type}function FromAsyncIterator2(args,type){type.items=FromType(args,type.items);return type}function FromIterator2(args,type){type.items=FromType(args,type.items);return type}function FromPromise3(args,type){type.item=FromType(args,type.item);return type}function FromObject2(args,type){const mappedProperties=FromProperties11(args,type.properties);return{...type,...Object2(mappedProperties)}}function FromRecord2(args,type){const mappedKey=FromType(args,RecordKey2(type));const mappedValue=FromType(args,RecordValue2(type));const result=Record(mappedKey,mappedValue);return{...type,...result}}function FromArgument(args,argument){return argument.index in args?args[argument.index]:Unknown()}function FromProperty2(args,type){const isReadonly=IsReadonly(type);const isOptional=IsOptional(type);const mapped=FromType(args,type);return isReadonly&&isOptional?ReadonlyOptional(mapped):isReadonly&&!isOptional?Readonly(mapped):!isReadonly&&isOptional?Optional(mapped):mapped}function FromProperties11(args,properties){return globalThis.Object.getOwnPropertyNames(properties).reduce((result,key)=>{return{...result,[key]:FromProperty2(args,properties[key])}},{})}function FromTypes(args,types){return types.map(type=>FromType(args,type))}function FromType(args,type){return IsConstructor(type)?FromConstructor2(args,type):IsFunction2(type)?FromFunction2(args,type):IsIntersect(type)?FromIntersect5(args,type):IsUnion(type)?FromUnion7(args,type):IsTuple(type)?FromTuple4(args,type):IsArray3(type)?FromArray5(args,type):IsAsyncIterator2(type)?FromAsyncIterator2(args,type):IsIterator2(type)?FromIterator2(args,type):IsPromise(type)?FromPromise3(args,type):IsObject3(type)?FromObject2(args,type):IsRecord(type)?FromRecord2(args,type):IsArgument(type)?FromArgument(args,type):type}function Instantiate(type,args){return FromType(args,CloneType(type))}function Integer(options){return CreateType({[Kind]:"Integer",type:"integer"},options)}function MappedIntrinsicPropertyKey(K,M,options){return{[K]:Intrinsic(Literal(K),M,Clone(options))}}function MappedIntrinsicPropertyKeys(K,M,options){const result=K.reduce((Acc,L)=>{return{...Acc,...MappedIntrinsicPropertyKey(L,M,options)}},{});return result}function MappedIntrinsicProperties(T,M,options){return MappedIntrinsicPropertyKeys(T["keys"],M,options)}function IntrinsicFromMappedKey(T,M,options){const P=MappedIntrinsicProperties(T,M,options);return MappedResult(P)}function ApplyUncapitalize(value){const[first,rest]=[value.slice(0,1),value.slice(1)];return[first.toLowerCase(),rest].join("")}function ApplyCapitalize(value){const[first,rest]=[value.slice(0,1),value.slice(1)];return[first.toUpperCase(),rest].join("")}function ApplyUppercase(value){return value.toUpperCase()}function ApplyLowercase(value){return value.toLowerCase()}function FromTemplateLiteral3(schema,mode,options){const expression=TemplateLiteralParseExact(schema.pattern);const finite=IsTemplateLiteralExpressionFinite(expression);if(!finite)return{...schema,pattern:FromLiteralValue(schema.pattern,mode)};const strings=[...TemplateLiteralExpressionGenerate(expression)];const literals=strings.map(value=>Literal(value));const mapped=FromRest5(literals,mode);const union=Union(mapped);return TemplateLiteral([union],options)}function FromLiteralValue(value,mode){return typeof value==="string"?mode==="Uncapitalize"?ApplyUncapitalize(value):mode==="Capitalize"?ApplyCapitalize(value):mode==="Uppercase"?ApplyUppercase(value):mode==="Lowercase"?ApplyLowercase(value):value:value.toString()}function FromRest5(T,M){return T.map(L=>Intrinsic(L,M))}function Intrinsic(schema,mode,options={}){return IsMappedKey(schema)?IntrinsicFromMappedKey(schema,mode,options):IsTemplateLiteral(schema)?FromTemplateLiteral3(schema,mode,options):IsUnion(schema)?Union(FromRest5(schema.anyOf,mode),options):IsLiteral(schema)?Literal(FromLiteralValue(schema.const,mode),options):CreateType(schema,options)}function Capitalize(T,options={}){return Intrinsic(T,"Capitalize",options)}function Lowercase(T,options={}){return Intrinsic(T,"Lowercase",options)}function Uncapitalize(T,options={}){return Intrinsic(T,"Uncapitalize",options)}function Uppercase(T,options={}){return Intrinsic(T,"Uppercase",options)}function FromProperties12(properties,propertyKeys,options){const result={};for(const K2 of globalThis.Object.getOwnPropertyNames(properties))result[K2]=Omit(properties[K2],propertyKeys,Clone(options));return result}function FromMappedResult9(mappedResult,propertyKeys,options){return FromProperties12(mappedResult.properties,propertyKeys,options)}function OmitFromMappedResult(mappedResult,propertyKeys,options){const properties=FromMappedResult9(mappedResult,propertyKeys,options);return MappedResult(properties)}function FromIntersect6(types,propertyKeys){return types.map(type=>OmitResolve(type,propertyKeys))}function FromUnion8(types,propertyKeys){return types.map(type=>OmitResolve(type,propertyKeys))}function FromProperty3(properties,key){const{[key]:_,...R}=properties;return R}function FromProperties13(properties,propertyKeys){return propertyKeys.reduce((T,K2)=>FromProperty3(T,K2),properties)}function FromObject3(type,propertyKeys,properties){const options=Discard(type,[TransformKind,"$id","required","properties"]);const mappedProperties=FromProperties13(properties,propertyKeys);return Object2(mappedProperties,options)}function UnionFromPropertyKeys(propertyKeys){const result=propertyKeys.reduce((result2,key)=>IsLiteralValue(key)?[...result2,Literal(key)]:result2,[]);return Union(result)}function OmitResolve(type,propertyKeys){return IsIntersect(type)?Intersect(FromIntersect6(type.allOf,propertyKeys)):IsUnion(type)?Union(FromUnion8(type.anyOf,propertyKeys)):IsObject3(type)?FromObject3(type,propertyKeys,type.properties):Object2({})}function Omit(type,key,options){const typeKey=IsArray(key)?UnionFromPropertyKeys(key):key;const propertyKeys=IsSchema(key)?IndexPropertyKeys(key):key;const isTypeRef=IsRef(type);const isKeyRef=IsRef(key);return IsMappedResult(type)?OmitFromMappedResult(type,propertyKeys,options):IsMappedKey(key)?OmitFromMappedKey(type,key,options):isTypeRef&&isKeyRef?Computed("Omit",[type,typeKey],options):!isTypeRef&&isKeyRef?Computed("Omit",[type,typeKey],options):isTypeRef&&!isKeyRef?Computed("Omit",[type,typeKey],options):CreateType({...OmitResolve(type,propertyKeys),...options})}function FromPropertyKey2(type,key,options){return{[key]:Omit(type,[key],Clone(options))}}function FromPropertyKeys2(type,propertyKeys,options){return propertyKeys.reduce((Acc,LK)=>{return{...Acc,...FromPropertyKey2(type,LK,options)}},{})}function FromMappedKey3(type,mappedKey,options){return FromPropertyKeys2(type,mappedKey.keys,options)}function OmitFromMappedKey(type,mappedKey,options){const properties=FromMappedKey3(type,mappedKey,options);return MappedResult(properties)}function FromProperties14(properties,propertyKeys,options){const result={};for(const K2 of globalThis.Object.getOwnPropertyNames(properties))result[K2]=Pick(properties[K2],propertyKeys,Clone(options));return result}function FromMappedResult10(mappedResult,propertyKeys,options){return FromProperties14(mappedResult.properties,propertyKeys,options)}function PickFromMappedResult(mappedResult,propertyKeys,options){const properties=FromMappedResult10(mappedResult,propertyKeys,options);return MappedResult(properties)}function FromIntersect7(types,propertyKeys){return types.map(type=>PickResolve(type,propertyKeys))}function FromUnion9(types,propertyKeys){return types.map(type=>PickResolve(type,propertyKeys))}function FromProperties15(properties,propertyKeys){const result={};for(const K2 of propertyKeys)if(K2 in properties)result[K2]=properties[K2];return result}function FromObject4(Type2,keys,properties){const options=Discard(Type2,[TransformKind,"$id","required","properties"]);const mappedProperties=FromProperties15(properties,keys);return Object2(mappedProperties,options)}function UnionFromPropertyKeys2(propertyKeys){const result=propertyKeys.reduce((result2,key)=>IsLiteralValue(key)?[...result2,Literal(key)]:result2,[]);return Union(result)}function PickResolve(type,propertyKeys){return IsIntersect(type)?Intersect(FromIntersect7(type.allOf,propertyKeys)):IsUnion(type)?Union(FromUnion9(type.anyOf,propertyKeys)):IsObject3(type)?FromObject4(type,propertyKeys,type.properties):Object2({})}function Pick(type,key,options){const typeKey=IsArray(key)?UnionFromPropertyKeys2(key):key;const propertyKeys=IsSchema(key)?IndexPropertyKeys(key):key;const isTypeRef=IsRef(type);const isKeyRef=IsRef(key);return IsMappedResult(type)?PickFromMappedResult(type,propertyKeys,options):IsMappedKey(key)?PickFromMappedKey(type,key,options):isTypeRef&&isKeyRef?Computed("Pick",[type,typeKey],options):!isTypeRef&&isKeyRef?Computed("Pick",[type,typeKey],options):isTypeRef&&!isKeyRef?Computed("Pick",[type,typeKey],options):CreateType({...PickResolve(type,propertyKeys),...options})}function FromPropertyKey3(type,key,options){return{[key]:Pick(type,[key],Clone(options))}}function FromPropertyKeys3(type,propertyKeys,options){return propertyKeys.reduce((result,leftKey)=>{return{...result,...FromPropertyKey3(type,leftKey,options)}},{})}function FromMappedKey4(type,mappedKey,options){return FromPropertyKeys3(type,mappedKey.keys,options)}function PickFromMappedKey(type,mappedKey,options){const properties=FromMappedKey4(type,mappedKey,options);return MappedResult(properties)}function FromComputed3(target,parameters){return Computed("Partial",[Computed(target,parameters)])}function FromRef3($ref){return Computed("Partial",[Ref($ref)])}function FromProperties16(properties){const partialProperties={};for(const K of globalThis.Object.getOwnPropertyNames(properties))partialProperties[K]=Optional(properties[K]);return partialProperties}function FromObject5(type,properties){const options=Discard(type,[TransformKind,"$id","required","properties"]);const mappedProperties=FromProperties16(properties);return Object2(mappedProperties,options)}function FromRest6(types){return types.map(type=>PartialResolve(type))}function PartialResolve(type){return IsComputed(type)?FromComputed3(type.target,type.parameters):IsRef(type)?FromRef3(type.$ref):IsIntersect(type)?Intersect(FromRest6(type.allOf)):IsUnion(type)?Union(FromRest6(type.anyOf)):IsObject3(type)?FromObject5(type,type.properties):IsBigInt2(type)?type:IsBoolean2(type)?type:IsInteger(type)?type:IsLiteral(type)?type:IsNull2(type)?type:IsNumber3(type)?type:IsString2(type)?type:IsSymbol2(type)?type:IsUndefined3(type)?type:Object2({})}function Partial(type,options){if(IsMappedResult(type)){return PartialFromMappedResult(type,options)}else{return CreateType({...PartialResolve(type),...options})}}function FromProperties17(K,options){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(K))Acc[K2]=Partial(K[K2],Clone(options));return Acc}function FromMappedResult11(R,options){return FromProperties17(R.properties,options)}function PartialFromMappedResult(R,options){const P=FromMappedResult11(R,options);return MappedResult(P)}function FromComputed4(target,parameters){return Computed("Required",[Computed(target,parameters)])}function FromRef4($ref){return Computed("Required",[Ref($ref)])}function FromProperties18(properties){const requiredProperties={};for(const K of globalThis.Object.getOwnPropertyNames(properties))requiredProperties[K]=Discard(properties[K],[OptionalKind]);return requiredProperties}function FromObject6(type,properties){const options=Discard(type,[TransformKind,"$id","required","properties"]);const mappedProperties=FromProperties18(properties);return Object2(mappedProperties,options)}function FromRest7(types){return types.map(type=>RequiredResolve(type))}function RequiredResolve(type){return IsComputed(type)?FromComputed4(type.target,type.parameters):IsRef(type)?FromRef4(type.$ref):IsIntersect(type)?Intersect(FromRest7(type.allOf)):IsUnion(type)?Union(FromRest7(type.anyOf)):IsObject3(type)?FromObject6(type,type.properties):IsBigInt2(type)?type:IsBoolean2(type)?type:IsInteger(type)?type:IsLiteral(type)?type:IsNull2(type)?type:IsNumber3(type)?type:IsString2(type)?type:IsSymbol2(type)?type:IsUndefined3(type)?type:Object2({})}function Required(type,options){if(IsMappedResult(type)){return RequiredFromMappedResult(type,options)}else{return CreateType({...RequiredResolve(type),...options})}}function FromProperties19(P,options){const Acc={};for(const K2 of globalThis.Object.getOwnPropertyNames(P))Acc[K2]=Required(P[K2],options);return Acc}function FromMappedResult12(R,options){return FromProperties19(R.properties,options)}function RequiredFromMappedResult(R,options){const P=FromMappedResult12(R,options);return MappedResult(P)}function DereferenceParameters(moduleProperties,types){return types.map(type=>{return IsRef(type)?Dereference(moduleProperties,type.$ref):FromType2(moduleProperties,type)})}function Dereference(moduleProperties,ref){return ref in moduleProperties?IsRef(moduleProperties[ref])?Dereference(moduleProperties,moduleProperties[ref].$ref):FromType2(moduleProperties,moduleProperties[ref]):Never()}function FromAwaited(parameters){return Awaited(parameters[0])}function FromIndex(parameters){return Index(parameters[0],parameters[1])}function FromKeyOf(parameters){return KeyOf(parameters[0])}function FromPartial(parameters){return Partial(parameters[0])}function FromOmit(parameters){return Omit(parameters[0],parameters[1])}function FromPick(parameters){return Pick(parameters[0],parameters[1])}function FromRequired(parameters){return Required(parameters[0])}function FromComputed5(moduleProperties,target,parameters){const dereferenced=DereferenceParameters(moduleProperties,parameters);return target==="Awaited"?FromAwaited(dereferenced):target==="Index"?FromIndex(dereferenced):target==="KeyOf"?FromKeyOf(dereferenced):target==="Partial"?FromPartial(dereferenced):target==="Omit"?FromOmit(dereferenced):target==="Pick"?FromPick(dereferenced):target==="Required"?FromRequired(dereferenced):Never()}function FromArray6(moduleProperties,type){return Array2(FromType2(moduleProperties,type))}function FromAsyncIterator3(moduleProperties,type){return AsyncIterator(FromType2(moduleProperties,type))}function FromConstructor3(moduleProperties,parameters,instanceType){return Constructor(FromTypes2(moduleProperties,parameters),FromType2(moduleProperties,instanceType))}function FromFunction3(moduleProperties,parameters,returnType){return Function(FromTypes2(moduleProperties,parameters),FromType2(moduleProperties,returnType))}function FromIntersect8(moduleProperties,types){return Intersect(FromTypes2(moduleProperties,types))}function FromIterator3(moduleProperties,type){return Iterator(FromType2(moduleProperties,type))}function FromObject7(moduleProperties,properties){return Object2(globalThis.Object.keys(properties).reduce((result,key)=>{return{...result,[key]:FromType2(moduleProperties,properties[key])}},{}))}function FromRecord3(moduleProperties,type){const[value,pattern]=[FromType2(moduleProperties,RecordValue2(type)),RecordPattern(type)];const result=CloneType(type);result.patternProperties[pattern]=value;return result}function FromTransform(moduleProperties,transform){return IsRef(transform)?{...Dereference(moduleProperties,transform.$ref),[TransformKind]:transform[TransformKind]}:transform}function FromTuple5(moduleProperties,types){return Tuple(FromTypes2(moduleProperties,types))}function FromUnion10(moduleProperties,types){return Union(FromTypes2(moduleProperties,types))}function FromTypes2(moduleProperties,types){return types.map(type=>FromType2(moduleProperties,type))}function FromType2(moduleProperties,type){return IsOptional(type)?CreateType(FromType2(moduleProperties,Discard(type,[OptionalKind])),type):IsReadonly(type)?CreateType(FromType2(moduleProperties,Discard(type,[ReadonlyKind])),type):IsTransform(type)?CreateType(FromTransform(moduleProperties,type),type):IsArray3(type)?CreateType(FromArray6(moduleProperties,type.items),type):IsAsyncIterator2(type)?CreateType(FromAsyncIterator3(moduleProperties,type.items),type):IsComputed(type)?CreateType(FromComputed5(moduleProperties,type.target,type.parameters)):IsConstructor(type)?CreateType(FromConstructor3(moduleProperties,type.parameters,type.returns),type):IsFunction2(type)?CreateType(FromFunction3(moduleProperties,type.parameters,type.returns),type):IsIntersect(type)?CreateType(FromIntersect8(moduleProperties,type.allOf),type):IsIterator2(type)?CreateType(FromIterator3(moduleProperties,type.items),type):IsObject3(type)?CreateType(FromObject7(moduleProperties,type.properties),type):IsRecord(type)?CreateType(FromRecord3(moduleProperties,type)):IsTuple(type)?CreateType(FromTuple5(moduleProperties,type.items||[]),type):IsUnion(type)?CreateType(FromUnion10(moduleProperties,type.anyOf),type):type}function ComputeType(moduleProperties,key){return key in moduleProperties?FromType2(moduleProperties,moduleProperties[key]):Never()}function ComputeModuleProperties(moduleProperties){return globalThis.Object.getOwnPropertyNames(moduleProperties).reduce((result,key)=>{return{...result,[key]:ComputeType(moduleProperties,key)}},{})}var TModule=class{constructor($defs){const computed=ComputeModuleProperties($defs);const identified=this.WithIdentifiers(computed);this.$defs=identified}Import(key,options){const $defs={...this.$defs,[key]:CreateType(this.$defs[key],options)};return CreateType({[Kind]:"Import",$defs,$ref:key})}WithIdentifiers($defs){return globalThis.Object.getOwnPropertyNames($defs).reduce((result,key)=>{return{...result,[key]:{...$defs[key],$id:key}}},{})}};function Module(properties){return new TModule(properties)}function Not(type,options){return CreateType({[Kind]:"Not",not:type},options)}function Parameters(schema,options){return IsFunction2(schema)?Tuple(schema.parameters,options):Never()}var Ordinal=0;function Recursive(callback,options={}){if(IsUndefined(options.$id))options.$id=`T${Ordinal++}`;const thisType=CloneType(callback({[Kind]:"This",$ref:`${options.$id}`}));thisType.$id=options.$id;return CreateType({[Hint]:"Recursive",...thisType},options)}function RegExp2(unresolved,options){const expr=IsString(unresolved)?new globalThis.RegExp(unresolved):unresolved;return CreateType({[Kind]:"RegExp",type:"RegExp",source:expr.source,flags:expr.flags},options)}function RestResolve(T){return IsIntersect(T)?T.allOf:IsUnion(T)?T.anyOf:IsTuple(T)?T.items??[]:[]}function Rest(T){return RestResolve(T)}function ReturnType(schema,options){return IsFunction2(schema)?CreateType(schema.returns,options):Never(options)}var TransformDecodeBuilder=class{constructor(schema){this.schema=schema}Decode(decode){return new TransformEncodeBuilder(this.schema,decode)}};var TransformEncodeBuilder=class{constructor(schema,decode){this.schema=schema;this.decode=decode}EncodeTransform(encode,schema){const Encode=value=>schema[TransformKind].Encode(encode(value));const Decode=value=>this.decode(schema[TransformKind].Decode(value));const Codec={Encode,Decode};return{...schema,[TransformKind]:Codec}}EncodeSchema(encode,schema){const Codec={Decode:this.decode,Encode:encode};return{...schema,[TransformKind]:Codec}}Encode(encode){return IsTransform(this.schema)?this.EncodeTransform(encode,this.schema):this.EncodeSchema(encode,this.schema)}};function Transform(schema){return new TransformDecodeBuilder(schema)}function Unsafe(options={}){return CreateType({[Kind]:options[Kind]??"Unsafe"},options)}function Void(options){return CreateType({[Kind]:"Void",type:"void"},options)}var type_exports2={};__export(type_exports2,{Any:()=>Any,Argument:()=>Argument,Array:()=>Array2,AsyncIterator:()=>AsyncIterator,Awaited:()=>Awaited,BigInt:()=>BigInt,Boolean:()=>Boolean2,Capitalize:()=>Capitalize,Composite:()=>Composite,Const:()=>Const,Constructor:()=>Constructor,ConstructorParameters:()=>ConstructorParameters,Date:()=>Date2,Enum:()=>Enum,Exclude:()=>Exclude,Extends:()=>Extends,Extract:()=>Extract,Function:()=>Function,Index:()=>Index,InstanceType:()=>InstanceType,Instantiate:()=>Instantiate,Integer:()=>Integer,Intersect:()=>Intersect,Iterator:()=>Iterator,KeyOf:()=>KeyOf,Literal:()=>Literal,Lowercase:()=>Lowercase,Mapped:()=>Mapped,Module:()=>Module,Never:()=>Never,Not:()=>Not,Null:()=>Null,Number:()=>Number2,Object:()=>Object2,Omit:()=>Omit,Optional:()=>Optional,Parameters:()=>Parameters,Partial:()=>Partial,Pick:()=>Pick,Promise:()=>Promise2,Readonly:()=>Readonly,ReadonlyOptional:()=>ReadonlyOptional,Record:()=>Record,Recursive:()=>Recursive,Ref:()=>Ref,RegExp:()=>RegExp2,Required:()=>Required,Rest:()=>Rest,ReturnType:()=>ReturnType,String:()=>String2,Symbol:()=>Symbol2,TemplateLiteral:()=>TemplateLiteral,Transform:()=>Transform,Tuple:()=>Tuple,Uint8Array:()=>Uint8Array2,Uncapitalize:()=>Uncapitalize,Undefined:()=>Undefined,Union:()=>Union,Unknown:()=>Unknown,Unsafe:()=>Unsafe,Uppercase:()=>Uppercase,Void:()=>Void});var Type=type_exports2;function jsonResult(payload){return{content:[{type:"text",text:JSON.stringify(payload,null,2)}],details:payload}}async function lookupConversationForSession(input){const store=input.lcm.getConversationStore();if(typeof store.getConversationForSession==="function"){return store.getConversationForSession({sessionId:input.sessionId,sessionKey:input.sessionKey})}const normalizedSessionKey=input.sessionKey?.trim();if(normalizedSessionKey&&typeof store.getConversationBySessionKey==="function"){const byKey=await store.getConversationBySessionKey(normalizedSessionKey);if(byKey){return byKey}}const normalizedSessionId=input.sessionId?.trim();if(!normalizedSessionId){return null}return store.getConversationBySessionId(normalizedSessionId)}function parseIsoTimestampParam(params,key){const raw=params[key];if(typeof raw!=="string"){return void 0}const value=raw.trim();if(!value){return void 0}const parsed=new Date(value);if(Number.isNaN(parsed.getTime())){throw new Error(`${key} must be a valid ISO timestamp.`)}return parsed}async function resolveLcmConversationScope(input){const{lcm,params}=input;const explicitConversationId=typeof params.conversationId==="number"&&Number.isFinite(params.conversationId)?Math.trunc(params.conversationId):void 0;if(explicitConversationId!=null){return{conversationId:explicitConversationId,allConversations:false}}if(params.allConversations===true){return{conversationId:void 0,allConversations:true}}const normalizedSessionKey=input.sessionKey?.trim();if(normalizedSessionKey){const bySessionKey=await lcm.getConversationStore().getConversationBySessionKey(normalizedSessionKey);if(bySessionKey){return{conversationId:bySessionKey.conversationId,allConversations:false}}}let normalizedSessionId=input.sessionId?.trim();if(!normalizedSessionId&&normalizedSessionKey&&input.deps){normalizedSessionId=await input.deps.resolveSessionIdFromSessionKey(normalizedSessionKey)}if(!normalizedSessionId&&!input.sessionKey?.trim()){return{conversationId:void 0,allConversations:false}}const conversation=await lookupConversationForSession({lcm,sessionId:normalizedSessionId,sessionKey:input.sessionKey});if(!conversation){return{conversationId:void 0,allConversations:false}}return{conversationId:conversation.conversationId,allConversations:false}}function formatDisplayTime(value,timezone){if(value==null){return"-"}const date=value instanceof Date?value:new Date(value);if(Number.isNaN(date.getTime())){return"-"}return formatTimestamp(date,timezone)}var LcmDescribeSchema=Type.Object({id:Type.String({description:"The LCM ID to look up. Use sum_xxx for summaries, file_xxx for files."}),conversationId:Type.Optional(Type.Number({description:"Conversation ID to scope describe lookups to. If omitted, uses the current session conversation."})),allConversations:Type.Optional(Type.Boolean({description:"Set true to explicitly allow lookups across all conversations. Ignored when conversationId is provided."})),tokenCap:Type.Optional(Type.Number({description:"Optional budget cap used for subtree manifest budget-fit annotations.",minimum:1}))});function normalizeRequestedTokenCap(value){if(typeof value!=="number"||!Number.isFinite(value)){return void 0}return Math.max(1,Math.trunc(value))}function createLcmDescribeTool(input){return{name:"lcm_describe",label:"LCM Describe",description:"Look up metadata and content for an LCM item by ID. Use this to inspect summaries (sum_xxx) or stored files (file_xxx) from compacted conversation history. Returns summary content, lineage, token counts, and file exploration results.",parameters:LcmDescribeSchema,async execute(_toolCallId,params){const lcm=input.lcm??await input.getLcm?.();if(!lcm){throw new Error("LCM engine is unavailable.")}const retrieval=lcm.getRetrieval();const timezone=lcm.timezone;const p=params;const id=p.id.trim();const conversationScope=await resolveLcmConversationScope({lcm,deps:input.deps,sessionId:input.sessionId,sessionKey:input.sessionKey,params:p});if(!conversationScope.allConversations&&conversationScope.conversationId==null){return jsonResult({error:"No LCM conversation found for this session. Provide conversationId or set allConversations=true."})}const result=await retrieval.describe(id);if(!result){return jsonResult({error:`Not found: ${id}`,hint:"Check the ID format (sum_xxx for summaries, file_xxx for files)."})}if(conversationScope.conversationId!=null){const itemConversationId=result.type==="summary"?result.summary?.conversationId:result.file?.conversationId;if(itemConversationId!=null&&itemConversationId!==conversationScope.conversationId){return jsonResult({error:`Not found in conversation ${conversationScope.conversationId}: ${id}`,hint:"Use allConversations=true for cross-conversation lookup."})}}if(result.type==="summary"&&result.summary){const s=result.summary;const requestedTokenCap=normalizeRequestedTokenCap(params.tokenCap);const sessionKey=(typeof input.sessionKey==="string"?input.sessionKey:input.sessionId)?.trim()??"";const delegatedGrantId=input.deps.isSubagentSessionKey(sessionKey)?resolveDelegatedExpansionGrantId(sessionKey)??"":"";const delegatedRemainingBudget=delegatedGrantId!==""?getRuntimeExpansionAuthManager().getRemainingTokenBudget(delegatedGrantId):null;const defaultTokenCap=Math.max(1,Math.trunc(input.deps.config.maxExpandTokens));const resolvedTokenCap=(()=>{const base=requestedTokenCap??(typeof delegatedRemainingBudget==="number"?delegatedRemainingBudget:defaultTokenCap);if(typeof delegatedRemainingBudget==="number"){return Math.max(0,Math.min(base,delegatedRemainingBudget))}return Math.max(1,base)})();const manifestNodes=s.subtree.map(node=>{const summariesOnlyCost=Math.max(0,node.tokenCount+node.descendantTokenCount);const withMessagesCost=Math.max(0,summariesOnlyCost+node.sourceMessageTokenCount);return{summaryId:node.summaryId,parentSummaryId:node.parentSummaryId,depthFromRoot:node.depthFromRoot,depth:node.depth,kind:node.kind,tokenCount:node.tokenCount,descendantCount:node.descendantCount,descendantTokenCount:node.descendantTokenCount,sourceMessageTokenCount:node.sourceMessageTokenCount,childCount:node.childCount,earliestAt:node.earliestAt,latestAt:node.latestAt,path:node.path,costs:{summariesOnly:summariesOnlyCost,withMessages:withMessagesCost},budgetFit:{summariesOnly:summariesOnlyCost<=resolvedTokenCap,withMessages:withMessagesCost<=resolvedTokenCap}}});const lines=[];lines.push(`LCM_SUMMARY ${id}`);lines.push(`meta conv=${s.conversationId} kind=${s.kind} depth=${s.depth} tok=${s.tokenCount} descTok=${s.descendantTokenCount} srcTok=${s.sourceMessageTokenCount} desc=${s.descendantCount} range=${formatDisplayTime(s.earliestAt,timezone)}..${formatDisplayTime(s.latestAt,timezone)} budgetCap=${resolvedTokenCap}`);if(s.parentIds.length>0){lines.push(`parents ${s.parentIds.join(" ")}`)}if(s.childIds.length>0){lines.push(`children ${s.childIds.join(" ")}`)}lines.push("manifest");for(const node of manifestNodes){lines.push(`d${node.depthFromRoot} ${node.summaryId} k=${node.kind} tok=${node.tokenCount} descTok=${node.descendantTokenCount} srcTok=${node.sourceMessageTokenCount} desc=${node.descendantCount} child=${node.childCount} range=${formatDisplayTime(node.earliestAt,timezone)}..${formatDisplayTime(node.latestAt,timezone)} cost[s=${node.costs.summariesOnly},m=${node.costs.withMessages}] budget[s=${node.budgetFit.summariesOnly?"in":"over"},m=${node.budgetFit.withMessages?"in":"over"}]`)}lines.push("content");lines.push(s.content);return{content:[{type:"text",text:lines.join("\n")}],details:{...result,manifest:{tokenCap:resolvedTokenCap,budgetSource:requestedTokenCap!=null?"request":typeof delegatedRemainingBudget==="number"?"delegated_grant_remaining":"config_default",nodes:manifestNodes}}}}if(result.type==="file"&&result.file){const f=result.file;const lines=[];lines.push(`## LCM File: ${id}`);lines.push("");lines.push(`**Conversation:** ${f.conversationId}`);lines.push(`**Name:** ${f.fileName??"(no name)"}`);lines.push(`**Type:** ${f.mimeType??"unknown"}`);if(f.byteSize!=null){lines.push(`**Size:** ${f.byteSize.toLocaleString()} bytes`)}lines.push(`**Created:** ${formatDisplayTime(f.createdAt,timezone)}`);if(f.explorationSummary){lines.push("");lines.push("## Exploration Summary");lines.push("");lines.push(f.explorationSummary)}else{lines.push("");lines.push("*No exploration summary available.*")}return{content:[{type:"text",text:lines.join("\n")}],details:result}}return jsonResult(result)}}}import crypto4 from"node:crypto";import crypto3 from"node:crypto";import crypto2 from"node:crypto";var EXPANSION_RECURSION_ERROR_CODE="EXPANSION_RECURSION_BLOCKED";var EXPANSION_CONCURRENCY_ERROR_CODE="EXPANSION_CONCURRENCY_BLOCKED";var EXPANSION_DELEGATION_DEPTH_CAP=1;var telemetryCounters={start:0,block:0,timeout:0,success:0};var delegatedContextBySessionKey=new Map;var blockedRequestIdsBySessionKey=new Map;var activeRequestIdByOriginSessionKey=new Map;function normalizeSessionKey(sessionKey){return typeof sessionKey==="string"?sessionKey.trim():""}function getOrInitBlockedRequestIds(sessionKey){const existing=blockedRequestIdsBySessionKey.get(sessionKey);if(existing){return existing}const created=new Set;blockedRequestIdsBySessionKey.set(sessionKey,created);return created}function resolveFallbackDelegatedContext(sessionKey,requestId){if(!sessionKey){return void 0}const grantId=resolveDelegatedExpansionGrantId(sessionKey);if(!grantId){return void 0}return{requestId,expansionDepth:EXPANSION_DELEGATION_DEPTH_CAP,originSessionKey:sessionKey,stampedBy:"delegated_grant",createdAt:new Date().toISOString()}}function buildExpansionRecursionRecoveryGuidance(originSessionKey){return`Recovery: In delegated sub-agent sessions, call \`lcm_expand\` directly and synthesize your answer from that result. Do NOT call \`lcm_expand_query\` from delegated context. If deeper delegation is required, return to the origin session (${originSessionKey}) and call \`lcm_expand_query\` there.`}function buildExpansionConcurrencyRecoveryGuidance(originSessionKey){return`Recovery: Wait for the active expansion to finish before retrying. If you need an immediate fallback, stay in the origin session (${originSessionKey}) and use \`lcm_grep\` or \`lcm_describe\` instead.`}function createExpansionRequestId(){return crypto2.randomUUID()}function resolveExpansionRequestId(sessionKey){const key=normalizeSessionKey(sessionKey);return delegatedContextBySessionKey.get(key)?.requestId??createExpansionRequestId()}function resolveNextExpansionDepth(sessionKey){const key=normalizeSessionKey(sessionKey);if(!key){return 1}const existing=delegatedContextBySessionKey.get(key);if(existing){return existing.expansionDepth+1}return resolveDelegatedExpansionGrantId(key)?EXPANSION_DELEGATION_DEPTH_CAP+1:1}function stampDelegatedExpansionContext(params){const sessionKey=normalizeSessionKey(params.sessionKey);const context={requestId:params.requestId,expansionDepth:Math.max(0,Math.trunc(params.expansionDepth)),originSessionKey:params.originSessionKey.trim()||"main",stampedBy:params.stampedBy,createdAt:new Date().toISOString()};if(sessionKey){delegatedContextBySessionKey.set(sessionKey,context)}return context}function clearDelegatedExpansionContext(sessionKey){const key=normalizeSessionKey(sessionKey);if(!key){return}delegatedContextBySessionKey.delete(key);blockedRequestIdsBySessionKey.delete(key)}function evaluateExpansionRecursionGuard(params){const sessionKey=normalizeSessionKey(params.sessionKey);const requestId=params.requestId.trim();const delegatedContext=delegatedContextBySessionKey.get(sessionKey)??resolveFallbackDelegatedContext(sessionKey,requestId||createExpansionRequestId());if(!delegatedContext){return{blocked:false,requestId,expansionDepth:0,originSessionKey:sessionKey||"main"}}if(delegatedContext.expansionDepth<EXPANSION_DELEGATION_DEPTH_CAP){return{blocked:false,requestId,expansionDepth:delegatedContext.expansionDepth,originSessionKey:delegatedContext.originSessionKey}}const seenRequestIds=getOrInitBlockedRequestIds(sessionKey);const isIdempotentReentry=seenRequestIds.has(requestId);seenRequestIds.add(requestId);const reason=isIdempotentReentry?"idempotent_reentry":"depth_cap";return{blocked:true,code:EXPANSION_RECURSION_ERROR_CODE,reason,message:`${EXPANSION_RECURSION_ERROR_CODE}: Expansion delegation blocked at depth ${delegatedContext.expansionDepth} (${reason}; requestId=${requestId}; origin=${delegatedContext.originSessionKey}). `+buildExpansionRecursionRecoveryGuidance(delegatedContext.originSessionKey),requestId,expansionDepth:delegatedContext.expansionDepth,originSessionKey:delegatedContext.originSessionKey}}function acquireExpansionConcurrencySlot(params){const originSessionKey=normalizeSessionKey(params.originSessionKey)||"main";const requestId=params.requestId.trim();const activeRequestId=activeRequestIdByOriginSessionKey.get(originSessionKey);if(activeRequestId&&activeRequestId!==requestId){return{blocked:true,code:EXPANSION_CONCURRENCY_ERROR_CODE,reason:"origin_session_in_flight",message:`${EXPANSION_CONCURRENCY_ERROR_CODE}: Another lcm_expand_query delegation is already in flight for origin session (${originSessionKey}; activeRequestId=${activeRequestId}). `+buildExpansionConcurrencyRecoveryGuidance(originSessionKey),requestId,originSessionKey}}if(!activeRequestId){activeRequestIdByOriginSessionKey.set(originSessionKey,requestId)}return{blocked:false,requestId,originSessionKey}}function releaseExpansionConcurrencySlot(params){const originSessionKey=normalizeSessionKey(params.originSessionKey);if(!originSessionKey){return}const activeRequestId=activeRequestIdByOriginSessionKey.get(originSessionKey);if(!activeRequestId){return}const requestId=params.requestId?.trim();if(requestId&&activeRequestId!==requestId){return}activeRequestIdByOriginSessionKey.delete(originSessionKey)}function recordExpansionDelegationTelemetry(params){telemetryCounters[params.event]+=1;const payload={component:params.component,event:params.event,requestId:params.requestId,sessionKey:normalizeSessionKey(params.sessionKey)||void 0,expansionDepth:params.expansionDepth,originSessionKey:params.originSessionKey,reason:params.reason,runId:params.runId,counters:{start:telemetryCounters.start,block:telemetryCounters.block,timeout:telemetryCounters.timeout,success:telemetryCounters.success}};const line=`[lcm][expansion_delegation] ${JSON.stringify(payload)}`;if(params.event==="start"||params.event==="success"){params.deps.log.info(line);return}params.deps.log.warn(line)}var MAX_GATEWAY_TIMEOUT_MS=2147483647;function normalizeSummaryIds(input){if(!Array.isArray(input)){return[]}const seen=new Set;const normalized=[];for(const value of input){if(typeof value!=="string"){continue}const trimmed=value.trim();if(!trimmed||seen.has(trimmed)){continue}seen.add(trimmed);normalized.push(trimmed)}return normalized}function parseDelegatedExpansionReply(rawReply){const fallback={summary:(rawReply??"").trim(),citedIds:[],followUpSummaryIds:[],totalTokens:0,truncated:false};const reply=rawReply?.trim();if(!reply){return fallback}const candidates=[reply];const fenced=reply.match(/```(?:json)?\s*([\s\S]*?)```/i);if(fenced?.[1]){candidates.unshift(fenced[1].trim())}for(const candidate of candidates){try{const parsed=JSON.parse(candidate);const summary=typeof parsed.summary==="string"?parsed.summary.trim():"";const citedIds=normalizeSummaryIds(Array.isArray(parsed.citedIds)?parsed.citedIds.filter(value=>typeof value==="string"):void 0);const followUpSummaryIds=normalizeSummaryIds(Array.isArray(parsed.followUpSummaryIds)?parsed.followUpSummaryIds.filter(value=>typeof value==="string"):void 0);const totalTokens=typeof parsed.totalTokens==="number"&&Number.isFinite(parsed.totalTokens)?Math.max(0,Math.floor(parsed.totalTokens)):0;const truncated=parsed.truncated===true;return{summary:summary||fallback.summary,citedIds,followUpSummaryIds,totalTokens,truncated}}catch{}}return fallback}function formatDelegatedExpansionText(passes){const lines=[];const allCitedIds=new Set;for(const pass of passes){for(const summaryId of pass.citedIds){allCitedIds.add(summaryId)}if(!pass.summary.trim()){continue}if(passes.length>1){lines.push(`Pass ${pass.pass}: ${pass.summary.trim()}`)}else{lines.push(pass.summary.trim())}}if(lines.length===0){lines.push("Delegated expansion completed with no textual summary.")}if(allCitedIds.size>0){lines.push("","Cited IDs:",...Array.from(allCitedIds).map(value=>`- ${value}`))}return lines.join("\n")}function buildDelegatedExpansionTask(params){const payload={summaryIds:params.summaryIds,conversationId:params.conversationId,maxDepth:params.maxDepth,includeMessages:params.includeMessages};if(typeof params.tokenCap==="number"&&Number.isFinite(params.tokenCap)){payload.tokenCap=params.tokenCap}return["Run LCM expansion and report distilled findings.",params.query?`Original query: ${params.query}`:void 0,`Pass ${params.pass}`,"","Call `lcm_expand` using exactly this JSON payload:",JSON.stringify(payload,null,2),"","Delegated expansion metadata (for tracing):",`- requestId: ${params.requestId}`,`- expansionDepth: ${params.expansionDepth}`,`- originSessionKey: ${params.originSessionKey}`,"","Then return ONLY JSON with this shape:","{",' "summary": "string concise findings",',' "citedIds": ["sum_xxx"],',' "followUpSummaryIds": ["sum_xxx"],',' "totalTokens": 0,',' "truncated": false',"}","","Rules:","- In delegated context, use `lcm_expand` directly for retrieval.","- DO NOT call `lcm_expand_query` from this delegated session.","- Keep summary concise and factual.","- Synthesize findings from the `lcm_expand` result before returning.","- citedIds/followUpSummaryIds must contain unique summary IDs only.","- If no follow-up is needed, return an empty followUpSummaryIds array."].filter(line=>line!==void 0).join("\n")}async function resolveRequesterConversationScopeId(params){const requesterSessionKey=params.requesterSessionKey.trim();if(!requesterSessionKey){return void 0}try{const store=params.lcm.getConversationStore();if(typeof store.getConversationForSession==="function"){const conversation2=await store.getConversationForSession({sessionKey:requesterSessionKey});if(conversation2){return conversation2.conversationId}}else if(typeof store.getConversationBySessionKey==="function"){const byKey=await store.getConversationBySessionKey(requesterSessionKey);if(byKey){return byKey.conversationId}}const runtimeSessionId=await params.deps.resolveSessionIdFromSessionKey(requesterSessionKey);if(!runtimeSessionId){return void 0}const conversation=await store.getConversationBySessionId(runtimeSessionId);return conversation?.conversationId}catch{return void 0}}async function runDelegatedExpansionPass(params){const requesterAgentId=params.deps.normalizeAgentId(params.deps.parseAgentSessionKey(params.requesterSessionKey)?.agentId);const childSessionKey=`agent:${requesterAgentId}:subagent:${crypto3.randomUUID()}`;let runId="";createDelegatedExpansionGrant({delegatedSessionKey:childSessionKey,issuerSessionId:params.requesterSessionKey,allowedConversationIds:[params.conversationId],tokenCap:params.tokenCap,ttlMs:MAX_GATEWAY_TIMEOUT_MS});stampDelegatedExpansionContext({sessionKey:childSessionKey,requestId:params.requestId,expansionDepth:params.parentExpansionDepth+1,originSessionKey:params.originSessionKey,stampedBy:"runDelegatedExpansionLoop"});try{const message=buildDelegatedExpansionTask({summaryIds:params.summaryIds,conversationId:params.conversationId,maxDepth:params.maxDepth,tokenCap:params.tokenCap,includeMessages:params.includeMessages,pass:params.pass,query:params.query,requestId:params.requestId,expansionDepth:params.parentExpansionDepth+1,originSessionKey:params.originSessionKey});const response=await params.deps.callGateway({method:"agent",params:{message,sessionKey:childSessionKey,deliver:false,lane:params.deps.agentLaneSubagent,extraSystemPrompt:params.deps.buildSubagentSystemPrompt({depth:1,maxDepth:8,taskSummary:"Run lcm_expand and return JSON findings"})},timeoutMs:1e4});runId=typeof response?.runId==="string"&&response.runId?response.runId:crypto3.randomUUID();const wait=await params.deps.callGateway({method:"agent.wait",params:{runId,timeoutMs:MAX_GATEWAY_TIMEOUT_MS},timeoutMs:MAX_GATEWAY_TIMEOUT_MS});const status=typeof wait?.status==="string"?wait.status:"error";if(status==="timeout"){return{pass:params.pass,status:"timeout",runId,childSessionKey,summary:"",citedIds:[],followUpSummaryIds:[],totalTokens:0,truncated:true,error:"delegated expansion pass timed out"}}if(status!=="ok"){return{pass:params.pass,status:"error",runId,childSessionKey,summary:"",citedIds:[],followUpSummaryIds:[],totalTokens:0,truncated:true,error:typeof wait?.error==="string"?wait.error:"delegated expansion pass failed"}}const replyPayload=await params.deps.callGateway({method:"sessions.get",params:{key:childSessionKey,limit:80},timeoutMs:1e4});const reply=params.deps.readLatestAssistantReply(Array.isArray(replyPayload.messages)?replyPayload.messages:[]);const parsed=parseDelegatedExpansionReply(reply);return{pass:params.pass,status:"ok",runId,childSessionKey,summary:parsed.summary,citedIds:parsed.citedIds,followUpSummaryIds:parsed.followUpSummaryIds,totalTokens:parsed.totalTokens,truncated:parsed.truncated,rawReply:reply}}catch(err){return{pass:params.pass,status:"error",runId:runId||crypto3.randomUUID(),childSessionKey,summary:"",citedIds:[],followUpSummaryIds:[],totalTokens:0,truncated:true,error:err instanceof Error?err.message:String(err)}}finally{try{await params.deps.callGateway({method:"sessions.delete",params:{key:childSessionKey,deleteTranscript:true},timeoutMs:1e4})}catch{}revokeDelegatedExpansionGrantForSession(childSessionKey,{removeBinding:true});clearDelegatedExpansionContext(childSessionKey)}}async function runDelegatedExpansionLoop(params){const requestId=params.requestId?.trim()||resolveExpansionRequestId(params.requesterSessionKey);const recursionCheck=evaluateExpansionRecursionGuard({sessionKey:params.requesterSessionKey,requestId});recordExpansionDelegationTelemetry({deps:params.deps,component:"runDelegatedExpansionLoop",event:"start",requestId,sessionKey:params.requesterSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey});if(recursionCheck.blocked){recordExpansionDelegationTelemetry({deps:params.deps,component:"runDelegatedExpansionLoop",event:"block",requestId,sessionKey:params.requesterSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey,reason:recursionCheck.reason});return{status:"error",passes:[],citedIds:[],totalTokens:0,truncated:true,text:"Delegated expansion blocked by recursion guard.",error:recursionCheck.message}}const passes=[];const visited=new Set;const cited=new Set;let queue=normalizeSummaryIds(params.summaryIds);let pass=1;while(queue.length>0){for(const summaryId of queue){visited.add(summaryId)}const result=await runDelegatedExpansionPass({deps:params.deps,requesterSessionKey:params.requesterSessionKey,conversationId:params.conversationId,summaryIds:queue,maxDepth:params.maxDepth,tokenCap:params.tokenCap,includeMessages:params.includeMessages,query:params.query,pass,requestId,parentExpansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey});passes.push(result);if(result.status!=="ok"){if(result.status==="timeout"){recordExpansionDelegationTelemetry({deps:params.deps,component:"runDelegatedExpansionLoop",event:"timeout",requestId,sessionKey:params.requesterSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey,runId:result.runId})}const okPasses=passes.filter(entry=>entry.status==="ok");for(const okPass of okPasses){for(const summaryId of okPass.citedIds){cited.add(summaryId)}}const text=okPasses.length>0?formatDelegatedExpansionText(okPasses):"Delegated expansion failed before any pass completed.";return{status:result.status,passes,citedIds:Array.from(cited),totalTokens:okPasses.reduce((sum,entry)=>sum+entry.totalTokens,0),truncated:true,text,error:result.error}}for(const summaryId of result.citedIds){cited.add(summaryId)}const nextQueue=result.followUpSummaryIds.filter(summaryId=>!visited.has(summaryId));queue=nextQueue;pass+=1}recordExpansionDelegationTelemetry({deps:params.deps,component:"runDelegatedExpansionLoop",event:"success",requestId,sessionKey:params.requesterSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey});return{status:"ok",passes,citedIds:Array.from(cited),totalTokens:passes.reduce((sum,entry)=>sum+entry.totalTokens,0),truncated:passes.some(entry=>entry.truncated),text:formatDelegatedExpansionText(passes)}}var DEFAULT_DELEGATED_WAIT_TIMEOUT_MS=12e4;var GATEWAY_TIMEOUT_MS=1e4;var DEFAULT_MAX_ANSWER_TOKENS=2e3;var DEFAULT_MAX_CONVERSATION_BUCKETS=3;var LcmExpandQuerySchema=Type.Object({summaryIds:Type.Optional(Type.Array(Type.String(),{description:"Summary IDs to expand (sum_xxx). Required when query is not provided."})),query:Type.Optional(Type.String({description:"FTS5 query used to find summaries via the same full-text search path as lcm_grep before expansion. Use 1-3 distinctive terms or a quoted phrase; FTS5 defaults to AND matching, so extra terms make matches stricter. Required when summaryIds is not provided."})),prompt:Type.String({description:"Natural-language question or task to answer using expanded context. Put the answer request here, not in query."}),conversationId:Type.Optional(Type.Number({description:"Conversation ID to scope expansion to. If omitted, uses the current session conversation."})),allConversations:Type.Optional(Type.Boolean({description:"Set true to explicitly allow cross-conversation lookup. Ignored when conversationId is provided."})),maxTokens:Type.Optional(Type.Number({description:`Maximum answer tokens to target (default: ${DEFAULT_MAX_ANSWER_TOKENS}).`,minimum:1})),tokenCap:Type.Optional(Type.Number({description:"Expansion retrieval token budget across all delegated lcm_expand calls for this query.",minimum:1}))});function collectExpansionFailureText(value,parts,depth=0){if(depth>3||value==null){return}if(typeof value==="string"){const trimmed=value.trim();if(trimmed){parts.push(trimmed)}return}if(typeof value==="number"||typeof value==="boolean"){parts.push(String(value));return}if(value instanceof Error){if(value.message.trim()){parts.push(value.message.trim())}collectExpansionFailureText(value.cause,parts,depth+1);return}if(Array.isArray(value)){for(const entry of value){collectExpansionFailureText(entry,parts,depth+1)}return}if(typeof value==="object"){const record=value;for(const key of["message","error","reason","details","response","cause","code"]){collectExpansionFailureText(record[key],parts,depth+1)}}}function formatExpansionFailure(error){const parts=[];collectExpansionFailureText(error,parts);const message=parts.join(" ").replace(/\s+/g," ").trim();if(message){return message}if(typeof error==="string"&&error.trim()){return error.trim()}return"Delegated expansion query failed."}function shouldRetryWithoutOverride(message){const normalized=message.toLowerCase();return["model.request","missing scopes","insufficient scope","unauthorized","not authorized","forbidden","provider/model overrides are not authorized","model override is not authorized","unknown model","model not found","invalid model","not available","not supported","401","403"].some(signal=>normalized.includes(signal))}function maxDate(left,right){if(!left){return right}if(!right){return left}return left.getTime()>=right.getTime()?left:right}function buildDelegatedExpandQueryTask(params){const seedSummaryIds=params.summaryIds.length>0?params.summaryIds.join(", "):"(none)";const messageBackedSummaryIds=params.messageBackedSummaryIds.length>0?params.messageBackedSummaryIds.join(", "):"(none)";return["You are an autonomous LCM retrieval navigator. Plan and execute retrieval before answering.","","Available tools: lcm_describe, lcm_expand, lcm_grep",`Conversation scope: ${params.conversationId}`,`Expansion token budget (total across this run): ${params.tokenCap}`,`Seed summary IDs: ${seedSummaryIds}`,`Seed summaries requiring raw message expansion: ${messageBackedSummaryIds}`,params.query?`Routing query: ${params.query}`:void 0,"","Strategy:","1. Start with `lcm_describe` on seed summaries to inspect subtree manifests and branch costs.",'2. If additional candidates are needed, use `lcm_grep` scoped to summaries. Prefer `mode: "full_text"`, quote exact multi-word phrases, use `sort: "relevance"` for older-topic recall, and `sort: "hybrid"` when recency should still matter.',"3. Select branches that fit remaining budget; prefer high-signal paths first.","4. Call `lcm_expand` selectively (do not expand everything blindly).","5. Keep includeMessages=false by default; use includeMessages=true for the message-backed seed summaries above and any other specific leaf evidence.",`6. Stay within ${params.tokenCap} total expansion tokens across all lcm_expand calls.`,"","User prompt to answer:",params.prompt,"","Delegated expansion metadata (for tracing):",`- requestId: ${params.requestId}`,`- expansionDepth: ${params.expansionDepth}`,`- originSessionKey: ${params.originSessionKey}`,"","Return ONLY JSON with this shape:","{",' "answer": "string",',' "citedIds": ["sum_xxx"],',' "expandedSummaryCount": 0,',' "totalSourceTokens": 0,',' "truncated": false',"}","","Rules:","- In delegated context, call `lcm_expand` directly for source retrieval.","- DO NOT call `lcm_expand_query` from this delegated session.","- Synthesize the final answer from retrieved evidence, not assumptions.",`- Keep answer concise and focused (target <= ${params.maxTokens} tokens).`,"- citedIds must be unique summary IDs.","- expandedSummaryCount should reflect how many summaries were expanded/used.","- totalSourceTokens should estimate total tokens consumed from expansion calls.","- truncated should indicate whether source expansion appears truncated."].filter(line=>typeof line==="string").join("\n")}function formatInvalidDelegatedReply(reply,reason){const compact=reply.replace(/\s+/g," ").trim();const snippet=compact.length<=240?compact:`${compact.slice(0,240)}...`;return`Delegated expansion query returned ${reason}: ${snippet}`}function buildConversationBuckets(candidates){const buckets=new Map;for(const candidate of candidates){const bucket=buckets.get(candidate.conversationId)??{conversationId:candidate.conversationId,summaryIds:[],messageBackedSummaryIds:[],summaryIdSet:new Set,explicitSummaryIdSet:new Set,messageBackedSummaryIdSet:new Set,newestMatchAt:void 0};if(!bucket.summaryIdSet.has(candidate.summaryId)){bucket.summaryIds.push(candidate.summaryId);bucket.summaryIdSet.add(candidate.summaryId)}if(candidate.isExplicit){bucket.explicitSummaryIdSet.add(candidate.summaryId)}if(candidate.requiresMessageExpansion&&!bucket.messageBackedSummaryIdSet.has(candidate.summaryId)){bucket.messageBackedSummaryIds.push(candidate.summaryId);bucket.messageBackedSummaryIdSet.add(candidate.summaryId)}bucket.newestMatchAt=maxDate(bucket.newestMatchAt,candidate.matchedAt);buckets.set(candidate.conversationId,bucket)}return Array.from(buckets.values()).map(bucket=>({conversationId:bucket.conversationId,summaryIds:normalizeSummaryIds(bucket.summaryIds),messageBackedSummaryIds:normalizeSummaryIds(bucket.messageBackedSummaryIds),candidateCount:bucket.summaryIds.length,explicitSummaryCount:bucket.explicitSummaryIdSet.size,messageBackedCount:bucket.messageBackedSummaryIds.length,newestMatchAt:bucket.newestMatchAt}))}function compareConversationBuckets(left,right){const explicitDelta=right.explicitSummaryCount-left.explicitSummaryCount;if(explicitDelta!==0){return explicitDelta}const candidateDelta=right.candidateCount-left.candidateCount;if(candidateDelta!==0){return candidateDelta}const recencyDelta=(right.newestMatchAt?.getTime()??0)-(left.newestMatchAt?.getTime()??0);if(recencyDelta!==0){return recencyDelta}const messageBackedDelta=right.messageBackedCount-left.messageBackedCount;if(messageBackedDelta!==0){return messageBackedDelta}return left.conversationId-right.conversationId}function buildExpandQueryReply(params){const sourceConversationIds=[...params.sourceConversationIds].sort((left,right)=>left-right);return{answer:params.answer,citedIds:normalizeSummaryIds(params.citedIds),sourceConversationIds,...sourceConversationIds.length===1?{sourceConversationId:sourceConversationIds[0]}:{},expandedSummaryCount:params.expandedSummaryCount,totalSourceTokens:params.totalSourceTokens,truncated:params.truncated,...params.conversationBreakdown?{conversationBreakdown:params.conversationBreakdown}:{}}}function synthesizeConversationAnswers(params){const successfulResults=params.results.filter(result=>result.status==="success");const failedResults=params.results.filter(result=>result.status==="failed");const skippedResults=params.results.filter(result=>result.status==="skipped");if(successfulResults.length===1&&failedResults.length===0&&skippedResults.length===0){return successfulResults[0].reply.answer}const lines=[];if(successfulResults.length>1){lines.push(`Merged findings across ${successfulResults.length} conversations:`);lines.push("")}for(const result of successfulResults){if(successfulResults.length>1){lines.push(`Conversation ${result.conversationId}:`)}lines.push(result.reply.answer);if(successfulResults.length>1){lines.push("")}}const notes=[];if(failedResults.length>0){notes.push(`failed conversations: ${failedResults.map(result=>`${result.conversationId} (${result.error})`).join("; ")}`)}if(skippedResults.length>0){notes.push(`skipped conversations: ${skippedResults.map(result=>`${result.conversationId} (${result.error})`).join("; ")}`)}if(notes.length>0){if(lines.length>0&&lines[lines.length-1]!==""){lines.push("")}lines.push(`Partial coverage for "${params.prompt}": ${notes.join("; ")}`)}return lines.join("\n").trim()}function parseDelegatedExpandQueryReply(rawReply,fallbackExpandedSummaryCount){const reply=rawReply?.trim();if(!reply){return{ok:false,error:"Delegated expansion query returned an empty reply."}}const candidates=[reply];const fenced=reply.match(/```(?:json)?\s*([\s\S]*?)```/i);if(fenced?.[1]){candidates.unshift(fenced[1].trim())}for(const candidate of candidates){try{const parsed=JSON.parse(candidate);const answer=typeof parsed.answer==="string"?parsed.answer.trim():"";if(!answer){return{ok:false,error:formatInvalidDelegatedReply(reply,'JSON without a non-empty "answer"')}}const citedIds=normalizeSummaryIds(Array.isArray(parsed.citedIds)?parsed.citedIds.filter(value=>typeof value==="string"):void 0);const expandedSummaryCount=typeof parsed.expandedSummaryCount==="number"&&Number.isFinite(parsed.expandedSummaryCount)?Math.max(0,Math.floor(parsed.expandedSummaryCount)):fallbackExpandedSummaryCount;const totalSourceTokens=typeof parsed.totalSourceTokens==="number"&&Number.isFinite(parsed.totalSourceTokens)?Math.max(0,Math.floor(parsed.totalSourceTokens)):0;const truncated=parsed.truncated===true;return{ok:true,value:{answer,citedIds,expandedSummaryCount,totalSourceTokens,truncated}}}catch{}}return{ok:false,error:formatInvalidDelegatedReply(reply,"non-JSON output")}}function resolveSourceConversationId(params){if(typeof params.scopedConversationId==="number"){const mismatched=params.candidates.filter(candidate=>candidate.conversationId!==params.scopedConversationId).map(candidate=>candidate.summaryId);if(mismatched.length>0){throw new Error(`Some summaryIds are outside conversation ${params.scopedConversationId}: ${mismatched.join(", ")}`)}return params.scopedConversationId}const conversationIds=Array.from(new Set(params.candidates.map(candidate=>candidate.conversationId)));if(conversationIds.length===1&&typeof conversationIds[0]==="number"){return conversationIds[0]}if(params.allConversations&&conversationIds.length>1){throw new Error("Query matched summaries from multiple conversations. Provide conversationId or narrow the query.")}throw new Error("Unable to resolve a single conversation scope. Provide conversationId or set a narrower summary scope.")}function selectSingleConversationBucket(params){const bucket=params.buckets.find(candidateBucket=>candidateBucket.conversationId===params.sourceConversationId);if(!bucket||bucket.summaryIds.length===0){throw new Error("No summaryIds available after applying conversation scope.")}return bucket}function upsertSummaryCandidate(candidates,candidate){const existing=candidates.get(candidate.summaryId);if(!existing){candidates.set(candidate.summaryId,candidate);return}candidates.set(candidate.summaryId,{...existing,requiresMessageExpansion:existing.requiresMessageExpansion||candidate.requiresMessageExpansion,isExplicit:existing.isExplicit||candidate.isExplicit,matchedAt:maxDate(existing.matchedAt,candidate.matchedAt)})}async function resolveSummaryCandidates2(params){const retrieval=params.lcm.getRetrieval();const candidates=new Map;for(const summaryId of params.explicitSummaryIds){const described=await retrieval.describe(summaryId);if(!described||described.type!=="summary"||!described.summary){throw new Error(`Summary not found: ${summaryId}`)}upsertSummaryCandidate(candidates,{summaryId,conversationId:described.summary.conversationId,requiresMessageExpansion:false,isExplicit:true,matchedAt:described.summary.latestAt??described.summary.createdAt})}if(params.query){const summaryStore=params.lcm.getSummaryStore();const grepResult=await retrieval.grep({query:params.query,mode:"full_text",scope:"summaries",conversationId:params.conversationId});for(const summary of grepResult.summaries){upsertSummaryCandidate(candidates,{summaryId:summary.summaryId,conversationId:summary.conversationId,requiresMessageExpansion:false,isExplicit:false,matchedAt:summary.createdAt})}if(grepResult.summaries.length===0&&typeof params.conversationId==="number"){const maxDepth=await summaryStore.getConversationMaxSummaryDepth(params.conversationId);if(typeof maxDepth==="number"&&maxDepth<=1){const messageResult=await retrieval.grep({query:params.query,mode:"full_text",scope:"messages",conversationId:params.conversationId});const messageIds=messageResult.messages.map(message=>message.messageId);const leafLinks=await summaryStore.getLeafSummaryLinksForMessageIds(params.conversationId,messageIds);const summaryIdsByMessageId=new Map;for(const link of leafLinks){const linkedSummaryIds=summaryIdsByMessageId.get(link.messageId)??[];if(!linkedSummaryIds.includes(link.summaryId)){linkedSummaryIds.push(link.summaryId);summaryIdsByMessageId.set(link.messageId,linkedSummaryIds)}}for(const message of messageResult.messages){for(const summaryId of summaryIdsByMessageId.get(message.messageId)??[]){upsertSummaryCandidate(candidates,{summaryId,conversationId:params.conversationId,requiresMessageExpansion:true,isExplicit:false,matchedAt:message.createdAt})}}}}}return Array.from(candidates.values())}async function runDelegatedExpandQuery(params){const task=buildDelegatedExpandQueryTask({summaryIds:params.bucket.summaryIds,messageBackedSummaryIds:params.bucket.messageBackedSummaryIds,conversationId:params.bucket.conversationId,query:params.query,prompt:params.prompt,maxTokens:params.maxTokens,tokenCap:params.tokenCap,requestId:params.requestId,expansionDepth:params.childExpansionDepth,originSessionKey:params.originSessionKey});const expansionProvider=params.deps.config.expansionProvider||void 0;const expansionModel=params.deps.config.expansionModel||void 0;const canonicalExpansionModel=expansionModel?.includes("/")?expansionModel:void 0;const delegatedOverrideProvider=canonicalExpansionModel?void 0:expansionProvider;const delegatedOverrideModel=canonicalExpansionModel||expansionModel;const configuredOverrideLabel=delegatedOverrideProvider&&delegatedOverrideModel?`${delegatedOverrideProvider}/${delegatedOverrideModel}`:delegatedOverrideModel||delegatedOverrideProvider||"configured override";const runDelegatedQuery=async(provider,model)=>{const childSessionKey=`agent:${params.requesterAgentId}:subagent:${crypto4.randomUUID()}`;const childIdem=crypto4.randomUUID();let grantCreated=false;try{createDelegatedExpansionGrant({delegatedSessionKey:childSessionKey,issuerSessionId:params.callerSessionKey||"main",allowedConversationIds:[params.bucket.conversationId],tokenCap:params.tokenCap,ttlMs:params.delegatedWaitTimeoutMs+3e4});stampDelegatedExpansionContext({sessionKey:childSessionKey,requestId:params.requestId,expansionDepth:params.childExpansionDepth,originSessionKey:params.originSessionKey,stampedBy:"lcm_expand_query"});grantCreated=true;const response=await params.deps.callGateway({method:"agent",params:{message:task,sessionKey:childSessionKey,deliver:false,lane:params.deps.agentLaneSubagent,idempotencyKey:childIdem,...provider?{provider}:{},...model?{model}:{},extraSystemPrompt:params.deps.buildSubagentSystemPrompt({depth:1,maxDepth:8,taskSummary:"Run lcm_expand and return prompt-focused JSON answer"})},timeoutMs:GATEWAY_TIMEOUT_MS});const runId=typeof response?.runId==="string"?response.runId.trim():"";if(!runId){throw new Error(formatExpansionFailure(response?.error??response)||"Delegated expansion did not return a runId.")}const wait=await params.deps.callGateway({method:"agent.wait",params:{runId,timeoutMs:params.delegatedWaitTimeoutMs},timeoutMs:params.delegatedWaitTimeoutMs});const status=typeof wait?.status==="string"?wait.status:"error";if(status==="timeout"){recordExpansionDelegationTelemetry({deps:params.deps,component:"lcm_expand_query",event:"timeout",requestId:params.requestId,sessionKey:params.callerSessionKey,expansionDepth:params.childExpansionDepth,originSessionKey:params.originSessionKey,runId});throw new Error(`lcm_expand_query timed out waiting for delegated expansion (${params.delegatedWaitTimeoutSeconds}s).`)}if(status!=="ok"){throw new Error(formatExpansionFailure(wait?.error))}const replyPayload=await params.deps.callGateway({method:"sessions.get",params:{key:childSessionKey,limit:80},timeoutMs:GATEWAY_TIMEOUT_MS});const reply=params.deps.readLatestAssistantReply(Array.isArray(replyPayload.messages)?replyPayload.messages:[]);const parsed=parseDelegatedExpandQueryReply(reply,params.bucket.summaryIds.length);if(!parsed.ok){throw new Error(parsed.error)}recordExpansionDelegationTelemetry({deps:params.deps,component:"lcm_expand_query",event:"success",requestId:params.requestId,sessionKey:params.callerSessionKey,expansionDepth:params.childExpansionDepth,originSessionKey:params.originSessionKey,runId});return parsed.value}finally{try{await params.deps.callGateway({method:"sessions.delete",params:{key:childSessionKey,deleteTranscript:true},timeoutMs:GATEWAY_TIMEOUT_MS})}catch{}if(grantCreated){revokeDelegatedExpansionGrantForSession(childSessionKey,{removeBinding:true})}clearDelegatedExpansionContext(childSessionKey)}};if(!expansionProvider&&!expansionModel){return await runDelegatedQuery()}try{return await runDelegatedQuery(delegatedOverrideProvider,delegatedOverrideModel)}catch(error){const failure=formatExpansionFailure(error);params.deps.log.warn(`[lcm] delegated expansion override failed (${configuredOverrideLabel}) for conversation ${params.bucket.conversationId}: ${failure}`);if(!shouldRetryWithoutOverride(failure)){throw new Error(failure)}params.deps.log.warn(`[lcm] retrying delegated expansion without provider/model override after: ${failure}`);return await runDelegatedQuery()}}function createLcmExpandQueryTool(input){const delegatedWaitTimeoutMs=input.deps.config.delegationTimeoutMs||DEFAULT_DELEGATED_WAIT_TIMEOUT_MS;const delegatedWaitTimeoutSeconds=Math.ceil(delegatedWaitTimeoutMs/1e3);return{name:"lcm_expand_query",label:"LCM Expand Query",description:"Answer a focused natural-language question using delegated LCM expansion. Find candidate summaries (by IDs or a short FTS5 query that follows the same full-text rules as lcm_grep), expand them in a delegated sub-agent, and return a compact prompt-focused answer. Tool output includes cited summary IDs for follow-up.",parameters:LcmExpandQuerySchema,async execute(_toolCallId,params){const lcm=input.lcm??await input.getLcm?.();if(!lcm){throw new Error("LCM engine is unavailable.")}const p=params;const explicitSummaryIds=normalizeSummaryIds(p.summaryIds);const query=typeof p.query==="string"?p.query.trim():"";const prompt=typeof p.prompt==="string"?p.prompt.trim():"";const requestedMaxTokens=typeof p.maxTokens==="number"?Math.trunc(p.maxTokens):void 0;const maxTokens=typeof requestedMaxTokens==="number"&&Number.isFinite(requestedMaxTokens)?Math.max(1,requestedMaxTokens):DEFAULT_MAX_ANSWER_TOKENS;const requestedTokenCap=typeof p.tokenCap==="number"?Math.trunc(p.tokenCap):void 0;const expansionTokenCap=typeof requestedTokenCap==="number"&&Number.isFinite(requestedTokenCap)?Math.max(1,requestedTokenCap):Math.max(1,Math.trunc(input.deps.config.maxExpandTokens));if(!prompt){return jsonResult({error:"prompt is required."})}if(explicitSummaryIds.length===0&&!query){return jsonResult({error:"Either summaryIds or query must be provided."})}const callerSessionKey=(typeof input.requesterSessionKey==="string"?input.requesterSessionKey:input.sessionId)?.trim()??"";const requestId=resolveExpansionRequestId(callerSessionKey);const recursionCheck=evaluateExpansionRecursionGuard({sessionKey:callerSessionKey,requestId});recordExpansionDelegationTelemetry({deps:input.deps,component:"lcm_expand_query",event:"start",requestId,sessionKey:callerSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey});if(recursionCheck.blocked){recordExpansionDelegationTelemetry({deps:input.deps,component:"lcm_expand_query",event:"block",requestId,sessionKey:callerSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey,reason:recursionCheck.reason});return jsonResult({errorCode:recursionCheck.code,error:recursionCheck.message,requestId:recursionCheck.requestId,expansionDepth:recursionCheck.expansionDepth,originSessionKey:recursionCheck.originSessionKey,reason:recursionCheck.reason})}const originSessionKey=recursionCheck.originSessionKey||callerSessionKey||"main";try{const conversationScope=await resolveLcmConversationScope({lcm,deps:input.deps,sessionId:input.sessionId,sessionKey:input.sessionKey,params:p});let scopedConversationId=conversationScope.conversationId;if(!conversationScope.allConversations&&scopedConversationId==null&&callerSessionKey){scopedConversationId=await resolveRequesterConversationScopeId({deps:input.deps,requesterSessionKey:callerSessionKey,lcm})}if(!conversationScope.allConversations&&scopedConversationId==null){return jsonResult({error:"No LCM conversation found for this session. Provide conversationId or set allConversations=true."})}const candidates=await resolveSummaryCandidates2({lcm,explicitSummaryIds,query:query||void 0,conversationId:scopedConversationId});if(candidates.length===0){if(typeof scopedConversationId!=="number"){return jsonResult({error:"No matching summaries found."})}return jsonResult(buildExpandQueryReply({answer:"No matching summaries found for this scope.",citedIds:[],sourceConversationIds:[scopedConversationId],expandedSummaryCount:0,totalSourceTokens:0,truncated:false}))}const conversationBuckets=buildConversationBuckets(candidates);const concurrencyCheck=acquireExpansionConcurrencySlot({originSessionKey,requestId});if(concurrencyCheck.blocked){recordExpansionDelegationTelemetry({deps:input.deps,component:"lcm_expand_query",event:"block",requestId,sessionKey:callerSessionKey,expansionDepth:recursionCheck.expansionDepth,originSessionKey:concurrencyCheck.originSessionKey,reason:concurrencyCheck.reason});return jsonResult({errorCode:concurrencyCheck.code,error:concurrencyCheck.message,requestId:concurrencyCheck.requestId,expansionDepth:recursionCheck.expansionDepth,originSessionKey:concurrencyCheck.originSessionKey,reason:concurrencyCheck.reason})}const requesterAgentId=input.deps.normalizeAgentId(input.deps.parseAgentSessionKey(callerSessionKey)?.agentId);const childExpansionDepth=resolveNextExpansionDepth(callerSessionKey);if(!conversationScope.allConversations){const sourceConversationId=resolveSourceConversationId({scopedConversationId,allConversations:conversationScope.allConversations,candidates});const bucket=selectSingleConversationBucket({sourceConversationId,buckets:conversationBuckets});const delegatedReply=await runDelegatedExpandQuery({deps:input.deps,callerSessionKey,requesterAgentId,bucket,query:query||void 0,prompt,maxTokens,tokenCap:expansionTokenCap,requestId,childExpansionDepth,originSessionKey,delegatedWaitTimeoutMs,delegatedWaitTimeoutSeconds});return jsonResult(buildExpandQueryReply({answer:delegatedReply.answer,citedIds:delegatedReply.citedIds,sourceConversationIds:[sourceConversationId],expandedSummaryCount:delegatedReply.expandedSummaryCount,totalSourceTokens:delegatedReply.totalSourceTokens,truncated:delegatedReply.truncated}))}const rankedBuckets=[...conversationBuckets].sort(compareConversationBuckets);const bucketResults=[];const bucketsToExpand=rankedBuckets.slice(0,DEFAULT_MAX_CONVERSATION_BUCKETS);const skippedBuckets=rankedBuckets.slice(DEFAULT_MAX_CONVERSATION_BUCKETS);let remainingTokenCap=expansionTokenCap;let firstFailure;for(const bucket of bucketsToExpand){if(remainingTokenCap<=0){bucketResults.push({conversationId:bucket.conversationId,status:"skipped",candidateCount:bucket.candidateCount,error:"global token budget exhausted"});continue}try{const delegatedReply=await runDelegatedExpandQuery({deps:input.deps,callerSessionKey,requesterAgentId,bucket,query:query||void 0,prompt,maxTokens,tokenCap:remainingTokenCap,requestId,childExpansionDepth,originSessionKey,delegatedWaitTimeoutMs,delegatedWaitTimeoutSeconds});bucketResults.push({conversationId:bucket.conversationId,status:"success",candidateCount:bucket.candidateCount,reply:delegatedReply});remainingTokenCap=Math.max(0,remainingTokenCap-Math.max(0,delegatedReply.totalSourceTokens))}catch(error){const failure=formatExpansionFailure(error);firstFailure??=failure;bucketResults.push({conversationId:bucket.conversationId,status:"failed",candidateCount:bucket.candidateCount,error:failure})}}for(const bucket of skippedBuckets){bucketResults.push({conversationId:bucket.conversationId,status:"skipped",candidateCount:bucket.candidateCount,error:`skipped after reaching max conversation bucket limit (${DEFAULT_MAX_CONVERSATION_BUCKETS})`})}const successfulResults=bucketResults.filter(result=>result.status==="success");if(successfulResults.length===0){throw new Error(firstFailure??"Delegated expansion query failed.")}const conversationBreakdown=bucketResults.map(result=>{if(result.status==="success"){return{conversationId:result.conversationId,expandedSummaryCount:result.reply.expandedSummaryCount,citedIds:result.reply.citedIds,totalSourceTokens:result.reply.totalSourceTokens,truncated:result.reply.truncated,status:"success"}}return{conversationId:result.conversationId,expandedSummaryCount:0,citedIds:[],totalSourceTokens:0,truncated:true,status:result.status,error:result.error}});return jsonResult(buildExpandQueryReply({answer:synthesizeConversationAnswers({prompt,results:bucketResults}),citedIds:successfulResults.flatMap(result=>result.reply.citedIds),sourceConversationIds:successfulResults.map(result=>result.conversationId),expandedSummaryCount:successfulResults.reduce((total,result)=>total+result.reply.expandedSummaryCount,0),totalSourceTokens:successfulResults.reduce((total,result)=>total+result.reply.totalSourceTokens,0),truncated:successfulResults.some(result=>result.reply.truncated)||bucketResults.some(result=>result.status!=="success"),conversationBreakdown}))}catch(error){const failure=formatExpansionFailure(error);input.deps.log.error(`[lcm] delegated expansion query failed: ${failure}`);return jsonResult({error:failure})}finally{releaseExpansionConcurrencySlot({originSessionKey,requestId})}}}}var EXPANSION_ROUTING_THRESHOLDS={defaultDepth:3,minDepth:1,maxDepth:10,directMaxDepth:2,directMaxCandidates:1,moderateTokenRiskRatio:.35,highTokenRiskRatio:.7,baseTokensPerSummary:220,includeMessagesTokenMultiplier:1.9,perDepthTokenGrowth:.65,broadTimeRangeTokenMultiplier:1.35,multiHopTokenMultiplier:1.25,multiHopDepthThreshold:3,multiHopCandidateThreshold:5};var BROAD_TIME_RANGE_PATTERNS=[/\b(last|past)\s+(month|months|quarter|quarters|year|years)\b/i,/\b(over|across|throughout)\s+(time|months|quarters|years)\b/i,/\b(timeline|chronology|history|long[-\s]?term)\b/i,/\bbetween\s+[^.]{0,40}\s+and\s+[^.]{0,40}\b/i];var MULTI_HOP_QUERY_PATTERNS=[/\b(root\s+cause|causal\s+chain|chain\s+of\s+events)\b/i,/\b(multi[-\s]?hop|multi[-\s]?step|cross[-\s]?summary)\b/i,/\bhow\s+did\b.+\blead\s+to\b/i];function normalizeDepth(requestedMaxDepth){if(typeof requestedMaxDepth!=="number"||!Number.isFinite(requestedMaxDepth)){return EXPANSION_ROUTING_THRESHOLDS.defaultDepth}const rounded=Math.trunc(requestedMaxDepth);return Math.max(EXPANSION_ROUTING_THRESHOLDS.minDepth,Math.min(EXPANSION_ROUTING_THRESHOLDS.maxDepth,rounded))}function normalizeTokenCap(tokenCap){if(!Number.isFinite(tokenCap)){return Number.MAX_SAFE_INTEGER}return Math.max(1,Math.trunc(tokenCap))}function detectBroadTimeRangeIndicator(query){if(!query){return false}const trimmed=query.trim();if(!trimmed){return false}if(BROAD_TIME_RANGE_PATTERNS.some(pattern=>pattern.test(trimmed))){return true}const years=Array.from(trimmed.matchAll(/\b(?:19|20)\d{2}\b/g),match=>Number(match[0]));if(years.length<2){return false}const earliest=Math.min(...years);const latest=Math.max(...years);return latest-earliest>=2}function detectMultiHopIndicator(input){const normalizedMaxDepth=normalizeDepth(input.requestedMaxDepth);const candidateSummaryCount=Math.max(0,Math.trunc(input.candidateSummaryCount));if(normalizedMaxDepth>=EXPANSION_ROUTING_THRESHOLDS.multiHopDepthThreshold){return true}if(candidateSummaryCount>=EXPANSION_ROUTING_THRESHOLDS.multiHopCandidateThreshold){return true}if(!input.query){return false}const trimmed=input.query.trim();if(!trimmed){return false}return MULTI_HOP_QUERY_PATTERNS.some(pattern=>pattern.test(trimmed))}function estimateExpansionTokens(input){const normalizedMaxDepth=normalizeDepth(input.requestedMaxDepth);const candidateSummaryCount=Math.max(0,Math.trunc(input.candidateSummaryCount));if(candidateSummaryCount===0){return 0}const includeMessagesMultiplier=input.includeMessages?EXPANSION_ROUTING_THRESHOLDS.includeMessagesTokenMultiplier:1;const depthMultiplier=1+(normalizedMaxDepth-1)*EXPANSION_ROUTING_THRESHOLDS.perDepthTokenGrowth;const timeRangeMultiplier=input.broadTimeRangeIndicator?EXPANSION_ROUTING_THRESHOLDS.broadTimeRangeTokenMultiplier:1;const multiHopMultiplier=input.multiHopIndicator?EXPANSION_ROUTING_THRESHOLDS.multiHopTokenMultiplier:1;const perSummaryEstimate=EXPANSION_ROUTING_THRESHOLDS.baseTokensPerSummary*includeMessagesMultiplier*depthMultiplier*timeRangeMultiplier*multiHopMultiplier;return Math.max(0,Math.ceil(perSummaryEstimate*candidateSummaryCount))}function classifyExpansionTokenRisk(input){const estimatedTokens=Math.max(0,Math.trunc(input.estimatedTokens));const tokenCap=normalizeTokenCap(input.tokenCap);const ratio=estimatedTokens/tokenCap;if(ratio>=EXPANSION_ROUTING_THRESHOLDS.highTokenRiskRatio){return{ratio,level:"high"}}if(ratio>=EXPANSION_ROUTING_THRESHOLDS.moderateTokenRiskRatio){return{ratio,level:"moderate"}}return{ratio,level:"low"}}function decideLcmExpansionRouting(input){const normalizedMaxDepth=normalizeDepth(input.requestedMaxDepth);const candidateSummaryCount=Math.max(0,Math.trunc(input.candidateSummaryCount));const tokenCap=normalizeTokenCap(input.tokenCap);const broadTimeRange=detectBroadTimeRangeIndicator(input.query);const multiHopRetrieval=detectMultiHopIndicator({query:input.query,requestedMaxDepth:normalizedMaxDepth,candidateSummaryCount});const estimatedTokens=estimateExpansionTokens({requestedMaxDepth:normalizedMaxDepth,candidateSummaryCount,includeMessages:input.includeMessages,broadTimeRangeIndicator:broadTimeRange,multiHopIndicator:multiHopRetrieval});const tokenRisk=classifyExpansionTokenRisk({estimatedTokens,tokenCap});const directByNoCandidates=candidateSummaryCount===0;const directByLowComplexityProbe=input.intent==="query_probe"&&!directByNoCandidates&&normalizedMaxDepth<=EXPANSION_ROUTING_THRESHOLDS.directMaxDepth&&candidateSummaryCount<=EXPANSION_ROUTING_THRESHOLDS.directMaxCandidates&&tokenRisk.level==="low"&&!broadTimeRange&&!multiHopRetrieval;const delegateByDepth=false;const delegateByCandidateCount=false;const delegateByTokenRisk=tokenRisk.level==="high";const delegateByBroadTimeRangeAndMultiHop=broadTimeRange&&multiHopRetrieval;const shouldDirect=directByNoCandidates||directByLowComplexityProbe;const shouldDelegate=!shouldDirect&&(delegateByTokenRisk||delegateByBroadTimeRangeAndMultiHop);const action=shouldDirect?"answer_directly":shouldDelegate?"delegate_traversal":"expand_shallow";const reasons=[];if(directByNoCandidates){reasons.push("No candidate summary IDs are available.")}if(directByLowComplexityProbe){reasons.push("Query probe is low complexity and below retrieval-risk thresholds.")}if(delegateByTokenRisk){reasons.push(`Estimated token risk ratio ${tokenRisk.ratio.toFixed(2)} meets delegate threshold ${EXPANSION_ROUTING_THRESHOLDS.highTokenRiskRatio.toFixed(2)}.`)}if(delegateByBroadTimeRangeAndMultiHop){reasons.push("Broad time-range request combined with multi-hop retrieval indicators.")}if(action==="expand_shallow"){reasons.push("Complexity is bounded; use direct/shallow expansion.")}return{action,normalizedMaxDepth,candidateSummaryCount,estimatedTokens,tokenCap,tokenRiskRatio:tokenRisk.ratio,tokenRiskLevel:tokenRisk.level,indicators:{broadTimeRange,multiHopRetrieval},triggers:{directByNoCandidates,directByLowComplexityProbe,delegateByDepth,delegateByCandidateCount,delegateByTokenRisk,delegateByBroadTimeRangeAndMultiHop},reasons}}var SNIPPET_MAX_CHARS=200;function truncateSnippet(content,maxChars=SNIPPET_MAX_CHARS){if(content.length<=maxChars){return content}return content.slice(0,maxChars)+"..."}function toExpansionEntry(summaryId,raw){return{summaryId,children:raw.children.map(c=>({summaryId:c.summaryId,kind:c.kind,snippet:truncateSnippet(c.content),tokenCount:c.tokenCount})),messages:raw.messages.map(m=>({messageId:m.messageId,role:m.role,snippet:truncateSnippet(m.content),tokenCount:m.tokenCount}))}}function collectCitedIds(entry){const ids=[entry.summaryId];for(const child of entry.children){ids.push(child.summaryId)}return ids}var ExpansionOrchestrator=class{constructor(retrieval){this.retrieval=retrieval}retrieval;async expand(request){const maxDepth=request.maxDepth??3;const tokenCap=request.tokenCap??Infinity;const includeMessages=request.includeMessages??false;const result={expansions:[],citedIds:[],totalTokens:0,truncated:false};const citedSet=new Set;for(const summaryId of request.summaryIds){if(result.truncated){break}const remainingBudget=tokenCap-result.totalTokens;if(remainingBudget<=0){result.truncated=true;break}const raw=await this.retrieval.expand({summaryId,depth:maxDepth,includeMessages,tokenCap:remainingBudget});const entry=toExpansionEntry(summaryId,raw);result.expansions.push(entry);result.totalTokens+=raw.estimatedTokens;for(const id of collectCitedIds(entry)){citedSet.add(id)}if(raw.truncated){result.truncated=true}}result.citedIds=[...citedSet];return result}async describeAndExpand(input){const grepResult=await this.retrieval.grep({query:input.query,mode:input.mode,scope:"summaries",conversationId:input.conversationId});const summaryIds=[...grepResult.summaries].sort((a,b)=>{const recencyDelta=b.createdAt.getTime()-a.createdAt.getTime();if(recencyDelta!==0){return recencyDelta}const aRank=a.rank??Number.POSITIVE_INFINITY;const bRank=b.rank??Number.POSITIVE_INFINITY;return aRank-bRank}).map(s=>s.summaryId);if(summaryIds.length===0){return{expansions:[],citedIds:[],totalTokens:0,truncated:false}}return this.expand({summaryIds,maxDepth:input.maxDepth,tokenCap:input.tokenCap,includeMessages:false,conversationId:input.conversationId??0})}};function distillForSubagent(result){const lines=[];lines.push(`## Expansion Results (${result.expansions.length} summaries, ${result.totalTokens} total tokens)`);lines.push("");for(const entry of result.expansions){const kind=entry.children.length>0?"condensed":"leaf";const tokenSum=entry.children.reduce((sum,c)=>sum+c.tokenCount,0)+entry.messages.reduce((sum,m)=>sum+m.tokenCount,0);lines.push(`### ${entry.summaryId} (${kind}, ${tokenSum} tokens)`);if(entry.children.length>0){lines.push(`Children: ${entry.children.map(c=>c.summaryId).join(", ")}`)}if(entry.messages.length>0){const msgParts=entry.messages.map(m=>`msg#${m.messageId} (${m.role}, ${m.tokenCount} tokens)`);lines.push(`Messages: ${msgParts.join(", ")}`)}for(const child of entry.children){if(child.snippet){lines.push(`[Snippet: ${truncateSnippet(child.snippet)}]`);break}}lines.push("")}if(result.citedIds.length>0){lines.push(`Cited IDs for follow-up: ${result.citedIds.join(", ")}`)}lines.push(`[Truncated: ${result.truncated?"yes":"no"}]`);return lines.join("\n")}var LcmExpansionSchema=Type.Object({summaryIds:Type.Optional(Type.Array(Type.String(),{description:"Summary IDs to expand (e.g. sum_abc123). Required if query is not provided."})),query:Type.Optional(Type.String({description:"Text query to grep for matching summaries before expanding. If provided, summaryIds is ignored and the top grep results are expanded instead."})),maxDepth:Type.Optional(Type.Number({description:"Max traversal depth per summary (default: 3).",minimum:1,maximum:10})),tokenCap:Type.Optional(Type.Number({description:"Max tokens across the entire expansion result.",minimum:1})),includeMessages:Type.Optional(Type.Boolean({description:"Whether to include raw source messages at leaf level (default: false)."}))});var LcmExpandSchema=Type.Object({summaryIds:Type.Optional(Type.Array(Type.String(),{description:"Summary IDs to expand (sum_xxx format). Required if query is not provided."})),query:Type.Optional(Type.String({description:"Text query to grep for matching summaries before expanding. If provided, summaryIds is ignored and the top grep results are expanded."})),maxDepth:Type.Optional(Type.Number({description:"Max traversal depth per summary (default: 3).",minimum:1})),tokenCap:Type.Optional(Type.Number({description:"Max tokens across the entire expansion result.",minimum:1})),includeMessages:Type.Optional(Type.Boolean({description:"Whether to include raw source messages at leaf level (default: false)."})),conversationId:Type.Optional(Type.Number({description:"Conversation ID to scope the expansion to. If omitted, uses the current session's conversation."})),allConversations:Type.Optional(Type.Boolean({description:"Set true to explicitly allow cross-conversation expansion. Ignored when conversationId is provided."}))});function makeEmptyExpansionResult(){return{expansions:[],citedIds:[],totalTokens:0,truncated:false}}function toDelegatedRunReferences(delegated){if(!delegated){return void 0}const refs=delegated.passes.map(pass=>({pass:pass.pass,status:pass.status,runId:pass.runId,childSessionKey:pass.childSessionKey}));return refs.length>0?refs:void 0}function buildOrchestrationObservability(input){return{decisionPath:{policyAction:input.policy.action,executionPath:input.executionPath},policyReasons:input.policy.reasons,delegatedRunRefs:toDelegatedRunReferences(input.delegated)}}function createLcmExpandTool(input){return{name:"lcm_expand",label:"LCM Expand",description:"Expand compacted conversation summaries from LCM (Lossless Context Management). Traverses the summary DAG to retrieve children and source messages. Use this to drill into previously-compacted context when you need detail that was summarised away. Provide either summaryIds (direct expansion) or query (grep-first, then expand top matches). Returns a compact text payload plus cited IDs in tool output for follow-up.",parameters:LcmExpandSchema,async execute(_toolCallId,params){const lcm=input.lcm??await input.getLcm?.();if(!lcm){throw new Error("LCM engine is unavailable.")}const retrieval=lcm.getRetrieval();const orchestrator=new ExpansionOrchestrator(retrieval);const runtimeAuthManager=getRuntimeExpansionAuthManager();const p=params;const summaryIds=p.summaryIds;const query=typeof p.query==="string"?p.query.trim():void 0;const maxDepth=typeof p.maxDepth==="number"?Math.trunc(p.maxDepth):void 0;const requestedTokenCap=typeof p.tokenCap==="number"?Math.trunc(p.tokenCap):void 0;const tokenCap=typeof requestedTokenCap==="number"&&Number.isFinite(requestedTokenCap)?Math.max(1,requestedTokenCap):void 0;const includeMessages=typeof p.includeMessages==="boolean"?p.includeMessages:false;const sessionKey=(typeof input.sessionKey==="string"?input.sessionKey:input.sessionId)?.trim()??"";if(!input.deps.isSubagentSessionKey(sessionKey)){return jsonResult({error:"lcm_expand is only available in sub-agent sessions. Use lcm_expand_query to ask a focused question against expanded summaries, or lcm_describe/lcm_grep for lighter lookups."})}const isDelegatedSession=input.deps.isSubagentSessionKey(sessionKey);const delegatedGrantId=isDelegatedSession?resolveDelegatedExpansionGrantId(sessionKey)??void 0:void 0;const delegatedGrant=delegatedGrantId!==void 0?runtimeAuthManager.getGrant(delegatedGrantId):null;const authorizedOrchestrator=delegatedGrantId!==void 0?wrapWithAuth(orchestrator,runtimeAuthManager):null;if(isDelegatedSession&&!delegatedGrantId){return jsonResult({error:"Delegated expansion requires a valid grant. This sub-agent session has no propagated expansion grant."})}const conversationScope=await resolveLcmConversationScope({lcm,deps:input.deps,sessionId:input.sessionId,sessionKey:input.sessionKey,params:p});const runExpand=async input2=>{if(!authorizedOrchestrator||!delegatedGrantId){return orchestrator.expand(input2)}return authorizedOrchestrator.expand(delegatedGrantId,input2)};const resolvedConversationId=conversationScope.conversationId??(delegatedGrant?.allowedConversationIds.length===1?delegatedGrant.allowedConversationIds[0]:void 0);if(query){try{if(resolvedConversationId==null){const result2=await orchestrator.describeAndExpand({query,mode:"full_text",conversationId:void 0,maxDepth,tokenCap});const text2=distillForSubagent(result2);const policy2=decideLcmExpansionRouting({intent:"query_probe",query,requestedMaxDepth:maxDepth,candidateSummaryCount:result2.expansions.length,tokenCap:tokenCap??Number.MAX_SAFE_INTEGER,includeMessages:false});return{content:[{type:"text",text:text2}],details:{expansionCount:result2.expansions.length,citedIds:result2.citedIds,totalTokens:result2.totalTokens,truncated:result2.truncated,policy:policy2,executionPath:"direct",observability:buildOrchestrationObservability({policy:policy2,executionPath:"direct"})}}}const grepResult=await retrieval.grep({query,mode:"full_text",scope:"summaries",conversationId:resolvedConversationId});const matchedSummaryIds=grepResult.summaries.map(entry=>entry.summaryId);const policy=decideLcmExpansionRouting({intent:"query_probe",query,requestedMaxDepth:maxDepth,candidateSummaryCount:matchedSummaryIds.length,tokenCap:tokenCap??Number.MAX_SAFE_INTEGER,includeMessages:false});const canDelegate=matchedSummaryIds.length>0&&policy.action==="delegate_traversal"&&!isDelegatedSession&&!!sessionKey;const delegated=canDelegate&&resolvedConversationId!=null?await runDelegatedExpansionLoop({deps:input.deps,requesterSessionKey:sessionKey,conversationId:resolvedConversationId,summaryIds:matchedSummaryIds,maxDepth,tokenCap,includeMessages:false,query}):void 0;if(delegated&&delegated.status==="ok"){return{content:[{type:"text",text:delegated.text}],details:{expansionCount:delegated.citedIds.length,citedIds:delegated.citedIds,totalTokens:delegated.totalTokens,truncated:delegated.truncated,policy,executionPath:"delegated",delegated,observability:buildOrchestrationObservability({policy,executionPath:"delegated",delegated})}}}const executionPath=delegated?"direct_fallback":"direct";const result=matchedSummaryIds.length===0?makeEmptyExpansionResult():await runExpand({summaryIds:matchedSummaryIds,maxDepth,tokenCap,includeMessages:false,conversationId:resolvedConversationId});const text=distillForSubagent(result);return{content:[{type:"text",text}],details:{expansionCount:result.expansions.length,citedIds:result.citedIds,totalTokens:result.totalTokens,truncated:result.truncated,policy,executionPath,delegated:delegated&&delegated.status!=="ok"?{status:delegated.status,error:delegated.error,passes:delegated.passes}:void 0,observability:buildOrchestrationObservability({policy,executionPath,delegated})}}}catch(err){const message=err instanceof Error?err.message:String(err);return jsonResult({error:message})}}if(summaryIds&&summaryIds.length>0){try{if(conversationScope.conversationId!=null){const outOfScope=[];for(const summaryId of summaryIds){const described=await retrieval.describe(summaryId);if(described?.type==="summary"&&described.summary?.conversationId!==conversationScope.conversationId){outOfScope.push(summaryId)}}if(outOfScope.length>0){return jsonResult({error:`Some summaryIds are outside conversation ${conversationScope.conversationId}: `+outOfScope.join(", "),hint:"Use allConversations=true for cross-conversation expansion."})}}const policy=decideLcmExpansionRouting({intent:"explicit_expand",requestedMaxDepth:maxDepth,candidateSummaryCount:summaryIds.length,tokenCap:tokenCap??Number.MAX_SAFE_INTEGER,includeMessages});const normalizedSummaryIds=normalizeSummaryIds(summaryIds);const canDelegate=normalizedSummaryIds.length>0&&policy.action==="delegate_traversal"&&!isDelegatedSession&&!!sessionKey&&resolvedConversationId!=null;const delegated=canDelegate?await runDelegatedExpansionLoop({deps:input.deps,requesterSessionKey:sessionKey,conversationId:resolvedConversationId,summaryIds:normalizedSummaryIds,maxDepth,tokenCap,includeMessages}):void 0;if(delegated&&delegated.status==="ok"){return{content:[{type:"text",text:delegated.text}],details:{expansionCount:delegated.citedIds.length,citedIds:delegated.citedIds,totalTokens:delegated.totalTokens,truncated:delegated.truncated,policy,executionPath:"delegated",delegated,observability:buildOrchestrationObservability({policy,executionPath:"delegated",delegated})}}}const executionPath=delegated?"direct_fallback":"direct";const result=await runExpand({summaryIds:normalizedSummaryIds,maxDepth,tokenCap,includeMessages,conversationId:resolvedConversationId??0});const text=distillForSubagent(result);return{content:[{type:"text",text}],details:{expansionCount:result.expansions.length,citedIds:result.citedIds,totalTokens:result.totalTokens,truncated:result.truncated,policy,executionPath,delegated:delegated&&delegated.status!=="ok"?{status:delegated.status,error:delegated.error,passes:delegated.passes}:void 0,observability:buildOrchestrationObservability({policy,executionPath,delegated})}}}catch(err){const message=err instanceof Error?err.message:String(err);return jsonResult({error:message})}}return jsonResult({error:"Either summaryIds or query must be provided."})}}}var MAX_RESULT_CHARS=4e4;function formatDisplayTime2(value,timezone){if(value==null){return"-"}const date=value instanceof Date?value:new Date(value);if(Number.isNaN(date.getTime())){return"-"}return formatTimestamp(date,timezone)}var LcmGrepSchema=Type.Object({pattern:Type.String({description:'Search pattern. Interpreted as regex when mode is "regex", or as an FTS5 text query when mode is "full_text". In full_text mode, FTS5 defaults to AND matching, so prefer 1-3 distinctive terms or one quoted multi-word phrase instead of padding with synonyms or extra keywords.'}),mode:Type.Optional(Type.String({description:'Search mode: "regex" for regular expression matching, "full_text" for text search. Default: "regex".',enum:["regex","full_text"]})),scope:Type.Optional(Type.String({description:'What to search: "messages" for raw messages, "summaries" for compacted summaries, "both" for all. Default: "both".',enum:["messages","summaries","both"]})),conversationId:Type.Optional(Type.Number({description:"Conversation ID to search within. If omitted, defaults to the current session conversation."})),allConversations:Type.Optional(Type.Boolean({description:"Set true to explicitly search across all conversations. Ignored when conversationId is provided."})),since:Type.Optional(Type.String({description:"Only return matches created at or after this ISO timestamp."})),before:Type.Optional(Type.String({description:"Only return matches created before this ISO timestamp."})),limit:Type.Optional(Type.Number({description:"Maximum number of results to return (default: 50).",minimum:1,maximum:200})),sort:Type.Optional(Type.String({description:'Sort order: "recency" (newest first, default), "relevance" (best FTS5 match first, full_text mode only), or "hybrid" (full_text mode only; balances relevance with recency). Applied before limit is enforced.',enum:["recency","relevance","hybrid"]}))});function truncateSnippet2(content,maxLen=200){const singleLine=content.replace(/\n/g," ").trim();if(singleLine.length<=maxLen){return singleLine}return singleLine.substring(0,maxLen-3)+"..."}function createLcmGrepTool(input){return{name:"lcm_grep",label:"LCM Grep",description:"Search compacted conversation history using regex or full-text search. Searches across messages and/or summaries stored by LCM. Use this to find specific content that may have been compacted away from active context. In full_text mode, queries use FTS5 AND semantics by default, so keep them short and focused; quoted phrases stay intact and optional sort modes can prioritize relevance for older topics. Returns matching snippets with their summary/message IDs for follow-up with lcm_expand or lcm_describe.",parameters:LcmGrepSchema,async execute(_toolCallId,params){const lcm=input.lcm??await input.getLcm?.();if(!lcm){throw new Error("LCM engine is unavailable.")}const retrieval=lcm.getRetrieval();const timezone=lcm.timezone;const p=params;const pattern=p.pattern.trim();const mode=p.mode??"regex";const scope=p.scope??"both";const limit=typeof p.limit==="number"?Math.trunc(p.limit):50;const requestedSort=p.sort??"recency";const effectiveSort=mode==="full_text"?requestedSort:"recency";let since;let before;try{since=parseIsoTimestampParam(p,"since");before=parseIsoTimestampParam(p,"before")}catch(error){return jsonResult({error:error instanceof Error?error.message:"Invalid timestamp filter."})}if(since&&before&&since.getTime()>=before.getTime()){return jsonResult({error:"`since` must be earlier than `before`."})}const conversationScope=await resolveLcmConversationScope({lcm,deps:input.deps,sessionId:input.sessionId,sessionKey:input.sessionKey,params:p});if(!conversationScope.allConversations&&conversationScope.conversationId==null){return jsonResult({error:"No LCM conversation found for this session. Provide conversationId or set allConversations=true."})}const result=await retrieval.grep({query:pattern,mode,scope,conversationId:conversationScope.conversationId,limit,since,before,sort:effectiveSort});const lines=[];lines.push("## LCM Grep Results");lines.push(`**Pattern:** \`${pattern}\``);lines.push(`**Mode:** ${mode} | **Scope:** ${scope} | **Sort:** ${effectiveSort}`);if(conversationScope.allConversations){lines.push("**Conversation scope:** all conversations")}else if(conversationScope.conversationId!=null){lines.push(`**Conversation scope:** ${conversationScope.conversationId}`)}if(since||before){lines.push(`**Time filter:** ${since?`since ${formatDisplayTime2(since,timezone)}`:"since -\u221E"} | ${before?`before ${formatDisplayTime2(before,timezone)}`:"before +\u221E"}`)}lines.push(`**Total matches:** ${result.totalMatches}`);lines.push("");let currentChars=lines.join("\n").length;if(result.messages.length>0){lines.push("### Messages");lines.push("");for(const msg of result.messages){const snippet=truncateSnippet2(msg.snippet);const line=`- [msg#${msg.messageId}] (${msg.role}, ${formatDisplayTime2(msg.createdAt,timezone)}): ${snippet}`;if(currentChars+line.length>MAX_RESULT_CHARS){lines.push("*(truncated \u2014 more results available)*");break}lines.push(line);currentChars+=line.length}lines.push("")}if(result.summaries.length>0){lines.push("### Summaries");lines.push("");for(const sum of result.summaries){const snippet=truncateSnippet2(sum.snippet);const line=`- [${sum.summaryId}] (${sum.kind}, ${formatDisplayTime2(sum.createdAt,timezone)}): ${snippet}`;if(currentChars+line.length>MAX_RESULT_CHARS){lines.push("*(truncated \u2014 more results available)*");break}lines.push(line);currentChars+=line.length}lines.push("")}if(result.totalMatches===0){lines.push("No matches found.")}return{content:[{type:"text",text:lines.join("\n")}],details:{messageCount:result.messages.length,summaryCount:result.summaries.length,totalMatches:result.totalMatches}}}}}import{existsSync,statSync as statSync2}from"node:fs";var package_default={name:"@martian-engineering/lossless-claw",version:"0.9.1",description:"Lossless Context Management plugin for OpenClaw \u2014 DAG-based conversation summarization with incremental compaction",type:"module",main:"dist/index.js",license:"MIT",author:"Josh Lehman <josh@martian.engineering>",keywords:["openclaw","openclaw-plugin","context-management","llm","summarization","conversation-memory","dag"],scripts:{build:'esbuild index.ts --bundle --platform=node --target=node22 --format=esm --outfile=dist/index.js --external:openclaw --external:"@mariozechner/*" --minify-whitespace',changeset:"changeset","release:verify":"npm run build && npm test && npm pack --dry-run",test:"vitest run --dir test","version-packages":"changeset version"},files:["dist/","skills/","openclaw.plugin.json","docs/","README.md","LICENSE"],dependencies:{"@mariozechner/pi-agent-core":"*","@mariozechner/pi-ai":"*","@sinclair/typebox":"0.34.48"},devDependencies:{"@changesets/changelog-github":"^0.6.0","@changesets/cli":"^2.30.0",esbuild:"^0.28.0",typescript:"^5.7.0",vitest:"^3.0.0"},peerDependencies:{openclaw:"*"},publishConfig:{access:"public"},openclaw:{extensions:["./dist/index.js"]},repository:{type:"git",url:"git+https://github.com/Martian-Engineering/lossless-claw.git"},homepage:"https://github.com/Martian-Engineering/lossless-claw#readme",bugs:{url:"https://github.com/Martian-Engineering/lossless-claw/issues"}};var FALLBACK_SUMMARY_MARKER="[LCM fallback summary; truncated for context management]";var TRUNCATED_SUMMARY_PREFIX="[Truncated from ";var TRUNCATED_SUMMARY_WINDOW=40;var FALLBACK_SUMMARY_WINDOW=80;function detectDoctorMarker(content){if(content.startsWith(FALLBACK_SUMMARY_MARKER)){return"old"}const truncatedIndex=content.indexOf(TRUNCATED_SUMMARY_PREFIX);if(truncatedIndex>=0&&content.length-truncatedIndex<TRUNCATED_SUMMARY_WINDOW){return"new"}const fallbackIndex=content.indexOf(FALLBACK_SUMMARY_MARKER);if(fallbackIndex>=0&&content.length-fallbackIndex<FALLBACK_SUMMARY_WINDOW){return"fallback"}return null}function loadDoctorTargets(db,conversationId){const statement=conversationId===void 0?db.prepare(`SELECT
|
|
743
746
|
s.conversation_id,
|
|
744
747
|
s.summary_id,
|
|
745
748
|
s.kind,
|
|
@@ -1050,4 +1053,4 @@ UNION
|
|
|
1050
1053
|
FROM conversations
|
|
1051
1054
|
WHERE session_id = ?
|
|
1052
1055
|
ORDER BY active DESC, created_at DESC
|
|
1053
|
-
LIMIT 1`).get(sessionId);if(!row){return null}return getConversationStatusStats(db,row.conversation_id)}async function getConversationCompactionMaintenanceByConversationId(db,conversationId){return await new CompactionMaintenanceStore(db).getConversationCompactionMaintenance(conversationId)}async function getConversationCompactionTelemetryByConversationId(db,conversationId){return await new CompactionTelemetryStore(db).getConversationCompactionTelemetry(conversationId)}async function resolveCurrentConversation(params){const sessionKey=normalizeIdentity(params.ctx.sessionKey);const sessionId=normalizeIdentity(params.ctx.sessionId);if(sessionKey){const bySessionKey=getConversationStatusBySessionKey(params.db,sessionKey);if(bySessionKey){return{kind:"resolved",source:"session_key",stats:bySessionKey}}if(sessionId){const bySessionId=getConversationStatusBySessionId(params.db,sessionId);if(bySessionId){if(!bySessionId.sessionKey||bySessionId.sessionKey===sessionKey){return{kind:"resolved",source:"session_key_via_session_id",stats:bySessionId}}return{kind:"unavailable",reason:`Active session key ${formatCommand(sessionKey)} is not stored in LCM yet. Session id fallback found conversation #${formatNumber(bySessionId.conversationId)}, but it is bound to ${formatCommand(bySessionId.sessionKey)}, so Global stats are safer.`}}}return{kind:"unavailable",reason:sessionId?`No LCM conversation is stored yet for active session key ${formatCommand(sessionKey)} or active session id ${formatCommand(sessionId)}.`:`No LCM conversation is stored yet for active session key ${formatCommand(sessionKey)}.`}}if(sessionId){const bySessionId=getConversationStatusBySessionId(params.db,sessionId);if(bySessionId){return{kind:"resolved",source:"session_id",stats:bySessionId}}return{kind:"unavailable",reason:`OpenClaw did not expose an active session key here. Tried active session id ${formatCommand(sessionId)}, but no stored LCM conversation matched it.`}}return{kind:"unavailable",reason:"OpenClaw did not expose an active session key or session id here, so only GLOBAL stats are available."}}async function resolveRotateSessionId(params){const directSessionId=normalizeIdentity(params.ctx.sessionId);if(directSessionId){return directSessionId}const sessionKey=normalizeIdentity(params.ctx.sessionKey);if(sessionKey){const runtimeSessionId=normalizeIdentity(await params.deps.resolveSessionIdFromSessionKey(sessionKey));if(runtimeSessionId){return runtimeSessionId}}return normalizeIdentity(params.current.stats.sessionId)}function resolvePluginEnabled(config){const root=asRecord2(config);const plugins=asRecord2(root?.plugins);const entries=asRecord2(plugins?.entries);const entry=asRecord2(entries?.["lossless-claw"]);if(typeof entry?.enabled==="boolean"){return entry.enabled}return true}function resolveContextEngineSlot(config){const root=asRecord2(config);const plugins=asRecord2(root?.plugins);const slots=asRecord2(plugins?.slots);return typeof slots?.contextEngine==="string"?slots.contextEngine.trim():""}function resolvePluginSelected(config){const slot=resolveContextEngineSlot(config);return slot===""||slot==="lossless-claw"||slot==="default"}function resolveDbSizeLabel(dbPath){const trimmed=dbPath.trim();if(!trimmed||trimmed===":memory:"||trimmed.startsWith("file::memory:")){return"in-memory"}try{return formatBytes(statSync2(trimmed).size)}catch{return"missing"}}function buildHelpText(error){const lines=[...error?[`\u26A0\uFE0F ${error}`,""]:[],...buildHeaderLines(),"",buildSection("\u{1F4D8} Commands",[buildStatLine(formatCommand(VISIBLE_COMMAND),"Show compact status output."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} status`),"Show plugin, Global, current-conversation, and compaction-maintenance status."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} backup`),"Create a timestamped backup of the current LCM database."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} rotate`),"Compact the current session transcript while preserving the same LCM conversation and live session identity."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} doctor`),"Scan for broken or truncated summaries."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} doctor clean`),"Report global high-confidence junk candidates without deleting anything."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} doctor clean apply`),"Delete approved high-confidence cleaner matches after creating a DB backup."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} doctor apply`),"Repair broken summaries in the current conversation.")]),"",buildSection("\u{1F9ED} Notes",[buildStatLine("subcommands",`Discover them with ${formatCommand(`${VISIBLE_COMMAND} help`)}.`),buildStatLine("alias",`${formatCommand(HIDDEN_ALIAS)} is accepted as a shorter alias.`),buildStatLine("current conversation","Uses the active LCM session when the host exposes session identity."),buildStatLine("`/new`","Prunes context for the current LCM conversation. It does not split storage."),buildStatLine("`/reset`","Resets OpenClaw session flow. Use rotate when you only want transcript compaction.")])];return lines.join("\n")}function buildDoctorCleanerExampleLine(params){const sessionKey=params.sessionKey?formatCommand(truncateMiddle(params.sessionKey,44)):"missing";const preview=params.firstMessagePreview?` \xB7 first: ${JSON.stringify(params.firstMessagePreview)}`:"";return`conv ${formatNumber(params.conversationId)} \xB7 session key ${sessionKey} \xB7 messages ${formatNumber(params.messageCount)}${preview}`}async function buildStatusText(params){const status=getLcmStatusStats(params.db);const doctor=getDoctorSummaryStats(params.db);const enabled=resolvePluginEnabled(params.ctx.config);const selected=resolvePluginSelected(params.ctx.config);const slot=resolveContextEngineSlot(params.ctx.config);const dbSize=resolveDbSizeLabel(params.config.databasePath);const current=await resolveCurrentConversation({ctx:params.ctx,db:params.db});const lines=[...buildHeaderLines(),"",buildSection("\u{1F9E9} Plugin",[buildStatLine("enabled",formatBoolean(enabled)),buildStatLine("selected",`${formatBoolean(selected)}${slot?` (slot=${slot})`:" (slot=unset)"}`),buildStatLine("db path",params.config.databasePath),buildStatLine("db size",dbSize)]),"",buildSection("\u{1F310} Global",[buildStatLine("conversations",formatNumber(status.conversationCount)),buildStatLine("summaries",`${formatNumber(status.summaryCount)} (${formatNumber(status.leafSummaryCount)} leaf, ${formatNumber(status.condensedSummaryCount)} condensed)`),buildStatLine("stored summary tokens",formatNumber(status.storedSummaryTokens)),buildStatLine("summarized source tokens",formatNumber(status.summarizedSourceTokens))]),""];if(current.kind==="resolved"){const conversationDoctor=doctor.byConversation.get(current.stats.conversationId)??{total:0,old:0,truncated:0,fallback:0};const maintenance=await getConversationCompactionMaintenanceByConversationId(params.db,current.stats.conversationId);const telemetry=await getConversationCompactionTelemetryByConversationId(params.db,current.stats.conversationId);const formatMaintenanceTime=value=>value?formatTimestamp(value,params.config.timezone):"never";lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",current.stats.sessionKey?formatCommand(truncateMiddle(current.stats.sessionKey,44)):"missing"),buildStatLine("messages",formatNumber(current.stats.messageCount)),buildStatLine("summaries",`${formatNumber(current.stats.summaryCount)} (${formatNumber(current.stats.leafSummaryCount)} leaf, ${formatNumber(current.stats.condensedSummaryCount)} condensed)`),buildStatLine("stored summary tokens",formatNumber(current.stats.storedSummaryTokens)),buildStatLine("summarized source tokens",formatNumber(current.stats.summarizedSourceTokens)),buildStatLine("tokens in context",formatNumber(current.stats.contextTokenCount)),buildStatLine("compression ratio",formatCompressionRatio(current.stats.contextTokenCount,current.stats.compressedTokenCount)),buildStatLine("doctor",conversationDoctor.total>0?`${formatNumber(conversationDoctor.total)} issue(s) in this conversation`:"clean")]));lines.push("",buildSection("\u{1F6E0}\uFE0F Maintenance",[buildStatLine("state",maintenance?.pending?"pending":maintenance?.running?"running":"idle"),buildStatLine("requested at",formatMaintenanceTime(maintenance?.requestedAt??null)),buildStatLine("reason",maintenance?.reason??"none"),buildStatLine("last started",formatMaintenanceTime(maintenance?.lastStartedAt??null)),buildStatLine("last finished",formatMaintenanceTime(maintenance?.lastFinishedAt??null)),buildStatLine("last failure",maintenance?.lastFailureSummary??"none"),buildStatLine("requested token budget",maintenance?.tokenBudget!=null?formatNumber(maintenance.tokenBudget):"unknown"),buildStatLine("observed token count",maintenance?.currentTokenCount!=null?formatNumber(maintenance.currentTokenCount):"unknown"),buildStatLine("last api call",formatMaintenanceTime(telemetry?.lastApiCallAt??null)),buildStatLine("last cache touch",formatMaintenanceTime(telemetry?.lastCacheTouchAt??null)),buildStatLine("cache retention",telemetry?.retention??"unknown"),buildStatLine("cache state",telemetry?.cacheState??"unknown"),buildStatLine("provider/model",[telemetry?.provider,telemetry?.model].filter(Boolean).join(" / ")||"unknown")]))}else{lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason),buildStatLine("fallback","Showing Global stats only.")]))}return lines.join("\n")}async function buildDoctorText(params){const current=await resolveCurrentConversation(params);if(current.kind==="unavailable"){return[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor","",buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason),buildStatLine("fallback","Doctor is conversation-scoped, so no global scan ran.")])].join("\n")}const stats=getDoctorSummaryStats(params.db,current.stats.conversationId);const lines=[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor","",buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",current.stats.sessionKey?formatCommand(truncateMiddle(current.stats.sessionKey,44)):"missing"),buildStatLine("scope","this conversation only")]),"",buildSection("\u{1F9EA} Scan",[buildStatLine("detected summaries",formatNumber(stats.total)),buildStatLine("old-marker summaries",formatNumber(stats.old)),buildStatLine("truncated-marker summaries",formatNumber(stats.truncated)),buildStatLine("fallback-marker summaries",formatNumber(stats.fallback)),buildStatLine("result",stats.total===0?"clean":"issues found")])];if(stats.total>0){const summaryList=stats.candidates.slice().sort((left,right)=>left.summaryId.localeCompare(right.summaryId)).map(candidate=>`${candidate.summaryId} (${candidate.markerKind})`).join(", ");lines.push("",buildSection("\u{1F9F7} Affected summaries",[summaryList]),"",buildSection("\u{1F6E0}\uFE0F Next step",[`${formatCommand(`${VISIBLE_COMMAND} doctor apply`)} repairs these in place for the current conversation.`]))}return lines.join("\n")}async function buildDoctorCleanersText(params){const scan=scanDoctorCleaners(params.db);const lines=[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor Clean","",buildSection("\u{1F310} Global scan",[buildStatLine("filters",formatNumber(scan.filters.length)),buildStatLine("matched conversations",formatNumber(scan.totalDistinctConversations)),buildStatLine("matched messages",formatNumber(scan.totalDistinctMessages)),buildStatLine("mode","read-only diagnostics")])];if(scan.filters.every(filter=>filter.conversationCount===0)){lines.push("",buildSection("\u2705 Result",["No high-confidence cleaner candidates detected."]));return lines.join("\n")}for(const filter of scan.filters){lines.push("",buildSection(`\u{1F9F9} ${filter.label}`,[buildStatLine("filter id",formatCommand(filter.id)),buildStatLine("description",filter.description),buildStatLine("matched conversations",formatNumber(filter.conversationCount)),buildStatLine("matched messages",formatNumber(filter.messageCount))]));if(filter.examples.length>0){lines.push("",buildSection("\u{1F9F7} Examples",filter.examples.map(example=>buildDoctorCleanerExampleLine(example))))}}lines.push("",buildSection("\u{1F6E0}\uFE0F Next step",[`Review the examples, then run ${formatCommand(`${VISIBLE_COMMAND} doctor clean apply`)} to delete approved matches after Lossless Claw creates a backup.`]));return lines.join("\n")}function runQuickCheck(db){const rows=db.prepare(`PRAGMA quick_check`).all();const results=rows.map(row=>row.quick_check).filter(value=>typeof value==="string"&&value.length>0);if(results.length===0){return"unknown"}if(results.length===1&&results[0]==="ok"){return"ok"}return results.join("; ")}function isPassingQuickCheck(result){return result==="ok"}function getLcmBackupUnavailableReason(databasePath){const trimmed=databasePath.trim();if(!trimmed||trimmed===":memory:"||trimmed.startsWith("file::memory:")){return"Backup requires a file-backed SQLite database."}return null}async function buildBackupText(params){const lines=[...buildHeaderLines(),"","\u{1F4BE} Lossless Claw Backup",""];const unavailableReason=getLcmBackupUnavailableReason(params.config.databasePath);if(unavailableReason){lines.push(buildSection("\u{1F6E0}\uFE0F Backup",[buildStatLine("status","unavailable"),buildStatLine("reason",unavailableReason)]));return lines.join("\n")}let backupPath;try{backupPath=createLcmDatabaseBackup(params.db,{databasePath:params.config.databasePath,label:"backup"})}catch(error){lines.push(buildSection("\u{1F6E0}\uFE0F Backup",[buildStatLine("status","failed"),buildStatLine("reason",formatFailureReason(error))]));return lines.join("\n")}if(!backupPath){lines.push(buildSection("\u{1F6E0}\uFE0F Backup",[buildStatLine("status","unavailable"),buildStatLine("reason","Lossless Claw could not determine a backup path.")]));return lines.join("\n")}lines.push(buildSection("\u{1F6E0}\uFE0F Backup",[buildStatLine("status","created"),buildStatLine("db path",params.config.databasePath),buildStatLine("backup path",backupPath)]));return lines.join("\n")}async function buildRotateText(params){const lines=[...buildHeaderLines(),"","\u{1FA93} Lossless Claw Rotate",""];const sessionKey=normalizeIdentity(params.ctx.sessionKey);if(!sessionKey){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason","OpenClaw must expose the active session key for Lossless Claw to rotate storage safely.")]));return lines.join("\n")}const current=await resolveCurrentConversation({ctx:params.ctx,db:params.db});if(current.kind==="unavailable"){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason)]));return lines.join("\n")}if(!params.deps||!params.getLcm){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason","Rotate requires the runtime-backed LCM engine to be available.")]));return lines.join("\n")}const sessionId=await resolveRotateSessionId({ctx:params.ctx,deps:params.deps,current});if(!sessionId){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(sessionKey,44))),buildStatLine("messages",formatNumber(current.stats.messageCount))]),"",buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason","Lossless Claw resolved the active conversation, but OpenClaw did not expose or resolve a runtime session id, so rotate cannot locate the live transcript safely.")]));return lines.join("\n")}const transcriptPath=await params.deps.resolveSessionTranscriptFile({sessionId,sessionKey});if(!transcriptPath||!existsSync(transcriptPath)){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason","Lossless Claw could not resolve the active session transcript path, so it cannot rotate the transcript safely.")]));return lines.join("\n")}const unavailableReason=getLcmBackupUnavailableReason(params.config.databasePath);if(unavailableReason){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason",unavailableReason)]));return lines.join("\n")}let result;try{result=await(await params.getLcm()).rotateSessionStorageWithBackup({sessionId,sessionKey,sessionFile:transcriptPath,lockTimeoutMs:ROTATE_DATABASE_LOCK_TIMEOUT_MS})}catch(error){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","failed"),buildStatLine("reason",formatFailureReason(error))]));return lines.join("\n")}lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(result.currentConversationId??current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(sessionKey,44))),buildStatLine("messages",formatNumber(result.currentMessageCount??current.stats.messageCount))]),"");if(result.kind==="backup_failed"){lines.push(buildSection("\u{1F4BE} Backup",[buildStatLine("status","failed"),buildStatLine("reason",result.reason)]));return lines.join("\n")}if(result.kind==="unavailable"&&!result.backupPath){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason",result.reason)]));return lines.join("\n")}lines.push(buildSection("\u{1F4BE} Backup",[buildStatLine("status","replaced latest"),buildStatLine("backup path",result.backupPath)]),"");if(result.kind==="rotate_failed"){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","failed"),buildStatLine("reason",result.reason)]));return lines.join("\n")}if(result.kind==="unavailable"){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason",result.reason)]));return lines.join("\n")}lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","rotated"),buildStatLine("preserved tail messages",formatNumber(result.preservedTailMessageCount)),buildStatLine("checkpoint bytes",formatNumber(result.checkpointSize)),buildStatLine("bytes removed",formatNumber(result.bytesRemoved)),buildStatLine("transcript",transcriptPath),buildStatLine("mode","preserved current conversation and rotated transcript tail")]),"",buildSection("\u{1F9ED} Notes",["Current LCM conversation, summaries, and context items remain in place.",`${formatCommand("/new")} still prunes context only, and ${formatCommand("/reset")} still resets OpenClaw session flow.`]));return lines.join("\n")}async function buildDoctorCleanersApplyText(params){const filterIds=params.filterId?[params.filterId]:void 0;const unavailableReason=getDoctorCleanerApplyUnavailableReason(params.config.databasePath);const lines=[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor Clean Apply","",buildSection("\u{1F310} Cleaner scope",[buildStatLine("filters",filterIds&&filterIds.length>0?filterIds.map(filter=>formatCommand(filter)).join(", "):"all approved cleaner filters"),buildStatLine("vacuum requested",formatBoolean(params.vacuum))]),""];if(unavailableReason){lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("status","unavailable"),buildStatLine("reason",unavailableReason)]));return lines.join("\n")}const before=scanDoctorCleaners(params.db,filterIds);lines.splice(lines.length-1,0,buildSection("\u{1F4CA} Current matches",[buildStatLine("matched conversations before apply",formatNumber(before.totalDistinctConversations)),buildStatLine("matched messages before apply",formatNumber(before.totalDistinctMessages))]),"");if(before.totalDistinctConversations===0){lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("status","completed"),buildStatLine("backup path","skipped (no matches)"),buildStatLine("deleted conversations","0"),buildStatLine("deleted messages","0"),buildStatLine("vacuumed","no"),buildStatLine("quick_check","not run (no writes)"),buildStatLine("result","clean; no deletes ran")]));return lines.join("\n")}let result;try{result=applyDoctorCleaners(params.db,{databasePath:params.config.databasePath,filterIds,vacuum:params.vacuum})}catch(error){lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("status","failed"),buildStatLine("reason",error instanceof Error?error.message:"unknown cleaner apply failure")]));return lines.join("\n")}if(result.kind==="unavailable"){lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("status","unavailable"),buildStatLine("reason",result.reason)]));return lines.join("\n")}const quickCheck=runQuickCheck(params.db);const quickCheckPassed=isPassingQuickCheck(quickCheck);lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("status",quickCheckPassed?"completed":"warning"),buildStatLine("backup path",result.backupPath),buildStatLine("deleted conversations",formatNumber(result.deletedConversations)),buildStatLine("deleted messages",formatNumber(result.deletedMessages)),buildStatLine("vacuumed",formatBoolean(result.vacuumed)),buildStatLine("quick_check",quickCheck),buildStatLine("result",quickCheckPassed?result.deletedConversations>0?`removed ${formatNumber(result.deletedConversations)} conversation(s)`:"clean; no deletes ran":"writes committed, but SQLite integrity verification reported problems; inspect the database or restore from the backup before continuing")]));return lines.join("\n")}async function buildDoctorApplyText(params){const current=await resolveCurrentConversation(params);if(current.kind==="unavailable"){return[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor Apply","",buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason),buildStatLine("fallback","Doctor apply is conversation-scoped, so no global repair ran.")])].join("\n")}const stats=getDoctorSummaryStats(params.db,current.stats.conversationId);let result;try{result=await applyScopedDoctorRepair({db:params.db,config:params.config,conversationId:current.stats.conversationId,deps:params.deps,summarize:params.summarize,runtimeConfig:params.ctx.config})}catch(error){return[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor Apply","",buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",current.stats.sessionKey?formatCommand(truncateMiddle(current.stats.sessionKey,44)):"missing"),buildStatLine("scope","this conversation only")]),"",buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("mode","in-place summary rewrite"),buildStatLine("status","failed"),buildStatLine("reason",error instanceof Error?error.message:"unknown repair failure")])].join("\n")}const lines=[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor Apply","",buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",current.stats.sessionKey?formatCommand(truncateMiddle(current.stats.sessionKey,44)):"missing"),buildStatLine("scope","this conversation only")]),""];if(result.kind==="unavailable"){lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("mode","in-place summary rewrite"),buildStatLine("status","unavailable"),buildStatLine("reason",result.reason)]));return lines.join("\n")}lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("mode","in-place summary rewrite"),buildStatLine("detected summaries",formatNumber(stats.total)),buildStatLine("old-marker summaries",formatNumber(stats.old)),buildStatLine("truncated-marker summaries",formatNumber(stats.truncated)),buildStatLine("fallback-marker summaries",formatNumber(stats.fallback)),buildStatLine("repaired summaries",formatNumber(result.repaired)),buildStatLine("unchanged summaries",formatNumber(result.unchanged)),buildStatLine("skipped summaries",formatNumber(result.skipped.length)),buildStatLine("result",stats.total===0?"clean; no writes ran":result.repaired>0?`repaired ${formatNumber(result.repaired)} summary(s) in place`:"no repairs applied")]));if(result.repairedSummaryIds.length>0){lines.push("",buildSection("\u{1F9F7} Repaired summaries",[result.repairedSummaryIds.join(", ")]))}if(result.skipped.length>0){lines.push("",buildSection("\u26A0\uFE0F Deferred",result.skipped.map(item=>`${item.summaryId}: ${item.reason}`)))}return lines.join("\n")}function createLcmCommand(params){const getDb=async()=>typeof params.db==="function"?await params.db():params.db;return{name:"lcm",nativeNames:{default:"lossless"},nativeProgressMessages:{telegram:"Lossless Claw is working..."},description:"Show Lossless Claw health, create DB backups, compact the current session transcript while preserving LCM context, inspect high-confidence junk candidates, and run scoped doctor actions.",acceptsArgs:true,handler:async ctx=>{const parsed=parseLcmCommand(ctx.args);switch(parsed.kind){case"status":return{text:await buildStatusText({ctx,db:await getDb(),config:params.config})};case"backup":return{text:await buildBackupText({db:await getDb(),config:params.config})};case"rotate":return{text:await buildRotateText({ctx,db:await getDb(),config:params.config,deps:params.deps,getLcm:params.getLcm})};case"doctor":return parsed.apply?{text:await buildDoctorApplyText({ctx,db:await getDb(),config:params.config,deps:params.deps,summarize:params.summarize})}:{text:await buildDoctorText({ctx,db:await getDb()})};case"doctor_cleaners":return parsed.apply?{text:await buildDoctorCleanersApplyText({db:await getDb(),config:params.config,filterId:parsed.filterId,vacuum:parsed.vacuum})}:{text:await buildDoctorCleanersText({db:await getDb()})};case"help":return{text:buildHelpText(parsed.error)}}}}}function parseAgentSessionKey(sessionKey){const value=sessionKey.trim();if(!value.startsWith("agent:")){return null}const parts=value.split(":");if(parts.length<3){return null}const agentId=parts[1]?.trim();const suffix=parts.slice(2).join(":").trim();if(!agentId||!suffix){return null}return{agentId,suffix}}function normalizeAgentId(agentId){const normalized=(agentId??"").trim();return normalized.length>0?normalized:"main"}var MODEL_AUTH_PR_URL="https://github.com/openclaw/openclaw/pull/41090";var MODEL_AUTH_MERGE_COMMIT="4790e40";var MODEL_AUTH_REQUIRED_RELEASE="the first OpenClaw release after 2026.3.8";var PROVIDER_API_RESOLUTION_ERROR_PREFIX="[lcm] unable to resolve API family for provider ";var AUTH_ERROR_TEXT_PATTERN2=/\b401\b|unauthorized|unauthorised|invalid[_ -]?token|invalid[_ -]?api[_ -]?key|authentication failed|authorization failed|missing scope|insufficient scope|model\.request\b/i;var AUTH_ERROR_STATUS_KEYS2=["status","statusCode","status_code"];var AUTH_ERROR_NESTED_KEYS2=["error","response","cause","details","data","body"];var LOSSLESS_RECALL_POLICY_PROMPT=["## Lossless Recall Policy","","The lossless-claw plugin is active.","","For compacted conversation history, these instructions supersede generic memory-recall guidance. Prefer lossless-claw recall tools first when answering questions about prior conversation content, decisions made in the conversation, or details that may have been compacted.","","**Conflict handling:** If newer evidence conflicts with an older summary or recollection, prefer the newer evidence. Do not trust a stale summary over fresher contradictory information.","","**Contradictions/uncertainty:** If facts seem contradictory or uncertain, verify with lossless-claw recall tools before answering instead of trusting the summary at face value.","","**Tool escalation:**","Recall order for compacted conversation history:","1. `lcm_grep` \u2014 search by regex or full-text across messages and summaries","2. `lcm_describe` \u2014 inspect a specific summary (cheap, no sub-agent)","3. `lcm_expand_query` \u2014 deep recall: spawns bounded sub-agent, expands DAG, and returns answer plus cited summary IDs in tool output for follow-up (~120s, don't ration it)","","**`lcm_grep` routing guidance:**",'- Prefer `mode: "full_text"` for keyword or topical recall; keep `mode: "regex"` for literal patterns.',"- Full-text queries use FTS5 semantics, and FTS5 defaults to AND matching, so extra terms make matching stricter rather than broader.","- Prefer 1-3 distinctive full-text terms or one quoted phrase. Do not pad queries with synonyms or extra keywords.",'- Wrap exact multi-word phrases in quotes, for example `"error handling"`.','- Keep the default `sort: "recency"` for "what just happened?" lookups.','- Use `sort: "relevance"` when hunting for the best older match on a topic.','- Use `sort: "hybrid"` when relevance matters but newer context should still get a boost.',"","**`lcm_expand_query` usage** \u2014 two patterns (always requires `prompt`):",'- With IDs: `lcm_expand_query(summaryIds: ["sum_xxx"], prompt: "What config changes were discussed?")`','- With search: `lcm_expand_query(query: "database migration", prompt: "What strategy was decided?")`',"- `query` uses the same FTS5 full-text search path as `lcm_grep`, so the same query-construction rules apply.","- `query` is for matching candidate summaries; `prompt` is the natural-language question or task to answer after expansion.","- FTS5 defaults to AND matching, so more query terms narrow results instead of broadening them.","- For `query`, use 1-3 distinctive terms or a quoted phrase. Do not stuff synonyms or extra keywords into it.","**Scope selection rule:**","- Start with the current conversation scope.","- If the in-context summaries already look relevant to the user's question, prefer `lcm_grep` or `lcm_expand_query` without `allConversations`.","- Use `allConversations: true` only when the current summaries do not appear sufficient, the question seems outside the current conversation, or the user is explicitly asking about work across sessions.","- For global discovery, prefer `lcm_grep(..., allConversations: true)` first.","- If global matches are found and the user needs one synthesized answer, use `lcm_expand_query(..., allConversations: true)`; this is bounded synthesis, not exhaustive expansion.","- If you already know the exact target conversation, prefer explicit `conversationId` instead of `allConversations`.","- Optional: `maxTokens` (default 2000), `conversationId`, `allConversations: true`","- Keep raw summary IDs out of normal user-facing prose unless the user explicitly asks for sources or IDs.","","These precedence rules apply only to compacted conversation history. Lossless-claw does not supersede memory tools globally.","","If a summary conflicts with newer evidence, prefer the newer evidence. Do not guess exact commands, SHAs, paths, timestamps, config values, or causal claims from compacted summaries when expansion is needed."].join("\n");function snapshotPluginEnv(env=process.env){return{lcmSummaryModel:env.LCM_SUMMARY_MODEL?.trim()??"",lcmSummaryProvider:env.LCM_SUMMARY_PROVIDER?.trim()??"",pluginSummaryModel:"",pluginSummaryProvider:"",openclawProvider:env.OPENCLAW_PROVIDER?.trim()??"",openclawDefaultModel:"",agentDir:env.OPENCLAW_AGENT_DIR?.trim()||env.PI_CODING_AGENT_DIR?.trim()||"",home:env.HOME?.trim()??"",stateDir:resolveOpenclawStateDir(env)}}function toPluginConfig(value){return value&&typeof value==="object"&&!Array.isArray(value)?value:void 0}function resolvePluginConfig(api){const directPluginConfig=toPluginConfig(api.pluginConfig);if(directPluginConfig&&Object.keys(directPluginConfig).length>0){return directPluginConfig}const rootConfig=toPluginConfig(api.config);const plugins=toPluginConfig(rootConfig?.plugins);const entries=toPluginConfig(plugins?.entries);const pluginEntry=toPluginConfig(entries?.["lossless-claw"]);return toPluginConfig(pluginEntry?.config)}function truncateErrorMessage(message,maxChars=240){return message.length<=maxChars?message:`${message.slice(0,maxChars)}...`}function collectErrorText(value,out,depth=0){if(depth>=4){return}if(typeof value==="string"){const trimmed=value.trim();if(trimmed){out.push(trimmed)}return}if(Array.isArray(value)){for(const entry of value.slice(0,8)){collectErrorText(entry,out,depth+1)}return}if(!isRecord2(value)){return}for(const entry of Object.values(value).slice(0,12)){collectErrorText(entry,out,depth+1)}}function extractErrorStatusCode(value,depth=0){if(depth>=4||!isRecord2(value)){return void 0}for(const key of AUTH_ERROR_STATUS_KEYS2){const candidate=value[key];if(typeof candidate==="number"&&Number.isFinite(candidate)){return Math.trunc(candidate)}if(typeof candidate==="string"){const parsed=Number.parseInt(candidate,10);if(Number.isFinite(parsed)){return parsed}}}for(const key of AUTH_ERROR_NESTED_KEYS2){const nested=value[key];const statusCode=extractErrorStatusCode(nested,depth+1);if(statusCode!==void 0){return statusCode}}return void 0}function detectProviderAuthError(error){const statusCode=extractErrorStatusCode(error);const textParts=[];collectErrorText(error,textParts);const normalizedMessage=textParts.join(" ").replace(/\s+/g," ").trim();if(statusCode!==401&&!AUTH_ERROR_TEXT_PATTERN2.test(normalizedMessage)){return void 0}const directCode=isRecord2(error)&&typeof error.code==="string"&&error.code.trim()?error.code.trim():isRecord2(error)&&isRecord2(error.error)&&typeof error.error.code==="string"&&error.error.code.trim()?error.error.code.trim():void 0;return{kind:"provider_auth",...statusCode!==void 0?{statusCode}:{},...directCode?{code:directCode}:{},...normalizedMessage?{message:truncateErrorMessage(normalizedMessage)}:{}}}function readDefaultModelFromConfig(config){if(!config||typeof config!=="object"){return""}const model=config.agents?.defaults?.model;if(typeof model==="string"){return model.trim()}const primary=model?.primary;return typeof primary==="string"?primary.trim():""}function readCompactionModelFromConfig(config){if(!config||typeof config!=="object"){return""}const compaction=config.agents?.defaults?.compaction;const model=compaction?.model;if(typeof model==="string"){return model.trim()}const primary=model?.primary;return typeof primary==="string"?primary.trim():""}function formatProviderModel(params){return`${params.provider}/${params.model}`}function buildCompactionModelLog(params){const envSummaryModel=process.env.LCM_SUMMARY_MODEL?.trim()??"";const envSummaryProvider=process.env.LCM_SUMMARY_PROVIDER?.trim()??"";const pluginSummaryModel=params.config.summaryModel.trim();const pluginSummaryProvider=params.config.summaryProvider.trim();const compactionModelRef=readCompactionModelFromConfig(params.openClawConfig);const defaultModelRef=readDefaultModelFromConfig(params.openClawConfig);const selected=envSummaryModel?{raw:envSummaryModel,source:"override"}:pluginSummaryModel?{raw:pluginSummaryModel,source:"override"}:compactionModelRef?{raw:compactionModelRef,source:"override"}:defaultModelRef?{raw:defaultModelRef,source:"default"}:void 0;const usingOverride=selected?.source==="override"||Boolean(envSummaryProvider||pluginSummaryProvider);const raw=selected?.raw.trim()??"";if(!raw){return"[lcm] Compaction summarization model: (unconfigured)"}if(raw.includes("/")){const[provider2,...rest]=raw.split("/");const model=rest.join("/").trim();if(provider2&&model){return`[lcm] Compaction summarization model: ${formatProviderModel({provider:provider2.trim(),model})} (${usingOverride?"override":"default"})`}}const provider=(envSummaryProvider||pluginSummaryProvider||params.defaultProvider||"openai").trim();return`[lcm] Compaction summarization model: ${formatProviderModel({provider,model:raw})} (${usingOverride?"override":"default"})`}function resolveApiKey(provider,readEnv){const keyMap={openai:["OPENAI_API_KEY"],anthropic:["ANTHROPIC_API_KEY"],google:["GOOGLE_API_KEY","GEMINI_API_KEY"],groq:["GROQ_API_KEY"],xai:["XAI_API_KEY"],mistral:["MISTRAL_API_KEY"],together:["TOGETHER_API_KEY"],openrouter:["OPENROUTER_API_KEY"],"github-copilot":["GITHUB_COPILOT_API_KEY","GITHUB_TOKEN"]};const providerKey=provider.trim().toLowerCase();const keys=keyMap[providerKey]??[];const normalizedProviderEnv=`${providerKey.replace(/[^a-z0-9]/g,"_").toUpperCase()}_API_KEY`;keys.push(normalizedProviderEnv);for(const key of keys){const value=readEnv(key)?.trim();if(value){return value}}return void 0}function isRecord2(value){return!!value&&typeof value==="object"&&!Array.isArray(value)}function normalizeProviderId2(provider){return provider.trim().toLowerCase()}function inferApiFromProvider(provider){const normalized=normalizeProviderId2(provider);const map={anthropic:"anthropic-messages",openai:"openai-responses","openai-codex":"openai-codex-responses","github-copilot":"openai-codex-responses",google:"google-generative-ai","google-gemini-cli":"google-gemini-cli","google-antigravity":"google-gemini-cli","google-vertex":"google-vertex","amazon-bedrock":"bedrock-converse-stream"};return map[normalized]}function shouldOmitTemperatureForApi(api){return(api??"").trim().toLowerCase()==="openai-codex-responses"}function buildCompleteSimpleOptions(params){const options={apiKey:params.apiKey,maxTokens:params.maxTokens};if(typeof params.temperature==="number"&&Number.isFinite(params.temperature)&&!shouldOmitTemperatureForApi(params.api)){options.temperature=params.temperature}if(typeof params.reasoning==="string"&¶ms.reasoning.trim()){options.reasoning=params.reasoning.trim()}return options}function resolveEffectiveReasoning(params){if(typeof params.reasoning==="string"&¶ms.reasoning.trim()){return params.reasoning.trim()}if(params.modelSupportsReasoning===true&&typeof params.reasoningIfSupported==="string"&¶ms.reasoningIfSupported.trim()){return params.reasoningIfSupported.trim()}return void 0}function findProviderConfigValue(map,provider){if(!map){return void 0}if(map[provider]!==void 0){return map[provider]}const normalizedProvider=normalizeProviderId2(provider);for(const[key,value]of Object.entries(map)){if(normalizeProviderId2(key)===normalizedProvider){return value}}return void 0}function resolveProviderApiFromRuntimeConfig(runtimeConfig,provider){if(!isRecord2(runtimeConfig)){return void 0}const providers=runtimeConfig.models?.providers;if(!providers||!isRecord2(providers)){return void 0}const value=findProviderConfigValue(providers,provider);if(!isRecord2(value)){return void 0}const api=value.api;return typeof api==="string"&&api.trim()?api.trim():void 0}function getRuntimeModelAuth(api){const runtime=api.runtime;return runtime.modelAuth}function buildModelAuthLookupModel(params){const contextWindow=typeof params.contextWindow==="number"&&Number.isFinite(params.contextWindow)&¶ms.contextWindow>0?params.contextWindow:1e6;return{id:params.model,name:params.model,provider:params.provider,api:params.api?.trim()||inferApiFromProvider(params.provider)||"",reasoning:false,input:["text"],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow,maxTokens:8e3}}function resolveApiKeyFromAuthResult(auth){const apiKey=auth?.apiKey?.trim();return apiKey?apiKey:void 0}function resolveBaseUrlFromAuthResult(auth){const baseUrl=auth?.baseUrl?.trim();return baseUrl?baseUrl:void 0}function resolveRuntimeAuthHeaders(request){if(!request){return void 0}const headers={};if(isRecord2(request.headers)){for(const[key,value]of Object.entries(request.headers)){if(typeof value!=="string"){continue}const headerName=key.trim();const headerValue=value.trim();if(headerName&&headerValue){headers[headerName]=headerValue}}}const auth=request.auth;if(auth?.mode==="authorization-bearer"){const token=auth.token.trim();if(token){for(const key of Object.keys(headers)){if(key.toLowerCase()==="authorization"){delete headers[key]}}headers.Authorization=`Bearer ${token}`}}else if(auth?.mode==="header"){const headerName=auth.headerName.trim();const value=auth.value.trim();if(headerName&&value){const normalizedHeader=headerName.toLowerCase();for(const key of Object.keys(headers)){if(key.toLowerCase()===normalizedHeader||normalizedHeader!=="authorization"&&key.toLowerCase()==="authorization"){delete headers[key]}}headers[headerName]=`${auth.prefix?.trim()??""}${value}`}}return Object.keys(headers).length>0?headers:void 0}function attachRuntimeAuthRequestTransport(model,request){if(!request){return model}const next={...model};next[Symbol.for("openclaw.modelProviderRequestTransport")]=request;return next}function buildLegacyAuthFallbackWarning(){return["[lcm] OpenClaw runtime.modelAuth is unavailable; using legacy auth-profiles fallback.",`Stock lossless-claw 0.2.7 expects OpenClaw plugin runtime support from PR #41090 (${MODEL_AUTH_PR_URL}).`,`OpenClaw 2026.3.8 and 2026.3.8-beta.1 do not include merge commit ${MODEL_AUTH_MERGE_COMMIT};`,`${MODEL_AUTH_REQUIRED_RELEASE} is required for stock lossless-claw 0.2.7 without this fallback patch.`].join(" ")}function parseAuthProfileStore(raw){try{const parsed=JSON.parse(raw);if(!isRecord2(parsed)||!isRecord2(parsed.profiles)){return void 0}const profiles={};for(const[profileId,value]of Object.entries(parsed.profiles)){if(!isRecord2(value)){continue}const type=value.type;const provider=typeof value.provider==="string"?value.provider.trim():"";if(!provider||type!=="api_key"&&type!=="token"&&type!=="oauth"){continue}profiles[profileId]=value}const rawOrder=isRecord2(parsed.order)?parsed.order:void 0;const order=rawOrder?Object.entries(rawOrder).reduce((acc,[provider,value])=>{if(!Array.isArray(value)){return acc}const ids=value.map(entry=>typeof entry==="string"?entry.trim():"").filter(Boolean);if(ids.length>0){acc[provider]=ids}return acc},{}):void 0;return{profiles,...order&&Object.keys(order).length>0?{order}:{}}}catch{return void 0}}function mergeAuthProfileStores(stores){if(stores.length===0){return void 0}const merged={profiles:{}};for(const store of stores){merged.profiles={...merged.profiles,...store.profiles};if(store.order){merged.order={...merged.order??{},...store.order}}}return merged}function resolveAuthStorePaths(params){const paths=[];const directAgentDir=params.agentDir?.trim();if(directAgentDir){paths.push(join4(directAgentDir,"auth-profiles.json"))}const envAgentDir=params.envSnapshot.agentDir;if(envAgentDir){paths.push(join4(envAgentDir,"auth-profiles.json"))}const stateDir=params.envSnapshot.stateDir;if(stateDir){paths.push(join4(stateDir,"agents","main","agent","auth-profiles.json"))}return[...new Set(paths)]}function resolveAuthProfileCandidates(params){const candidates=[];const normalizedProvider=normalizeProviderId2(params.provider);const push=value=>{const profileId=value?.trim();if(!profileId){return}if(!candidates.includes(profileId)){candidates.push(profileId)}};push(params.authProfileId);const storeOrder=findProviderConfigValue(params.store.order,params.provider);for(const profileId of storeOrder??[]){push(profileId)}if(isRecord2(params.runtimeConfig)){const auth=params.runtimeConfig.auth;if(isRecord2(auth)){const order=findProviderConfigValue(isRecord2(auth.order)?auth.order:void 0,params.provider);if(Array.isArray(order)){for(const profileId of order){if(typeof profileId==="string"){push(profileId)}}}}}for(const[profileId,credential]of Object.entries(params.store.profiles)){if(normalizeProviderId2(credential.provider)===normalizedProvider){push(profileId)}}return candidates}function resolveSecretRef(params){const ref=params.ref;if(!ref?.id)return void 0;if(ref.source==="env"){const val=process.env[ref.id]?.trim();return val||void 0}try{const providers=isRecord2(params.config)?params.config.secrets?.providers:void 0;const providerName=ref.provider?.trim()||"default";const provider=providers&&isRecord2(providers)?providers[providerName]:void 0;if(isRecord2(provider)&&provider.source==="file"&&typeof provider.path==="string"){const configuredPath=provider.path.trim();const filePath=configuredPath.startsWith("~/")&¶ms.home?join4(params.home,configuredPath.slice(2)):configuredPath;if(!filePath){return void 0}const raw=readFileSync(filePath,"utf8");if(provider.mode==="singleValue"){if(ref.id.trim()!=="value"){return void 0}const value=raw.trim();return value||void 0}const secrets=JSON.parse(raw);const parts=ref.id.replace(/^\//,"").split("/");let current=secrets;for(const part of parts){if(!current||typeof current!=="object")return void 0;current=current[part]}return typeof current==="string"&¤t.trim()?current.trim():void 0}}catch{}try{const secretsPath=join4(params.stateDir,"secrets.json");const raw=readFileSync(secretsPath,"utf8");const secrets=JSON.parse(raw);const parts=ref.id.replace(/^\//,"").split("/");let current=secrets;for(const part of parts){if(!current||typeof current!=="object")return void 0;current=current[part]}return typeof current==="string"&¤t.trim()?current.trim():void 0}catch{return void 0}}async function resolveApiKeyFromAuthProfiles(params){const storesWithPaths=resolveAuthStorePaths({agentDir:params.agentDir,envSnapshot:params.envSnapshot}).map(path=>{try{const parsed=parseAuthProfileStore(readFileSync(path,"utf8"));return parsed?{path,store:parsed}:void 0}catch{return void 0}}).filter(entry=>!!entry);if(storesWithPaths.length===0){return void 0}const mergedStore=mergeAuthProfileStores(storesWithPaths.map(entry=>entry.store));if(!mergedStore){return void 0}const candidates=resolveAuthProfileCandidates({provider:params.provider,store:mergedStore,authProfileId:params.authProfileId,runtimeConfig:params.runtimeConfig});if(candidates.length===0){return void 0}const persistPath=params.agentDir?.trim()?join4(params.agentDir.trim(),"auth-profiles.json"):storesWithPaths[0]?.path;const secretConfig=(()=>{if(isRecord2(params.runtimeConfig)){const runtimeProviders=params.runtimeConfig.secrets?.providers;if(isRecord2(runtimeProviders)&&Object.keys(runtimeProviders).length>0){return params.runtimeConfig}}return params.appConfig??params.runtimeConfig})();for(const profileId of candidates){const credential=mergedStore.profiles[profileId];if(!credential){continue}if(normalizeProviderId2(credential.provider)!==normalizeProviderId2(params.provider)){continue}if(credential.type==="api_key"){const key=credential.key?.trim()||resolveSecretRef({ref:credential.keyRef,home:params.envSnapshot.home,stateDir:params.envSnapshot.stateDir,config:secretConfig});if(key){return key}continue}if(credential.type==="token"){const token=credential.token?.trim()||resolveSecretRef({ref:credential.tokenRef,home:params.envSnapshot.home,stateDir:params.envSnapshot.stateDir,config:secretConfig});if(!token){continue}const expires2=credential.expires;if(typeof expires2==="number"&&Number.isFinite(expires2)&&expires2>0&&Date.now()>=expires2){continue}return token}const access=credential.access?.trim();const expires=credential.expires;const isExpired=typeof expires==="number"&&Number.isFinite(expires)&&expires>0&&Date.now()>=expires;const shouldPreferOAuthHelper=typeof params.piAiModule.getOAuthApiKey==="function"&&normalizeProviderId2(params.provider)==="openai-codex";if(shouldPreferOAuthHelper){try{const oauthCredential={access:credential.access??"",refresh:credential.refresh??"",expires:typeof credential.expires==="number"?credential.expires:0,...typeof credential.projectId==="string"?{projectId:credential.projectId}:{},...typeof credential.accountId==="string"?{accountId:credential.accountId}:{}};const refreshed=await params.piAiModule.getOAuthApiKey(params.provider,{[params.provider]:oauthCredential});if(refreshed?.apiKey){mergedStore.profiles[profileId]={...credential,...refreshed.newCredentials,type:"oauth"};if(persistPath){try{writeFileSync(persistPath,JSON.stringify({version:1,profiles:mergedStore.profiles,...mergedStore.order?{order:mergedStore.order}:{}},null,2),"utf8")}catch{}}return refreshed.apiKey}}catch{}}if(!isExpired&&access){if((credential.provider==="google-gemini-cli"||credential.provider==="google-antigravity")&&typeof credential.projectId==="string"&&credential.projectId.trim()){return JSON.stringify({token:access,projectId:credential.projectId.trim()})}return access}if(typeof params.piAiModule.getOAuthApiKey!=="function"){continue}try{const oauthCredential={access:credential.access??"",refresh:credential.refresh??"",expires:typeof credential.expires==="number"?credential.expires:0,...typeof credential.projectId==="string"?{projectId:credential.projectId}:{},...typeof credential.accountId==="string"?{accountId:credential.accountId}:{}};const refreshed=await params.piAiModule.getOAuthApiKey(params.provider,{[params.provider]:oauthCredential});if(!refreshed?.apiKey){continue}mergedStore.profiles[profileId]={...credential,...refreshed.newCredentials,type:"oauth"};if(persistPath){try{writeFileSync(persistPath,JSON.stringify({version:1,profiles:mergedStore.profiles,...mergedStore.order?{order:mergedStore.order}:{}},null,2),"utf8")}catch{}}return refreshed.apiKey}catch{if(access){return access}}}return void 0}function buildSubagentSystemPrompt(params){const task=params.taskSummary?.trim()||"Perform delegated LCM expansion work.";return["You are a delegated sub-agent for LCM expansion.",`Depth: ${params.depth}/${params.maxDepth}`,"Return concise, factual results only.",task].join("\n")}function readLatestAssistantReply(messages){for(let i=messages.length-1;i>=0;i--){const item=messages[i];if(!item||typeof item!=="object"){continue}const record=item;if(record.role!=="assistant"){continue}if(typeof record.content==="string"){const trimmed=record.content.trim();if(trimmed){return trimmed}continue}if(!Array.isArray(record.content)){continue}const text=record.content.filter(entry=>{return!!entry&&typeof entry==="object"}).map(entry=>entry.type==="text"&&typeof entry.text==="string"?entry.text:"").filter(Boolean).join("\n").trim();if(text){return text}}return void 0}function createLcmDependencies(api){const envSnapshot=snapshotPluginEnv();envSnapshot.openclawDefaultModel=readDefaultModelFromConfig(api.config);const modelAuth=getRuntimeModelAuth(api);const readEnv=key=>process.env[key];const pluginConfig=resolvePluginConfig(api);const log=createLcmLogger(api);const{config,diagnostics}=resolveLcmConfigWithDiagnostics(process.env,pluginConfig);if(diagnostics.ignoreSessionPatternsEnvOverridesPluginConfig){logStartupBannerOnce({key:"ignore-session-patterns-env-override",log:message=>log.warn(message),message:"[lcm] LCM_IGNORE_SESSION_PATTERNS from env overrides plugins.entries.lossless-claw.config.ignoreSessionPatterns; plugin config array will be ignored"})}if(diagnostics.statelessSessionPatternsEnvOverridesPluginConfig){logStartupBannerOnce({key:"stateless-session-patterns-env-override",log:message=>log.warn(message),message:"[lcm] LCM_STATELESS_SESSION_PATTERNS from env overrides plugins.entries.lossless-claw.config.statelessSessionPatterns; plugin config array will be ignored"})}if(pluginConfig){const summaryModel=pluginConfig.summaryModel;const summaryProvider=pluginConfig.summaryProvider;if(typeof summaryModel==="string"){envSnapshot.pluginSummaryModel=summaryModel.trim()}if(typeof summaryProvider==="string"){envSnapshot.pluginSummaryProvider=summaryProvider.trim()}}if(!modelAuth){log.warn(buildLegacyAuthFallbackWarning())}logStartupBannerOnce({key:"transcript-gc-enabled",log:message=>log.info(message),message:`[lcm] Transcript GC ${config.transcriptGcEnabled?"enabled":"disabled"} (default false)`});logStartupBannerOnce({key:"proactive-threshold-compaction-mode",log:message=>log.info(message),message:`[lcm] Proactive threshold compaction mode: ${config.proactiveThresholdCompactionMode} (default deferred)`});const resolveModelAuthConfig=runtimeConfig=>{if(runtimeConfig&&typeof runtimeConfig==="object"){return runtimeConfig}return api.config};const lookupApiKey=async(provider,model,options)=>{const modelAuthConfig=resolveModelAuthConfig(options?.runtimeConfig);if(modelAuth&&options?.skipModelAuth!==true){try{const modelAuthKey=resolveApiKeyFromAuthResult(await modelAuth.getApiKeyForModel({model:buildModelAuthLookupModel({provider,model,contextWindow:1e6}),cfg:modelAuthConfig,...options?.profileId?{profileId:options.profileId}:{},...options?.preferredProfile?{preferredProfile:options.preferredProfile}:{}}));if(modelAuthKey){return modelAuthKey}}catch{}}const envKey=resolveApiKey(provider,readEnv);if(envKey){return envKey}const piAiModuleId="@mariozechner/pi-ai";const mod=await import(piAiModuleId);return resolveApiKeyFromAuthProfiles({provider,authProfileId:options?.profileId,agentDir:options?.agentDir??api.resolvePath("."),runtimeConfig:options?.runtimeConfig,appConfig:api.config,piAiModule:mod,envSnapshot})};return{config,configDiagnostics:diagnostics,isRuntimeManagedAuthProvider:(provider,providerApi)=>{const normalizedProvider=normalizeProviderId2(provider);if(normalizedProvider==="openai-codex"||normalizedProvider==="github-copilot"){return true}return shouldOmitTemperatureForApi(providerApi)},complete:async({provider,model,apiKey,providerApi,authProfileId,agentDir,runtimeConfig,skipModelAuth,messages,system,maxTokens,temperature,reasoning,reasoningIfSupported})=>{try{const piAiModuleId="@mariozechner/pi-ai";const mod=await import(piAiModuleId);if(typeof mod.completeSimple!=="function"){return{content:[]}}const providerId=(provider??"").trim();const modelId=model.trim();if(!providerId||!modelId){return{content:[]}}const workspaceDir=agentDir?.trim()||api.resolvePath(".");let effectiveRuntimeConfig=runtimeConfig;if(!isRecord2(effectiveRuntimeConfig)){try{effectiveRuntimeConfig=api.runtime.config.loadConfig()}catch{}}const knownModel=typeof mod.getModel==="function"?mod.getModel(providerId,modelId):void 0;const fallbackApi=(isRecord2(knownModel)&&typeof knownModel.api==="string"&&knownModel.api.trim()?knownModel.api.trim():void 0)||providerApi?.trim()||resolveProviderApiFromRuntimeConfig(effectiveRuntimeConfig,providerId)||(()=>{if(typeof mod.getModels!=="function"){return void 0}const models=mod.getModels(providerId);const first=Array.isArray(models)?models[0]:void 0;if(!isRecord2(first)||typeof first.api!=="string"||!first.api.trim()){return void 0}return first.api.trim()})()||inferApiFromProvider(providerId);if(!fallbackApi){throw new Error(`[lcm] unable to resolve API family for provider ${providerId}; set models.providers.${providerId}.api explicitly instead of falling back implicitly.`)}const modelAuthConfig=resolveModelAuthConfig(effectiveRuntimeConfig);const providerLevelConfig=(()=>{if(!isRecord2(effectiveRuntimeConfig))return{};const providers=effectiveRuntimeConfig.models?.providers;if(!providers)return{};const cfg=findProviderConfigValue(providers,providerId);return isRecord2(cfg)?cfg:{}})();let resolvedModel=isRecord2(knownModel)&&typeof knownModel.api==="string"&&typeof knownModel.provider==="string"&&typeof knownModel.id==="string"?{...knownModel,id:knownModel.id,provider:knownModel.provider,api:typeof providerLevelConfig.api==="string"&&providerLevelConfig.api.trim()?providerLevelConfig.api.trim():knownModel.api,baseUrl:typeof providerLevelConfig.baseUrl==="string"?providerLevelConfig.baseUrl:typeof knownModel.baseUrl==="string"?knownModel.baseUrl:"",...isRecord2(providerLevelConfig.headers)?{headers:{...isRecord2(knownModel.headers)?knownModel.headers:{},...providerLevelConfig.headers}}:{}}:{id:modelId,name:modelId,provider:providerId,api:fallbackApi,reasoning:false,input:["text"],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:1e6,maxTokens:8e3,baseUrl:typeof providerLevelConfig.baseUrl==="string"?providerLevelConfig.baseUrl:"",...isRecord2(providerLevelConfig.headers)?{headers:providerLevelConfig.headers}:{}};let runtimeAuth;if(modelAuth&&skipModelAuth!==true&&typeof modelAuth.getRuntimeAuthForModel==="function"){try{runtimeAuth=await modelAuth.getRuntimeAuthForModel({model:buildModelAuthLookupModel({provider:providerId,model:modelId,api:resolvedModel.api,contextWindow:resolvedModel.contextWindow}),cfg:modelAuthConfig,...authProfileId?{profileId:authProfileId}:{},workspaceDir})}catch(err){console.error(`[lcm] modelAuth.getRuntimeAuthForModel FAILED:`,err instanceof Error?err.message:err)}}const runtimeAuthBaseUrl=resolveBaseUrlFromAuthResult(runtimeAuth);const runtimeAuthHeaders=resolveRuntimeAuthHeaders(runtimeAuth?.request);resolvedModel=attachRuntimeAuthRequestTransport({...resolvedModel,...runtimeAuthBaseUrl?{baseUrl:runtimeAuthBaseUrl}:{},...runtimeAuthHeaders?{headers:{...isRecord2(resolvedModel.headers)?resolvedModel.headers:{},...runtimeAuthHeaders}}:{}},runtimeAuth?.request);let resolvedApiKey=apiKey?.trim();if(!resolvedApiKey){resolvedApiKey=resolveApiKeyFromAuthResult(runtimeAuth)}if(!resolvedApiKey&&modelAuth&&skipModelAuth!==true){try{resolvedApiKey=resolveApiKeyFromAuthResult(await modelAuth.getApiKeyForModel({model:buildModelAuthLookupModel({provider:providerId,model:modelId,api:resolvedModel.api,contextWindow:resolvedModel.contextWindow}),cfg:modelAuthConfig,...authProfileId?{profileId:authProfileId}:{}}))}catch(err){log.warn(`[lcm] modelAuth.getApiKeyForModel FAILED: ${describeLogError(err)}`)}}if(!resolvedApiKey&&modelAuth&&skipModelAuth!==true){try{resolvedApiKey=resolveApiKeyFromAuthResult(await modelAuth.resolveApiKeyForProvider({provider:providerId,cfg:modelAuthConfig,...authProfileId?{profileId:authProfileId}:{}}))}catch(err){log.warn(`[lcm] modelAuth.resolveApiKeyForProvider FAILED: ${describeLogError(err)}`)}}if(!resolvedApiKey){resolvedApiKey=resolveApiKey(providerId,readEnv)}if(!resolvedApiKey&&typeof mod.getEnvApiKey==="function"){resolvedApiKey=mod.getEnvApiKey(providerId)?.trim()}if(!resolvedApiKey){resolvedApiKey=await resolveApiKeyFromAuthProfiles({provider:providerId,authProfileId,agentDir,appConfig:api.config,runtimeConfig:effectiveRuntimeConfig,piAiModule:mod,envSnapshot})}if(!resolvedApiKey&&isRecord2(effectiveRuntimeConfig)){const providers=effectiveRuntimeConfig.models?.providers;if(providers){const providerCfg=findProviderConfigValue(providers,providerId);if(isRecord2(providerCfg)&&typeof providerCfg.apiKey==="string"){const cfgKey=providerCfg.apiKey.trim();if(cfgKey){resolvedApiKey=cfgKey}}}}const effectiveReasoning=resolveEffectiveReasoning({reasoning,reasoningIfSupported,modelSupportsReasoning:resolvedModel.reasoning});const completeOptions=buildCompleteSimpleOptions({api:resolvedModel.api,apiKey:resolvedApiKey,maxTokens,temperature,reasoning:effectiveReasoning});const requestMetadata={request_provider:providerId,request_model:modelId,request_api:resolvedModel.api,request_reasoning:effectiveReasoning??"(none)",request_has_system:typeof system==="string"&&system.trim().length>0?"true":"false",request_temperature:typeof completeOptions.temperature==="number"?String(completeOptions.temperature):"(omitted)",request_temperature_sent:typeof completeOptions.temperature==="number"?"true":"false"};const result=await mod.completeSimple(resolvedModel,{...typeof system==="string"&&system.trim()?{systemPrompt:system.trim()}:{},messages:messages.map(message=>({role:message.role,content:message.content,timestamp:Date.now()}))},completeOptions);if(!isRecord2(result)){return{content:[],...requestMetadata}}return{...result,content:Array.isArray(result.content)?result.content:[],...requestMetadata}}catch(err){log.error(`[lcm] completeSimple error: ${describeLogError(err)}`);const authError=detectProviderAuthError(err);const configError=!authError&&err instanceof Error&&err.message.startsWith(PROVIDER_API_RESOLUTION_ERROR_PREFIX)?{kind:"provider_config",message:err.message}:void 0;return{content:[],...authError?{error:authError}:{},...configError?{error:configError}:{}}}},callGateway:async params=>{const sub=api.runtime.subagent;switch(params.method){case"agent":return sub.run({sessionKey:String(params.params?.sessionKey??""),message:String(params.params?.message??""),provider:params.params?.provider,model:params.params?.model,extraSystemPrompt:params.params?.extraSystemPrompt,lane:params.params?.lane,deliver:params.params?.deliver??false,idempotencyKey:params.params?.idempotencyKey});case"agent.wait":return sub.waitForRun({runId:String(params.params?.runId??""),timeoutMs:params.params?.timeoutMs??params.timeoutMs});case"sessions.get":return sub.getSession({sessionKey:String(params.params?.key??""),limit:params.params?.limit});case"sessions.delete":await sub.deleteSession({sessionKey:String(params.params?.key??""),deleteTranscript:params.params?.deleteTranscript??true});return{};default:throw new Error(`Unsupported gateway method in LCM plugin: ${params.method}`)}},resolveModel:(modelRef,providerHint)=>{const raw=(envSnapshot.lcmSummaryModel||config.summaryModel||modelRef?.trim()||envSnapshot.openclawDefaultModel).trim();if(!raw){throw new Error("No model configured for LCM summarization.")}if(raw.includes("/")){const[provider2,...rest]=raw.split("/");const model=rest.join("/").trim();if(provider2&&model){return{provider:provider2.trim(),model}}}const provider=(providerHint?.trim()||envSnapshot.lcmSummaryProvider||config.summaryProvider||envSnapshot.openclawProvider||"openai").trim();return{provider,model:raw}},getApiKey:async(provider,model,options)=>{return lookupApiKey(provider,model,options)},requireApiKey:async(provider,model,options)=>{const key=await lookupApiKey(provider,model,options);if(!key){throw new Error(`Missing API key for provider '${provider}' (model '${model}').`)}return key},parseAgentSessionKey,isSubagentSessionKey:sessionKey=>{const parsed=parseAgentSessionKey(sessionKey);return!!parsed&&parsed.suffix.startsWith("subagent:")},normalizeAgentId,buildSubagentSystemPrompt,readLatestAssistantReply,resolveAgentDir:()=>api.resolvePath("."),resolveSessionIdFromSessionKey:async sessionKey=>{const key=sessionKey.trim();if(!key){return void 0}try{const cfg=api.runtime.config.loadConfig();const parsed=parseAgentSessionKey(key);const agentId=normalizeAgentId(parsed?.agentId);const storePath=api.runtime.agent.session.resolveStorePath(cfg.session?.store,{agentId});const store=api.runtime.agent.session.loadSessionStore(storePath);const sessionId=store[key]?.sessionId;return typeof sessionId==="string"&&sessionId.trim()?sessionId.trim():void 0}catch{return void 0}},resolveSessionTranscriptFile:async({sessionId,sessionKey})=>{const normalizedSessionId=sessionId.trim();if(!normalizedSessionId){return void 0}try{const cfg=api.runtime.config.loadConfig();const normalizedSessionKey=sessionKey?.trim();const parsed=normalizedSessionKey?parseAgentSessionKey(normalizedSessionKey):null;const agentId=normalizeAgentId(parsed?.agentId);const storePath=api.runtime.agent.session.resolveStorePath(cfg.session?.store,{agentId});const store=api.runtime.agent.session.loadSessionStore(storePath);const entry=(normalizedSessionKey?store[normalizedSessionKey]:void 0)??Object.values(store).find(candidate=>candidate?.sessionId===normalizedSessionId);const transcriptPath=api.runtime.agent.session.resolveSessionFilePath(normalizedSessionId,entry,{agentId,storePath});return transcriptPath.trim()||void 0}catch{return void 0}},agentLaneSubagent:"subagent",log}}function wirePluginHandlers(api,deps,shared){api.on("before_reset",async(event,ctx)=>{await(await shared.waitForEngine()).handleBeforeReset({reason:event.reason,sessionId:ctx.sessionId,sessionKey:ctx.sessionKey})});api.on("before_prompt_build",()=>({prependSystemContext:LOSSLESS_RECALL_POLICY_PROMPT}));api.on("session_end",async event=>{const lifecycleEvent=event;await(await shared.waitForEngine()).handleSessionEnd({reason:lifecycleEvent.reason,sessionId:lifecycleEvent.sessionId,sessionKey:lifecycleEvent.sessionKey,nextSessionId:lifecycleEvent.nextSessionId,nextSessionKey:lifecycleEvent.nextSessionKey})});api.registerContextEngine("lossless-claw",()=>shared.getCachedEngine()??shared.waitForEngine());api.registerContextEngine("default",()=>shared.getCachedEngine()??shared.waitForEngine());api.registerTool(ctx=>createLcmGrepTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey}));api.registerTool(ctx=>createLcmDescribeTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey}));api.registerTool(ctx=>createLcmExpandTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey}));api.registerTool(ctx=>createLcmExpandQueryTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey,requesterSessionKey:ctx.sessionKey}));api.registerCommand(createLcmCommand({db:shared.waitForDatabase,config:deps.config,deps,getLcm:shared.waitForEngine}))}var lcmPlugin={id:"lossless-claw",name:"Lossless Context Management",description:"DAG-based conversation summarization with incremental compaction, full-text search, and sub-agent expansion",configSchema:{parse(value){const raw=value&&typeof value==="object"&&!Array.isArray(value)?value:{};return resolveLcmConfigWithDiagnostics(process.env,raw).config}},register(api){const deps=createLcmDependencies(api);const dbPath=deps.config.databasePath;const normalizedDbPath=normalizePath(dbPath);const existingInit=getSharedInit(normalizedDbPath);if(existingInit&&!existingInit.stopped){deps.log.info(`[lcm] Reusing shared engine init for db=${normalizedDbPath}`);wirePluginHandlers(api,deps,existingInit);return}let database=null;let lcm=null;let initPromise=null;let initError=null;let resolveDeferredInit=null;let rejectDeferredInit=null;let stopped=false;function toInitError(error){return error instanceof Error?error:new Error(String(error))}function initializeEngine(){const startedAt=Date.now();const nextDatabase=createLcmDatabaseConnection(dbPath);try{const nextEngine=new LcmContextEngine(deps,nextDatabase);database=nextDatabase;lcm=nextEngine;initError=null;deps.log.info(`[lcm] Engine initialized for db=${normalizedDbPath} duration=${Date.now()-startedAt}ms`);return nextEngine}catch(error){closeLcmConnection(nextDatabase);deps.log.info(`[lcm] Engine init failed for db=${normalizedDbPath} duration=${Date.now()-startedAt}ms error=${toInitError(error).message}`);throw error}}function ensureDeferredInitPromise(){if(initPromise){return initPromise}initPromise=new Promise((resolve2,reject)=>{resolveDeferredInit=resolve2;rejectDeferredInit=reject});initPromise.catch(()=>{});return initPromise}function resolveDeferredEngine(nextEngine){const resolve2=resolveDeferredInit;resolveDeferredInit=null;rejectDeferredInit=null;resolve2?.(nextEngine)}function rejectDeferredEngine(error){initError=error;const reject=rejectDeferredInit;resolveDeferredInit=null;rejectDeferredInit=null;reject?.(error)}async function waitForEngine(){if(stopped){throw new Error("[lcm] Database connection closed after gateway_stop")}if(initError){throw initError}if(lcm){return lcm}if(initPromise){return initPromise}try{const nextEngine=initializeEngine();initPromise=Promise.resolve(nextEngine);return nextEngine}catch(error){const normalized=toInitError(error);if(!/database is locked/i.test(normalized.message)){initError=normalized;throw normalized}deps.log.warn("[lcm] DB locked during eager init, deferring to gateway_start");return ensureDeferredInitPromise()}}async function waitForDatabase(){await waitForEngine();if(!database){throw initError??new Error("[lcm] Database initialization finished without a handle")}return database}try{const nextEngine=initializeEngine();initPromise=Promise.resolve(nextEngine)}catch(error){const normalized=toInitError(error);if(!/database is locked/i.test(normalized.message)){initError=normalized;throw normalized}deps.log.warn("[lcm] DB locked during eager init, deferring to gateway_start");ensureDeferredInitPromise();api.on("gateway_start",async()=>{if(stopped||lcm||initError){return}try{const nextEngine=initializeEngine();initPromise=Promise.resolve(nextEngine);resolveDeferredEngine(nextEngine)}catch(retryError){const normalizedRetryError=toInitError(retryError);rejectDeferredEngine(normalizedRetryError);deps.log.error(`[lcm] Deferred DB init failed: ${normalizedRetryError.message}`)}})}const shared={stopped:false,getCachedEngine:()=>lcm,waitForEngine,waitForDatabase};setSharedInit(normalizedDbPath,shared);api.on("gateway_stop",async()=>{stopped=true;shared.stopped=true;if(!lcm&&!database){rejectDeferredEngine(new Error("[lcm] Database connection closed after gateway_stop"))}if(database){closeLcmConnection(database);database=null}lcm=null;removeSharedInit(normalizedDbPath)});wirePluginHandlers(api,deps,shared);logStartupBannerOnce({key:"plugin-loaded",log:message=>deps.log.info(message),message:`[lcm] Plugin loaded (enabled=${deps.config.enabled}, db=${deps.config.databasePath}, threshold=${deps.config.contextThreshold}, proactiveThresholdCompactionMode=${deps.config.proactiveThresholdCompactionMode})`});logStartupBannerOnce({key:"state-dir",log:message=>deps.log.info(message),message:`[lcm] State dir: ${resolveOpenclawStateDir(process.env)}`});logStartupBannerOnce({key:"compaction-model",log:message=>deps.log.info(message),message:buildCompactionModelLog({config:deps.config,openClawConfig:api.config,defaultProvider:process.env.OPENCLAW_PROVIDER?.trim()??""})});if(deps.config.fallbackProviders.length>0){logStartupBannerOnce({key:"fallback-providers",log:message=>deps.log.info(message),message:`[lcm] Fallback providers: ${deps.config.fallbackProviders.map(fp=>`${fp.provider}/${fp.model}`).join(", ")}`})}}};var plugin_default=lcmPlugin;export{buildCompleteSimpleOptions,plugin_default as default,shouldOmitTemperatureForApi};
|
|
1056
|
+
LIMIT 1`).get(sessionId);if(!row){return null}return getConversationStatusStats(db,row.conversation_id)}async function getConversationCompactionMaintenanceByConversationId(db,conversationId){return await new CompactionMaintenanceStore(db).getConversationCompactionMaintenance(conversationId)}async function getConversationCompactionTelemetryByConversationId(db,conversationId){return await new CompactionTelemetryStore(db).getConversationCompactionTelemetry(conversationId)}async function resolveCurrentConversation(params){const sessionKey=normalizeIdentity(params.ctx.sessionKey);const sessionId=normalizeIdentity(params.ctx.sessionId);if(sessionKey){const bySessionKey=getConversationStatusBySessionKey(params.db,sessionKey);if(bySessionKey){return{kind:"resolved",source:"session_key",stats:bySessionKey}}if(sessionId){const bySessionId=getConversationStatusBySessionId(params.db,sessionId);if(bySessionId){if(!bySessionId.sessionKey||bySessionId.sessionKey===sessionKey){return{kind:"resolved",source:"session_key_via_session_id",stats:bySessionId}}return{kind:"unavailable",reason:`Active session key ${formatCommand(sessionKey)} is not stored in LCM yet. Session id fallback found conversation #${formatNumber(bySessionId.conversationId)}, but it is bound to ${formatCommand(bySessionId.sessionKey)}, so Global stats are safer.`}}}return{kind:"unavailable",reason:sessionId?`No LCM conversation is stored yet for active session key ${formatCommand(sessionKey)} or active session id ${formatCommand(sessionId)}.`:`No LCM conversation is stored yet for active session key ${formatCommand(sessionKey)}.`}}if(sessionId){const bySessionId=getConversationStatusBySessionId(params.db,sessionId);if(bySessionId){return{kind:"resolved",source:"session_id",stats:bySessionId}}return{kind:"unavailable",reason:`OpenClaw did not expose an active session key here. Tried active session id ${formatCommand(sessionId)}, but no stored LCM conversation matched it.`}}return{kind:"unavailable",reason:"OpenClaw did not expose an active session key or session id here, so only GLOBAL stats are available."}}async function resolveRotateSessionId(params){const directSessionId=normalizeIdentity(params.ctx.sessionId);if(directSessionId){return directSessionId}const sessionKey=normalizeIdentity(params.ctx.sessionKey);if(sessionKey){const runtimeSessionId=normalizeIdentity(await params.deps.resolveSessionIdFromSessionKey(sessionKey));if(runtimeSessionId){return runtimeSessionId}}return normalizeIdentity(params.current.stats.sessionId)}function resolvePluginEnabled(config){const root=asRecord2(config);const plugins=asRecord2(root?.plugins);const entries=asRecord2(plugins?.entries);const entry=asRecord2(entries?.["lossless-claw"]);if(typeof entry?.enabled==="boolean"){return entry.enabled}return true}function resolveContextEngineSlot(config){const root=asRecord2(config);const plugins=asRecord2(root?.plugins);const slots=asRecord2(plugins?.slots);return typeof slots?.contextEngine==="string"?slots.contextEngine.trim():""}function resolvePluginSelected(config){const slot=resolveContextEngineSlot(config);return slot===""||slot==="lossless-claw"||slot==="default"}function resolveDbSizeLabel(dbPath){const trimmed=dbPath.trim();if(!trimmed||trimmed===":memory:"||trimmed.startsWith("file::memory:")){return"in-memory"}try{return formatBytes(statSync2(trimmed).size)}catch{return"missing"}}function buildHelpText(error){const lines=[...error?[`\u26A0\uFE0F ${error}`,""]:[],...buildHeaderLines(),"",buildSection("\u{1F4D8} Commands",[buildStatLine(formatCommand(VISIBLE_COMMAND),"Show compact status output."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} status`),"Show plugin, Global, current-conversation, and compaction-maintenance status."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} backup`),"Create a timestamped backup of the current LCM database."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} rotate`),"Compact the current session transcript while preserving the same LCM conversation and live session identity."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} doctor`),"Scan for broken or truncated summaries."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} doctor clean`),"Report global high-confidence junk candidates without deleting anything."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} doctor clean apply`),"Delete approved high-confidence cleaner matches after creating a DB backup."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} doctor apply`),"Repair broken summaries in the current conversation.")]),"",buildSection("\u{1F9ED} Notes",[buildStatLine("subcommands",`Discover them with ${formatCommand(`${VISIBLE_COMMAND} help`)}.`),buildStatLine("alias",`${formatCommand(HIDDEN_ALIAS)} is accepted as a shorter alias.`),buildStatLine("current conversation","Uses the active LCM session when the host exposes session identity."),buildStatLine("`/new`","Prunes context for the current LCM conversation. It does not split storage."),buildStatLine("`/reset`","Resets OpenClaw session flow. Use rotate when you only want transcript compaction.")])];return lines.join("\n")}function buildDoctorCleanerExampleLine(params){const sessionKey=params.sessionKey?formatCommand(truncateMiddle(params.sessionKey,44)):"missing";const preview=params.firstMessagePreview?` \xB7 first: ${JSON.stringify(params.firstMessagePreview)}`:"";return`conv ${formatNumber(params.conversationId)} \xB7 session key ${sessionKey} \xB7 messages ${formatNumber(params.messageCount)}${preview}`}async function buildStatusText(params){const status=getLcmStatusStats(params.db);const doctor=getDoctorSummaryStats(params.db);const enabled=resolvePluginEnabled(params.ctx.config);const selected=resolvePluginSelected(params.ctx.config);const slot=resolveContextEngineSlot(params.ctx.config);const dbSize=resolveDbSizeLabel(params.config.databasePath);const current=await resolveCurrentConversation({ctx:params.ctx,db:params.db});const lines=[...buildHeaderLines(),"",buildSection("\u{1F9E9} Plugin",[buildStatLine("enabled",formatBoolean(enabled)),buildStatLine("selected",`${formatBoolean(selected)}${slot?` (slot=${slot})`:" (slot=unset)"}`),buildStatLine("db path",params.config.databasePath),buildStatLine("db size",dbSize)]),"",buildSection("\u{1F310} Global",[buildStatLine("conversations",formatNumber(status.conversationCount)),buildStatLine("summaries",`${formatNumber(status.summaryCount)} (${formatNumber(status.leafSummaryCount)} leaf, ${formatNumber(status.condensedSummaryCount)} condensed)`),buildStatLine("stored summary tokens",formatNumber(status.storedSummaryTokens)),buildStatLine("summarized source tokens",formatNumber(status.summarizedSourceTokens))]),""];if(current.kind==="resolved"){const conversationDoctor=doctor.byConversation.get(current.stats.conversationId)??{total:0,old:0,truncated:0,fallback:0};const maintenance=await getConversationCompactionMaintenanceByConversationId(params.db,current.stats.conversationId);const telemetry=await getConversationCompactionTelemetryByConversationId(params.db,current.stats.conversationId);const formatMaintenanceTime=value=>value?formatTimestamp(value,params.config.timezone):"never";lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",current.stats.sessionKey?formatCommand(truncateMiddle(current.stats.sessionKey,44)):"missing"),buildStatLine("messages",formatNumber(current.stats.messageCount)),buildStatLine("summaries",`${formatNumber(current.stats.summaryCount)} (${formatNumber(current.stats.leafSummaryCount)} leaf, ${formatNumber(current.stats.condensedSummaryCount)} condensed)`),buildStatLine("stored summary tokens",formatNumber(current.stats.storedSummaryTokens)),buildStatLine("summarized source tokens",formatNumber(current.stats.summarizedSourceTokens)),buildStatLine("tokens in context",formatNumber(current.stats.contextTokenCount)),buildStatLine("compression ratio",formatCompressionRatio(current.stats.contextTokenCount,current.stats.compressedTokenCount)),buildStatLine("doctor",conversationDoctor.total>0?`${formatNumber(conversationDoctor.total)} issue(s) in this conversation`:"clean")]));lines.push("",buildSection("\u{1F6E0}\uFE0F Maintenance",[buildStatLine("state",maintenance?.pending?"pending":maintenance?.running?"running":"idle"),buildStatLine("requested at",formatMaintenanceTime(maintenance?.requestedAt??null)),buildStatLine("reason",maintenance?.reason??"none"),buildStatLine("last started",formatMaintenanceTime(maintenance?.lastStartedAt??null)),buildStatLine("last finished",formatMaintenanceTime(maintenance?.lastFinishedAt??null)),buildStatLine("last failure",maintenance?.lastFailureSummary??"none"),buildStatLine("requested token budget",maintenance?.tokenBudget!=null?formatNumber(maintenance.tokenBudget):"unknown"),buildStatLine("observed token count",maintenance?.currentTokenCount!=null?formatNumber(maintenance.currentTokenCount):"unknown"),buildStatLine("last api call",formatMaintenanceTime(telemetry?.lastApiCallAt??null)),buildStatLine("last cache touch",formatMaintenanceTime(telemetry?.lastCacheTouchAt??null)),buildStatLine("cache retention",telemetry?.retention??"unknown"),buildStatLine("cache state",telemetry?.cacheState??"unknown"),buildStatLine("provider/model",[telemetry?.provider,telemetry?.model].filter(Boolean).join(" / ")||"unknown")]))}else{lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason),buildStatLine("fallback","Showing Global stats only.")]))}return lines.join("\n")}async function buildDoctorText(params){const current=await resolveCurrentConversation(params);if(current.kind==="unavailable"){return[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor","",buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason),buildStatLine("fallback","Doctor is conversation-scoped, so no global scan ran.")])].join("\n")}const stats=getDoctorSummaryStats(params.db,current.stats.conversationId);const lines=[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor","",buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",current.stats.sessionKey?formatCommand(truncateMiddle(current.stats.sessionKey,44)):"missing"),buildStatLine("scope","this conversation only")]),"",buildSection("\u{1F9EA} Scan",[buildStatLine("detected summaries",formatNumber(stats.total)),buildStatLine("old-marker summaries",formatNumber(stats.old)),buildStatLine("truncated-marker summaries",formatNumber(stats.truncated)),buildStatLine("fallback-marker summaries",formatNumber(stats.fallback)),buildStatLine("result",stats.total===0?"clean":"issues found")])];if(stats.total>0){const summaryList=stats.candidates.slice().sort((left,right)=>left.summaryId.localeCompare(right.summaryId)).map(candidate=>`${candidate.summaryId} (${candidate.markerKind})`).join(", ");lines.push("",buildSection("\u{1F9F7} Affected summaries",[summaryList]),"",buildSection("\u{1F6E0}\uFE0F Next step",[`${formatCommand(`${VISIBLE_COMMAND} doctor apply`)} repairs these in place for the current conversation.`]))}return lines.join("\n")}async function buildDoctorCleanersText(params){const scan=scanDoctorCleaners(params.db);const lines=[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor Clean","",buildSection("\u{1F310} Global scan",[buildStatLine("filters",formatNumber(scan.filters.length)),buildStatLine("matched conversations",formatNumber(scan.totalDistinctConversations)),buildStatLine("matched messages",formatNumber(scan.totalDistinctMessages)),buildStatLine("mode","read-only diagnostics")])];if(scan.filters.every(filter=>filter.conversationCount===0)){lines.push("",buildSection("\u2705 Result",["No high-confidence cleaner candidates detected."]));return lines.join("\n")}for(const filter of scan.filters){lines.push("",buildSection(`\u{1F9F9} ${filter.label}`,[buildStatLine("filter id",formatCommand(filter.id)),buildStatLine("description",filter.description),buildStatLine("matched conversations",formatNumber(filter.conversationCount)),buildStatLine("matched messages",formatNumber(filter.messageCount))]));if(filter.examples.length>0){lines.push("",buildSection("\u{1F9F7} Examples",filter.examples.map(example=>buildDoctorCleanerExampleLine(example))))}}lines.push("",buildSection("\u{1F6E0}\uFE0F Next step",[`Review the examples, then run ${formatCommand(`${VISIBLE_COMMAND} doctor clean apply`)} to delete approved matches after Lossless Claw creates a backup.`]));return lines.join("\n")}function runQuickCheck(db){const rows=db.prepare(`PRAGMA quick_check`).all();const results=rows.map(row=>row.quick_check).filter(value=>typeof value==="string"&&value.length>0);if(results.length===0){return"unknown"}if(results.length===1&&results[0]==="ok"){return"ok"}return results.join("; ")}function isPassingQuickCheck(result){return result==="ok"}function getLcmBackupUnavailableReason(databasePath){const trimmed=databasePath.trim();if(!trimmed||trimmed===":memory:"||trimmed.startsWith("file::memory:")){return"Backup requires a file-backed SQLite database."}return null}async function buildBackupText(params){const lines=[...buildHeaderLines(),"","\u{1F4BE} Lossless Claw Backup",""];const unavailableReason=getLcmBackupUnavailableReason(params.config.databasePath);if(unavailableReason){lines.push(buildSection("\u{1F6E0}\uFE0F Backup",[buildStatLine("status","unavailable"),buildStatLine("reason",unavailableReason)]));return lines.join("\n")}let backupPath;try{backupPath=createLcmDatabaseBackup(params.db,{databasePath:params.config.databasePath,label:"backup"})}catch(error){lines.push(buildSection("\u{1F6E0}\uFE0F Backup",[buildStatLine("status","failed"),buildStatLine("reason",formatFailureReason(error))]));return lines.join("\n")}if(!backupPath){lines.push(buildSection("\u{1F6E0}\uFE0F Backup",[buildStatLine("status","unavailable"),buildStatLine("reason","Lossless Claw could not determine a backup path.")]));return lines.join("\n")}lines.push(buildSection("\u{1F6E0}\uFE0F Backup",[buildStatLine("status","created"),buildStatLine("db path",params.config.databasePath),buildStatLine("backup path",backupPath)]));return lines.join("\n")}async function buildRotateText(params){const lines=[...buildHeaderLines(),"","\u{1FA93} Lossless Claw Rotate",""];const sessionKey=normalizeIdentity(params.ctx.sessionKey);if(!sessionKey){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason","OpenClaw must expose the active session key for Lossless Claw to rotate storage safely.")]));return lines.join("\n")}const current=await resolveCurrentConversation({ctx:params.ctx,db:params.db});if(current.kind==="unavailable"){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason)]));return lines.join("\n")}if(!params.deps||!params.getLcm){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason","Rotate requires the runtime-backed LCM engine to be available.")]));return lines.join("\n")}const sessionId=await resolveRotateSessionId({ctx:params.ctx,deps:params.deps,current});if(!sessionId){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(sessionKey,44))),buildStatLine("messages",formatNumber(current.stats.messageCount))]),"",buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason","Lossless Claw resolved the active conversation, but OpenClaw did not expose or resolve a runtime session id, so rotate cannot locate the live transcript safely.")]));return lines.join("\n")}const transcriptPath=await params.deps.resolveSessionTranscriptFile({sessionId,sessionKey});if(!transcriptPath||!existsSync(transcriptPath)){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason","Lossless Claw could not resolve the active session transcript path, so it cannot rotate the transcript safely.")]));return lines.join("\n")}const unavailableReason=getLcmBackupUnavailableReason(params.config.databasePath);if(unavailableReason){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason",unavailableReason)]));return lines.join("\n")}let result;try{result=await(await params.getLcm()).rotateSessionStorageWithBackup({sessionId,sessionKey,sessionFile:transcriptPath,lockTimeoutMs:ROTATE_DATABASE_LOCK_TIMEOUT_MS})}catch(error){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","failed"),buildStatLine("reason",formatFailureReason(error))]));return lines.join("\n")}lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(result.currentConversationId??current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(sessionKey,44))),buildStatLine("messages",formatNumber(result.currentMessageCount??current.stats.messageCount))]),"");if(result.kind==="backup_failed"){lines.push(buildSection("\u{1F4BE} Backup",[buildStatLine("status","failed"),buildStatLine("reason",result.reason)]));return lines.join("\n")}if(result.kind==="unavailable"&&!result.backupPath){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason",result.reason)]));return lines.join("\n")}lines.push(buildSection("\u{1F4BE} Backup",[buildStatLine("status","replaced latest"),buildStatLine("backup path",result.backupPath)]),"");if(result.kind==="rotate_failed"){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","failed"),buildStatLine("reason",result.reason)]));return lines.join("\n")}if(result.kind==="unavailable"){lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","unavailable"),buildStatLine("reason",result.reason)]));return lines.join("\n")}lines.push(buildSection("\u{1F6E0}\uFE0F Rotate",[buildStatLine("status","rotated"),buildStatLine("preserved tail messages",formatNumber(result.preservedTailMessageCount)),buildStatLine("checkpoint bytes",formatNumber(result.checkpointSize)),buildStatLine("bytes removed",formatNumber(result.bytesRemoved)),buildStatLine("transcript",transcriptPath),buildStatLine("mode","preserved current conversation and rotated transcript tail")]),"",buildSection("\u{1F9ED} Notes",["Current LCM conversation, summaries, and context items remain in place.",`${formatCommand("/new")} still prunes context only, and ${formatCommand("/reset")} still resets OpenClaw session flow.`]));return lines.join("\n")}async function buildDoctorCleanersApplyText(params){const filterIds=params.filterId?[params.filterId]:void 0;const unavailableReason=getDoctorCleanerApplyUnavailableReason(params.config.databasePath);const lines=[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor Clean Apply","",buildSection("\u{1F310} Cleaner scope",[buildStatLine("filters",filterIds&&filterIds.length>0?filterIds.map(filter=>formatCommand(filter)).join(", "):"all approved cleaner filters"),buildStatLine("vacuum requested",formatBoolean(params.vacuum))]),""];if(unavailableReason){lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("status","unavailable"),buildStatLine("reason",unavailableReason)]));return lines.join("\n")}const before=scanDoctorCleaners(params.db,filterIds);lines.splice(lines.length-1,0,buildSection("\u{1F4CA} Current matches",[buildStatLine("matched conversations before apply",formatNumber(before.totalDistinctConversations)),buildStatLine("matched messages before apply",formatNumber(before.totalDistinctMessages))]),"");if(before.totalDistinctConversations===0){lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("status","completed"),buildStatLine("backup path","skipped (no matches)"),buildStatLine("deleted conversations","0"),buildStatLine("deleted messages","0"),buildStatLine("vacuumed","no"),buildStatLine("quick_check","not run (no writes)"),buildStatLine("result","clean; no deletes ran")]));return lines.join("\n")}let result;try{result=applyDoctorCleaners(params.db,{databasePath:params.config.databasePath,filterIds,vacuum:params.vacuum})}catch(error){lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("status","failed"),buildStatLine("reason",error instanceof Error?error.message:"unknown cleaner apply failure")]));return lines.join("\n")}if(result.kind==="unavailable"){lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("status","unavailable"),buildStatLine("reason",result.reason)]));return lines.join("\n")}const quickCheck=runQuickCheck(params.db);const quickCheckPassed=isPassingQuickCheck(quickCheck);lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("status",quickCheckPassed?"completed":"warning"),buildStatLine("backup path",result.backupPath),buildStatLine("deleted conversations",formatNumber(result.deletedConversations)),buildStatLine("deleted messages",formatNumber(result.deletedMessages)),buildStatLine("vacuumed",formatBoolean(result.vacuumed)),buildStatLine("quick_check",quickCheck),buildStatLine("result",quickCheckPassed?result.deletedConversations>0?`removed ${formatNumber(result.deletedConversations)} conversation(s)`:"clean; no deletes ran":"writes committed, but SQLite integrity verification reported problems; inspect the database or restore from the backup before continuing")]));return lines.join("\n")}async function buildDoctorApplyText(params){const current=await resolveCurrentConversation(params);if(current.kind==="unavailable"){return[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor Apply","",buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason),buildStatLine("fallback","Doctor apply is conversation-scoped, so no global repair ran.")])].join("\n")}const stats=getDoctorSummaryStats(params.db,current.stats.conversationId);let result;try{result=await applyScopedDoctorRepair({db:params.db,config:params.config,conversationId:current.stats.conversationId,deps:params.deps,summarize:params.summarize,runtimeConfig:params.ctx.config})}catch(error){return[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor Apply","",buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",current.stats.sessionKey?formatCommand(truncateMiddle(current.stats.sessionKey,44)):"missing"),buildStatLine("scope","this conversation only")]),"",buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("mode","in-place summary rewrite"),buildStatLine("status","failed"),buildStatLine("reason",error instanceof Error?error.message:"unknown repair failure")])].join("\n")}const lines=[...buildHeaderLines(),"","\u{1FA7A} Lossless Claw Doctor Apply","",buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",current.stats.sessionKey?formatCommand(truncateMiddle(current.stats.sessionKey,44)):"missing"),buildStatLine("scope","this conversation only")]),""];if(result.kind==="unavailable"){lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("mode","in-place summary rewrite"),buildStatLine("status","unavailable"),buildStatLine("reason",result.reason)]));return lines.join("\n")}lines.push(buildSection("\u{1F6E0}\uFE0F Apply",[buildStatLine("mode","in-place summary rewrite"),buildStatLine("detected summaries",formatNumber(stats.total)),buildStatLine("old-marker summaries",formatNumber(stats.old)),buildStatLine("truncated-marker summaries",formatNumber(stats.truncated)),buildStatLine("fallback-marker summaries",formatNumber(stats.fallback)),buildStatLine("repaired summaries",formatNumber(result.repaired)),buildStatLine("unchanged summaries",formatNumber(result.unchanged)),buildStatLine("skipped summaries",formatNumber(result.skipped.length)),buildStatLine("result",stats.total===0?"clean; no writes ran":result.repaired>0?`repaired ${formatNumber(result.repaired)} summary(s) in place`:"no repairs applied")]));if(result.repairedSummaryIds.length>0){lines.push("",buildSection("\u{1F9F7} Repaired summaries",[result.repairedSummaryIds.join(", ")]))}if(result.skipped.length>0){lines.push("",buildSection("\u26A0\uFE0F Deferred",result.skipped.map(item=>`${item.summaryId}: ${item.reason}`)))}return lines.join("\n")}function createLcmCommand(params){const getDb=async()=>typeof params.db==="function"?await params.db():params.db;return{name:"lcm",nativeNames:{default:"lossless"},nativeProgressMessages:{telegram:"Lossless Claw is working..."},description:"Show Lossless Claw health, create DB backups, compact the current session transcript while preserving LCM context, inspect high-confidence junk candidates, and run scoped doctor actions.",acceptsArgs:true,handler:async ctx=>{const parsed=parseLcmCommand(ctx.args);switch(parsed.kind){case"status":return{text:await buildStatusText({ctx,db:await getDb(),config:params.config})};case"backup":return{text:await buildBackupText({db:await getDb(),config:params.config})};case"rotate":return{text:await buildRotateText({ctx,db:await getDb(),config:params.config,deps:params.deps,getLcm:params.getLcm})};case"doctor":return parsed.apply?{text:await buildDoctorApplyText({ctx,db:await getDb(),config:params.config,deps:params.deps,summarize:params.summarize})}:{text:await buildDoctorText({ctx,db:await getDb()})};case"doctor_cleaners":return parsed.apply?{text:await buildDoctorCleanersApplyText({db:await getDb(),config:params.config,filterId:parsed.filterId,vacuum:parsed.vacuum})}:{text:await buildDoctorCleanersText({db:await getDb()})};case"help":return{text:buildHelpText(parsed.error)}}}}}function parseAgentSessionKey(sessionKey){const value=sessionKey.trim();if(!value.startsWith("agent:")){return null}const parts=value.split(":");if(parts.length<3){return null}const agentId=parts[1]?.trim();const suffix=parts.slice(2).join(":").trim();if(!agentId||!suffix){return null}return{agentId,suffix}}function normalizeAgentId(agentId){const normalized=(agentId??"").trim();return normalized.length>0?normalized:"main"}var MODEL_AUTH_PR_URL="https://github.com/openclaw/openclaw/pull/41090";var MODEL_AUTH_MERGE_COMMIT="4790e40";var MODEL_AUTH_REQUIRED_RELEASE="the first OpenClaw release after 2026.3.8";var PROVIDER_API_RESOLUTION_ERROR_PREFIX="[lcm] unable to resolve API family for provider ";var AUTH_ERROR_TEXT_PATTERN2=/\b401\b|unauthorized|unauthorised|invalid[_ -]?token|invalid[_ -]?api[_ -]?key|authentication failed|authorization failed|missing scope|insufficient scope|model\.request\b/i;var AUTH_ERROR_STATUS_KEYS2=["status","statusCode","status_code"];var AUTH_ERROR_NESTED_KEYS2=["error","response","cause","details","data","body"];var LOSSLESS_RECALL_POLICY_PROMPT=["## Lossless Recall Policy","","The lossless-claw plugin is active.","","For compacted conversation history, these instructions supersede generic memory-recall guidance. Prefer lossless-claw recall tools first when answering questions about prior conversation content, decisions made in the conversation, or details that may have been compacted.","","**Conflict handling:** If newer evidence conflicts with an older summary or recollection, prefer the newer evidence. Do not trust a stale summary over fresher contradictory information.","","**Contradictions/uncertainty:** If facts seem contradictory or uncertain, verify with lossless-claw recall tools before answering instead of trusting the summary at face value.","","**Tool escalation:**","Recall order for compacted conversation history:","1. `lcm_grep` \u2014 search by regex or full-text across messages and summaries","2. `lcm_describe` \u2014 inspect a specific summary (cheap, no sub-agent)","3. `lcm_expand_query` \u2014 deep recall: spawns bounded sub-agent, expands DAG, and returns answer plus cited summary IDs in tool output for follow-up (~120s, don't ration it)","","**`lcm_grep` routing guidance:**",'- Prefer `mode: "full_text"` for keyword or topical recall; keep `mode: "regex"` for literal patterns.',"- Full-text queries use FTS5 semantics, and FTS5 defaults to AND matching, so extra terms make matching stricter rather than broader.","- Prefer 1-3 distinctive full-text terms or one quoted phrase. Do not pad queries with synonyms or extra keywords.",'- Wrap exact multi-word phrases in quotes, for example `"error handling"`.','- Keep the default `sort: "recency"` for "what just happened?" lookups.','- Use `sort: "relevance"` when hunting for the best older match on a topic.','- Use `sort: "hybrid"` when relevance matters but newer context should still get a boost.',"","**`lcm_expand_query` usage** \u2014 two patterns (always requires `prompt`):",'- With IDs: `lcm_expand_query(summaryIds: ["sum_xxx"], prompt: "What config changes were discussed?")`','- With search: `lcm_expand_query(query: "database migration", prompt: "What strategy was decided?")`',"- `query` uses the same FTS5 full-text search path as `lcm_grep`, so the same query-construction rules apply.","- `query` is for matching candidate summaries; `prompt` is the natural-language question or task to answer after expansion.","- FTS5 defaults to AND matching, so more query terms narrow results instead of broadening them.","- For `query`, use 1-3 distinctive terms or a quoted phrase. Do not stuff synonyms or extra keywords into it.","**Scope selection rule:**","- Start with the current conversation scope.","- If the in-context summaries already look relevant to the user's question, prefer `lcm_grep` or `lcm_expand_query` without `allConversations`.","- Use `allConversations: true` only when the current summaries do not appear sufficient, the question seems outside the current conversation, or the user is explicitly asking about work across sessions.","- For global discovery, prefer `lcm_grep(..., allConversations: true)` first.","- If global matches are found and the user needs one synthesized answer, use `lcm_expand_query(..., allConversations: true)`; this is bounded synthesis, not exhaustive expansion.","- If you already know the exact target conversation, prefer explicit `conversationId` instead of `allConversations`.","- Optional: `maxTokens` (default 2000), `conversationId`, `allConversations: true`","- Keep raw summary IDs out of normal user-facing prose unless the user explicitly asks for sources or IDs.","","These precedence rules apply only to compacted conversation history. Lossless-claw does not supersede memory tools globally.","","If a summary conflicts with newer evidence, prefer the newer evidence. Do not guess exact commands, SHAs, paths, timestamps, config values, or causal claims from compacted summaries when expansion is needed."].join("\n");function snapshotPluginEnv(env=process.env){return{lcmSummaryModel:env.LCM_SUMMARY_MODEL?.trim()??"",lcmSummaryProvider:env.LCM_SUMMARY_PROVIDER?.trim()??"",pluginSummaryModel:"",pluginSummaryProvider:"",openclawProvider:env.OPENCLAW_PROVIDER?.trim()??"",openclawDefaultModel:"",agentDir:env.OPENCLAW_AGENT_DIR?.trim()||env.PI_CODING_AGENT_DIR?.trim()||"",home:env.HOME?.trim()??"",stateDir:resolveOpenclawStateDir(env)}}function truncateErrorMessage(message,maxChars=240){return message.length<=maxChars?message:`${message.slice(0,maxChars)}...`}function collectErrorText(value,out,depth=0){if(depth>=4){return}if(typeof value==="string"){const trimmed=value.trim();if(trimmed){out.push(trimmed)}return}if(Array.isArray(value)){for(const entry of value.slice(0,8)){collectErrorText(entry,out,depth+1)}return}if(!isRecord2(value)){return}for(const entry of Object.values(value).slice(0,12)){collectErrorText(entry,out,depth+1)}}function extractErrorStatusCode(value,depth=0){if(depth>=4||!isRecord2(value)){return void 0}for(const key of AUTH_ERROR_STATUS_KEYS2){const candidate=value[key];if(typeof candidate==="number"&&Number.isFinite(candidate)){return Math.trunc(candidate)}if(typeof candidate==="string"){const parsed=Number.parseInt(candidate,10);if(Number.isFinite(parsed)){return parsed}}}for(const key of AUTH_ERROR_NESTED_KEYS2){const nested=value[key];const statusCode=extractErrorStatusCode(nested,depth+1);if(statusCode!==void 0){return statusCode}}return void 0}function detectProviderAuthError(error){const statusCode=extractErrorStatusCode(error);const textParts=[];collectErrorText(error,textParts);const normalizedMessage=textParts.join(" ").replace(/\s+/g," ").trim();if(statusCode!==401&&!AUTH_ERROR_TEXT_PATTERN2.test(normalizedMessage)){return void 0}const directCode=isRecord2(error)&&typeof error.code==="string"&&error.code.trim()?error.code.trim():isRecord2(error)&&isRecord2(error.error)&&typeof error.error.code==="string"&&error.error.code.trim()?error.error.code.trim():void 0;return{kind:"provider_auth",...statusCode!==void 0?{statusCode}:{},...directCode?{code:directCode}:{},...normalizedMessage?{message:truncateErrorMessage(normalizedMessage)}:{}}}function readDefaultModelFromConfig(config){if(!config||typeof config!=="object"){return""}const model=config.agents?.defaults?.model;if(typeof model==="string"){return model.trim()}const primary=model?.primary;return typeof primary==="string"?primary.trim():""}function loadEffectiveOpenClawConfig(api){try{const runtimeConfig=api.runtime.config.loadConfig();if(runtimeConfig!==void 0){if(isRecord2(runtimeConfig)&&Object.keys(runtimeConfig).length>0){return runtimeConfig}if(!isRecord2(api.config)||Object.keys(api.config).length===0){return runtimeConfig}}}catch{}return api.config}function readPluginConfigFromOpenClawConfig(openClawConfig,pluginId){if(!isRecord2(openClawConfig)){return void 0}const plugins=openClawConfig.plugins;if(!isRecord2(plugins)){return void 0}const entries=plugins.entries;if(!isRecord2(entries)){return void 0}const entry=entries[pluginId];if(!isRecord2(entry)||!isRecord2(entry.config)){return void 0}return entry.config}function resolveRegistrationConfig(api){const openClawConfig=loadEffectiveOpenClawConfig(api);const apiPluginConfig=api.pluginConfig&&typeof api.pluginConfig==="object"&&!Array.isArray(api.pluginConfig)?api.pluginConfig:void 0;if(apiPluginConfig&&Object.keys(apiPluginConfig).length>0){return{openClawConfig,pluginConfig:apiPluginConfig}}return{openClawConfig,pluginConfig:readPluginConfigFromOpenClawConfig(openClawConfig,api.id)}}function readCompactionModelFromConfig(config){if(!config||typeof config!=="object"){return""}const compaction=config.agents?.defaults?.compaction;const model=compaction?.model;if(typeof model==="string"){return model.trim()}const primary=model?.primary;return typeof primary==="string"?primary.trim():""}function formatProviderModel(params){return`${params.provider}/${params.model}`}function buildCompactionModelLog(params){const envSummaryModel=process.env.LCM_SUMMARY_MODEL?.trim()??"";const envSummaryProvider=process.env.LCM_SUMMARY_PROVIDER?.trim()??"";const pluginSummaryModel=params.config.summaryModel.trim();const pluginSummaryProvider=params.config.summaryProvider.trim();const compactionModelRef=readCompactionModelFromConfig(params.openClawConfig);const defaultModelRef=readDefaultModelFromConfig(params.openClawConfig);const selected=envSummaryModel?{raw:envSummaryModel,source:"override"}:pluginSummaryModel?{raw:pluginSummaryModel,source:"override"}:compactionModelRef?{raw:compactionModelRef,source:"override"}:defaultModelRef?{raw:defaultModelRef,source:"default"}:void 0;const usingOverride=selected?.source==="override"||Boolean(envSummaryProvider||pluginSummaryProvider);const raw=selected?.raw.trim()??"";if(!raw){return"[lcm] Compaction summarization model: (unconfigured)"}if(raw.includes("/")){const[provider2,...rest]=raw.split("/");const model=rest.join("/").trim();if(provider2&&model){return`[lcm] Compaction summarization model: ${formatProviderModel({provider:provider2.trim(),model})} (${usingOverride?"override":"default"})`}}const provider=(envSummaryProvider||pluginSummaryProvider||params.defaultProvider||"openai").trim();return`[lcm] Compaction summarization model: ${formatProviderModel({provider,model:raw})} (${usingOverride?"override":"default"})`}function resolveApiKey(provider,readEnv){const keyMap={openai:["OPENAI_API_KEY"],anthropic:["ANTHROPIC_API_KEY"],google:["GOOGLE_API_KEY","GEMINI_API_KEY"],groq:["GROQ_API_KEY"],xai:["XAI_API_KEY"],mistral:["MISTRAL_API_KEY"],together:["TOGETHER_API_KEY"],openrouter:["OPENROUTER_API_KEY"],"github-copilot":["GITHUB_COPILOT_API_KEY","GITHUB_TOKEN"]};const providerKey=provider.trim().toLowerCase();const keys=keyMap[providerKey]??[];const normalizedProviderEnv=`${providerKey.replace(/[^a-z0-9]/g,"_").toUpperCase()}_API_KEY`;keys.push(normalizedProviderEnv);for(const key of keys){const value=readEnv(key)?.trim();if(value){return value}}return void 0}function isRecord2(value){return!!value&&typeof value==="object"&&!Array.isArray(value)}function normalizeProviderId2(provider){return provider.trim().toLowerCase()}function inferApiFromProvider(provider){const normalized=normalizeProviderId2(provider);const map={anthropic:"anthropic-messages",openai:"openai-responses","openai-codex":"openai-codex-responses","github-copilot":"openai-codex-responses",google:"google-generative-ai","google-gemini-cli":"google-gemini-cli","google-antigravity":"google-gemini-cli","google-vertex":"google-vertex","amazon-bedrock":"bedrock-converse-stream",ollama:"openai-completions"};return map[normalized]}function shouldOmitTemperatureForApi(api){return(api??"").trim().toLowerCase()==="openai-codex-responses"}function buildCompleteSimpleOptions(params){const options={apiKey:params.apiKey,maxTokens:params.maxTokens};if(typeof params.temperature==="number"&&Number.isFinite(params.temperature)&&!shouldOmitTemperatureForApi(params.api)){options.temperature=params.temperature}if(typeof params.reasoning==="string"&¶ms.reasoning.trim()){options.reasoning=params.reasoning.trim()}return options}function resolveEffectiveReasoning(params){if(typeof params.reasoning==="string"&¶ms.reasoning.trim()){return params.reasoning.trim()}if(params.modelSupportsReasoning===true&&typeof params.reasoningIfSupported==="string"&¶ms.reasoningIfSupported.trim()){return params.reasoningIfSupported.trim()}return void 0}function findProviderConfigValue(map,provider){if(!map){return void 0}if(map[provider]!==void 0){return map[provider]}const normalizedProvider=normalizeProviderId2(provider);for(const[key,value]of Object.entries(map)){if(normalizeProviderId2(key)===normalizedProvider){return value}}return void 0}function resolveProviderApiFromRuntimeConfig(runtimeConfig,provider){if(!isRecord2(runtimeConfig)){return void 0}const providers=runtimeConfig.models?.providers;if(!providers||!isRecord2(providers)){return void 0}const value=findProviderConfigValue(providers,provider);if(!isRecord2(value)){return void 0}const api=value.api;return typeof api==="string"&&api.trim()?api.trim():void 0}function getRuntimeModelAuth(api){const runtime=api.runtime;return runtime.modelAuth}function buildModelAuthLookupModel(params){const contextWindow=typeof params.contextWindow==="number"&&Number.isFinite(params.contextWindow)&¶ms.contextWindow>0?params.contextWindow:1e6;return{id:params.model,name:params.model,provider:params.provider,api:params.api?.trim()||inferApiFromProvider(params.provider)||"",reasoning:false,input:["text"],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow,maxTokens:8e3}}function resolveApiKeyFromAuthResult(auth){const apiKey=auth?.apiKey?.trim();return apiKey?apiKey:void 0}function resolveBaseUrlFromAuthResult(auth){const baseUrl=auth?.baseUrl?.trim();return baseUrl?baseUrl:void 0}function resolveRuntimeAuthHeaders(request){if(!request){return void 0}const headers={};if(isRecord2(request.headers)){for(const[key,value]of Object.entries(request.headers)){if(typeof value!=="string"){continue}const headerName=key.trim();const headerValue=value.trim();if(headerName&&headerValue){headers[headerName]=headerValue}}}const auth=request.auth;if(auth?.mode==="authorization-bearer"){const token=auth.token.trim();if(token){for(const key of Object.keys(headers)){if(key.toLowerCase()==="authorization"){delete headers[key]}}headers.Authorization=`Bearer ${token}`}}else if(auth?.mode==="header"){const headerName=auth.headerName.trim();const value=auth.value.trim();if(headerName&&value){const normalizedHeader=headerName.toLowerCase();for(const key of Object.keys(headers)){if(key.toLowerCase()===normalizedHeader||normalizedHeader!=="authorization"&&key.toLowerCase()==="authorization"){delete headers[key]}}headers[headerName]=`${auth.prefix?.trim()??""}${value}`}}return Object.keys(headers).length>0?headers:void 0}function attachRuntimeAuthRequestTransport(model,request){if(!request){return model}const next={...model};next[Symbol.for("openclaw.modelProviderRequestTransport")]=request;return next}function buildLegacyAuthFallbackWarning(){return["[lcm] OpenClaw runtime.modelAuth is unavailable; using legacy auth-profiles fallback.",`Stock lossless-claw 0.2.7 expects OpenClaw plugin runtime support from PR #41090 (${MODEL_AUTH_PR_URL}).`,`OpenClaw 2026.3.8 and 2026.3.8-beta.1 do not include merge commit ${MODEL_AUTH_MERGE_COMMIT};`,`${MODEL_AUTH_REQUIRED_RELEASE} is required for stock lossless-claw 0.2.7 without this fallback patch.`].join(" ")}function parseAuthProfileStore(raw){try{const parsed=JSON.parse(raw);if(!isRecord2(parsed)||!isRecord2(parsed.profiles)){return void 0}const profiles={};for(const[profileId,value]of Object.entries(parsed.profiles)){if(!isRecord2(value)){continue}const type=value.type;const provider=typeof value.provider==="string"?value.provider.trim():"";if(!provider||type!=="api_key"&&type!=="token"&&type!=="oauth"){continue}profiles[profileId]=value}const rawOrder=isRecord2(parsed.order)?parsed.order:void 0;const order=rawOrder?Object.entries(rawOrder).reduce((acc,[provider,value])=>{if(!Array.isArray(value)){return acc}const ids=value.map(entry=>typeof entry==="string"?entry.trim():"").filter(Boolean);if(ids.length>0){acc[provider]=ids}return acc},{}):void 0;return{profiles,...order&&Object.keys(order).length>0?{order}:{}}}catch{return void 0}}function mergeAuthProfileStores(stores){if(stores.length===0){return void 0}const merged={profiles:{}};for(const store of stores){merged.profiles={...merged.profiles,...store.profiles};if(store.order){merged.order={...merged.order??{},...store.order}}}return merged}function resolveAuthStorePaths(params){const paths=[];const directAgentDir=params.agentDir?.trim();if(directAgentDir){paths.push(join4(directAgentDir,"auth-profiles.json"))}const envAgentDir=params.envSnapshot.agentDir;if(envAgentDir){paths.push(join4(envAgentDir,"auth-profiles.json"))}const stateDir=params.envSnapshot.stateDir;if(stateDir){paths.push(join4(stateDir,"agents","main","agent","auth-profiles.json"))}return[...new Set(paths)]}function resolveAuthProfileCandidates(params){const candidates=[];const normalizedProvider=normalizeProviderId2(params.provider);const push=value=>{const profileId=value?.trim();if(!profileId){return}if(!candidates.includes(profileId)){candidates.push(profileId)}};push(params.authProfileId);const storeOrder=findProviderConfigValue(params.store.order,params.provider);for(const profileId of storeOrder??[]){push(profileId)}if(isRecord2(params.runtimeConfig)){const auth=params.runtimeConfig.auth;if(isRecord2(auth)){const order=findProviderConfigValue(isRecord2(auth.order)?auth.order:void 0,params.provider);if(Array.isArray(order)){for(const profileId of order){if(typeof profileId==="string"){push(profileId)}}}}}for(const[profileId,credential]of Object.entries(params.store.profiles)){if(normalizeProviderId2(credential.provider)===normalizedProvider){push(profileId)}}return candidates}function resolveSecretRef(params){const ref=params.ref;if(!ref?.id)return void 0;if(ref.source==="env"){const val=process.env[ref.id]?.trim();return val||void 0}try{const providers=isRecord2(params.config)?params.config.secrets?.providers:void 0;const providerName=ref.provider?.trim()||"default";const provider=providers&&isRecord2(providers)?providers[providerName]:void 0;if(isRecord2(provider)&&provider.source==="file"&&typeof provider.path==="string"){const configuredPath=provider.path.trim();const filePath=configuredPath.startsWith("~/")&¶ms.home?join4(params.home,configuredPath.slice(2)):configuredPath;if(!filePath){return void 0}const raw=readFileSync(filePath,"utf8");if(provider.mode==="singleValue"){if(ref.id.trim()!=="value"){return void 0}const value=raw.trim();return value||void 0}const secrets=JSON.parse(raw);const parts=ref.id.replace(/^\//,"").split("/");let current=secrets;for(const part of parts){if(!current||typeof current!=="object")return void 0;current=current[part]}return typeof current==="string"&¤t.trim()?current.trim():void 0}}catch{}try{const secretsPath=join4(params.stateDir,"secrets.json");const raw=readFileSync(secretsPath,"utf8");const secrets=JSON.parse(raw);const parts=ref.id.replace(/^\//,"").split("/");let current=secrets;for(const part of parts){if(!current||typeof current!=="object")return void 0;current=current[part]}return typeof current==="string"&¤t.trim()?current.trim():void 0}catch{return void 0}}async function resolveApiKeyFromAuthProfiles(params){const storesWithPaths=resolveAuthStorePaths({agentDir:params.agentDir,envSnapshot:params.envSnapshot}).map(path=>{try{const parsed=parseAuthProfileStore(readFileSync(path,"utf8"));return parsed?{path,store:parsed}:void 0}catch{return void 0}}).filter(entry=>!!entry);if(storesWithPaths.length===0){return void 0}const mergedStore=mergeAuthProfileStores(storesWithPaths.map(entry=>entry.store));if(!mergedStore){return void 0}const candidates=resolveAuthProfileCandidates({provider:params.provider,store:mergedStore,authProfileId:params.authProfileId,runtimeConfig:params.runtimeConfig});if(candidates.length===0){return void 0}const persistPath=params.agentDir?.trim()?join4(params.agentDir.trim(),"auth-profiles.json"):storesWithPaths[0]?.path;const secretConfig=(()=>{if(isRecord2(params.runtimeConfig)){const runtimeProviders=params.runtimeConfig.secrets?.providers;if(isRecord2(runtimeProviders)&&Object.keys(runtimeProviders).length>0){return params.runtimeConfig}}return params.appConfig??params.runtimeConfig})();for(const profileId of candidates){const credential=mergedStore.profiles[profileId];if(!credential){continue}if(normalizeProviderId2(credential.provider)!==normalizeProviderId2(params.provider)){continue}if(credential.type==="api_key"){const key=credential.key?.trim()||resolveSecretRef({ref:credential.keyRef,home:params.envSnapshot.home,stateDir:params.envSnapshot.stateDir,config:secretConfig});if(key){return key}continue}if(credential.type==="token"){const token=credential.token?.trim()||resolveSecretRef({ref:credential.tokenRef,home:params.envSnapshot.home,stateDir:params.envSnapshot.stateDir,config:secretConfig});if(!token){continue}const expires2=credential.expires;if(typeof expires2==="number"&&Number.isFinite(expires2)&&expires2>0&&Date.now()>=expires2){continue}return token}const access=credential.access?.trim();const expires=credential.expires;const isExpired=typeof expires==="number"&&Number.isFinite(expires)&&expires>0&&Date.now()>=expires;const shouldPreferOAuthHelper=typeof params.piAiModule.getOAuthApiKey==="function"&&normalizeProviderId2(params.provider)==="openai-codex";if(shouldPreferOAuthHelper){try{const oauthCredential={access:credential.access??"",refresh:credential.refresh??"",expires:typeof credential.expires==="number"?credential.expires:0,...typeof credential.projectId==="string"?{projectId:credential.projectId}:{},...typeof credential.accountId==="string"?{accountId:credential.accountId}:{}};const refreshed=await params.piAiModule.getOAuthApiKey(params.provider,{[params.provider]:oauthCredential});if(refreshed?.apiKey){mergedStore.profiles[profileId]={...credential,...refreshed.newCredentials,type:"oauth"};if(persistPath){try{writeFileSync(persistPath,JSON.stringify({version:1,profiles:mergedStore.profiles,...mergedStore.order?{order:mergedStore.order}:{}},null,2),"utf8")}catch{}}return refreshed.apiKey}}catch{}}if(!isExpired&&access){if((credential.provider==="google-gemini-cli"||credential.provider==="google-antigravity")&&typeof credential.projectId==="string"&&credential.projectId.trim()){return JSON.stringify({token:access,projectId:credential.projectId.trim()})}return access}if(typeof params.piAiModule.getOAuthApiKey!=="function"){continue}try{const oauthCredential={access:credential.access??"",refresh:credential.refresh??"",expires:typeof credential.expires==="number"?credential.expires:0,...typeof credential.projectId==="string"?{projectId:credential.projectId}:{},...typeof credential.accountId==="string"?{accountId:credential.accountId}:{}};const refreshed=await params.piAiModule.getOAuthApiKey(params.provider,{[params.provider]:oauthCredential});if(!refreshed?.apiKey){continue}mergedStore.profiles[profileId]={...credential,...refreshed.newCredentials,type:"oauth"};if(persistPath){try{writeFileSync(persistPath,JSON.stringify({version:1,profiles:mergedStore.profiles,...mergedStore.order?{order:mergedStore.order}:{}},null,2),"utf8")}catch{}}return refreshed.apiKey}catch{if(access){return access}}}return void 0}function buildSubagentSystemPrompt(params){const task=params.taskSummary?.trim()||"Perform delegated LCM expansion work.";return["You are a delegated sub-agent for LCM expansion.",`Depth: ${params.depth}/${params.maxDepth}`,"Return concise, factual results only.",task].join("\n")}function readLatestAssistantReply(messages){for(let i=messages.length-1;i>=0;i--){const item=messages[i];if(!item||typeof item!=="object"){continue}const record=item;if(record.role!=="assistant"){continue}if(typeof record.content==="string"){const trimmed=record.content.trim();if(trimmed){return trimmed}continue}if(!Array.isArray(record.content)){continue}const text=record.content.filter(entry=>{return!!entry&&typeof entry==="object"}).map(entry=>entry.type==="text"&&typeof entry.text==="string"?entry.text:"").filter(Boolean).join("\n").trim();if(text){return text}}return void 0}function createLcmDependencies(api,registrationConfig=resolveRegistrationConfig(api)){const envSnapshot=snapshotPluginEnv();envSnapshot.openclawDefaultModel=readDefaultModelFromConfig(registrationConfig.openClawConfig);const modelAuth=getRuntimeModelAuth(api);const readEnv=key=>process.env[key];const pluginConfig=registrationConfig.pluginConfig;const log=createLcmLogger(api);const{config,diagnostics}=resolveLcmConfigWithDiagnostics(process.env,pluginConfig);if(diagnostics.ignoreSessionPatternsEnvOverridesPluginConfig){logStartupBannerOnce({key:"ignore-session-patterns-env-override",log:message=>log.warn(message),message:"[lcm] LCM_IGNORE_SESSION_PATTERNS from env overrides plugins.entries.lossless-claw.config.ignoreSessionPatterns; plugin config array will be ignored"})}if(diagnostics.statelessSessionPatternsEnvOverridesPluginConfig){logStartupBannerOnce({key:"stateless-session-patterns-env-override",log:message=>log.warn(message),message:"[lcm] LCM_STATELESS_SESSION_PATTERNS from env overrides plugins.entries.lossless-claw.config.statelessSessionPatterns; plugin config array will be ignored"})}if(pluginConfig){const summaryModel=pluginConfig.summaryModel;const summaryProvider=pluginConfig.summaryProvider;if(typeof summaryModel==="string"){envSnapshot.pluginSummaryModel=summaryModel.trim()}if(typeof summaryProvider==="string"){envSnapshot.pluginSummaryProvider=summaryProvider.trim()}}if(!modelAuth){log.warn(buildLegacyAuthFallbackWarning())}logStartupBannerOnce({key:"transcript-gc-enabled",log:message=>log.info(message),message:`[lcm] Transcript GC ${config.transcriptGcEnabled?"enabled":"disabled"} (default false)`});logStartupBannerOnce({key:"proactive-threshold-compaction-mode",log:message=>log.info(message),message:`[lcm] Proactive threshold compaction mode: ${config.proactiveThresholdCompactionMode} (default deferred)`});const resolveModelAuthConfig=runtimeConfig=>{if(runtimeConfig&&typeof runtimeConfig==="object"){return runtimeConfig}return api.config};const lookupApiKey=async(provider,model,options)=>{const modelAuthConfig=resolveModelAuthConfig(options?.runtimeConfig);if(modelAuth&&options?.skipModelAuth!==true){try{const modelAuthKey=resolveApiKeyFromAuthResult(await modelAuth.getApiKeyForModel({model:buildModelAuthLookupModel({provider,model,contextWindow:1e6}),cfg:modelAuthConfig,...options?.profileId?{profileId:options.profileId}:{},...options?.preferredProfile?{preferredProfile:options.preferredProfile}:{}}));if(modelAuthKey){return modelAuthKey}}catch{}}const envKey=resolveApiKey(provider,readEnv);if(envKey){return envKey}const piAiModuleId="@mariozechner/pi-ai";const mod=await import(piAiModuleId);return resolveApiKeyFromAuthProfiles({provider,authProfileId:options?.profileId,agentDir:options?.agentDir??api.resolvePath("."),runtimeConfig:options?.runtimeConfig,appConfig:api.config,piAiModule:mod,envSnapshot})};return{config,configDiagnostics:diagnostics,isRuntimeManagedAuthProvider:(provider,providerApi)=>{const normalizedProvider=normalizeProviderId2(provider);if(normalizedProvider==="openai-codex"||normalizedProvider==="github-copilot"){return true}return shouldOmitTemperatureForApi(providerApi)},complete:async({provider,model,apiKey,providerApi,authProfileId,agentDir,runtimeConfig,skipModelAuth,messages,system,maxTokens,temperature,reasoning,reasoningIfSupported})=>{try{const piAiModuleId="@mariozechner/pi-ai";const mod=await import(piAiModuleId);if(typeof mod.completeSimple!=="function"){return{content:[]}}const providerId=(provider??"").trim();const modelId=model.trim();if(!providerId||!modelId){return{content:[]}}const workspaceDir=agentDir?.trim()||api.resolvePath(".");let effectiveRuntimeConfig=runtimeConfig;if(!isRecord2(effectiveRuntimeConfig)){try{effectiveRuntimeConfig=api.runtime.config.loadConfig()}catch{}}const knownModel=typeof mod.getModel==="function"?mod.getModel(providerId,modelId):void 0;const fallbackApi=(isRecord2(knownModel)&&typeof knownModel.api==="string"&&knownModel.api.trim()?knownModel.api.trim():void 0)||providerApi?.trim()||resolveProviderApiFromRuntimeConfig(effectiveRuntimeConfig,providerId)||(()=>{if(typeof mod.getModels!=="function"){return void 0}const models=mod.getModels(providerId);const first=Array.isArray(models)?models[0]:void 0;if(!isRecord2(first)||typeof first.api!=="string"||!first.api.trim()){return void 0}return first.api.trim()})()||inferApiFromProvider(providerId);if(!fallbackApi){throw new Error(`[lcm] unable to resolve API family for provider ${providerId}; set models.providers.${providerId}.api explicitly instead of falling back implicitly.`)}const modelAuthConfig=resolveModelAuthConfig(effectiveRuntimeConfig);const providerLevelConfig=(()=>{if(!isRecord2(effectiveRuntimeConfig))return{};const providers=effectiveRuntimeConfig.models?.providers;if(!providers)return{};const cfg=findProviderConfigValue(providers,providerId);return isRecord2(cfg)?cfg:{}})();let resolvedModel=isRecord2(knownModel)&&typeof knownModel.api==="string"&&typeof knownModel.provider==="string"&&typeof knownModel.id==="string"?{...knownModel,id:knownModel.id,provider:knownModel.provider,api:typeof providerLevelConfig.api==="string"&&providerLevelConfig.api.trim()?providerLevelConfig.api.trim():knownModel.api,baseUrl:typeof providerLevelConfig.baseUrl==="string"?providerLevelConfig.baseUrl:typeof knownModel.baseUrl==="string"?knownModel.baseUrl:"",...isRecord2(providerLevelConfig.headers)?{headers:{...isRecord2(knownModel.headers)?knownModel.headers:{},...providerLevelConfig.headers}}:{}}:{id:modelId,name:modelId,provider:providerId,api:fallbackApi,reasoning:false,input:["text"],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:1e6,maxTokens:8e3,baseUrl:typeof providerLevelConfig.baseUrl==="string"?providerLevelConfig.baseUrl:"",...isRecord2(providerLevelConfig.headers)?{headers:providerLevelConfig.headers}:{}};let runtimeAuth;if(modelAuth&&skipModelAuth!==true&&typeof modelAuth.getRuntimeAuthForModel==="function"){try{runtimeAuth=await modelAuth.getRuntimeAuthForModel({model:buildModelAuthLookupModel({provider:providerId,model:modelId,api:resolvedModel.api,contextWindow:resolvedModel.contextWindow}),cfg:modelAuthConfig,...authProfileId?{profileId:authProfileId}:{},workspaceDir})}catch(err){console.error(`[lcm] modelAuth.getRuntimeAuthForModel FAILED:`,err instanceof Error?err.message:err)}}const runtimeAuthBaseUrl=resolveBaseUrlFromAuthResult(runtimeAuth);const runtimeAuthHeaders=resolveRuntimeAuthHeaders(runtimeAuth?.request);resolvedModel=attachRuntimeAuthRequestTransport({...resolvedModel,...runtimeAuthBaseUrl?{baseUrl:runtimeAuthBaseUrl}:{},...runtimeAuthHeaders?{headers:{...isRecord2(resolvedModel.headers)?resolvedModel.headers:{},...runtimeAuthHeaders}}:{}},runtimeAuth?.request);let resolvedApiKey=apiKey?.trim();if(!resolvedApiKey){resolvedApiKey=resolveApiKeyFromAuthResult(runtimeAuth)}if(!resolvedApiKey&&modelAuth&&skipModelAuth!==true){try{resolvedApiKey=resolveApiKeyFromAuthResult(await modelAuth.getApiKeyForModel({model:buildModelAuthLookupModel({provider:providerId,model:modelId,api:resolvedModel.api,contextWindow:resolvedModel.contextWindow}),cfg:modelAuthConfig,...authProfileId?{profileId:authProfileId}:{}}))}catch(err){log.warn(`[lcm] modelAuth.getApiKeyForModel FAILED: ${describeLogError(err)}`)}}if(!resolvedApiKey&&modelAuth&&skipModelAuth!==true){try{resolvedApiKey=resolveApiKeyFromAuthResult(await modelAuth.resolveApiKeyForProvider({provider:providerId,cfg:modelAuthConfig,...authProfileId?{profileId:authProfileId}:{}}))}catch(err){log.warn(`[lcm] modelAuth.resolveApiKeyForProvider FAILED: ${describeLogError(err)}`)}}if(!resolvedApiKey){resolvedApiKey=resolveApiKey(providerId,readEnv)}if(!resolvedApiKey&&typeof mod.getEnvApiKey==="function"){resolvedApiKey=mod.getEnvApiKey(providerId)?.trim()}if(!resolvedApiKey){resolvedApiKey=await resolveApiKeyFromAuthProfiles({provider:providerId,authProfileId,agentDir,appConfig:api.config,runtimeConfig:effectiveRuntimeConfig,piAiModule:mod,envSnapshot})}if(!resolvedApiKey&&isRecord2(effectiveRuntimeConfig)){const providers=effectiveRuntimeConfig.models?.providers;if(providers){const providerCfg=findProviderConfigValue(providers,providerId);if(isRecord2(providerCfg)&&typeof providerCfg.apiKey==="string"){const cfgKey=providerCfg.apiKey.trim();if(cfgKey){resolvedApiKey=cfgKey}}}}const effectiveReasoning=resolveEffectiveReasoning({reasoning,reasoningIfSupported,modelSupportsReasoning:resolvedModel.reasoning});const completeOptions=buildCompleteSimpleOptions({api:resolvedModel.api,apiKey:resolvedApiKey,maxTokens,temperature,reasoning:effectiveReasoning});const requestMetadata={request_provider:providerId,request_model:modelId,request_api:resolvedModel.api,request_reasoning:effectiveReasoning??"(none)",request_has_system:typeof system==="string"&&system.trim().length>0?"true":"false",request_temperature:typeof completeOptions.temperature==="number"?String(completeOptions.temperature):"(omitted)",request_temperature_sent:typeof completeOptions.temperature==="number"?"true":"false"};const result=await mod.completeSimple(resolvedModel,{...typeof system==="string"&&system.trim()?{systemPrompt:system.trim()}:{},messages:messages.map(message=>({role:message.role,content:message.content,timestamp:Date.now()}))},completeOptions);if(!isRecord2(result)){return{content:[],...requestMetadata}}return{...result,content:Array.isArray(result.content)?result.content:[],...requestMetadata}}catch(err){log.error(`[lcm] completeSimple error: ${describeLogError(err)}`);const authError=detectProviderAuthError(err);const configError=!authError&&err instanceof Error&&err.message.startsWith(PROVIDER_API_RESOLUTION_ERROR_PREFIX)?{kind:"provider_config",message:err.message}:void 0;return{content:[],...authError?{error:authError}:{},...configError?{error:configError}:{}}}},callGateway:async params=>{const sub=api.runtime.subagent;switch(params.method){case"agent":return sub.run({sessionKey:String(params.params?.sessionKey??""),message:String(params.params?.message??""),provider:params.params?.provider,model:params.params?.model,extraSystemPrompt:params.params?.extraSystemPrompt,lane:params.params?.lane,deliver:params.params?.deliver??false,idempotencyKey:params.params?.idempotencyKey});case"agent.wait":return sub.waitForRun({runId:String(params.params?.runId??""),timeoutMs:params.params?.timeoutMs??params.timeoutMs});case"sessions.get":return sub.getSession({sessionKey:String(params.params?.key??""),limit:params.params?.limit});case"sessions.delete":await sub.deleteSession({sessionKey:String(params.params?.key??""),deleteTranscript:params.params?.deleteTranscript??true});return{};default:throw new Error(`Unsupported gateway method in LCM plugin: ${params.method}`)}},resolveModel:(modelRef,providerHint)=>{const raw=(envSnapshot.lcmSummaryModel||config.summaryModel||modelRef?.trim()||envSnapshot.openclawDefaultModel).trim();if(!raw){throw new Error("No model configured for LCM summarization.")}if(raw.includes("/")){const[provider2,...rest]=raw.split("/");const model=rest.join("/").trim();if(provider2&&model){return{provider:provider2.trim(),model}}}const provider=(providerHint?.trim()||envSnapshot.lcmSummaryProvider||config.summaryProvider||envSnapshot.openclawProvider||"openai").trim();return{provider,model:raw}},getApiKey:async(provider,model,options)=>{return lookupApiKey(provider,model,options)},requireApiKey:async(provider,model,options)=>{const key=await lookupApiKey(provider,model,options);if(!key){throw new Error(`Missing API key for provider '${provider}' (model '${model}').`)}return key},parseAgentSessionKey,isSubagentSessionKey:sessionKey=>{const parsed=parseAgentSessionKey(sessionKey);return!!parsed&&parsed.suffix.startsWith("subagent:")},normalizeAgentId,buildSubagentSystemPrompt,readLatestAssistantReply,resolveAgentDir:()=>api.resolvePath("."),resolveSessionIdFromSessionKey:async sessionKey=>{const key=sessionKey.trim();if(!key){return void 0}try{const cfg=api.runtime.config.loadConfig();const parsed=parseAgentSessionKey(key);const agentId=normalizeAgentId(parsed?.agentId);const storePath=api.runtime.agent.session.resolveStorePath(cfg.session?.store,{agentId});const store=api.runtime.agent.session.loadSessionStore(storePath);const sessionId=store[key]?.sessionId;return typeof sessionId==="string"&&sessionId.trim()?sessionId.trim():void 0}catch{return void 0}},resolveSessionTranscriptFile:async({sessionId,sessionKey})=>{const normalizedSessionId=sessionId.trim();if(!normalizedSessionId){return void 0}try{const cfg=api.runtime.config.loadConfig();const normalizedSessionKey=sessionKey?.trim();const parsed=normalizedSessionKey?parseAgentSessionKey(normalizedSessionKey):null;const agentId=normalizeAgentId(parsed?.agentId);const storePath=api.runtime.agent.session.resolveStorePath(cfg.session?.store,{agentId});const store=api.runtime.agent.session.loadSessionStore(storePath);const entry=(normalizedSessionKey?store[normalizedSessionKey]:void 0)??Object.values(store).find(candidate=>candidate?.sessionId===normalizedSessionId);const transcriptPath=api.runtime.agent.session.resolveSessionFilePath(normalizedSessionId,entry,{agentId,storePath});return transcriptPath.trim()||void 0}catch{return void 0}},agentLaneSubagent:"subagent",log}}function wirePluginHandlers(api,deps,shared){api.on("before_reset",async(event,ctx)=>{await(await shared.waitForEngine()).handleBeforeReset({reason:event.reason,sessionId:ctx.sessionId,sessionKey:ctx.sessionKey})});api.on("before_prompt_build",()=>({prependSystemContext:LOSSLESS_RECALL_POLICY_PROMPT}));api.on("session_end",async event=>{const lifecycleEvent=event;await(await shared.waitForEngine()).handleSessionEnd({reason:lifecycleEvent.reason,sessionId:lifecycleEvent.sessionId,sessionKey:lifecycleEvent.sessionKey,nextSessionId:lifecycleEvent.nextSessionId,nextSessionKey:lifecycleEvent.nextSessionKey})});api.registerContextEngine("lossless-claw",()=>shared.getCachedEngine()??shared.waitForEngine());api.registerContextEngine("default",()=>shared.getCachedEngine()??shared.waitForEngine());api.registerTool(ctx=>createLcmGrepTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey}));api.registerTool(ctx=>createLcmDescribeTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey}));api.registerTool(ctx=>createLcmExpandTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey}));api.registerTool(ctx=>createLcmExpandQueryTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey,requesterSessionKey:ctx.sessionKey}));api.registerCommand(createLcmCommand({db:shared.waitForDatabase,config:deps.config,deps,getLcm:shared.waitForEngine}))}var lcmPlugin={id:"lossless-claw",name:"Lossless Context Management",description:"DAG-based conversation summarization with incremental compaction, full-text search, and sub-agent expansion",configSchema:{parse(value){const raw=value&&typeof value==="object"&&!Array.isArray(value)?value:{};return resolveLcmConfigWithDiagnostics(process.env,raw).config}},register(api){const registrationConfig=resolveRegistrationConfig(api);const deps=createLcmDependencies(api,registrationConfig);const dbPath=deps.config.databasePath;const normalizedDbPath=normalizePath(dbPath);const existingInit=getSharedInit(normalizedDbPath);if(existingInit&&!existingInit.stopped){deps.log.info(`[lcm] Reusing shared engine init for db=${normalizedDbPath}`);wirePluginHandlers(api,deps,existingInit);return}let database=null;let lcm=null;let initPromise=null;let initError=null;let resolveDeferredInit=null;let rejectDeferredInit=null;let stopped=false;function toInitError(error){return error instanceof Error?error:new Error(String(error))}function initializeEngine(){const startedAt=Date.now();const nextDatabase=createLcmDatabaseConnection(dbPath);try{const nextEngine=new LcmContextEngine(deps,nextDatabase);database=nextDatabase;lcm=nextEngine;initError=null;deps.log.info(`[lcm] Engine initialized for db=${normalizedDbPath} duration=${Date.now()-startedAt}ms`);return nextEngine}catch(error){closeLcmConnection(nextDatabase);deps.log.info(`[lcm] Engine init failed for db=${normalizedDbPath} duration=${Date.now()-startedAt}ms error=${toInitError(error).message}`);throw error}}function ensureDeferredInitPromise(){if(initPromise){return initPromise}initPromise=new Promise((resolve2,reject)=>{resolveDeferredInit=resolve2;rejectDeferredInit=reject});initPromise.catch(()=>{});return initPromise}function resolveDeferredEngine(nextEngine){const resolve2=resolveDeferredInit;resolveDeferredInit=null;rejectDeferredInit=null;resolve2?.(nextEngine)}function rejectDeferredEngine(error){initError=error;const reject=rejectDeferredInit;resolveDeferredInit=null;rejectDeferredInit=null;reject?.(error)}async function waitForEngine(){if(stopped){throw new Error("[lcm] Database connection closed after gateway_stop")}if(initError){throw initError}if(lcm){return lcm}if(initPromise){return initPromise}try{const nextEngine=initializeEngine();initPromise=Promise.resolve(nextEngine);return nextEngine}catch(error){const normalized=toInitError(error);if(!/database is locked/i.test(normalized.message)){initError=normalized;throw normalized}deps.log.warn("[lcm] DB locked during eager init, deferring to gateway_start");return ensureDeferredInitPromise()}}async function waitForDatabase(){await waitForEngine();if(!database){throw initError??new Error("[lcm] Database initialization finished without a handle")}return database}try{const nextEngine=initializeEngine();initPromise=Promise.resolve(nextEngine)}catch(error){const normalized=toInitError(error);if(!/database is locked/i.test(normalized.message)){initError=normalized;throw normalized}deps.log.warn("[lcm] DB locked during eager init, deferring to gateway_start");ensureDeferredInitPromise();api.on("gateway_start",async()=>{if(stopped||lcm||initError){return}try{const nextEngine=initializeEngine();initPromise=Promise.resolve(nextEngine);resolveDeferredEngine(nextEngine)}catch(retryError){const normalizedRetryError=toInitError(retryError);rejectDeferredEngine(normalizedRetryError);deps.log.error(`[lcm] Deferred DB init failed: ${normalizedRetryError.message}`)}})}const shared={stopped:false,getCachedEngine:()=>lcm,waitForEngine,waitForDatabase};setSharedInit(normalizedDbPath,shared);api.on("gateway_stop",async()=>{stopped=true;shared.stopped=true;if(!lcm&&!database){rejectDeferredEngine(new Error("[lcm] Database connection closed after gateway_stop"))}if(database){closeLcmConnection(database);database=null}lcm=null;removeSharedInit(normalizedDbPath)});wirePluginHandlers(api,deps,shared);logStartupBannerOnce({key:"plugin-loaded",log:message=>deps.log.info(message),message:`[lcm] Plugin loaded (enabled=${deps.config.enabled}, db=${deps.config.databasePath}, threshold=${deps.config.contextThreshold}, proactiveThresholdCompactionMode=${deps.config.proactiveThresholdCompactionMode})`});logStartupBannerOnce({key:"state-dir",log:message=>deps.log.info(message),message:`[lcm] State dir: ${resolveOpenclawStateDir(process.env)}`});logStartupBannerOnce({key:"compaction-model",log:message=>deps.log.info(message),message:buildCompactionModelLog({config:deps.config,openClawConfig:registrationConfig.openClawConfig,defaultProvider:process.env.OPENCLAW_PROVIDER?.trim()??""})});if(deps.config.fallbackProviders.length>0){logStartupBannerOnce({key:"fallback-providers",log:message=>deps.log.info(message),message:`[lcm] Fallback providers: ${deps.config.fallbackProviders.map(fp=>`${fp.provider}/${fp.model}`).join(", ")}`})}}};var plugin_default=lcmPlugin;export{buildCompleteSimpleOptions,plugin_default as default,shouldOmitTemperatureForApi};
|