@martian-engineering/lossless-claw 0.8.2 → 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/README.md +20 -0
- package/dist/index.js +125 -40
- package/docs/architecture.md +1 -1
- package/docs/configuration.md +33 -1
- package/openclaw.plugin.json +34 -0
- package/package.json +1 -1
- package/skills/lossless-claw/SKILL.md +2 -2
- package/skills/lossless-claw/references/config.md +39 -1
- package/skills/lossless-claw/references/session-lifecycle.md +20 -4
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var __defProp=Object.defineProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};import{readFileSync,writeFileSync}from"node:fs";import{join as join4}from"node:path";import{homedir}from"os";import{join}from"path";function resolveOpenclawStateDir(env=process.env){const explicit=env.OPENCLAW_STATE_DIR?.trim();return explicit||join(homedir(),".openclaw")}function toNumber(value){if(typeof value==="number"&&Number.isFinite(value))return value;if(typeof value==="string"){const n=Number(value);if(Number.isFinite(n))return n}return void 0}function parseFiniteInt(value){if(value===void 0)return void 0;const parsed=parseInt(value,10);return Number.isFinite(parsed)?parsed:void 0}function parseFiniteNumber(value){if(value===void 0)return void 0;const parsed=parseFloat(value);return Number.isFinite(parsed)?parsed:void 0}function parseFallbackProviders(value){if(!value?.trim())return void 0;const entries=[];for(const part of value.split(",")){const trimmed=part.trim();if(!trimmed)continue;const slashIdx=trimmed.indexOf("/");if(slashIdx>0&&slashIdx<trimmed.length-1){const provider=trimmed.slice(0,slashIdx).trim();const model=trimmed.slice(slashIdx+1).trim();if(provider&&model){entries.push({provider,model})}}}return entries.length>0?entries:void 0}function toFallbackProviderArray(value){if(!Array.isArray(value))return void 0;const entries=[];for(const item of value){if(item&&typeof item==="object"&&!Array.isArray(item)){const p=toStr(item.provider);const m=toStr(item.model);if(p&&m)entries.push({provider:p,model:m})}}return entries.length>0?entries:void 0}function toBool(value){if(typeof value==="boolean")return value;if(value==="true")return true;if(value==="false")return false;return void 0}function toStr(value){if(typeof value==="string"){const trimmed=value.trim();return trimmed.length>0?trimmed:void 0}return void 0}function toStrArray(value){if(Array.isArray(value)){const normalized=value.map(entry=>toStr(entry)).filter(entry=>typeof entry==="string");return normalized.length>0?normalized:[]}const single=toStr(value);if(!single){return void 0}return single.split(",").map(entry=>entry.trim()).filter(Boolean)}function toRecord(value){return value&&typeof value==="object"&&!Array.isArray(value)?value:void 0}function parseEnvStrArray(value){if(value===void 0){return void 0}return value.split(",").map(entry=>entry.trim()).filter(Boolean)}function resolvePatternArray(params){const pluginPatterns=toStrArray(params.pluginValue);const pluginHasPatterns=(pluginPatterns?.length??0)>0;if(params.envValue!==void 0){return{patterns:parseEnvStrArray(params.envValue)??[],source:"env",envOverridesPluginConfig:pluginHasPatterns}}if(pluginPatterns!==void 0){return{patterns:pluginPatterns,source:"plugin-config",envOverridesPluginConfig:false}}return{patterns:[],source:"default",envOverridesPluginConfig:false}}function describeLcmConfigSource(source){switch(source){case"env":return"env";case"plugin-config":return"plugin config";case"default":return"defaults"}}function resolveLcmConfigWithDiagnostics(env=process.env,pluginConfig){const pc=pluginConfig??{};const cacheAwareCompaction=toRecord(pc.cacheAwareCompaction);const dynamicLeafChunkTokens=toRecord(pc.dynamicLeafChunkTokens);const resolvedLeafChunkTokens=parseFiniteInt(env.LCM_LEAF_CHUNK_TOKENS)??toNumber(pc.leafChunkTokens)??2e4;const resolvedBootstrapMaxTokens=parseFiniteInt(env.LCM_BOOTSTRAP_MAX_TOKENS)??toNumber(pc.bootstrapMaxTokens)??Math.max(6e3,Math.floor(resolvedLeafChunkTokens*.3));const envDelegationTimeoutMs=env.LCM_DELEGATION_TIMEOUT_MS!==void 0?toNumber(env.LCM_DELEGATION_TIMEOUT_MS):void 0;const resolvedDynamicLeafChunkMax=Math.max(resolvedLeafChunkTokens,parseFiniteInt(env.LCM_DYNAMIC_LEAF_CHUNK_TOKENS_MAX)??toNumber(dynamicLeafChunkTokens?.max)??Math.floor(resolvedLeafChunkTokens*2));const resolvedHotCachePressureFactor=Math.max(1,parseFiniteNumber(env.LCM_HOT_CACHE_PRESSURE_FACTOR)??toNumber(cacheAwareCompaction?.hotCachePressureFactor)??4);const resolvedHotCacheBudgetHeadroomRatio=Math.min(.95,Math.max(0,parseFiniteNumber(env.LCM_HOT_CACHE_BUDGET_HEADROOM_RATIO)??toNumber(cacheAwareCompaction?.hotCacheBudgetHeadroomRatio)??.2));const ignoreSessionPatterns=resolvePatternArray({envValue:env.LCM_IGNORE_SESSION_PATTERNS,pluginValue:pc.ignoreSessionPatterns});const statelessSessionPatterns=resolvePatternArray({envValue:env.LCM_STATELESS_SESSION_PATTERNS,pluginValue:pc.statelessSessionPatterns});return{config:{enabled:env.LCM_ENABLED!==void 0?env.LCM_ENABLED!=="false":toBool(pc.enabled)??true,databasePath:env.LCM_DATABASE_PATH??toStr(pc.dbPath)??toStr(pc.databasePath)??join(resolveOpenclawStateDir(env),"lcm.db"),largeFilesDir:env.LCM_LARGE_FILES_DIR?.trim()??toStr(pc.largeFilesDir)??join(resolveOpenclawStateDir(env),"lcm-files"),ignoreSessionPatterns:ignoreSessionPatterns.patterns,statelessSessionPatterns:statelessSessionPatterns.patterns,skipStatelessSessions:env.LCM_SKIP_STATELESS_SESSIONS!==void 0?env.LCM_SKIP_STATELESS_SESSIONS==="true":toBool(pc.skipStatelessSessions)??true,contextThreshold:parseFiniteNumber(env.LCM_CONTEXT_THRESHOLD)??toNumber(pc.contextThreshold)??.75,freshTailCount:parseFiniteInt(env.LCM_FRESH_TAIL_COUNT)??toNumber(pc.freshTailCount)??64,freshTailMaxTokens:parseFiniteInt(env.LCM_FRESH_TAIL_MAX_TOKENS)??toNumber(pc.freshTailMaxTokens)??void 0,newSessionRetainDepth:parseFiniteInt(env.LCM_NEW_SESSION_RETAIN_DEPTH)??toNumber(pc.newSessionRetainDepth)??2,leafMinFanout:parseFiniteInt(env.LCM_LEAF_MIN_FANOUT)??toNumber(pc.leafMinFanout)??8,condensedMinFanout:parseFiniteInt(env.LCM_CONDENSED_MIN_FANOUT)??toNumber(pc.condensedMinFanout)??4,condensedMinFanoutHard:parseFiniteInt(env.LCM_CONDENSED_MIN_FANOUT_HARD)??toNumber(pc.condensedMinFanoutHard)??2,incrementalMaxDepth:parseFiniteInt(env.LCM_INCREMENTAL_MAX_DEPTH)??toNumber(pc.incrementalMaxDepth)??1,leafChunkTokens:resolvedLeafChunkTokens,bootstrapMaxTokens:resolvedBootstrapMaxTokens,leafTargetTokens:parseFiniteInt(env.LCM_LEAF_TARGET_TOKENS)??toNumber(pc.leafTargetTokens)??2400,condensedTargetTokens:parseFiniteInt(env.LCM_CONDENSED_TARGET_TOKENS)??toNumber(pc.condensedTargetTokens)??2e3,maxExpandTokens:parseFiniteInt(env.LCM_MAX_EXPAND_TOKENS)??toNumber(pc.maxExpandTokens)??4e3,largeFileTokenThreshold:parseFiniteInt(env.LCM_LARGE_FILE_TOKEN_THRESHOLD)??toNumber(pc.largeFileThresholdTokens)??toNumber(pc.largeFileTokenThreshold)??25e3,summaryProvider:env.LCM_SUMMARY_PROVIDER?.trim()??toStr(pc.summaryProvider)??"",summaryModel:env.LCM_SUMMARY_MODEL?.trim()??toStr(pc.summaryModel)??"",largeFileSummaryProvider:env.LCM_LARGE_FILE_SUMMARY_PROVIDER?.trim()??toStr(pc.largeFileSummaryProvider)??"",largeFileSummaryModel:env.LCM_LARGE_FILE_SUMMARY_MODEL?.trim()??toStr(pc.largeFileSummaryModel)??"",expansionProvider:env.LCM_EXPANSION_PROVIDER?.trim()??toStr(pc.expansionProvider)??"",expansionModel:env.LCM_EXPANSION_MODEL?.trim()??toStr(pc.expansionModel)??"",delegationTimeoutMs:envDelegationTimeoutMs??toNumber(pc.delegationTimeoutMs)??12e4,summaryTimeoutMs:parseFiniteInt(env.LCM_SUMMARY_TIMEOUT_MS)??toNumber(pc.summaryTimeoutMs)??6e4,timezone:env.TZ??toStr(pc.timezone)??Intl.DateTimeFormat().resolvedOptions().timeZone,pruneHeartbeatOk:env.LCM_PRUNE_HEARTBEAT_OK!==void 0?env.LCM_PRUNE_HEARTBEAT_OK==="true":toBool(pc.pruneHeartbeatOk)??false,transcriptGcEnabled:env.LCM_TRANSCRIPT_GC_ENABLED!==void 0?env.LCM_TRANSCRIPT_GC_ENABLED==="true":toBool(pc.transcriptGcEnabled)??false,maxAssemblyTokenBudget:parseFiniteInt(env.LCM_MAX_ASSEMBLY_TOKEN_BUDGET)??toNumber(pc.maxAssemblyTokenBudget)??void 0,summaryMaxOverageFactor:parseFiniteNumber(env.LCM_SUMMARY_MAX_OVERAGE_FACTOR)??toNumber(pc.summaryMaxOverageFactor)??3,customInstructions:env.LCM_CUSTOM_INSTRUCTIONS?.trim()??toStr(pc.customInstructions)??"",circuitBreakerThreshold:parseFiniteInt(env.LCM_CIRCUIT_BREAKER_THRESHOLD)??toNumber(pc.circuitBreakerThreshold)??5,circuitBreakerCooldownMs:parseFiniteInt(env.LCM_CIRCUIT_BREAKER_COOLDOWN_MS)??toNumber(pc.circuitBreakerCooldownMs)??18e5,fallbackProviders:parseFallbackProviders(env.LCM_FALLBACK_PROVIDERS)??toFallbackProviderArray(pc.fallbackProviders)??[],cacheAwareCompaction:{enabled:env.LCM_CACHE_AWARE_COMPACTION_ENABLED!==void 0?env.LCM_CACHE_AWARE_COMPACTION_ENABLED!=="false":toBool(cacheAwareCompaction?.enabled)??true,maxColdCacheCatchupPasses:parseFiniteInt(env.LCM_MAX_COLD_CACHE_CATCHUP_PASSES)??toNumber(cacheAwareCompaction?.maxColdCacheCatchupPasses)??2,hotCachePressureFactor:resolvedHotCachePressureFactor,hotCacheBudgetHeadroomRatio:resolvedHotCacheBudgetHeadroomRatio},dynamicLeafChunkTokens:{enabled:env.LCM_DYNAMIC_LEAF_CHUNK_TOKENS_ENABLED!==void 0?env.LCM_DYNAMIC_LEAF_CHUNK_TOKENS_ENABLED==="true":toBool(dynamicLeafChunkTokens?.enabled)??true,max:resolvedDynamicLeafChunkMax}},diagnostics:{ignoreSessionPatternsSource:ignoreSessionPatterns.source,statelessSessionPatternsSource:statelessSessionPatterns.source,ignoreSessionPatternsEnvOverridesPluginConfig:ignoreSessionPatterns.envOverridesPluginConfig,statelessSessionPatternsEnvOverridesPluginConfig:statelessSessionPatterns.envOverridesPluginConfig}}}import{mkdirSync}from"node:fs";import{dirname,resolve}from"node:path";import{DatabaseSync}from"node:sqlite";var SQLITE_BUSY_TIMEOUT_MS=5e3;var connectionsByPath=new Map;var connectionIndex=new Map;function isInMemoryPath(dbPath){const normalized=dbPath.trim();return normalized===":memory:"||normalized.startsWith("file::memory:")}function getFileBackedDatabasePath(dbPath){const trimmed=dbPath.trim();if(!trimmed||isInMemoryPath(trimmed)){return null}return resolve(trimmed)}function normalizePath(dbPath){const fileBackedDatabasePath=getFileBackedDatabasePath(dbPath);if(!fileBackedDatabasePath){const trimmed=dbPath.trim();return trimmed.length>0?trimmed:":memory:"}return fileBackedDatabasePath}function ensureDbDirectory(dbPath){const fileBackedDatabasePath=getFileBackedDatabasePath(dbPath);if(!fileBackedDatabasePath){return}mkdirSync(dirname(fileBackedDatabasePath),{recursive:true})}function configureConnection(db){db.exec("PRAGMA journal_mode = WAL");db.exec(`PRAGMA busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`);db.exec("PRAGMA foreign_keys = ON");db.exec("PRAGMA cache_size = -65536");db.exec("PRAGMA synchronous = NORMAL");db.exec("PRAGMA temp_store = MEMORY");return db}function trackConnection(dbPath,db){const key=normalizePath(dbPath);let entries=connectionsByPath.get(key);if(!entries){entries=new Set;connectionsByPath.set(key,entries)}entries.add(db);connectionIndex.set(db,key)}function untrackConnection(db){const key=connectionIndex.get(db);if(!key){return}const entries=connectionsByPath.get(key);if(entries){entries.delete(db);if(entries.size===0){connectionsByPath.delete(key)}}connectionIndex.delete(db)}function closeDatabase(db){if(!db){return}try{try{db.exec("PRAGMA optimize")}catch{}db.close()}catch{}finally{untrackConnection(db)}}function createLcmDatabaseConnection(dbPath){ensureDbDirectory(dbPath);const db=new DatabaseSync(dbPath);try{configureConnection(db)}catch(err){try{db.close()}catch{}throw err}trackConnection(dbPath,db);return db}function closeLcmConnection(target){if(target&&typeof target!=="string"){closeDatabase(target);return}if(typeof target==="string"){const key=normalizePath(target);const entries=connectionsByPath.get(key);if(!entries){return}for(const db of[...entries]){closeDatabase(db)}connectionsByPath.delete(key);return}for(const db of[...connectionIndex.keys()]){closeDatabase(db)}connectionsByPath.clear();connectionIndex.clear()}import{createHash as createHash2,randomUUID as randomUUID2}from"node:crypto";import{closeSync,createReadStream,openSync,readSync,statSync}from"node:fs";import{mkdir,writeFile}from"node:fs/promises";import{join as join2}from"node:path";import{createInterface}from"node:readline";import{SessionManager}from"@mariozechner/pi-coding-agent";var TOOL_CALL_TYPES=new Set(["toolCall","toolUse","tool_use","tool-use","functionCall","function_call"]);var OPENAI_FUNCTION_CALL_TYPES=new Set(["functionCall","function_call"]);function extractToolCallId(block){if(typeof block.id==="string"&&block.id){return block.id}if(typeof block.call_id==="string"&&block.call_id){return block.call_id}return null}function normalizeAssistantReasoningBlocks(message){if(!Array.isArray(message.content)){return message}let sawToolCall=false;let reasoningAfterToolCall=false;let functionCallCount=0;for(const block of message.content){if(!block||typeof block!=="object"){return message}const type=block.type;if(type==="reasoning"||type==="thinking"){if(sawToolCall){reasoningAfterToolCall=true}continue}if(typeof type==="string"&&TOOL_CALL_TYPES.has(type)){sawToolCall=true;if(OPENAI_FUNCTION_CALL_TYPES.has(type)){functionCallCount+=1}continue}return message}if(!reasoningAfterToolCall||functionCallCount!==1){return message}const reasoning=message.content.filter(block=>{const type=block.type;return type==="reasoning"||type==="thinking"});const toolCalls=message.content.filter(block=>{const type=block.type;return typeof type==="string"&&TOOL_CALL_TYPES.has(type)});return{...message,content:[...reasoning,...toolCalls]}}function extractToolCallsFromAssistant(msg){const content=msg.content;if(!Array.isArray(content)){return[]}const toolCalls=[];for(const block of content){if(!block||typeof block!=="object"){continue}const rec=block;const id=extractToolCallId(rec);if(!id){continue}if(typeof rec.type==="string"&&TOOL_CALL_TYPES.has(rec.type)){toolCalls.push({id,name:typeof rec.name==="string"?rec.name:void 0})}}return toolCalls}function extractToolResultId(msg){if(typeof msg.toolCallId==="string"&&msg.toolCallId){return msg.toolCallId}if(typeof msg.toolUseId==="string"&&msg.toolUseId){return msg.toolUseId}return null}function makeMissingToolResult(params){return{role:"toolResult",toolCallId:params.toolCallId,toolName:params.toolName??"unknown",content:[{type:"text",text:"[lossless-claw] missing tool result in session history; inserted synthetic error result for transcript repair."}],isError:true,timestamp:Date.now()}}function sanitizeToolUseResultPairing(messages){const out=[];const seenToolResultIds=new Set;let droppedDuplicateCount=0;let droppedOrphanCount=0;let moved=false;let changed=false;const pushToolResult=msg=>{const id=extractToolResultId(msg);if(id&&seenToolResultIds.has(id)){droppedDuplicateCount+=1;changed=true;return}if(id){seenToolResultIds.add(id)}out.push(msg)};for(let i=0;i<messages.length;i+=1){const msg=messages[i];if(!msg||typeof msg!=="object"){out.push(msg);continue}const role=msg.role;if(role!=="assistant"){if(role!=="toolResult"){out.push(msg)}else{droppedOrphanCount+=1;changed=true}continue}const normalizedAssistant=normalizeAssistantReasoningBlocks(msg);if(normalizedAssistant!==msg){changed=true}const stopReason=normalizedAssistant.stopReason;if(stopReason==="error"||stopReason==="aborted"){out.push(normalizedAssistant);continue}const toolCalls=extractToolCallsFromAssistant(normalizedAssistant);if(toolCalls.length===0){out.push(normalizedAssistant);continue}const toolCallIds=new Set(toolCalls.map(t=>t.id));const spanResultsById=new Map;const remainder=[];let j=i+1;for(;j<messages.length;j+=1){const next=messages[j];if(!next||typeof next!=="object"){remainder.push(next);continue}const nextRole=next.role;if(nextRole==="assistant"){break}if(nextRole==="toolResult"){const id=extractToolResultId(next);if(id&&toolCallIds.has(id)){if(seenToolResultIds.has(id)){droppedDuplicateCount+=1;changed=true;continue}if(!spanResultsById.has(id)){spanResultsById.set(id,next)}continue}}if(next.role!=="toolResult"){remainder.push(next)}else{droppedOrphanCount+=1;changed=true}}out.push(normalizedAssistant);if(spanResultsById.size>0&&remainder.length>0){moved=true;changed=true}for(const call of toolCalls){const existing=spanResultsById.get(call.id);if(existing){pushToolResult(existing)}else{const missing=makeMissingToolResult({toolCallId:call.id,toolName:call.name});changed=true;pushToolResult(missing)}}for(const rem of remainder){out.push(rem)}i=j-1}const changedOrMoved=changed||moved;return changedOrMoved?out:messages}function isCjkCodePoint(cp){return cp>=19968&&cp<=40959||cp>=13312&&cp<=19903||cp>=131072&&cp<=173791||cp>=173824&&cp<=177983||cp>=177984&&cp<=178207||cp>=178208&&cp<=183983||cp>=183984&&cp<=191471||cp>=12288&&cp<=12351||cp>=12352&&cp<=12543||cp>=44032&&cp<=55215||cp>=65280&&cp<=65519}function estimateCodePointTokens(cp){if(isCjkCodePoint(cp)){return 1.5}if(cp>65535){return 2}return .25}function estimateTokens(text){let tokens=0;for(const char of text){const cp=char.codePointAt(0)??0;tokens+=estimateCodePointTokens(cp)}return Math.ceil(tokens)}function truncateTextToEstimatedTokens(text,maxTokens){if(maxTokens<=0||!text){return""}let tokens=0;let end=0;for(const char of text){const cp=char.codePointAt(0)??0;const nextTokens=tokens+estimateCodePointTokens(cp);if(Math.ceil(nextTokens)>maxTokens){break}tokens=nextTokens;end+=char.length}return text.slice(0,end)}var TOOL_CALL_TYPES2=new Set(["toolCall","toolUse","tool_use","tool-use","functionCall","function_call"]);function buildSystemPromptAddition(summarySignals){if(summarySignals.length===0){return void 0}const maxDepth=summarySignals.reduce((deepest,signal)=>Math.max(deepest,signal.depth),0);const condensedCount=summarySignals.filter(signal=>signal.kind==="condensed").length;const heavilyCompacted=maxDepth>=2||condensedCount>=2;const sections=[];sections.push("## Compacted Conversation Context","","Summaries above are compressed context, not full detail.","","Treat summaries as compressed recall cues rather than proof of exact wording or exact values.","",'If a summary includes an "Expand for details about:" footer, use it as a cue to expand before asserting specifics.');if(heavilyCompacted){sections.push("","**Deeply compacted context: expand before asserting specifics.**","","Before answering with exact commands, SHAs, paths, timestamps, config values, or causal chains, expand for the missing detail.","","Default recall flow for precision work:","1) `lcm_grep` to locate relevant summary/message IDs","2) `lcm_expand_query` with a focused prompt","3) Answer directly from the retrieved evidence","","Keep raw summary IDs in tool context for follow-up; do not include them in the user-facing answer unless the user asks for sources or IDs.","",'`lcm_grep` tips: prefer `mode: "full_text"` for keyword/topic lookup, quote exact multi-word phrases, use `sort: "relevance"` for older-topic retrieval, and use `sort: "hybrid"` when recency should still influence ranking.',"`lcm_expand_query(query: ...)` uses the same FTS5 full-text search rules as `lcm_grep`: terms are ANDed by default, so extra query words narrow results. Keep `query` to 1-3 distinctive terms or a quoted phrase, and put the natural-language question in `prompt`.","","**Uncertainty checklist (run before answering):**","- Am I making an exact factual claim from a compressed or condensed summary?","- Could compaction have omitted a crucial detail?","- Would I need an expansion step if the user asks for proof or the exact text?","- Should I state uncertainty instead of asserting specifics until I expand?","","If yes to any item, expand first or explicitly say that you need to expand.","","Do not guess exact commands, SHAs, file paths, timestamps, config values, or causal claims from condensed summaries. Expand first or explicitly say that you need to expand.")}else{sections.push("","For exact commands, SHAs, paths, timestamps, config values, or causal chains, expand for details before answering.","State uncertainty instead of guessing from compressed summaries.")}return sections.join("\n")}function parseJson(value){if(typeof value!=="string"||!value.trim()){return void 0}try{return JSON.parse(value)}catch{return void 0}}function getOriginalRole(parts){for(const part of parts){const decoded=parseJson(part.metadata);if(!decoded||typeof decoded!=="object"){continue}const role=decoded.originalRole;if(typeof role==="string"&&role.length>0){return role}}return null}function getPartMetadata(part){const decoded=parseJson(part.metadata);if(!decoded||typeof decoded!=="object"){return{}}const record=decoded;return{originalRole:typeof record.originalRole==="string"&&record.originalRole.length>0?record.originalRole:void 0,rawType:typeof record.rawType==="string"&&record.rawType.length>0?record.rawType:void 0,raw:record.raw}}function parseStoredValue(value){if(typeof value!=="string"||value.length===0){return void 0}const parsed=parseJson(value);return parsed!==void 0?parsed:value}function reasoningBlockFromPart(part,rawType){const type=rawType==="thinking"?"thinking":"reasoning";if(typeof part.textContent==="string"&&part.textContent.length>0){return type==="thinking"?{type,thinking:part.textContent}:{type,text:part.textContent}}return{type}}function tryRestoreOpenAIReasoning(raw){if(raw.type!=="thinking")return null;const sig=raw.thinkingSignature;if(typeof sig!=="string"||!sig.startsWith("{"))return null;try{const parsed=JSON.parse(sig);if(parsed.type==="reasoning"&&typeof parsed.id==="string"){return parsed}}catch{}return null}function toolCallBlockFromPart(part,rawType){const type=rawType==="function_call"||rawType==="functionCall"||rawType==="tool_use"||rawType==="tool-use"||rawType==="toolUse"||rawType==="toolCall"?rawType:"toolCall";const input=parseStoredValue(part.toolInput);const block={type};if(type==="function_call"){if(typeof part.toolCallId==="string"&&part.toolCallId.length>0){block.call_id=part.toolCallId}if(typeof part.toolName==="string"&&part.toolName.length>0){block.name=part.toolName}if(input!==void 0){block.arguments=input}return block}block.id=typeof part.toolCallId==="string"&&part.toolCallId.length>0?part.toolCallId:`toolu_lcm_${part.partId??"unknown"}`;if(typeof part.toolName==="string"&&part.toolName.length>0){block.name=part.toolName}if(input!==void 0){if(type==="functionCall"||type==="toolCall"){block.arguments=input}else{block.input=input}}return block}function toolResultBlockFromPart(part,rawType,raw){if(raw&&typeof raw.text==="string"&&raw.output===void 0&&raw.content===void 0&&(part.toolOutput==null||part.toolOutput==="")&&(part.textContent==null||part.textContent===raw.text)){return{type:"text",text:raw.text}}const type=rawType==="function_call_output"||rawType==="toolResult"||rawType==="tool_result"?rawType:"tool_result";const output=parseStoredValue(part.toolOutput);const block={type};if(typeof part.toolName==="string"&&part.toolName.length>0){block.name=part.toolName}if(output!==void 0){block.output=output}else if(typeof part.textContent==="string"){block.output=part.textContent}else if(raw&&raw.output!==void 0){block.output=raw.output}else if(raw&&raw.content!==void 0){block.content=raw.content}else{block.output=""}if(raw&&typeof raw.is_error==="boolean"){block.is_error=raw.is_error}else if(raw&&typeof raw.isError==="boolean"){block.isError=raw.isError}if(type==="function_call_output"){if(typeof part.toolCallId==="string"&&part.toolCallId.length>0){block.call_id=part.toolCallId}return block}if(typeof part.toolCallId==="string"&&part.toolCallId.length>0){block.tool_use_id=part.toolCallId}return block}function toRuntimeRole(dbRole,parts){const originalRole=getOriginalRole(parts);if(originalRole==="toolResult"){return"toolResult"}if(originalRole==="assistant"){return"assistant"}if(originalRole==="user"){return"user"}if(originalRole==="system"){return"user"}if(dbRole==="tool"){return"toolResult"}if(dbRole==="assistant"){return"assistant"}return"user"}function blockFromPart(part){const metadata=getPartMetadata(part);if(metadata.raw&&typeof metadata.raw==="object"){const restored=tryRestoreOpenAIReasoning(metadata.raw);if(restored)return restored;const rawType=metadata.raw.type;const isToolBlock=rawType==="toolCall"||rawType==="tool_use"||rawType==="tool-use"||rawType==="toolUse"||rawType==="functionCall"||rawType==="function_call"||rawType==="function_call_output"||rawType==="toolResult"||rawType==="tool_result";if(!isToolBlock){return metadata.raw}const rawRecord=metadata.raw;const rawToolCallId=typeof rawRecord.id==="string"&&rawRecord.id.length>0?rawRecord.id:typeof rawRecord.call_id==="string"&&rawRecord.call_id.length>0?rawRecord.call_id:void 0;if(rawToolCallId){if(typeof part.toolCallId!=="string"||part.toolCallId.length===0){part.toolCallId=rawToolCallId}}if(typeof rawRecord.name==="string"&&rawRecord.name.length>0){if(typeof part.toolName!=="string"||part.toolName.length===0){part.toolName=rawRecord.name}}if(part.toolInput==null||part.toolInput===""){const rawArgs=rawRecord.arguments??rawRecord.input;if(rawArgs!==void 0){part.toolInput=typeof rawArgs==="string"?rawArgs:JSON.stringify(rawArgs)}}}if(part.partType==="reasoning"){return reasoningBlockFromPart(part,metadata.rawType)}if(part.partType==="tool"){if(metadata.originalRole==="toolResult"||metadata.rawType==="function_call_output"){return toolResultBlockFromPart(part,metadata.rawType,metadata.raw&&typeof metadata.raw==="object"?metadata.raw:void 0)}return toolCallBlockFromPart(part,metadata.rawType)}if(metadata.rawType==="function_call"||metadata.rawType==="functionCall"||metadata.rawType==="tool_use"||metadata.rawType==="tool-use"||metadata.rawType==="toolUse"||metadata.rawType==="toolCall"){return toolCallBlockFromPart(part,metadata.rawType)}if(metadata.rawType==="function_call_output"||metadata.rawType==="tool_result"||metadata.rawType==="toolResult"){return toolResultBlockFromPart(part,metadata.rawType,metadata.raw&&typeof metadata.raw==="object"?metadata.raw:void 0)}if(part.partType==="text"){return{type:"text",text:part.textContent??""}}if(typeof part.textContent==="string"&&part.textContent.length>0){return{type:"text",text:part.textContent}}const decodedFallback=parseJson(part.metadata);if(decodedFallback&&typeof decodedFallback==="object"){return{type:"text",text:JSON.stringify(decodedFallback)}}return{type:"text",text:""}}function contentFromParts(parts,role,fallbackContent){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&&blocks[0]&&typeof blocks[0]==="object"&&blocks[0].type==="text"&&typeof blocks[0].text==="string"){return blocks[0].text}return blocks}function pickToolCallId(parts){for(const part of parts){if(typeof part.toolCallId==="string"&&part.toolCallId.length>0){return part.toolCallId}const decoded=parseJson(part.metadata);if(!decoded||typeof decoded!=="object"){continue}const metadataToolCallId=decoded.toolCallId;if(typeof metadataToolCallId==="string"&&metadataToolCallId.length>0){return metadataToolCallId}const raw=decoded.raw;if(!raw||typeof raw!=="object"){continue}const maybe=raw.toolCallId;if(typeof maybe==="string"&&maybe.length>0){return maybe}const maybeSnake=raw.tool_call_id;if(typeof maybeSnake==="string"&&maybeSnake.length>0){return maybeSnake}}return void 0}function pickToolName(parts){for(const part of parts){if(typeof part.toolName==="string"&&part.toolName.length>0){return part.toolName}const decoded=parseJson(part.metadata);if(!decoded||typeof decoded!=="object"){continue}const metadataToolName=decoded.toolName;if(typeof metadataToolName==="string"&&metadataToolName.length>0){return metadataToolName}const raw=decoded.raw;if(!raw||typeof raw!=="object"){continue}const maybe=raw.name;if(typeof maybe==="string"&&maybe.length>0){return maybe}const maybeCamel=raw.toolName;if(typeof maybeCamel==="string"&&maybeCamel.length>0){return maybeCamel}}return void 0}function pickToolIsError(parts){for(const part of parts){const decoded=parseJson(part.metadata);if(!decoded||typeof decoded!=="object"){continue}const metadataIsError=decoded.isError;if(typeof metadataIsError==="boolean"){return metadataIsError}}return void 0}function extractToolCallId2(block){if(typeof block.id==="string"&&block.id.length>0){return block.id}if(typeof block.call_id==="string"&&block.call_id.length>0){return block.call_id}return null}function extractToolCallIdsFromAssistant(message){if(message?.role!=="assistant"||!Array.isArray(message.content)){return[]}const ids=[];for(const block of message.content){if(!block||typeof block!=="object"){continue}const record=block;if(typeof record.type!=="string"||!TOOL_CALL_TYPES2.has(record.type)){continue}const id=extractToolCallId2(record);if(id){ids.push(id)}}return ids}function extractToolResultIdFromMessage(message){if(!message||typeof message!=="object"){return null}if(typeof message.toolCallId==="string"&&message.toolCallId.length>0){return message.toolCallId}if(typeof message.toolUseId==="string"&&message.toolUseId.length>0){return message.toolUseId}return null}function collectAssistantToolCallIds(items){const ids=new Set;for(const item of items){for(const id of extractToolCallIdsFromAssistant(item.message)){ids.add(id)}}return ids}function normalizeFreshTailTokenCap(freshTailMaxTokens){if(typeof freshTailMaxTokens==="number"&&Number.isFinite(freshTailMaxTokens)&&freshTailMaxTokens>=0){return Math.floor(freshTailMaxTokens)}return void 0}function mergeFreshTailWithMatchingToolResults(freshTail,matchingToolResults,freshTailMaxTokens){if(matchingToolResults.length===0){return{items:freshTail,promotedOrdinals:new Set}}const resultsById=new Map;for(const item of matchingToolResults){const toolResultId=extractToolResultIdFromMessage(item.message);if(!toolResultId){continue}const existing=resultsById.get(toolResultId);if(existing){existing.push(item)}else{resultsById.set(toolResultId,[item])}}const merged=[];const promotedOrdinals=new Set;const tokenCap=normalizeFreshTailTokenCap(freshTailMaxTokens);let mergedTokens=freshTail.reduce((sum,item)=>sum+item.tokens,0);for(const item of freshTail){merged.push(item);const toolCallIds=extractToolCallIdsFromAssistant(item.message);if(toolCallIds.length===0){continue}for(const toolCallId of toolCallIds){const matches=resultsById.get(toolCallId);if(!matches){continue}for(const match of matches){if(promotedOrdinals.has(match.ordinal)){continue}if(typeof tokenCap==="number"&&mergedTokens+match.tokens>tokenCap){continue}merged.push(match);promotedOrdinals.add(match.ordinal);mergedTokens+=match.tokens}}}if(typeof tokenCap!=="number"){for(const item of matchingToolResults){if(!promotedOrdinals.has(item.ordinal)){merged.push(item)}}}return{items:merged,promotedOrdinals}}function filterNonFreshAssistantToolCalls(items,freshTailOrdinals,preserveFreshTailToolCalls=true){const availableToolResultIds=new Set;for(const item of items){const toolResultId=extractToolResultIdFromMessage(item.message);if(toolResultId){availableToolResultIds.add(toolResultId)}}const filteredMessages=[];for(const item of items){if(item.message?.role!=="assistant"||preserveFreshTailToolCalls&&freshTailOrdinals.has(item.ordinal)){filteredMessages.push(item.message);continue}if(!Array.isArray(item.message.content)){filteredMessages.push(item.message);continue}let removedAny=false;const content=item.message.content.filter(block=>{if(!block||typeof block!=="object"){return true}const record=block;if(typeof record.type!=="string"||!TOOL_CALL_TYPES2.has(record.type)){return true}const toolCallId=extractToolCallId2(record);if(!toolCallId||availableToolResultIds.has(toolCallId)){return true}removedAny=true;return false});if(content.length===0){continue}if(!removedAny){filteredMessages.push(item.message);continue}filteredMessages.push({...item.message,content})}return filteredMessages}function formatDateForAttribute(date,timezone){const tz=timezone??"UTC";try{const fmt=new Intl.DateTimeFormat("en-CA",{timeZone:tz,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:false});const p=Object.fromEntries(fmt.formatToParts(date).map(part=>[part.type,part.value]));return`${p.year}-${p.month}-${p.day}T${p.hour}:${p.minute}:${p.second}`}catch{return date.toISOString()}}async function formatSummaryContent(summary,summaryStore,timezone){const attributes=[`id="${summary.summaryId}"`,`kind="${summary.kind}"`,`depth="${summary.depth}"`,`descendant_count="${summary.descendantCount}"`];if(summary.earliestAt){attributes.push(`earliest_at="${formatDateForAttribute(summary.earliestAt,timezone)}"`)}if(summary.latestAt){attributes.push(`latest_at="${formatDateForAttribute(summary.latestAt,timezone)}"`)}const lines=[];lines.push(`<summary ${attributes.join(" ")}>`);if(summary.kind==="condensed"){const parents=await summaryStore.getSummaryParents(summary.summaryId);if(parents.length>0){lines.push(" <parents>");for(const parent of parents){lines.push(` <summary_ref id="${parent.summaryId}" />`)}lines.push(" </parents>")}}lines.push(" <content>");lines.push(summary.content);lines.push(" </content>");lines.push("</summary>");return lines.join("\n")}function resolveFreshTailOrdinal(resolved,freshTailCount,freshTailMaxTokens){if(!Number.isFinite(freshTailCount)||freshTailCount<=0){return Infinity}const rawMessages=resolved.filter(item=>item.isMessage);if(rawMessages.length===0){return Infinity}const tokenCap=typeof freshTailMaxTokens==="number"&&Number.isFinite(freshTailMaxTokens)&&freshTailMaxTokens>=0?Math.floor(freshTailMaxTokens):void 0;let protectedCount=0;let protectedTokens=0;let tailStartOrdinal=Infinity;for(let idx=rawMessages.length-1;idx>=0;idx--){if(protectedCount>=freshTailCount){break}const item=rawMessages[idx];if(!item){continue}const wouldExceedBudget=protectedCount>0&&typeof tokenCap==="number"&&protectedTokens+item.tokens>tokenCap;if(wouldExceedBudget){break}tailStartOrdinal=item.ordinal;protectedCount++;protectedTokens+=item.tokens}return tailStartOrdinal}function tokenizeText(text){return text.toLowerCase().split(/[^a-z0-9]+/).filter(t=>t.length>1)}function scoreRelevance(itemText,prompt){const promptTerms=tokenizeText(prompt);if(promptTerms.length===0)return 0;const itemTerms=tokenizeText(itemText);if(itemTerms.length===0)return 0;const freq=new Map;for(const term of itemTerms){freq.set(term,(freq.get(term)??0)+1)}const seen=new Set;let score=0;for(const term of promptTerms){if(seen.has(term))continue;seen.add(term);const tf=freq.get(term)??0;if(tf>0){score+=tf/itemTerms.length}}return score}function hasSearchablePrompt(prompt){return typeof prompt==="string"&&tokenizeText(prompt).length>0}var ContextAssembler=class{constructor(conversationStore,summaryStore,timezone){this.conversationStore=conversationStore;this.summaryStore=summaryStore;this.timezone=timezone}conversationStore;summaryStore;timezone;async assemble(input){const{conversationId,tokenBudget}=input;const freshTailCount=input.freshTailCount??8;const contextItems=await this.summaryStore.getContextItems(conversationId);if(contextItems.length===0){return{messages:[],estimatedTokens:0,stats:{rawMessageCount:0,summaryCount:0,totalContextItems:0}}}const resolved=await this.resolveItems(contextItems);let rawMessageCount=0;let summaryCount=0;const summarySignals=[];for(const item of resolved){if(item.isMessage){rawMessageCount++}else{summaryCount++;if(item.summarySignal){summarySignals.push(item.summarySignal)}}}const systemPromptAddition=buildSystemPromptAddition(summarySignals);const freshTailOrdinal=resolveFreshTailOrdinal(resolved,freshTailCount,input.freshTailMaxTokens);const baseFreshTail=resolved.filter(item=>item.ordinal>=freshTailOrdinal);const initialEvictable=resolved.filter(item=>item.ordinal<freshTailOrdinal);const freshTailOrdinals=new Set(baseFreshTail.map(item=>item.ordinal));const tailToolCallIds=collectAssistantToolCallIds(baseFreshTail);const tailPairToolResults=initialEvictable.filter(item=>{const toolResultId=extractToolResultIdFromMessage(item.message);return toolResultId!==null&&tailToolCallIds.has(toolResultId)});const mergedFreshTail=mergeFreshTailWithMatchingToolResults(baseFreshTail,tailPairToolResults,input.freshTailMaxTokens);const evictable=initialEvictable.filter(item=>!mergedFreshTail.promotedOrdinals.has(item.ordinal));const freshTail=mergedFreshTail.items;let tailTokens=0;for(const item of freshTail){tailTokens+=item.tokens}const remainingBudget=Math.max(0,tokenBudget-tailTokens);const selected=[];let evictableTokens=0;const evictableTotalTokens=evictable.reduce((sum,it)=>sum+it.tokens,0);if(evictableTotalTokens<=remainingBudget){selected.push(...evictable);evictableTokens=evictableTotalTokens}else if(hasSearchablePrompt(input.prompt)){const scored=evictable.map((item,idx)=>({item,score:scoreRelevance(item.text,input.prompt),idx}));scored.sort((a,b)=>b.score-a.score||b.idx-a.idx);const kept=[];let accum=0;for(const{item}of scored){if(accum+item.tokens<=remainingBudget){kept.push(item);accum+=item.tokens}}kept.sort((a,b)=>a.ordinal-b.ordinal);selected.push(...kept);evictableTokens=accum}else{const kept=[];let accum=0;for(let i=evictable.length-1;i>=0;i--){const item=evictable[i];if(accum+item.tokens<=remainingBudget){kept.push(item);accum+=item.tokens}else{break}}kept.reverse();selected.push(...kept);evictableTokens=accum}selected.push(...freshTail);const estimatedTokens=evictableTokens+tailTokens;const rawMessages=filterNonFreshAssistantToolCalls(selected,freshTailOrdinals,normalizeFreshTailTokenCap(input.freshTailMaxTokens)===void 0);for(let i=0;i<rawMessages.length;i++){const msg=rawMessages[i];if(msg?.role==="assistant"&&typeof msg.content==="string"){rawMessages[i]={...msg,content:[{type:"text",text:msg.content}]}}}const cleaned=rawMessages.filter(m=>!(m?.role==="assistant"&&(Array.isArray(m.content)?m.content.length===0:!m.content)));return{messages:sanitizeToolUseResultPairing(cleaned),estimatedTokens,systemPromptAddition,stats:{rawMessageCount,summaryCount,totalContextItems:resolved.length}}}async resolveItems(contextItems){const resolved=[];for(const item of contextItems){const result=await this.resolveItem(item);if(result){resolved.push(result)}}return resolved}async resolveItem(item){if(item.itemType==="message"&&item.messageId!=null){return this.resolveMessageItem(item)}if(item.itemType==="summary"&&item.summaryId!=null){return this.resolveSummaryItem(item)}return null}async resolveMessageItem(item){const msg=await this.conversationStore.getMessageById(item.messageId);if(!msg){return null}const parts=await this.conversationStore.getMessageParts(msg.messageId);if(msg.role==="assistant"&&!msg.content.trim()&&parts.length===0){return null}const roleFromStore=toRuntimeRole(msg.role,parts);const isToolResult=roleFromStore==="toolResult";const toolCallId=isToolResult?pickToolCallId(parts):void 0;const toolName=isToolResult?pickToolName(parts)??"unknown":void 0;const toolIsError=isToolResult?pickToolIsError(parts):void 0;const role=isToolResult&&!toolCallId?"assistant":roleFromStore;const content=contentFromParts(parts,role,msg.content);const contentText=typeof content==="string"?content:JSON.stringify(content)??msg.content;const tokenCount=estimateTokens(contentText);return{ordinal:item.ordinal,message:role==="assistant"?{role,content,usage:{input:0,output:tokenCount,cacheRead:0,cacheWrite:0,totalTokens:tokenCount,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}}}:{role,content,...toolCallId?{toolCallId}:{},...toolName?{toolName}:{},...role==="toolResult"&&toolIsError!==void 0?{isError:toolIsError}:{}},tokens:tokenCount,isMessage:true,text:contentText}}async resolveSummaryItem(item){const summary=await this.summaryStore.getSummary(item.summaryId);if(!summary){return null}const content=await formatSummaryContent(summary,this.summaryStore,this.timezone);const tokens=estimateTokens(content);return{ordinal:item.ordinal,message:{role:"user",content},tokens,isMessage:false,text:summary.content,summarySignal:{kind:summary.kind,depth:summary.depth,descendantCount:summary.descendantCount}}}};import{createHash}from"node:crypto";var FILE_BLOCK_RE=/<file\b([^>]*)>([\s\S]*?)<\/file>/gi;var FILE_ID_RE=/\bfile_[a-f0-9]{16}\b/gi;var CODE_EXTENSIONS=new Set(["c","cc","cpp","cs","go","h","hpp","java","js","jsx","kt","m","php","py","rb","rs","scala","sh","sql","swift","ts","tsx"]);var STRUCTURED_EXTENSIONS=new Set(["csv","json","tsv","xml","yaml","yml"]);var MIME_EXTENSION_MAP={"application/json":"json","application/xml":"xml","application/yaml":"yaml","application/x-yaml":"yaml","application/x-ndjson":"json","application/csv":"csv","application/javascript":"js","application/typescript":"ts","application/x-python-code":"py","application/x-rust":"rs","application/x-sh":"sh","text/csv":"csv","text/markdown":"md","text/plain":"txt","text/tab-separated-values":"tsv","text/x-c":"c","text/x-c++":"cpp","text/x-go":"go","text/x-java":"java","text/x-python":"py","text/x-rust":"rs","text/x-script.python":"py","text/x-shellscript":"sh","text/x-typescript":"ts","text/xml":"xml"};var STRUCTURED_MIME_PREFIXES=["application/json","application/xml","application/yaml","application/x-yaml","application/x-ndjson","text/csv","text/tab-separated-values","text/xml"];var CODE_MIME_PREFIXES=["application/javascript","application/typescript","application/x-python-code","application/x-rust","text/javascript","text/x-c","text/x-c++","text/x-go","text/x-java","text/x-python","text/x-rust","text/x-script.python","text/x-shellscript","text/x-typescript"];var TEXT_SUMMARY_SLICE_CHARS=2400;var TEXT_HEADER_LIMIT=18;function parseFileAttributes(raw){const attrs={};const attrRe=/([A-Za-z_:][A-Za-z0-9_:\-.]*)\s*=\s*("([^"]*)"|'([^']*)'|([^\s"'>]+))/g;let match;while((match=attrRe.exec(raw))!==null){const key=match[1].trim().toLowerCase();const value=(match[3]??match[4]??match[5]??"").trim();if(key.length>0&&value.length>0){attrs[key]=value}}return attrs}function normalizeTextForLine(text,maxLen){const compact=text.replace(/\s+/g," ").trim();if(compact.length<=maxLen){return compact}return`${compact.slice(0,maxLen)}...`}function collectFileNameExtension(fileName){if(!fileName){return void 0}const base=fileName.trim().split(/[\\/]/).pop()??"";const idx=base.lastIndexOf(".");if(idx<=0||idx===base.length-1){return void 0}const ext=base.slice(idx+1).toLowerCase();if(!/^[a-z0-9]{1,10}$/.test(ext)){return void 0}return ext}function guessMimeExtension(mimeType){if(!mimeType){return void 0}const normalized=mimeType.trim().toLowerCase();return MIME_EXTENSION_MAP[normalized]}function isStructured(params){const mime=params.mimeType?.trim().toLowerCase();if(mime&&STRUCTURED_MIME_PREFIXES.some(candidate=>mime.startsWith(candidate))){return true}return params.extension?STRUCTURED_EXTENSIONS.has(params.extension):false}function isCode(params){const mime=params.mimeType?.trim().toLowerCase();if(mime&&CODE_MIME_PREFIXES.some(candidate=>mime.startsWith(candidate))){return true}return params.extension?CODE_EXTENSIONS.has(params.extension):false}function uniqueOrdered(values){const seen=new Set;const out=[];for(const value of values){if(!seen.has(value)){seen.add(value);out.push(value)}}return out}function exploreJson(content){const parsed=JSON.parse(content);const describe=(value,depth=0)=>{if(depth>=2){return"..."}if(Array.isArray(value)){const sample=value.slice(0,3).map(item=>describe(item,depth+1));return`array(len=${value.length}${sample.length>0?`, sample=[${sample.join(", ")}]`:""})`}if(!value||typeof value!=="object"){return typeof value}const keys=Object.keys(value);const preview=keys.slice(0,10).join(", ");return`object(keys=${keys.length}${preview?`: ${preview}`:""})`};const topLevel=Array.isArray(parsed)?"array":typeof parsed;return[`Structured summary (JSON):`,`Top-level type: ${topLevel}.`,`Shape: ${describe(parsed)}.`].join("\n")}function parseDelimitedLine(line,delimiter){return line.split(delimiter).map(item=>item.trim()).filter(item=>item.length>0)}function exploreDelimited(content,delimiter,kind){const lines=content.split(/\r?\n/).map(line=>line.trim()).filter(line=>line.length>0);if(lines.length===0){return`Structured summary (${kind}): no rows found.`}const headers=parseDelimitedLine(lines[0],delimiter);const rowCount=Math.max(0,lines.length-1);const firstData=lines[1]?normalizeTextForLine(lines[1],180):"(no data rows)";return[`Structured summary (${kind}):`,`Rows: ${rowCount.toLocaleString("en-US")}.`,`Columns (${headers.length}): ${headers.join(", ")||"(none detected)"}.`,`First row sample: ${firstData}.`].join("\n")}function exploreYaml(content){const topLevelKeys=uniqueOrdered(content.split(/\r?\n/).map(line=>{const match=line.match(/^([A-Za-z0-9_.-]+):\s*(?:#.*)?$/);return match?match[1]:""}).filter(key=>key.length>0));return["Structured summary (YAML):",`Top-level keys (${topLevelKeys.length}): ${topLevelKeys.slice(0,30).join(", ")||"(none detected)"}.`].join("\n")}function exploreXml(content){const rootMatch=content.match(/<([A-Za-z0-9_:-]+)(\s|>)/);const rootTag=rootMatch?.[1]??"unknown";const childTags=uniqueOrdered([...content.matchAll(/<([A-Za-z0-9_:-]+)(\s|>)/g)].map(match=>match[1]).filter(tag=>tag!==rootTag).slice(0,30));return["Structured summary (XML):",`Root element: ${rootTag}.`,`Child elements seen: ${childTags.join(", ")||"(none detected)"}.`].join("\n")}function exploreStructuredData(content,mimeType,fileName){const extension=collectFileNameExtension(fileName)??guessMimeExtension(mimeType);const normalizedMime=mimeType?.trim().toLowerCase()??"";if(extension==="json"||normalizedMime.startsWith("application/json")){try{return exploreJson(content)}catch{return"Structured summary (JSON): failed to parse as valid JSON."}}if(extension==="csv"||normalizedMime.startsWith("text/csv")){return exploreDelimited(content,",","CSV")}if(extension==="tsv"||normalizedMime.startsWith("text/tab-separated-values")){return exploreDelimited(content," ","TSV")}if(extension==="xml"||normalizedMime.startsWith("text/xml")||normalizedMime.startsWith("application/xml")){return exploreXml(content)}if(extension==="yaml"||extension==="yml"||normalizedMime.includes("yaml")){return exploreYaml(content)}return["Structured summary:",`Characters: ${content.length.toLocaleString("en-US")}.`,`Lines: ${content.split(/\r?\n/).length.toLocaleString("en-US")}.`].join("\n")}function exploreCode(content,fileName){const lines=content.split(/\r?\n/);const imports=uniqueOrdered(lines.filter(line=>/^\s*(import\s+|from\s+\S+\s+import\s+|const\s+\w+\s*=\s*require\()/.test(line)).map(line=>normalizeTextForLine(line,180)).slice(0,12));const signatures=uniqueOrdered(lines.map(line=>line.trim()).filter(line=>/^(export\s+)?(async\s+)?(function|class|interface|type|const\s+\w+\s*=\s*\(|def\s+\w+\(|struct\s+\w+)/.test(line)).map(line=>normalizeTextForLine(line,200)).slice(0,24));return[`Code exploration summary${fileName?` (${fileName})`:""}:`,`Lines: ${lines.length.toLocaleString("en-US")}.`,`Imports/dependencies (${imports.length}): ${imports.join(" | ")||"none detected"}.`,`Top-level definitions (${signatures.length}): ${signatures.join(" | ")||"none detected"}.`].join("\n")}function extractTextHeaders(content){const headers=uniqueOrdered(content.split(/\r?\n/).map(line=>line.trim()).filter(line=>line.length>1).filter(line=>/^#{1,6}\s+/.test(line)||/^[A-Z0-9][A-Z0-9\s:_-]{6,}$/.test(line)).map(line=>normalizeTextForLine(line,160)).slice(0,TEXT_HEADER_LIMIT));return headers}function buildTextSample(content){if(content.length<=TEXT_SUMMARY_SLICE_CHARS*2){return content}const middleStart=Math.max(0,Math.floor(content.length/2)-Math.floor(TEXT_SUMMARY_SLICE_CHARS/2));const middleEnd=middleStart+TEXT_SUMMARY_SLICE_CHARS;const head=content.slice(0,TEXT_SUMMARY_SLICE_CHARS);const mid=content.slice(middleStart,middleEnd);const tail=content.slice(-TEXT_SUMMARY_SLICE_CHARS);return["[Document Start]",head,"[Document Middle]",mid,"[Document End]",tail].join("\n\n")}function buildTextPrompt(params){const sample=buildTextSample(params.content);return[`Summarize this large file for retrieval-time context references.`,`File name: ${params.fileName??"unknown"}`,`Mime type: ${params.mimeType??"unknown"}`,`Length: ${params.content.length.toLocaleString("en-US")} chars`,`Line count: ${params.content.split(/\r?\n/).length.toLocaleString("en-US")}`,params.headers.length>0?`Detected section headers: ${params.headers.join(" | ")}`:"Detected section headers: none","Produce 200-300 words with:","- What the document is about","- Key sections and topics","- Important names, dates, and numbers","- Any action items or constraints","Do not quote long passages verbatim.","","Document sample:",sample].join("\n")}function exploreTextDeterministicFallback(content,fileName){const normalized=content.replace(/\s+/g," ").trim();const headers=extractTextHeaders(content);const lineCount=content.split(/\r?\n/).length;const wordCount=normalized.length>0?normalized.split(/\s+/).length:0;const first=normalizeTextForLine(content.slice(0,500),500);const last=normalizeTextForLine(content.slice(-500),500);return[`Text exploration summary${fileName?` (${fileName})`:""}:`,`Characters: ${content.length.toLocaleString("en-US")}.`,`Words: ${wordCount.toLocaleString("en-US")}.`,`Lines: ${lineCount.toLocaleString("en-US")}.`,`Detected section headers: ${headers.join(" | ")||"none detected"}.`,`Opening excerpt: ${first||"(empty)"}.`,`Closing excerpt: ${last||"(empty)"}.`].join("\n")}async function exploreText(params){const headers=extractTextHeaders(params.content);if(params.summarizeText){const prompt=buildTextPrompt({content:params.content,fileName:params.fileName,mimeType:params.mimeType,headers});try{const summary=await params.summarizeText(prompt);if(typeof summary==="string"&&summary.trim().length>0){return summary.trim()}}catch{}}return exploreTextDeterministicFallback(params.content,params.fileName)}function parseFileBlocks(content){const blocks=[];let match;FILE_BLOCK_RE.lastIndex=0;while((match=FILE_BLOCK_RE.exec(content))!==null){const fullMatch=match[0];const rawAttrs=match[1]??"";const text=match[2]??"";const start=match.index;const end=start+fullMatch.length;const attributes=parseFileAttributes(rawAttrs);blocks.push({fullMatch,start,end,attributes,fileName:attributes.name,mimeType:attributes.mime,text})}return blocks}function extensionFromNameOrMime(fileName,mimeType){const fromName=collectFileNameExtension(fileName);if(fromName){return fromName}const fromMime=guessMimeExtension(mimeType);if(fromMime){return fromMime}return"txt"}function extractFileIdsFromContent(content){const matches=content.match(FILE_ID_RE)??[];return uniqueOrdered(matches.map(id=>id.toLowerCase()))}function formatFileReference(input){const name=input.fileName?.trim()||"unknown";const mime=input.mimeType?.trim()||"unknown";const byteSize=Math.max(0,input.byteSize);return[`[LCM File: ${input.fileId} | ${name} | ${mime} | ${byteSize.toLocaleString("en-US")} bytes]`,"","Exploration Summary:",input.summary.trim()||"(no summary available)"].join("\n")}function formatToolOutputReference(input){const toolName=input.toolName?.trim()||"unknown";const byteSize=Math.max(0,input.byteSize);return[`[LCM Tool Output: ${input.fileId} | tool=${toolName} | ${byteSize.toLocaleString("en-US")} bytes]`,"","Exploration Summary:",input.summary.trim()||"(no summary available)","","Use lcm_describe with the file id to inspect the full output."].join("\n")}async function generateExplorationSummary(input){const extension=extensionFromNameOrMime(input.fileName,input.mimeType);if(isStructured({mimeType:input.mimeType,extension})){return exploreStructuredData(input.content,input.mimeType,input.fileName)}if(isCode({mimeType:input.mimeType,extension})){return exploreCode(input.content,input.fileName)}return exploreText(input)}var NOOP_LCM_LOGGER={info:()=>{},warn:()=>{},error:()=>{},debug:()=>{}};function describeLogError(error){return error instanceof Error?error.message:String(error)}function createLcmLogger(api){const runtimeLogger=api.runtime.logging?.getChildLogger?.({plugin:"lossless-claw"});if(runtimeLogger){return{info:message=>runtimeLogger.info(message),warn:message=>runtimeLogger.warn(message),error:message=>runtimeLogger.error(message),debug:message=>runtimeLogger.debug?.(message)}}return{info:message=>api.logger.info(message),warn:message=>api.logger.warn(message),error:message=>api.logger.error(message),debug:message=>api.logger.debug?.(message)}}function buildSummarizerBreakerKey(params){const authProfileId=params.candidate.useLegacyAuthProfile?params.legacyAuthProfileId??"-":"-";return`provider:${params.candidate.provider};model:${params.candidate.model};authProfile:${authProfileId}`}var DEFAULT_LEAF_TARGET_TOKENS=2400;var DEFAULT_CONDENSED_TARGET_TOKENS=2e3;var LCM_SUMMARIZER_SYSTEM_PROMPT="You are a context-compaction summarization engine. Follow user instructions exactly and return plain text summary content only.";var DIAGNOSTIC_MAX_DEPTH=4;var DIAGNOSTIC_MAX_ARRAY_ITEMS=8;var DIAGNOSTIC_MAX_OBJECT_KEYS=16;var DIAGNOSTIC_MAX_CHARS=1200;var DIAGNOSTIC_SENSITIVE_KEY_PATTERN=/(api[-_]?key|authorization|token|secret|password|cookie|set-cookie|private[-_]?key|bearer)/i;var AUTH_ERROR_TEXT_PATTERN=/\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_KEYS=["status","statusCode","status_code"];var AUTH_ERROR_NESTED_KEYS=["error","response","cause","details","data","body"];var AUTH_ERROR_TOP_LEVEL_KEYS=["error","errorMessage","status","statusCode","status_code","code","details","cause","data","body"];var LcmProviderAuthError=class extends Error{provider;model;failure;constructor(params){super(buildProviderAuthWarning(params));this.name="LcmProviderAuthError";this.provider=params.provider;this.model=params.model;this.failure=params.failure}};var DEFAULT_SUMMARIZER_TIMEOUT_MS=6e4;var SummarizerTimeoutError=class extends Error{constructor(ms,label){super(`[lcm] summarizer timeout after ${ms}ms (${label})`);this.name="SummarizerTimeoutError"}};function withTimeout(promise,ms,label){return new Promise((resolve2,reject)=>{const timer=setTimeout(()=>reject(new SummarizerTimeoutError(ms,label)),ms);promise.then(val=>{clearTimeout(timer);resolve2(val)},err=>{clearTimeout(timer);reject(err)})})}function normalizeProviderId(provider){return provider.trim().toLowerCase()}function resolveProviderApiFromLegacyConfig(config,provider){if(!config||typeof config!=="object"){return void 0}const providers=config.models?.providers;if(!providers||typeof providers!=="object"){return void 0}const direct=providers[provider];if(direct&&typeof direct==="object"){const api=direct.api;if(typeof api==="string"&&api.trim()){return api.trim()}}const normalizedProvider=normalizeProviderId(provider);for(const[entryProvider,value]of Object.entries(providers)){if(normalizeProviderId(entryProvider)!==normalizedProvider){continue}if(!value||typeof value!=="object"){continue}const api=value.api;if(typeof api==="string"&&api.trim()){return api.trim()}}return void 0}function isRecord(value){return!!value&&typeof value==="object"&&!Array.isArray(value)}function normalizeTextFragments(chunks){const normalized=[];const seen=new Set;for(const chunk of chunks){const trimmed=chunk.trim();if(!trimmed||seen.has(trimmed)){continue}seen.add(trimmed);normalized.push(trimmed)}return normalized.join("\n").trim()}function collectBlockTypes(value,out){if(Array.isArray(value)){for(const entry of value){collectBlockTypes(entry,out)}return}if(!isRecord(value)){return}if(typeof value.type==="string"&&value.type.trim()){out.add(value.type.trim())}for(const nested of Object.values(value)){collectBlockTypes(nested,out)}}function isReasoningLikeType(type){if(typeof type!=="string"){return false}const normalized=type.trim().toLowerCase();return normalized.includes("reasoning")||normalized.includes("thinking")}function collectTextLikeFields(value,out){if(Array.isArray(value)){for(const entry of value){collectTextLikeFields(entry,out)}return}if(!isRecord(value)){return}if(isReasoningLikeType(value.type)){return}for(const key of["text","output_text"]){appendTextValue(value[key],out)}for(const key of["content","summary","output","message","response"]){if(key in value){collectTextLikeFields(value[key],out)}}}function appendTextValue(value,out){if(typeof value==="string"){out.push(value);return}if(Array.isArray(value)){for(const entry of value){appendTextValue(entry,out)}return}if(!isRecord(value)){return}if(typeof value.value==="string"){out.push(value.value)}if(typeof value.text==="string"){out.push(value.text)}}function normalizeCompletionSummary(content){const chunks=[];const blockTypeSet=new Set;collectTextLikeFields(content,chunks);collectBlockTypes(content,blockTypeSet);const blockTypes=[...blockTypeSet].sort((a,b)=>a.localeCompare(b));return{summary:normalizeTextFragments(chunks),blockTypes}}function formatBlockTypes(blockTypes){if(blockTypes.length===0){return"(none)"}return blockTypes.join(",")}function truncateDiagnosticText(value,maxChars=DIAGNOSTIC_MAX_CHARS){if(value.length<=maxChars){return value}return`${value.slice(0,maxChars)}...[truncated:${value.length-maxChars} chars]`}function sanitizeForDiagnostics(value,depth=0){if(depth>=DIAGNOSTIC_MAX_DEPTH){return"[max-depth]"}if(typeof value==="string"){return truncateDiagnosticText(value)}if(value===null||typeof value==="number"||typeof value==="boolean"||typeof value==="bigint"){return value}if(value===void 0){return"[undefined]"}if(typeof value==="function"){return"[function]"}if(typeof value==="symbol"){return"[symbol]"}if(Array.isArray(value)){const head=value.slice(0,DIAGNOSTIC_MAX_ARRAY_ITEMS).map(entry=>sanitizeForDiagnostics(entry,depth+1));if(value.length>DIAGNOSTIC_MAX_ARRAY_ITEMS){head.push(`[+${value.length-DIAGNOSTIC_MAX_ARRAY_ITEMS} more items]`)}return head}if(!isRecord(value)){return String(value)}const out={};const entries=Object.entries(value);for(const[key,entry]of entries.slice(0,DIAGNOSTIC_MAX_OBJECT_KEYS)){out[key]=DIAGNOSTIC_SENSITIVE_KEY_PATTERN.test(key)?"[redacted]":sanitizeForDiagnostics(entry,depth+1)}if(entries.length>DIAGNOSTIC_MAX_OBJECT_KEYS){out.__truncated_keys__=entries.length-DIAGNOSTIC_MAX_OBJECT_KEYS}return out}function formatDiagnosticPayload(value){try{const json=JSON.stringify(sanitizeForDiagnostics(value));if(!json){return'""'}return truncateDiagnosticText(json)}catch{return'"[unserializable]"'}}function collectAuthFailureText(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,DIAGNOSTIC_MAX_ARRAY_ITEMS)){collectAuthFailureText(entry,out,depth+1)}return}if(!isRecord(value)){return}for(const entry of Object.values(value).slice(0,DIAGNOSTIC_MAX_OBJECT_KEYS)){collectAuthFailureText(entry,out,depth+1)}}function extractAuthFailureStatusCode(value,depth=0){if(depth>=4||!isRecord(value)){return void 0}for(const key of AUTH_ERROR_STATUS_KEYS){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_KEYS){const nested=value[key];const statusCode=extractAuthFailureStatusCode(nested,depth+1);if(statusCode!==void 0){return statusCode}}return void 0}function hasTopLevelAuthInspectionKeys(value){return AUTH_ERROR_TOP_LEVEL_KEYS.some(key=>key in value)}function looksLikeThrownError(value){return typeof value.name==="string"&&/\berror\b/i.test(value.name)||"stack"in value||typeof value.message==="string"&&!("content"in value)&&!("response"in value)&&!("output"in value)}function pickAuthInspectionValue(value){if(!isRecord(value)){return value}if(isRecord(value.error)&&value.error.kind==="provider_auth"){return value.error}const subset={};const hasTopLevelAuthKeys=hasTopLevelAuthInspectionKeys(value);const errorLike=value instanceof Error||looksLikeThrownError(value);for(const key of AUTH_ERROR_TOP_LEVEL_KEYS){if(key in value){subset[key]=value[key]}}if((hasTopLevelAuthKeys||errorLike)&&"message"in value){subset.message=value.message}if("response"in value){const response=value.response;if(hasTopLevelAuthKeys||isRecord(response)&&hasTopLevelAuthInspectionKeys(response)||isRecord(response)&&looksLikeThrownError(response)){subset.response=response}}return Object.keys(subset).length>0?subset:{}}function extractProviderAuthFailure(value,opts){const inspectValue=pickAuthInspectionValue(value);const statusCode=extractAuthFailureStatusCode(inspectValue);const textParts=[];collectAuthFailureText(inspectValue,textParts);const normalizedMessage=textParts.join(" ").replace(/\s+/g," ").trim();const missingModelRequestScope=/\bmodel\.request\b/i.test(normalizedMessage);const hasScopeSignal=missingModelRequestScope||/\b(missing|insufficient)\s+scope\b/i.test(normalizedMessage);const hasExplicitErrorKind=isRecord(value)&&isRecord(value.error)&&value.error.kind==="provider_auth";if(opts?.requireStructuralSignal){if(statusCode!==401&&!hasExplicitErrorKind){return void 0}}else if(statusCode!==401&&!hasScopeSignal&&!AUTH_ERROR_TEXT_PATTERN.test(normalizedMessage)){return void 0}return{...statusCode!==void 0?{statusCode}:{},...normalizedMessage?{message:truncateDiagnosticText(normalizedMessage,240)}:{},missingModelRequestScope}}function buildProviderAuthWarning(params){const detailParts=[];if(params.failure.statusCode===401){detailParts.push("401")}if(params.failure.missingModelRequestScope){detailParts.push("missing model.request scope")}const detail=detailParts.length>0?`provider auth error (${detailParts.join(" / ")})`:"provider auth error";const messageSuffix=params.failure.message&&!params.failure.missingModelRequestScope?` Detail: ${params.failure.message}`:"";return`[lcm] compaction failed: ${detail}. Check that the configured summaryProvider has valid API credentials. Current: ${params.provider}/${params.model}${messageSuffix}`}function extractResponseDiagnostics(result){if(!isRecord(result)){return""}const parts=[];const topLevelKeys=Object.keys(result).slice(0,24);if(topLevelKeys.length>0){parts.push(`keys=${topLevelKeys.join(",")}`)}if("content"in result){const contentVal=result.content;if(Array.isArray(contentVal)){parts.push(`content_kind=array`);parts.push(`content_len=${contentVal.length}`)}else if(contentVal===null){parts.push(`content_kind=null`)}else{parts.push(`content_kind=${typeof contentVal}`)}parts.push(`content_preview=${formatDiagnosticPayload(contentVal)}`)}else{parts.push("content_kind=missing")}const envelopePayload={};for(const key of["summary","output","message","response"]){if(key in result){envelopePayload[key]=result[key]}}if(Object.keys(envelopePayload).length>0){parts.push(`payload_preview=${formatDiagnosticPayload(envelopePayload)}`)}for(const key of["id","request_id","x-request-id"]){const val=result[key];if(typeof val==="string"&&val.trim()){parts.push(`${key}=${val.trim()}`)}}if(typeof result.model==="string"&&result.model.trim()){parts.push(`resp_model=${result.model.trim()}`)}if(typeof result.provider==="string"&&result.provider.trim()){parts.push(`resp_provider=${result.provider.trim()}`)}if(typeof result.status==="string"&&result.status.trim()){parts.push(`status=${result.status.trim()}`)}if(isRecord(result.incomplete_details)&&typeof result.incomplete_details.reason==="string"){const reason=result.incomplete_details.reason.trim();if(reason){parts.push(`incomplete_reason=${reason}`)}}for(const key of["request_provider","request_model","request_api","request_reasoning","request_has_system","request_temperature","request_temperature_sent"]){const val=result[key];if(typeof val==="string"&&val.trim()){parts.push(`${key}=${val.trim()}`)}}if(isRecord(result.usage)){const u=result.usage;const tokens=[];for(const k of["prompt_tokens","completion_tokens","total_tokens","input","output","cacheRead","cacheWrite"]){if(typeof u[k]==="number"){tokens.push(`${k}=${u[k]}`)}}if(tokens.length>0){parts.push(tokens.join(","))}}const finishReason=typeof result.finish_reason==="string"?result.finish_reason:typeof result.stopReason==="string"?result.stopReason:typeof result.stop_reason==="string"?result.stop_reason:void 0;if(finishReason){parts.push(`finish=${finishReason}`)}const errorMessage=result.errorMessage;if(typeof errorMessage==="string"&&errorMessage.trim()){parts.push(`error_message=${truncateDiagnosticText(errorMessage.trim(),400)}`)}const errorPayload=result.error;if(errorPayload!==void 0){parts.push(`error_preview=${formatDiagnosticPayload(errorPayload)}`)}return parts.join("; ")}function collectIncompleteResponseSignals(value,out,label="response",depth=0){if(depth>=DIAGNOSTIC_MAX_DEPTH){return}if(Array.isArray(value)){value.slice(0,DIAGNOSTIC_MAX_ARRAY_ITEMS).forEach((entry,index)=>{collectIncompleteResponseSignals(entry,out,`${label}[${index}]`,depth+1)});return}if(!isRecord(value)){return}if(typeof value.status==="string"&&value.status.trim().toLowerCase()==="incomplete"){out.add(`${label}.status=incomplete`)}if(isRecord(value.incomplete_details)&&typeof value.incomplete_details.reason==="string"){const reason=value.incomplete_details.reason.trim();if(reason){out.add(`${label}.reason=${reason}`)}}for(const key of["content","output","message","response","items"]){if(key in value){collectIncompleteResponseSignals(value[key],out,`${label}.${key}`,depth+1)}}}function extractIncompleteResponseSignals(value){const signals=new Set;collectIncompleteResponseSignals(value,signals);return[...signals].sort((a,b)=>a.localeCompare(b))}function resolveTargetTokens(params){if(params.isCondensed){return Math.max(512,params.condensedTargetTokens)}const{inputTokens,mode}=params;const leafTargetTokens=Math.max(192,params.leafTargetTokens);if(mode==="aggressive"){const aggressiveCap=Math.max(96,Math.min(leafTargetTokens,Math.floor(leafTargetTokens*.55)));return Math.max(96,Math.min(aggressiveCap,Math.floor(inputTokens*.2)))}return Math.max(192,Math.min(leafTargetTokens,Math.floor(inputTokens*.35)))}function buildLeafSummaryPrompt(params){const{text,mode,targetTokens,previousSummary,customInstructions}=params;const previousContext=previousSummary?.trim()||"(none)";const policy=mode==="aggressive"?["Aggressive summary policy:","- Keep only durable facts and current task state.","- Remove examples, repetition, and low-value narrative details.","- Preserve explicit TODOs, blockers, decisions, and constraints."].join("\n"):["Normal summary policy:","- Preserve key decisions, rationale, constraints, and active tasks.","- Keep essential technical details needed to continue work safely.","- Remove obvious repetition and conversational filler."].join("\n");const instructionBlock=customInstructions?.trim()?`Operator instructions:
|
|
1
|
+
var __defProp=Object.defineProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};import{readFileSync,writeFileSync}from"node:fs";import{join as join4}from"node:path";import{homedir}from"os";import{join}from"path";function resolveOpenclawStateDir(env=process.env){const explicit=env.OPENCLAW_STATE_DIR?.trim();return explicit||join(homedir(),".openclaw")}function toNumber(value){if(typeof value==="number"&&Number.isFinite(value))return value;if(typeof value==="string"){const n=Number(value);if(Number.isFinite(n))return n}return void 0}function parseFiniteInt(value){if(value===void 0)return void 0;const parsed=parseInt(value,10);return Number.isFinite(parsed)?parsed:void 0}function parseFiniteNumber(value){if(value===void 0)return void 0;const parsed=parseFloat(value);return Number.isFinite(parsed)?parsed:void 0}function parseFallbackProviders(value){if(!value?.trim())return void 0;const entries=[];for(const part of value.split(",")){const trimmed=part.trim();if(!trimmed)continue;const slashIdx=trimmed.indexOf("/");if(slashIdx>0&&slashIdx<trimmed.length-1){const provider=trimmed.slice(0,slashIdx).trim();const model=trimmed.slice(slashIdx+1).trim();if(provider&&model){entries.push({provider,model})}}}return entries.length>0?entries:void 0}function toFallbackProviderArray(value){if(!Array.isArray(value))return void 0;const entries=[];for(const item of value){if(item&&typeof item==="object"&&!Array.isArray(item)){const p=toStr(item.provider);const m=toStr(item.model);if(p&&m)entries.push({provider:p,model:m})}}return entries.length>0?entries:void 0}function toBool(value){if(typeof value==="boolean")return value;if(value==="true")return true;if(value==="false")return false;return void 0}function toStr(value){if(typeof value==="string"){const trimmed=value.trim();return trimmed.length>0?trimmed:void 0}return void 0}function toProactiveThresholdCompactionMode(value){const normalized=toStr(value)?.toLowerCase();if(normalized==="inline"||normalized==="deferred"){return normalized}return void 0}function toStrArray(value){if(Array.isArray(value)){const normalized=value.map(entry=>toStr(entry)).filter(entry=>typeof entry==="string");return normalized.length>0?normalized:[]}const single=toStr(value);if(!single){return void 0}return single.split(",").map(entry=>entry.trim()).filter(Boolean)}function toRecord(value){return value&&typeof value==="object"&&!Array.isArray(value)?value:void 0}function parseEnvStrArray(value){if(value===void 0){return void 0}return value.split(",").map(entry=>entry.trim()).filter(Boolean)}function resolvePatternArray(params){const pluginPatterns=toStrArray(params.pluginValue);const pluginHasPatterns=(pluginPatterns?.length??0)>0;if(params.envValue!==void 0){return{patterns:parseEnvStrArray(params.envValue)??[],source:"env",envOverridesPluginConfig:pluginHasPatterns}}if(pluginPatterns!==void 0){return{patterns:pluginPatterns,source:"plugin-config",envOverridesPluginConfig:false}}return{patterns:[],source:"default",envOverridesPluginConfig:false}}function describeLcmConfigSource(source){switch(source){case"env":return"env";case"plugin-config":return"plugin config";case"default":return"defaults"}}function resolveLcmConfigWithDiagnostics(env=process.env,pluginConfig){const pc=pluginConfig??{};const cacheAwareCompaction=toRecord(pc.cacheAwareCompaction);const dynamicLeafChunkTokens=toRecord(pc.dynamicLeafChunkTokens);const proactiveThresholdCompactionMode=toProactiveThresholdCompactionMode(env.LCM_PROACTIVE_THRESHOLD_COMPACTION_MODE)??toProactiveThresholdCompactionMode(pc.proactiveThresholdCompactionMode)??"deferred";const resolvedLeafChunkTokens=parseFiniteInt(env.LCM_LEAF_CHUNK_TOKENS)??toNumber(pc.leafChunkTokens)??2e4;const resolvedBootstrapMaxTokens=parseFiniteInt(env.LCM_BOOTSTRAP_MAX_TOKENS)??toNumber(pc.bootstrapMaxTokens)??Math.max(6e3,Math.floor(resolvedLeafChunkTokens*.3));const envDelegationTimeoutMs=env.LCM_DELEGATION_TIMEOUT_MS!==void 0?toNumber(env.LCM_DELEGATION_TIMEOUT_MS):void 0;const resolvedDynamicLeafChunkMax=Math.max(resolvedLeafChunkTokens,parseFiniteInt(env.LCM_DYNAMIC_LEAF_CHUNK_TOKENS_MAX)??toNumber(dynamicLeafChunkTokens?.max)??Math.floor(resolvedLeafChunkTokens*2));const resolvedHotCachePressureFactor=Math.max(1,parseFiniteNumber(env.LCM_HOT_CACHE_PRESSURE_FACTOR)??toNumber(cacheAwareCompaction?.hotCachePressureFactor)??4);const resolvedHotCacheBudgetHeadroomRatio=Math.min(.95,Math.max(0,parseFiniteNumber(env.LCM_HOT_CACHE_BUDGET_HEADROOM_RATIO)??toNumber(cacheAwareCompaction?.hotCacheBudgetHeadroomRatio)??.2));const resolvedColdCacheObservationThreshold=Math.max(1,Math.floor(parseFiniteNumber(env.LCM_COLD_CACHE_OBSERVATION_THRESHOLD)??toNumber(cacheAwareCompaction?.coldCacheObservationThreshold)??3));const ignoreSessionPatterns=resolvePatternArray({envValue:env.LCM_IGNORE_SESSION_PATTERNS,pluginValue:pc.ignoreSessionPatterns});const statelessSessionPatterns=resolvePatternArray({envValue:env.LCM_STATELESS_SESSION_PATTERNS,pluginValue:pc.statelessSessionPatterns});return{config:{enabled:env.LCM_ENABLED!==void 0?env.LCM_ENABLED!=="false":toBool(pc.enabled)??true,databasePath:env.LCM_DATABASE_PATH??toStr(pc.dbPath)??toStr(pc.databasePath)??join(resolveOpenclawStateDir(env),"lcm.db"),largeFilesDir:env.LCM_LARGE_FILES_DIR?.trim()??toStr(pc.largeFilesDir)??join(resolveOpenclawStateDir(env),"lcm-files"),ignoreSessionPatterns:ignoreSessionPatterns.patterns,statelessSessionPatterns:statelessSessionPatterns.patterns,skipStatelessSessions:env.LCM_SKIP_STATELESS_SESSIONS!==void 0?env.LCM_SKIP_STATELESS_SESSIONS==="true":toBool(pc.skipStatelessSessions)??true,contextThreshold:parseFiniteNumber(env.LCM_CONTEXT_THRESHOLD)??toNumber(pc.contextThreshold)??.75,freshTailCount:parseFiniteInt(env.LCM_FRESH_TAIL_COUNT)??toNumber(pc.freshTailCount)??64,freshTailMaxTokens:parseFiniteInt(env.LCM_FRESH_TAIL_MAX_TOKENS)??toNumber(pc.freshTailMaxTokens)??void 0,newSessionRetainDepth:parseFiniteInt(env.LCM_NEW_SESSION_RETAIN_DEPTH)??toNumber(pc.newSessionRetainDepth)??2,leafMinFanout:parseFiniteInt(env.LCM_LEAF_MIN_FANOUT)??toNumber(pc.leafMinFanout)??8,condensedMinFanout:parseFiniteInt(env.LCM_CONDENSED_MIN_FANOUT)??toNumber(pc.condensedMinFanout)??4,condensedMinFanoutHard:parseFiniteInt(env.LCM_CONDENSED_MIN_FANOUT_HARD)??toNumber(pc.condensedMinFanoutHard)??2,incrementalMaxDepth:parseFiniteInt(env.LCM_INCREMENTAL_MAX_DEPTH)??toNumber(pc.incrementalMaxDepth)??1,leafChunkTokens:resolvedLeafChunkTokens,bootstrapMaxTokens:resolvedBootstrapMaxTokens,leafTargetTokens:parseFiniteInt(env.LCM_LEAF_TARGET_TOKENS)??toNumber(pc.leafTargetTokens)??2400,condensedTargetTokens:parseFiniteInt(env.LCM_CONDENSED_TARGET_TOKENS)??toNumber(pc.condensedTargetTokens)??2e3,maxExpandTokens:parseFiniteInt(env.LCM_MAX_EXPAND_TOKENS)??toNumber(pc.maxExpandTokens)??4e3,largeFileTokenThreshold:parseFiniteInt(env.LCM_LARGE_FILE_TOKEN_THRESHOLD)??toNumber(pc.largeFileThresholdTokens)??toNumber(pc.largeFileTokenThreshold)??25e3,summaryProvider:env.LCM_SUMMARY_PROVIDER?.trim()??toStr(pc.summaryProvider)??"",summaryModel:env.LCM_SUMMARY_MODEL?.trim()??toStr(pc.summaryModel)??"",largeFileSummaryProvider:env.LCM_LARGE_FILE_SUMMARY_PROVIDER?.trim()??toStr(pc.largeFileSummaryProvider)??"",largeFileSummaryModel:env.LCM_LARGE_FILE_SUMMARY_MODEL?.trim()??toStr(pc.largeFileSummaryModel)??"",expansionProvider:env.LCM_EXPANSION_PROVIDER?.trim()??toStr(pc.expansionProvider)??"",expansionModel:env.LCM_EXPANSION_MODEL?.trim()??toStr(pc.expansionModel)??"",delegationTimeoutMs:envDelegationTimeoutMs??toNumber(pc.delegationTimeoutMs)??12e4,summaryTimeoutMs:parseFiniteInt(env.LCM_SUMMARY_TIMEOUT_MS)??toNumber(pc.summaryTimeoutMs)??6e4,timezone:env.TZ??toStr(pc.timezone)??Intl.DateTimeFormat().resolvedOptions().timeZone,pruneHeartbeatOk:env.LCM_PRUNE_HEARTBEAT_OK!==void 0?env.LCM_PRUNE_HEARTBEAT_OK==="true":toBool(pc.pruneHeartbeatOk)??false,transcriptGcEnabled:env.LCM_TRANSCRIPT_GC_ENABLED!==void 0?env.LCM_TRANSCRIPT_GC_ENABLED==="true":toBool(pc.transcriptGcEnabled)??false,proactiveThresholdCompactionMode,maxAssemblyTokenBudget:parseFiniteInt(env.LCM_MAX_ASSEMBLY_TOKEN_BUDGET)??toNumber(pc.maxAssemblyTokenBudget)??void 0,summaryMaxOverageFactor:parseFiniteNumber(env.LCM_SUMMARY_MAX_OVERAGE_FACTOR)??toNumber(pc.summaryMaxOverageFactor)??3,customInstructions:env.LCM_CUSTOM_INSTRUCTIONS?.trim()??toStr(pc.customInstructions)??"",circuitBreakerThreshold:parseFiniteInt(env.LCM_CIRCUIT_BREAKER_THRESHOLD)??toNumber(pc.circuitBreakerThreshold)??5,circuitBreakerCooldownMs:parseFiniteInt(env.LCM_CIRCUIT_BREAKER_COOLDOWN_MS)??toNumber(pc.circuitBreakerCooldownMs)??18e5,fallbackProviders:parseFallbackProviders(env.LCM_FALLBACK_PROVIDERS)??toFallbackProviderArray(pc.fallbackProviders)??[],cacheAwareCompaction:{enabled:env.LCM_CACHE_AWARE_COMPACTION_ENABLED!==void 0?env.LCM_CACHE_AWARE_COMPACTION_ENABLED!=="false":toBool(cacheAwareCompaction?.enabled)??true,cacheTTLSeconds:parseFiniteInt(env.LCM_CACHE_TTL_SECONDS)??toNumber(cacheAwareCompaction?.cacheTTLSeconds)??300,maxColdCacheCatchupPasses:parseFiniteInt(env.LCM_MAX_COLD_CACHE_CATCHUP_PASSES)??toNumber(cacheAwareCompaction?.maxColdCacheCatchupPasses)??2,hotCachePressureFactor:resolvedHotCachePressureFactor,hotCacheBudgetHeadroomRatio:resolvedHotCacheBudgetHeadroomRatio,coldCacheObservationThreshold:resolvedColdCacheObservationThreshold},dynamicLeafChunkTokens:{enabled:env.LCM_DYNAMIC_LEAF_CHUNK_TOKENS_ENABLED!==void 0?env.LCM_DYNAMIC_LEAF_CHUNK_TOKENS_ENABLED==="true":toBool(dynamicLeafChunkTokens?.enabled)??true,max:resolvedDynamicLeafChunkMax}},diagnostics:{ignoreSessionPatternsSource:ignoreSessionPatterns.source,statelessSessionPatternsSource:statelessSessionPatterns.source,ignoreSessionPatternsEnvOverridesPluginConfig:ignoreSessionPatterns.envOverridesPluginConfig,statelessSessionPatternsEnvOverridesPluginConfig:statelessSessionPatterns.envOverridesPluginConfig}}}import{mkdirSync}from"node:fs";import{dirname,resolve}from"node:path";import{DatabaseSync}from"node:sqlite";var SQLITE_BUSY_TIMEOUT_MS=3e4;var connectionsByPath=new Map;var connectionIndex=new Map;function isInMemoryPath(dbPath){const normalized=dbPath.trim();return normalized===":memory:"||normalized.startsWith("file::memory:")}function getFileBackedDatabasePath(dbPath){const trimmed=dbPath.trim();if(!trimmed||isInMemoryPath(trimmed)){return null}return resolve(trimmed)}function normalizePath(dbPath){const fileBackedDatabasePath=getFileBackedDatabasePath(dbPath);if(!fileBackedDatabasePath){const trimmed=dbPath.trim();return trimmed.length>0?trimmed:":memory:"}return fileBackedDatabasePath}function ensureDbDirectory(dbPath){const fileBackedDatabasePath=getFileBackedDatabasePath(dbPath);if(!fileBackedDatabasePath){return}mkdirSync(dirname(fileBackedDatabasePath),{recursive:true})}function configureConnection(db){db.exec("PRAGMA journal_mode = WAL");db.exec(`PRAGMA busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`);db.exec("PRAGMA foreign_keys = ON");db.exec("PRAGMA cache_size = -65536");db.exec("PRAGMA synchronous = NORMAL");db.exec("PRAGMA temp_store = MEMORY");return db}function trackConnection(dbPath,db){const key=normalizePath(dbPath);let entries=connectionsByPath.get(key);if(!entries){entries=new Set;connectionsByPath.set(key,entries)}entries.add(db);connectionIndex.set(db,key)}function untrackConnection(db){const key=connectionIndex.get(db);if(!key){return}const entries=connectionsByPath.get(key);if(entries){entries.delete(db);if(entries.size===0){connectionsByPath.delete(key)}}connectionIndex.delete(db)}function closeDatabase(db){if(!db){return}try{try{db.exec("PRAGMA optimize")}catch{}db.close()}catch{}finally{untrackConnection(db)}}function createLcmDatabaseConnection(dbPath){ensureDbDirectory(dbPath);const db=new DatabaseSync(dbPath);try{configureConnection(db)}catch(err){try{db.close()}catch{}throw err}trackConnection(dbPath,db);return db}function closeLcmConnection(target){if(target&&typeof target!=="string"){closeDatabase(target);return}if(typeof target==="string"){const key=normalizePath(target);const entries=connectionsByPath.get(key);if(!entries){return}for(const db of[...entries]){closeDatabase(db)}connectionsByPath.delete(key);return}for(const db of[...connectionIndex.keys()]){closeDatabase(db)}connectionsByPath.clear();connectionIndex.clear()}import{createHash as createHash3,randomUUID as randomUUID2}from"node:crypto";import{createReadStream}from"node:fs";import{mkdir,open,stat,writeFile}from"node:fs/promises";import{join as join3}from"node:path";import{createInterface}from"node:readline";import{SessionManager}from"@mariozechner/pi-coding-agent";var TOOL_CALL_TYPES=new Set(["toolCall","toolUse","tool_use","tool-use","functionCall","function_call"]);var OPENAI_FUNCTION_CALL_TYPES=new Set(["functionCall","function_call"]);function extractToolCallId(block){if(typeof block.id==="string"&&block.id){return block.id}if(typeof block.call_id==="string"&&block.call_id){return block.call_id}return null}function normalizeAssistantReasoningBlocks(message){if(!Array.isArray(message.content)){return message}let sawToolCall=false;let reasoningAfterToolCall=false;let functionCallCount=0;for(const block of message.content){if(!block||typeof block!=="object"){return message}const type=block.type;if(type==="reasoning"||type==="thinking"){if(sawToolCall){reasoningAfterToolCall=true}continue}if(typeof type==="string"&&TOOL_CALL_TYPES.has(type)){sawToolCall=true;if(OPENAI_FUNCTION_CALL_TYPES.has(type)){functionCallCount+=1}continue}return message}if(!reasoningAfterToolCall||functionCallCount!==1){return message}const reasoning=message.content.filter(block=>{const type=block.type;return type==="reasoning"||type==="thinking"});const toolCalls=message.content.filter(block=>{const type=block.type;return typeof type==="string"&&TOOL_CALL_TYPES.has(type)});return{...message,content:[...reasoning,...toolCalls]}}function extractToolCallsFromAssistant(msg){const content=msg.content;if(!Array.isArray(content)){return[]}const toolCalls=[];for(const block of content){if(!block||typeof block!=="object"){continue}const rec=block;const id=extractToolCallId(rec);if(!id){continue}if(typeof rec.type==="string"&&TOOL_CALL_TYPES.has(rec.type)){toolCalls.push({id,name:typeof rec.name==="string"?rec.name:void 0})}}return toolCalls}function extractToolResultId(msg){if(typeof msg.toolCallId==="string"&&msg.toolCallId){return msg.toolCallId}if(typeof msg.toolUseId==="string"&&msg.toolUseId){return msg.toolUseId}return null}function makeMissingToolResult(params){return{role:"toolResult",toolCallId:params.toolCallId,toolName:params.toolName??"unknown",content:[{type:"text",text:"[lossless-claw] missing tool result in session history; inserted synthetic error result for transcript repair."}],isError:true,timestamp:Date.now()}}function sanitizeToolUseResultPairing(messages){const out=[];const seenToolResultIds=new Set;let droppedDuplicateCount=0;let droppedOrphanCount=0;let moved=false;let changed=false;const pushToolResult=msg=>{const id=extractToolResultId(msg);if(id&&seenToolResultIds.has(id)){droppedDuplicateCount+=1;changed=true;return}if(id){seenToolResultIds.add(id)}out.push(msg)};for(let i=0;i<messages.length;i+=1){const msg=messages[i];if(!msg||typeof msg!=="object"){out.push(msg);continue}const role=msg.role;if(role!=="assistant"){if(role!=="toolResult"){out.push(msg)}else{droppedOrphanCount+=1;changed=true}continue}const normalizedAssistant=normalizeAssistantReasoningBlocks(msg);if(normalizedAssistant!==msg){changed=true}const stopReason=normalizedAssistant.stopReason;if(stopReason==="error"||stopReason==="aborted"){out.push(normalizedAssistant);continue}const toolCalls=extractToolCallsFromAssistant(normalizedAssistant);if(toolCalls.length===0){out.push(normalizedAssistant);continue}const toolCallIds=new Set(toolCalls.map(t=>t.id));const spanResultsById=new Map;const remainder=[];let j=i+1;for(;j<messages.length;j+=1){const next=messages[j];if(!next||typeof next!=="object"){remainder.push(next);continue}const nextRole=next.role;if(nextRole==="assistant"){break}if(nextRole==="toolResult"){const id=extractToolResultId(next);if(id&&toolCallIds.has(id)){if(seenToolResultIds.has(id)){droppedDuplicateCount+=1;changed=true;continue}if(!spanResultsById.has(id)){spanResultsById.set(id,next)}continue}}if(next.role!=="toolResult"){remainder.push(next)}else{droppedOrphanCount+=1;changed=true}}out.push(normalizedAssistant);if(spanResultsById.size>0&&remainder.length>0){moved=true;changed=true}for(const call of toolCalls){const existing=spanResultsById.get(call.id);if(existing){pushToolResult(existing)}else{const missing=makeMissingToolResult({toolCallId:call.id,toolName:call.name});changed=true;pushToolResult(missing)}}for(const rem of remainder){out.push(rem)}i=j-1}const changedOrMoved=changed||moved;return changedOrMoved?out:messages}function isCjkCodePoint(cp){return cp>=19968&&cp<=40959||cp>=13312&&cp<=19903||cp>=131072&&cp<=173791||cp>=173824&&cp<=177983||cp>=177984&&cp<=178207||cp>=178208&&cp<=183983||cp>=183984&&cp<=191471||cp>=12288&&cp<=12351||cp>=12352&&cp<=12543||cp>=44032&&cp<=55215||cp>=65280&&cp<=65519}function estimateCodePointTokens(cp){if(isCjkCodePoint(cp)){return 1.5}if(cp>65535){return 2}return .25}function estimateTokens(text){let tokens=0;for(const char of text){const cp=char.codePointAt(0)??0;tokens+=estimateCodePointTokens(cp)}return Math.ceil(tokens)}function truncateTextToEstimatedTokens(text,maxTokens){if(maxTokens<=0||!text){return""}let tokens=0;let end=0;for(const char of text){const cp=char.codePointAt(0)??0;const nextTokens=tokens+estimateCodePointTokens(cp);if(Math.ceil(nextTokens)>maxTokens){break}tokens=nextTokens;end+=char.length}return text.slice(0,end)}var TOOL_CALL_TYPES2=new Set(["toolCall","toolUse","tool_use","tool-use","functionCall","function_call"]);function buildSystemPromptAddition(summarySignals){if(summarySignals.length===0){return void 0}const maxDepth=summarySignals.reduce((deepest,signal)=>Math.max(deepest,signal.depth),0);const condensedCount=summarySignals.filter(signal=>signal.kind==="condensed").length;const heavilyCompacted=maxDepth>=2||condensedCount>=2;const sections=[];sections.push("## Compacted Conversation Context","","Summaries above are compressed context, not full detail.","","Treat summaries as compressed recall cues rather than proof of exact wording or exact values.","",'If a summary includes an "Expand for details about:" footer, use it as a cue to expand before asserting specifics.');if(heavilyCompacted){sections.push("","**Deeply compacted context: expand before asserting specifics.**","","Before answering with exact commands, SHAs, paths, timestamps, config values, or causal chains, expand for the missing detail.","","Default recall flow for precision work:","1) `lcm_grep` to locate relevant summary/message IDs","2) `lcm_expand_query` with a focused prompt","3) Answer directly from the retrieved evidence","","Keep raw summary IDs in tool context for follow-up; do not include them in the user-facing answer unless the user asks for sources or IDs.","",'`lcm_grep` tips: prefer `mode: "full_text"` for keyword/topic lookup, quote exact multi-word phrases, use `sort: "relevance"` for older-topic retrieval, and use `sort: "hybrid"` when recency should still influence ranking.',"`lcm_expand_query(query: ...)` uses the same FTS5 full-text search rules as `lcm_grep`: terms are ANDed by default, so extra query words narrow results. Keep `query` to 1-3 distinctive terms or a quoted phrase, and put the natural-language question in `prompt`.","","**Uncertainty checklist (run before answering):**","- Am I making an exact factual claim from a compressed or condensed summary?","- Could compaction have omitted a crucial detail?","- Would I need an expansion step if the user asks for proof or the exact text?","- Should I state uncertainty instead of asserting specifics until I expand?","","If yes to any item, expand first or explicitly say that you need to expand.","","Do not guess exact commands, SHAs, file paths, timestamps, config values, or causal claims from condensed summaries. Expand first or explicitly say that you need to expand.")}else{sections.push("","For exact commands, SHAs, paths, timestamps, config values, or causal chains, expand for details before answering.","State uncertainty instead of guessing from compressed summaries.")}return sections.join("\n")}function parseJson(value){if(typeof value!=="string"||!value.trim()){return void 0}try{return JSON.parse(value)}catch{return void 0}}function getOriginalRole(parts){for(const part of parts){const decoded=parseJson(part.metadata);if(!decoded||typeof decoded!=="object"){continue}const role=decoded.originalRole;if(typeof role==="string"&&role.length>0){return role}}return null}function getPartMetadata(part){const decoded=parseJson(part.metadata);if(!decoded||typeof decoded!=="object"){return{}}const record=decoded;return{originalRole:typeof record.originalRole==="string"&&record.originalRole.length>0?record.originalRole:void 0,rawType:typeof record.rawType==="string"&&record.rawType.length>0?record.rawType:void 0,raw:record.raw}}function parseStoredValue(value){if(typeof value!=="string"||value.length===0){return void 0}const parsed=parseJson(value);return parsed!==void 0?parsed:value}function reasoningBlockFromPart(part,rawType){const type=rawType==="thinking"?"thinking":"reasoning";if(typeof part.textContent==="string"&&part.textContent.length>0){return type==="thinking"?{type,thinking:part.textContent}:{type,text:part.textContent}}return{type}}function tryRestoreOpenAIReasoning(raw){if(raw.type!=="thinking")return null;const sig=raw.thinkingSignature;if(typeof sig!=="string"||!sig.startsWith("{"))return null;try{const parsed=JSON.parse(sig);if(parsed.type==="reasoning"&&typeof parsed.id==="string"){return parsed}}catch{}return null}function toolCallBlockFromPart(part,rawType){const type=rawType==="function_call"||rawType==="functionCall"||rawType==="tool_use"||rawType==="tool-use"||rawType==="toolUse"||rawType==="toolCall"?rawType:"toolCall";const input=parseStoredValue(part.toolInput);const block={type};if(type==="function_call"){if(typeof part.toolCallId==="string"&&part.toolCallId.length>0){block.call_id=part.toolCallId}if(typeof part.toolName==="string"&&part.toolName.length>0){block.name=part.toolName}if(input!==void 0){block.arguments=input}return block}block.id=typeof part.toolCallId==="string"&&part.toolCallId.length>0?part.toolCallId:`toolu_lcm_${part.partId??"unknown"}`;if(typeof part.toolName==="string"&&part.toolName.length>0){block.name=part.toolName}if(input!==void 0){if(type==="functionCall"||type==="toolCall"){block.arguments=input}else{block.input=input}}return block}function toolResultBlockFromPart(part,rawType,raw){if(raw&&typeof raw.text==="string"&&raw.output===void 0&&raw.content===void 0&&(part.toolOutput==null||part.toolOutput==="")&&(part.textContent==null||part.textContent===raw.text)){return{type:"text",text:raw.text}}const type=rawType==="function_call_output"||rawType==="toolResult"||rawType==="tool_result"?rawType:"tool_result";const output=parseStoredValue(part.toolOutput);const block={type};if(typeof part.toolName==="string"&&part.toolName.length>0){block.name=part.toolName}if(output!==void 0){block.output=output}else if(typeof part.textContent==="string"){block.output=part.textContent}else if(raw&&raw.output!==void 0){block.output=raw.output}else if(raw&&raw.content!==void 0){block.content=raw.content}else{block.output=""}if(raw&&typeof raw.is_error==="boolean"){block.is_error=raw.is_error}else if(raw&&typeof raw.isError==="boolean"){block.isError=raw.isError}if(type==="function_call_output"){if(typeof part.toolCallId==="string"&&part.toolCallId.length>0){block.call_id=part.toolCallId}return block}if(typeof part.toolCallId==="string"&&part.toolCallId.length>0){block.tool_use_id=part.toolCallId}return block}function toRuntimeRole(dbRole,parts){const originalRole=getOriginalRole(parts);if(originalRole==="toolResult"){return"toolResult"}if(originalRole==="assistant"){return"assistant"}if(originalRole==="user"){return"user"}if(originalRole==="system"){return"user"}if(dbRole==="tool"){return"toolResult"}if(dbRole==="assistant"){return"assistant"}return"user"}function blockFromPart(part){const metadata=getPartMetadata(part);if(metadata.raw&&typeof metadata.raw==="object"){const restored=tryRestoreOpenAIReasoning(metadata.raw);if(restored)return restored;const rawType=metadata.raw.type;const isToolBlock=rawType==="toolCall"||rawType==="tool_use"||rawType==="tool-use"||rawType==="toolUse"||rawType==="functionCall"||rawType==="function_call"||rawType==="function_call_output"||rawType==="toolResult"||rawType==="tool_result";if(!isToolBlock){return metadata.raw}const rawRecord=metadata.raw;const rawToolCallId=typeof rawRecord.id==="string"&&rawRecord.id.length>0?rawRecord.id:typeof rawRecord.call_id==="string"&&rawRecord.call_id.length>0?rawRecord.call_id:void 0;if(rawToolCallId){if(typeof part.toolCallId!=="string"||part.toolCallId.length===0){part.toolCallId=rawToolCallId}}if(typeof rawRecord.name==="string"&&rawRecord.name.length>0){if(typeof part.toolName!=="string"||part.toolName.length===0){part.toolName=rawRecord.name}}if(part.toolInput==null||part.toolInput===""){const rawArgs=rawRecord.arguments??rawRecord.input;if(rawArgs!==void 0){part.toolInput=typeof rawArgs==="string"?rawArgs:JSON.stringify(rawArgs)}}}if(part.partType==="reasoning"){return reasoningBlockFromPart(part,metadata.rawType)}if(part.partType==="tool"){if(metadata.originalRole==="toolResult"||metadata.rawType==="function_call_output"){return toolResultBlockFromPart(part,metadata.rawType,metadata.raw&&typeof metadata.raw==="object"?metadata.raw:void 0)}return toolCallBlockFromPart(part,metadata.rawType)}if(metadata.rawType==="function_call"||metadata.rawType==="functionCall"||metadata.rawType==="tool_use"||metadata.rawType==="tool-use"||metadata.rawType==="toolUse"||metadata.rawType==="toolCall"){return toolCallBlockFromPart(part,metadata.rawType)}if(metadata.rawType==="function_call_output"||metadata.rawType==="tool_result"||metadata.rawType==="toolResult"){return toolResultBlockFromPart(part,metadata.rawType,metadata.raw&&typeof metadata.raw==="object"?metadata.raw:void 0)}if(part.partType==="text"){return{type:"text",text:part.textContent??""}}if(typeof part.textContent==="string"&&part.textContent.length>0){return{type:"text",text:part.textContent}}const decodedFallback=parseJson(part.metadata);if(decodedFallback&&typeof decodedFallback==="object"){return{type:"text",text:JSON.stringify(decodedFallback)}}return{type:"text",text:""}}function contentFromParts(parts,role,fallbackContent){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&&blocks[0]&&typeof blocks[0]==="object"&&blocks[0].type==="text"&&typeof blocks[0].text==="string"){return blocks[0].text}return blocks}function pickToolCallId(parts){for(const part of parts){if(typeof part.toolCallId==="string"&&part.toolCallId.length>0){return part.toolCallId}const decoded=parseJson(part.metadata);if(!decoded||typeof decoded!=="object"){continue}const metadataToolCallId=decoded.toolCallId;if(typeof metadataToolCallId==="string"&&metadataToolCallId.length>0){return metadataToolCallId}const raw=decoded.raw;if(!raw||typeof raw!=="object"){continue}const maybe=raw.toolCallId;if(typeof maybe==="string"&&maybe.length>0){return maybe}const maybeSnake=raw.tool_call_id;if(typeof maybeSnake==="string"&&maybeSnake.length>0){return maybeSnake}}return void 0}function pickToolName(parts){for(const part of parts){if(typeof part.toolName==="string"&&part.toolName.length>0){return part.toolName}const decoded=parseJson(part.metadata);if(!decoded||typeof decoded!=="object"){continue}const metadataToolName=decoded.toolName;if(typeof metadataToolName==="string"&&metadataToolName.length>0){return metadataToolName}const raw=decoded.raw;if(!raw||typeof raw!=="object"){continue}const maybe=raw.name;if(typeof maybe==="string"&&maybe.length>0){return maybe}const maybeCamel=raw.toolName;if(typeof maybeCamel==="string"&&maybeCamel.length>0){return maybeCamel}}return void 0}function pickToolIsError(parts){for(const part of parts){const decoded=parseJson(part.metadata);if(!decoded||typeof decoded!=="object"){continue}const metadataIsError=decoded.isError;if(typeof metadataIsError==="boolean"){return metadataIsError}}return void 0}function extractToolCallId2(block){if(typeof block.id==="string"&&block.id.length>0){return block.id}if(typeof block.call_id==="string"&&block.call_id.length>0){return block.call_id}return null}function extractToolCallIdsFromAssistant(message){if(message?.role!=="assistant"||!Array.isArray(message.content)){return[]}const ids=[];for(const block of message.content){if(!block||typeof block!=="object"){continue}const record=block;if(typeof record.type!=="string"||!TOOL_CALL_TYPES2.has(record.type)){continue}const id=extractToolCallId2(record);if(id){ids.push(id)}}return ids}function extractToolResultIdFromMessage(message){if(!message||typeof message!=="object"){return null}if(typeof message.toolCallId==="string"&&message.toolCallId.length>0){return message.toolCallId}if(typeof message.toolUseId==="string"&&message.toolUseId.length>0){return message.toolUseId}return null}function collectAssistantToolCallIds(items){const ids=new Set;for(const item of items){for(const id of extractToolCallIdsFromAssistant(item.message)){ids.add(id)}}return ids}function normalizeFreshTailTokenCap(freshTailMaxTokens){if(typeof freshTailMaxTokens==="number"&&Number.isFinite(freshTailMaxTokens)&&freshTailMaxTokens>=0){return Math.floor(freshTailMaxTokens)}return void 0}function mergeFreshTailWithMatchingToolResults(freshTail,matchingToolResults,freshTailMaxTokens){if(matchingToolResults.length===0){return{items:freshTail,promotedOrdinals:new Set}}const resultsById=new Map;for(const item of matchingToolResults){const toolResultId=extractToolResultIdFromMessage(item.message);if(!toolResultId){continue}const existing=resultsById.get(toolResultId);if(existing){existing.push(item)}else{resultsById.set(toolResultId,[item])}}const merged=[];const promotedOrdinals=new Set;const tokenCap=normalizeFreshTailTokenCap(freshTailMaxTokens);let mergedTokens=freshTail.reduce((sum,item)=>sum+item.tokens,0);for(const item of freshTail){merged.push(item);const toolCallIds=extractToolCallIdsFromAssistant(item.message);if(toolCallIds.length===0){continue}for(const toolCallId of toolCallIds){const matches=resultsById.get(toolCallId);if(!matches){continue}for(const match of matches){if(promotedOrdinals.has(match.ordinal)){continue}if(typeof tokenCap==="number"&&mergedTokens+match.tokens>tokenCap){continue}merged.push(match);promotedOrdinals.add(match.ordinal);mergedTokens+=match.tokens}}}if(typeof tokenCap!=="number"){for(const item of matchingToolResults){if(!promotedOrdinals.has(item.ordinal)){merged.push(item)}}}return{items:merged,promotedOrdinals}}function filterNonFreshAssistantToolCalls(items,freshTailOrdinals,preserveFreshTailToolCalls=true){const availableToolResultIds=new Set;for(const item of items){const toolResultId=extractToolResultIdFromMessage(item.message);if(toolResultId){availableToolResultIds.add(toolResultId)}}const filteredMessages=[];for(const item of items){if(item.message?.role!=="assistant"||preserveFreshTailToolCalls&&freshTailOrdinals.has(item.ordinal)){filteredMessages.push(item.message);continue}if(!Array.isArray(item.message.content)){filteredMessages.push(item.message);continue}let removedAny=false;const content=item.message.content.filter(block=>{if(!block||typeof block!=="object"){return true}const record=block;if(typeof record.type!=="string"||!TOOL_CALL_TYPES2.has(record.type)){return true}const toolCallId=extractToolCallId2(record);if(!toolCallId||availableToolResultIds.has(toolCallId)){return true}removedAny=true;return false});if(content.length===0){continue}if(!removedAny){filteredMessages.push(item.message);continue}filteredMessages.push({...item.message,content})}return filteredMessages}function formatDateForAttribute(date,timezone){const tz=timezone??"UTC";try{const fmt=new Intl.DateTimeFormat("en-CA",{timeZone:tz,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:false});const p=Object.fromEntries(fmt.formatToParts(date).map(part=>[part.type,part.value]));return`${p.year}-${p.month}-${p.day}T${p.hour}:${p.minute}:${p.second}`}catch{return date.toISOString()}}async function formatSummaryContent(summary,summaryStore,timezone){const attributes=[`id="${summary.summaryId}"`,`kind="${summary.kind}"`,`depth="${summary.depth}"`,`descendant_count="${summary.descendantCount}"`];if(summary.earliestAt){attributes.push(`earliest_at="${formatDateForAttribute(summary.earliestAt,timezone)}"`)}if(summary.latestAt){attributes.push(`latest_at="${formatDateForAttribute(summary.latestAt,timezone)}"`)}const lines=[];lines.push(`<summary ${attributes.join(" ")}>`);if(summary.kind==="condensed"){const parents=await summaryStore.getSummaryParents(summary.summaryId);if(parents.length>0){lines.push(" <parents>");for(const parent of parents){lines.push(` <summary_ref id="${parent.summaryId}" />`)}lines.push(" </parents>")}}lines.push(" <content>");lines.push(summary.content);lines.push(" </content>");lines.push("</summary>");return lines.join("\n")}function resolveFreshTailOrdinal(resolved,freshTailCount,freshTailMaxTokens){if(!Number.isFinite(freshTailCount)||freshTailCount<=0){return Infinity}const rawMessages=resolved.filter(item=>item.isMessage);if(rawMessages.length===0){return Infinity}const tokenCap=typeof freshTailMaxTokens==="number"&&Number.isFinite(freshTailMaxTokens)&&freshTailMaxTokens>=0?Math.floor(freshTailMaxTokens):void 0;let protectedCount=0;let protectedTokens=0;let tailStartOrdinal=Infinity;for(let idx=rawMessages.length-1;idx>=0;idx--){if(protectedCount>=freshTailCount){break}const item=rawMessages[idx];if(!item){continue}const wouldExceedBudget=protectedCount>0&&typeof tokenCap==="number"&&protectedTokens+item.tokens>tokenCap;if(wouldExceedBudget){break}tailStartOrdinal=item.ordinal;protectedCount++;protectedTokens+=item.tokens}return tailStartOrdinal}function tokenizeText(text){return text.toLowerCase().split(/[^a-z0-9]+/).filter(t=>t.length>1)}function scoreRelevance(itemText,prompt){const promptTerms=tokenizeText(prompt);if(promptTerms.length===0)return 0;const itemTerms=tokenizeText(itemText);if(itemTerms.length===0)return 0;const freq=new Map;for(const term of itemTerms){freq.set(term,(freq.get(term)??0)+1)}const seen=new Set;let score=0;for(const term of promptTerms){if(seen.has(term))continue;seen.add(term);const tf=freq.get(term)??0;if(tf>0){score+=tf/itemTerms.length}}return score}function hasSearchablePrompt(prompt){return typeof prompt==="string"&&tokenizeText(prompt).length>0}var ContextAssembler=class{constructor(conversationStore,summaryStore,timezone){this.conversationStore=conversationStore;this.summaryStore=summaryStore;this.timezone=timezone}conversationStore;summaryStore;timezone;async assemble(input){const{conversationId,tokenBudget}=input;const freshTailCount=input.freshTailCount??8;const contextItems=await this.summaryStore.getContextItems(conversationId);if(contextItems.length===0){return{messages:[],estimatedTokens:0,stats:{rawMessageCount:0,summaryCount:0,totalContextItems:0}}}const resolved=await this.resolveItems(contextItems);let rawMessageCount=0;let summaryCount=0;const summarySignals=[];for(const item of resolved){if(item.isMessage){rawMessageCount++}else{summaryCount++;if(item.summarySignal){summarySignals.push(item.summarySignal)}}}const systemPromptAddition=buildSystemPromptAddition(summarySignals);const freshTailOrdinal=resolveFreshTailOrdinal(resolved,freshTailCount,input.freshTailMaxTokens);const baseFreshTail=resolved.filter(item=>item.ordinal>=freshTailOrdinal);const initialEvictable=resolved.filter(item=>item.ordinal<freshTailOrdinal);const freshTailOrdinals=new Set(baseFreshTail.map(item=>item.ordinal));const tailToolCallIds=collectAssistantToolCallIds(baseFreshTail);const tailPairToolResults=initialEvictable.filter(item=>{const toolResultId=extractToolResultIdFromMessage(item.message);return toolResultId!==null&&tailToolCallIds.has(toolResultId)});const mergedFreshTail=mergeFreshTailWithMatchingToolResults(baseFreshTail,tailPairToolResults,input.freshTailMaxTokens);const evictable=initialEvictable.filter(item=>!mergedFreshTail.promotedOrdinals.has(item.ordinal));const freshTail=mergedFreshTail.items;let tailTokens=0;for(const item of freshTail){tailTokens+=item.tokens}const remainingBudget=Math.max(0,tokenBudget-tailTokens);const selected=[];let evictableTokens=0;const evictableTotalTokens=evictable.reduce((sum,it)=>sum+it.tokens,0);if(evictableTotalTokens<=remainingBudget){selected.push(...evictable);evictableTokens=evictableTotalTokens}else if(hasSearchablePrompt(input.prompt)){const scored=evictable.map((item,idx)=>({item,score:scoreRelevance(item.text,input.prompt),idx}));scored.sort((a,b)=>b.score-a.score||b.idx-a.idx);const kept=[];let accum=0;for(const{item}of scored){if(accum+item.tokens<=remainingBudget){kept.push(item);accum+=item.tokens}}kept.sort((a,b)=>a.ordinal-b.ordinal);selected.push(...kept);evictableTokens=accum}else{const kept=[];let accum=0;for(let i=evictable.length-1;i>=0;i--){const item=evictable[i];if(accum+item.tokens<=remainingBudget){kept.push(item);accum+=item.tokens}else{break}}kept.reverse();selected.push(...kept);evictableTokens=accum}selected.push(...freshTail);const estimatedTokens=evictableTokens+tailTokens;const rawMessages=filterNonFreshAssistantToolCalls(selected,freshTailOrdinals,normalizeFreshTailTokenCap(input.freshTailMaxTokens)===void 0);for(let i=0;i<rawMessages.length;i++){const msg=rawMessages[i];if(msg?.role==="assistant"&&typeof msg.content==="string"){rawMessages[i]={...msg,content:[{type:"text",text:msg.content}]}}}const cleaned=rawMessages.filter(m=>!(m?.role==="assistant"&&(Array.isArray(m.content)?m.content.length===0:!m.content)));return{messages:sanitizeToolUseResultPairing(cleaned),estimatedTokens,systemPromptAddition,stats:{rawMessageCount,summaryCount,totalContextItems:resolved.length}}}async resolveItems(contextItems){const resolved=[];for(const item of contextItems){const result=await this.resolveItem(item);if(result){resolved.push(result)}}return resolved}async resolveItem(item){if(item.itemType==="message"&&item.messageId!=null){return this.resolveMessageItem(item)}if(item.itemType==="summary"&&item.summaryId!=null){return this.resolveSummaryItem(item)}return null}async resolveMessageItem(item){const msg=await this.conversationStore.getMessageById(item.messageId);if(!msg){return null}const parts=await this.conversationStore.getMessageParts(msg.messageId);if(msg.role==="assistant"&&!msg.content.trim()&&parts.length===0){return null}const roleFromStore=toRuntimeRole(msg.role,parts);const isToolResult=roleFromStore==="toolResult";const toolCallId=isToolResult?pickToolCallId(parts):void 0;const toolName=isToolResult?pickToolName(parts)??"unknown":void 0;const toolIsError=isToolResult?pickToolIsError(parts):void 0;const role=isToolResult&&!toolCallId?"assistant":roleFromStore;const content=contentFromParts(parts,role,msg.content);const contentText=typeof content==="string"?content:JSON.stringify(content)??msg.content;const tokenCount=estimateTokens(contentText);return{ordinal:item.ordinal,message:role==="assistant"?{role,content,usage:{input:0,output:tokenCount,cacheRead:0,cacheWrite:0,totalTokens:tokenCount,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}}}:{role,content,...toolCallId?{toolCallId}:{},...toolName?{toolName}:{},...role==="toolResult"&&toolIsError!==void 0?{isError:toolIsError}:{}},tokens:tokenCount,isMessage:true,text:contentText}}async resolveSummaryItem(item){const summary=await this.summaryStore.getSummary(item.summaryId);if(!summary){return null}const content=await formatSummaryContent(summary,this.summaryStore,this.timezone);const tokens=estimateTokens(content);return{ordinal:item.ordinal,message:{role:"user",content},tokens,isMessage:false,text:summary.content,summarySignal:{kind:summary.kind,depth:summary.depth,descendantCount:summary.descendantCount}}}};import{createHash}from"node:crypto";var FILE_BLOCK_RE=/<file\b([^>]*)>([\s\S]*?)<\/file>/gi;var FILE_ID_RE=/\bfile_[a-f0-9]{16}\b/gi;var CODE_EXTENSIONS=new Set(["c","cc","cpp","cs","go","h","hpp","java","js","jsx","kt","m","php","py","rb","rs","scala","sh","sql","swift","ts","tsx"]);var STRUCTURED_EXTENSIONS=new Set(["csv","json","tsv","xml","yaml","yml"]);var MIME_EXTENSION_MAP={"application/json":"json","application/xml":"xml","application/yaml":"yaml","application/x-yaml":"yaml","application/x-ndjson":"json","application/csv":"csv","application/javascript":"js","application/typescript":"ts","application/x-python-code":"py","application/x-rust":"rs","application/x-sh":"sh","text/csv":"csv","text/markdown":"md","text/plain":"txt","text/tab-separated-values":"tsv","text/x-c":"c","text/x-c++":"cpp","text/x-go":"go","text/x-java":"java","text/x-python":"py","text/x-rust":"rs","text/x-script.python":"py","text/x-shellscript":"sh","text/x-typescript":"ts","text/xml":"xml"};var STRUCTURED_MIME_PREFIXES=["application/json","application/xml","application/yaml","application/x-yaml","application/x-ndjson","text/csv","text/tab-separated-values","text/xml"];var CODE_MIME_PREFIXES=["application/javascript","application/typescript","application/x-python-code","application/x-rust","text/javascript","text/x-c","text/x-c++","text/x-go","text/x-java","text/x-python","text/x-rust","text/x-script.python","text/x-shellscript","text/x-typescript"];var TEXT_SUMMARY_SLICE_CHARS=2400;var TEXT_HEADER_LIMIT=18;function parseFileAttributes(raw){const attrs={};const attrRe=/([A-Za-z_:][A-Za-z0-9_:\-.]*)\s*=\s*("([^"]*)"|'([^']*)'|([^\s"'>]+))/g;let match;while((match=attrRe.exec(raw))!==null){const key=match[1].trim().toLowerCase();const value=(match[3]??match[4]??match[5]??"").trim();if(key.length>0&&value.length>0){attrs[key]=value}}return attrs}function normalizeTextForLine(text,maxLen){const compact=text.replace(/\s+/g," ").trim();if(compact.length<=maxLen){return compact}return`${compact.slice(0,maxLen)}...`}function collectFileNameExtension(fileName){if(!fileName){return void 0}const base=fileName.trim().split(/[\\/]/).pop()??"";const idx=base.lastIndexOf(".");if(idx<=0||idx===base.length-1){return void 0}const ext=base.slice(idx+1).toLowerCase();if(!/^[a-z0-9]{1,10}$/.test(ext)){return void 0}return ext}function guessMimeExtension(mimeType){if(!mimeType){return void 0}const normalized=mimeType.trim().toLowerCase();return MIME_EXTENSION_MAP[normalized]}function isStructured(params){const mime=params.mimeType?.trim().toLowerCase();if(mime&&STRUCTURED_MIME_PREFIXES.some(candidate=>mime.startsWith(candidate))){return true}return params.extension?STRUCTURED_EXTENSIONS.has(params.extension):false}function isCode(params){const mime=params.mimeType?.trim().toLowerCase();if(mime&&CODE_MIME_PREFIXES.some(candidate=>mime.startsWith(candidate))){return true}return params.extension?CODE_EXTENSIONS.has(params.extension):false}function uniqueOrdered(values){const seen=new Set;const out=[];for(const value of values){if(!seen.has(value)){seen.add(value);out.push(value)}}return out}function exploreJson(content){const parsed=JSON.parse(content);const describe=(value,depth=0)=>{if(depth>=2){return"..."}if(Array.isArray(value)){const sample=value.slice(0,3).map(item=>describe(item,depth+1));return`array(len=${value.length}${sample.length>0?`, sample=[${sample.join(", ")}]`:""})`}if(!value||typeof value!=="object"){return typeof value}const keys=Object.keys(value);const preview=keys.slice(0,10).join(", ");return`object(keys=${keys.length}${preview?`: ${preview}`:""})`};const topLevel=Array.isArray(parsed)?"array":typeof parsed;return[`Structured summary (JSON):`,`Top-level type: ${topLevel}.`,`Shape: ${describe(parsed)}.`].join("\n")}function parseDelimitedLine(line,delimiter){return line.split(delimiter).map(item=>item.trim()).filter(item=>item.length>0)}function exploreDelimited(content,delimiter,kind){const lines=content.split(/\r?\n/).map(line=>line.trim()).filter(line=>line.length>0);if(lines.length===0){return`Structured summary (${kind}): no rows found.`}const headers=parseDelimitedLine(lines[0],delimiter);const rowCount=Math.max(0,lines.length-1);const firstData=lines[1]?normalizeTextForLine(lines[1],180):"(no data rows)";return[`Structured summary (${kind}):`,`Rows: ${rowCount.toLocaleString("en-US")}.`,`Columns (${headers.length}): ${headers.join(", ")||"(none detected)"}.`,`First row sample: ${firstData}.`].join("\n")}function exploreYaml(content){const topLevelKeys=uniqueOrdered(content.split(/\r?\n/).map(line=>{const match=line.match(/^([A-Za-z0-9_.-]+):\s*(?:#.*)?$/);return match?match[1]:""}).filter(key=>key.length>0));return["Structured summary (YAML):",`Top-level keys (${topLevelKeys.length}): ${topLevelKeys.slice(0,30).join(", ")||"(none detected)"}.`].join("\n")}function exploreXml(content){const rootMatch=content.match(/<([A-Za-z0-9_:-]+)(\s|>)/);const rootTag=rootMatch?.[1]??"unknown";const childTags=uniqueOrdered([...content.matchAll(/<([A-Za-z0-9_:-]+)(\s|>)/g)].map(match=>match[1]).filter(tag=>tag!==rootTag).slice(0,30));return["Structured summary (XML):",`Root element: ${rootTag}.`,`Child elements seen: ${childTags.join(", ")||"(none detected)"}.`].join("\n")}function exploreStructuredData(content,mimeType,fileName){const extension=collectFileNameExtension(fileName)??guessMimeExtension(mimeType);const normalizedMime=mimeType?.trim().toLowerCase()??"";if(extension==="json"||normalizedMime.startsWith("application/json")){try{return exploreJson(content)}catch{return"Structured summary (JSON): failed to parse as valid JSON."}}if(extension==="csv"||normalizedMime.startsWith("text/csv")){return exploreDelimited(content,",","CSV")}if(extension==="tsv"||normalizedMime.startsWith("text/tab-separated-values")){return exploreDelimited(content," ","TSV")}if(extension==="xml"||normalizedMime.startsWith("text/xml")||normalizedMime.startsWith("application/xml")){return exploreXml(content)}if(extension==="yaml"||extension==="yml"||normalizedMime.includes("yaml")){return exploreYaml(content)}return["Structured summary:",`Characters: ${content.length.toLocaleString("en-US")}.`,`Lines: ${content.split(/\r?\n/).length.toLocaleString("en-US")}.`].join("\n")}function exploreCode(content,fileName){const lines=content.split(/\r?\n/);const imports=uniqueOrdered(lines.filter(line=>/^\s*(import\s+|from\s+\S+\s+import\s+|const\s+\w+\s*=\s*require\()/.test(line)).map(line=>normalizeTextForLine(line,180)).slice(0,12));const signatures=uniqueOrdered(lines.map(line=>line.trim()).filter(line=>/^(export\s+)?(async\s+)?(function|class|interface|type|const\s+\w+\s*=\s*\(|def\s+\w+\(|struct\s+\w+)/.test(line)).map(line=>normalizeTextForLine(line,200)).slice(0,24));return[`Code exploration summary${fileName?` (${fileName})`:""}:`,`Lines: ${lines.length.toLocaleString("en-US")}.`,`Imports/dependencies (${imports.length}): ${imports.join(" | ")||"none detected"}.`,`Top-level definitions (${signatures.length}): ${signatures.join(" | ")||"none detected"}.`].join("\n")}function extractTextHeaders(content){const headers=uniqueOrdered(content.split(/\r?\n/).map(line=>line.trim()).filter(line=>line.length>1).filter(line=>/^#{1,6}\s+/.test(line)||/^[A-Z0-9][A-Z0-9\s:_-]{6,}$/.test(line)).map(line=>normalizeTextForLine(line,160)).slice(0,TEXT_HEADER_LIMIT));return headers}function buildTextSample(content){if(content.length<=TEXT_SUMMARY_SLICE_CHARS*2){return content}const middleStart=Math.max(0,Math.floor(content.length/2)-Math.floor(TEXT_SUMMARY_SLICE_CHARS/2));const middleEnd=middleStart+TEXT_SUMMARY_SLICE_CHARS;const head=content.slice(0,TEXT_SUMMARY_SLICE_CHARS);const mid=content.slice(middleStart,middleEnd);const tail=content.slice(-TEXT_SUMMARY_SLICE_CHARS);return["[Document Start]",head,"[Document Middle]",mid,"[Document End]",tail].join("\n\n")}function buildTextPrompt(params){const sample=buildTextSample(params.content);return[`Summarize this large file for retrieval-time context references.`,`File name: ${params.fileName??"unknown"}`,`Mime type: ${params.mimeType??"unknown"}`,`Length: ${params.content.length.toLocaleString("en-US")} chars`,`Line count: ${params.content.split(/\r?\n/).length.toLocaleString("en-US")}`,params.headers.length>0?`Detected section headers: ${params.headers.join(" | ")}`:"Detected section headers: none","Produce 200-300 words with:","- What the document is about","- Key sections and topics","- Important names, dates, and numbers","- Any action items or constraints","Do not quote long passages verbatim.","","Document sample:",sample].join("\n")}function exploreTextDeterministicFallback(content,fileName){const normalized=content.replace(/\s+/g," ").trim();const headers=extractTextHeaders(content);const lineCount=content.split(/\r?\n/).length;const wordCount=normalized.length>0?normalized.split(/\s+/).length:0;const first=normalizeTextForLine(content.slice(0,500),500);const last=normalizeTextForLine(content.slice(-500),500);return[`Text exploration summary${fileName?` (${fileName})`:""}:`,`Characters: ${content.length.toLocaleString("en-US")}.`,`Words: ${wordCount.toLocaleString("en-US")}.`,`Lines: ${lineCount.toLocaleString("en-US")}.`,`Detected section headers: ${headers.join(" | ")||"none detected"}.`,`Opening excerpt: ${first||"(empty)"}.`,`Closing excerpt: ${last||"(empty)"}.`].join("\n")}async function exploreText(params){const headers=extractTextHeaders(params.content);if(params.summarizeText){const prompt=buildTextPrompt({content:params.content,fileName:params.fileName,mimeType:params.mimeType,headers});try{const summary=await params.summarizeText(prompt);if(typeof summary==="string"&&summary.trim().length>0){return summary.trim()}}catch{}}return exploreTextDeterministicFallback(params.content,params.fileName)}function parseFileBlocks(content){const blocks=[];let match;FILE_BLOCK_RE.lastIndex=0;while((match=FILE_BLOCK_RE.exec(content))!==null){const fullMatch=match[0];const rawAttrs=match[1]??"";const text=match[2]??"";const start=match.index;const end=start+fullMatch.length;const attributes=parseFileAttributes(rawAttrs);blocks.push({fullMatch,start,end,attributes,fileName:attributes.name,mimeType:attributes.mime,text})}return blocks}function extensionFromNameOrMime(fileName,mimeType){const fromName=collectFileNameExtension(fileName);if(fromName){return fromName}const fromMime=guessMimeExtension(mimeType);if(fromMime){return fromMime}return"txt"}function extractFileIdsFromContent(content){const matches=content.match(FILE_ID_RE)??[];return uniqueOrdered(matches.map(id=>id.toLowerCase()))}function formatFileReference(input){const name=input.fileName?.trim()||"unknown";const mime=input.mimeType?.trim()||"unknown";const byteSize=Math.max(0,input.byteSize);return[`[LCM File: ${input.fileId} | ${name} | ${mime} | ${byteSize.toLocaleString("en-US")} bytes]`,"","Exploration Summary:",input.summary.trim()||"(no summary available)"].join("\n")}function formatToolOutputReference(input){const toolName=input.toolName?.trim()||"unknown";const byteSize=Math.max(0,input.byteSize);return[`[LCM Tool Output: ${input.fileId} | tool=${toolName} | ${byteSize.toLocaleString("en-US")} bytes]`,"","Exploration Summary:",input.summary.trim()||"(no summary available)","","Use lcm_describe with the file id to inspect the full output."].join("\n")}async function generateExplorationSummary(input){const extension=extensionFromNameOrMime(input.fileName,input.mimeType);if(isStructured({mimeType:input.mimeType,extension})){return exploreStructuredData(input.content,input.mimeType,input.fileName)}if(isCode({mimeType:input.mimeType,extension})){return exploreCode(input.content,input.fileName)}return exploreText(input)}var NOOP_LCM_LOGGER={info:()=>{},warn:()=>{},error:()=>{},debug:()=>{}};function describeLogError(error){return error instanceof Error?error.message:String(error)}function createLcmLogger(api){const runtimeLogger=api.runtime.logging?.getChildLogger?.({plugin:"lossless-claw"});if(runtimeLogger){return{info:message=>runtimeLogger.info(message),warn:message=>runtimeLogger.warn(message),error:message=>runtimeLogger.error(message),debug:message=>runtimeLogger.debug?.(message)}}return{info:message=>api.logger.info(message),warn:message=>api.logger.warn(message),error:message=>api.logger.error(message),debug:message=>api.logger.debug?.(message)}}function buildSummarizerBreakerKey(params){const authProfileId=params.candidate.useLegacyAuthProfile?params.legacyAuthProfileId??"-":"-";return`provider:${params.candidate.provider};model:${params.candidate.model};authProfile:${authProfileId}`}var DEFAULT_LEAF_TARGET_TOKENS=2400;var DEFAULT_CONDENSED_TARGET_TOKENS=2e3;var LCM_SUMMARIZER_SYSTEM_PROMPT="You are a context-compaction summarization engine. Follow user instructions exactly and return plain text summary content only.";var DIAGNOSTIC_MAX_DEPTH=4;var DIAGNOSTIC_MAX_ARRAY_ITEMS=8;var DIAGNOSTIC_MAX_OBJECT_KEYS=16;var DIAGNOSTIC_MAX_CHARS=1200;var DIAGNOSTIC_SENSITIVE_KEY_PATTERN=/(api[-_]?key|authorization|token|secret|password|cookie|set-cookie|private[-_]?key|bearer)/i;var AUTH_ERROR_TEXT_PATTERN=/\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_KEYS=["status","statusCode","status_code"];var AUTH_ERROR_NESTED_KEYS=["error","response","cause","details","data","body"];var AUTH_ERROR_TOP_LEVEL_KEYS=["error","errorMessage","status","statusCode","status_code","code","details","cause","data","body"];var LcmProviderAuthError=class extends Error{provider;model;failure;constructor(params){super(buildProviderAuthWarning(params));this.name="LcmProviderAuthError";this.provider=params.provider;this.model=params.model;this.failure=params.failure}};var DEFAULT_SUMMARIZER_TIMEOUT_MS=6e4;var SummarizerTimeoutError=class extends Error{constructor(ms,label){super(`[lcm] summarizer timeout after ${ms}ms (${label})`);this.name="SummarizerTimeoutError"}};function withTimeout(promise,ms,label){return new Promise((resolve2,reject)=>{const timer=setTimeout(()=>reject(new SummarizerTimeoutError(ms,label)),ms);promise.then(val=>{clearTimeout(timer);resolve2(val)},err=>{clearTimeout(timer);reject(err)})})}function normalizeProviderId(provider){return provider.trim().toLowerCase()}function resolveProviderApiFromLegacyConfig(config,provider){if(!config||typeof config!=="object"){return void 0}const providers=config.models?.providers;if(!providers||typeof providers!=="object"){return void 0}const direct=providers[provider];if(direct&&typeof direct==="object"){const api=direct.api;if(typeof api==="string"&&api.trim()){return api.trim()}}const normalizedProvider=normalizeProviderId(provider);for(const[entryProvider,value]of Object.entries(providers)){if(normalizeProviderId(entryProvider)!==normalizedProvider){continue}if(!value||typeof value!=="object"){continue}const api=value.api;if(typeof api==="string"&&api.trim()){return api.trim()}}return void 0}function isRecord(value){return!!value&&typeof value==="object"&&!Array.isArray(value)}function normalizeTextFragments(chunks){const normalized=[];const seen=new Set;for(const chunk of chunks){const trimmed=chunk.trim();if(!trimmed||seen.has(trimmed)){continue}seen.add(trimmed);normalized.push(trimmed)}return normalized.join("\n").trim()}function collectBlockTypes(value,out){if(Array.isArray(value)){for(const entry of value){collectBlockTypes(entry,out)}return}if(!isRecord(value)){return}if(typeof value.type==="string"&&value.type.trim()){out.add(value.type.trim())}for(const nested of Object.values(value)){collectBlockTypes(nested,out)}}function isReasoningLikeType(type){if(typeof type!=="string"){return false}const normalized=type.trim().toLowerCase();return normalized.includes("reasoning")||normalized.includes("thinking")}function collectTextLikeFields(value,out){if(Array.isArray(value)){for(const entry of value){collectTextLikeFields(entry,out)}return}if(!isRecord(value)){return}if(isReasoningLikeType(value.type)){return}for(const key of["text","output_text"]){appendTextValue(value[key],out)}for(const key of["content","summary","output","message","response"]){if(key in value){collectTextLikeFields(value[key],out)}}}function appendTextValue(value,out){if(typeof value==="string"){out.push(value);return}if(Array.isArray(value)){for(const entry of value){appendTextValue(entry,out)}return}if(!isRecord(value)){return}if(typeof value.value==="string"){out.push(value.value)}if(typeof value.text==="string"){out.push(value.text)}}function normalizeCompletionSummary(content){const chunks=[];const blockTypeSet=new Set;collectTextLikeFields(content,chunks);collectBlockTypes(content,blockTypeSet);const blockTypes=[...blockTypeSet].sort((a,b)=>a.localeCompare(b));return{summary:normalizeTextFragments(chunks),blockTypes}}function formatBlockTypes(blockTypes){if(blockTypes.length===0){return"(none)"}return blockTypes.join(",")}function truncateDiagnosticText(value,maxChars=DIAGNOSTIC_MAX_CHARS){if(value.length<=maxChars){return value}return`${value.slice(0,maxChars)}...[truncated:${value.length-maxChars} chars]`}function sanitizeForDiagnostics(value,depth=0){if(depth>=DIAGNOSTIC_MAX_DEPTH){return"[max-depth]"}if(typeof value==="string"){return truncateDiagnosticText(value)}if(value===null||typeof value==="number"||typeof value==="boolean"||typeof value==="bigint"){return value}if(value===void 0){return"[undefined]"}if(typeof value==="function"){return"[function]"}if(typeof value==="symbol"){return"[symbol]"}if(Array.isArray(value)){const head=value.slice(0,DIAGNOSTIC_MAX_ARRAY_ITEMS).map(entry=>sanitizeForDiagnostics(entry,depth+1));if(value.length>DIAGNOSTIC_MAX_ARRAY_ITEMS){head.push(`[+${value.length-DIAGNOSTIC_MAX_ARRAY_ITEMS} more items]`)}return head}if(!isRecord(value)){return String(value)}const out={};const entries=Object.entries(value);for(const[key,entry]of entries.slice(0,DIAGNOSTIC_MAX_OBJECT_KEYS)){out[key]=DIAGNOSTIC_SENSITIVE_KEY_PATTERN.test(key)?"[redacted]":sanitizeForDiagnostics(entry,depth+1)}if(entries.length>DIAGNOSTIC_MAX_OBJECT_KEYS){out.__truncated_keys__=entries.length-DIAGNOSTIC_MAX_OBJECT_KEYS}return out}function formatDiagnosticPayload(value){try{const json=JSON.stringify(sanitizeForDiagnostics(value));if(!json){return'""'}return truncateDiagnosticText(json)}catch{return'"[unserializable]"'}}function collectAuthFailureText(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,DIAGNOSTIC_MAX_ARRAY_ITEMS)){collectAuthFailureText(entry,out,depth+1)}return}if(!isRecord(value)){return}for(const entry of Object.values(value).slice(0,DIAGNOSTIC_MAX_OBJECT_KEYS)){collectAuthFailureText(entry,out,depth+1)}}function extractAuthFailureStatusCode(value,depth=0){if(depth>=4||!isRecord(value)){return void 0}for(const key of AUTH_ERROR_STATUS_KEYS){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_KEYS){const nested=value[key];const statusCode=extractAuthFailureStatusCode(nested,depth+1);if(statusCode!==void 0){return statusCode}}return void 0}function hasTopLevelAuthInspectionKeys(value){return AUTH_ERROR_TOP_LEVEL_KEYS.some(key=>key in value)}function looksLikeThrownError(value){return typeof value.name==="string"&&/\berror\b/i.test(value.name)||"stack"in value||typeof value.message==="string"&&!("content"in value)&&!("response"in value)&&!("output"in value)}function pickAuthInspectionValue(value){if(!isRecord(value)){return value}if(isRecord(value.error)&&value.error.kind==="provider_auth"){return value.error}const subset={};const hasTopLevelAuthKeys=hasTopLevelAuthInspectionKeys(value);const errorLike=value instanceof Error||looksLikeThrownError(value);for(const key of AUTH_ERROR_TOP_LEVEL_KEYS){if(key in value){subset[key]=value[key]}}if((hasTopLevelAuthKeys||errorLike)&&"message"in value){subset.message=value.message}if("response"in value){const response=value.response;if(hasTopLevelAuthKeys||isRecord(response)&&hasTopLevelAuthInspectionKeys(response)||isRecord(response)&&looksLikeThrownError(response)){subset.response=response}}return Object.keys(subset).length>0?subset:{}}function extractProviderAuthFailure(value,opts){const inspectValue=pickAuthInspectionValue(value);const statusCode=extractAuthFailureStatusCode(inspectValue);const textParts=[];collectAuthFailureText(inspectValue,textParts);const normalizedMessage=textParts.join(" ").replace(/\s+/g," ").trim();const missingModelRequestScope=/\bmodel\.request\b/i.test(normalizedMessage);const hasScopeSignal=missingModelRequestScope||/\b(missing|insufficient)\s+scope\b/i.test(normalizedMessage);const hasExplicitErrorKind=isRecord(value)&&isRecord(value.error)&&value.error.kind==="provider_auth";if(opts?.requireStructuralSignal){if(statusCode!==401&&!hasExplicitErrorKind){return void 0}}else if(statusCode!==401&&!hasScopeSignal&&!AUTH_ERROR_TEXT_PATTERN.test(normalizedMessage)){return void 0}return{...statusCode!==void 0?{statusCode}:{},...normalizedMessage?{message:truncateDiagnosticText(normalizedMessage,240)}:{},missingModelRequestScope}}function buildProviderAuthWarning(params){const detailParts=[];if(params.failure.statusCode===401){detailParts.push("401")}if(params.failure.missingModelRequestScope){detailParts.push("missing model.request scope")}const detail=detailParts.length>0?`provider auth error (${detailParts.join(" / ")})`:"provider auth error";const messageSuffix=params.failure.message&&!params.failure.missingModelRequestScope?` Detail: ${params.failure.message}`:"";return`[lcm] compaction failed: ${detail}. Check that the configured summaryProvider has valid API credentials. Current: ${params.provider}/${params.model}${messageSuffix}`}function extractResponseDiagnostics(result){if(!isRecord(result)){return""}const parts=[];const topLevelKeys=Object.keys(result).slice(0,24);if(topLevelKeys.length>0){parts.push(`keys=${topLevelKeys.join(",")}`)}if("content"in result){const contentVal=result.content;if(Array.isArray(contentVal)){parts.push(`content_kind=array`);parts.push(`content_len=${contentVal.length}`)}else if(contentVal===null){parts.push(`content_kind=null`)}else{parts.push(`content_kind=${typeof contentVal}`)}parts.push(`content_preview=${formatDiagnosticPayload(contentVal)}`)}else{parts.push("content_kind=missing")}const envelopePayload={};for(const key of["summary","output","message","response"]){if(key in result){envelopePayload[key]=result[key]}}if(Object.keys(envelopePayload).length>0){parts.push(`payload_preview=${formatDiagnosticPayload(envelopePayload)}`)}for(const key of["id","request_id","x-request-id"]){const val=result[key];if(typeof val==="string"&&val.trim()){parts.push(`${key}=${val.trim()}`)}}if(typeof result.model==="string"&&result.model.trim()){parts.push(`resp_model=${result.model.trim()}`)}if(typeof result.provider==="string"&&result.provider.trim()){parts.push(`resp_provider=${result.provider.trim()}`)}if(typeof result.status==="string"&&result.status.trim()){parts.push(`status=${result.status.trim()}`)}if(isRecord(result.incomplete_details)&&typeof result.incomplete_details.reason==="string"){const reason=result.incomplete_details.reason.trim();if(reason){parts.push(`incomplete_reason=${reason}`)}}for(const key of["request_provider","request_model","request_api","request_reasoning","request_has_system","request_temperature","request_temperature_sent"]){const val=result[key];if(typeof val==="string"&&val.trim()){parts.push(`${key}=${val.trim()}`)}}if(isRecord(result.usage)){const u=result.usage;const tokens=[];for(const k of["prompt_tokens","completion_tokens","total_tokens","input","output","cacheRead","cacheWrite"]){if(typeof u[k]==="number"){tokens.push(`${k}=${u[k]}`)}}if(tokens.length>0){parts.push(tokens.join(","))}}const finishReason=typeof result.finish_reason==="string"?result.finish_reason:typeof result.stopReason==="string"?result.stopReason:typeof result.stop_reason==="string"?result.stop_reason:void 0;if(finishReason){parts.push(`finish=${finishReason}`)}const errorMessage=result.errorMessage;if(typeof errorMessage==="string"&&errorMessage.trim()){parts.push(`error_message=${truncateDiagnosticText(errorMessage.trim(),400)}`)}const errorPayload=result.error;if(errorPayload!==void 0){parts.push(`error_preview=${formatDiagnosticPayload(errorPayload)}`)}return parts.join("; ")}function collectIncompleteResponseSignals(value,out,label="response",depth=0){if(depth>=DIAGNOSTIC_MAX_DEPTH){return}if(Array.isArray(value)){value.slice(0,DIAGNOSTIC_MAX_ARRAY_ITEMS).forEach((entry,index)=>{collectIncompleteResponseSignals(entry,out,`${label}[${index}]`,depth+1)});return}if(!isRecord(value)){return}if(typeof value.status==="string"&&value.status.trim().toLowerCase()==="incomplete"){out.add(`${label}.status=incomplete`)}if(isRecord(value.incomplete_details)&&typeof value.incomplete_details.reason==="string"){const reason=value.incomplete_details.reason.trim();if(reason){out.add(`${label}.reason=${reason}`)}}for(const key of["content","output","message","response","items"]){if(key in value){collectIncompleteResponseSignals(value[key],out,`${label}.${key}`,depth+1)}}}function extractIncompleteResponseSignals(value){const signals=new Set;collectIncompleteResponseSignals(value,signals);return[...signals].sort((a,b)=>a.localeCompare(b))}function resolveTargetTokens(params){if(params.isCondensed){return Math.max(512,params.condensedTargetTokens)}const{inputTokens,mode}=params;const leafTargetTokens=Math.max(192,params.leafTargetTokens);if(mode==="aggressive"){const aggressiveCap=Math.max(96,Math.min(leafTargetTokens,Math.floor(leafTargetTokens*.55)));return Math.max(96,Math.min(aggressiveCap,Math.floor(inputTokens*.2)))}return Math.max(192,Math.min(leafTargetTokens,Math.floor(inputTokens*.35)))}function buildLeafSummaryPrompt(params){const{text,mode,targetTokens,previousSummary,customInstructions}=params;const previousContext=previousSummary?.trim()||"(none)";const policy=mode==="aggressive"?["Aggressive summary policy:","- Keep only durable facts and current task state.","- Remove examples, repetition, and low-value narrative details.","- Preserve explicit TODOs, blockers, decisions, and constraints."].join("\n"):["Normal summary policy:","- Preserve key decisions, rationale, constraints, and active tasks.","- Keep essential technical details needed to continue work safely.","- Remove obvious repetition and conversational filler."].join("\n");const instructionBlock=customInstructions?.trim()?`Operator instructions:
|
|
2
2
|
${customInstructions.trim()}`:"Operator instructions: (none)";return["You summarize a SEGMENT of an OpenClaw conversation for future model turns.","Treat this as incremental memory compaction input, not a full-conversation summary.",policy,instructionBlock,["Output requirements:","- Plain text only.","- No preamble, headings, or markdown formatting.","- Keep it concise while preserving required details.","- Track file operations (created, modified, deleted, renamed) with file paths and current status.",'- If no file operations appear, include exactly: "Files: none".','- End with exactly: "Expand for details about: <comma-separated list of what was dropped or compressed>".',`- Target length: about ${targetTokens} tokens or less.`].join("\n"),`<previous_context>
|
|
3
3
|
${previousContext}
|
|
4
4
|
</previous_context>`,`<conversation_segment>
|
|
@@ -20,7 +20,12 @@ ${text}
|
|
|
20
20
|
[Capped to ~${maxTokens}]`,"\n[Capped]",""];for(const suffix of suffixes){const contentBudget=Math.max(0,maxTokens-estimateTokens(suffix));const capped=`${truncateTextToEstimatedTokens(content,contentBudget)}${suffix}`;if(estimateTokens(capped)<=maxTokens){return capped}}return truncateTextToEstimatedTokens(content,maxTokens)}function formatTimestamp(value,timezone="UTC"){try{const fmt=new Intl.DateTimeFormat("en-CA",{timeZone:timezone,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:false});const parts=Object.fromEntries(fmt.formatToParts(value).map(p=>[p.type,p.value]));const tzAbbr=timezone==="UTC"?"UTC":shortTzAbbr(value,timezone);return`${parts.year}-${parts.month}-${parts.day} ${parts.hour}:${parts.minute} ${tzAbbr}`}catch{const year=value.getUTCFullYear();const month=String(value.getUTCMonth()+1).padStart(2,"0");const day=String(value.getUTCDate()).padStart(2,"0");const hours=String(value.getUTCHours()).padStart(2,"0");const minutes=String(value.getUTCMinutes()).padStart(2,"0");return`${year}-${month}-${day} ${hours}:${minutes} UTC`}}function shortTzAbbr(value,timezone){try{const abbr=new Intl.DateTimeFormat("en-US",{timeZone:timezone,timeZoneName:"short"}).formatToParts(value).find(p=>p.type==="timeZoneName")?.value;return abbr??timezone}catch{return timezone}}function generateSummaryId(content){return"sum_"+createHash("sha256").update(content+Date.now().toString()).digest("hex").slice(0,16)}var FALLBACK_MAX_TOKENS=512;var DEFAULT_LEAF_CHUNK_TOKENS=2e4;var MEDIA_PATH_RE=/^MEDIA:\/.+$/;var EMBEDDED_DATA_URL_RE=/data:[^;\s"'`]+;base64,[A-Za-z0-9+/=\s]+/gi;var MEDIA_ATTACHMENT_PART_TYPES=new Set(["file","snapshot"]);var MEDIA_ATTACHMENT_RAW_TYPES=new Set(["file","image","snapshot"]);var STRUCTURED_MEDIA_TEXT_KEYS=["text","caption","alt","title","summary"];var STRUCTURED_MEDIA_NESTED_KEYS=["content","parts","items","message","messages"];var CONDENSED_MIN_INPUT_RATIO=.1;function dedupeOrderedIds(ids){const seen=new Set;const ordered=[];for(const id of ids){if(!seen.has(id)){seen.add(id);ordered.push(id)}}return ordered}function parseMessagePartMetadata(part){if(typeof part.metadata!=="string"||!part.metadata.trim()){return{}}try{const parsed=JSON.parse(part.metadata);return parsed&&typeof parsed==="object"&&!Array.isArray(parsed)?parsed:{}}catch{return{}}}function looksLikeBinaryPayload(value){const trimmed=value.trim();if(!trimmed){return false}if(/^data:[^;\s"'`]+;base64,/i.test(trimmed)){return true}const compact=trimmed.replace(/\s+/g,"");if(compact.length<256||compact.length%4!==0){return false}if(!/^[A-Za-z0-9+/=]+$/.test(compact)){return false}return!/[ .,:;!?()[\]{}]/.test(trimmed)}function stripEmbeddedMediaPayloads(content){const withoutDataUrls=content.replace(EMBEDDED_DATA_URL_RE,"[embedded media omitted]");const sanitizedLines=withoutDataUrls.split(/\r?\n/).map(line=>line.trimEnd()).filter(line=>{const trimmed=line.trim();if(!trimmed){return false}if(MEDIA_PATH_RE.test(trimmed)){return false}if(looksLikeBinaryPayload(trimmed)){return false}return true});return sanitizedLines.join("\n").trim()}function extractSanitizedStructuredText(value,depth=0){if(depth>=4||value==null){return[]}if(typeof value==="string"){const sanitized=stripEmbeddedMediaPayloads(value);return sanitized?[sanitized]:[]}if(Array.isArray(value)){return value.flatMap(entry=>extractSanitizedStructuredText(entry,depth+1))}if(typeof value!=="object"){return[]}const record=value;const rawType=typeof record.type==="string"?record.type.trim().toLowerCase():"";const textFragments=[];for(const key of STRUCTURED_MEDIA_TEXT_KEYS){const candidate=record[key];if(typeof candidate!=="string"){continue}const sanitized=stripEmbeddedMediaPayloads(candidate);if(sanitized){textFragments.push(sanitized)}}if(MEDIA_ATTACHMENT_RAW_TYPES.has(rawType)){return textFragments}for(const key of STRUCTURED_MEDIA_NESTED_KEYS){textFragments.push(...extractSanitizedStructuredText(record[key],depth+1))}return textFragments}function extractMeaningfulMessageText(content){const trimmed=content.trim();if(!trimmed){return""}if(trimmed.startsWith("[")&&trimmed.endsWith("]")||trimmed.startsWith("{")&&trimmed.endsWith("}")){try{const parsed=JSON.parse(trimmed);const extracted=extractSanitizedStructuredText(parsed).map(fragment=>fragment.trim()).filter(Boolean);return extracted.join("\n").trim()}catch{}}return stripEmbeddedMediaPayloads(content)}function isMediaAttachmentPart(part){if(MEDIA_ATTACHMENT_PART_TYPES.has(part.partType)){return true}const metadata=parseMessagePartMetadata(part);const rawType=typeof metadata.rawType==="string"?metadata.rawType.trim().toLowerCase():metadata.raw&&typeof metadata.raw==="object"&&!Array.isArray(metadata.raw)&&typeof metadata.raw.type==="string"?metadata.raw.type.trim().toLowerCase():"";return MEDIA_ATTACHMENT_RAW_TYPES.has(rawType)}var CompactionEngine=class{constructor(conversationStore,summaryStore,config,log=NOOP_LCM_LOGGER){this.conversationStore=conversationStore;this.summaryStore=summaryStore;this.config=config;this.log=log}conversationStore;summaryStore;config;log;_contextItemsCache=null;_contextItemsCacheRefCount=0;async getContextItemsCached(conversationId){if(this._contextItemsCache){if(this._contextItemsCache.has(conversationId)){return this._contextItemsCache.get(conversationId)}const items=await this.summaryStore.getContextItems(conversationId);this._contextItemsCache.set(conversationId,items);return items}return this.summaryStore.getContextItems(conversationId)}invalidateContextCache(conversationId){this._contextItemsCache?.delete(conversationId)}async withContextCache(fn){if(!this._contextItemsCache)this._contextItemsCache=new Map;this._contextItemsCacheRefCount++;try{return await fn()}finally{this._contextItemsCacheRefCount--;if(this._contextItemsCacheRefCount<=0){this._contextItemsCache=null;this._contextItemsCacheRefCount=0}}}async evaluate(conversationId,tokenBudget,observedTokenCount){const storedTokens=await this.summaryStore.getContextTokenCount(conversationId);const liveTokens=typeof observedTokenCount==="number"&&Number.isFinite(observedTokenCount)&&observedTokenCount>0?Math.floor(observedTokenCount):0;const currentTokens=Math.max(storedTokens,liveTokens);const threshold=Math.floor(this.config.contextThreshold*tokenBudget);if(currentTokens>threshold){return{shouldCompact:true,reason:"threshold",currentTokens,threshold}}return{shouldCompact:false,reason:"none",currentTokens,threshold}}async evaluateLeafTrigger(conversationId,leafChunkTokensOverride){const rawTokensOutsideTail=await this.countRawTokensOutsideFreshTail(conversationId);const threshold=this.resolveLeafChunkTokens(leafChunkTokensOverride);return{shouldCompact:rawTokensOutsideTail>=threshold,rawTokensOutsideTail,threshold}}async compact(input){return this.withContextCache(()=>this.compactFullSweep(input))}async compactLeaf(input){return this.withContextCache(()=>this._compactLeafImpl(input))}async _compactLeafImpl(input){const{conversationId,tokenBudget,summarize,force}=input;const tokensBefore=await this.summaryStore.getContextTokenCount(conversationId);const threshold=Math.floor(this.config.contextThreshold*tokenBudget);const leafTrigger=await this.evaluateLeafTrigger(conversationId,input.leafChunkTokens);if(!force&&tokensBefore<=threshold&&!leafTrigger.shouldCompact){return{actionTaken:false,tokensBefore,tokensAfter:tokensBefore,condensed:false}}const leafChunk=await this.selectOldestLeafChunk(conversationId,input.leafChunkTokens);if(leafChunk.items.length===0){return{actionTaken:false,tokensBefore,tokensAfter:tokensBefore,condensed:false}}const previousSummaryContent=input.previousSummaryContent??await this.resolvePriorLeafSummaryContext(conversationId,leafChunk.items);const leafResult=await this.leafPass(conversationId,leafChunk.items,summarize,previousSummaryContent,input.summaryModel);if(!leafResult){return{actionTaken:false,tokensBefore,tokensAfter:tokensBefore,condensed:false,authFailure:true}}const tokensAfterLeaf=tokensBefore-leafResult.removedTokens+leafResult.addedTokens;await this.persistCompactionEvents({conversationId,tokensBefore,tokensAfterLeaf,tokensAfterFinal:tokensAfterLeaf,leafResult:{summaryId:leafResult.summaryId,level:leafResult.level},condenseResult:null});let tokensAfter=tokensAfterLeaf;let condensed=false;let createdSummaryId=leafResult.summaryId;let level=leafResult.level;const incrementalMaxDepth=this.resolveIncrementalMaxDepth();const condensedMinChunkTokens=this.resolveCondensedMinChunkTokens();let runningTokens=tokensAfterLeaf;if(incrementalMaxDepth>0&&input.allowCondensedPasses!==false){for(let targetDepth=0;targetDepth<incrementalMaxDepth;targetDepth++){const fanout=this.resolveFanoutForDepth(targetDepth,false);const chunk=await this.selectOldestChunkAtDepth(conversationId,targetDepth);if(chunk.items.length<fanout||chunk.summaryTokens<condensedMinChunkTokens){break}const passTokensBefore=runningTokens;const condenseResult=await this.condensedPass(conversationId,chunk.items,targetDepth,summarize,input.summaryModel);if(!condenseResult){break}const passTokensAfter=passTokensBefore-condenseResult.removedTokens+condenseResult.addedTokens;await this.persistCompactionEvents({conversationId,tokensBefore:passTokensBefore,tokensAfterLeaf:passTokensBefore,tokensAfterFinal:passTokensAfter,leafResult:null,condenseResult});tokensAfter=passTokensAfter;runningTokens=passTokensAfter;condensed=true;createdSummaryId=condenseResult.summaryId;level=condenseResult.level;if(passTokensAfter>=passTokensBefore){break}}}return{actionTaken:true,tokensBefore,tokensAfter,createdSummaryId,condensed,level}}async compactFullSweep(input){const{conversationId,tokenBudget,summarize,force,hardTrigger}=input;const tokensBefore=await this.summaryStore.getContextTokenCount(conversationId);const threshold=Math.floor(this.config.contextThreshold*tokenBudget);const leafTrigger=await this.evaluateLeafTrigger(conversationId);if(!force&&tokensBefore<=threshold&&!leafTrigger.shouldCompact){return{actionTaken:false,tokensBefore,tokensAfter:tokensBefore,condensed:false}}const contextItems=await this.getContextItemsCached(conversationId);if(contextItems.length===0){return{actionTaken:false,tokensBefore,tokensAfter:tokensBefore,condensed:false}}let actionTaken=false;let condensed=false;let createdSummaryId;let level;let previousSummaryContent;let previousTokens=tokensBefore;let hadAuthFailure=false;let runningTokens=tokensBefore;while(true){const leafChunk=await this.selectOldestLeafChunk(conversationId);if(leafChunk.items.length===0){break}const passTokensBefore=runningTokens;const leafResult=await this.leafPass(conversationId,leafChunk.items,summarize,previousSummaryContent,input.summaryModel);if(!leafResult){hadAuthFailure=true;break}const passTokensAfter=passTokensBefore-leafResult.removedTokens+leafResult.addedTokens;await this.persistCompactionEvents({conversationId,tokensBefore:passTokensBefore,tokensAfterLeaf:passTokensAfter,tokensAfterFinal:passTokensAfter,leafResult:{summaryId:leafResult.summaryId,level:leafResult.level},condenseResult:null});actionTaken=true;createdSummaryId=leafResult.summaryId;level=leafResult.level;previousSummaryContent=leafResult.content;runningTokens=passTokensAfter;if(!force&&passTokensAfter<=threshold){previousTokens=passTokensAfter;break}if(passTokensAfter>=passTokensBefore||passTokensAfter>=previousTokens){break}previousTokens=passTokensAfter}while(force||previousTokens>threshold){const candidate=await this.selectShallowestCondensationCandidate({conversationId,hardTrigger:hardTrigger===true});if(!candidate){break}const passTokensBefore=runningTokens;const condenseResult=await this.condensedPass(conversationId,candidate.chunk.items,candidate.targetDepth,summarize,input.summaryModel);if(!condenseResult){hadAuthFailure=true;break}const passTokensAfter=passTokensBefore-condenseResult.removedTokens+condenseResult.addedTokens;await this.persistCompactionEvents({conversationId,tokensBefore:passTokensBefore,tokensAfterLeaf:passTokensBefore,tokensAfterFinal:passTokensAfter,leafResult:null,condenseResult});actionTaken=true;condensed=true;createdSummaryId=condenseResult.summaryId;level=condenseResult.level;runningTokens=passTokensAfter;if(!force&&passTokensAfter<=threshold){previousTokens=passTokensAfter;break}if(passTokensAfter>=passTokensBefore||passTokensAfter>=previousTokens){break}previousTokens=passTokensAfter}const tokensAfter=runningTokens;return{actionTaken,tokensBefore,tokensAfter,createdSummaryId,condensed,level,...hadAuthFailure?{authFailure:true}:{}}}async compactUntilUnder(input){return this.withContextCache(()=>this._compactUntilUnderImpl(input))}async _compactUntilUnderImpl(input){const{conversationId,tokenBudget,summarize}=input;const targetTokens=typeof input.targetTokens==="number"&&Number.isFinite(input.targetTokens)&&input.targetTokens>0?Math.floor(input.targetTokens):tokenBudget;const storedTokens=await this.summaryStore.getContextTokenCount(conversationId);const liveTokens=typeof input.currentTokens==="number"&&Number.isFinite(input.currentTokens)&&input.currentTokens>0?Math.floor(input.currentTokens):0;let lastTokens=Math.max(storedTokens,liveTokens);if(lastTokens<targetTokens){return{success:true,rounds:0,finalTokens:lastTokens}}for(let round=1;round<=this.config.maxRounds;round++){const result=await this.compact({conversationId,tokenBudget,summarize,force:true,summaryModel:input.summaryModel});if(result.authFailure){return{success:false,rounds:round,finalTokens:result.tokensAfter,authFailure:true}}if(result.tokensAfter<=targetTokens){return{success:true,rounds:round,finalTokens:result.tokensAfter}}if(!result.actionTaken||result.tokensAfter>=lastTokens){return{success:false,rounds:round,finalTokens:result.tokensAfter}}lastTokens=result.tokensAfter}const finalTokens=lastTokens;return{success:finalTokens<=targetTokens,rounds:this.config.maxRounds,finalTokens}}resolveLeafChunkTokens(leafChunkTokensOverride){if(typeof leafChunkTokensOverride==="number"&&Number.isFinite(leafChunkTokensOverride)&&leafChunkTokensOverride>0){return Math.floor(leafChunkTokensOverride)}if(typeof this.config.leafChunkTokens==="number"&&Number.isFinite(this.config.leafChunkTokens)&&this.config.leafChunkTokens>0){return Math.floor(this.config.leafChunkTokens)}return DEFAULT_LEAF_CHUNK_TOKENS}resolveFreshTailCount(){if(typeof this.config.freshTailCount==="number"&&Number.isFinite(this.config.freshTailCount)&&this.config.freshTailCount>0){return Math.floor(this.config.freshTailCount)}return 0}resolveFreshTailMaxTokens(){if(typeof this.config.freshTailMaxTokens==="number"&&Number.isFinite(this.config.freshTailMaxTokens)&&this.config.freshTailMaxTokens>=0){return Math.floor(this.config.freshTailMaxTokens)}return void 0}async resolveFreshTailOrdinal(contextItems){const freshTailCount=this.resolveFreshTailCount();if(freshTailCount<=0){return Infinity}const freshTailMaxTokens=this.resolveFreshTailMaxTokens();const rawMessageItems=contextItems.filter(item=>item.itemType==="message"&&item.messageId!=null);if(rawMessageItems.length===0){return Infinity}let protectedCount=0;let protectedTokens=0;let tailStartOrdinal=Infinity;for(let idx=rawMessageItems.length-1;idx>=0;idx--){if(protectedCount>=freshTailCount){break}const item=rawMessageItems[idx];if(!item||item.messageId==null){continue}const messageTokens=await this.getMessageTokenCount(item.messageId);const wouldExceedBudget=protectedCount>0&&typeof freshTailMaxTokens==="number"&&protectedTokens+messageTokens>freshTailMaxTokens;if(wouldExceedBudget){break}tailStartOrdinal=item.ordinal;protectedCount++;protectedTokens+=messageTokens}return tailStartOrdinal}async getMessageTokenCount(messageId){const message=await this.conversationStore.getMessageById(messageId);if(!message){return 0}if(typeof message.tokenCount==="number"&&Number.isFinite(message.tokenCount)&&message.tokenCount>0){return message.tokenCount}return estimateTokens(message.content)}async countRawTokensOutsideFreshTail(conversationId){const contextItems=await this.getContextItemsCached(conversationId);const freshTailOrdinal=await this.resolveFreshTailOrdinal(contextItems);let rawTokens=0;for(const item of contextItems){if(item.ordinal>=freshTailOrdinal){break}if(item.itemType!=="message"||item.messageId==null){continue}rawTokens+=await this.getMessageTokenCount(item.messageId)}return rawTokens}async selectOldestLeafChunk(conversationId,leafChunkTokensOverride){const contextItems=await this.getContextItemsCached(conversationId);const freshTailOrdinal=await this.resolveFreshTailOrdinal(contextItems);const threshold=this.resolveLeafChunkTokens(leafChunkTokensOverride);let rawTokensOutsideTail=0;for(const item of contextItems){if(item.ordinal>=freshTailOrdinal){break}if(item.itemType!=="message"||item.messageId==null){continue}rawTokensOutsideTail+=await this.getMessageTokenCount(item.messageId)}const chunk=[];let chunkTokens=0;let started=false;for(const item of contextItems){if(item.ordinal>=freshTailOrdinal){break}if(!started){if(item.itemType!=="message"||item.messageId==null){continue}started=true}else if(item.itemType!=="message"||item.messageId==null){break}if(item.messageId==null){continue}const messageTokens=await this.getMessageTokenCount(item.messageId);if(chunk.length>0&&chunkTokens+messageTokens>threshold){break}chunk.push(item);chunkTokens+=messageTokens;if(chunkTokens>=threshold){break}}return{items:chunk,rawTokensOutsideTail,threshold}}async resolvePriorLeafSummaryContext(conversationId,messageItems){if(messageItems.length===0){return void 0}const startOrdinal=Math.min(...messageItems.map(item=>item.ordinal));const priorSummaryItems=(await this.getContextItemsCached(conversationId)).filter(item=>item.ordinal<startOrdinal&&item.itemType==="summary"&&typeof item.summaryId==="string").slice(-2);if(priorSummaryItems.length===0){return void 0}const summaryContents=[];for(const item of priorSummaryItems){if(typeof item.summaryId!=="string"){continue}const summary=await this.summaryStore.getSummary(item.summaryId);const content=summary?.content.trim();if(content){summaryContents.push(content)}}if(summaryContents.length===0){return void 0}return summaryContents.join("\n\n")}resolveSummaryTokenCount(summary){if(typeof summary.tokenCount==="number"&&Number.isFinite(summary.tokenCount)&&summary.tokenCount>0){return summary.tokenCount}return estimateTokens(summary.content)}resolveMessageTokenCount(message){if(typeof message.tokenCount==="number"&&Number.isFinite(message.tokenCount)&&message.tokenCount>0){return message.tokenCount}return estimateTokens(message.content)}resolveLeafMinFanout(){if(typeof this.config.leafMinFanout==="number"&&Number.isFinite(this.config.leafMinFanout)&&this.config.leafMinFanout>0){return Math.floor(this.config.leafMinFanout)}return 8}resolveCondensedMinFanout(){if(typeof this.config.condensedMinFanout==="number"&&Number.isFinite(this.config.condensedMinFanout)&&this.config.condensedMinFanout>0){return Math.floor(this.config.condensedMinFanout)}return 4}resolveCondensedMinFanoutHard(){if(typeof this.config.condensedMinFanoutHard==="number"&&Number.isFinite(this.config.condensedMinFanoutHard)&&this.config.condensedMinFanoutHard>0){return Math.floor(this.config.condensedMinFanoutHard)}return 2}resolveIncrementalMaxDepth(){if(typeof this.config.incrementalMaxDepth==="number"&&Number.isFinite(this.config.incrementalMaxDepth)){if(this.config.incrementalMaxDepth<0)return Infinity;if(this.config.incrementalMaxDepth>0)return Math.floor(this.config.incrementalMaxDepth)}return 0}resolveFanoutForDepth(targetDepth,hardTrigger){if(hardTrigger){return this.resolveCondensedMinFanoutHard()}if(targetDepth===0){return this.resolveLeafMinFanout()}return this.resolveCondensedMinFanout()}resolveCondensedMinChunkTokens(){const chunkTarget=this.resolveLeafChunkTokens();const ratioFloor=Math.floor(chunkTarget*CONDENSED_MIN_INPUT_RATIO);return Math.max(this.config.condensedTargetTokens,ratioFloor)}async selectShallowestCondensationCandidate(params){const{conversationId,hardTrigger}=params;const contextItems=await this.getContextItemsCached(conversationId);const freshTailOrdinal=await this.resolveFreshTailOrdinal(contextItems);const minChunkTokens=this.resolveCondensedMinChunkTokens();const depthLevels=await this.summaryStore.getDistinctDepthsInContext(conversationId,{maxOrdinalExclusive:freshTailOrdinal});for(const targetDepth of depthLevels){const fanout=this.resolveFanoutForDepth(targetDepth,hardTrigger);const chunk=await this.selectOldestChunkAtDepth(conversationId,targetDepth,freshTailOrdinal);if(chunk.items.length<fanout){continue}if(chunk.summaryTokens<minChunkTokens){continue}return{targetDepth,chunk}}return null}async selectOldestChunkAtDepth(conversationId,targetDepth,freshTailOrdinalOverride){const contextItems=await this.getContextItemsCached(conversationId);const freshTailOrdinal=typeof freshTailOrdinalOverride==="number"?freshTailOrdinalOverride:await this.resolveFreshTailOrdinal(contextItems);const chunkTokenBudget=this.resolveLeafChunkTokens();const chunk=[];let summaryTokens=0;for(const item of contextItems){if(item.ordinal>=freshTailOrdinal){break}if(item.itemType!=="summary"||item.summaryId==null){if(chunk.length>0){break}continue}const summary=await this.summaryStore.getSummary(item.summaryId);if(!summary){if(chunk.length>0){break}continue}if(summary.depth!==targetDepth){if(chunk.length>0){break}continue}const tokenCount=this.resolveSummaryTokenCount(summary);if(chunk.length>0&&summaryTokens+tokenCount>chunkTokenBudget){break}chunk.push(item);summaryTokens+=tokenCount;if(summaryTokens>=chunkTokenBudget){break}}return{items:chunk,summaryTokens}}async resolvePriorSummaryContextAtDepth(conversationId,summaryItems,targetDepth){if(summaryItems.length===0){return void 0}const startOrdinal=Math.min(...summaryItems.map(item=>item.ordinal));const priorSummaryItems=(await this.getContextItemsCached(conversationId)).filter(item=>item.ordinal<startOrdinal&&item.itemType==="summary"&&typeof item.summaryId==="string").slice(-4);if(priorSummaryItems.length===0){return void 0}const summaryContents=[];for(const item of priorSummaryItems){if(typeof item.summaryId!=="string"){continue}const summary=await this.summaryStore.getSummary(item.summaryId);if(!summary||summary.depth!==targetDepth){continue}const content=summary.content.trim();if(content){summaryContents.push(content)}}if(summaryContents.length===0){return void 0}return summaryContents.slice(-2).join("\n\n")}async summarizeWithEscalation(params){const sourceText=params.sourceText.trim();if(!sourceText){return{content:"[Truncated from 0 tokens]",level:"fallback"}}const inputTokens=Math.max(1,estimateTokens(sourceText));const buildDeterministicFallback=()=>{const suffix=`
|
|
21
21
|
[Truncated from ${inputTokens} tokens]`;const truncated=truncateTextToEstimatedTokens(sourceText,Math.max(0,FALLBACK_MAX_TOKENS-estimateTokens(suffix)));return{content:`${truncated}${suffix}`,level:"fallback"}};const authFailure=Symbol("authFailure");const runSummarizer=async aggressiveMode=>{let output;try{output=await params.summarize(sourceText,aggressiveMode,params.options)}catch(err){if(err instanceof LcmProviderAuthError){return authFailure}throw err}const trimmed=output.trim();return trimmed||null};const initialSummary=await runSummarizer(false);if(initialSummary===authFailure){return null}if(initialSummary===null){return buildDeterministicFallback()}let summaryText=initialSummary;let level="normal";if(estimateTokens(summaryText)>=inputTokens){const aggressiveSummary=await runSummarizer(true);if(aggressiveSummary===authFailure){return null}if(aggressiveSummary===null){return buildDeterministicFallback()}summaryText=aggressiveSummary;level="aggressive";if(estimateTokens(summaryText)>=inputTokens){return buildDeterministicFallback()}}const summaryTokens=estimateTokens(summaryText);const maxTokens=Math.ceil(params.targetTokens*this.config.summaryMaxOverageFactor);if(summaryTokens>Math.ceil(params.targetTokens*1.5)){this.log.warn(`[lcm] summary exceeds target by ${Math.round((summaryTokens/params.targetTokens-1)*100)}%: ${summaryTokens} tokens vs target ${params.targetTokens}`)}if(summaryTokens>maxTokens){summaryText=capSummaryText(summaryText,summaryTokens,maxTokens);level="capped"}return{content:summaryText,level}}async annotateMediaContent(messageId,content){const parts=await this.conversationStore.getMessageParts(messageId);const hasMediaParts=parts.some(part=>isMediaAttachmentPart(part));if(!hasMediaParts){return content}const partText=parts.filter(part=>!isMediaAttachmentPart(part)).map(part=>typeof part.textContent==="string"?part.textContent:"").map(text=>stripEmbeddedMediaPayloads(text)).map(text=>text.trim()).filter(Boolean).join("\n").trim();const fallbackText=extractMeaningfulMessageText(content);const meaningfulText=(partText||fallbackText).trim();if(!meaningfulText){return"[Media attachment]"}if(meaningfulText.includes("[with media attachment]")){return meaningfulText}return`${meaningfulText} [with media attachment]`}async leafPass(conversationId,messageItems,summarize,previousSummaryContent,summaryModel){const messageContents=[];for(const item of messageItems){if(item.messageId==null){continue}const msg=await this.conversationStore.getMessageById(item.messageId);if(msg){const annotatedContent=await this.annotateMediaContent(msg.messageId,msg.content);messageContents.push({messageId:msg.messageId,content:annotatedContent,createdAt:msg.createdAt,tokenCount:this.resolveMessageTokenCount(msg)})}}const concatenated=messageContents.map(message=>`[${formatTimestamp(message.createdAt,this.config.timezone)}]
|
|
22
22
|
${message.content}`).join("\n\n");const fileIds=dedupeOrderedIds(messageContents.flatMap(message=>extractFileIdsFromContent(message.content)));const summary=await this.summarizeWithEscalation({sourceText:concatenated,summarize,options:{previousSummary:previousSummaryContent,isCondensed:false},targetTokens:this.config.leafTargetTokens});if(!summary){this.log.warn(`[lcm] leaf compaction skipped summary write; conversationId=${conversationId}; chunkMessages=${messageContents.length}`);return null}const summaryId=generateSummaryId(summary.content);const tokenCount=estimateTokens(summary.content);const removedTokens=messageContents.reduce((sum,message)=>sum+Math.max(0,Math.floor(message.tokenCount)),0);await this.summaryStore.withTransaction(async()=>{await this.summaryStore.insertSummary({summaryId,conversationId,kind:"leaf",depth:0,content:summary.content,tokenCount,fileIds,earliestAt:messageContents.length>0?new Date(Math.min(...messageContents.map(message=>message.createdAt.getTime()))):void 0,latestAt:messageContents.length>0?new Date(Math.max(...messageContents.map(message=>message.createdAt.getTime()))):void 0,descendantCount:0,descendantTokenCount:0,sourceMessageTokenCount:removedTokens,model:summaryModel});const messageIds=messageContents.map(m=>m.messageId);await this.summaryStore.linkSummaryToMessages(summaryId,messageIds);const ordinals=messageItems.map(ci=>ci.ordinal);const startOrdinal=Math.min(...ordinals);const endOrdinal=Math.max(...ordinals);await this.summaryStore.replaceContextRangeWithSummary({conversationId,startOrdinal,endOrdinal,summaryId})});this.invalidateContextCache(conversationId);return{summaryId,level:summary.level,content:summary.content,removedTokens,addedTokens:tokenCount}}async condensedPass(conversationId,summaryItems,targetDepth,summarize,summaryModel){const summaryRecords=[];for(const item of summaryItems){if(item.summaryId==null){continue}const rec=await this.summaryStore.getSummary(item.summaryId);if(rec){summaryRecords.push(rec)}}const concatenated=summaryRecords.map(summary=>{const earliestAt=summary.earliestAt??summary.createdAt;const latestAt=summary.latestAt??summary.createdAt;const tz=this.config.timezone;const header=`[${formatTimestamp(earliestAt,tz)} - ${formatTimestamp(latestAt,tz)}]`;return`${header}
|
|
23
|
-
${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords.flatMap(summary=>[...summary.fileIds,...extractFileIdsFromContent(summary.content)]));const previousSummaryContent=targetDepth===0?await this.resolvePriorSummaryContextAtDepth(conversationId,summaryItems,targetDepth):void 0;const condensed=await this.summarizeWithEscalation({sourceText:concatenated,summarize,options:{previousSummary:previousSummaryContent,isCondensed:true,depth:targetDepth+1},targetTokens:this.config.condensedTargetTokens});if(!condensed){this.log.warn(`[lcm] condensed compaction skipped summary write; conversationId=${conversationId}; depth=${targetDepth}; chunkSummaries=${summaryRecords.length}`);return null}const summaryId=generateSummaryId(condensed.content);const tokenCount=estimateTokens(condensed.content);await this.summaryStore.withTransaction(async()=>{await this.summaryStore.insertSummary({summaryId,conversationId,kind:"condensed",depth:targetDepth+1,content:condensed.content,tokenCount,fileIds,earliestAt:summaryRecords.length>0?new Date(Math.min(...summaryRecords.map(summary=>(summary.earliestAt??summary.createdAt).getTime()))):void 0,latestAt:summaryRecords.length>0?new Date(Math.max(...summaryRecords.map(summary=>(summary.latestAt??summary.createdAt).getTime()))):void 0,descendantCount:summaryRecords.reduce((count,summary)=>{const childDescendants=typeof summary.descendantCount==="number"&&Number.isFinite(summary.descendantCount)?Math.max(0,Math.floor(summary.descendantCount)):0;return count+childDescendants+1},0),descendantTokenCount:summaryRecords.reduce((count,summary)=>{const childDescendantTokens=typeof summary.descendantTokenCount==="number"&&Number.isFinite(summary.descendantTokenCount)?Math.max(0,Math.floor(summary.descendantTokenCount)):0;return count+Math.max(0,Math.floor(summary.tokenCount))+childDescendantTokens},0),sourceMessageTokenCount:summaryRecords.reduce((count,summary)=>{const sourceTokens=typeof summary.sourceMessageTokenCount==="number"&&Number.isFinite(summary.sourceMessageTokenCount)?Math.max(0,Math.floor(summary.sourceMessageTokenCount)):0;return count+sourceTokens},0),model:summaryModel});const parentSummaryIds=summaryRecords.map(s=>s.summaryId);await this.summaryStore.linkSummaryToParents(summaryId,parentSummaryIds);const ordinals=summaryItems.map(ci=>ci.ordinal);const startOrdinal=Math.min(...ordinals);const endOrdinal=Math.max(...ordinals);await this.summaryStore.replaceContextRangeWithSummary({conversationId,startOrdinal,endOrdinal,summaryId})});this.invalidateContextCache(conversationId);const removedTokens=summaryRecords.reduce((sum,s)=>sum+Math.max(0,Math.floor(s.tokenCount)),0);return{summaryId,level:condensed.level,removedTokens,addedTokens:tokenCount}}async persistCompactionEvents(input){const{conversationId,tokensBefore,tokensAfterLeaf,tokensAfterFinal,leafResult,condenseResult}=input;if(!leafResult&&!condenseResult){return}const conversation=await this.conversationStore.getConversation(conversationId);if(!conversation){return}const createdSummaryIds=[leafResult?.summaryId,condenseResult?.summaryId].filter(id=>typeof id==="string"&&id.length>0);const condensedPassOccurred=condenseResult!==null;if(leafResult){await this.persistCompactionEvent({conversationId,sessionId:conversation.sessionId,pass:"leaf",level:leafResult.level,tokensBefore,tokensAfter:tokensAfterLeaf,createdSummaryId:leafResult.summaryId,createdSummaryIds,condensedPassOccurred})}if(condenseResult){await this.persistCompactionEvent({conversationId,sessionId:conversation.sessionId,pass:"condensed",level:condenseResult.level,tokensBefore:tokensAfterLeaf,tokensAfter:tokensAfterFinal,createdSummaryId:condenseResult.summaryId,createdSummaryIds,condensedPassOccurred})}}async persistCompactionEvent(input){const content=`LCM compaction ${input.pass} pass (${input.level}): ${input.tokensBefore} -> ${input.tokensAfter}`;this.log.info(`[lcm] ${content} conversation=${input.conversationId} summary=${input.createdSummaryId}`)}};var featureCache=new WeakMap;function probeVirtualTable(db,sql){try{db.exec("DROP TABLE IF EXISTS temp.__lcm_virtual_table_probe");db.exec(sql);db.exec("DROP TABLE temp.__lcm_virtual_table_probe");return true}catch{try{db.exec("DROP TABLE IF EXISTS temp.__lcm_virtual_table_probe")}catch{}return false}}function probeFts5(db){return probeVirtualTable(db,"CREATE VIRTUAL TABLE temp.__lcm_virtual_table_probe USING fts5(content)")}function probeTrigramTokenizer(db){return probeVirtualTable(db,"CREATE VIRTUAL TABLE temp.__lcm_virtual_table_probe USING fts5(content, tokenize='trigram')")}function getLcmDbFeatures(db){const cached=featureCache.get(db);if(cached){return cached}const detected={fts5Available:probeFts5(db),trigramTokenizerAvailable:false};if(detected.fts5Available){detected.trigramTokenizerAvailable=probeTrigramTokenizer(db)}featureCache.set(db,detected);return detected}function parseUtcTimestamp(value){const s=value.trim();if(/(?:[zZ]|[+-]\d{2}:\d{2})$/.test(s)){return new Date(s)}const normalized=s.includes("T")?s:s.replace(" ","T");return new Date(`${normalized}Z`)}function parseUtcTimestampOrNull(value){if(value==null)return null;return parseUtcTimestamp(value)}var VERSIONED_BACKFILL_STEPS={backfillSummaryDepths:1,backfillSummaryMetadata:1,backfillToolCallColumns:1};function ensureSummaryDepthColumn(db){const summaryColumns=db.prepare(`PRAGMA table_info(summaries)`).all();const hasDepth=summaryColumns.some(col=>col.name==="depth");if(!hasDepth){db.exec(`ALTER TABLE summaries ADD COLUMN depth INTEGER NOT NULL DEFAULT 0`)}}function ensureSummaryMetadataColumns(db){const summaryColumns=db.prepare(`PRAGMA table_info(summaries)`).all();const hasEarliestAt=summaryColumns.some(col=>col.name==="earliest_at");const hasLatestAt=summaryColumns.some(col=>col.name==="latest_at");const hasDescendantCount=summaryColumns.some(col=>col.name==="descendant_count");const hasDescendantTokenCount=summaryColumns.some(col=>col.name==="descendant_token_count");const hasSourceMessageTokenCount=summaryColumns.some(col=>col.name==="source_message_token_count");if(!hasEarliestAt){db.exec(`ALTER TABLE summaries ADD COLUMN earliest_at TEXT`)}if(!hasLatestAt){db.exec(`ALTER TABLE summaries ADD COLUMN latest_at TEXT`)}if(!hasDescendantCount){db.exec(`ALTER TABLE summaries ADD COLUMN descendant_count INTEGER NOT NULL DEFAULT 0`)}if(!hasDescendantTokenCount){db.exec(`ALTER TABLE summaries ADD COLUMN descendant_token_count INTEGER NOT NULL DEFAULT 0`)}if(!hasSourceMessageTokenCount){db.exec(`ALTER TABLE summaries ADD COLUMN source_message_token_count INTEGER NOT NULL DEFAULT 0`)}}function parseTimestamp(value){return parseUtcTimestampOrNull(value)}function isoStringOrNull(value){return value?value.toISOString():null}function ensureSummaryModelColumn(db){const summaryColumns=db.prepare(`PRAGMA table_info(summaries)`).all();const hasModel=summaryColumns.some(col=>col.name==="model");if(!hasModel){db.exec(`ALTER TABLE summaries ADD COLUMN model TEXT NOT NULL DEFAULT 'unknown'`)}}function ensureCompactionTelemetryColumns(db){const telemetryColumns=db.prepare(`PRAGMA table_info(conversation_compaction_telemetry)`).all();const hasLastLeafCompactionAt=telemetryColumns.some(col=>col.name==="last_leaf_compaction_at");const hasTurnsSinceLeafCompaction=telemetryColumns.some(col=>col.name==="turns_since_leaf_compaction");const hasTokensAccumulatedSinceLeafCompaction=telemetryColumns.some(col=>col.name==="tokens_accumulated_since_leaf_compaction");const hasLastActivityBand=telemetryColumns.some(col=>col.name==="last_activity_band");if(!hasLastLeafCompactionAt){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN last_leaf_compaction_at TEXT`)}if(!hasTurnsSinceLeafCompaction){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN turns_since_leaf_compaction INTEGER NOT NULL DEFAULT 0`)}if(!hasTokensAccumulatedSinceLeafCompaction){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN tokens_accumulated_since_leaf_compaction INTEGER NOT NULL DEFAULT 0`)}if(!hasLastActivityBand){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN last_activity_band TEXT NOT NULL DEFAULT 'low' CHECK (last_activity_band IN ('low', 'medium', 'high'))`)}
|
|
23
|
+
${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords.flatMap(summary=>[...summary.fileIds,...extractFileIdsFromContent(summary.content)]));const previousSummaryContent=targetDepth===0?await this.resolvePriorSummaryContextAtDepth(conversationId,summaryItems,targetDepth):void 0;const condensed=await this.summarizeWithEscalation({sourceText:concatenated,summarize,options:{previousSummary:previousSummaryContent,isCondensed:true,depth:targetDepth+1},targetTokens:this.config.condensedTargetTokens});if(!condensed){this.log.warn(`[lcm] condensed compaction skipped summary write; conversationId=${conversationId}; depth=${targetDepth}; chunkSummaries=${summaryRecords.length}`);return null}const summaryId=generateSummaryId(condensed.content);const tokenCount=estimateTokens(condensed.content);await this.summaryStore.withTransaction(async()=>{await this.summaryStore.insertSummary({summaryId,conversationId,kind:"condensed",depth:targetDepth+1,content:condensed.content,tokenCount,fileIds,earliestAt:summaryRecords.length>0?new Date(Math.min(...summaryRecords.map(summary=>(summary.earliestAt??summary.createdAt).getTime()))):void 0,latestAt:summaryRecords.length>0?new Date(Math.max(...summaryRecords.map(summary=>(summary.latestAt??summary.createdAt).getTime()))):void 0,descendantCount:summaryRecords.reduce((count,summary)=>{const childDescendants=typeof summary.descendantCount==="number"&&Number.isFinite(summary.descendantCount)?Math.max(0,Math.floor(summary.descendantCount)):0;return count+childDescendants+1},0),descendantTokenCount:summaryRecords.reduce((count,summary)=>{const childDescendantTokens=typeof summary.descendantTokenCount==="number"&&Number.isFinite(summary.descendantTokenCount)?Math.max(0,Math.floor(summary.descendantTokenCount)):0;return count+Math.max(0,Math.floor(summary.tokenCount))+childDescendantTokens},0),sourceMessageTokenCount:summaryRecords.reduce((count,summary)=>{const sourceTokens=typeof summary.sourceMessageTokenCount==="number"&&Number.isFinite(summary.sourceMessageTokenCount)?Math.max(0,Math.floor(summary.sourceMessageTokenCount)):0;return count+sourceTokens},0),model:summaryModel});const parentSummaryIds=summaryRecords.map(s=>s.summaryId);await this.summaryStore.linkSummaryToParents(summaryId,parentSummaryIds);const ordinals=summaryItems.map(ci=>ci.ordinal);const startOrdinal=Math.min(...ordinals);const endOrdinal=Math.max(...ordinals);await this.summaryStore.replaceContextRangeWithSummary({conversationId,startOrdinal,endOrdinal,summaryId})});this.invalidateContextCache(conversationId);const removedTokens=summaryRecords.reduce((sum,s)=>sum+Math.max(0,Math.floor(s.tokenCount)),0);return{summaryId,level:condensed.level,removedTokens,addedTokens:tokenCount}}async persistCompactionEvents(input){const{conversationId,tokensBefore,tokensAfterLeaf,tokensAfterFinal,leafResult,condenseResult}=input;if(!leafResult&&!condenseResult){return}const conversation=await this.conversationStore.getConversation(conversationId);if(!conversation){return}const createdSummaryIds=[leafResult?.summaryId,condenseResult?.summaryId].filter(id=>typeof id==="string"&&id.length>0);const condensedPassOccurred=condenseResult!==null;if(leafResult){await this.persistCompactionEvent({conversationId,sessionId:conversation.sessionId,pass:"leaf",level:leafResult.level,tokensBefore,tokensAfter:tokensAfterLeaf,createdSummaryId:leafResult.summaryId,createdSummaryIds,condensedPassOccurred})}if(condenseResult){await this.persistCompactionEvent({conversationId,sessionId:conversation.sessionId,pass:"condensed",level:condenseResult.level,tokensBefore:tokensAfterLeaf,tokensAfter:tokensAfterFinal,createdSummaryId:condenseResult.summaryId,createdSummaryIds,condensedPassOccurred})}}async persistCompactionEvent(input){const content=`LCM compaction ${input.pass} pass (${input.level}): ${input.tokensBefore} -> ${input.tokensAfter}`;this.log.info(`[lcm] ${content} conversation=${input.conversationId} summary=${input.createdSummaryId}`)}};var featureCache=new WeakMap;function probeVirtualTable(db,sql){try{db.exec("DROP TABLE IF EXISTS temp.__lcm_virtual_table_probe");db.exec(sql);db.exec("DROP TABLE temp.__lcm_virtual_table_probe");return true}catch{try{db.exec("DROP TABLE IF EXISTS temp.__lcm_virtual_table_probe")}catch{}return false}}function probeFts5(db){return probeVirtualTable(db,"CREATE VIRTUAL TABLE temp.__lcm_virtual_table_probe USING fts5(content)")}function probeTrigramTokenizer(db){return probeVirtualTable(db,"CREATE VIRTUAL TABLE temp.__lcm_virtual_table_probe USING fts5(content, tokenize='trigram')")}function getLcmDbFeatures(db){const cached=featureCache.get(db);if(cached){return cached}const detected={fts5Available:probeFts5(db),trigramTokenizerAvailable:false};if(detected.fts5Available){detected.trigramTokenizerAvailable=probeTrigramTokenizer(db)}featureCache.set(db,detected);return detected}import{createHash as createHash2}from"node:crypto";function buildMessageIdentityHash(role,content){return createHash2("sha256").update(role).update("\0").update(content).digest("hex")}function parseUtcTimestamp(value){const s=value.trim();if(/(?:[zZ]|[+-]\d{2}:\d{2})$/.test(s)){return new Date(s)}const normalized=s.includes("T")?s:s.replace(" ","T");return new Date(`${normalized}Z`)}function parseUtcTimestampOrNull(value){if(value==null)return null;return parseUtcTimestamp(value)}var VERSIONED_BACKFILL_STEPS={backfillSummaryDepths:1,backfillSummaryMetadata:1,backfillToolCallColumns:1};function ensureSummaryDepthColumn(db){const summaryColumns=db.prepare(`PRAGMA table_info(summaries)`).all();const hasDepth=summaryColumns.some(col=>col.name==="depth");if(!hasDepth){db.exec(`ALTER TABLE summaries ADD COLUMN depth INTEGER NOT NULL DEFAULT 0`)}}function ensureSummaryMetadataColumns(db){const summaryColumns=db.prepare(`PRAGMA table_info(summaries)`).all();const hasEarliestAt=summaryColumns.some(col=>col.name==="earliest_at");const hasLatestAt=summaryColumns.some(col=>col.name==="latest_at");const hasDescendantCount=summaryColumns.some(col=>col.name==="descendant_count");const hasDescendantTokenCount=summaryColumns.some(col=>col.name==="descendant_token_count");const hasSourceMessageTokenCount=summaryColumns.some(col=>col.name==="source_message_token_count");if(!hasEarliestAt){db.exec(`ALTER TABLE summaries ADD COLUMN earliest_at TEXT`)}if(!hasLatestAt){db.exec(`ALTER TABLE summaries ADD COLUMN latest_at TEXT`)}if(!hasDescendantCount){db.exec(`ALTER TABLE summaries ADD COLUMN descendant_count INTEGER NOT NULL DEFAULT 0`)}if(!hasDescendantTokenCount){db.exec(`ALTER TABLE summaries ADD COLUMN descendant_token_count INTEGER NOT NULL DEFAULT 0`)}if(!hasSourceMessageTokenCount){db.exec(`ALTER TABLE summaries ADD COLUMN source_message_token_count INTEGER NOT NULL DEFAULT 0`)}}function parseTimestamp(value){return parseUtcTimestampOrNull(value)}function isoStringOrNull(value){return value?value.toISOString():null}function ensureSummaryModelColumn(db){const summaryColumns=db.prepare(`PRAGMA table_info(summaries)`).all();const hasModel=summaryColumns.some(col=>col.name==="model");if(!hasModel){db.exec(`ALTER TABLE summaries ADD COLUMN model TEXT NOT NULL DEFAULT 'unknown'`)}}function ensureCompactionTelemetryColumns(db){const telemetryColumns=db.prepare(`PRAGMA table_info(conversation_compaction_telemetry)`).all();const hasConsecutiveColdObservations=telemetryColumns.some(col=>col.name==="consecutive_cold_observations");const hasLastLeafCompactionAt=telemetryColumns.some(col=>col.name==="last_leaf_compaction_at");const hasTurnsSinceLeafCompaction=telemetryColumns.some(col=>col.name==="turns_since_leaf_compaction");const hasTokensAccumulatedSinceLeafCompaction=telemetryColumns.some(col=>col.name==="tokens_accumulated_since_leaf_compaction");const hasLastActivityBand=telemetryColumns.some(col=>col.name==="last_activity_band");const hasLastApiCallAt=telemetryColumns.some(col=>col.name==="last_api_call_at");const hasLastCacheTouchAt=telemetryColumns.some(col=>col.name==="last_cache_touch_at");const hasProvider=telemetryColumns.some(col=>col.name==="provider");const hasModel=telemetryColumns.some(col=>col.name==="model");if(!hasConsecutiveColdObservations){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN consecutive_cold_observations INTEGER NOT NULL DEFAULT 0`)}if(!hasLastLeafCompactionAt){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN last_leaf_compaction_at TEXT`)}if(!hasTurnsSinceLeafCompaction){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN turns_since_leaf_compaction INTEGER NOT NULL DEFAULT 0`)}if(!hasTokensAccumulatedSinceLeafCompaction){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN tokens_accumulated_since_leaf_compaction INTEGER NOT NULL DEFAULT 0`)}if(!hasLastActivityBand){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN last_activity_band TEXT NOT NULL DEFAULT 'low' CHECK (last_activity_band IN ('low', 'medium', 'high'))`)}if(!hasLastApiCallAt){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN last_api_call_at TEXT`)}if(!hasLastCacheTouchAt){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN last_cache_touch_at TEXT`)}if(!hasProvider){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN provider TEXT`)}if(!hasModel){db.exec(`ALTER TABLE conversation_compaction_telemetry ADD COLUMN model TEXT`)}}function ensureMessageIdentityHashColumn(db){const messageColumns=db.prepare(`PRAGMA table_info(messages)`).all();const hasIdentityHash=messageColumns.some(col=>col.name==="identity_hash");if(!hasIdentityHash){db.exec(`ALTER TABLE messages ADD COLUMN identity_hash TEXT`)}}function backfillMessageIdentityHashes(db){const selectStmt=db.prepare(`SELECT message_id, role, content
|
|
24
|
+
FROM messages
|
|
25
|
+
WHERE message_id > ?
|
|
26
|
+
AND (identity_hash IS NULL OR identity_hash = '')
|
|
27
|
+
ORDER BY message_id
|
|
28
|
+
LIMIT ?`);const updateStmt=db.prepare(`UPDATE messages SET identity_hash = ? WHERE message_id = ?`);let lastProcessedMessageId=0;while(true){const rows=selectStmt.all(lastProcessedMessageId,1e3);if(rows.length===0){return}db.exec(`BEGIN`);try{for(const row of rows){updateStmt.run(buildMessageIdentityHash(row.role,row.content),row.message_id)}db.exec(`COMMIT`)}catch(error){try{db.exec(`ROLLBACK`)}catch{}throw error}lastProcessedMessageId=rows[rows.length-1]?.message_id??lastProcessedMessageId}}function describeMigrationError(error){return error instanceof Error?error.message:String(error)}function runMigrationStep(name,log,step){const startedAt=Date.now();try{step();log?.info?.(`[lcm] migration step complete: step=${name} durationMs=${Date.now()-startedAt}`)}catch(error){log?.info?.(`[lcm] migration step failed: step=${name} durationMs=${Date.now()-startedAt} error=${describeMigrationError(error)}`);throw error}}function getVersionedBackfillSavepointName(stepName){return`lcm_backfill_${stepName}`}function hasCompletedVersionedBackfill(db,stepName,algorithmVersion){const row=db.prepare(`SELECT 1
|
|
24
29
|
FROM lcm_migration_state
|
|
25
30
|
WHERE step_name = ? AND algorithm_version = ?
|
|
26
31
|
LIMIT 1`).get(stepName,algorithmVersion);return row!=null}function markVersionedBackfillComplete(db,stepName,algorithmVersion){db.prepare(`INSERT INTO lcm_migration_state (step_name, algorithm_version, completed_at)
|
|
@@ -114,6 +119,7 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
114
119
|
role TEXT NOT NULL CHECK (role IN ('system', 'user', 'assistant', 'tool')),
|
|
115
120
|
content TEXT NOT NULL,
|
|
116
121
|
token_count INTEGER NOT NULL,
|
|
122
|
+
identity_hash TEXT,
|
|
117
123
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
118
124
|
UNIQUE (conversation_id, seq)
|
|
119
125
|
);
|
|
@@ -229,12 +235,31 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
229
235
|
last_observed_cache_break_at TEXT,
|
|
230
236
|
cache_state TEXT NOT NULL DEFAULT 'unknown'
|
|
231
237
|
CHECK (cache_state IN ('hot', 'cold', 'unknown')),
|
|
238
|
+
consecutive_cold_observations INTEGER NOT NULL DEFAULT 0,
|
|
232
239
|
retention TEXT,
|
|
233
240
|
last_leaf_compaction_at TEXT,
|
|
234
241
|
turns_since_leaf_compaction INTEGER NOT NULL DEFAULT 0,
|
|
235
242
|
tokens_accumulated_since_leaf_compaction INTEGER NOT NULL DEFAULT 0,
|
|
236
243
|
last_activity_band TEXT NOT NULL DEFAULT 'low'
|
|
237
244
|
CHECK (last_activity_band IN ('low', 'medium', 'high')),
|
|
245
|
+
last_api_call_at TEXT,
|
|
246
|
+
last_cache_touch_at TEXT,
|
|
247
|
+
provider TEXT,
|
|
248
|
+
model TEXT,
|
|
249
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
CREATE TABLE IF NOT EXISTS conversation_compaction_maintenance (
|
|
253
|
+
conversation_id INTEGER PRIMARY KEY REFERENCES conversations(conversation_id) ON DELETE CASCADE,
|
|
254
|
+
pending INTEGER NOT NULL DEFAULT 0,
|
|
255
|
+
requested_at TEXT,
|
|
256
|
+
reason TEXT,
|
|
257
|
+
running INTEGER NOT NULL DEFAULT 0,
|
|
258
|
+
last_started_at TEXT,
|
|
259
|
+
last_finished_at TEXT,
|
|
260
|
+
last_failure_summary TEXT,
|
|
261
|
+
token_budget INTEGER,
|
|
262
|
+
current_token_count INTEGER,
|
|
238
263
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
239
264
|
);
|
|
240
265
|
|
|
@@ -271,7 +296,7 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
271
296
|
`);db.exec(`
|
|
272
297
|
CREATE INDEX IF NOT EXISTS conversations_session_id_active_created_idx
|
|
273
298
|
ON conversations (session_id, active, created_at)
|
|
274
|
-
`);db.exec(`DROP INDEX IF EXISTS conversations_session_key_idx`);runMigrationStep("ensureSummaryDepthColumn",log,()=>ensureSummaryDepthColumn(db));runMigrationStep("ensureSummaryMetadataColumns",log,()=>ensureSummaryMetadataColumns(db));runMigrationStep("ensureSummaryModelColumn",log,()=>ensureSummaryModelColumn(db));runMigrationStep("ensureCompactionTelemetryColumns",log,()=>ensureCompactionTelemetryColumns(db));runVersionedBackfillStep(db,"backfillSummaryDepths",log,()=>backfillSummaryDepths(db));runMigrationStep("createSummariesDepthIndex",log,()=>db.exec(`CREATE INDEX IF NOT EXISTS summaries_conv_depth_kind_idx ON summaries (conversation_id, depth, kind)`));runVersionedBackfillStep(db,"backfillSummaryMetadata",log,()=>backfillSummaryMetadata(db));runVersionedBackfillStep(db,"backfillToolCallColumns",log,()=>backfillToolCallColumns(db));const detectedFeatures=options?.fts5Available===false?null:getLcmDbFeatures(db);const fts5Available=options?.fts5Available??detectedFeatures?.fts5Available??false;if(!fts5Available){return}const trigramTokenizerAvailable=detectedFeatures?.trigramTokenizerAvailable??false;if(!trigramTokenizerAvailable){try{db.exec(`DROP TABLE IF EXISTS summaries_fts_cjk`)}catch{}}runMigrationStep("ensureMessagesFts",log,()=>{ensureStandaloneFtsTable(db,{tableName:"messages_fts",createSql:`
|
|
299
|
+
`);db.exec(`DROP INDEX IF EXISTS conversations_session_key_idx`);runMigrationStep("ensureSummaryDepthColumn",log,()=>ensureSummaryDepthColumn(db));runMigrationStep("ensureSummaryMetadataColumns",log,()=>ensureSummaryMetadataColumns(db));runMigrationStep("ensureSummaryModelColumn",log,()=>ensureSummaryModelColumn(db));runMigrationStep("ensureMessageIdentityHashColumn",log,()=>ensureMessageIdentityHashColumn(db));runMigrationStep("backfillMessageIdentityHashes",log,()=>backfillMessageIdentityHashes(db));runMigrationStep("createMessagesIdentityHashIndex",log,()=>db.exec(`CREATE INDEX IF NOT EXISTS messages_conv_identity_hash_idx ON messages (conversation_id, identity_hash)`));runMigrationStep("ensureCompactionTelemetryColumns",log,()=>ensureCompactionTelemetryColumns(db));runVersionedBackfillStep(db,"backfillSummaryDepths",log,()=>backfillSummaryDepths(db));runMigrationStep("createSummariesDepthIndex",log,()=>db.exec(`CREATE INDEX IF NOT EXISTS summaries_conv_depth_kind_idx ON summaries (conversation_id, depth, kind)`));runVersionedBackfillStep(db,"backfillSummaryMetadata",log,()=>backfillSummaryMetadata(db));runVersionedBackfillStep(db,"backfillToolCallColumns",log,()=>backfillToolCallColumns(db));const detectedFeatures=options?.fts5Available===false?null:getLcmDbFeatures(db);const fts5Available=options?.fts5Available??detectedFeatures?.fts5Available??false;if(!fts5Available){return}const trigramTokenizerAvailable=detectedFeatures?.trigramTokenizerAvailable??false;if(!trigramTokenizerAvailable){try{db.exec(`DROP TABLE IF EXISTS summaries_fts_cjk`)}catch{}}runMigrationStep("ensureMessagesFts",log,()=>{ensureStandaloneFtsTable(db,{tableName:"messages_fts",createSql:`
|
|
275
300
|
CREATE VIRTUAL TABLE messages_fts USING fts5(
|
|
276
301
|
content,
|
|
277
302
|
tokenize='porter unicode61'
|
|
@@ -297,18 +322,23 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
297
322
|
`,seedSql:`
|
|
298
323
|
INSERT INTO summaries_fts_cjk(summary_id, content)
|
|
299
324
|
SELECT summary_id, content FROM summaries
|
|
300
|
-
`,expectedColumns:["summary_id","content"]})}})}var DEFAULT_MAX_DEPTH=3;var DEFAULT_TOKEN_CAP=4e3;var DEFAULT_TTL_MS=5*60*1e3;var ExpansionAuthManager=class{grants=new Map;consumedTokensByGrantId=new Map;createGrant(input){const grantId="grant_"+crypto.randomUUID().slice(0,12);const now=new Date;const ttlMs=input.ttlMs??DEFAULT_TTL_MS;const grant={grantId,issuerSessionId:input.issuerSessionId,allowedConversationIds:input.allowedConversationIds,allowedSummaryIds:input.allowedSummaryIds??[],maxDepth:input.maxDepth??DEFAULT_MAX_DEPTH,tokenCap:input.tokenCap??DEFAULT_TOKEN_CAP,expiresAt:new Date(now.getTime()+ttlMs),revoked:false,createdAt:now};this.grants.set(grantId,grant);this.consumedTokensByGrantId.set(grantId,0);return grant}getGrant(grantId){const grant=this.grants.get(grantId);if(!grant){return null}if(grant.revoked){return null}if(grant.expiresAt.getTime()<=Date.now()){return null}return grant}revokeGrant(grantId){const grant=this.grants.get(grantId);if(!grant){return false}grant.revoked=true;return true}getRemainingTokenBudget(grantId){const grant=this.getGrant(grantId);if(!grant){return null}const consumed=Math.max(0,this.consumedTokensByGrantId.get(grantId)??0);return Math.max(0,Math.floor(grant.tokenCap)-consumed)}consumeTokenBudget(grantId,consumedTokens){const grant=this.getGrant(grantId);if(!grant){return null}const safeConsumed=typeof consumedTokens==="number"&&Number.isFinite(consumedTokens)?Math.max(0,Math.floor(consumedTokens)):0;const previous=Math.max(0,this.consumedTokensByGrantId.get(grantId)??0);const next=Math.min(Math.max(1,Math.floor(grant.tokenCap)),previous+safeConsumed);this.consumedTokensByGrantId.set(grantId,next);return Math.max(0,Math.floor(grant.tokenCap)-next)}validateExpansion(grantId,request){const grant=this.grants.get(grantId);if(!grant){return{valid:false,reason:"Grant not found"}}if(grant.revoked){return{valid:false,reason:"Grant has been revoked"}}if(grant.expiresAt.getTime()<=Date.now()){return{valid:false,reason:"Grant has expired"}}if(!grant.allowedConversationIds.includes(request.conversationId)){return{valid:false,reason:`Conversation ${request.conversationId} is not in the allowed set`}}if(grant.allowedSummaryIds.length>0){const allowedSet=new Set(grant.allowedSummaryIds);const unauthorized=request.summaryIds.filter(id=>!allowedSet.has(id));if(unauthorized.length>0){return{valid:false,reason:`Summary IDs not authorized: ${unauthorized.join(", ")}`}}}return{valid:true}}cleanup(){const now=Date.now();let removed=0;for(const[grantId,grant]of this.grants){if(grant.revoked||grant.expiresAt.getTime()<=now){this.grants.delete(grantId);this.consumedTokensByGrantId.delete(grantId);removed++}}return removed}};var runtimeExpansionAuthManager=new ExpansionAuthManager;var delegatedSessionGrantIds=new Map;function getRuntimeExpansionAuthManager(){return runtimeExpansionAuthManager}function createDelegatedExpansionGrant(input){const delegatedSessionKey=input.delegatedSessionKey.trim();if(!delegatedSessionKey){throw new Error("delegatedSessionKey is required for delegated expansion grants")}const grant=runtimeExpansionAuthManager.createGrant({issuerSessionId:input.issuerSessionId,allowedConversationIds:input.allowedConversationIds,allowedSummaryIds:input.allowedSummaryIds,maxDepth:input.maxDepth,tokenCap:input.tokenCap,ttlMs:input.ttlMs});delegatedSessionGrantIds.set(delegatedSessionKey,grant.grantId);return grant}function resolveDelegatedExpansionGrantId(sessionKey){const key=sessionKey.trim();if(!key){return null}return delegatedSessionGrantIds.get(key)??null}function revokeDelegatedExpansionGrantForSession(sessionKey,opts){const key=sessionKey.trim();if(!key){return false}const grantId=delegatedSessionGrantIds.get(key);if(!grantId){return false}const didRevoke=runtimeExpansionAuthManager.revokeGrant(grantId);if(opts?.removeBinding){delegatedSessionGrantIds.delete(key)}return didRevoke}function removeDelegatedExpansionGrantForSession(sessionKey){const key=sessionKey.trim();if(!key){return false}return delegatedSessionGrantIds.delete(key)}function wrapWithAuth(orchestrator,authManager){return{async expand(grantId,request){const validation=authManager.validateExpansion(grantId,{conversationId:request.conversationId,summaryIds:request.summaryIds,depth:request.maxDepth??DEFAULT_MAX_DEPTH,tokenCap:request.tokenCap??DEFAULT_TOKEN_CAP});if(!validation.valid){throw new Error(`Expansion authorization failed: ${validation.reason}`)}const remainingBudget=authManager.getRemainingTokenBudget(grantId);if(remainingBudget==null){throw new Error("Expansion authorization failed: Grant not found")}if(remainingBudget<=0){throw new Error("Expansion authorization failed: Grant token budget exhausted")}const grant=authManager.getGrant(grantId);const grantMaxDepth=grant?.maxDepth??DEFAULT_MAX_DEPTH;const requestedDepth=typeof request.maxDepth==="number"&&Number.isFinite(request.maxDepth)?Math.max(1,Math.trunc(request.maxDepth)):grantMaxDepth;const effectiveDepth=Math.min(requestedDepth,grantMaxDepth);const requestedTokenCap=typeof request.tokenCap==="number"&&Number.isFinite(request.tokenCap)?Math.max(1,Math.trunc(request.tokenCap)):remainingBudget;const effectiveTokenCap=Math.max(1,Math.min(requestedTokenCap,remainingBudget));const result=await orchestrator.expand({...request,maxDepth:effectiveDepth,tokenCap:effectiveTokenCap});authManager.consumeTokenBudget(grantId,result.totalTokens);return result}}}var RetrievalEngine=class{constructor(conversationStore,summaryStore){this.conversationStore=conversationStore;this.summaryStore=summaryStore}conversationStore;summaryStore;async describe(id){if(id.startsWith("sum_")){return this.describeSummary(id)}if(id.startsWith("file_")){return this.describeFile(id)}return null}async describeSummary(id){const summary=await this.summaryStore.getSummary(id);if(!summary){return null}const[parents,children,messageIds,subtree]=await Promise.all([this.summaryStore.getSummaryParents(id),this.summaryStore.getSummaryChildren(id),this.summaryStore.getSummaryMessages(id),this.summaryStore.getSummarySubtree(id)]);return{id,type:"summary",summary:{conversationId:summary.conversationId,kind:summary.kind,content:summary.content,depth:summary.depth,tokenCount:summary.tokenCount,descendantCount:summary.descendantCount,descendantTokenCount:summary.descendantTokenCount,sourceMessageTokenCount:summary.sourceMessageTokenCount,fileIds:summary.fileIds,parentIds:parents.map(p=>p.summaryId),childIds:children.map(c=>c.summaryId),messageIds,earliestAt:summary.earliestAt,latestAt:summary.latestAt,subtree:subtree.map(node=>({summaryId:node.summaryId,parentSummaryId:node.parentSummaryId,depthFromRoot:node.depthFromRoot,kind:node.kind,depth:node.depth,tokenCount:node.tokenCount,descendantCount:node.descendantCount,descendantTokenCount:node.descendantTokenCount,sourceMessageTokenCount:node.sourceMessageTokenCount,earliestAt:node.earliestAt,latestAt:node.latestAt,childCount:node.childCount,path:node.path})),createdAt:summary.createdAt}}}async describeFile(id){const file=await this.summaryStore.getLargeFile(id);if(!file){return null}return{id,type:"file",file:{conversationId:file.conversationId,fileName:file.fileName,mimeType:file.mimeType,byteSize:file.byteSize,storageUri:file.storageUri,explorationSummary:file.explorationSummary,createdAt:file.createdAt}}}async grep(input){const{query,mode,scope,conversationId,since,before,limit,sort}=input;const searchInput={query,mode,conversationId,since,before,limit,sort};let messages=[];let summaries=[];if(scope==="messages"){messages=await this.conversationStore.searchMessages(searchInput)}else if(scope==="summaries"){summaries=await this.summaryStore.searchSummaries(searchInput)}else{[messages,summaries]=await Promise.all([this.conversationStore.searchMessages(searchInput),this.summaryStore.searchSummaries(searchInput)])}return{messages,summaries,totalMatches:messages.length+summaries.length}}async expand(input){const depth=input.depth??1;const includeMessages=input.includeMessages??false;const tokenCap=input.tokenCap??Infinity;const result={children:[],messages:[],estimatedTokens:0,truncated:false};await this.expandRecursive(input.summaryId,depth,includeMessages,tokenCap,result);return result}async expandRecursive(summaryId,depth,includeMessages,tokenCap,result){if(depth<=0){return}if(result.truncated){return}const summary=await this.summaryStore.getSummary(summaryId);if(!summary){return}if(summary.kind==="condensed"){const children=await this.summaryStore.getSummaryParents(summaryId);for(const child of children){if(result.truncated){break}if(result.estimatedTokens+child.tokenCount>tokenCap){result.truncated=true;break}result.children.push({summaryId:child.summaryId,kind:child.kind,content:child.content,tokenCount:child.tokenCount});result.estimatedTokens+=child.tokenCount;if(depth>1){await this.expandRecursive(child.summaryId,depth-1,includeMessages,tokenCap,result)}}}else if(summary.kind==="leaf"&&includeMessages){const messageIds=await this.summaryStore.getSummaryMessages(summaryId);for(const msgId of messageIds){if(result.truncated){break}const msg=await this.conversationStore.getMessageById(msgId);if(!msg){continue}const tokenCount=msg.tokenCount||estimateTokens(msg.content);if(result.estimatedTokens+tokenCount>tokenCap){result.truncated=true;break}result.messages.push({messageId:msg.messageId,role:msg.role,content:msg.content,tokenCount});result.estimatedTokens+=tokenCount}}}};function compileSessionPattern(pattern){const escaped=pattern.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*\*/g,"\0").replace(/\*/g,"[^:]*").replace(/\u0000/g,".*");return new RegExp(`^${escaped}$`)}function compileSessionPatterns(patterns){return patterns.map(pattern=>compileSessionPattern(pattern))}function matchesSessionPattern(sessionKey,patterns){return patterns.some(pattern=>pattern.test(sessionKey))}var STARTUP_BANNER_LOG_STATE=Symbol.for("@martian-engineering/lossless-claw/startup-banner-log-state");function getStartupBannerLogState(){const globalState=globalThis;if(!globalState[STARTUP_BANNER_LOG_STATE]){globalState[STARTUP_BANNER_LOG_STATE]={emitted:new Set}}return globalState[STARTUP_BANNER_LOG_STATE]}function logStartupBannerOnce(params){const state=getStartupBannerLogState();if(state.emitted.has(params.key)){return}state.emitted.add(params.key);params.log(params.message)}import{AsyncLocalStorage}from"node:async_hooks";var mutexMap=new WeakMap;var heldLockContext=new AsyncLocalStorage;var nextSavepointId=0;function getOrCreateMutex(db){let state=mutexMap.get(db);if(!state){state={tail:Promise.resolve()};mutexMap.set(db,state)}return state}function getHeldLockDepth(db){return heldLockContext.getStore()?.get(db)??0}function nextSavepointName(){nextSavepointId+=1;return`lcm_txn_savepoint_${nextSavepointId}`}function acquireTransactionLock(db){const mutex=getOrCreateMutex(db);let releaseResolve;const releasePromise=new Promise(resolve2=>{releaseResolve=resolve2});const waitOn=mutex.tail;mutex.tail=releasePromise;return waitOn.then(()=>releaseResolve)}async function withDatabaseTransaction(db,beginStatement,operation){if(getHeldLockDepth(db)>0){const savepointName=nextSavepointName();db.exec(`SAVEPOINT ${savepointName}`);try{const result=await operation();db.exec(`RELEASE SAVEPOINT ${savepointName}`);return result}catch(error){db.exec(`ROLLBACK TO SAVEPOINT ${savepointName}`);db.exec(`RELEASE SAVEPOINT ${savepointName}`);throw error}}const release=await acquireTransactionLock(db);try{const heldLocks=new Map(heldLockContext.getStore()??[]);heldLocks.set(db,(heldLocks.get(db)??0)+1);return await heldLockContext.run(heldLocks,async()=>{db.exec(beginStatement);try{const result=await operation();db.exec("COMMIT");return result}catch(error){db.exec("ROLLBACK");throw error}})}finally{release()}}function toConversationCompactionTelemetryRecord(row){return{conversationId:row.conversation_id,lastObservedCacheRead:row.last_observed_cache_read,lastObservedCacheWrite:row.last_observed_cache_write,lastObservedCacheHitAt:parseUtcTimestampOrNull(row.last_observed_cache_hit_at),lastObservedCacheBreakAt:parseUtcTimestampOrNull(row.last_observed_cache_break_at),cacheState:row.cache_state,retention:row.retention,lastLeafCompactionAt:parseUtcTimestampOrNull(row.last_leaf_compaction_at),turnsSinceLeafCompaction:row.turns_since_leaf_compaction??0,tokensAccumulatedSinceLeafCompaction:row.tokens_accumulated_since_leaf_compaction??0,lastActivityBand:row.last_activity_band??"low",updatedAt:parseUtcTimestampOrNull(row.updated_at)??new Date(0)}}var CompactionTelemetryStore=class{constructor(db){this.db=db}db;withTransaction(fn){return withDatabaseTransaction(this.db,"BEGIN",fn)}async getConversationCompactionTelemetry(conversationId){const row=this.db.prepare(`SELECT
|
|
325
|
+
`,expectedColumns:["summary_id","content"]})}})}var DEFAULT_MAX_DEPTH=3;var DEFAULT_TOKEN_CAP=4e3;var DEFAULT_TTL_MS=5*60*1e3;var ExpansionAuthManager=class{grants=new Map;consumedTokensByGrantId=new Map;createGrant(input){const grantId="grant_"+crypto.randomUUID().slice(0,12);const now=new Date;const ttlMs=input.ttlMs??DEFAULT_TTL_MS;const grant={grantId,issuerSessionId:input.issuerSessionId,allowedConversationIds:input.allowedConversationIds,allowedSummaryIds:input.allowedSummaryIds??[],maxDepth:input.maxDepth??DEFAULT_MAX_DEPTH,tokenCap:input.tokenCap??DEFAULT_TOKEN_CAP,expiresAt:new Date(now.getTime()+ttlMs),revoked:false,createdAt:now};this.grants.set(grantId,grant);this.consumedTokensByGrantId.set(grantId,0);return grant}getGrant(grantId){const grant=this.grants.get(grantId);if(!grant){return null}if(grant.revoked){return null}if(grant.expiresAt.getTime()<=Date.now()){return null}return grant}revokeGrant(grantId){const grant=this.grants.get(grantId);if(!grant){return false}grant.revoked=true;return true}getRemainingTokenBudget(grantId){const grant=this.getGrant(grantId);if(!grant){return null}const consumed=Math.max(0,this.consumedTokensByGrantId.get(grantId)??0);return Math.max(0,Math.floor(grant.tokenCap)-consumed)}consumeTokenBudget(grantId,consumedTokens){const grant=this.getGrant(grantId);if(!grant){return null}const safeConsumed=typeof consumedTokens==="number"&&Number.isFinite(consumedTokens)?Math.max(0,Math.floor(consumedTokens)):0;const previous=Math.max(0,this.consumedTokensByGrantId.get(grantId)??0);const next=Math.min(Math.max(1,Math.floor(grant.tokenCap)),previous+safeConsumed);this.consumedTokensByGrantId.set(grantId,next);return Math.max(0,Math.floor(grant.tokenCap)-next)}validateExpansion(grantId,request){const grant=this.grants.get(grantId);if(!grant){return{valid:false,reason:"Grant not found"}}if(grant.revoked){return{valid:false,reason:"Grant has been revoked"}}if(grant.expiresAt.getTime()<=Date.now()){return{valid:false,reason:"Grant has expired"}}if(!grant.allowedConversationIds.includes(request.conversationId)){return{valid:false,reason:`Conversation ${request.conversationId} is not in the allowed set`}}if(grant.allowedSummaryIds.length>0){const allowedSet=new Set(grant.allowedSummaryIds);const unauthorized=request.summaryIds.filter(id=>!allowedSet.has(id));if(unauthorized.length>0){return{valid:false,reason:`Summary IDs not authorized: ${unauthorized.join(", ")}`}}}return{valid:true}}cleanup(){const now=Date.now();let removed=0;for(const[grantId,grant]of this.grants){if(grant.revoked||grant.expiresAt.getTime()<=now){this.grants.delete(grantId);this.consumedTokensByGrantId.delete(grantId);removed++}}return removed}};var runtimeExpansionAuthManager=new ExpansionAuthManager;var delegatedSessionGrantIds=new Map;function getRuntimeExpansionAuthManager(){return runtimeExpansionAuthManager}function createDelegatedExpansionGrant(input){const delegatedSessionKey=input.delegatedSessionKey.trim();if(!delegatedSessionKey){throw new Error("delegatedSessionKey is required for delegated expansion grants")}const grant=runtimeExpansionAuthManager.createGrant({issuerSessionId:input.issuerSessionId,allowedConversationIds:input.allowedConversationIds,allowedSummaryIds:input.allowedSummaryIds,maxDepth:input.maxDepth,tokenCap:input.tokenCap,ttlMs:input.ttlMs});delegatedSessionGrantIds.set(delegatedSessionKey,grant.grantId);return grant}function resolveDelegatedExpansionGrantId(sessionKey){const key=sessionKey.trim();if(!key){return null}return delegatedSessionGrantIds.get(key)??null}function revokeDelegatedExpansionGrantForSession(sessionKey,opts){const key=sessionKey.trim();if(!key){return false}const grantId=delegatedSessionGrantIds.get(key);if(!grantId){return false}const didRevoke=runtimeExpansionAuthManager.revokeGrant(grantId);if(opts?.removeBinding){delegatedSessionGrantIds.delete(key)}return didRevoke}function removeDelegatedExpansionGrantForSession(sessionKey){const key=sessionKey.trim();if(!key){return false}return delegatedSessionGrantIds.delete(key)}function wrapWithAuth(orchestrator,authManager){return{async expand(grantId,request){const validation=authManager.validateExpansion(grantId,{conversationId:request.conversationId,summaryIds:request.summaryIds,depth:request.maxDepth??DEFAULT_MAX_DEPTH,tokenCap:request.tokenCap??DEFAULT_TOKEN_CAP});if(!validation.valid){throw new Error(`Expansion authorization failed: ${validation.reason}`)}const remainingBudget=authManager.getRemainingTokenBudget(grantId);if(remainingBudget==null){throw new Error("Expansion authorization failed: Grant not found")}if(remainingBudget<=0){throw new Error("Expansion authorization failed: Grant token budget exhausted")}const grant=authManager.getGrant(grantId);const grantMaxDepth=grant?.maxDepth??DEFAULT_MAX_DEPTH;const requestedDepth=typeof request.maxDepth==="number"&&Number.isFinite(request.maxDepth)?Math.max(1,Math.trunc(request.maxDepth)):grantMaxDepth;const effectiveDepth=Math.min(requestedDepth,grantMaxDepth);const requestedTokenCap=typeof request.tokenCap==="number"&&Number.isFinite(request.tokenCap)?Math.max(1,Math.trunc(request.tokenCap)):remainingBudget;const effectiveTokenCap=Math.max(1,Math.min(requestedTokenCap,remainingBudget));const result=await orchestrator.expand({...request,maxDepth:effectiveDepth,tokenCap:effectiveTokenCap});authManager.consumeTokenBudget(grantId,result.totalTokens);return result}}}var RetrievalEngine=class{constructor(conversationStore,summaryStore){this.conversationStore=conversationStore;this.summaryStore=summaryStore}conversationStore;summaryStore;async describe(id){if(id.startsWith("sum_")){return this.describeSummary(id)}if(id.startsWith("file_")){return this.describeFile(id)}return null}async describeSummary(id){const summary=await this.summaryStore.getSummary(id);if(!summary){return null}const[parents,children,messageIds,subtree]=await Promise.all([this.summaryStore.getSummaryParents(id),this.summaryStore.getSummaryChildren(id),this.summaryStore.getSummaryMessages(id),this.summaryStore.getSummarySubtree(id)]);return{id,type:"summary",summary:{conversationId:summary.conversationId,kind:summary.kind,content:summary.content,depth:summary.depth,tokenCount:summary.tokenCount,descendantCount:summary.descendantCount,descendantTokenCount:summary.descendantTokenCount,sourceMessageTokenCount:summary.sourceMessageTokenCount,fileIds:summary.fileIds,parentIds:parents.map(p=>p.summaryId),childIds:children.map(c=>c.summaryId),messageIds,earliestAt:summary.earliestAt,latestAt:summary.latestAt,subtree:subtree.map(node=>({summaryId:node.summaryId,parentSummaryId:node.parentSummaryId,depthFromRoot:node.depthFromRoot,kind:node.kind,depth:node.depth,tokenCount:node.tokenCount,descendantCount:node.descendantCount,descendantTokenCount:node.descendantTokenCount,sourceMessageTokenCount:node.sourceMessageTokenCount,earliestAt:node.earliestAt,latestAt:node.latestAt,childCount:node.childCount,path:node.path})),createdAt:summary.createdAt}}}async describeFile(id){const file=await this.summaryStore.getLargeFile(id);if(!file){return null}return{id,type:"file",file:{conversationId:file.conversationId,fileName:file.fileName,mimeType:file.mimeType,byteSize:file.byteSize,storageUri:file.storageUri,explorationSummary:file.explorationSummary,createdAt:file.createdAt}}}async grep(input){const{query,mode,scope,conversationId,since,before,limit,sort}=input;const searchInput={query,mode,conversationId,since,before,limit,sort};let messages=[];let summaries=[];if(scope==="messages"){messages=await this.conversationStore.searchMessages(searchInput)}else if(scope==="summaries"){summaries=await this.summaryStore.searchSummaries(searchInput)}else{[messages,summaries]=await Promise.all([this.conversationStore.searchMessages(searchInput),this.summaryStore.searchSummaries(searchInput)])}return{messages,summaries,totalMatches:messages.length+summaries.length}}async expand(input){const depth=input.depth??1;const includeMessages=input.includeMessages??false;const tokenCap=input.tokenCap??Infinity;const result={children:[],messages:[],estimatedTokens:0,truncated:false};await this.expandRecursive(input.summaryId,depth,includeMessages,tokenCap,result);return result}async expandRecursive(summaryId,depth,includeMessages,tokenCap,result){if(depth<=0){return}if(result.truncated){return}const summary=await this.summaryStore.getSummary(summaryId);if(!summary){return}if(summary.kind==="condensed"){const children=await this.summaryStore.getSummaryParents(summaryId);for(const child of children){if(result.truncated){break}if(result.estimatedTokens+child.tokenCount>tokenCap){result.truncated=true;break}result.children.push({summaryId:child.summaryId,kind:child.kind,content:child.content,tokenCount:child.tokenCount});result.estimatedTokens+=child.tokenCount;if(depth>1){await this.expandRecursive(child.summaryId,depth-1,includeMessages,tokenCap,result)}}}else if(summary.kind==="leaf"&&includeMessages){const messageIds=await this.summaryStore.getSummaryMessages(summaryId);for(const msgId of messageIds){if(result.truncated){break}const msg=await this.conversationStore.getMessageById(msgId);if(!msg){continue}const tokenCount=msg.tokenCount||estimateTokens(msg.content);if(result.estimatedTokens+tokenCount>tokenCap){result.truncated=true;break}result.messages.push({messageId:msg.messageId,role:msg.role,content:msg.content,tokenCount});result.estimatedTokens+=tokenCount}}}};function compileSessionPattern(pattern){const escaped=pattern.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*\*/g,"\0").replace(/\*/g,"[^:]*").replace(/\u0000/g,".*");return new RegExp(`^${escaped}$`)}function compileSessionPatterns(patterns){return patterns.map(pattern=>compileSessionPattern(pattern))}function matchesSessionPattern(sessionKey,patterns){return patterns.some(pattern=>pattern.test(sessionKey))}var STARTUP_BANNER_LOG_STATE=Symbol.for("@martian-engineering/lossless-claw/startup-banner-log-state");function getStartupBannerLogState(){const globalState=globalThis;if(!globalState[STARTUP_BANNER_LOG_STATE]){globalState[STARTUP_BANNER_LOG_STATE]={emitted:new Set}}return globalState[STARTUP_BANNER_LOG_STATE]}function logStartupBannerOnce(params){const state=getStartupBannerLogState();if(state.emitted.has(params.key)){return}state.emitted.add(params.key);params.log(params.message)}import{AsyncLocalStorage}from"node:async_hooks";var mutexMap=new WeakMap;var heldLockContext=new AsyncLocalStorage;var nextSavepointId=0;function getOrCreateMutex(db){let state=mutexMap.get(db);if(!state){state={tail:Promise.resolve()};mutexMap.set(db,state)}return state}function getHeldLockDepth(db){return heldLockContext.getStore()?.get(db)??0}function nextSavepointName(){nextSavepointId+=1;return`lcm_txn_savepoint_${nextSavepointId}`}function acquireTransactionLock(db){const mutex=getOrCreateMutex(db);let releaseResolve;const releasePromise=new Promise(resolve2=>{releaseResolve=resolve2});const waitOn=mutex.tail;mutex.tail=releasePromise;return waitOn.then(()=>releaseResolve)}var DatabaseTransactionTimeoutError=class extends Error{constructor(timeoutMs){super(`Timed out after ${timeoutMs}ms waiting for exclusive database access.`);this.name="DatabaseTransactionTimeoutError"}};async function acquireTransactionLockWithTimeout(db,timeoutMs){const normalizedTimeoutMs=Math.floor(timeoutMs);const acquisition=acquireTransactionLock(db);if(!Number.isFinite(normalizedTimeoutMs)||normalizedTimeoutMs<0){return acquisition}let timeoutHandle;try{return await Promise.race([acquisition,new Promise((_,reject)=>{timeoutHandle=setTimeout(()=>{reject(new DatabaseTransactionTimeoutError(normalizedTimeoutMs))},normalizedTimeoutMs)})])}catch(error){acquisition.then(release=>release(),()=>{});throw error}finally{if(timeoutHandle){clearTimeout(timeoutHandle)}}}async function withExclusiveDatabaseLock(db,options,operation){const release=await acquireTransactionLockWithTimeout(db,options.timeoutMs);try{return await operation()}finally{release()}}async function withDatabaseTransaction(db,beginStatement,operation){if(getHeldLockDepth(db)>0){const savepointName=nextSavepointName();db.exec(`SAVEPOINT ${savepointName}`);try{const result=await operation();db.exec(`RELEASE SAVEPOINT ${savepointName}`);return result}catch(error){db.exec(`ROLLBACK TO SAVEPOINT ${savepointName}`);db.exec(`RELEASE SAVEPOINT ${savepointName}`);throw error}}const release=await acquireTransactionLock(db);try{const heldLocks=new Map(heldLockContext.getStore()??[]);heldLocks.set(db,(heldLocks.get(db)??0)+1);return await heldLockContext.run(heldLocks,async()=>{db.exec(beginStatement);try{const result=await operation();db.exec("COMMIT");return result}catch(error){db.exec("ROLLBACK");throw error}})}finally{release()}}function toConversationCompactionTelemetryRecord(row){return{conversationId:row.conversation_id,lastObservedCacheRead:row.last_observed_cache_read,lastObservedCacheWrite:row.last_observed_cache_write,lastObservedCacheHitAt:parseUtcTimestampOrNull(row.last_observed_cache_hit_at),lastObservedCacheBreakAt:parseUtcTimestampOrNull(row.last_observed_cache_break_at),cacheState:row.cache_state,consecutiveColdObservations:row.consecutive_cold_observations??0,retention:row.retention,lastLeafCompactionAt:parseUtcTimestampOrNull(row.last_leaf_compaction_at),turnsSinceLeafCompaction:row.turns_since_leaf_compaction??0,tokensAccumulatedSinceLeafCompaction:row.tokens_accumulated_since_leaf_compaction??0,lastActivityBand:row.last_activity_band??"low",lastApiCallAt:parseUtcTimestampOrNull(row.last_api_call_at),lastCacheTouchAt:parseUtcTimestampOrNull(row.last_cache_touch_at),provider:row.provider,model:row.model,updatedAt:parseUtcTimestampOrNull(row.updated_at)??new Date(0)}}var CompactionTelemetryStore=class{constructor(db){this.db=db}db;withTransaction(fn){return withDatabaseTransaction(this.db,"BEGIN",fn)}async getConversationCompactionTelemetry(conversationId){const row=this.db.prepare(`SELECT
|
|
301
326
|
conversation_id,
|
|
302
327
|
last_observed_cache_read,
|
|
303
328
|
last_observed_cache_write,
|
|
304
329
|
last_observed_cache_hit_at,
|
|
305
330
|
last_observed_cache_break_at,
|
|
306
331
|
cache_state,
|
|
332
|
+
consecutive_cold_observations,
|
|
307
333
|
retention,
|
|
308
334
|
last_leaf_compaction_at,
|
|
309
335
|
turns_since_leaf_compaction,
|
|
310
336
|
tokens_accumulated_since_leaf_compaction,
|
|
311
337
|
last_activity_band,
|
|
338
|
+
last_api_call_at,
|
|
339
|
+
last_cache_touch_at,
|
|
340
|
+
provider,
|
|
341
|
+
model,
|
|
312
342
|
updated_at
|
|
313
343
|
FROM conversation_compaction_telemetry
|
|
314
344
|
WHERE conversation_id = ?`).get(conversationId);return row?toConversationCompactionTelemetryRecord(row):null}async upsertConversationCompactionTelemetry(input){this.db.prepare(`INSERT INTO conversation_compaction_telemetry (
|
|
@@ -318,27 +348,73 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
318
348
|
last_observed_cache_hit_at,
|
|
319
349
|
last_observed_cache_break_at,
|
|
320
350
|
cache_state,
|
|
351
|
+
consecutive_cold_observations,
|
|
321
352
|
retention,
|
|
322
353
|
last_leaf_compaction_at,
|
|
323
354
|
turns_since_leaf_compaction,
|
|
324
355
|
tokens_accumulated_since_leaf_compaction,
|
|
325
356
|
last_activity_band,
|
|
357
|
+
last_api_call_at,
|
|
358
|
+
last_cache_touch_at,
|
|
359
|
+
provider,
|
|
360
|
+
model,
|
|
326
361
|
updated_at
|
|
327
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
362
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
328
363
|
ON CONFLICT(conversation_id) DO UPDATE SET
|
|
329
364
|
last_observed_cache_read = excluded.last_observed_cache_read,
|
|
330
365
|
last_observed_cache_write = excluded.last_observed_cache_write,
|
|
331
366
|
last_observed_cache_hit_at = excluded.last_observed_cache_hit_at,
|
|
332
367
|
last_observed_cache_break_at = excluded.last_observed_cache_break_at,
|
|
333
368
|
cache_state = excluded.cache_state,
|
|
369
|
+
consecutive_cold_observations = excluded.consecutive_cold_observations,
|
|
334
370
|
retention = excluded.retention,
|
|
335
371
|
last_leaf_compaction_at = excluded.last_leaf_compaction_at,
|
|
336
372
|
turns_since_leaf_compaction = excluded.turns_since_leaf_compaction,
|
|
337
373
|
tokens_accumulated_since_leaf_compaction = excluded.tokens_accumulated_since_leaf_compaction,
|
|
338
374
|
last_activity_band = excluded.last_activity_band,
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
375
|
+
last_api_call_at = excluded.last_api_call_at,
|
|
376
|
+
last_cache_touch_at = excluded.last_cache_touch_at,
|
|
377
|
+
provider = excluded.provider,
|
|
378
|
+
model = excluded.model,
|
|
379
|
+
updated_at = datetime('now')`).run(input.conversationId,input.lastObservedCacheRead??null,input.lastObservedCacheWrite??null,input.lastObservedCacheHitAt?.toISOString()??null,input.lastObservedCacheBreakAt?.toISOString()??null,input.cacheState,input.consecutiveColdObservations??0,input.retention??null,input.lastLeafCompactionAt?.toISOString()??null,input.turnsSinceLeafCompaction??0,input.tokensAccumulatedSinceLeafCompaction??0,input.lastActivityBand??"low",input.lastApiCallAt?.toISOString()??null,input.lastCacheTouchAt?.toISOString()??null,input.provider??null,input.model??null)}};function toMaintenanceRecord(row){return{conversationId:row.conversation_id,pending:row.pending===1,requestedAt:parseUtcTimestampOrNull(row.requested_at),reason:row.reason,running:row.running===1,lastStartedAt:parseUtcTimestampOrNull(row.last_started_at),lastFinishedAt:parseUtcTimestampOrNull(row.last_finished_at),lastFailureSummary:row.last_failure_summary,tokenBudget:row.token_budget,currentTokenCount:row.current_token_count,updatedAt:parseUtcTimestampOrNull(row.updated_at)??new Date(0)}}function mergeMaintenanceRecord(conversationId,existing,patch){return{conversationId,pending:patch.pending!==void 0?patch.pending:existing?.pending??false,requestedAt:patch.requestedAt!==void 0?patch.requestedAt:existing?.requestedAt??null,reason:patch.reason!==void 0?patch.reason:existing?.reason??null,running:patch.running!==void 0?patch.running:existing?.running??false,lastStartedAt:patch.lastStartedAt!==void 0?patch.lastStartedAt:existing?.lastStartedAt??null,lastFinishedAt:patch.lastFinishedAt!==void 0?patch.lastFinishedAt:existing?.lastFinishedAt??null,lastFailureSummary:patch.lastFailureSummary!==void 0?patch.lastFailureSummary:existing?.lastFailureSummary??null,tokenBudget:patch.tokenBudget!==void 0?patch.tokenBudget:existing?.tokenBudget??null,currentTokenCount:patch.currentTokenCount!==void 0?patch.currentTokenCount:existing?.currentTokenCount??null,updatedAt:new Date}}var CompactionMaintenanceStore=class{constructor(db){this.db=db}db;withTransaction(fn){return withDatabaseTransaction(this.db,"BEGIN",fn)}async getConversationCompactionMaintenance(conversationId){const row=this.db.prepare(`SELECT
|
|
380
|
+
conversation_id,
|
|
381
|
+
pending,
|
|
382
|
+
requested_at,
|
|
383
|
+
reason,
|
|
384
|
+
running,
|
|
385
|
+
last_started_at,
|
|
386
|
+
last_finished_at,
|
|
387
|
+
last_failure_summary,
|
|
388
|
+
token_budget,
|
|
389
|
+
current_token_count,
|
|
390
|
+
updated_at
|
|
391
|
+
FROM conversation_compaction_maintenance
|
|
392
|
+
WHERE conversation_id = ?`).get(conversationId);return row?toMaintenanceRecord(row):null}async saveConversationCompactionMaintenance(record){this.db.prepare(`INSERT INTO conversation_compaction_maintenance (
|
|
393
|
+
conversation_id,
|
|
394
|
+
pending,
|
|
395
|
+
requested_at,
|
|
396
|
+
reason,
|
|
397
|
+
running,
|
|
398
|
+
last_started_at,
|
|
399
|
+
last_finished_at,
|
|
400
|
+
last_failure_summary,
|
|
401
|
+
token_budget,
|
|
402
|
+
current_token_count,
|
|
403
|
+
updated_at
|
|
404
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
405
|
+
ON CONFLICT(conversation_id) DO UPDATE SET
|
|
406
|
+
pending = excluded.pending,
|
|
407
|
+
requested_at = excluded.requested_at,
|
|
408
|
+
reason = excluded.reason,
|
|
409
|
+
running = excluded.running,
|
|
410
|
+
last_started_at = excluded.last_started_at,
|
|
411
|
+
last_finished_at = excluded.last_finished_at,
|
|
412
|
+
last_failure_summary = excluded.last_failure_summary,
|
|
413
|
+
token_budget = excluded.token_budget,
|
|
414
|
+
current_token_count = excluded.current_token_count,
|
|
415
|
+
updated_at = datetime('now')`).run(record.conversationId,record.pending?1:0,record.requestedAt?.toISOString()??null,record.reason??null,record.running?1:0,record.lastStartedAt?.toISOString()??null,record.lastFinishedAt?.toISOString()??null,record.lastFailureSummary??null,record.tokenBudget??null,record.currentTokenCount??null)}async requestProactiveCompactionDebt(input){const existing=await this.getConversationCompactionMaintenance(input.conversationId);await this.saveConversationCompactionMaintenance(mergeMaintenanceRecord(input.conversationId,existing,{pending:true,requestedAt:input.requestedAt??new Date,reason:input.reason,running:false,tokenBudget:input.tokenBudget??existing?.tokenBudget??null,currentTokenCount:input.currentTokenCount??existing?.currentTokenCount??null}))}async markProactiveCompactionRunning(input){const existing=await this.getConversationCompactionMaintenance(input.conversationId);await this.saveConversationCompactionMaintenance(mergeMaintenanceRecord(input.conversationId,existing,{pending:false,running:true,lastStartedAt:input.startedAt??new Date}))}async markProactiveCompactionFinished(input){const existing=await this.getConversationCompactionMaintenance(input.conversationId);const finishedAt=input.finishedAt??new Date;const isFailure=input.failureSummary!=null;await this.saveConversationCompactionMaintenance(mergeMaintenanceRecord(input.conversationId,existing,{pending:input.keepPending??isFailure,running:false,lastFinishedAt:finishedAt,lastFailureSummary:input.failureSummary===void 0?existing?.lastFailureSummary??null:input.failureSummary}))}};import{randomUUID}from"node:crypto";function sanitizeFts5Query(raw){const parts=[];const phraseRegex=/"([^"]+)"/g;let match;let lastIndex=0;while((match=phraseRegex.exec(raw))!==null){const before=raw.slice(lastIndex,match.index);for(const t of before.split(/\s+/).filter(Boolean)){parts.push(`"${t.replace(/"/g,"")}"`)}const phrase=match[1].replace(/"/g,"").trim();if(phrase){parts.push(`"${phrase}"`)}lastIndex=match.index+match[0].length}for(const t of raw.slice(lastIndex).split(/\s+/).filter(Boolean)){parts.push(`"${t.replace(/"/g,"")}"`)}return parts.length>0?parts.join(" "):'""'}var RAW_TERM_RE=/"([^"]+)"|(\S+)/g;var CJK_RE=/[\u2E80-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\uAC00-\uD7AF\u3040-\u309F\u30A0-\u30FF]/;function containsCjk(text){return CJK_RE.test(text)}var EDGE_PUNCTUATION_RE=/^[`'"()[\]{}<>.,:;!?*_+=|\\/-]+|[`'"()[\]{}<>.,:;!?*_+=|\\/-]+$/g;function normalizeFallbackTerm(raw){return raw.trim().replace(EDGE_PUNCTUATION_RE,"").toLowerCase()}function escapeLike(term){return term.replace(/([\\%_])/g,"\\$1")}function buildLikeSearchPlan(column,query){const terms=[];for(const match of query.matchAll(RAW_TERM_RE)){const raw=match[1]??match[2]??"";const normalized=normalizeFallbackTerm(raw);if(normalized.length>0&&!terms.includes(normalized)){terms.push(normalized)}}if(terms.length===0){const fallback=normalizeFallbackTerm(query);if(fallback.length>0){terms.push(fallback)}}return{terms,where:terms.map(()=>`LOWER(${column}) LIKE ? ESCAPE '\\'`),args:terms.map(term=>`%${escapeLike(term)}%`)}}function createFallbackSnippet(content,terms){const haystack=content.toLowerCase();let matchIndex=-1;let matchLength=0;for(const term of terms){const idx=haystack.indexOf(term);if(idx!==-1&&(matchIndex===-1||idx<matchIndex)){matchIndex=idx;matchLength=term.length}}if(matchIndex===-1){const head=content.trim();return head.length<=80?head:`${head.slice(0,77).trimEnd()}...`}const start=Math.max(0,matchIndex-24);const end=Math.min(content.length,matchIndex+Math.max(matchLength,1)+40);const prefix=start>0?"...":"";const suffix=end<content.length?"...":"";return`${prefix}${content.slice(start,end).trim()}${suffix}`}var AGE_DECAY_RATE=.001;function buildFtsOrderBy(sort,createdAtExpr){switch(sort??"recency"){case"relevance":return`rank ASC, ${createdAtExpr} DESC`;case"hybrid":return`(rank / (1 + ((julianday('now') - julianday(${createdAtExpr})) * 24 * ${AGE_DECAY_RATE}))) ASC, ${createdAtExpr} DESC`;default:return`${createdAtExpr} DESC`}}function toConversationRecord(row){return{conversationId:row.conversation_id,sessionId:row.session_id,sessionKey:row.session_key??null,active:row.active===1,archivedAt:parseUtcTimestampOrNull(row.archived_at),title:row.title,bootstrappedAt:parseUtcTimestampOrNull(row.bootstrapped_at),createdAt:parseUtcTimestamp(row.created_at),updatedAt:parseUtcTimestamp(row.updated_at)}}function toMessageRecord(row){return{messageId:row.message_id,conversationId:row.conversation_id,seq:row.seq,role:row.role,content:row.content,tokenCount:row.token_count,createdAt:parseUtcTimestamp(row.created_at)}}function toSearchResult(row){return{messageId:row.message_id,conversationId:row.conversation_id,role:row.role,snippet:row.snippet,createdAt:parseUtcTimestamp(row.created_at),rank:row.rank}}function toMessagePartRecord(row){return{partId:row.part_id,messageId:row.message_id,sessionId:row.session_id,partType:row.part_type,ordinal:row.ordinal,textContent:row.text_content,toolCallId:row.tool_call_id,toolName:row.tool_name,toolInput:row.tool_input,toolOutput:row.tool_output,metadata:row.metadata}}function normalizeMessageContentForFullTextIndex(content){const trimmed=content.trim();if(!trimmed){return null}const isExternalizedReference=trimmed.startsWith("[LCM File:")||trimmed.startsWith("[LCM Tool Output:");if(!isExternalizedReference){return content}const lines=trimmed.split(/\r?\n/).map(line=>line.trim()).filter(line=>line.length>0);if(lines.length===0){return null}const header=lines[0]??"";const summaryLines=[];let inSummary=false;for(let index=1;index<lines.length;index+=1){const line=lines[index];if(line==="Exploration Summary:"){inSummary=true;continue}if(line.startsWith("Use lcm_describe")){continue}if(inSummary){summaryLines.push(line)}}const normalized=[header,...summaryLines].filter(line=>line.length>0).join("\n");return normalized||null}var ConversationStore=class{constructor(db,options){this.db=db;this.fts5Available=options?.fts5Available??true}db;fts5Available;async withTransaction(operation){return withDatabaseTransaction(this.db,"BEGIN IMMEDIATE",operation)}async createConversation(input){try{const result=this.db.prepare(`INSERT INTO conversations (session_id, session_key, active, archived_at, title)
|
|
416
|
+
VALUES (?, ?, ?, ?, ?)`).run(input.sessionId,input.sessionKey??null,input.active===false?0:1,input.archivedAt?.toISOString()??null,input.title??null);const row=this.db.prepare(`SELECT conversation_id, session_id, session_key, active, archived_at, title, bootstrapped_at, created_at, updated_at
|
|
417
|
+
FROM conversations WHERE conversation_id = ?`).get(Number(result.lastInsertRowid));return toConversationRecord(row)}catch(err){if(err instanceof Error&&/UNIQUE constraint failed|SQLITE_CONSTRAINT_UNIQUE/i.test(err.message)){if(input.sessionKey){const existing2=await this.getConversationBySessionKey(input.sessionKey);if(existing2)return existing2}const existing=await this.getConversationBySessionId(input.sessionId);if(existing)return existing}throw err}}async getConversation(conversationId){const row=this.db.prepare(`SELECT conversation_id, session_id, session_key, active, archived_at, title, bootstrapped_at, created_at, updated_at
|
|
342
418
|
FROM conversations WHERE conversation_id = ?`).get(conversationId);return row?toConversationRecord(row):null}async getConversationBySessionId(sessionId){const row=this.db.prepare(`SELECT conversation_id, session_id, session_key, active, archived_at, title, bootstrapped_at, created_at, updated_at
|
|
343
419
|
FROM conversations
|
|
344
420
|
WHERE session_id = ?
|
|
@@ -355,11 +431,11 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
355
431
|
SET active = 0,
|
|
356
432
|
archived_at = COALESCE(archived_at, datetime('now')),
|
|
357
433
|
updated_at = datetime('now')
|
|
358
|
-
WHERE conversation_id = ?`).run(conversationId)}async createMessage(input){const result=this.db.prepare(`INSERT INTO messages (conversation_id, seq, role, content, token_count)
|
|
359
|
-
VALUES (?, ?, ?, ?, ?)`).run(input.conversationId,input.seq,input.role,input.content,input.tokenCount);const messageId=Number(result.lastInsertRowid);this.indexMessageForFullText(messageId,input.content);const row=this.db.prepare(`SELECT message_id, conversation_id, seq, role, content, token_count, created_at
|
|
360
|
-
FROM messages WHERE message_id = ?`).get(messageId);return toMessageRecord(row)}async createMessagesBulk(inputs){if(inputs.length===0){return[]}const insertStmt=this.db.prepare(`INSERT INTO messages (conversation_id, seq, role, content, token_count)
|
|
361
|
-
VALUES (?, ?, ?, ?, ?)`);const selectStmt=this.db.prepare(`SELECT message_id, conversation_id, seq, role, content, token_count, created_at
|
|
362
|
-
FROM messages WHERE message_id = ?`);const records=[];for(const input of inputs){const result=insertStmt.run(input.conversationId,input.seq,input.role,input.content,input.tokenCount);const messageId=Number(result.lastInsertRowid);this.indexMessageForFullText(messageId,input.content);const row=selectStmt.get(messageId);records.push(toMessageRecord(row))}return records}async getMessages(conversationId,opts){const afterSeq=opts?.afterSeq??-1;const limit=opts?.limit;if(limit!=null){const rows2=this.db.prepare(`SELECT message_id, conversation_id, seq, role, content, token_count, created_at
|
|
434
|
+
WHERE conversation_id = ?`).run(conversationId)}async createMessage(input){const result=this.db.prepare(`INSERT INTO messages (conversation_id, seq, role, content, token_count, identity_hash)
|
|
435
|
+
VALUES (?, ?, ?, ?, ?, ?)`).run(input.conversationId,input.seq,input.role,input.content,input.tokenCount,input.identityHash??buildMessageIdentityHash(input.role,input.content));const messageId=Number(result.lastInsertRowid);this.indexMessageForFullText(messageId,input.content);const row=this.db.prepare(`SELECT message_id, conversation_id, seq, role, content, token_count, created_at
|
|
436
|
+
FROM messages WHERE message_id = ?`).get(messageId);return toMessageRecord(row)}async createMessagesBulk(inputs){if(inputs.length===0){return[]}const insertStmt=this.db.prepare(`INSERT INTO messages (conversation_id, seq, role, content, token_count, identity_hash)
|
|
437
|
+
VALUES (?, ?, ?, ?, ?, ?)`);const selectStmt=this.db.prepare(`SELECT message_id, conversation_id, seq, role, content, token_count, created_at
|
|
438
|
+
FROM messages WHERE message_id = ?`);const records=[];for(const input of inputs){const result=insertStmt.run(input.conversationId,input.seq,input.role,input.content,input.tokenCount,input.identityHash??buildMessageIdentityHash(input.role,input.content));const messageId=Number(result.lastInsertRowid);this.indexMessageForFullText(messageId,input.content);const row=selectStmt.get(messageId);records.push(toMessageRecord(row))}return records}async getMessages(conversationId,opts){const afterSeq=opts?.afterSeq??-1;const limit=opts?.limit;if(limit!=null){const rows2=this.db.prepare(`SELECT message_id, conversation_id, seq, role, content, token_count, created_at
|
|
363
439
|
FROM messages
|
|
364
440
|
WHERE conversation_id = ? AND seq > ?
|
|
365
441
|
ORDER BY seq
|
|
@@ -370,12 +446,12 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
370
446
|
FROM messages
|
|
371
447
|
WHERE conversation_id = ?
|
|
372
448
|
ORDER BY seq DESC
|
|
373
|
-
LIMIT 1`).get(conversationId);return row?toMessageRecord(row):null}async hasMessage(conversationId,role,content){const row=this.db.prepare(`SELECT 1 AS count
|
|
449
|
+
LIMIT 1`).get(conversationId);return row?toMessageRecord(row):null}async hasMessage(conversationId,role,content){const identityHash=buildMessageIdentityHash(role,content);const row=this.db.prepare(`SELECT 1 AS count
|
|
374
450
|
FROM messages
|
|
375
|
-
WHERE conversation_id = ? AND role = ? AND content = ?
|
|
376
|
-
LIMIT 1`).get(conversationId,role,content);return row?.count===1}async countMessagesByIdentity(conversationId,role,content){const row=this.db.prepare(`SELECT COUNT(*) AS count
|
|
451
|
+
WHERE conversation_id = ? AND identity_hash = ? AND role = ? AND content = ?
|
|
452
|
+
LIMIT 1`).get(conversationId,identityHash,role,content);return row?.count===1}async countMessagesByIdentity(conversationId,role,content){const identityHash=buildMessageIdentityHash(role,content);const row=this.db.prepare(`SELECT COUNT(*) AS count
|
|
377
453
|
FROM messages
|
|
378
|
-
WHERE conversation_id = ? AND role = ? AND content = ?`).get(conversationId,role,content);return row?.count??0}async getMessageById(messageId){const row=this.db.prepare(`SELECT message_id, conversation_id, seq, role, content, token_count, created_at
|
|
454
|
+
WHERE conversation_id = ? AND identity_hash = ? AND role = ? AND content = ?`).get(conversationId,identityHash,role,content);return row?.count??0}async getMessageById(messageId){const row=this.db.prepare(`SELECT message_id, conversation_id, seq, role, content, token_count, created_at
|
|
379
455
|
FROM messages WHERE message_id = ?`).get(messageId);return row?toMessageRecord(row):null}async createMessageParts(messageId,parts){if(parts.length===0){return}const stmt=this.db.prepare(`INSERT INTO message_parts (
|
|
380
456
|
part_id,
|
|
381
457
|
message_id,
|
|
@@ -421,7 +497,7 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
421
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
|
|
422
498
|
FROM messages
|
|
423
499
|
${whereClause}
|
|
424
|
-
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 (
|
|
425
501
|
summary_id,
|
|
426
502
|
conversation_id,
|
|
427
503
|
kind,
|
|
@@ -592,46 +668,49 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
592
668
|
JOIN summaries s ON s.summary_id = ci.summary_id
|
|
593
669
|
WHERE ci.conversation_id = ?
|
|
594
670
|
AND ci.item_type = 'summary'
|
|
595
|
-
) 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
|
|
596
672
|
summaries_fts.summary_id,
|
|
597
673
|
s.conversation_id,
|
|
598
674
|
s.kind,
|
|
599
675
|
snippet(summaries_fts, 1, '', '', '...', 32) AS snippet,
|
|
600
676
|
rank,
|
|
601
|
-
|
|
677
|
+
${SUMMARY_SEARCH_TIME_EXPR} AS created_at
|
|
602
678
|
FROM summaries_fts
|
|
603
679
|
JOIN summaries s ON s.summary_id = summaries_fts.summary_id
|
|
604
680
|
WHERE ${where.join(" AND ")}
|
|
605
681
|
ORDER BY ${orderBy}
|
|
606
|
-
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,
|
|
607
683
|
earliest_at, latest_at, descendant_count, descendant_token_count,
|
|
608
|
-
source_message_token_count, model,
|
|
684
|
+
source_message_token_count, model,
|
|
685
|
+
${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED} AS created_at
|
|
609
686
|
FROM summaries
|
|
610
687
|
${whereClause}
|
|
611
|
-
ORDER BY
|
|
612
|
-
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
|
|
613
690
|
f.summary_id,
|
|
614
691
|
s.conversation_id,
|
|
615
692
|
s.kind,
|
|
616
693
|
snippet(summaries_fts_cjk, 1, '', '', '...', 32) AS snippet,
|
|
617
694
|
rank,
|
|
618
|
-
|
|
695
|
+
${SUMMARY_SEARCH_TIME_EXPR} AS created_at
|
|
619
696
|
FROM summaries_fts_cjk f
|
|
620
697
|
JOIN summaries s ON s.summary_id = f.summary_id
|
|
621
698
|
WHERE ${where.join(" AND ")}
|
|
622
|
-
ORDER BY
|
|
623
|
-
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,
|
|
624
701
|
earliest_at, latest_at, descendant_count, descendant_token_count,
|
|
625
|
-
source_message_token_count, model,
|
|
702
|
+
source_message_token_count, model,
|
|
703
|
+
${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED} AS created_at
|
|
626
704
|
FROM summaries
|
|
627
705
|
WHERE ${where.join(" AND ")}
|
|
628
|
-
ORDER BY
|
|
629
|
-
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,
|
|
630
708
|
earliest_at, latest_at, descendant_count, descendant_token_count,
|
|
631
|
-
source_message_token_count, model,
|
|
709
|
+
source_message_token_count, model,
|
|
710
|
+
${SUMMARY_SEARCH_TIME_EXPR_UNQUALIFIED} AS created_at
|
|
632
711
|
FROM summaries
|
|
633
712
|
${whereClause}
|
|
634
|
-
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)
|
|
635
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
|
|
636
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
|
|
637
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
|
|
@@ -658,10 +737,12 @@ ${summary.content}`}).join("\n\n");const fileIds=dedupeOrderedIds(summaryRecords
|
|
|
658
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,
|
|
659
738
|
last_processed_offset, last_processed_entry_hash, updated_at
|
|
660
739
|
FROM conversation_bootstrap_state
|
|
661
|
-
WHERE conversation_id = ?`).get(input.conversationId);return toConversationBootstrapStateRecord(row)}};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 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}
|
|
662
|
-
${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
|
|
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}
|
|
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}
|
|
663
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}
|
|
664
|
-
`;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}function readFileSegment(sessionFile,offset){let fd=null;try{fd=openSync(sessionFile,"r");const stats=statSync(sessionFile);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);readSync(fd,buffer,0,length,safeOffset);return buffer.toString("utf8")}catch{return null}finally{if(fd!=null){closeSync(fd)}}}function readLastJsonlEntryBeforeOffset(sessionFile,offset,messageOnly=false,matcher){const chunkSize=16384;let fd=null;try{const safeOffset=Math.max(0,Math.floor(offset));if(safeOffset<=0){return null}fd=openSync(sessionFile,"r");let cursor=safeOffset;let carry="";let reachedStart=false;while(cursor>0||reachedStart&&carry.length>0){if(!reachedStart){const start=Math.max(0,cursor-chunkSize);const length=cursor-start;const buffer=Buffer.alloc(length);readSync(fd,buffer,0,length,start);carry=buffer.toString("utf8")+carry;cursor=start;if(start===0){reachedStart=true}}const trimmedEnd=carry.replace(/\s+$/u,"");if(!trimmedEnd){if(reachedStart)break;carry="";continue}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(reachedStart){const firstLine=trimmedEnd.trim()||null;if(firstLine&&messageOnly){let matchedMessage=null;try{matchedMessage=extractBootstrapMessageCandidate(JSON.parse(firstLine))}catch{}if(!matchedMessage||matcher&&!matcher(matchedMessage))return null}return firstLine}continue}return null}catch{return null}finally{if(fd!=null){closeSync(fd)}}}function readAppendedLeafPathMessages(params){const raw=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{info;config;get timezone(){return this.config.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone}conversationStore;summaryStore;compactionTelemetryStore;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:"lcm",name:"Lossless Context Management Engine",version:"0.1.0",ownsCompaction:migrationOk};this.conversationStore=new ConversationStore(this.db,{fts5Available:this.fts5Available});this.summaryStore=new SummaryStore(this.db,{fts5Available:this.fts5Available});this.compactionTelemetryStore=new CompactionTelemetryStore(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"}return telemetry.cacheState}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);if(!promptCache){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 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}}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 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",retention:snapshot?.retention??existing?.retention??null,lastLeafCompactionAt:existing?.lastLeafCompactionAt??null,turnsSinceLeafCompaction,tokensAccumulatedSinceLeafCompaction,lastActivityBand});const updated=await this.compactionTelemetryStore.getConversationCompactionTelemetry(params.conversationId);if(updated){this.deps.log.debug(`[lcm] compaction telemetry updated: conversation=${params.conversationId} cacheState=${updated.cacheState} cacheRead=${updated.lastObservedCacheRead??"null"} cacheWrite=${updated.lastObservedCacheWrite??"null"} retention=${updated.retention??"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",retention:existing?.retention??null,lastLeafCompactionAt:new Date,turnsSinceLeafCompaction:0,tokensAccumulatedSinceLeafCompaction:0,lastActivityBand:params.activityBand??existing?.lastActivityBand??"low"});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,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 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}}async storeLargeFileContent(params){const dir=join2(this.config.largeFilesDir,String(params.conversationId));await mkdir(dir,{recursive:true});const normalizedExtension=params.extension.replace(/[^a-z0-9]/gi,"").toLowerCase()||"txt";const filePath=join2(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(!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"||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??statSync(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=statSync(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=existingCount>0?await this.summaryStore.getConversationBootstrapState(conversationId):null;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(existingCount>0&&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 tailEntryRaw=readLastJsonlEntryBeforeOffset(params.sessionFile,bootstrapState.lastProcessedOffset,true,message=>createBootstrapEntryHash(toStoredMessage(message))===latestDbHash);const tailEntryMessage=readBootstrapMessageFromJsonLine(tailEntryRaw);const tailEntryHash=tailEntryMessage?createBootstrapEntryHash(toStoredMessage(tailEntryMessage)):null;if(latestDbHash&&latestDbHash===bootstrapState.lastProcessedEntryHash&&tailEntryHash&&tailEntryHash===bootstrapState.lastProcessedEntryHash){const appended=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"}}if(!this.config.transcriptGcEnabled){return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"transcript GC disabled"}}if(typeof params.runtimeContext?.rewriteTranscriptEntries!=="function"){return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"runtime rewrite helper unavailable"}}const rewriteTranscriptEntries=params.runtimeContext.rewriteTranscriptEntries;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"}}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{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{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)}`)}}this.deps.log.info(`[lcm] maintain: done conversation=${conversation.conversationId} ${sessionLabel} candidates=${candidates.length} replacements=${replacements.length} changed=${result.changed} rewrittenEntries=${result.rewrittenEntries} bytesFreed=${result.bytesFreed} duration=${formatDurationMs(Date.now()-startedAt)}`);return result},{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}}}}const stored=toStoredMessage(message);const conversation=await this.conversationStore.getOrCreateConversation(sessionId,{sessionKey});const conversationId=conversation.conversationId;let messageForParts=message;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});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 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}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)}`)}try{const rawLeafTrigger=await this.compaction.evaluateLeafTrigger(conversation.conversationId);await this.updateCompactionTelemetry({conversationId:conversation.conversationId,runtimeContext:asRecord(params.runtimeContext),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});if(leafDecision.shouldCompact){this.compactLeafAsync({sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile,tokenBudget,currentTokenCount:liveContextTokens,legacyParams,maxPasses:leafDecision.maxPasses,leafChunkTokens:leafDecision.leafChunkTokens,fallbackLeafChunkTokens:leafDecision.fallbackLeafChunkTokens,activityBand:leafDecision.activityBand,allowCondensedPasses:leafDecision.allowCondensedPasses}).catch(()=>{})}}catch{}try{await this.compact({sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile,tokenBudget,currentTokenCount:liveContextTokens,compactionTarget:"threshold",legacyParams})}catch{}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 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 tokenBudget=this.applyAssemblyBudgetCap(typeof params.tokenBudget==="number"&&Number.isFinite(params.tokenBudget)&¶ms.tokenBudget>0?Math.floor(params.tokenBudget):128e3);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 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"}}const lp=legacyParams??{};const observedTokens=this.normalizeObservedTokenCount(params.currentTokenCount??lp.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(conversation.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=${conversation.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:conversation.conversationId,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:conversation.conversationId,activityBand:params.activityBand})}const tokensBefore=observedTokens??storedTokensBefore;this.deps.log.debug(`[lcm] compactLeafAsync result: conversation=${conversation.conversationId} session=${params.sessionId} rounds=${rounds} compacted=${rounds>0} authFailure=${authFailure} finalLeafChunkTokens=${activeLeafChunkTokens??"null"} finalTokens=${finalTokens}`);return{ok:true,compacted:rounds>0,reason:authFailure?"provider auth failure":rounds>0?"compacted":"below threshold",result:{tokensBefore,tokensAfter:finalTokens,details:{rounds,targetTokens:tokenBudget,mode:"leaf",maxPasses}}}})}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{sessionId,force=false}=params;const conversation=await this.conversationStore.getConversationForSession({sessionId,sessionKey:params.sessionKey});if(!conversation){return{ok:true,compacted:false,reason:"no conversation found for session"}}const conversationId=conversation.conversationId;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 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 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})}))}getRetrieval(){return this.retrieval}getConversationStore(){return this.conversationStore}getSummaryStore(){return this.summaryStore}getCompactionTelemetryStore(){return this.compactionTelemetryStore}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{statSync as statSync2}from"node:fs";var package_default={name:"@martian-engineering/lossless-claw",version:"0.8.2",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
|
+
`;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}
|
|
744
|
+
|
|
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
|
|
665
746
|
s.conversation_id,
|
|
666
747
|
s.summary_id,
|
|
667
748
|
s.kind,
|
|
@@ -748,7 +829,7 @@ ${content}`:content}).filter(value=>typeof value==="string");if(parts.length===0
|
|
|
748
829
|
AND COALESCE(depth, 0) = ?
|
|
749
830
|
AND (created_at < ? OR (created_at = ? AND summary_id < ?))
|
|
750
831
|
ORDER BY created_at DESC, summary_id DESC
|
|
751
|
-
LIMIT 1`).get(params.target.conversationId,params.target.depth,params.target.createdAt,params.target.createdAt,params.target.summaryId);return resolveSummaryContent(params.db,previousRow?.summary_id,params.overrides)}function resolveSummaryContent(db,summaryId,overrides){if(!summaryId){return void 0}const override=overrides.get(summaryId);if(override?.content.trim()){return override.content.trim()}const row=db.prepare(`SELECT COALESCE(content, '') AS content FROM summaries WHERE summary_id = ?`).get(summaryId);const content=row?.content.trim();return content?content:void 0}function resolveSummaryTimeRange(params){const earliestAt=parseSqliteTimestamp(params.earliestAt)??parseSqliteTimestamp(params.createdAt);const latestAt=parseSqliteTimestamp(params.latestAt)??parseSqliteTimestamp(params.createdAt);return{earliestAt,latestAt}}function formatSummaryTimeRange(range,timezone){if(!range.earliestAt||!range.latestAt){return""}return`[${formatTimestamp(range.earliestAt,timezone)} - ${formatTimestamp(range.latestAt,timezone)}]`}function formatSqliteTimestamp(value,timezone){const date=parseSqliteTimestamp(value);if(date){return formatTimestamp(date,timezone)}const fallback=value.trim();return fallback||"unknown"}function parseSqliteTimestamp(value){const normalized=value?.trim();if(!normalized){return null}const direct=new Date(normalized);if(!Number.isNaN(direct.getTime())){return direct}const sqlite=new Date(normalized.replace(" ","T")+"Z");if(!Number.isNaN(sqlite.getTime())){return sqlite}return null}function updateSummaryFts(db,summaryId,content){try{const update=db.prepare(`UPDATE summaries_fts SET content = ? WHERE summary_id = ?`).run(content,summaryId);if(Number(update.changes??0)===0){db.prepare(`INSERT INTO summaries_fts(summary_id, content) VALUES (?, ?)`).run(summaryId,content)}}catch{}}
|
|
832
|
+
LIMIT 1`).get(params.target.conversationId,params.target.depth,params.target.createdAt,params.target.createdAt,params.target.summaryId);return resolveSummaryContent(params.db,previousRow?.summary_id,params.overrides)}function resolveSummaryContent(db,summaryId,overrides){if(!summaryId){return void 0}const override=overrides.get(summaryId);if(override?.content.trim()){return override.content.trim()}const row=db.prepare(`SELECT COALESCE(content, '') AS content FROM summaries WHERE summary_id = ?`).get(summaryId);const content=row?.content.trim();return content?content:void 0}function resolveSummaryTimeRange(params){const earliestAt=parseSqliteTimestamp(params.earliestAt)??parseSqliteTimestamp(params.createdAt);const latestAt=parseSqliteTimestamp(params.latestAt)??parseSqliteTimestamp(params.createdAt);return{earliestAt,latestAt}}function formatSummaryTimeRange(range,timezone){if(!range.earliestAt||!range.latestAt){return""}return`[${formatTimestamp(range.earliestAt,timezone)} - ${formatTimestamp(range.latestAt,timezone)}]`}function formatSqliteTimestamp(value,timezone){const date=parseSqliteTimestamp(value);if(date){return formatTimestamp(date,timezone)}const fallback=value.trim();return fallback||"unknown"}function parseSqliteTimestamp(value){const normalized=value?.trim();if(!normalized){return null}const direct=new Date(normalized);if(!Number.isNaN(direct.getTime())){return direct}const sqlite=new Date(normalized.replace(" ","T")+"Z");if(!Number.isNaN(sqlite.getTime())){return sqlite}return null}function updateSummaryFts(db,summaryId,content){try{const update=db.prepare(`UPDATE summaries_fts SET content = ? WHERE summary_id = ?`).run(content,summaryId);if(Number(update.changes??0)===0){db.prepare(`INSERT INTO summaries_fts(summary_id, content) VALUES (?, ?)`).run(summaryId,content)}}catch{}}var SCAN_FIRST_MESSAGE_PREVIEW_LIMIT=256;var CLEANER_DEFINITIONS=[{id:"archived_subagents",label:"Archived subagents",description:"Archived subagent conversations keyed as agent:main:subagent:*.",candidatePredicateSql:"(c.active = 0 AND c.session_key LIKE 'agent:main:subagent:%')",predicateSql:"(c.active = 0 AND c.session_key LIKE 'agent:main:subagent:%')"},{id:"cron_sessions",label:"Cron sessions",description:"Background cron conversations keyed as agent:main:cron:*.",candidatePredicateSql:"(c.session_key LIKE 'agent:main:cron:%')",predicateSql:"(c.session_key LIKE 'agent:main:cron:%')"},{id:"null_subagent_context",label:"NULL-key subagent context",description:"Archived conversations with NULL session_key whose first stored message begins with [Subagent Context].",candidatePredicateSql:"(c.session_key IS NULL AND c.active = 0 AND c.archived_at IS NOT NULL)",predicateSql:"(c.session_key IS NULL AND c.active = 0 AND c.archived_at IS NOT NULL AND message_stats.first_message_preview LIKE '[Subagent Context]%')",needsFirstMessage:true}];var DOCTOR_CLEANER_IDS=CLEANER_DEFINITIONS.map(definition=>definition.id);function getCleanerDefinitions(filterIds){if(!filterIds||filterIds.length===0){return CLEANER_DEFINITIONS}const requested=new Set(filterIds);return CLEANER_DEFINITIONS.filter(definition=>requested.has(definition.id))}function truncatePreview(value){if(!value){return null}const normalized=value.replace(/\s+/g," ").trim();if(!normalized){return null}return normalized.length<=120?normalized:`${normalized.slice(0,117)}...`}function buildMatchedConversationsSql(params){const{definitions,includeFilterId=true,messageStatsTableName}=params;if(definitions.length===0){return includeFilterId?`SELECT NULL AS filter_id, NULL AS conversation_id WHERE 0`:`SELECT NULL AS conversation_id WHERE 0`}return definitions.map(definition=>{const selectSql=includeFilterId?`SELECT '${definition.id}' AS filter_id, c.conversation_id`:`SELECT c.conversation_id`;const joinSql=definition.needsFirstMessage&&messageStatsTableName?`LEFT JOIN ${messageStatsTableName} message_stats ON message_stats.conversation_id = c.conversation_id`:"";return`${selectSql}
|
|
752
833
|
FROM conversations c
|
|
753
834
|
${joinSql}
|
|
754
835
|
WHERE ${definition.predicateSql}`}).join(`
|
|
@@ -923,7 +1004,7 @@ UNION
|
|
|
923
1004
|
WHERE rowid IN (SELECT message_id FROM temp.doctor_cleaner_message_ids)`).run()}if(hasSummariesFts){db.prepare(`DELETE FROM summaries_fts
|
|
924
1005
|
WHERE summary_id IN (SELECT summary_id FROM temp.doctor_cleaner_summary_ids)`).run()}if(hasSummariesFtsCjk){db.prepare(`DELETE FROM summaries_fts_cjk
|
|
925
1006
|
WHERE summary_id IN (SELECT summary_id FROM temp.doctor_cleaner_summary_ids)`).run()}return Number(db.prepare(`DELETE FROM conversations
|
|
926
|
-
WHERE conversation_id IN (SELECT conversation_id FROM temp.doctor_cleaner_conversation_ids)`).run().changes??0)}function
|
|
1007
|
+
WHERE conversation_id IN (SELECT conversation_id FROM temp.doctor_cleaner_conversation_ids)`).run().changes??0)}function getDoctorCleanerApplyUnavailableReason(databasePath){return getFileBackedDatabasePath(databasePath)?null:"Cleaner apply requires a file-backed SQLite database so Lossless Claw can create a backup first."}function buildCleanerBackupPath(databasePath){return buildLcmDatabaseBackupPath(databasePath,"doctor-cleaners")}function applyDoctorCleaners(db,options){const definitions=getCleanerDefinitions(options.filterIds);if(definitions.length===0){return{kind:"unavailable",reason:"No valid doctor cleaner filters were selected."}}const unavailableReason=getDoctorCleanerApplyUnavailableReason(options.databasePath);if(unavailableReason){return{kind:"unavailable",reason:unavailableReason}}const backupPath=buildCleanerBackupPath(options.databasePath);if(!backupPath){return{kind:"unavailable",reason:getDoctorCleanerApplyUnavailableReason(options.databasePath)??"Cleaner apply could not determine a backup path."}}writeLcmDatabaseBackup(db,backupPath);let deletedConversations=0;let deletedMessages=0;let vacuumed=false;let transactionActive=false;try{db.exec("BEGIN IMMEDIATE");transactionActive=true;stageCleanerConversationIds(db,definitions);const counts=readTempCleanerDeleteCounts(db);deletedMessages=counts.messageCount;if(counts.conversationCount>0){deletedConversations=deleteTempCleanerCandidates(db)}db.exec("COMMIT");transactionActive=false}catch(error){if(transactionActive){db.exec("ROLLBACK")}throw error}finally{dropTempCleanerTables(db)}if(options.vacuum&&deletedConversations>0){db.exec("VACUUM");db.exec("PRAGMA wal_checkpoint(TRUNCATE)");vacuumed=true}return{kind:"applied",filterIds:definitions.map(definition=>definition.id),deletedConversations,deletedMessages,vacuumed,backupPath}}var VISIBLE_COMMAND="/lossless";var HIDDEN_ALIAS="/lcm";var ROTATE_DATABASE_LOCK_TIMEOUT_MS=3e4;var DOCTOR_CLEANER_IDS2=new Set(getDoctorCleanerFilterIds());function asRecord2(value){return value&&typeof value==="object"&&!Array.isArray(value)?value:void 0}function formatBoolean(value){return value?"yes":"no"}function formatNumber(value){return new Intl.NumberFormat("en-US").format(value)}function formatBytes(bytes){if(!Number.isFinite(bytes)||bytes<0){return"unknown"}if(bytes<1024){return`${bytes} B`}const units=["KB","MB","GB","TB"];let value=bytes/1024;let unitIndex=0;while(value>=1024&&unitIndex<units.length-1){value/=1024;unitIndex+=1}const precision=value>=100?0:value>=10?1:2;return`${value.toFixed(precision)} ${units[unitIndex]}`}function formatCommand(command){return`\`${command}\``}function buildHeaderLines(){return[`**\u{1F980} Lossless Claw v${package_default.version}**`,`Help: ${formatCommand(`${VISIBLE_COMMAND} help`)} \xB7 Alias: ${formatCommand(HIDDEN_ALIAS)}`]}function buildSection(title,lines){return[`**${title}**`,...lines.map(line=>` ${line}`)].join("\n")}function buildStatLine(label,value){return`${label}: ${value}`}function formatFailureReason(error){const message=describeLogError(error).trim();return message||"Unknown error"}function formatCompressionRatio(contextTokens,compressedTokens){if(!Number.isFinite(contextTokens)||contextTokens<=0||!Number.isFinite(compressedTokens)||compressedTokens<=0){return"n/a"}const ratio=Math.max(1,Math.round(compressedTokens/contextTokens));return`1:${formatNumber(ratio)}`}function truncateMiddle(value,maxChars){if(value.length<=maxChars){return value}if(maxChars<=3){return value.slice(0,maxChars)}const head=Math.ceil((maxChars-1)/2);const tail=Math.floor((maxChars-1)/2);return`${value.slice(0,head)}\u2026${value.slice(value.length-tail)}`}function splitArgs(rawArgs){return(rawArgs??"").trim().split(/\s+/).map(token=>token.trim()).filter(Boolean)}function parseDoctorCleanerApplyArgs(tokens){let filterId;let vacuum=false;for(const token of tokens){const normalized=token.toLowerCase();if(normalized==="vacuum"){vacuum=true;continue}if(DOCTOR_CLEANER_IDS2.has(normalized)&&!filterId){filterId=normalized;continue}return{ok:false,error:`\`${VISIBLE_COMMAND} doctor clean apply\` accepts at most one filter id (\`${getDoctorCleanerFilterIds().join("`, `")}\`) plus optional \`vacuum\`.`}}return{ok:true,filterId,vacuum}}function parseLcmCommand(rawArgs){const tokens=splitArgs(rawArgs);if(tokens.length===0){return{kind:"status"}}const[head,...rest]=tokens;switch(head.toLowerCase()){case"status":return rest.length===0?{kind:"status"}:{kind:"help",error:"`/lcm status` does not accept extra arguments."};case"backup":return rest.length===0?{kind:"backup"}:{kind:"help",error:"`/lcm backup` does not accept extra arguments."};case"rotate":return rest.length===0?{kind:"rotate"}:{kind:"help",error:"`/lcm rotate` does not accept extra arguments."};case"doctor":if(rest.length===0){return{kind:"doctor",apply:false}}if(rest.length===1&&rest[0]?.toLowerCase()==="clean"){return{kind:"doctor_cleaners",apply:false,vacuum:false}}if(rest[0]?.toLowerCase()==="clean"&&rest[1]?.toLowerCase()==="apply"){const parsedApply=parseDoctorCleanerApplyArgs(rest.slice(2));return parsedApply.ok?{kind:"doctor_cleaners",apply:true,filterId:parsedApply.filterId,vacuum:parsedApply.vacuum}:{kind:"help",error:parsedApply.error}}if(rest.length===1&&rest[0]?.toLowerCase()==="apply"){return{kind:"doctor",apply:true}}return{kind:"help",error:`\`${VISIBLE_COMMAND} doctor\` accepts no arguments, \`clean\` for global high-confidence junk diagnostics, \`clean apply [filter-id] [vacuum]\` for cleanup, or \`apply\` for the scoped summary repair path.`};case"help":return{kind:"help"};default:return{kind:"help",error:`Unknown subcommand \`${head}\`. Supported: status, backup, rotate, doctor, doctor clean, doctor apply, help.`}}}function getLcmStatusStats(db){const row=db.prepare(`SELECT
|
|
927
1008
|
COALESCE((SELECT COUNT(*) FROM conversations), 0) AS conversation_count,
|
|
928
1009
|
COALESCE(COUNT(*), 0) AS summary_count,
|
|
929
1010
|
COALESCE(SUM(token_count), 0) AS stored_summary_tokens,
|
|
@@ -964,8 +1045,12 @@ UNION
|
|
|
964
1045
|
COALESCE((SELECT SUM(CASE WHEN kind = 'leaf' THEN 1 ELSE 0 END) FROM summaries WHERE conversation_id = c.conversation_id), 0) AS leaf_summary_count,
|
|
965
1046
|
COALESCE((SELECT SUM(CASE WHEN kind = 'condensed' THEN 1 ELSE 0 END) FROM summaries WHERE conversation_id = c.conversation_id), 0) AS condensed_summary_count
|
|
966
1047
|
FROM conversations c
|
|
967
|
-
WHERE c.conversation_id = ?`).get(conversationId);if(!row){return null}return{conversationId:row.conversation_id,sessionId:row.session_id,sessionKey:row.session_key,messageCount:row.message_count,summaryCount:row.summary_count,storedSummaryTokens:row.stored_summary_tokens,summarizedSourceTokens:row.summarized_source_tokens,contextTokenCount:row.context_token_count,compressedTokenCount:row.compressed_token_count,leafSummaryCount:row.leaf_summary_count,condensedSummaryCount:row.condensed_summary_count}}function normalizeIdentity(value){const normalized=value?.trim();return normalized?normalized:void 0}function getConversationStatusBySessionKey(db,sessionKey){const row=db.prepare(`SELECT conversation_id
|
|
1048
|
+
WHERE c.conversation_id = ?`).get(conversationId);if(!row){return null}return{conversationId:row.conversation_id,sessionId:row.session_id,sessionKey:row.session_key,messageCount:row.message_count,summaryCount:row.summary_count,storedSummaryTokens:row.stored_summary_tokens,summarizedSourceTokens:row.summarized_source_tokens,contextTokenCount:row.context_token_count,compressedTokenCount:row.compressed_token_count,leafSummaryCount:row.leaf_summary_count,condensedSummaryCount:row.condensed_summary_count}}function normalizeIdentity(value){const normalized=value?.trim();return normalized?normalized:void 0}function getConversationStatusBySessionKey(db,sessionKey){const row=db.prepare(`SELECT conversation_id
|
|
1049
|
+
FROM conversations
|
|
1050
|
+
WHERE session_key = ?
|
|
1051
|
+
ORDER BY active DESC, created_at DESC
|
|
1052
|
+
LIMIT 1`).get(sessionKey);if(!row){return null}return getConversationStatusStats(db,row.conversation_id)}function getConversationStatusBySessionId(db,sessionId){const row=db.prepare(`SELECT conversation_id
|
|
968
1053
|
FROM conversations
|
|
969
1054
|
WHERE session_id = ?
|
|
970
|
-
ORDER BY created_at DESC
|
|
971
|
-
LIMIT 1`).get(sessionId);if(!row){return null}return getConversationStatusStats(db,row.conversation_id)}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."}}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, and current-conversation status."),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.")])];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};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")]))}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"}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, scan broken summaries, 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"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)`});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.channel.session.resolveStorePath(cfg.session?.store,{agentId});const raw=readFileSync(storePath,"utf8");const store=JSON.parse(raw);const sessionId=store[key]?.sessionId;return typeof sessionId==="string"&&sessionId.trim()?sessionId.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}))}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})`});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};
|
|
1055
|
+
ORDER BY active DESC, created_at DESC
|
|
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};
|