@martian-engineering/lossless-claw 0.11.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1075,7 +1075,7 @@ ${externalized.reference}`,fileIds:[externalized.fileId]}}async interceptPureBas
|
|
|
1075
1075
|
OR json_extract(mp.metadata, '$.raw.toolUseId') = ?
|
|
1076
1076
|
OR json_extract(mp.metadata, '$.raw.tool_use_id') = ?
|
|
1077
1077
|
)
|
|
1078
|
-
LIMIT 1`);let matchedRawIds=0;for(const rawId of candidateRawIds){const row=matchStmt.get(params.conversationId,rawId,rawId,rawId,rawId,rawId,rawId);if(row?.found===1){matchedRawIds+=1}}return{candidateRawIds:candidateRawIds.size,matchedRawIds}}async filterBootstrapReplayMessages(params){if(params.messages.length<3){return params.messages}let replayCandidateLength=0;while(replayCandidateLength<params.messages.length&&isBootstrapReplayCandidateMessage(params.messages[replayCandidateLength])){replayCandidateLength+=1}if(replayCandidateLength<3){return params.messages}const priorMessages=params.priorMessages??(params.sessionFile?await readLeafPathMessages(params.sessionFile):void 0);if(!priorMessages||priorMessages.length===0){return params.messages}const replayCandidates=params.messages.slice(0,replayCandidateLength);const earlierReplayCandidates=(params.priorMessages?priorMessages:priorMessages.slice(0,Math.max(0,priorMessages.length-params.messages.length))).filter(isBootstrapReplayCandidateMessage);if(earlierReplayCandidates.length<3){return params.messages}const incomingSignatures=replayCandidates.map(createBootstrapReplaySignature);const earlierSignatures=earlierReplayCandidates.map(createBootstrapReplaySignature);let replayPrefixLength=0;prefixLoop:for(let candidatePrefixLength=incomingSignatures.length;candidatePrefixLength>=3;candidatePrefixLength-=1){for(let startIndex=0;startIndex<=earlierSignatures.length-candidatePrefixLength;startIndex+=1){let matched=true;for(let offset=0;offset<candidatePrefixLength;offset+=1){if(earlierSignatures[startIndex+offset]!==incomingSignatures[offset]){matched=false;break}}if(matched){replayPrefixLength=candidatePrefixLength;break prefixLoop}}}if(replayPrefixLength>0){this.deps.log.warn(`[lcm] bootstrap replay guard: ${params.source} dropped ${replayPrefixLength}/${params.messages.length} replayed transcript messages for ${params.sessionContext}`)}return replayPrefixLength>0?params.messages.slice(replayPrefixLength):params.messages}async reconcileTranscriptTailForAfterTurn(params){const queueKey=this.resolveSessionQueueKey(params.sessionId,params.sessionKey);return await this.withSessionQueue(queueKey,async()=>{const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){return{importedMessages:0,blockedByImportCap:false,hasOverlap:true}}const checkpoint=await this.summaryStore.getConversationBootstrapState(conversation.conversationId);let sessionFileState;try{const sessionFileStats=await stat(params.sessionFile);sessionFileState={size:sessionFileStats.size,mtimeMs:Math.trunc(sessionFileStats.mtimeMs)}}catch{}const transcriptEpochShrank=checkpointIsPastTranscriptEof(checkpoint,sessionFileState?.size??Number.POSITIVE_INFINITY);if(checkpoint&&checkpoint.sessionFilePath===params.sessionFile&&checkpoint.lastProcessedOffset>=0&&!transcriptEpochShrank){const appended=await readAppendedLeafPathMessages({sessionFile:params.sessionFile,offset:checkpoint.lastProcessedOffset});if(appended.canUseAppendOnly){const placeholderCheckpoint=checkpoint.lastSeenSize===0&&checkpoint.lastSeenMtimeMs===0&&checkpoint.lastProcessedOffset===0&&checkpoint.lastProcessedEntryHash===null;if(placeholderCheckpoint&&appended.messages.length>0){const reconcile2=await this.reconcileSessionTail({sessionId:params.sessionId,sessionKey:params.sessionKey,conversationId:conversation.conversationId,historicalMessages:appended.messages,noAnchorImportReason:"placeholder-checkpoint-recovery"});if(reconcile2.importedMessages>0){this.clearStableOrphanStrippingOrdinal(conversation.conversationId);this.recordRecentBootstrapImport(conversation.conversationId,reconcile2.importedMessages,"reconciled missing session messages");await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile})}return reconcile2}const replayFilteredMessages=await this.filterBootstrapReplayMessages({messages:appended.messages,sessionContext:this.formatSessionLogContext({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey}),source:"afterTurn transcript reconcile append-only",sessionFile:params.sessionFile});let importedMessages=0;for(const message of replayFilteredMessages){const result=await this.ingestSingle({sessionId:params.sessionId,sessionKey:params.sessionKey,message});if(result.ingested){importedMessages+=1}}if(importedMessages>0){this.recordRecentBootstrapImport(conversation.conversationId,importedMessages,"reconciled missing session messages");await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile})}return{importedMessages,blockedByImportCap:false,hasOverlap:true}}}const fullReadKey=`${queueKey}\0${params.sessionFile}`;const reason=!checkpoint?"checkpoint-missing":checkpoint.sessionFilePath!==params.sessionFile?"path-mismatch":transcriptEpochShrank?"same-path-shrink":"append-only-ineligible";if(reason==="same-path-shrink"){this.afterTurnReconcileFullReadStates.delete(fullReadKey)}const rememberedFileState=this.afterTurnReconcileFullReadStates.get(fullReadKey);if(rememberedFileState&&sessionFileState&&rememberedFileState.size===sessionFileState.size&&rememberedFileState.mtimeMs===sessionFileState.mtimeMs){this.deps.log.debug(`[lcm] afterTurn: transcript reconcile slow path skipped (file state already read this process) conversation=${conversation.conversationId} reason=${reason} sessionFile=${params.sessionFile}`);return{importedMessages:0,blockedByImportCap:false,hasOverlap:true}}const rememberSlowReadState=()=>{if(!sessionFileState){return}if(!this.afterTurnReconcileFullReadStates.has(fullReadKey)&&this.afterTurnReconcileFullReadStates.size>=_LcmContextEngine.AFTER_TURN_RECONCILE_KEY_CAP){const oldest=this.afterTurnReconcileFullReadStates.keys().next().value;if(typeof oldest==="string"){this.afterTurnReconcileFullReadStates.delete(oldest)}}this.afterTurnReconcileFullReadStates.set(fullReadKey,sessionFileState)};const slowPathStartedAt=Date.now();const historicalMessages=await readLeafPathMessages(params.sessionFile);if(historicalMessages.length===0){if(!sessionFileState){if(!checkpoint){try{await this.summaryStore.upsertConversationBootstrapState({conversationId:conversation.conversationId,sessionFilePath:params.sessionFile,lastSeenSize:0,lastSeenMtimeMs:0,lastProcessedOffset:0,lastProcessedEntryHash:null})}catch(seedError){this.deps.log.warn(`[lcm] afterTurn: transcript reconcile slow path failed to seed placeholder bootstrap_state conversation=${conversation.conversationId} sessionFile=${params.sessionFile} error=${seedError instanceof Error?seedError.message:String(seedError)}`)}this.deps.log.warn(`[lcm] afterTurn: transcript reconcile slow path could not stat/read transcript; allowing live afterTurn persistence and seeding placeholder bootstrap_state at offset=0 to unblock next-turn recovery conversation=${conversation.conversationId} sessionFile=${params.sessionFile}`)}else{this.deps.log.warn(`[lcm] afterTurn: transcript reconcile slow path could not stat/read transcript; preserving existing checkpoint (offset=${checkpoint.lastProcessedOffset}) instead of reseeding conversation=${conversation.conversationId} sessionFile=${params.sessionFile}`)}return{importedMessages:0,blockedByImportCap:false,hasOverlap:true}}if(sessionFileState.size===0){await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile});rememberSlowReadState()}else{this.deps.log.warn(`[lcm] afterTurn: transcript reconcile slow path read empty messages from non-empty file (${sessionFileState?.size??"?"} bytes) \u2014 skipping checkpoint refresh to avoid dropping messages on parser failure conversation=${conversation.conversationId} sessionFile=${params.sessionFile}`)}return{importedMessages:0,blockedByImportCap:false,hasOverlap:sessionFileState.size===0}}const reconcile=await this.reconcileSessionTail({sessionId:params.sessionId,sessionKey:params.sessionKey,conversationId:conversation.conversationId,historicalMessages,skipContentAnchorScan:reason==="same-path-shrink",allowNoAnchorImport:reason==="path-mismatch"||reason==="same-path-shrink",noAnchorImportReason:reason});if(reconcile.blockedByImportCap){return{importedMessages:0,blockedByImportCap:true,hasOverlap:reconcile.hasOverlap}}if(reconcile.importedMessages>0){this.recordRecentBootstrapImport(conversation.conversationId,reconcile.importedMessages,"reconciled missing session messages")}if(!reconcile.hasOverlap&&reconcile.importedMessages===0){this.deps.log.warn(`[lcm] afterTurn: transcript reconcile found no anchor and imported 0 messages; skipping checkpoint refresh conversation=${conversation.conversationId} reason=${reason} sessionFile=${params.sessionFile} historicalMessages=${historicalMessages.length}`);return{importedMessages:0,blockedByImportCap:false,hasOverlap:false}}await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile});rememberSlowReadState();this.deps.log.warn(`[lcm] afterTurn: transcript reconcile slow path (full re-read) conversation=${conversation.conversationId} reason=${reason} sessionFile=${params.sessionFile} historicalMessages=${historicalMessages.length} importedMessages=${reconcile.importedMessages} duration=${formatDurationMs(Date.now()-slowPathStartedAt)}`);return{importedMessages:reconcile.importedMessages,blockedByImportCap:false,hasOverlap:reconcile.hasOverlap}},{operationName:"afterTurnTranscriptReconcile",context:[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ")})}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:params.lastProcessedEntryHash!==void 0?params.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,lastProcessedEntryHash)=>{await this.refreshBootstrapState({conversationId:conversationId2,sessionFile:params.sessionFile,fileStats:{size:sessionFileSize,mtimeMs:sessionFileMtimeMs},lastProcessedEntryHash});this.lastFullReadFileState.set(conversationId2,{size:sessionFileSize,mtimeMs:sessionFileMtimeMs})};const normalizedSessionKey=params.sessionKey?.trim();if(normalizedSessionKey){const activeByKey=await this.conversationStore.getConversationBySessionKey(normalizedSessionKey);if(activeByKey&&activeByKey.sessionId!==params.sessionId){const activeBootstrapState=await this.summaryStore.getConversationBootstrapState(activeByKey.conversationId);const trackedSessionFile=activeBootstrapState?.sessionFilePath;let trackedSessionFileMissing=false;if(typeof trackedSessionFile==="string"&&trackedSessionFile.length>0){try{await stat(trackedSessionFile)}catch(err){const code=getErrorCode(err);if(code==="ENOENT"||code==="ENOTDIR"){trackedSessionFileMissing=true}else{this.deps.log.warn(`[lcm] bootstrap: could not verify tracked transcript path conversation=${activeByKey.conversationId} file=${trackedSessionFile} error=${describeLogError(err)}`)}}}const transcriptRotated=typeof trackedSessionFile==="string"&&trackedSessionFile.length>0&&trackedSessionFile!==params.sessionFile;if(transcriptRotated&&trackedSessionFileMissing){this.deps.log.warn(`[lcm] bootstrap: detected reset/rollover without prior lifecycle split; rotating conversation=${activeByKey.conversationId} session=${params.sessionId} sessionKey=${normalizedSessionKey} oldSessionId=${activeByKey.sessionId} oldFile=${trackedSessionFile} newFile=${params.sessionFile}`);await this.applySessionReplacement({reason:"bootstrap session-file rollover fallback",sessionId:activeByKey.sessionId,sessionKey:normalizedSessionKey,nextSessionId:params.sessionId,nextSessionKey:normalizedSessionKey,createReplacement:true})}}}const conversation2=await this.conversationStore.getOrCreateConversation(params.sessionId,{sessionKey:params.sessionKey});const conversationId=conversation2.conversationId;let existingCount=await this.conversationStore.getMessageCount(conversationId);let bootstrapState=await this.summaryStore.getConversationBootstrapState(conversationId);let transcriptEpochRotated=false;let transcriptEpochReason;if(bootstrapState&&bootstrapState.sessionFilePath!==params.sessionFile){transcriptEpochRotated=true;transcriptEpochReason="path-mismatch";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&&checkpointIsPastTranscriptEof(bootstrapState,sessionFileSize)){transcriptEpochRotated=true;transcriptEpochReason="same-path-shrink";this.deps.log.warn(`[lcm] bootstrap: session file shrank past checkpoint conversation=${conversationId} ${sessionLabel} file=${params.sessionFile} checkpointOffset=${bootstrapState.lastProcessedOffset} checkpointSize=${bootstrapState.lastSeenSize} currentSize=${sessionFileSize}`);this.lastFullReadFileState.delete(conversationId);bootstrapState=null}if(bootstrapState&&bootstrapState.sessionFilePath===params.sessionFile&&bootstrapState.lastSeenSize===sessionFileSize&&bootstrapState.lastSeenMtimeMs===sessionFileMtimeMs){if(!conversation2.bootstrappedAt){await this.conversationStore.markConversationBootstrapped(conversationId)}this.deps.log.debug(`[lcm] bootstrap: checkpoint hit conversation=${conversationId} ${sessionLabel} existingCount=${existingCount} duration=${formatDurationMs(Date.now()-startedAt)}`);return{bootstrapped:false,importedMessages:0,reason:conversation2.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(!conversation2.bootstrappedAt){await this.conversationStore.markConversationBootstrapped(conversationId)}const replayFilteredMessages=await this.filterBootstrapReplayMessages({messages:appended.messages,sessionContext:this.formatSessionLogContext({conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey}),source:"bootstrap append-only",sessionFile:params.sessionFile});let importedMessages=0;for(const message of replayFilteredMessages){const ingestResult=await this.ingestSingle({sessionId:params.sessionId,sessionKey:params.sessionKey,message});if(ingestResult.ingested){importedMessages+=1}}await persistBootstrapState(conversationId);this.deps.log.debug(`[lcm] bootstrap: append-only conversation=${conversationId} ${sessionLabel} existingCount=${existingCount} appendedMessages=${appended.messages.length} replayFilteredMessages=${replayFilteredMessages.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:conversation2.bootstrappedAt?"already bootstrapped":"conversation already up to date"}}}}if(conversation2.bootstrappedAt&&existingCount>0){const cached=this.lastFullReadFileState.get(conversationId);if(cached&&cached.size===sessionFileSize&&cached.mtimeMs===sessionFileMtimeMs){await persistBootstrapState(conversationId);this.deps.log.debug(`[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.debug(`[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"}}let importedMessages=0;for(const message of bootstrapMessages){const result2=await this.ingestSingle({sessionId:params.sessionId,sessionKey:params.sessionKey,message,skipReplayTimestampFloodGuard:true});if(result2.ingested){importedMessages+=1}}await this.conversationStore.markConversationBootstrapped(conversationId);let prunedMessages=0;if(this.config.pruneHeartbeatOk){const pruned=await this.pruneHeartbeatOkTurns(conversationId);prunedMessages=pruned;if(pruned>0){this.deps.log.info(`[lcm] bootstrap: pruned ${pruned} HEARTBEAT_OK messages from conversation ${conversationId}`)}}const lastImportedHash=prunedMessages===0&&bootstrapMessages.length>0?createBootstrapEntryHash(toStoredMessage(bootstrapMessages[bootstrapMessages.length-1])):void 0;await persistBootstrapState(conversationId,lastImportedHash);this.deps.log.debug(`[lcm] bootstrap: initial import conversation=${conversationId} ${sessionLabel} importedMessages=${importedMessages} sourceMessages=${historicalMessages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return{bootstrapped:true,importedMessages}}const reconcile=await this.reconcileSessionTail({sessionId:params.sessionId,sessionKey:params.sessionKey,conversationId,historicalMessages,checkpointEntryHash:transcriptEpochReason==="same-path-shrink"?void 0:bootstrapState?.lastProcessedEntryHash,skipContentAnchorScan:transcriptEpochReason==="same-path-shrink",allowNoAnchorImport:transcriptEpochRotated,noAnchorImportReason:transcriptEpochReason});this.deps.log.debug(`[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.blockedReason==="cross-conversation-raw-id"?"reconcile duplicate raw ids":"reconcile import capped"}}if(!conversation2.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(conversation2.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 conversation2=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(conversation2){const pruned=await this.pruneHeartbeatOkTurns(conversation2.conversationId);if(pruned>0){await this.refreshBootstrapState({conversationId:conversation2.conversationId,sessionFile:params.sessionFile});this.deps.log.info(`[lcm] bootstrap: retroactively pruned ${pruned} HEARTBEAT_OK messages from conversation ${conversation2.conversationId}`)}}}catch(err){this.deps.log.warn(`[lcm] bootstrap: heartbeat pruning failed: ${describeLogError(err)}`)}}const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(conversation){this.recordRecentBootstrapImport(conversation.conversationId,result.importedMessages,result.reason??null)}this.deps.log.debug(`[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,options){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)return batch;const lastDbMessage=await this.conversationStore.getLastMessage(conversationId);if(!lastDbMessage)return batch;const storedBatch=batch.map(m=>toStoredMessage(m));if(storedMessageCount>batch.length){return this.deduplicateOversizedBatch(conversationId,batch,storedBatch,storedMessageCount,lastDbMessage,options)}const batchAtBoundary=storedBatch[storedMessageCount-1];if(messageIdentity(lastDbMessage.role,lastDbMessage.content)!==messageIdentity(batchAtBoundary.role,batchAtBoundary.content)){return this.deduplicateSuffixFallback(conversationId,batch,storedBatch,storedMessageCount,"prefix-mismatch")}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 deduplicateOversizedBatch(conversationId,batch,storedBatch,storedMessageCount,lastDbMessage,options){const lastBatchIdentity=messageIdentity(storedBatch[storedBatch.length-1].role,storedBatch[storedBatch.length-1].content);const lastDbIdentity=messageIdentity(lastDbMessage.role,lastDbMessage.content);if(lastDbIdentity===lastBatchIdentity){const storedMessages=await this.conversationStore.getMessages(conversationId,{limit:storedMessageCount});const tailMessages=storedMessages.slice(-batch.length);if(tailMessages.length===batch.length){let tailMatch=true;for(let i=0;i<batch.length;i++){if(messageIdentity(tailMessages[i].role,tailMessages[i].content)!==messageIdentity(storedBatch[i].role,storedBatch[i].content)){tailMatch=false;break}}if(tailMatch){this.deps.log.debug(`[lcm] dedup: tail-match detected, batch already fully stored (storedCount=${storedMessageCount} batchLen=${batch.length}), skipping entire batch`);return[]}}}return this.deduplicateSuffixFallback(conversationId,batch,storedBatch,storedMessageCount,"oversized",{onNoOverlap:options?.oversizedNoOverlap??"skip"})}async deduplicateSuffixFallback(conversationId,batch,storedBatch,storedMessageCount,context,options){const allStored=await this.conversationStore.getMessages(conversationId,{limit:storedMessageCount});if(allStored.length===0)return batch;const lastStoredIdentity=messageIdentity(allStored[allStored.length-1].role,allStored[allStored.length-1].content);for(let k=batch.length-1;k>=0;k--){if(messageIdentity(storedBatch[k].role,storedBatch[k].content)!==lastStoredIdentity){continue}const matchLen=Math.min(k+1,allStored.length);const startDb=allStored.length-matchLen;let suffixMatch=true;for(let j=0;j<matchLen;j++){if(messageIdentity(allStored[startDb+j].role,allStored[startDb+j].content)!==messageIdentity(storedBatch[k-matchLen+1+j].role,storedBatch[k-matchLen+1+j].content)){suffixMatch=false;break}}const newSlice=batch.slice(k+1);if(suffixMatch&&(newSlice.length>0||matchLen>1)){this.deps.log.debug(`[lcm] dedup: ${context} suffix-match at batch[${k}], returning ${newSlice.length} new messages (storedCount=${storedMessageCount} batchLen=${batch.length})`);return newSlice}}if(options?.onNoOverlap==="skip"){this.deps.log.warn(`[lcm] dedup: ${context}, storedCount=${storedMessageCount} batchLen=${batch.length}, no overlap found \u2014 fail-closed skipping full batch`);return[]}this.deps.log.warn(`[lcm] dedup: ${context}, storedCount=${storedMessageCount} batchLen=${batch.length}, no overlap found \u2014 ingesting full batch`);return batch}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){const runRuntimeAutoRotate=async()=>{await this.maybeAutoRotateManagedSessionFile({phase:"runtime",sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile})};if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){await runRuntimeAutoRotate();return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"session excluded by pattern"}}if(this.isStatelessSession(params.sessionKey)){await runRuntimeAutoRotate();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(" ");const result=await 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);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})();const cappedTokenBudget=this.applyAssemblyBudgetCap(runtimeTokenBudget);const maintainCurrentTokenCount=typeof params.runtimeContext?.currentTokenCount==="number"?Math.floor(params.runtimeContext.currentTokenCount):void 0;if(maintenance?.pending||maintenance?.running){deferredCompactionResult=await this.consumeDeferredCompactionDebt({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:cappedTokenBudget,currentTokenCount:maintainCurrentTokenCount,runtimeContext:params.runtimeContext,legacyParams:asRecord(params.runtimeContext)})}}else if(maintenance?.pending||maintenance?.running){this.deps.log.debug(`[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.debug(`[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.debug(`[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 result2=await rewriteTranscriptEntries({replacements});if(result2.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||result2.changed,bytesFreed:result2.bytesFreed,rewrittenEntries:result2.rewrittenEntries,reason:result2.reason??deferredCompactionResult.reason}:result2;this.deps.log.debug(`[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});await runRuntimeAutoRotate();return result}async ingestSingle(params){const{sessionId,sessionKey,message,isHeartbeat,skipReplayTimestampFloodGuard}=params;if(isHeartbeat){return{ingested:false}}if(!hasPersistableMessageRole(message)){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;const nativeImageIntercepted=await this.interceptNativeImageBlocks({conversationId,message:messageForParts});if(nativeImageIntercepted){messageForParts=nativeImageIntercepted.rewrittenMessage;stored=toStoredMessage(messageForParts)}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 rawPayloadIntercepted=await this.interceptLargeRawPayload({conversationId,message:messageForParts,stored});if(rawPayloadIntercepted){messageForParts=rawPayloadIntercepted.rewrittenMessage;stored=rawPayloadIntercepted.stored}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,skipReplayTimestampFloodGuard});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()=>{return this.conversationStore.withTransaction(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){const runRuntimeAutoRotate=async()=>{await this.maybeAutoRotateManagedSessionFile({phase:"runtime",sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile})};if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){await runRuntimeAutoRotate();return}if(this.isStatelessSession(params.sessionKey)){await runRuntimeAutoRotate();return}this.ensureMigrated();const startedAt=Date.now();const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");const newMessages=filterPersistableMessages(params.messages.slice(params.prePromptMessageCount));let transcriptReconcileResult={importedMessages:0,blockedByImportCap:false,hasOverlap:true};try{transcriptReconcileResult=await this.reconcileTranscriptTailForAfterTurn({sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile})}catch(err){this.deps.log.warn(`[lcm] afterTurn: transcript reconcile failed for ${sessionLabel}: ${describeLogError(err)}`)}const transcriptReconcileUnsafeToAdvance=transcriptReconcileResult.blockedByImportCap||!transcriptReconcileResult.hasOverlap&&transcriptReconcileResult.importedMessages===0;let dedupedNewMessages=[];if(transcriptReconcileUnsafeToAdvance){if(newMessages.length>0||params.autoCompactionSummary){this.deps.log.warn(`[lcm] afterTurn: transcript reconcile did not cover the transcript frontier; skipping afterTurn persistence to avoid creating a future anchor past unreconciled transcript history ${sessionLabel}`)}}else{dedupedNewMessages=await this.deduplicateAfterTurnBatch(params.sessionId,params.sessionKey,newMessages,{oversizedNoOverlap:transcriptReconcileResult.importedMessages>0?"ingest":"skip"})}const summaryCoveredMessages=[];const summaryDedupedNewMessages=[];if(params.autoCompactionSummary){for(const message of dedupedNewMessages){if(messageContentCoveredBySummary({message,summary:params.autoCompactionSummary})){summaryCoveredMessages.push(message)}else{summaryDedupedNewMessages.push(message)}}}else{summaryDedupedNewMessages.push(...dedupedNewMessages)}if(summaryCoveredMessages.length>0){this.deps.log.debug(`[lcm] afterTurn: skipped ${summaryCoveredMessages.length} messages already covered by autoCompactionSummary ${sessionLabel}`)}const ingestBatch=[];if(!transcriptReconcileUnsafeToAdvance&¶ms.autoCompactionSummary){ingestBatch.push({role:"user",content:params.autoCompactionSummary})}ingestBatch.push(...summaryDedupedNewMessages);if(ingestBatch.length===0){this.deps.log.debug(`[lcm] afterTurn: nothing to ingest ${sessionLabel} newMessages=${newMessages.length} (continuing to compaction evaluation; transcript reconcile may have already ingested) duration=${formatDurationMs(Date.now()-startedAt)}`)}else{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)}`);this.logAutoRotateSessionFileDecision({phase:"runtime",action:"skip",sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile,thresholdBytes:this.config.autoRotateSessionFiles.sizeBytes,durationMs:0,reason:"ingest-failed",error:describeLogError(err),level:"warn"});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}`);await runRuntimeAutoRotate();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 estimatedContextTokens=estimateSessionTokenCountForAfterTurn(params.messages);const runtimePromptTokens=extractRuntimePromptTokenCount(asRecord(params.runtimeContext));const suppliedCurrentTokenCount=this.normalizeObservedTokenCount((legacyParams??{}).currentTokenCount);const observedCurrentTokenCount=runtimePromptTokens??suppliedCurrentTokenCount??estimatedContextTokens;if(runtimePromptTokens!==void 0){this.deps.log.debug(`[lcm] afterTurn: using runtime prompt token count currentTokenCount=${runtimePromptTokens} estimatedTokenCount=${estimatedContextTokens}`)}const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){this.deps.log.debug(`[lcm] afterTurn: conversation lookup missed ${sessionLabel} ingestBatch=${ingestBatch.length} duration=${formatDurationMs(Date.now()-startedAt)}`);await runRuntimeAutoRotate();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:observedCurrentTokenCount})}catch(err){this.deps.log.warn(`[lcm] afterTurn: failed to persist deferred compaction retry for ${sessionLabel}: ${describeLogError(err)}`)}};let shouldRefreshBootstrapState=!transcriptReconcileResult.blockedByImportCap&&(transcriptReconcileResult.hasOverlap||transcriptReconcileResult.importedMessages>0);let deferredCompactionDrain=null;try{await this.updateCompactionTelemetry({conversationId:conversation.conversationId,runtimeContext:legacyParams,tokenBudget})}catch(err){this.deps.log.warn(`[lcm] afterTurn: compaction telemetry update failed: ${describeLogError(err)}`)}try{const thresholdDecision=await this.compaction.evaluate(conversation.conversationId,tokenBudget,observedCurrentTokenCount);if(this.config.proactiveThresholdCompactionMode==="inline"){if(thresholdDecision.shouldCompact){const compactResult=await this.compact({sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile,tokenBudget,currentTokenCount:observedCurrentTokenCount,compactionTarget:"threshold",legacyParams});if(!compactResult.ok){shouldRefreshBootstrapState=false;await recordAfterTurnCompactionRetry("threshold")}}}else if(thresholdDecision.shouldCompact){await this.recordDeferredCompactionDebt({conversationId:conversation.conversationId,reason:"threshold",tokenBudget,currentTokenCount:observedCurrentTokenCount});deferredCompactionDrain={tokenBudget,currentTokenCount:observedCurrentTokenCount,reason:"threshold"}}}catch(err){this.deps.log.warn(`[lcm] afterTurn: compaction policy check failed for ${sessionLabel}: ${describeLogError(err)}`)}if(shouldRefreshBootstrapState){await refreshAfterTurnBootstrapState()}if(deferredCompactionDrain){this.scheduleDeferredCompactionDebtDrain({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:deferredCompactionDrain.tokenBudget,currentTokenCount:deferredCompactionDrain.currentTokenCount,reason:deferredCompactionDrain.reason})}this.deps.log.debug(`[lcm] afterTurn: done conversation=${conversation.conversationId} ${sessionLabel} newMessages=${newMessages.length} dedupedMessages=${dedupedNewMessages.length} ingestedMessages=${ingestBatch.length} duration=${formatDurationMs(Date.now()-startedAt)}`);await runRuntimeAutoRotate()}async assemble(params){const safeFallback=()=>{const msgs=params.messages.slice();while(msgs.length>0&&msgs[msgs.length-1]?.role==="assistant"){msgs.pop()}return{messages:msgs,estimatedTokens:0}};if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return safeFallback()}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.debug(`[lcm] assemble: conversation lookup missed ${sessionLabel} duration=${formatDurationMs(Date.now()-startedAt)}`);return safeFallback()}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.debug(`[lcm] assemble: no context items conversation=${conversation.conversationId} ${sessionLabel} duration=${formatDurationMs(Date.now()-startedAt)}`);return safeFallback()}const hasSummaryItems=contextItems.some(item=>item.itemType==="summary");if(!hasSummaryItems&&contextItems.length<params.messages.length){this.deps.log.debug(`[lcm] assemble: falling back to live context conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} liveMessages=${params.messages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return safeFallback()}const assembled=await this.assembler.assemble({conversationId:conversation.conversationId,tokenBudget,freshTailCount:this.config.freshTailCount,freshTailMaxTokens:this.config.freshTailMaxTokens,promptAwareEviction:this.config.promptAwareEviction,prompt:params.prompt,stubLargeToolPayloads:this.config.stubLargeToolPayloads});if(assembled.messages.length===0&¶ms.messages.length>0){this.deps.log.debug(`[lcm] assemble: empty assembled output, using live context conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} tokenBudget=${tokenBudget} duration=${formatDurationMs(Date.now()-startedAt)}`);return safeFallback()}const assembledHasUserTurn=assembled.messages.some(m=>m.role==="user");if(!assembledHasUserTurn&¶ms.messages.length>0){this.deps.log.debug(`[lcm] assemble: assembled context has no user turns, falling back to live context to prevent prefill errors conversation=${conversation.conversationId} ${sessionLabel} assembledMessages=${assembled.messages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return safeFallback()}const volatileLiveInputAppend=appendUncoveredVolatileLiveInputsWithinBudget({assembledMessages:assembled.messages,assembledEstimatedTokens:assembled.estimatedTokens,liveMessages:params.messages,protectedAssembledIndexes:resolveProtectedFreshTailAssembledIndexes({assembledMessages:assembled.messages,freshTailMessageHashes:assembled.debug?.freshTailProtectionMessageHashes??assembled.debug?.preSanitizeFreshTailMessageHashes}),tokenBudget});if(volatileLiveInputAppend.appendedMessages>0){this.deps.log.warn(`[lcm] assemble: appended unpersisted volatile live input conversation=${conversation.conversationId} ${sessionLabel} appendedMessages=${volatileLiveInputAppend.appendedMessages} appendedTokens=${volatileLiveInputAppend.appendedTokens} evictedMessages=${volatileLiveInputAppend.evictedMessages} evictedTokens=${volatileLiveInputAppend.evictedTokens} overBudget=${volatileLiveInputAppend.overBudget}`)}const stubStatsLog=assembled.debug?.stubStats?` stubbed=${assembled.debug.stubStats.stubbedCount} tokensSaved=${assembled.debug.stubStats.tokensSaved}`:"";const activeFocusBrief=await this.focusBriefStore.getActiveFocusBrief(conversation.conversationId);const contextProjectionEpoch=buildContextEngineProjectionEpoch(conversation.conversationId,contextItems,activeFocusBrief);const summaryContextItems=contextItems.filter(item=>item.itemType==="summary").length;const volatileLiveInputLog=volatileLiveInputAppend.appendedMessages>0?` volatileLiveInputsAppended=${volatileLiveInputAppend.appendedMessages} volatileLiveInputEvicted=${volatileLiveInputAppend.evictedMessages} volatileLiveInputOverBudget=${volatileLiveInputAppend.overBudget}`:"";this.deps.log.info(`[lcm] assemble: done conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} summaryContextItems=${summaryContextItems} hasSummaryItems=${hasSummaryItems} inputMessages=${params.messages.length} outputMessages=${volatileLiveInputAppend.messages.length} tokenBudget=${tokenBudget} estimatedTokens=${volatileLiveInputAppend.estimatedTokens} contextProjectionMode=thread_bootstrap contextProjectionEpoch=${contextProjectionEpoch}${stubStatsLog}${volatileLiveInputLog} duration=${formatDurationMs(Date.now()-startedAt)}`);const prefixChange=describeAssembledPrefixChange(this.getPreviousAssembledSnapshot(conversation.conversationId),volatileLiveInputAppend.messages);this.setPreviousAssembledSnapshot(conversation.conversationId,prefixChange.currentSnapshot);if(assembled.debug){const promotedOrdinals=assembled.debug.promotedOrdinals.length>0?assembled.debug.promotedOrdinals.join(","):"none";const overflowDiagnostics=shouldLogOverflowDiagnostics({diagnostics:assembled.debug.overflowDiagnostics,assembledTokens:assembled.estimatedTokens,liveContextTokens})?` overflowDiagnostics=${formatOverflowDiagnosticsForLog({diagnostics:assembled.debug.overflowDiagnostics,recentBootstrapImport:this.recentBootstrapImportsByConversation.get(conversation.conversationId)})}`:"";this.deps.log.debug(`[lcm] assemble-debug conversation=${conversation.conversationId} ${sessionLabel} messagesHash=${assembled.debug.finalMessagesHash} preSanitizeHash=${assembled.debug.preSanitizeMessagesHash} previousAssembledCount=${prefixChange.previousCount} commonPrefixCount=${prefixChange.commonPrefixCount} commonPrefixHash=${prefixChange.commonPrefixHash} previousWasPrefix=${prefixChange.previousWasPrefix} firstDivergenceIndex=${prefixChange.firstDivergenceIndex} previousDivergenceMessage=${prefixChange.previousDivergenceMessage} currentDivergenceMessage=${prefixChange.currentDivergenceMessage} evictableCount=${assembled.debug.preSanitizeEvictableCount} evictableHash=${assembled.debug.preSanitizeEvictableHash} freshTailSegmentCount=${assembled.debug.preSanitizeFreshTailCount} freshTailSegmentHash=${assembled.debug.preSanitizeFreshTailHash} selectionMode=${assembled.debug.selectionMode} freshTailOrdinal=${assembled.debug.freshTailOrdinal} orphanStrippingOrdinal=${assembled.debug.orphanStrippingOrdinal} baseFreshTailCount=${assembled.debug.baseFreshTailCount} freshTailCount=${assembled.debug.freshTailCount} tailTokens=${assembled.debug.tailTokens} remainingBudget=${assembled.debug.remainingBudget} evictableTotalTokens=${assembled.debug.evictableTotalTokens} promotedToolResults=${assembled.debug.promotedToolResultCount} promotedOrdinals=${promotedOrdinals} removedToolUseBlocks=${assembled.debug.removedToolUseBlockCount} touchedAssistantMessages=${assembled.debug.touchedAssistantMessageCount}${overflowDiagnostics}`)}const result={messages:volatileLiveInputAppend.messages,estimatedTokens:volatileLiveInputAppend.estimatedTokens,contextProjection:{mode:"thread_bootstrap",epoch:contextProjectionEpoch}};return result}catch(err){this.deps.log.debug(`[lcm] assemble: failed for session=${params.sessionId}${params.sessionKey?.trim()?` sessionKey=${params.sessionKey.trim()}`:""} error=${describeLogError(err)}`);return safeFallback()}}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):4e4;return{shouldCompact:false,rawTokensOutsideTail:0,threshold:fallbackThreshold}}return this.compaction.evaluateLeafTrigger(conversation.conversationId)}async compact(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){this.deps.log.info(`[lcm] compact: skipped session=${params.sessionId}${params.sessionKey?.trim()?` sessionKey=${params.sessionKey.trim()}`:""} reason=session_excluded`);return{ok:true,compacted:false,reason:"session excluded"}}if(this.isStatelessSession(params.sessionKey)){this.deps.log.info(`[lcm] compact: skipped session=${params.sessionId}${params.sessionKey?.trim()?` sessionKey=${params.sessionKey.trim()}`:""} reason=stateless_session`);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){this.deps.log.info(`[lcm] compact: skipped session=${params.sessionId}${params.sessionKey?.trim()?` sessionKey=${params.sessionKey.trim()}`:""} reason=no_conversation_found`);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"||reason==="restart"||reason==="shutdown"){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})}))}getAutoRotateSessionFileMode(phase){return phase==="startup"?this.config.autoRotateSessionFiles.startup:this.config.autoRotateSessionFiles.runtime}logAutoRotateSessionFileDecision(params){const fields=[["phase",params.phase],["action",params.action],["sessionId",params.sessionId],["sessionKey",params.sessionKey],["conversationId",params.conversationId],["sessionFile",params.sessionFile],["sizeBytes",params.sizeBytes],["thresholdBytes",params.thresholdBytes],["durationMs",params.durationMs],["backupPath",params.backupPath],["bytesRemoved",params.bytesRemoved],["preservedTailMessageCount",params.preservedTailMessageCount],["checkpointSize",params.checkpointSize],["currentMessageCount",params.currentMessageCount],["scanned",params.scanned],["eligible",params.eligible],["rotated",params.rotated],["warned",params.warned],["skipped",params.skipped],["backupCreated",params.backupCreated],["reason",params.reason],["error",params.error]];const rendered=fields.filter(entry=>entry[1]!==void 0).map(([key,value])=>`${key}=${String(value).replace(/\s+/g,"_")}`).join(" ");const level=params.level??"info";this.deps.log[level](`[lcm] auto-rotate: ${rendered}`)}async maybeAutoRotateManagedSessionFile(params){const startedAt=Date.now();const thresholdBytes=this.config.autoRotateSessionFiles.sizeBytes;const sessionId=params.sessionId?.trim();const sessionKey=params.sessionKey?.trim();const sessionFile=params.sessionFile?.trim();const baseLog={phase:params.phase,sessionId,sessionKey,conversationId:params.conversationId,sessionFile,thresholdBytes};const skip=(reason,sizeBytes2)=>{this.logAutoRotateSessionFileDecision({...baseLog,action:"skip",sizeBytes:sizeBytes2,durationMs:Date.now()-startedAt,reason})};if(!this.config.autoRotateSessionFiles.enabled){skip("disabled");return}const mode=this.getAutoRotateSessionFileMode(params.phase);if(mode==="off"){skip("mode-off");return}if(!this.info.ownsCompaction){skip("engine-unhealthy");return}if(!sessionId||!sessionKey){skip("missing-session-identity");return}if(!sessionFile){skip("missing-session-file");return}if(this.shouldIgnoreSession({sessionId,sessionKey})){skip("session-excluded");return}if(this.isStatelessSession(sessionKey)){skip("stateless-session");return}let sizeBytes;try{sizeBytes=(await stat(sessionFile)).size}catch(error){this.logAutoRotateSessionFileDecision({...baseLog,action:"warn",durationMs:Date.now()-startedAt,reason:"session-file-stat-failed",error:describeLogError(error),level:"warn"});return}if(sizeBytes<=thresholdBytes){this.oversizedAutoRotateCheckpointByQueueKey.delete(this.resolveSessionQueueKey(sessionId,sessionKey));skip("below-threshold",sizeBytes);return}let conversation;try{conversation=params.conversationId!==void 0?await this.conversationStore.getConversation(params.conversationId):await this.conversationStore.getConversationForSession({sessionId,sessionKey})}catch(error){this.logAutoRotateSessionFileDecision({...baseLog,action:"warn",sizeBytes,durationMs:Date.now()-startedAt,reason:"conversation-lookup-failed",error:describeLogError(error),level:"warn"});return}if(!conversation?.active){skip("no-active-conversation",sizeBytes);return}const queueKey=this.resolveSessionQueueKey(sessionId,sessionKey);const previousOversizedCheckpoint=this.oversizedAutoRotateCheckpointByQueueKey.get(queueKey);if(previousOversizedCheckpoint!==void 0&&sizeBytes<previousOversizedCheckpoint+thresholdBytes){skip("previous-rotate-left-file-over-threshold",sizeBytes);return}if(mode==="warn"){this.logAutoRotateSessionFileDecision({...baseLog,action:"warn",conversationId:conversation.conversationId,sizeBytes,durationMs:Date.now()-startedAt,reason:"above-threshold",level:"warn"});return}let result;try{result=this.config.autoRotateSessionFiles.createBackups?await this.rotateSessionStorageWithBackup({sessionId,sessionKey,sessionFile,lockTimeoutMs:AUTO_ROTATE_DATABASE_LOCK_TIMEOUT_MS}):await this.rotateSessionStorage({sessionId,sessionKey,sessionFile})}catch(error){this.logAutoRotateSessionFileDecision({...baseLog,action:"warn",conversationId:conversation.conversationId,sizeBytes,durationMs:Date.now()-startedAt,reason:"rotate-threw",error:describeLogError(error),level:"warn"});return}if(result.kind==="rotated"){if(result.checkpointSize>=thresholdBytes){this.oversizedAutoRotateCheckpointByQueueKey.set(queueKey,result.checkpointSize)}else{this.oversizedAutoRotateCheckpointByQueueKey.delete(queueKey)}const conversationId="currentConversationId"in result?result.currentConversationId:result.conversationId;this.logAutoRotateSessionFileDecision({...baseLog,action:"rotate",conversationId,sizeBytes,durationMs:Date.now()-startedAt,backupPath:"backupPath"in result?result.backupPath:void 0,bytesRemoved:result.bytesRemoved,preservedTailMessageCount:result.preservedTailMessageCount,checkpointSize:result.checkpointSize,currentMessageCount:"currentMessageCount"in result?result.currentMessageCount:void 0});return}this.logAutoRotateSessionFileDecision({...baseLog,action:"warn",conversationId:"currentConversationId"in result?result.currentConversationId??conversation.conversationId:conversation.conversationId,sizeBytes,durationMs:Date.now()-startedAt,backupPath:"backupPath"in result?result.backupPath:void 0,currentMessageCount:"currentMessageCount"in result?result.currentMessageCount:void 0,reason:result.kind,error:result.reason,level:"warn"})}logStartupAutoRotateSummary(params){this.logAutoRotateSessionFileDecision({phase:"startup",action:"summary",thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,scanned:params.scanned,eligible:params.eligible,rotated:params.rotated,warned:params.warned,skipped:params.skipped,backupPath:params.backupPath,bytesRemoved:params.bytesRemoved,backupCreated:params.backupCreated,reason:params.reason})}async prepareStartupAutoRotateCandidate(params){const sessionId=params.candidate.sessionId?.trim();const sessionKey=params.candidate.sessionKey?.trim();const sessionFile=params.candidate.sessionFile?.trim();if(!sessionId||!sessionKey||!sessionFile){return{kind:"skipped"}}if(this.shouldIgnoreSession({sessionId,sessionKey})||this.isStatelessSession(sessionKey)){return{kind:"skipped"}}let conversation;try{conversation=await this.conversationStore.getConversationForSession({sessionId,sessionKey})}catch(error){this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",sessionId,sessionKey,sessionFile,thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"conversation-lookup-failed",error:describeLogError(error),level:"warn"});return{kind:"warned"}}if(!conversation?.active){return{kind:"skipped"}}const bootstrapState=await this.summaryStore.getConversationBootstrapState(conversation.conversationId);const bootstrapPath=bootstrapState?.sessionFilePath?.trim();if(!bootstrapPath||normalizeSessionFilePathForComparison(bootstrapPath)!==normalizeSessionFilePathForComparison(sessionFile)){return{kind:"skipped"}}let sizeBytes;try{sizeBytes=(await stat(sessionFile)).size}catch(error){if(isMissingFileError(error)){return{kind:"skipped"}}this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",sessionId,sessionKey,conversationId:conversation.conversationId,sessionFile,thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"session-file-stat-failed",error:describeLogError(error),level:"warn"});return{kind:"warned"}}if(sizeBytes<=params.thresholdBytes){this.oversizedAutoRotateCheckpointByQueueKey.delete(this.resolveSessionQueueKey(sessionId,sessionKey));return{kind:"skipped"}}return{kind:"eligible",candidate:{sessionId,sessionKey,sessionFile,conversationId:conversation.conversationId,sizeBytes,currentMessageCount:await this.conversationStore.getMessageCount(conversation.conversationId)}}}async withStartupAutoRotateSessionQueues(candidates,operation){const queueKeys=Array.from(new Set(candidates.map(candidate=>this.resolveSessionQueueKey(candidate.sessionId,candidate.sessionKey)))).sort();const enter=async index=>{if(index>=queueKeys.length){return operation()}return this.withSessionQueue(queueKeys[index],()=>enter(index+1))};return enter(0)}async rotateStartupAutoRotateBatch(params){const empty=()=>({rotated:0,warned:0,bytesRemoved:0,backupCreated:0});if(params.candidates.length===0){return empty()}try{return await this.withStartupAutoRotateSessionQueues(params.candidates,async()=>withExclusiveDatabaseLock(this.db,{timeoutMs:AUTO_ROTATE_DATABASE_LOCK_TIMEOUT_MS},async()=>{if(this.db.isTransaction){this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"database-transaction-active",level:"warn"});return{...empty(),warned:1}}let backupPath;let backupCreated=0;if(this.config.autoRotateSessionFiles.createBackups){try{backupPath=createLcmDatabaseBackup(this.db,{databasePath:this.config.databasePath,label:"rotate",replaceLatest:true})??void 0}catch(error){this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"backup-failed",error:describeLogError(error),level:"warn"});return{...empty(),warned:1}}if(!backupPath){this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"backup-unavailable",level:"warn"});return{...empty(),warned:1}}backupCreated=1}const result={rotated:0,warned:0,bytesRemoved:0,backupPath,backupCreated};for(const candidate of params.candidates){let rotateResult;try{rotateResult=await this.rotateSessionStorageWhileHoldingDatabaseLock({sessionId:candidate.sessionId,sessionKey:candidate.sessionKey,sessionFile:candidate.sessionFile})}catch(error){result.warned+=1;this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",sessionId:candidate.sessionId,sessionKey:candidate.sessionKey,conversationId:candidate.conversationId,sessionFile:candidate.sessionFile,sizeBytes:candidate.sizeBytes,thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,backupPath,currentMessageCount:candidate.currentMessageCount,reason:"rotate-threw",error:describeLogError(error),level:"warn"});continue}if(rotateResult.kind==="unavailable"){result.warned+=1;this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",sessionId:candidate.sessionId,sessionKey:candidate.sessionKey,conversationId:candidate.conversationId,sessionFile:candidate.sessionFile,sizeBytes:candidate.sizeBytes,thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,backupPath,currentMessageCount:candidate.currentMessageCount,reason:"unavailable",error:rotateResult.reason,level:"warn"});continue}result.rotated+=1;result.bytesRemoved+=rotateResult.bytesRemoved;const queueKey=this.resolveSessionQueueKey(candidate.sessionId,candidate.sessionKey);if(rotateResult.checkpointSize>=params.thresholdBytes){this.oversizedAutoRotateCheckpointByQueueKey.set(queueKey,rotateResult.checkpointSize)}else{this.oversizedAutoRotateCheckpointByQueueKey.delete(queueKey)}this.logAutoRotateSessionFileDecision({phase:"startup",action:"rotate",sessionId:candidate.sessionId,sessionKey:candidate.sessionKey,conversationId:rotateResult.conversationId,sessionFile:candidate.sessionFile,sizeBytes:candidate.sizeBytes,thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,backupPath,bytesRemoved:rotateResult.bytesRemoved,preservedTailMessageCount:rotateResult.preservedTailMessageCount,checkpointSize:rotateResult.checkpointSize,currentMessageCount:candidate.currentMessageCount})}return result}))}catch(error){if(error instanceof DatabaseTransactionTimeoutError){this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"database-lock-timeout",error:describeLogError(error),level:"warn"});return{...empty(),warned:1}}throw error}}async autoRotateManagedSessionFilesAtStartup(){const startedAt=Date.now();const thresholdBytes=this.config.autoRotateSessionFiles.sizeBytes;const mode=this.getAutoRotateSessionFileMode("startup");const summary={scanned:0,eligible:0,rotated:0,warned:0,skipped:0,bytesRemoved:0,backupPath:void 0,backupCreated:0};const logSummary=reason=>this.logStartupAutoRotateSummary({startedAt,thresholdBytes,...summary,reason});if(!this.config.autoRotateSessionFiles.enabled||mode==="off"){logSummary(this.config.autoRotateSessionFiles.enabled?"mode-off":"disabled");return}if(!this.info.ownsCompaction){logSummary("engine-unhealthy");return}if(!this.deps.listStartupSessionFileCandidates){logSummary("no-indexed-session-provider");return}this.ensureMigrated();let indexedCandidates;try{indexedCandidates=await this.deps.listStartupSessionFileCandidates()}catch(error){summary.warned+=1;this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",thresholdBytes,durationMs:Date.now()-startedAt,reason:"candidate-scan-failed",error:describeLogError(error),level:"warn"});logSummary("candidate-scan-failed");return}const rotateCandidates=[];for(const candidate of indexedCandidates){summary.scanned+=1;const prepared=await this.prepareStartupAutoRotateCandidate({candidate,startedAt,thresholdBytes});if(prepared.kind==="eligible"){summary.eligible+=1;if(mode==="warn"){summary.warned+=1;this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",sessionId:prepared.candidate.sessionId,sessionKey:prepared.candidate.sessionKey,conversationId:prepared.candidate.conversationId,sessionFile:prepared.candidate.sessionFile,sizeBytes:prepared.candidate.sizeBytes,thresholdBytes,durationMs:Date.now()-startedAt,currentMessageCount:prepared.candidate.currentMessageCount,reason:"above-threshold",level:"warn"})}else{rotateCandidates.push(prepared.candidate)}}else if(prepared.kind==="warned"){summary.warned+=1}else{summary.skipped+=1}}const batch=await this.rotateStartupAutoRotateBatch({candidates:rotateCandidates,startedAt,thresholdBytes});summary.rotated+=batch.rotated;summary.warned+=batch.warned;summary.bytesRemoved+=batch.bytesRemoved;summary.backupPath=batch.backupPath;summary.backupCreated+=batch.backupCreated;logSummary("completed")}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}getFocusBriefStore(){return this.focusBriefStore}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,conversationIds:[explicitConversationId],allConversations:false}}if(params.allConversations===true){return{conversationId:void 0,conversationIds:void 0,allConversations:true}}const normalizedSessionKey=input.sessionKey?.trim();if(normalizedSessionKey){const bySessionKey=await lcm.getConversationStore().getConversationBySessionKey(normalizedSessionKey);if(bySessionKey){const familyIds2=typeof lcm.getConversationStore().getConversationFamilyIds==="function"?await lcm.getConversationStore().getConversationFamilyIds({conversationId:bySessionKey.conversationId,sessionKey:normalizedSessionKey}):[bySessionKey.conversationId];return{conversationId:bySessionKey.conversationId,conversationIds:familyIds2.length>0?familyIds2:[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,conversationIds:void 0,allConversations:false}}const conversation=await lookupConversationForSession({lcm,sessionId:normalizedSessionId,sessionKey:input.sessionKey});if(!conversation){return{conversationId:void 0,conversationIds:void 0,allConversations:false}}const store=lcm.getConversationStore();const familyIds=typeof store.getConversationFamilyIds==="function"?await store.getConversationFamilyIds({conversationId:conversation.conversationId,sessionId:normalizedSessionId,sessionKey:input.sessionKey}):[conversation.conversationId];return{conversationId:conversation.conversationId,conversationIds:familyIds.length>0?familyIds:[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:"Physical conversation ID to scope describe lookups to. If omitted, uses the current session family."})),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})),expandFile:Type.Optional(Type.Boolean({description:"When true (and target is a file_xxx), inline the file's content from disk. Combined with the file's exploration_summary, this is how an agent recovers the original output of an elided tool result that was replaced with a [LCM Tool Output: file_xxx | tool=\u2026 | N bytes] reference. Capped at expandFileMaxBytes (default 32768 = ~8K tokens). Returns content + contentTruncated boolean. Use lcm_grep to search across the full file when it exceeds the cap."})),expandFileMaxBytes:Type.Optional(Type.Number({description:"Max bytes of inlined file content when expandFile=true. Default 32768. Hard cap 512000.",minimum:1024,maximum:512e3}))});function normalizeRequestedTokenCap(value){if(typeof value!=="number"||!Number.isFinite(value)){return void 0}return Math.max(1,Math.trunc(value))}function compactDescribeDetails(result){if(!result){return result}if(result.type==="summary"&&result.summary){const{content:_content,subtree:_subtree,...summary}=result.summary;return{id:result.id,type:result.type,summary}}if(result.type==="file"&&result.file){const{explorationSummary:_explorationSummary,...file}=result.file;return{id:result.id,type:result.type,file:{...file,hasExplorationSummary:Boolean(result.file.explorationSummary)}}}return{id:result.id,type:result.type}}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. ALSO USE THIS when you see a `[LCM Tool Output: file_xxx | tool=\u2026 | N bytes]` reference in the conversation \u2014 that means an older tool result was elided for context efficiency. Call lcm_describe(id=file_xxx, expandFile=true) to fetch the original output content before answering questions that depend on its specifics.",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 expandFile=p.expandFile===true;const expandFileMaxBytes=typeof p.expandFileMaxBytes==="number"&&Number.isFinite(p.expandFileMaxBytes)?p.expandFileMaxBytes:void 0;const result=await retrieval.describe(id,{expandFile,expandFileMaxBytes,largeFilesDir:lcm.configView?.largeFilesDir});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;const allowedConversationIds=new Set((conversationScope.conversationIds?.length??0)>0?conversationScope.conversationIds:conversationScope.conversationId!=null?[conversationScope.conversationId]:[]);if(itemConversationId!=null&&!allowedConversationIds.has(itemConversationId)){return jsonResult({error:`Not found in this session scope: ${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:{...compactDescribeDetails(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.*")}if(typeof f.content==="string"){lines.push("");lines.push("## Content");lines.push("");lines.push("```");lines.push(f.content);lines.push("```");if(f.contentTruncated){lines.push("");lines.push(`*Output truncated to ${f.content.length.toLocaleString()} of ${f.byteSize?.toLocaleString()??"?"} bytes. Use lcm_grep against the file id to search the full content.*`)}}else if(expandFile){lines.push("");lines.push("*Content unavailable: file missing on disk or path failed validation.*")}return{content:[{type:"text",text:lines.join("\n")}],details:compactDescribeDetails(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.debug(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:"Physical conversation ID to scope expansion to. If omitted, uses the current session family."})),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","not allowed for agent","not allowlisted for plugin","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"` for short literal terms, use `mode: "regex"` for alternation or other regex syntax, 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 the total source tokens consumed for retrieval. Include both: (a) the `totalTokens` returned by each `lcm_expand` call you made, AND (b) for any explicit leaf summary used as evidence, the leaf summary's own `tok` value from `lcm_describe`, even if you did not call `lcm_expand` for that leaf. This avoids reporting `totalSourceTokens: 0` when the answer was actually derived from a leaf summary's content.","- 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)));const allowedConversationIds=new Set(params.allowedConversationIds??[]);if(allowedConversationIds.size>0){const outOfScope=params.candidates.filter(candidate=>!allowedConversationIds.has(candidate.conversationId)).map(candidate=>candidate.summaryId);if(outOfScope.length>0){throw new Error(`Some summaryIds are outside the allowed conversation scope: ${outOfScope.join(", ")}`)}}if(allowedConversationIds.size>1){const firstAllowed=params.candidates.find(candidate=>allowedConversationIds.has(candidate.conversationId));if(firstAllowed){return firstAllowed.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 fallbackConversationIds=Array.from(new Set((params.conversationIds&¶ms.conversationIds.length>0?params.conversationIds:typeof params.conversationId==="number"?[params.conversationId]:[]).filter(conversationId=>Number.isInteger(conversationId))));const grepResult=await retrieval.grep({query:params.query,mode:"full_text",scope:"summaries",conversationId:params.conversationId,conversationIds:params.conversationIds});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&&fallbackConversationIds.length>0){const maxDepths=await Promise.all(fallbackConversationIds.map(async conversationId=>({conversationId,maxDepth:await summaryStore.getConversationMaxSummaryDepth(conversationId)})));const allowMessageFallback=maxDepths.every(({maxDepth})=>typeof maxDepth==="number"&&maxDepth<=1);if(allowMessageFallback){const messageResult=await retrieval.grep({query:params.query,mode:"full_text",scope:"messages",conversationId:params.conversationId,conversationIds:params.conversationIds});const messageIdsByConversationId=new Map;for(const message of messageResult.messages){const messageIds=messageIdsByConversationId.get(message.conversationId)??[];messageIds.push(message.messageId);messageIdsByConversationId.set(message.conversationId,messageIds)}const leafLinksPerConversation=await Promise.all(Array.from(messageIdsByConversationId.entries()).map(async([conversationId,messageIds])=>summaryStore.getLeafSummaryLinksForMessageIds(conversationId,messageIds)));const leafLinks=leafLinksPerConversation.flat();const messageConversationById=new Map(messageResult.messages.map(message=>[message.messageId,message.conversationId]));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)??[]){const linkedConversationId=messageConversationById.get(message.messageId);if(typeof linkedConversationId!=="number"){continue}upsertSummaryCandidate(candidates,{summaryId,conversationId:linkedConversationId,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});const familyScopedConversationId=(conversationScope.conversationIds?.length??0)>1?void 0:conversationScope.conversationId;let scopedConversationId=familyScopedConversationId;if(!conversationScope.allConversations&&scopedConversationId==null&&(conversationScope.conversationIds?.length??0)<=1&&callerSessionKey){scopedConversationId=await resolveRequesterConversationScopeId({deps:input.deps,requesterSessionKey:callerSessionKey,lcm})}if(!conversationScope.allConversations&&scopedConversationId==null&&(conversationScope.conversationIds?.length??0)<=1){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,conversationIds:conversationScope.conversationIds});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,allowedConversationIds:conversationScope.conversationIds,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}if(typeof query!=="string")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}if(typeof input.query!=="string")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. Regex syntax such as alternation (`A|B`) requires regex mode.'}),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:"Physical conversation ID to search within. If omitted, defaults to the current session family."})),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 findRegexSyntaxInFullTextQuery(pattern){let inQuote=false;let escaped=false;for(let index=0;index<pattern.length;index+=1){const char=pattern[index];const next=pattern[index+1];if(escaped){escaped=false;if(!inQuote&&char&&/[bBdDsSwW]/.test(char)){return"regex character escape"}continue}if(char==="\\"){escaped=true;continue}if(char==='"'){inQuote=!inQuote;continue}if(inQuote){continue}if(char==="|"){return"alternation"}if(char==="."&&(next==="*"||next==="+"||next==="?")){return"wildcard"}if(char==="["){const closing=pattern.indexOf("]",index+1);if(closing>index+1){return"character class"}}if(char==="^"&&(index===0||/\s/.test(pattern[index-1]??""))){return"anchor"}if(char==="$"&&(index===pattern.length-1||/\s/.test(next??""))){return"anchor"}}return null}function validateFullTextPattern(pattern){const syntax=findRegexSyntaxInFullTextQuery(pattern);if(!syntax){return null}return`full_text mode does not support regex syntax (${syntax}). Use mode: "regex" for \`${pattern}\`, or rewrite the full_text query as 1-3 literal terms or one quoted phrase.`}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";if(mode==="full_text"){const fullTextPatternError=validateFullTextPattern(pattern);if(fullTextPatternError){return jsonResult({error:fullTextPatternError})}}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,conversationIds:conversationScope.conversationIds,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){const familyCount=conversationScope.conversationIds?.length??0;lines.push(familyCount>1?`**Conversation scope:** session family rooted at ${conversationScope.conversationId} (${familyCount} segments)`:`**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.11.0",description:"Lossless Context Management plugin for OpenClaw \u2014 DAG-based conversation summarization with threshold 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:"@earendil-works/*" --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/","doctor-contract-api.d.ts","doctor-contract-api.js","skills/","openclaw.plugin.json","docs/","README.md","LICENSE"],dependencies:{"@earendil-works/pi-agent-core":">=0.74 <1","@earendil-works/pi-ai":">=0.74 <1","@earendil-works/pi-coding-agent":">=0.74 <1","@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:">=2026.5.12"},peerDependenciesMeta:{openclaw:{optional:true}},publishConfig:{access:"public"},openclaw:{extensions:["./dist/index.js"],compat:{pluginApi:">=2026.5.12",minGatewayVersion:"2026.5.12",tested:["2026.5.12"]},build:{openclawVersion:"2026.5.12"}},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"}};import crypto5 from"node:crypto";var DEFAULT_FOCUS_BRIEF_TARGET_TOKENS=12e3;var MAX_FOCUS_BRIEF_TARGET_TOKENS=12e3;var FOCUS_BRIEF_TARGET_TOKEN_MULTIPLIER=10;var FOCUS_BRIEF_MINIMUM_TOKEN_RATIO=.6;var MIN_FOCUS_BRIEF_TARGET_TOKENS=12e3;var MIN_FOCUS_BRIEF_TIMEOUT_MS=24e4;var MAX_FOCUS_BRIEF_TIMEOUT_MS=9e5;var FOCUS_BRIEF_TIMEOUT_MS_PER_TARGET_TOKEN=50;function normalizeStringArray(value){if(!Array.isArray(value)){return[]}const seen=new Set;const output=[];for(const item of value){if(typeof item!=="string"){continue}const trimmed=item.trim();if(!trimmed||seen.has(trimmed)){continue}seen.add(trimmed);output.push(trimmed)}return output}function collectFocusFailureText(value,output,depth=0){if(value==null||depth>3){return}if(typeof value==="string"){const trimmed=value.trim();if(trimmed){output.push(trimmed)}return}if(typeof value==="object"){const record=value;for(const key of["message","error","reason","details","response","cause","code"]){collectFocusFailureText(record[key],output,depth+1)}}}function formatFocusGatewayFailure(value,fallback){const parts=[];collectFocusFailureText(value,parts);const message=parts.join(" ").replace(/\s+/g," ").trim();return message||fallback}function normalizeExpansionPrompts(value){if(!Array.isArray(value)){return[]}const output=[];for(const item of value){if(!item||typeof item!=="object"){continue}const record=item;const prompt=typeof record.prompt==="string"?record.prompt.trim():"";if(!prompt){continue}output.push({prompt,summaryIds:normalizeStringArray(record.summaryIds)})}return output}function mergeExpansionPrompts(left,right){const seen=new Set;const output=[];for(const prompt of[...left,...right]){const normalizedPrompt=prompt.prompt.trim();if(!normalizedPrompt){continue}const summaryIds=normalizeStringArray(prompt.summaryIds);const key=`${normalizedPrompt}\0${summaryIds.join("\0")}`;if(seen.has(key)){continue}seen.add(key);output.push({prompt:normalizedPrompt,summaryIds})}return output}function parseFocusBriefReply(rawReply){const reply=rawReply?.trim();if(!reply){throw new Error("Focus brief subagent 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 briefMarkdown=typeof parsed.briefMarkdown==="string"?parsed.briefMarkdown.trim():typeof parsed.brief==="string"?parsed.brief.trim():"";if(!briefMarkdown){throw new Error("Focus brief JSON did not include briefMarkdown.")}return{briefMarkdown,citedSummaryIds:normalizeStringArray(parsed.citedSummaryIds),expandedSummaryIds:normalizeStringArray(parsed.expandedSummaryIds),irrelevantSummaryIds:normalizeStringArray(parsed.irrelevantSummaryIds),expansionPrompts:normalizeExpansionPrompts(parsed.expansionPrompts),confidenceNotes:normalizeStringArray(parsed.confidenceNotes),truncated:parsed.truncated===true,rawResultJson:candidate}}catch{}}throw new Error("Focus brief subagent did not return valid JSON.")}function parseFocusEvidenceReply(rawReply){const reply=rawReply?.trim();if(!reply){throw new Error("Focus evidence subagent 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 evidenceMarkdown=typeof parsed.evidenceMarkdown==="string"?parsed.evidenceMarkdown.trim():"";if(!evidenceMarkdown){throw new Error("Focus evidence JSON did not include evidenceMarkdown.")}return{evidenceMarkdown,citedSummaryIds:normalizeStringArray(parsed.citedSummaryIds),expandedSummaryIds:normalizeStringArray(parsed.expandedSummaryIds),irrelevantSummaryIds:normalizeStringArray(parsed.irrelevantSummaryIds),expansionPrompts:normalizeExpansionPrompts(parsed.expansionPrompts),confidenceNotes:normalizeStringArray(parsed.confidenceNotes),truncated:parsed.truncated===true,rawResultJson:candidate}}catch{}}throw new Error("Focus evidence subagent did not return valid JSON.")}function buildPersistedFocusResultJson(parsed,truncated){if(!parsed.rawResultJson||!truncated){return parsed.rawResultJson}try{const raw=JSON.parse(parsed.rawResultJson);raw.truncated=true;return JSON.stringify(raw)}catch{return parsed.rawResultJson}}function truncatePreview(value,maxChars){const compact=value.replace(/\s+/g," ").trim();if(compact.length<=maxChars){return compact}return`${compact.slice(0,Math.max(0,maxChars-3))}...`}function buildActiveSummaryManifest(summaries){return summaries.map(summary=>{const preview=truncatePreview(summary.content,600);return[`<summary_ref ordinal="${summary.ordinal}" id="${summary.summaryId}" kind="${summary.kind}" depth="${summary.depth}" token_count="${summary.tokenCount}" latest_at="${summary.latestAt??""}" max_source_seq="${summary.maxSourceSeq??""}">`,preview,"</summary_ref>"].join("\n")}).join("\n\n")}function resolveFocusTargetTokens(summaryTokens){if(!Number.isFinite(summaryTokens)||summaryTokens<=0){return DEFAULT_FOCUS_BRIEF_TARGET_TOKENS}const expandedTarget=Math.floor(summaryTokens*FOCUS_BRIEF_TARGET_TOKEN_MULTIPLIER);return Math.min(MAX_FOCUS_BRIEF_TARGET_TOKENS,Math.max(MIN_FOCUS_BRIEF_TARGET_TOKENS,expandedTarget))}function resolveFocusMinimumTokens(targetTokens){return Math.max(1e3,Math.floor(targetTokens*FOCUS_BRIEF_MINIMUM_TOKEN_RATIO))}function resolveFocusExpansionTokenCap(params){const configured=Math.max(1,Math.floor(params.defaultExpandTokens));const summaryDerived=Math.max(configured,Math.floor(params.summaryTokens*10));const targetDerived=Math.max(configured,Math.floor(params.targetTokens*2));return Math.min(12e4,Math.max(configured,summaryDerived,targetDerived,4e4))}function resolveFocusDelegationTimeoutMs(params){const configured=Math.max(1,Math.floor(params.configuredTimeoutMs));const targetDerived=Math.max(1,Math.floor(params.targetTokens*FOCUS_BRIEF_TIMEOUT_MS_PER_TARGET_TOKEN));return Math.min(MAX_FOCUS_BRIEF_TIMEOUT_MS,Math.max(configured,MIN_FOCUS_BRIEF_TIMEOUT_MS,targetDerived))}function buildFocusEvidenceTask(params){const minimumTokens=resolveFocusMinimumTokens(params.targetTokens);return["Gather Lossless focus evidence.","","You are a delegated subagent. Your job is to gather rich, prompt-oriented evidence for a later focus context brief. This is not the final brief.","","Focus prompt:",`<focus_prompt>${params.focusPrompt}</focus_prompt>`,"",`Conversation ID: ${params.conversationId}`,`Target brief length for the later synthesis turn: ${minimumTokens}-${params.targetTokens} tokens`,`Minimum acceptable final brief length: ${minimumTokens} tokens`,`Request ID: ${params.requestId}`,`Origin session key: ${params.originSessionKey}`,"","Evidence density requirements:","- Use this turn to search, inspect, and expand; do not write the final context brief yet.","- Prefer dense, specific working memory over a short overview.","- Include concrete decisions, file paths, command names, issue IDs, summary IDs, constraints, rejected options, unresolved questions, and handoff details when relevant.","- Do not pad with generic prose. Add detail by expanding evidence, recording provenance, and spelling out useful operational context.","","Required recall workflow:","1. Use lcm_grep with mode='full_text', scope='summaries', and this conversationId to discover relevant summaries.","2. Use lcm_describe on promising summary IDs to inspect metadata, parent/child relationships, and expansion costs.","3. Identify the newest summaries that pertain to the focus prompt, using lcm_grep recency ordering, latest_at values, and active summary context.","4. Use lcm_expand directly on high-value summary IDs to recover key details. Expand enough evidence to support a long brief. You are in delegated context, so do NOT call lcm_expand_query.","5. Record synthesis-relevant uncertainty when you only inferred something from summaries.","","Active summary context at generation time:","<active_summary_context>",buildActiveSummaryManifest(params.summaries),"</active_summary_context>","","Return ONLY JSON with this shape:","{",' "evidenceMarkdown": "markdown evidence dossier for later synthesis",',' "citedSummaryIds": ["sum_xxx"],',' "expandedSummaryIds": ["sum_xxx"],',' "irrelevantSummaryIds": ["sum_xxx"],',' "expansionPrompts": [{"prompt": "question to ask later", "summaryIds": ["sum_xxx"]}],',' "confidenceNotes": ["what is expanded evidence vs inferred synthesis"],',' "truncated": false',"}","","The evidenceMarkdown dossier must include:","- Focused Narrative Evidence: chronological, decision-rich source notes.","- Relevant Recent Context: the newest summaries that pertain to the focus prompt, with dates, current state, recency-sensitive decisions, and summary IDs.","- Current Working State Evidence: active branches, files, tests, commands, blockers, and next actions.","- Evidence Map with summary IDs: claims tied to summary IDs and expanded material.","- Expansion Guide with concrete future recall prompts: exact lcm_grep or lcm_expand follow-ups.","- Risks And Gaps: contradictions, stale assumptions, and unknowns.","- Likely Irrelevant Context: brief but explicit, with summary IDs when possible.","- Confidence Notes: separate expanded evidence from inferred synthesis."].join("\n")}function buildFocusSynthesisTask(params){const minimumTokens=resolveFocusMinimumTokens(params.targetTokens);return["Synthesize the final Lossless focus context brief.","","Focus prompt:",`<focus_prompt>${params.focusPrompt}</focus_prompt>`,"",`Target brief length: ${minimumTokens}-${params.targetTokens} tokens`,`Minimum acceptable length: ${minimumTokens} tokens`,"","Instructions:","- Use the evidence dossier below as the primary source material.","- Do not repeat the evidence dossier mechanically; turn it into a rich, task-shaped context brief.","- Use the available budget aggressively. Prefer dense, specific working memory over a short overview.","- Include concrete decisions, file paths, command names, issue IDs, summary IDs, constraints, rejected options, unresolved questions, and handoff details when relevant.","- Do not pad with generic prose. Add detail by preserving evidence, recording provenance, and spelling out useful operational context.","- Do NOT call lcm_expand_query from this delegated context.","","Evidence dossier:","<focus_evidence>",params.evidenceMarkdown,"</focus_evidence>","","Return ONLY JSON with this shape:","{",' "briefMarkdown": "markdown context brief",',' "citedSummaryIds": ["sum_xxx"],',' "expandedSummaryIds": ["sum_xxx"],',' "irrelevantSummaryIds": ["sum_xxx"],',' "expansionPrompts": [{"prompt": "question to ask later", "summaryIds": ["sum_xxx"]}],',' "confidenceNotes": ["what is expanded evidence vs inferred synthesis"],',' "truncated": false',"}","","The markdown brief must include:","- Focused Narrative: about 20% of the brief, chronological and decision-rich.","- Relevant Recent Context: about 20%, covering the newest summaries that pertain to the focus prompt, with dates, current state, recency-sensitive decisions, and summary IDs.","- Current Working State: about 20%, including active branches, files, tests, commands, blockers, and next actions.","- Evidence Map with summary IDs: about 18%, tying claims to summary IDs and expanded material.","- Expansion Guide with concrete future recall prompts: about 12%, including exact lcm_grep or lcm_expand follow-ups.","- Risks And Gaps: about 8%, including contradictions, stale assumptions, and unknowns.","- Likely Irrelevant Context: brief but explicit, with summary IDs when possible.","- Confidence Notes: separate expanded evidence from inferred synthesis."].join("\n")}function buildRefocusEvidenceTask(params){const minimumTokens=resolveFocusMinimumTokens(params.targetTokens);return["Gather Lossless refocus delta evidence.","","You are a delegated subagent. Your job is to evaluate new summary context against an existing Lossless focus brief and gather evidence for a refreshed brief. This is not the final brief.","","Original focus prompt:",`<focus_prompt>${params.focusPrompt}</focus_prompt>`,"",`Conversation ID: ${params.conversationId}`,`Target refreshed brief length for the later synthesis turn: ${minimumTokens}-${params.targetTokens} tokens`,`Minimum acceptable final brief length: ${minimumTokens} tokens`,`Request ID: ${params.requestId}`,`Origin session key: ${params.originSessionKey}`,"","Existing focus brief baseline:","<existing_focus_brief>",params.existingBriefMarkdown,"</existing_focus_brief>","","Delta summary context after the previous focus watermark:","<delta_summary_context>",buildActiveSummaryManifest(params.deltaSummaries),"</delta_summary_context>","","Evidence requirements:","- Treat the existing focus brief as the baseline working memory.","- Evaluate only the delta summaries as possible additions, corrections, or removals.","- Preserve relevant baseline details unless the delta clearly supersedes them.","- Include concrete new decisions, file paths, command names, issue IDs, constraints, test results, deployment details, and next actions when relevant to the original prompt.","- Identify obsolete baseline details if the delta contradicts or supersedes them.","","Required recall workflow:","1. Use lcm_grep with mode='full_text', scope='summaries', and this conversationId to search for delta evidence matching the original focus prompt.","2. Use lcm_describe on promising delta summary IDs to inspect metadata, parent/child relationships, and expansion costs.","3. Use lcm_expand directly on high-value delta summary IDs to recover details. You are in delegated context, so do NOT call lcm_expand_query.","4. Separate genuinely new relevant delta from repeated baseline material.","","Return ONLY JSON with this shape:","{",' "evidenceMarkdown": "markdown delta evidence dossier for later synthesis",',' "citedSummaryIds": ["sum_xxx"],',' "expandedSummaryIds": ["sum_xxx"],',' "irrelevantSummaryIds": ["sum_xxx"],',' "expansionPrompts": [{"prompt": "question to ask later", "summaryIds": ["sum_xxx"]}],',' "confidenceNotes": ["what is expanded evidence vs inferred synthesis"],',' "truncated": false',"}","","The evidenceMarkdown dossier must include:","- Baseline Retained: important existing brief claims that should remain.","- Relevant Delta: new or changed details tied to summary IDs.","- Superseded Or Contradicted Baseline Details: what should be revised or removed.","- Current Working State Delta: active branches, files, tests, commands, blockers, and next actions from new summaries.","- Evidence Map with delta summary IDs.","- Expansion Guide with concrete future recall prompts.","- Irrelevant Delta: new summaries inspected but not relevant to the original prompt.","- Confidence Notes."].join("\n")}function buildRefocusSynthesisTask(params){const minimumTokens=resolveFocusMinimumTokens(params.targetTokens);return["Synthesize the refreshed Lossless focus context brief.","","Original focus prompt:",`<focus_prompt>${params.focusPrompt}</focus_prompt>`,"",`Target refreshed brief length: ${minimumTokens}-${params.targetTokens} tokens`,`Minimum acceptable length: ${minimumTokens} tokens`,"","Existing focus brief baseline:","<existing_focus_brief>",params.existingBriefMarkdown,"</existing_focus_brief>","","Delta evidence dossier:","<refocus_delta_evidence>",params.evidenceMarkdown,"</refocus_delta_evidence>","","Instructions:","- Produce a complete updated focus context brief, not a diff or addendum.","- Preserve useful structure, specificity, and provenance from the existing brief.","- Merge in relevant delta details that match the original focus prompt.","- Remove or rewrite obsolete baseline details when the delta supersedes them.","- Keep summary IDs and future expansion prompts visible for later recall.","- Do NOT call lcm_expand_query from this delegated context.","","Return ONLY JSON with this shape:","{",' "briefMarkdown": "complete refreshed markdown context brief",',' "citedSummaryIds": ["sum_xxx"],',' "expandedSummaryIds": ["sum_xxx"],',' "irrelevantSummaryIds": ["sum_xxx"],',' "expansionPrompts": [{"prompt": "question to ask later", "summaryIds": ["sum_xxx"]}],',' "confidenceNotes": ["what is expanded evidence vs inferred synthesis"],',' "truncated": false',"}"].join("\n")}function buildFocusAgentParams(params){const agentParams={message:params.message,sessionKey:params.childSessionKey,deliver:false,lane:params.deps.agentLaneSubagent,extraSystemPrompt:params.deps.buildSubagentSystemPrompt({depth:1,maxDepth:8,taskSummary:"Generate a Lossless focus brief using lcm_grep, lcm_describe, and lcm_expand."})};const summaryModel=params.deps.config.summaryModel.trim();if(!summaryModel){return agentParams}const summaryProvider=params.deps.config.summaryProvider.trim();if(summaryProvider){agentParams.provider=summaryProvider}agentParams.model=summaryModel;return agentParams}async function runFocusAttempt(params){let runId="";try{const response=await params.deps.callGateway({method:"agent",params:buildFocusAgentParams({deps:params.deps,childSessionKey:params.childSessionKey,message:params.message}),timeoutMs:1e4});runId=typeof response?.runId==="string"?response.runId.trim():"";if(!runId){return{status:"error",runId,error:formatFocusGatewayFailure(response?.error??response,`delegated ${params.phaseName} did not return a runId`)}}const wait=await params.deps.callGateway({method:"agent.wait",params:{runId,timeoutMs:params.timeoutMs},timeoutMs:params.timeoutMs});const status=typeof wait?.status==="string"?wait.status:"error";if(status==="timeout"){return{status:"timeout",runId,error:`delegated ${params.phaseName} timed out`}}if(status!=="ok"){return{status:"error",runId,error:typeof wait?.error==="string"?wait.error:`delegated ${params.phaseName} failed`}}const replyPayload=await params.deps.callGateway({method:"sessions.get",params:{key:params.childSessionKey,limit:80},timeoutMs:1e4});const rawReply=params.deps.readLatestAssistantReply(Array.isArray(replyPayload.messages)?replyPayload.messages:[]);const parsed=params.parseReply(rawReply);return{status:"ok",runId,parsed,tokenCount:estimateTokens(params.estimateText(parsed)),rawReply}}catch(err){return{status:"error",runId,error:err instanceof Error?err.message:String(err)}}}async function runDelegatedFocusWorkflow(params){const targetTokens=resolveFocusTargetTokens(params.summaryTokens);const tokenCap=resolveFocusExpansionTokenCap({summaryTokens:params.summaryTokens,targetTokens,defaultExpandTokens:params.deps.config.maxExpandTokens});const minimumTokens=resolveFocusMinimumTokens(targetTokens);const timeoutMs=resolveFocusDelegationTimeoutMs({configuredTimeoutMs:params.deps.config.delegationTimeoutMs,targetTokens});const requestId=resolveExpansionRequestId(params.requesterSessionKey);const requesterAgentId=params.deps.normalizeAgentId(params.deps.parseAgentSessionKey(params.requesterSessionKey)?.agentId);const childSessionKey=`agent:${requesterAgentId}:subagent:${crypto5.randomUUID()}`;let runId="";createDelegatedExpansionGrant({delegatedSessionKey:childSessionKey,issuerSessionId:params.requesterSessionKey,allowedConversationIds:[params.conversationId],tokenCap,ttlMs:timeoutMs+6e4});stampDelegatedExpansionContext({sessionKey:childSessionKey,requestId,expansionDepth:1,originSessionKey:params.requesterSessionKey,stampedBy:params.stampedBy});try{const evidenceMessage=params.buildEvidenceMessage({targetTokens,requestId,originSessionKey:params.requesterSessionKey});const evidenceAttempt=await runFocusAttempt({deps:params.deps,childSessionKey,message:evidenceMessage,timeoutMs,phaseName:params.evidencePhaseName,parseReply:parseFocusEvidenceReply,estimateText:parsed2=>parsed2.evidenceMarkdown});runId=evidenceAttempt.runId;if(evidenceAttempt.status==="timeout"){return{status:"timeout",runId:evidenceAttempt.runId,childSessionKey,briefMarkdown:"",citedSummaryIds:[],expandedSummaryIds:[],irrelevantSummaryIds:[],expansionPrompts:[],confidenceNotes:[],tokenCount:0,targetTokens,truncated:true,error:evidenceAttempt.error}}if(evidenceAttempt.status!=="ok"){return{status:"error",runId:evidenceAttempt.runId,childSessionKey,briefMarkdown:"",citedSummaryIds:[],expandedSummaryIds:[],irrelevantSummaryIds:[],expansionPrompts:[],confidenceNotes:[],tokenCount:0,targetTokens,truncated:true,error:evidenceAttempt.error}}const attempt=await runFocusAttempt({deps:params.deps,childSessionKey,message:params.buildSynthesisMessage({evidenceMarkdown:evidenceAttempt.parsed.evidenceMarkdown,targetTokens}),timeoutMs,phaseName:params.synthesisPhaseName,parseReply:parseFocusBriefReply,estimateText:parsed2=>parsed2.briefMarkdown});runId=attempt.runId;if(attempt.status!=="ok"){return{status:attempt.status,runId:attempt.runId,childSessionKey,briefMarkdown:"",citedSummaryIds:evidenceAttempt.parsed.citedSummaryIds,expandedSummaryIds:evidenceAttempt.parsed.expandedSummaryIds,irrelevantSummaryIds:evidenceAttempt.parsed.irrelevantSummaryIds,expansionPrompts:evidenceAttempt.parsed.expansionPrompts,confidenceNotes:evidenceAttempt.parsed.confidenceNotes,tokenCount:0,targetTokens,truncated:true,rawResultJson:evidenceAttempt.parsed.rawResultJson,error:attempt.error}}const parsed=attempt.parsed;const stillShort=attempt.tokenCount<minimumTokens;const evidence=evidenceAttempt.parsed;const truncated=evidence.truncated||parsed.truncated;return{status:stillShort?"error":"ok",runId:attempt.runId,childSessionKey,briefMarkdown:parsed.briefMarkdown,citedSummaryIds:normalizeStringArray([...evidence.citedSummaryIds,...parsed.citedSummaryIds]),expandedSummaryIds:normalizeStringArray([...evidence.expandedSummaryIds,...parsed.expandedSummaryIds]),irrelevantSummaryIds:normalizeStringArray([...evidence.irrelevantSummaryIds,...parsed.irrelevantSummaryIds]),expansionPrompts:mergeExpansionPrompts(evidence.expansionPrompts,parsed.expansionPrompts),confidenceNotes:normalizeStringArray([...evidence.confidenceNotes,...parsed.confidenceNotes]),tokenCount:attempt.tokenCount,targetTokens,truncated,rawReply:attempt.rawReply,rawResultJson:buildPersistedFocusResultJson(parsed,truncated),error:stillShort?`Focus brief remained below the ${minimumTokens}-token minimum.`:void 0}}catch(err){return{status:"error",runId:runId||crypto5.randomUUID(),childSessionKey,briefMarkdown:"",citedSummaryIds:[],expandedSummaryIds:[],irrelevantSummaryIds:[],expansionPrompts:[],confidenceNotes:[],tokenCount:0,targetTokens,truncated:true,error:err instanceof Error?err.message:String(err)}}finally{try{await params.deps.callGateway({method:"sessions.delete",params:{key:childSessionKey,deleteTranscript:false},timeoutMs:1e4})}catch{}revokeDelegatedExpansionGrantForSession(childSessionKey,{removeBinding:true});clearDelegatedExpansionContext(childSessionKey)}}async function runDelegatedFocusBrief(params){const summaryTokens=params.summaries.reduce((sum,summary)=>sum+Math.max(0,summary.tokenCount),0);return runDelegatedFocusWorkflow({deps:params.deps,requesterSessionKey:params.requesterSessionKey,conversationId:params.conversationId,summaryTokens,evidencePhaseName:"focus evidence gathering",synthesisPhaseName:"focus brief synthesis",stampedBy:"runDelegatedFocusBrief",buildEvidenceMessage:({targetTokens,requestId,originSessionKey})=>buildFocusEvidenceTask({focusPrompt:params.focusPrompt,conversationId:params.conversationId,summaries:params.summaries,targetTokens,requestId,originSessionKey}),buildSynthesisMessage:({evidenceMarkdown,targetTokens})=>buildFocusSynthesisTask({focusPrompt:params.focusPrompt,evidenceMarkdown,targetTokens})})}async function runDelegatedRefocusBrief(params){const summaryTokens=estimateTokens(params.existingBriefMarkdown)+params.deltaSummaries.reduce((sum,summary)=>sum+Math.max(0,summary.tokenCount),0);return runDelegatedFocusWorkflow({deps:params.deps,requesterSessionKey:params.requesterSessionKey,conversationId:params.conversationId,summaryTokens,evidencePhaseName:"refocus delta evidence gathering",synthesisPhaseName:"refocus brief synthesis",stampedBy:"runDelegatedRefocusBrief",buildEvidenceMessage:({targetTokens,requestId,originSessionKey})=>buildRefocusEvidenceTask({focusPrompt:params.focusPrompt,existingBriefMarkdown:params.existingBriefMarkdown,conversationId:params.conversationId,deltaSummaries:params.deltaSummaries,targetTokens,requestId,originSessionKey}),buildSynthesisMessage:({evidenceMarkdown,targetTokens})=>buildRefocusSynthesisTask({focusPrompt:params.focusPrompt,existingBriefMarkdown:params.existingBriefMarkdown,evidenceMarkdown,targetTokens})})}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
|
|
1078
|
+
LIMIT 1`);let matchedRawIds=0;for(const rawId of candidateRawIds){const row=matchStmt.get(params.conversationId,rawId,rawId,rawId,rawId,rawId,rawId);if(row?.found===1){matchedRawIds+=1}}return{candidateRawIds:candidateRawIds.size,matchedRawIds}}async filterBootstrapReplayMessages(params){if(params.messages.length<3){return params.messages}let replayCandidateLength=0;while(replayCandidateLength<params.messages.length&&isBootstrapReplayCandidateMessage(params.messages[replayCandidateLength])){replayCandidateLength+=1}if(replayCandidateLength<3){return params.messages}const priorMessages=params.priorMessages??(params.sessionFile?await readLeafPathMessages(params.sessionFile):void 0);if(!priorMessages||priorMessages.length===0){return params.messages}const replayCandidates=params.messages.slice(0,replayCandidateLength);const earlierReplayCandidates=(params.priorMessages?priorMessages:priorMessages.slice(0,Math.max(0,priorMessages.length-params.messages.length))).filter(isBootstrapReplayCandidateMessage);if(earlierReplayCandidates.length<3){return params.messages}const incomingSignatures=replayCandidates.map(createBootstrapReplaySignature);const earlierSignatures=earlierReplayCandidates.map(createBootstrapReplaySignature);let replayPrefixLength=0;prefixLoop:for(let candidatePrefixLength=incomingSignatures.length;candidatePrefixLength>=3;candidatePrefixLength-=1){for(let startIndex=0;startIndex<=earlierSignatures.length-candidatePrefixLength;startIndex+=1){let matched=true;for(let offset=0;offset<candidatePrefixLength;offset+=1){if(earlierSignatures[startIndex+offset]!==incomingSignatures[offset]){matched=false;break}}if(matched){replayPrefixLength=candidatePrefixLength;break prefixLoop}}}if(replayPrefixLength>0){this.deps.log.warn(`[lcm] bootstrap replay guard: ${params.source} dropped ${replayPrefixLength}/${params.messages.length} replayed transcript messages for ${params.sessionContext}`)}return replayPrefixLength>0?params.messages.slice(replayPrefixLength):params.messages}async reconcileTranscriptTailForAfterTurn(params){const queueKey=this.resolveSessionQueueKey(params.sessionId,params.sessionKey);return await this.withSessionQueue(queueKey,async()=>{const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){return{importedMessages:0,blockedByImportCap:false,hasOverlap:true}}const checkpoint=await this.summaryStore.getConversationBootstrapState(conversation.conversationId);let sessionFileState;try{const sessionFileStats=await stat(params.sessionFile);sessionFileState={size:sessionFileStats.size,mtimeMs:Math.trunc(sessionFileStats.mtimeMs)}}catch{}const transcriptEpochShrank=checkpointIsPastTranscriptEof(checkpoint,sessionFileState?.size??Number.POSITIVE_INFINITY);if(checkpoint&&checkpoint.sessionFilePath===params.sessionFile&&checkpoint.lastProcessedOffset>=0&&!transcriptEpochShrank){const appended=await readAppendedLeafPathMessages({sessionFile:params.sessionFile,offset:checkpoint.lastProcessedOffset});if(appended.canUseAppendOnly){const placeholderCheckpoint=checkpoint.lastSeenSize===0&&checkpoint.lastSeenMtimeMs===0&&checkpoint.lastProcessedOffset===0&&checkpoint.lastProcessedEntryHash===null;if(placeholderCheckpoint&&appended.messages.length>0){const reconcile2=await this.reconcileSessionTail({sessionId:params.sessionId,sessionKey:params.sessionKey,conversationId:conversation.conversationId,historicalMessages:appended.messages,noAnchorImportReason:"placeholder-checkpoint-recovery"});if(reconcile2.importedMessages>0){this.clearStableOrphanStrippingOrdinal(conversation.conversationId);this.recordRecentBootstrapImport(conversation.conversationId,reconcile2.importedMessages,"reconciled missing session messages");await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile})}return reconcile2}const replayFilteredMessages=await this.filterBootstrapReplayMessages({messages:appended.messages,sessionContext:this.formatSessionLogContext({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey}),source:"afterTurn transcript reconcile append-only",sessionFile:params.sessionFile});let importedMessages=0;for(const message of replayFilteredMessages){const result=await this.ingestSingle({sessionId:params.sessionId,sessionKey:params.sessionKey,message});if(result.ingested){importedMessages+=1}}if(importedMessages>0){this.recordRecentBootstrapImport(conversation.conversationId,importedMessages,"reconciled missing session messages");await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile})}return{importedMessages,blockedByImportCap:false,hasOverlap:true}}}const fullReadKey=`${queueKey}\0${params.sessionFile}`;const reason=!checkpoint?"checkpoint-missing":checkpoint.sessionFilePath!==params.sessionFile?"path-mismatch":transcriptEpochShrank?"same-path-shrink":"append-only-ineligible";if(reason==="same-path-shrink"){this.afterTurnReconcileFullReadStates.delete(fullReadKey)}const rememberedFileState=this.afterTurnReconcileFullReadStates.get(fullReadKey);if(rememberedFileState&&sessionFileState&&rememberedFileState.size===sessionFileState.size&&rememberedFileState.mtimeMs===sessionFileState.mtimeMs){this.deps.log.debug(`[lcm] afterTurn: transcript reconcile slow path skipped (file state already read this process) conversation=${conversation.conversationId} reason=${reason} sessionFile=${params.sessionFile}`);return{importedMessages:0,blockedByImportCap:false,hasOverlap:true}}const rememberSlowReadState=()=>{if(!sessionFileState){return}if(!this.afterTurnReconcileFullReadStates.has(fullReadKey)&&this.afterTurnReconcileFullReadStates.size>=_LcmContextEngine.AFTER_TURN_RECONCILE_KEY_CAP){const oldest=this.afterTurnReconcileFullReadStates.keys().next().value;if(typeof oldest==="string"){this.afterTurnReconcileFullReadStates.delete(oldest)}}this.afterTurnReconcileFullReadStates.set(fullReadKey,sessionFileState)};const slowPathStartedAt=Date.now();const historicalMessages=await readLeafPathMessages(params.sessionFile);if(historicalMessages.length===0){if(!sessionFileState){if(!checkpoint){try{await this.summaryStore.upsertConversationBootstrapState({conversationId:conversation.conversationId,sessionFilePath:params.sessionFile,lastSeenSize:0,lastSeenMtimeMs:0,lastProcessedOffset:0,lastProcessedEntryHash:null})}catch(seedError){this.deps.log.warn(`[lcm] afterTurn: transcript reconcile slow path failed to seed placeholder bootstrap_state conversation=${conversation.conversationId} sessionFile=${params.sessionFile} error=${seedError instanceof Error?seedError.message:String(seedError)}`)}this.deps.log.warn(`[lcm] afterTurn: transcript reconcile slow path could not stat/read transcript; allowing live afterTurn persistence and seeding placeholder bootstrap_state at offset=0 to unblock next-turn recovery conversation=${conversation.conversationId} sessionFile=${params.sessionFile}`)}else{this.deps.log.warn(`[lcm] afterTurn: transcript reconcile slow path could not stat/read transcript; preserving existing checkpoint (offset=${checkpoint.lastProcessedOffset}) instead of reseeding conversation=${conversation.conversationId} sessionFile=${params.sessionFile}`)}return{importedMessages:0,blockedByImportCap:false,hasOverlap:true}}if(sessionFileState.size===0){await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile});rememberSlowReadState()}else{this.deps.log.warn(`[lcm] afterTurn: transcript reconcile slow path read empty messages from non-empty file (${sessionFileState?.size??"?"} bytes) \u2014 skipping checkpoint refresh to avoid dropping messages on parser failure conversation=${conversation.conversationId} sessionFile=${params.sessionFile}`)}return{importedMessages:0,blockedByImportCap:false,hasOverlap:sessionFileState.size===0}}const reconcile=await this.reconcileSessionTail({sessionId:params.sessionId,sessionKey:params.sessionKey,conversationId:conversation.conversationId,historicalMessages,skipContentAnchorScan:reason==="same-path-shrink",allowNoAnchorImport:reason==="path-mismatch"||reason==="same-path-shrink",noAnchorImportReason:reason});if(reconcile.blockedByImportCap){return{importedMessages:0,blockedByImportCap:true,hasOverlap:reconcile.hasOverlap}}if(reconcile.importedMessages>0){this.recordRecentBootstrapImport(conversation.conversationId,reconcile.importedMessages,"reconciled missing session messages")}if(!reconcile.hasOverlap&&reconcile.importedMessages===0){this.deps.log.warn(`[lcm] afterTurn: transcript reconcile found no anchor and imported 0 messages; skipping checkpoint refresh conversation=${conversation.conversationId} reason=${reason} sessionFile=${params.sessionFile} historicalMessages=${historicalMessages.length}`);return{importedMessages:0,blockedByImportCap:false,hasOverlap:false}}await this.refreshBootstrapState({conversationId:conversation.conversationId,sessionFile:params.sessionFile});rememberSlowReadState();this.deps.log.warn(`[lcm] afterTurn: transcript reconcile slow path (full re-read) conversation=${conversation.conversationId} reason=${reason} sessionFile=${params.sessionFile} historicalMessages=${historicalMessages.length} importedMessages=${reconcile.importedMessages} duration=${formatDurationMs(Date.now()-slowPathStartedAt)}`);return{importedMessages:reconcile.importedMessages,blockedByImportCap:false,hasOverlap:reconcile.hasOverlap}},{operationName:"afterTurnTranscriptReconcile",context:[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ")})}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:params.lastProcessedEntryHash!==void 0?params.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,lastProcessedEntryHash)=>{await this.refreshBootstrapState({conversationId:conversationId2,sessionFile:params.sessionFile,fileStats:{size:sessionFileSize,mtimeMs:sessionFileMtimeMs},lastProcessedEntryHash});this.lastFullReadFileState.set(conversationId2,{size:sessionFileSize,mtimeMs:sessionFileMtimeMs})};const normalizedSessionKey=params.sessionKey?.trim();if(normalizedSessionKey){const activeByKey=await this.conversationStore.getConversationBySessionKey(normalizedSessionKey);if(activeByKey&&activeByKey.sessionId!==params.sessionId){const activeBootstrapState=await this.summaryStore.getConversationBootstrapState(activeByKey.conversationId);const trackedSessionFile=activeBootstrapState?.sessionFilePath;let trackedSessionFileMissing=false;if(typeof trackedSessionFile==="string"&&trackedSessionFile.length>0){try{await stat(trackedSessionFile)}catch(err){const code=getErrorCode(err);if(code==="ENOENT"||code==="ENOTDIR"){trackedSessionFileMissing=true}else{this.deps.log.warn(`[lcm] bootstrap: could not verify tracked transcript path conversation=${activeByKey.conversationId} file=${trackedSessionFile} error=${describeLogError(err)}`)}}}const transcriptRotated=typeof trackedSessionFile==="string"&&trackedSessionFile.length>0&&trackedSessionFile!==params.sessionFile;if(transcriptRotated&&trackedSessionFileMissing){this.deps.log.warn(`[lcm] bootstrap: detected reset/rollover without prior lifecycle split; rotating conversation=${activeByKey.conversationId} session=${params.sessionId} sessionKey=${normalizedSessionKey} oldSessionId=${activeByKey.sessionId} oldFile=${trackedSessionFile} newFile=${params.sessionFile}`);await this.applySessionReplacement({reason:"bootstrap session-file rollover fallback",sessionId:activeByKey.sessionId,sessionKey:normalizedSessionKey,nextSessionId:params.sessionId,nextSessionKey:normalizedSessionKey,createReplacement:true})}}}const conversation2=await this.conversationStore.getOrCreateConversation(params.sessionId,{sessionKey:params.sessionKey});const conversationId=conversation2.conversationId;let existingCount=await this.conversationStore.getMessageCount(conversationId);let bootstrapState=await this.summaryStore.getConversationBootstrapState(conversationId);let transcriptEpochRotated=false;let transcriptEpochReason;if(bootstrapState&&bootstrapState.sessionFilePath!==params.sessionFile){transcriptEpochRotated=true;transcriptEpochReason="path-mismatch";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&&checkpointIsPastTranscriptEof(bootstrapState,sessionFileSize)){transcriptEpochRotated=true;transcriptEpochReason="same-path-shrink";this.deps.log.warn(`[lcm] bootstrap: session file shrank past checkpoint conversation=${conversationId} ${sessionLabel} file=${params.sessionFile} checkpointOffset=${bootstrapState.lastProcessedOffset} checkpointSize=${bootstrapState.lastSeenSize} currentSize=${sessionFileSize}`);this.lastFullReadFileState.delete(conversationId);bootstrapState=null}if(bootstrapState&&bootstrapState.sessionFilePath===params.sessionFile&&bootstrapState.lastSeenSize===sessionFileSize&&bootstrapState.lastSeenMtimeMs===sessionFileMtimeMs){if(!conversation2.bootstrappedAt){await this.conversationStore.markConversationBootstrapped(conversationId)}this.deps.log.debug(`[lcm] bootstrap: checkpoint hit conversation=${conversationId} ${sessionLabel} existingCount=${existingCount} duration=${formatDurationMs(Date.now()-startedAt)}`);return{bootstrapped:false,importedMessages:0,reason:conversation2.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(!conversation2.bootstrappedAt){await this.conversationStore.markConversationBootstrapped(conversationId)}const replayFilteredMessages=await this.filterBootstrapReplayMessages({messages:appended.messages,sessionContext:this.formatSessionLogContext({conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey}),source:"bootstrap append-only",sessionFile:params.sessionFile});let importedMessages=0;for(const message of replayFilteredMessages){const ingestResult=await this.ingestSingle({sessionId:params.sessionId,sessionKey:params.sessionKey,message});if(ingestResult.ingested){importedMessages+=1}}await persistBootstrapState(conversationId);this.deps.log.debug(`[lcm] bootstrap: append-only conversation=${conversationId} ${sessionLabel} existingCount=${existingCount} appendedMessages=${appended.messages.length} replayFilteredMessages=${replayFilteredMessages.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:conversation2.bootstrappedAt?"already bootstrapped":"conversation already up to date"}}}}if(conversation2.bootstrappedAt&&existingCount>0){const cached=this.lastFullReadFileState.get(conversationId);if(cached&&cached.size===sessionFileSize&&cached.mtimeMs===sessionFileMtimeMs){await persistBootstrapState(conversationId);this.deps.log.debug(`[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.debug(`[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"}}let importedMessages=0;for(const message of bootstrapMessages){const result2=await this.ingestSingle({sessionId:params.sessionId,sessionKey:params.sessionKey,message,skipReplayTimestampFloodGuard:true});if(result2.ingested){importedMessages+=1}}await this.conversationStore.markConversationBootstrapped(conversationId);let prunedMessages=0;if(this.config.pruneHeartbeatOk){const pruned=await this.pruneHeartbeatOkTurns(conversationId);prunedMessages=pruned;if(pruned>0){this.deps.log.info(`[lcm] bootstrap: pruned ${pruned} HEARTBEAT_OK messages from conversation ${conversationId}`)}}const lastImportedHash=prunedMessages===0&&bootstrapMessages.length>0?createBootstrapEntryHash(toStoredMessage(bootstrapMessages[bootstrapMessages.length-1])):void 0;await persistBootstrapState(conversationId,lastImportedHash);this.deps.log.debug(`[lcm] bootstrap: initial import conversation=${conversationId} ${sessionLabel} importedMessages=${importedMessages} sourceMessages=${historicalMessages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return{bootstrapped:true,importedMessages}}const reconcile=await this.reconcileSessionTail({sessionId:params.sessionId,sessionKey:params.sessionKey,conversationId,historicalMessages,checkpointEntryHash:transcriptEpochReason==="same-path-shrink"?void 0:bootstrapState?.lastProcessedEntryHash,skipContentAnchorScan:transcriptEpochReason==="same-path-shrink",allowNoAnchorImport:transcriptEpochRotated,noAnchorImportReason:transcriptEpochReason});this.deps.log.debug(`[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.blockedReason==="cross-conversation-raw-id"?"reconcile duplicate raw ids":"reconcile import capped"}}if(!conversation2.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(conversation2.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 conversation2=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(conversation2){const pruned=await this.pruneHeartbeatOkTurns(conversation2.conversationId);if(pruned>0){await this.refreshBootstrapState({conversationId:conversation2.conversationId,sessionFile:params.sessionFile});this.deps.log.info(`[lcm] bootstrap: retroactively pruned ${pruned} HEARTBEAT_OK messages from conversation ${conversation2.conversationId}`)}}}catch(err){this.deps.log.warn(`[lcm] bootstrap: heartbeat pruning failed: ${describeLogError(err)}`)}}const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(conversation){this.recordRecentBootstrapImport(conversation.conversationId,result.importedMessages,result.reason??null)}this.deps.log.debug(`[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,options){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)return batch;const lastDbMessage=await this.conversationStore.getLastMessage(conversationId);if(!lastDbMessage)return batch;const storedBatch=batch.map(m=>toStoredMessage(m));if(storedMessageCount>batch.length){return this.deduplicateOversizedBatch(conversationId,batch,storedBatch,storedMessageCount,lastDbMessage,options)}const batchAtBoundary=storedBatch[storedMessageCount-1];if(messageIdentity(lastDbMessage.role,lastDbMessage.content)!==messageIdentity(batchAtBoundary.role,batchAtBoundary.content)){return this.deduplicateSuffixFallback(conversationId,batch,storedBatch,storedMessageCount,"prefix-mismatch")}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 deduplicateOversizedBatch(conversationId,batch,storedBatch,storedMessageCount,lastDbMessage,options){const lastBatchIdentity=messageIdentity(storedBatch[storedBatch.length-1].role,storedBatch[storedBatch.length-1].content);const lastDbIdentity=messageIdentity(lastDbMessage.role,lastDbMessage.content);if(lastDbIdentity===lastBatchIdentity){const storedMessages=await this.conversationStore.getMessages(conversationId,{limit:storedMessageCount});const tailMessages=storedMessages.slice(-batch.length);if(tailMessages.length===batch.length){let tailMatch=true;for(let i=0;i<batch.length;i++){if(messageIdentity(tailMessages[i].role,tailMessages[i].content)!==messageIdentity(storedBatch[i].role,storedBatch[i].content)){tailMatch=false;break}}if(tailMatch){this.deps.log.debug(`[lcm] dedup: tail-match detected, batch already fully stored (storedCount=${storedMessageCount} batchLen=${batch.length}), skipping entire batch`);return[]}}}return this.deduplicateSuffixFallback(conversationId,batch,storedBatch,storedMessageCount,"oversized",{onNoOverlap:options?.oversizedNoOverlap??"skip"})}async deduplicateSuffixFallback(conversationId,batch,storedBatch,storedMessageCount,context,options){const allStored=await this.conversationStore.getMessages(conversationId,{limit:storedMessageCount});if(allStored.length===0)return batch;const lastStoredIdentity=messageIdentity(allStored[allStored.length-1].role,allStored[allStored.length-1].content);for(let k=batch.length-1;k>=0;k--){if(messageIdentity(storedBatch[k].role,storedBatch[k].content)!==lastStoredIdentity){continue}const matchLen=Math.min(k+1,allStored.length);const startDb=allStored.length-matchLen;let suffixMatch=true;for(let j=0;j<matchLen;j++){if(messageIdentity(allStored[startDb+j].role,allStored[startDb+j].content)!==messageIdentity(storedBatch[k-matchLen+1+j].role,storedBatch[k-matchLen+1+j].content)){suffixMatch=false;break}}const newSlice=batch.slice(k+1);if(suffixMatch&&(newSlice.length>0||matchLen>1)){this.deps.log.debug(`[lcm] dedup: ${context} suffix-match at batch[${k}], returning ${newSlice.length} new messages (storedCount=${storedMessageCount} batchLen=${batch.length})`);return newSlice}}if(options?.onNoOverlap==="skip"){this.deps.log.warn(`[lcm] dedup: ${context}, storedCount=${storedMessageCount} batchLen=${batch.length}, no overlap found \u2014 fail-closed skipping full batch`);return[]}this.deps.log.warn(`[lcm] dedup: ${context}, storedCount=${storedMessageCount} batchLen=${batch.length}, no overlap found \u2014 ingesting full batch`);return batch}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){const runRuntimeAutoRotate=async()=>{await this.maybeAutoRotateManagedSessionFile({phase:"runtime",sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile})};if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){await runRuntimeAutoRotate();return{changed:false,bytesFreed:0,rewrittenEntries:0,reason:"session excluded by pattern"}}if(this.isStatelessSession(params.sessionKey)){await runRuntimeAutoRotate();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(" ");const result=await 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);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})();const cappedTokenBudget=this.applyAssemblyBudgetCap(runtimeTokenBudget);const maintainCurrentTokenCount=typeof params.runtimeContext?.currentTokenCount==="number"?Math.floor(params.runtimeContext.currentTokenCount):void 0;if(maintenance?.pending||maintenance?.running){deferredCompactionResult=await this.consumeDeferredCompactionDebt({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:cappedTokenBudget,currentTokenCount:maintainCurrentTokenCount,runtimeContext:params.runtimeContext,legacyParams:asRecord(params.runtimeContext)})}}else if(maintenance?.pending||maintenance?.running){this.deps.log.debug(`[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.debug(`[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.debug(`[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 result2=await rewriteTranscriptEntries({replacements});if(result2.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||result2.changed,bytesFreed:result2.bytesFreed,rewrittenEntries:result2.rewrittenEntries,reason:result2.reason??deferredCompactionResult.reason}:result2;this.deps.log.debug(`[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});await runRuntimeAutoRotate();return result}async ingestSingle(params){const{sessionId,sessionKey,message,isHeartbeat,skipReplayTimestampFloodGuard}=params;if(isHeartbeat){return{ingested:false}}if(!hasPersistableMessageRole(message)){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;const nativeImageIntercepted=await this.interceptNativeImageBlocks({conversationId,message:messageForParts});if(nativeImageIntercepted){messageForParts=nativeImageIntercepted.rewrittenMessage;stored=toStoredMessage(messageForParts)}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 rawPayloadIntercepted=await this.interceptLargeRawPayload({conversationId,message:messageForParts,stored});if(rawPayloadIntercepted){messageForParts=rawPayloadIntercepted.rewrittenMessage;stored=rawPayloadIntercepted.stored}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,skipReplayTimestampFloodGuard});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()=>{return this.conversationStore.withTransaction(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){const runRuntimeAutoRotate=async()=>{await this.maybeAutoRotateManagedSessionFile({phase:"runtime",sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile})};if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){await runRuntimeAutoRotate();return}if(this.isStatelessSession(params.sessionKey)){await runRuntimeAutoRotate();return}this.ensureMigrated();const startedAt=Date.now();const sessionLabel=[`session=${params.sessionId}`,...params.sessionKey?.trim()?[`sessionKey=${params.sessionKey.trim()}`]:[]].join(" ");const newMessages=filterPersistableMessages(params.messages.slice(params.prePromptMessageCount));let transcriptReconcileResult={importedMessages:0,blockedByImportCap:false,hasOverlap:true};try{transcriptReconcileResult=await this.reconcileTranscriptTailForAfterTurn({sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile})}catch(err){this.deps.log.warn(`[lcm] afterTurn: transcript reconcile failed for ${sessionLabel}: ${describeLogError(err)}`)}const transcriptReconcileUnsafeToAdvance=transcriptReconcileResult.blockedByImportCap||!transcriptReconcileResult.hasOverlap&&transcriptReconcileResult.importedMessages===0;let dedupedNewMessages=[];if(transcriptReconcileUnsafeToAdvance){if(newMessages.length>0||params.autoCompactionSummary){this.deps.log.warn(`[lcm] afterTurn: transcript reconcile did not cover the transcript frontier; skipping afterTurn persistence to avoid creating a future anchor past unreconciled transcript history ${sessionLabel}`)}}else{dedupedNewMessages=await this.deduplicateAfterTurnBatch(params.sessionId,params.sessionKey,newMessages,{oversizedNoOverlap:transcriptReconcileResult.importedMessages>0?"ingest":"skip"})}const summaryCoveredMessages=[];const summaryDedupedNewMessages=[];if(params.autoCompactionSummary){for(const message of dedupedNewMessages){if(messageContentCoveredBySummary({message,summary:params.autoCompactionSummary})){summaryCoveredMessages.push(message)}else{summaryDedupedNewMessages.push(message)}}}else{summaryDedupedNewMessages.push(...dedupedNewMessages)}if(summaryCoveredMessages.length>0){this.deps.log.debug(`[lcm] afterTurn: skipped ${summaryCoveredMessages.length} messages already covered by autoCompactionSummary ${sessionLabel}`)}const ingestBatch=[];if(!transcriptReconcileUnsafeToAdvance&¶ms.autoCompactionSummary){ingestBatch.push({role:"user",content:params.autoCompactionSummary})}ingestBatch.push(...summaryDedupedNewMessages);if(ingestBatch.length===0){this.deps.log.debug(`[lcm] afterTurn: nothing to ingest ${sessionLabel} newMessages=${newMessages.length} (continuing to compaction evaluation; transcript reconcile may have already ingested) duration=${formatDurationMs(Date.now()-startedAt)}`)}else{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)}`);this.logAutoRotateSessionFileDecision({phase:"runtime",action:"skip",sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile,thresholdBytes:this.config.autoRotateSessionFiles.sizeBytes,durationMs:0,reason:"ingest-failed",error:describeLogError(err),level:"warn"});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}`);await runRuntimeAutoRotate();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 estimatedContextTokens=estimateSessionTokenCountForAfterTurn(params.messages);const runtimePromptTokens=extractRuntimePromptTokenCount(asRecord(params.runtimeContext));const suppliedCurrentTokenCount=this.normalizeObservedTokenCount((legacyParams??{}).currentTokenCount);const observedCurrentTokenCount=runtimePromptTokens??suppliedCurrentTokenCount??estimatedContextTokens;if(runtimePromptTokens!==void 0){this.deps.log.debug(`[lcm] afterTurn: using runtime prompt token count currentTokenCount=${runtimePromptTokens} estimatedTokenCount=${estimatedContextTokens}`)}const conversation=await this.conversationStore.getConversationForSession({sessionId:params.sessionId,sessionKey:params.sessionKey});if(!conversation){this.deps.log.debug(`[lcm] afterTurn: conversation lookup missed ${sessionLabel} ingestBatch=${ingestBatch.length} duration=${formatDurationMs(Date.now()-startedAt)}`);await runRuntimeAutoRotate();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:observedCurrentTokenCount})}catch(err){this.deps.log.warn(`[lcm] afterTurn: failed to persist deferred compaction retry for ${sessionLabel}: ${describeLogError(err)}`)}};let shouldRefreshBootstrapState=!transcriptReconcileResult.blockedByImportCap&&(transcriptReconcileResult.hasOverlap||transcriptReconcileResult.importedMessages>0);let deferredCompactionDrain=null;try{await this.updateCompactionTelemetry({conversationId:conversation.conversationId,runtimeContext:legacyParams,tokenBudget})}catch(err){this.deps.log.warn(`[lcm] afterTurn: compaction telemetry update failed: ${describeLogError(err)}`)}try{const thresholdDecision=await this.compaction.evaluate(conversation.conversationId,tokenBudget,observedCurrentTokenCount);if(this.config.proactiveThresholdCompactionMode==="inline"){if(thresholdDecision.shouldCompact){const compactResult=await this.compact({sessionId:params.sessionId,sessionKey:params.sessionKey,sessionFile:params.sessionFile,tokenBudget,currentTokenCount:observedCurrentTokenCount,compactionTarget:"threshold",legacyParams});if(!compactResult.ok){shouldRefreshBootstrapState=false;await recordAfterTurnCompactionRetry("threshold")}}}else if(thresholdDecision.shouldCompact){await this.recordDeferredCompactionDebt({conversationId:conversation.conversationId,reason:"threshold",tokenBudget,currentTokenCount:observedCurrentTokenCount});deferredCompactionDrain={tokenBudget,currentTokenCount:observedCurrentTokenCount,reason:"threshold"}}}catch(err){this.deps.log.warn(`[lcm] afterTurn: compaction policy check failed for ${sessionLabel}: ${describeLogError(err)}`)}if(shouldRefreshBootstrapState){await refreshAfterTurnBootstrapState()}if(deferredCompactionDrain){this.scheduleDeferredCompactionDebtDrain({conversationId:conversation.conversationId,sessionId:params.sessionId,sessionKey:params.sessionKey,tokenBudget:deferredCompactionDrain.tokenBudget,currentTokenCount:deferredCompactionDrain.currentTokenCount,reason:deferredCompactionDrain.reason})}this.deps.log.debug(`[lcm] afterTurn: done conversation=${conversation.conversationId} ${sessionLabel} newMessages=${newMessages.length} dedupedMessages=${dedupedNewMessages.length} ingestedMessages=${ingestBatch.length} duration=${formatDurationMs(Date.now()-startedAt)}`);await runRuntimeAutoRotate()}async assemble(params){const safeFallback=()=>{const msgs=params.messages.slice();while(msgs.length>0&&msgs[msgs.length-1]?.role==="assistant"){msgs.pop()}return{messages:msgs,estimatedTokens:0}};if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){return safeFallback()}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.debug(`[lcm] assemble: conversation lookup missed ${sessionLabel} duration=${formatDurationMs(Date.now()-startedAt)}`);return safeFallback()}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.debug(`[lcm] assemble: no context items conversation=${conversation.conversationId} ${sessionLabel} duration=${formatDurationMs(Date.now()-startedAt)}`);return safeFallback()}const hasSummaryItems=contextItems.some(item=>item.itemType==="summary");if(!hasSummaryItems&&contextItems.length<params.messages.length){this.deps.log.debug(`[lcm] assemble: falling back to live context conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} liveMessages=${params.messages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return safeFallback()}const assembled=await this.assembler.assemble({conversationId:conversation.conversationId,tokenBudget,freshTailCount:this.config.freshTailCount,freshTailMaxTokens:this.config.freshTailMaxTokens,promptAwareEviction:this.config.promptAwareEviction,prompt:params.prompt,stubLargeToolPayloads:this.config.stubLargeToolPayloads});if(assembled.messages.length===0&¶ms.messages.length>0){this.deps.log.debug(`[lcm] assemble: empty assembled output, using live context conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} tokenBudget=${tokenBudget} duration=${formatDurationMs(Date.now()-startedAt)}`);return safeFallback()}const assembledHasUserTurn=assembled.messages.some(m=>m.role==="user");if(!assembledHasUserTurn&¶ms.messages.length>0){this.deps.log.debug(`[lcm] assemble: assembled context has no user turns, falling back to live context to prevent prefill errors conversation=${conversation.conversationId} ${sessionLabel} assembledMessages=${assembled.messages.length} duration=${formatDurationMs(Date.now()-startedAt)}`);return safeFallback()}const volatileLiveInputAppend=appendUncoveredVolatileLiveInputsWithinBudget({assembledMessages:assembled.messages,assembledEstimatedTokens:assembled.estimatedTokens,liveMessages:params.messages,protectedAssembledIndexes:resolveProtectedFreshTailAssembledIndexes({assembledMessages:assembled.messages,freshTailMessageHashes:assembled.debug?.freshTailProtectionMessageHashes??assembled.debug?.preSanitizeFreshTailMessageHashes}),tokenBudget});if(volatileLiveInputAppend.appendedMessages>0){this.deps.log.warn(`[lcm] assemble: appended unpersisted volatile live input conversation=${conversation.conversationId} ${sessionLabel} appendedMessages=${volatileLiveInputAppend.appendedMessages} appendedTokens=${volatileLiveInputAppend.appendedTokens} evictedMessages=${volatileLiveInputAppend.evictedMessages} evictedTokens=${volatileLiveInputAppend.evictedTokens} overBudget=${volatileLiveInputAppend.overBudget}`)}const stubStatsLog=assembled.debug?.stubStats?` stubbed=${assembled.debug.stubStats.stubbedCount} tokensSaved=${assembled.debug.stubStats.tokensSaved}`:"";const activeFocusBrief=await this.focusBriefStore.getActiveFocusBrief(conversation.conversationId);const contextProjectionEpoch=buildContextEngineProjectionEpoch(conversation.conversationId,contextItems,activeFocusBrief);const summaryContextItems=contextItems.filter(item=>item.itemType==="summary").length;const volatileLiveInputLog=volatileLiveInputAppend.appendedMessages>0?` volatileLiveInputsAppended=${volatileLiveInputAppend.appendedMessages} volatileLiveInputEvicted=${volatileLiveInputAppend.evictedMessages} volatileLiveInputOverBudget=${volatileLiveInputAppend.overBudget}`:"";this.deps.log.info(`[lcm] assemble: done conversation=${conversation.conversationId} ${sessionLabel} contextItems=${contextItems.length} summaryContextItems=${summaryContextItems} hasSummaryItems=${hasSummaryItems} inputMessages=${params.messages.length} outputMessages=${volatileLiveInputAppend.messages.length} tokenBudget=${tokenBudget} estimatedTokens=${volatileLiveInputAppend.estimatedTokens} contextProjectionMode=thread_bootstrap contextProjectionEpoch=${contextProjectionEpoch}${stubStatsLog}${volatileLiveInputLog} duration=${formatDurationMs(Date.now()-startedAt)}`);const prefixChange=describeAssembledPrefixChange(this.getPreviousAssembledSnapshot(conversation.conversationId),volatileLiveInputAppend.messages);this.setPreviousAssembledSnapshot(conversation.conversationId,prefixChange.currentSnapshot);if(assembled.debug){const promotedOrdinals=assembled.debug.promotedOrdinals.length>0?assembled.debug.promotedOrdinals.join(","):"none";const overflowDiagnostics=shouldLogOverflowDiagnostics({diagnostics:assembled.debug.overflowDiagnostics,assembledTokens:assembled.estimatedTokens,liveContextTokens})?` overflowDiagnostics=${formatOverflowDiagnosticsForLog({diagnostics:assembled.debug.overflowDiagnostics,recentBootstrapImport:this.recentBootstrapImportsByConversation.get(conversation.conversationId)})}`:"";this.deps.log.debug(`[lcm] assemble-debug conversation=${conversation.conversationId} ${sessionLabel} messagesHash=${assembled.debug.finalMessagesHash} preSanitizeHash=${assembled.debug.preSanitizeMessagesHash} previousAssembledCount=${prefixChange.previousCount} commonPrefixCount=${prefixChange.commonPrefixCount} commonPrefixHash=${prefixChange.commonPrefixHash} previousWasPrefix=${prefixChange.previousWasPrefix} firstDivergenceIndex=${prefixChange.firstDivergenceIndex} previousDivergenceMessage=${prefixChange.previousDivergenceMessage} currentDivergenceMessage=${prefixChange.currentDivergenceMessage} evictableCount=${assembled.debug.preSanitizeEvictableCount} evictableHash=${assembled.debug.preSanitizeEvictableHash} freshTailSegmentCount=${assembled.debug.preSanitizeFreshTailCount} freshTailSegmentHash=${assembled.debug.preSanitizeFreshTailHash} selectionMode=${assembled.debug.selectionMode} freshTailOrdinal=${assembled.debug.freshTailOrdinal} orphanStrippingOrdinal=${assembled.debug.orphanStrippingOrdinal} baseFreshTailCount=${assembled.debug.baseFreshTailCount} freshTailCount=${assembled.debug.freshTailCount} tailTokens=${assembled.debug.tailTokens} remainingBudget=${assembled.debug.remainingBudget} evictableTotalTokens=${assembled.debug.evictableTotalTokens} promotedToolResults=${assembled.debug.promotedToolResultCount} promotedOrdinals=${promotedOrdinals} removedToolUseBlocks=${assembled.debug.removedToolUseBlockCount} touchedAssistantMessages=${assembled.debug.touchedAssistantMessageCount}${overflowDiagnostics}`)}const result={messages:volatileLiveInputAppend.messages,estimatedTokens:volatileLiveInputAppend.estimatedTokens,contextProjection:{mode:"thread_bootstrap",epoch:contextProjectionEpoch}};return result}catch(err){this.deps.log.debug(`[lcm] assemble: failed for session=${params.sessionId}${params.sessionKey?.trim()?` sessionKey=${params.sessionKey.trim()}`:""} error=${describeLogError(err)}`);return safeFallback()}}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):4e4;return{shouldCompact:false,rawTokensOutsideTail:0,threshold:fallbackThreshold}}return this.compaction.evaluateLeafTrigger(conversation.conversationId)}async compact(params){if(this.shouldIgnoreSession({sessionId:params.sessionId,sessionKey:params.sessionKey})){this.deps.log.info(`[lcm] compact: skipped session=${params.sessionId}${params.sessionKey?.trim()?` sessionKey=${params.sessionKey.trim()}`:""} reason=session_excluded`);return{ok:true,compacted:false,reason:"session excluded"}}if(this.isStatelessSession(params.sessionKey)){this.deps.log.info(`[lcm] compact: skipped session=${params.sessionId}${params.sessionKey?.trim()?` sessionKey=${params.sessionKey.trim()}`:""} reason=stateless_session`);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){this.deps.log.info(`[lcm] compact: skipped session=${params.sessionId}${params.sessionKey?.trim()?` sessionKey=${params.sessionKey.trim()}`:""} reason=no_conversation_found`);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"||reason==="restart"||reason==="shutdown"){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})}))}getAutoRotateSessionFileMode(phase){return phase==="startup"?this.config.autoRotateSessionFiles.startup:this.config.autoRotateSessionFiles.runtime}logAutoRotateSessionFileDecision(params){const fields=[["phase",params.phase],["action",params.action],["sessionId",params.sessionId],["sessionKey",params.sessionKey],["conversationId",params.conversationId],["sessionFile",params.sessionFile],["sizeBytes",params.sizeBytes],["thresholdBytes",params.thresholdBytes],["durationMs",params.durationMs],["backupPath",params.backupPath],["bytesRemoved",params.bytesRemoved],["preservedTailMessageCount",params.preservedTailMessageCount],["checkpointSize",params.checkpointSize],["currentMessageCount",params.currentMessageCount],["scanned",params.scanned],["eligible",params.eligible],["rotated",params.rotated],["warned",params.warned],["skipped",params.skipped],["backupCreated",params.backupCreated],["reason",params.reason],["error",params.error]];const rendered=fields.filter(entry=>entry[1]!==void 0).map(([key,value])=>`${key}=${String(value).replace(/\s+/g,"_")}`).join(" ");const level=params.level??"info";this.deps.log[level](`[lcm] auto-rotate: ${rendered}`)}async maybeAutoRotateManagedSessionFile(params){const startedAt=Date.now();const thresholdBytes=this.config.autoRotateSessionFiles.sizeBytes;const sessionId=params.sessionId?.trim();const sessionKey=params.sessionKey?.trim();const sessionFile=params.sessionFile?.trim();const baseLog={phase:params.phase,sessionId,sessionKey,conversationId:params.conversationId,sessionFile,thresholdBytes};const skip=(reason,sizeBytes2)=>{this.logAutoRotateSessionFileDecision({...baseLog,action:"skip",sizeBytes:sizeBytes2,durationMs:Date.now()-startedAt,reason})};if(!this.config.autoRotateSessionFiles.enabled){skip("disabled");return}const mode=this.getAutoRotateSessionFileMode(params.phase);if(mode==="off"){skip("mode-off");return}if(!this.info.ownsCompaction){skip("engine-unhealthy");return}if(!sessionId||!sessionKey){skip("missing-session-identity");return}if(!sessionFile){skip("missing-session-file");return}if(this.shouldIgnoreSession({sessionId,sessionKey})){skip("session-excluded");return}if(this.isStatelessSession(sessionKey)){skip("stateless-session");return}let sizeBytes;try{sizeBytes=(await stat(sessionFile)).size}catch(error){this.logAutoRotateSessionFileDecision({...baseLog,action:"warn",durationMs:Date.now()-startedAt,reason:"session-file-stat-failed",error:describeLogError(error),level:"warn"});return}if(sizeBytes<=thresholdBytes){this.oversizedAutoRotateCheckpointByQueueKey.delete(this.resolveSessionQueueKey(sessionId,sessionKey));skip("below-threshold",sizeBytes);return}let conversation;try{conversation=params.conversationId!==void 0?await this.conversationStore.getConversation(params.conversationId):await this.conversationStore.getConversationForSession({sessionId,sessionKey})}catch(error){this.logAutoRotateSessionFileDecision({...baseLog,action:"warn",sizeBytes,durationMs:Date.now()-startedAt,reason:"conversation-lookup-failed",error:describeLogError(error),level:"warn"});return}if(!conversation?.active){skip("no-active-conversation",sizeBytes);return}const queueKey=this.resolveSessionQueueKey(sessionId,sessionKey);const previousOversizedCheckpoint=this.oversizedAutoRotateCheckpointByQueueKey.get(queueKey);if(previousOversizedCheckpoint!==void 0&&sizeBytes<previousOversizedCheckpoint+thresholdBytes){skip("previous-rotate-left-file-over-threshold",sizeBytes);return}if(mode==="warn"){this.logAutoRotateSessionFileDecision({...baseLog,action:"warn",conversationId:conversation.conversationId,sizeBytes,durationMs:Date.now()-startedAt,reason:"above-threshold",level:"warn"});return}let result;try{result=this.config.autoRotateSessionFiles.createBackups?await this.rotateSessionStorageWithBackup({sessionId,sessionKey,sessionFile,lockTimeoutMs:AUTO_ROTATE_DATABASE_LOCK_TIMEOUT_MS}):await this.rotateSessionStorage({sessionId,sessionKey,sessionFile})}catch(error){this.logAutoRotateSessionFileDecision({...baseLog,action:"warn",conversationId:conversation.conversationId,sizeBytes,durationMs:Date.now()-startedAt,reason:"rotate-threw",error:describeLogError(error),level:"warn"});return}if(result.kind==="rotated"){if(result.checkpointSize>=thresholdBytes){this.oversizedAutoRotateCheckpointByQueueKey.set(queueKey,result.checkpointSize)}else{this.oversizedAutoRotateCheckpointByQueueKey.delete(queueKey)}const conversationId="currentConversationId"in result?result.currentConversationId:result.conversationId;this.logAutoRotateSessionFileDecision({...baseLog,action:"rotate",conversationId,sizeBytes,durationMs:Date.now()-startedAt,backupPath:"backupPath"in result?result.backupPath:void 0,bytesRemoved:result.bytesRemoved,preservedTailMessageCount:result.preservedTailMessageCount,checkpointSize:result.checkpointSize,currentMessageCount:"currentMessageCount"in result?result.currentMessageCount:void 0});return}this.logAutoRotateSessionFileDecision({...baseLog,action:"warn",conversationId:"currentConversationId"in result?result.currentConversationId??conversation.conversationId:conversation.conversationId,sizeBytes,durationMs:Date.now()-startedAt,backupPath:"backupPath"in result?result.backupPath:void 0,currentMessageCount:"currentMessageCount"in result?result.currentMessageCount:void 0,reason:result.kind,error:result.reason,level:"warn"})}logStartupAutoRotateSummary(params){this.logAutoRotateSessionFileDecision({phase:"startup",action:"summary",thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,scanned:params.scanned,eligible:params.eligible,rotated:params.rotated,warned:params.warned,skipped:params.skipped,backupPath:params.backupPath,bytesRemoved:params.bytesRemoved,backupCreated:params.backupCreated,reason:params.reason})}async prepareStartupAutoRotateCandidate(params){const sessionId=params.candidate.sessionId?.trim();const sessionKey=params.candidate.sessionKey?.trim();const sessionFile=params.candidate.sessionFile?.trim();if(!sessionId||!sessionKey||!sessionFile){return{kind:"skipped"}}if(this.shouldIgnoreSession({sessionId,sessionKey})||this.isStatelessSession(sessionKey)){return{kind:"skipped"}}let conversation;try{conversation=await this.conversationStore.getConversationForSession({sessionId,sessionKey})}catch(error){this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",sessionId,sessionKey,sessionFile,thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"conversation-lookup-failed",error:describeLogError(error),level:"warn"});return{kind:"warned"}}if(!conversation?.active){return{kind:"skipped"}}const bootstrapState=await this.summaryStore.getConversationBootstrapState(conversation.conversationId);const bootstrapPath=bootstrapState?.sessionFilePath?.trim();if(!bootstrapPath||normalizeSessionFilePathForComparison(bootstrapPath)!==normalizeSessionFilePathForComparison(sessionFile)){return{kind:"skipped"}}let sizeBytes;try{sizeBytes=(await stat(sessionFile)).size}catch(error){if(isMissingFileError(error)){return{kind:"skipped"}}this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",sessionId,sessionKey,conversationId:conversation.conversationId,sessionFile,thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"session-file-stat-failed",error:describeLogError(error),level:"warn"});return{kind:"warned"}}if(sizeBytes<=params.thresholdBytes){this.oversizedAutoRotateCheckpointByQueueKey.delete(this.resolveSessionQueueKey(sessionId,sessionKey));return{kind:"skipped"}}return{kind:"eligible",candidate:{sessionId,sessionKey,sessionFile,conversationId:conversation.conversationId,sizeBytes,currentMessageCount:await this.conversationStore.getMessageCount(conversation.conversationId)}}}async withStartupAutoRotateSessionQueues(candidates,operation){const queueKeys=Array.from(new Set(candidates.map(candidate=>this.resolveSessionQueueKey(candidate.sessionId,candidate.sessionKey)))).sort();const enter=async index=>{if(index>=queueKeys.length){return operation()}return this.withSessionQueue(queueKeys[index],()=>enter(index+1))};return enter(0)}async rotateStartupAutoRotateBatch(params){const empty=()=>({rotated:0,warned:0,bytesRemoved:0,backupCreated:0});if(params.candidates.length===0){return empty()}try{return await this.withStartupAutoRotateSessionQueues(params.candidates,async()=>withExclusiveDatabaseLock(this.db,{timeoutMs:AUTO_ROTATE_DATABASE_LOCK_TIMEOUT_MS},async()=>{if(this.db.isTransaction){this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"database-transaction-active",level:"warn"});return{...empty(),warned:1}}let backupPath;let backupCreated=0;if(this.config.autoRotateSessionFiles.createBackups){try{backupPath=createLcmDatabaseBackup(this.db,{databasePath:this.config.databasePath,label:"rotate",replaceLatest:true})??void 0}catch(error){this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"backup-failed",error:describeLogError(error),level:"warn"});return{...empty(),warned:1}}if(!backupPath){this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"backup-unavailable",level:"warn"});return{...empty(),warned:1}}backupCreated=1}const result={rotated:0,warned:0,bytesRemoved:0,backupPath,backupCreated};for(const candidate of params.candidates){let rotateResult;try{rotateResult=await this.rotateSessionStorageWhileHoldingDatabaseLock({sessionId:candidate.sessionId,sessionKey:candidate.sessionKey,sessionFile:candidate.sessionFile})}catch(error){result.warned+=1;this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",sessionId:candidate.sessionId,sessionKey:candidate.sessionKey,conversationId:candidate.conversationId,sessionFile:candidate.sessionFile,sizeBytes:candidate.sizeBytes,thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,backupPath,currentMessageCount:candidate.currentMessageCount,reason:"rotate-threw",error:describeLogError(error),level:"warn"});continue}if(rotateResult.kind==="unavailable"){result.warned+=1;this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",sessionId:candidate.sessionId,sessionKey:candidate.sessionKey,conversationId:candidate.conversationId,sessionFile:candidate.sessionFile,sizeBytes:candidate.sizeBytes,thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,backupPath,currentMessageCount:candidate.currentMessageCount,reason:"unavailable",error:rotateResult.reason,level:"warn"});continue}result.rotated+=1;result.bytesRemoved+=rotateResult.bytesRemoved;const queueKey=this.resolveSessionQueueKey(candidate.sessionId,candidate.sessionKey);if(rotateResult.checkpointSize>=params.thresholdBytes){this.oversizedAutoRotateCheckpointByQueueKey.set(queueKey,rotateResult.checkpointSize)}else{this.oversizedAutoRotateCheckpointByQueueKey.delete(queueKey)}this.logAutoRotateSessionFileDecision({phase:"startup",action:"rotate",sessionId:candidate.sessionId,sessionKey:candidate.sessionKey,conversationId:rotateResult.conversationId,sessionFile:candidate.sessionFile,sizeBytes:candidate.sizeBytes,thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,backupPath,bytesRemoved:rotateResult.bytesRemoved,preservedTailMessageCount:rotateResult.preservedTailMessageCount,checkpointSize:rotateResult.checkpointSize,currentMessageCount:candidate.currentMessageCount})}return result}))}catch(error){if(error instanceof DatabaseTransactionTimeoutError){this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",thresholdBytes:params.thresholdBytes,durationMs:Date.now()-params.startedAt,reason:"database-lock-timeout",error:describeLogError(error),level:"warn"});return{...empty(),warned:1}}throw error}}async autoRotateManagedSessionFilesAtStartup(){const startedAt=Date.now();const thresholdBytes=this.config.autoRotateSessionFiles.sizeBytes;const mode=this.getAutoRotateSessionFileMode("startup");const summary={scanned:0,eligible:0,rotated:0,warned:0,skipped:0,bytesRemoved:0,backupPath:void 0,backupCreated:0};const logSummary=reason=>this.logStartupAutoRotateSummary({startedAt,thresholdBytes,...summary,reason});if(!this.config.autoRotateSessionFiles.enabled||mode==="off"){logSummary(this.config.autoRotateSessionFiles.enabled?"mode-off":"disabled");return}if(!this.info.ownsCompaction){logSummary("engine-unhealthy");return}if(!this.deps.listStartupSessionFileCandidates){logSummary("no-indexed-session-provider");return}this.ensureMigrated();let indexedCandidates;try{indexedCandidates=await this.deps.listStartupSessionFileCandidates()}catch(error){summary.warned+=1;this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",thresholdBytes,durationMs:Date.now()-startedAt,reason:"candidate-scan-failed",error:describeLogError(error),level:"warn"});logSummary("candidate-scan-failed");return}const rotateCandidates=[];for(const candidate of indexedCandidates){summary.scanned+=1;const prepared=await this.prepareStartupAutoRotateCandidate({candidate,startedAt,thresholdBytes});if(prepared.kind==="eligible"){summary.eligible+=1;if(mode==="warn"){summary.warned+=1;this.logAutoRotateSessionFileDecision({phase:"startup",action:"warn",sessionId:prepared.candidate.sessionId,sessionKey:prepared.candidate.sessionKey,conversationId:prepared.candidate.conversationId,sessionFile:prepared.candidate.sessionFile,sizeBytes:prepared.candidate.sizeBytes,thresholdBytes,durationMs:Date.now()-startedAt,currentMessageCount:prepared.candidate.currentMessageCount,reason:"above-threshold",level:"warn"})}else{rotateCandidates.push(prepared.candidate)}}else if(prepared.kind==="warned"){summary.warned+=1}else{summary.skipped+=1}}const batch=await this.rotateStartupAutoRotateBatch({candidates:rotateCandidates,startedAt,thresholdBytes});summary.rotated+=batch.rotated;summary.warned+=batch.warned;summary.bytesRemoved+=batch.bytesRemoved;summary.backupPath=batch.backupPath;summary.backupCreated+=batch.backupCreated;logSummary("completed")}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}getFocusBriefStore(){return this.focusBriefStore}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,conversationIds:[explicitConversationId],allConversations:false}}if(params.allConversations===true){return{conversationId:void 0,conversationIds:void 0,allConversations:true}}const normalizedSessionKey=input.sessionKey?.trim();if(normalizedSessionKey){const bySessionKey=await lcm.getConversationStore().getConversationBySessionKey(normalizedSessionKey);if(bySessionKey){const familyIds2=typeof lcm.getConversationStore().getConversationFamilyIds==="function"?await lcm.getConversationStore().getConversationFamilyIds({conversationId:bySessionKey.conversationId,sessionKey:normalizedSessionKey}):[bySessionKey.conversationId];return{conversationId:bySessionKey.conversationId,conversationIds:familyIds2.length>0?familyIds2:[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,conversationIds:void 0,allConversations:false}}const conversation=await lookupConversationForSession({lcm,sessionId:normalizedSessionId,sessionKey:input.sessionKey});if(!conversation){return{conversationId:void 0,conversationIds:void 0,allConversations:false}}const store=lcm.getConversationStore();const familyIds=typeof store.getConversationFamilyIds==="function"?await store.getConversationFamilyIds({conversationId:conversation.conversationId,sessionId:normalizedSessionId,sessionKey:input.sessionKey}):[conversation.conversationId];return{conversationId:conversation.conversationId,conversationIds:familyIds.length>0?familyIds:[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:"Physical conversation ID to scope describe lookups to. If omitted, uses the current session family."})),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})),expandFile:Type.Optional(Type.Boolean({description:"When true (and target is a file_xxx), inline the file's content from disk. Combined with the file's exploration_summary, this is how an agent recovers the original output of an elided tool result that was replaced with a [LCM Tool Output: file_xxx | tool=\u2026 | N bytes] reference. Capped at expandFileMaxBytes (default 32768 = ~8K tokens). Returns content + contentTruncated boolean. Use lcm_grep to search across the full file when it exceeds the cap."})),expandFileMaxBytes:Type.Optional(Type.Number({description:"Max bytes of inlined file content when expandFile=true. Default 32768. Hard cap 512000.",minimum:1024,maximum:512e3}))});function normalizeRequestedTokenCap(value){if(typeof value!=="number"||!Number.isFinite(value)){return void 0}return Math.max(1,Math.trunc(value))}function compactDescribeDetails(result){if(!result){return result}if(result.type==="summary"&&result.summary){const{content:_content,subtree:_subtree,...summary}=result.summary;return{id:result.id,type:result.type,summary}}if(result.type==="file"&&result.file){const{explorationSummary:_explorationSummary,...file}=result.file;return{id:result.id,type:result.type,file:{...file,hasExplorationSummary:Boolean(result.file.explorationSummary)}}}return{id:result.id,type:result.type}}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. ALSO USE THIS when you see a `[LCM Tool Output: file_xxx | tool=\u2026 | N bytes]` reference in the conversation \u2014 that means an older tool result was elided for context efficiency. Call lcm_describe(id=file_xxx, expandFile=true) to fetch the original output content before answering questions that depend on its specifics.",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 expandFile=p.expandFile===true;const expandFileMaxBytes=typeof p.expandFileMaxBytes==="number"&&Number.isFinite(p.expandFileMaxBytes)?p.expandFileMaxBytes:void 0;const result=await retrieval.describe(id,{expandFile,expandFileMaxBytes,largeFilesDir:lcm.configView?.largeFilesDir});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;const allowedConversationIds=new Set((conversationScope.conversationIds?.length??0)>0?conversationScope.conversationIds:conversationScope.conversationId!=null?[conversationScope.conversationId]:[]);if(itemConversationId!=null&&!allowedConversationIds.has(itemConversationId)){return jsonResult({error:`Not found in this session scope: ${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:{...compactDescribeDetails(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.*")}if(typeof f.content==="string"){lines.push("");lines.push("## Content");lines.push("");lines.push("```");lines.push(f.content);lines.push("```");if(f.contentTruncated){lines.push("");lines.push(`*Output truncated to ${f.content.length.toLocaleString()} of ${f.byteSize?.toLocaleString()??"?"} bytes. Use lcm_grep against the file id to search the full content.*`)}}else if(expandFile){lines.push("");lines.push("*Content unavailable: file missing on disk or path failed validation.*")}return{content:[{type:"text",text:lines.join("\n")}],details:compactDescribeDetails(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.debug(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:"Physical conversation ID to scope expansion to. If omitted, uses the current session family."})),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","not allowed for agent","not allowlisted for plugin","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"` for short literal terms, use `mode: "regex"` for alternation or other regex syntax, 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 the total source tokens consumed for retrieval. Include both: (a) the `totalTokens` returned by each `lcm_expand` call you made, AND (b) for any explicit leaf summary used as evidence, the leaf summary's own `tok` value from `lcm_describe`, even if you did not call `lcm_expand` for that leaf. This avoids reporting `totalSourceTokens: 0` when the answer was actually derived from a leaf summary's content.","- 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)));const allowedConversationIds=new Set(params.allowedConversationIds??[]);if(allowedConversationIds.size>0){const outOfScope=params.candidates.filter(candidate=>!allowedConversationIds.has(candidate.conversationId)).map(candidate=>candidate.summaryId);if(outOfScope.length>0){throw new Error(`Some summaryIds are outside the allowed conversation scope: ${outOfScope.join(", ")}`)}}if(allowedConversationIds.size>1){const firstAllowed=params.candidates.find(candidate=>allowedConversationIds.has(candidate.conversationId));if(firstAllowed){return firstAllowed.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 fallbackConversationIds=Array.from(new Set((params.conversationIds&¶ms.conversationIds.length>0?params.conversationIds:typeof params.conversationId==="number"?[params.conversationId]:[]).filter(conversationId=>Number.isInteger(conversationId))));const grepResult=await retrieval.grep({query:params.query,mode:"full_text",scope:"summaries",conversationId:params.conversationId,conversationIds:params.conversationIds});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&&fallbackConversationIds.length>0){const maxDepths=await Promise.all(fallbackConversationIds.map(async conversationId=>({conversationId,maxDepth:await summaryStore.getConversationMaxSummaryDepth(conversationId)})));const allowMessageFallback=maxDepths.every(({maxDepth})=>typeof maxDepth==="number"&&maxDepth<=1);if(allowMessageFallback){const messageResult=await retrieval.grep({query:params.query,mode:"full_text",scope:"messages",conversationId:params.conversationId,conversationIds:params.conversationIds});const messageIdsByConversationId=new Map;for(const message of messageResult.messages){const messageIds=messageIdsByConversationId.get(message.conversationId)??[];messageIds.push(message.messageId);messageIdsByConversationId.set(message.conversationId,messageIds)}const leafLinksPerConversation=await Promise.all(Array.from(messageIdsByConversationId.entries()).map(async([conversationId,messageIds])=>summaryStore.getLeafSummaryLinksForMessageIds(conversationId,messageIds)));const leafLinks=leafLinksPerConversation.flat();const messageConversationById=new Map(messageResult.messages.map(message=>[message.messageId,message.conversationId]));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)??[]){const linkedConversationId=messageConversationById.get(message.messageId);if(typeof linkedConversationId!=="number"){continue}upsertSummaryCandidate(candidates,{summaryId,conversationId:linkedConversationId,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});const familyScopedConversationId=(conversationScope.conversationIds?.length??0)>1?void 0:conversationScope.conversationId;let scopedConversationId=familyScopedConversationId;if(!conversationScope.allConversations&&scopedConversationId==null&&(conversationScope.conversationIds?.length??0)<=1&&callerSessionKey){scopedConversationId=await resolveRequesterConversationScopeId({deps:input.deps,requesterSessionKey:callerSessionKey,lcm})}if(!conversationScope.allConversations&&scopedConversationId==null&&(conversationScope.conversationIds?.length??0)<=1){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,conversationIds:conversationScope.conversationIds});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,allowedConversationIds:conversationScope.conversationIds,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}if(typeof query!=="string")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}if(typeof input.query!=="string")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. Regex syntax such as alternation (`A|B`) requires regex mode.'}),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:"Physical conversation ID to search within. If omitted, defaults to the current session family."})),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 findRegexSyntaxInFullTextQuery(pattern){let inQuote=false;let escaped=false;for(let index=0;index<pattern.length;index+=1){const char=pattern[index];const next=pattern[index+1];if(escaped){escaped=false;if(!inQuote&&char&&/[bBdDsSwW]/.test(char)){return"regex character escape"}continue}if(char==="\\"){escaped=true;continue}if(char==='"'){inQuote=!inQuote;continue}if(inQuote){continue}if(char==="|"){return"alternation"}if(char==="."&&(next==="*"||next==="+"||next==="?")){return"wildcard"}if(char==="["){const closing=pattern.indexOf("]",index+1);if(closing>index+1){return"character class"}}if(char==="^"&&(index===0||/\s/.test(pattern[index-1]??""))){return"anchor"}if(char==="$"&&(index===pattern.length-1||/\s/.test(next??""))){return"anchor"}}return null}function validateFullTextPattern(pattern){const syntax=findRegexSyntaxInFullTextQuery(pattern);if(!syntax){return null}return`full_text mode does not support regex syntax (${syntax}). Use mode: "regex" for \`${pattern}\`, or rewrite the full_text query as 1-3 literal terms or one quoted phrase.`}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";if(mode==="full_text"){const fullTextPatternError=validateFullTextPattern(pattern);if(fullTextPatternError){return jsonResult({error:fullTextPatternError})}}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,conversationIds:conversationScope.conversationIds,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){const familyCount=conversationScope.conversationIds?.length??0;lines.push(familyCount>1?`**Conversation scope:** session family rooted at ${conversationScope.conversationId} (${familyCount} segments)`:`**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.11.1",description:"Lossless Context Management plugin for OpenClaw \u2014 DAG-based conversation summarization with threshold 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:"@earendil-works/*" --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/","doctor-contract-api.d.ts","doctor-contract-api.js","skills/","openclaw.plugin.json","docs/","README.md","LICENSE"],dependencies:{"@earendil-works/pi-agent-core":">=0.74 <1","@earendil-works/pi-ai":">=0.74 <1","@earendil-works/pi-coding-agent":">=0.74 <1","@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:">=2026.5.12"},peerDependenciesMeta:{openclaw:{optional:true}},publishConfig:{access:"public"},openclaw:{extensions:["./dist/index.js"],compat:{pluginApi:">=2026.5.12",minGatewayVersion:"2026.5.12",tested:["2026.5.12"]},build:{openclawVersion:"2026.5.12"}},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"}};import crypto5 from"node:crypto";var DEFAULT_FOCUS_BRIEF_TARGET_TOKENS=12e3;var MAX_FOCUS_BRIEF_TARGET_TOKENS=12e3;var FOCUS_BRIEF_TARGET_TOKEN_MULTIPLIER=10;var FOCUS_BRIEF_MINIMUM_TOKEN_RATIO=.6;var MIN_FOCUS_BRIEF_TARGET_TOKENS=12e3;var MIN_FOCUS_BRIEF_TIMEOUT_MS=24e4;var MAX_FOCUS_BRIEF_TIMEOUT_MS=9e5;var FOCUS_BRIEF_TIMEOUT_MS_PER_TARGET_TOKEN=50;function normalizeStringArray(value){if(!Array.isArray(value)){return[]}const seen=new Set;const output=[];for(const item of value){if(typeof item!=="string"){continue}const trimmed=item.trim();if(!trimmed||seen.has(trimmed)){continue}seen.add(trimmed);output.push(trimmed)}return output}function collectFocusFailureText(value,output,depth=0){if(value==null||depth>3){return}if(typeof value==="string"){const trimmed=value.trim();if(trimmed){output.push(trimmed)}return}if(typeof value==="object"){const record=value;for(const key of["message","error","reason","details","response","cause","code"]){collectFocusFailureText(record[key],output,depth+1)}}}function formatFocusGatewayFailure(value,fallback){const parts=[];collectFocusFailureText(value,parts);const message=parts.join(" ").replace(/\s+/g," ").trim();return message||fallback}function normalizeExpansionPrompts(value){if(!Array.isArray(value)){return[]}const output=[];for(const item of value){if(!item||typeof item!=="object"){continue}const record=item;const prompt=typeof record.prompt==="string"?record.prompt.trim():"";if(!prompt){continue}output.push({prompt,summaryIds:normalizeStringArray(record.summaryIds)})}return output}function mergeExpansionPrompts(left,right){const seen=new Set;const output=[];for(const prompt of[...left,...right]){const normalizedPrompt=prompt.prompt.trim();if(!normalizedPrompt){continue}const summaryIds=normalizeStringArray(prompt.summaryIds);const key=`${normalizedPrompt}\0${summaryIds.join("\0")}`;if(seen.has(key)){continue}seen.add(key);output.push({prompt:normalizedPrompt,summaryIds})}return output}function parseFocusBriefReply(rawReply){const reply=rawReply?.trim();if(!reply){throw new Error("Focus brief subagent 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 briefMarkdown=typeof parsed.briefMarkdown==="string"?parsed.briefMarkdown.trim():typeof parsed.brief==="string"?parsed.brief.trim():"";if(!briefMarkdown){throw new Error("Focus brief JSON did not include briefMarkdown.")}return{briefMarkdown,citedSummaryIds:normalizeStringArray(parsed.citedSummaryIds),expandedSummaryIds:normalizeStringArray(parsed.expandedSummaryIds),irrelevantSummaryIds:normalizeStringArray(parsed.irrelevantSummaryIds),expansionPrompts:normalizeExpansionPrompts(parsed.expansionPrompts),confidenceNotes:normalizeStringArray(parsed.confidenceNotes),truncated:parsed.truncated===true,rawResultJson:candidate}}catch{}}throw new Error("Focus brief subagent did not return valid JSON.")}function parseFocusEvidenceReply(rawReply){const reply=rawReply?.trim();if(!reply){throw new Error("Focus evidence subagent 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 evidenceMarkdown=typeof parsed.evidenceMarkdown==="string"?parsed.evidenceMarkdown.trim():"";if(!evidenceMarkdown){throw new Error("Focus evidence JSON did not include evidenceMarkdown.")}return{evidenceMarkdown,citedSummaryIds:normalizeStringArray(parsed.citedSummaryIds),expandedSummaryIds:normalizeStringArray(parsed.expandedSummaryIds),irrelevantSummaryIds:normalizeStringArray(parsed.irrelevantSummaryIds),expansionPrompts:normalizeExpansionPrompts(parsed.expansionPrompts),confidenceNotes:normalizeStringArray(parsed.confidenceNotes),truncated:parsed.truncated===true,rawResultJson:candidate}}catch{}}throw new Error("Focus evidence subagent did not return valid JSON.")}function buildPersistedFocusResultJson(parsed,truncated,warning){if(!parsed.rawResultJson||!truncated&&!warning){return parsed.rawResultJson}try{const raw=JSON.parse(parsed.rawResultJson);if(truncated){raw.truncated=true}if(warning){raw.warning=warning}return JSON.stringify(raw)}catch{return parsed.rawResultJson}}function truncatePreview(value,maxChars){const compact=value.replace(/\s+/g," ").trim();if(compact.length<=maxChars){return compact}return`${compact.slice(0,Math.max(0,maxChars-3))}...`}function buildActiveSummaryManifest(summaries){return summaries.map(summary=>{const preview=truncatePreview(summary.content,600);return[`<summary_ref ordinal="${summary.ordinal}" id="${summary.summaryId}" kind="${summary.kind}" depth="${summary.depth}" token_count="${summary.tokenCount}" latest_at="${summary.latestAt??""}" max_source_seq="${summary.maxSourceSeq??""}">`,preview,"</summary_ref>"].join("\n")}).join("\n\n")}function resolveFocusTargetTokens(summaryTokens){if(!Number.isFinite(summaryTokens)||summaryTokens<=0){return DEFAULT_FOCUS_BRIEF_TARGET_TOKENS}const expandedTarget=Math.floor(summaryTokens*FOCUS_BRIEF_TARGET_TOKEN_MULTIPLIER);return Math.min(MAX_FOCUS_BRIEF_TARGET_TOKENS,Math.max(MIN_FOCUS_BRIEF_TARGET_TOKENS,expandedTarget))}function resolveFocusMinimumTokens(targetTokens){return Math.max(1e3,Math.floor(targetTokens*FOCUS_BRIEF_MINIMUM_TOKEN_RATIO))}function resolveFocusExpansionTokenCap(params){const configured=Math.max(1,Math.floor(params.defaultExpandTokens));const summaryDerived=Math.max(configured,Math.floor(params.summaryTokens*10));const targetDerived=Math.max(configured,Math.floor(params.targetTokens*2));return Math.min(12e4,Math.max(configured,summaryDerived,targetDerived,4e4))}function resolveFocusDelegationTimeoutMs(params){const configured=Math.max(1,Math.floor(params.configuredTimeoutMs));const targetDerived=Math.max(1,Math.floor(params.targetTokens*FOCUS_BRIEF_TIMEOUT_MS_PER_TARGET_TOKEN));return Math.min(MAX_FOCUS_BRIEF_TIMEOUT_MS,Math.max(configured,MIN_FOCUS_BRIEF_TIMEOUT_MS,targetDerived))}function buildFocusEvidenceTask(params){const minimumTokens=resolveFocusMinimumTokens(params.targetTokens);return["Gather Lossless focus evidence.","","You are a delegated subagent. Your job is to gather rich, prompt-oriented evidence for a later focus context brief. This is not the final brief.","","Focus prompt:",`<focus_prompt>${params.focusPrompt}</focus_prompt>`,"",`Conversation ID: ${params.conversationId}`,`Target brief length for the later synthesis turn: ${minimumTokens}-${params.targetTokens} tokens`,`Minimum acceptable final brief length: ${minimumTokens} tokens`,`Request ID: ${params.requestId}`,`Origin session key: ${params.originSessionKey}`,"","Evidence density requirements:","- Use this turn to search, inspect, and expand; do not write the final context brief yet.","- Prefer dense, specific working memory over a short overview.","- Include concrete decisions, file paths, command names, issue IDs, summary IDs, constraints, rejected options, unresolved questions, and handoff details when relevant.","- Do not pad with generic prose. Add detail by expanding evidence, recording provenance, and spelling out useful operational context.","","Required recall workflow:","1. Use lcm_grep with mode='full_text', scope='summaries', and this conversationId to discover relevant summaries.","2. Use lcm_describe on promising summary IDs to inspect metadata, parent/child relationships, and expansion costs.","3. Identify the newest summaries that pertain to the focus prompt, using lcm_grep recency ordering, latest_at values, and active summary context.","4. Use lcm_expand directly on high-value summary IDs to recover key details. Expand enough evidence to support a long brief. You are in delegated context, so do NOT call lcm_expand_query.","5. Record synthesis-relevant uncertainty when you only inferred something from summaries.","","Active summary context at generation time:","<active_summary_context>",buildActiveSummaryManifest(params.summaries),"</active_summary_context>","","Return ONLY JSON with this shape:","{",' "evidenceMarkdown": "markdown evidence dossier for later synthesis",',' "citedSummaryIds": ["sum_xxx"],',' "expandedSummaryIds": ["sum_xxx"],',' "irrelevantSummaryIds": ["sum_xxx"],',' "expansionPrompts": [{"prompt": "question to ask later", "summaryIds": ["sum_xxx"]}],',' "confidenceNotes": ["what is expanded evidence vs inferred synthesis"],',' "truncated": false',"}","","The evidenceMarkdown dossier must include:","- Focused Narrative Evidence: chronological, decision-rich source notes.","- Relevant Recent Context: the newest summaries that pertain to the focus prompt, with dates, current state, recency-sensitive decisions, and summary IDs.","- Current Working State Evidence: active branches, files, tests, commands, blockers, and next actions.","- Evidence Map with summary IDs: claims tied to summary IDs and expanded material.","- Expansion Guide with concrete future recall prompts: exact lcm_grep or lcm_expand follow-ups.","- Risks And Gaps: contradictions, stale assumptions, and unknowns.","- Likely Irrelevant Context: brief but explicit, with summary IDs when possible.","- Confidence Notes: separate expanded evidence from inferred synthesis."].join("\n")}function buildFocusSynthesisTask(params){const minimumTokens=resolveFocusMinimumTokens(params.targetTokens);return["Synthesize the final Lossless focus context brief.","","Focus prompt:",`<focus_prompt>${params.focusPrompt}</focus_prompt>`,"",`Target brief length: ${minimumTokens}-${params.targetTokens} tokens`,`Minimum acceptable length: ${minimumTokens} tokens`,"","Instructions:","- Use the evidence dossier below as the primary source material.","- Do not repeat the evidence dossier mechanically; turn it into a rich, task-shaped context brief.","- Use the available budget aggressively. Prefer dense, specific working memory over a short overview.","- Include concrete decisions, file paths, command names, issue IDs, summary IDs, constraints, rejected options, unresolved questions, and handoff details when relevant.","- Do not pad with generic prose. Add detail by preserving evidence, recording provenance, and spelling out useful operational context.","- Do NOT call lcm_expand_query from this delegated context.","","Evidence dossier:","<focus_evidence>",params.evidenceMarkdown,"</focus_evidence>","","Return ONLY JSON with this shape:","{",' "briefMarkdown": "markdown context brief",',' "citedSummaryIds": ["sum_xxx"],',' "expandedSummaryIds": ["sum_xxx"],',' "irrelevantSummaryIds": ["sum_xxx"],',' "expansionPrompts": [{"prompt": "question to ask later", "summaryIds": ["sum_xxx"]}],',' "confidenceNotes": ["what is expanded evidence vs inferred synthesis"],',' "truncated": false',"}","","The markdown brief must include:","- Focused Narrative: about 20% of the brief, chronological and decision-rich.","- Relevant Recent Context: about 20%, covering the newest summaries that pertain to the focus prompt, with dates, current state, recency-sensitive decisions, and summary IDs.","- Current Working State: about 20%, including active branches, files, tests, commands, blockers, and next actions.","- Evidence Map with summary IDs: about 18%, tying claims to summary IDs and expanded material.","- Expansion Guide with concrete future recall prompts: about 12%, including exact lcm_grep or lcm_expand follow-ups.","- Risks And Gaps: about 8%, including contradictions, stale assumptions, and unknowns.","- Likely Irrelevant Context: brief but explicit, with summary IDs when possible.","- Confidence Notes: separate expanded evidence from inferred synthesis."].join("\n")}function buildRefocusEvidenceTask(params){const minimumTokens=resolveFocusMinimumTokens(params.targetTokens);return["Gather Lossless refocus delta evidence.","","You are a delegated subagent. Your job is to evaluate new summary context against an existing Lossless focus brief and gather evidence for a refreshed brief. This is not the final brief.","","Original focus prompt:",`<focus_prompt>${params.focusPrompt}</focus_prompt>`,"",`Conversation ID: ${params.conversationId}`,`Target refreshed brief length for the later synthesis turn: ${minimumTokens}-${params.targetTokens} tokens`,`Minimum acceptable final brief length: ${minimumTokens} tokens`,`Request ID: ${params.requestId}`,`Origin session key: ${params.originSessionKey}`,"","Existing focus brief baseline:","<existing_focus_brief>",params.existingBriefMarkdown,"</existing_focus_brief>","","Delta summary context after the previous focus watermark:","<delta_summary_context>",buildActiveSummaryManifest(params.deltaSummaries),"</delta_summary_context>","","Evidence requirements:","- Treat the existing focus brief as the baseline working memory.","- Evaluate only the delta summaries as possible additions, corrections, or removals.","- Preserve relevant baseline details unless the delta clearly supersedes them.","- Include concrete new decisions, file paths, command names, issue IDs, constraints, test results, deployment details, and next actions when relevant to the original prompt.","- Identify obsolete baseline details if the delta contradicts or supersedes them.","","Required recall workflow:","1. Use lcm_grep with mode='full_text', scope='summaries', and this conversationId to search for delta evidence matching the original focus prompt.","2. Use lcm_describe on promising delta summary IDs to inspect metadata, parent/child relationships, and expansion costs.","3. Use lcm_expand directly on high-value delta summary IDs to recover details. You are in delegated context, so do NOT call lcm_expand_query.","4. Separate genuinely new relevant delta from repeated baseline material.","","Return ONLY JSON with this shape:","{",' "evidenceMarkdown": "markdown delta evidence dossier for later synthesis",',' "citedSummaryIds": ["sum_xxx"],',' "expandedSummaryIds": ["sum_xxx"],',' "irrelevantSummaryIds": ["sum_xxx"],',' "expansionPrompts": [{"prompt": "question to ask later", "summaryIds": ["sum_xxx"]}],',' "confidenceNotes": ["what is expanded evidence vs inferred synthesis"],',' "truncated": false',"}","","The evidenceMarkdown dossier must include:","- Baseline Retained: important existing brief claims that should remain.","- Relevant Delta: new or changed details tied to summary IDs.","- Superseded Or Contradicted Baseline Details: what should be revised or removed.","- Current Working State Delta: active branches, files, tests, commands, blockers, and next actions from new summaries.","- Evidence Map with delta summary IDs.","- Expansion Guide with concrete future recall prompts.","- Irrelevant Delta: new summaries inspected but not relevant to the original prompt.","- Confidence Notes."].join("\n")}function buildRefocusSynthesisTask(params){const minimumTokens=resolveFocusMinimumTokens(params.targetTokens);return["Synthesize the refreshed Lossless focus context brief.","","Original focus prompt:",`<focus_prompt>${params.focusPrompt}</focus_prompt>`,"",`Target refreshed brief length: ${minimumTokens}-${params.targetTokens} tokens`,`Minimum acceptable length: ${minimumTokens} tokens`,"","Existing focus brief baseline:","<existing_focus_brief>",params.existingBriefMarkdown,"</existing_focus_brief>","","Delta evidence dossier:","<refocus_delta_evidence>",params.evidenceMarkdown,"</refocus_delta_evidence>","","Instructions:","- Produce a complete updated focus context brief, not a diff or addendum.","- Preserve useful structure, specificity, and provenance from the existing brief.","- Merge in relevant delta details that match the original focus prompt.","- Remove or rewrite obsolete baseline details when the delta supersedes them.","- Keep summary IDs and future expansion prompts visible for later recall.","- Do NOT call lcm_expand_query from this delegated context.","","Return ONLY JSON with this shape:","{",' "briefMarkdown": "complete refreshed markdown context brief",',' "citedSummaryIds": ["sum_xxx"],',' "expandedSummaryIds": ["sum_xxx"],',' "irrelevantSummaryIds": ["sum_xxx"],',' "expansionPrompts": [{"prompt": "question to ask later", "summaryIds": ["sum_xxx"]}],',' "confidenceNotes": ["what is expanded evidence vs inferred synthesis"],',' "truncated": false',"}"].join("\n")}function buildFocusAgentParams(params){const agentParams={message:params.message,sessionKey:params.childSessionKey,deliver:false,lane:params.deps.agentLaneSubagent,extraSystemPrompt:params.deps.buildSubagentSystemPrompt({depth:1,maxDepth:8,taskSummary:"Generate a Lossless focus brief using lcm_grep, lcm_describe, and lcm_expand."})};const summaryModel=params.deps.config.summaryModel.trim();if(!summaryModel){return agentParams}const summaryProvider=params.deps.config.summaryProvider.trim();if(summaryProvider){agentParams.provider=summaryProvider}agentParams.model=summaryModel;return agentParams}async function runFocusAttempt(params){let runId="";try{const response=await params.deps.callGateway({method:"agent",params:buildFocusAgentParams({deps:params.deps,childSessionKey:params.childSessionKey,message:params.message}),timeoutMs:1e4});runId=typeof response?.runId==="string"?response.runId.trim():"";if(!runId){return{status:"error",runId,error:formatFocusGatewayFailure(response?.error??response,`delegated ${params.phaseName} did not return a runId`)}}const wait=await params.deps.callGateway({method:"agent.wait",params:{runId,timeoutMs:params.timeoutMs},timeoutMs:params.timeoutMs});const status=typeof wait?.status==="string"?wait.status:"error";if(status==="timeout"){return{status:"timeout",runId,error:`delegated ${params.phaseName} timed out`}}if(status!=="ok"){return{status:"error",runId,error:typeof wait?.error==="string"?wait.error:`delegated ${params.phaseName} failed`}}const replyPayload=await params.deps.callGateway({method:"sessions.get",params:{key:params.childSessionKey,limit:80},timeoutMs:1e4});const rawReply=params.deps.readLatestAssistantReply(Array.isArray(replyPayload.messages)?replyPayload.messages:[]);const parsed=params.parseReply(rawReply);return{status:"ok",runId,parsed,tokenCount:estimateTokens(params.estimateText(parsed)),rawReply}}catch(err){return{status:"error",runId,error:err instanceof Error?err.message:String(err)}}}async function runDelegatedFocusWorkflow(params){const targetTokens=resolveFocusTargetTokens(params.summaryTokens);const tokenCap=resolveFocusExpansionTokenCap({summaryTokens:params.summaryTokens,targetTokens,defaultExpandTokens:params.deps.config.maxExpandTokens});const minimumTokens=resolveFocusMinimumTokens(targetTokens);const timeoutMs=resolveFocusDelegationTimeoutMs({configuredTimeoutMs:params.deps.config.delegationTimeoutMs,targetTokens});const requestId=resolveExpansionRequestId(params.requesterSessionKey);const requesterAgentId=params.deps.normalizeAgentId(params.deps.parseAgentSessionKey(params.requesterSessionKey)?.agentId);const childSessionKey=`agent:${requesterAgentId}:subagent:${crypto5.randomUUID()}`;let runId="";createDelegatedExpansionGrant({delegatedSessionKey:childSessionKey,issuerSessionId:params.requesterSessionKey,allowedConversationIds:[params.conversationId],tokenCap,ttlMs:timeoutMs+6e4});stampDelegatedExpansionContext({sessionKey:childSessionKey,requestId,expansionDepth:1,originSessionKey:params.requesterSessionKey,stampedBy:params.stampedBy});try{const evidenceMessage=params.buildEvidenceMessage({targetTokens,requestId,originSessionKey:params.requesterSessionKey});const evidenceAttempt=await runFocusAttempt({deps:params.deps,childSessionKey,message:evidenceMessage,timeoutMs,phaseName:params.evidencePhaseName,parseReply:parseFocusEvidenceReply,estimateText:parsed2=>parsed2.evidenceMarkdown});runId=evidenceAttempt.runId;if(evidenceAttempt.status==="timeout"){return{status:"timeout",runId:evidenceAttempt.runId,childSessionKey,briefMarkdown:"",citedSummaryIds:[],expandedSummaryIds:[],irrelevantSummaryIds:[],expansionPrompts:[],confidenceNotes:[],tokenCount:0,targetTokens,truncated:true,error:evidenceAttempt.error}}if(evidenceAttempt.status!=="ok"){return{status:"error",runId:evidenceAttempt.runId,childSessionKey,briefMarkdown:"",citedSummaryIds:[],expandedSummaryIds:[],irrelevantSummaryIds:[],expansionPrompts:[],confidenceNotes:[],tokenCount:0,targetTokens,truncated:true,error:evidenceAttempt.error}}const attempt=await runFocusAttempt({deps:params.deps,childSessionKey,message:params.buildSynthesisMessage({evidenceMarkdown:evidenceAttempt.parsed.evidenceMarkdown,targetTokens}),timeoutMs,phaseName:params.synthesisPhaseName,parseReply:parseFocusBriefReply,estimateText:parsed2=>parsed2.briefMarkdown});runId=attempt.runId;if(attempt.status!=="ok"){return{status:attempt.status,runId:attempt.runId,childSessionKey,briefMarkdown:"",citedSummaryIds:evidenceAttempt.parsed.citedSummaryIds,expandedSummaryIds:evidenceAttempt.parsed.expandedSummaryIds,irrelevantSummaryIds:evidenceAttempt.parsed.irrelevantSummaryIds,expansionPrompts:evidenceAttempt.parsed.expansionPrompts,confidenceNotes:evidenceAttempt.parsed.confidenceNotes,tokenCount:0,targetTokens,truncated:true,rawResultJson:evidenceAttempt.parsed.rawResultJson,error:attempt.error}}const parsed=attempt.parsed;const stillShort=attempt.tokenCount<minimumTokens;const warning=stillShort?`Focus brief is shorter than the requested ${minimumTokens}-token minimum.`:void 0;const evidence=evidenceAttempt.parsed;const truncated=evidence.truncated||parsed.truncated;return{status:"ok",runId:attempt.runId,childSessionKey,briefMarkdown:parsed.briefMarkdown,citedSummaryIds:normalizeStringArray([...evidence.citedSummaryIds,...parsed.citedSummaryIds]),expandedSummaryIds:normalizeStringArray([...evidence.expandedSummaryIds,...parsed.expandedSummaryIds]),irrelevantSummaryIds:normalizeStringArray([...evidence.irrelevantSummaryIds,...parsed.irrelevantSummaryIds]),expansionPrompts:mergeExpansionPrompts(evidence.expansionPrompts,parsed.expansionPrompts),confidenceNotes:normalizeStringArray([...evidence.confidenceNotes,...parsed.confidenceNotes]),tokenCount:attempt.tokenCount,targetTokens,truncated,rawReply:attempt.rawReply,rawResultJson:buildPersistedFocusResultJson(parsed,truncated,warning),warning}}catch(err){return{status:"error",runId:runId||crypto5.randomUUID(),childSessionKey,briefMarkdown:"",citedSummaryIds:[],expandedSummaryIds:[],irrelevantSummaryIds:[],expansionPrompts:[],confidenceNotes:[],tokenCount:0,targetTokens,truncated:true,error:err instanceof Error?err.message:String(err)}}finally{try{await params.deps.callGateway({method:"sessions.delete",params:{key:childSessionKey,deleteTranscript:false},timeoutMs:1e4})}catch{}revokeDelegatedExpansionGrantForSession(childSessionKey,{removeBinding:true});clearDelegatedExpansionContext(childSessionKey)}}async function runDelegatedFocusBrief(params){const summaryTokens=params.summaries.reduce((sum,summary)=>sum+Math.max(0,summary.tokenCount),0);return runDelegatedFocusWorkflow({deps:params.deps,requesterSessionKey:params.requesterSessionKey,conversationId:params.conversationId,summaryTokens,evidencePhaseName:"focus evidence gathering",synthesisPhaseName:"focus brief synthesis",stampedBy:"runDelegatedFocusBrief",buildEvidenceMessage:({targetTokens,requestId,originSessionKey})=>buildFocusEvidenceTask({focusPrompt:params.focusPrompt,conversationId:params.conversationId,summaries:params.summaries,targetTokens,requestId,originSessionKey}),buildSynthesisMessage:({evidenceMarkdown,targetTokens})=>buildFocusSynthesisTask({focusPrompt:params.focusPrompt,evidenceMarkdown,targetTokens})})}async function runDelegatedRefocusBrief(params){const summaryTokens=estimateTokens(params.existingBriefMarkdown)+params.deltaSummaries.reduce((sum,summary)=>sum+Math.max(0,summary.tokenCount),0);return runDelegatedFocusWorkflow({deps:params.deps,requesterSessionKey:params.requesterSessionKey,conversationId:params.conversationId,summaryTokens,evidencePhaseName:"refocus delta evidence gathering",synthesisPhaseName:"refocus brief synthesis",stampedBy:"runDelegatedRefocusBrief",buildEvidenceMessage:({targetTokens,requestId,originSessionKey})=>buildRefocusEvidenceTask({focusPrompt:params.focusPrompt,existingBriefMarkdown:params.existingBriefMarkdown,conversationId:params.conversationId,deltaSummaries:params.deltaSummaries,targetTokens,requestId,originSessionKey}),buildSynthesisMessage:({evidenceMarkdown,targetTokens})=>buildRefocusSynthesisTask({focusPrompt:params.focusPrompt,existingBriefMarkdown:params.existingBriefMarkdown,evidenceMarkdown,targetTokens})})}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
|
|
1079
1079
|
s.conversation_id,
|
|
1080
1080
|
s.summary_id,
|
|
1081
1081
|
s.kind,
|
|
@@ -1386,7 +1386,7 @@ UNION
|
|
|
1386
1386
|
FROM conversations
|
|
1387
1387
|
WHERE session_id = ?
|
|
1388
1388
|
ORDER BY active DESC, created_at DESC
|
|
1389
|
-
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 resolveRuntimeSessionId(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 resolveLifecycleCompactionTokenBudget(config){return config.maxAssemblyTokenBudget&&config.maxAssemblyTokenBudget>0?Math.floor(config.maxAssemblyTokenBudget):128e3}async function runFocusLifecycleCompaction(params){if(!params.deps||!params.getLcm){return{status:"unavailable",reason:"Focus lifecycle compaction requires the runtime-backed LCM engine."}}const sessionKey=params.sessionKey??normalizeIdentity(params.ctx.sessionKey);const sessionId=await resolveRuntimeSessionId({ctx:params.ctx,deps:params.deps,current:params.current});if(!sessionId){return{status:"unavailable",reason:"Lossless Claw resolved the active conversation, but OpenClaw did not expose or resolve a runtime session id for compaction."}}const engine=await params.getLcm();if(typeof engine.compact!=="function"){return{status:"unavailable",reason:"The runtime-backed LCM engine does not expose compaction to commands."}}let sessionFile="";try{sessionFile=await params.deps.resolveSessionTranscriptFile({sessionId,sessionKey})??""}catch{sessionFile=""}const tokenBudget=resolveLifecycleCompactionTokenBudget(params.config);try{const result=await engine.compact({sessionId,sessionKey,sessionFile,tokenBudget,currentTokenCount:params.current.stats.contextTokenCount,compactionTarget:"threshold",runtimeContext:{manualCompaction:true,tokenBudget,currentTokenCount:params.current.stats.contextTokenCount},force:true});return result.ok?{status:"ok",sessionId,result}:{status:"failed",reason:result.reason??result.error??"focus lifecycle compaction failed"}}catch(error){return{status:"failed",reason:formatFailureReason(error)}}}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"}function resolveDbSizeLabel(dbPath){if(typeof dbPath!=="string")return"unknown";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} focus <prompt>`),"Generate an active focus brief with a delegated recall sub-agent."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} focus`),"Show the latest focus brief for the current conversation."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} refocus`),"Refresh the active focus brief from post-focus summary deltas."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} unfocus`),"Deactivate the active focus overlay without deleting focus history."),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 focusLines=await buildFocusSummaryLines({store:new FocusBriefStore(params.db),conversationId:current.stats.conversationId,timezone:params.config.timezone});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{1F3AF} Focus",focusLines));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){if(typeof databasePath!=="string")return"Invalid database path.";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 resolveRuntimeSessionId({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")}function formatFocusPreview(content,maxChars=1200){const trimmed=content.trim();if(trimmed.length<=maxChars){return trimmed}return`${trimmed.slice(0,Math.max(0,maxChars-3)).trimEnd()}...`}function formatFocusBriefTime(value,timezone){return value?formatTimestamp(value,timezone):"unknown"}function formatFocusDelta(diagnostics){return[`${formatNumber(diagnostics.postFocusMessageCount)} messages`,`${formatNumber(diagnostics.postFocusSummaryCount)} summaries`,`~${formatNumber(diagnostics.postFocusTokenCount)} tokens`].join(", ")}async function buildFocusSummaryLines(params){const active=await params.store.getActiveFocusBrief(params.conversationId);const latest=await params.store.getLatestFocusBrief(params.conversationId);if(!active){return[buildStatLine("status","none"),...latest?[buildStatLine("latest generation",latest.status),buildStatLine("latest brief id",formatCommand(latest.briefId))]:[]]}const diagnostics=await params.store.getFocusBriefDiagnostics(active);const lines=[buildStatLine("status","active"),buildStatLine("brief id",formatCommand(active.briefId)),buildStatLine("created",formatFocusBriefTime(active.createdAt,params.timezone)),buildStatLine("prompt",JSON.stringify(formatFocusPreview(active.prompt,160))),buildStatLine("tokens",`${formatNumber(active.tokenCount)} / ${formatNumber(active.targetTokens)}`),buildStatLine("delta since focus",formatFocusDelta(diagnostics)),buildStatLine("stale",formatBoolean(diagnostics.stale)),buildStatLine("truncated",formatBoolean(diagnostics.truncated)),buildStatLine("source snapshot",diagnostics.sourceContextChanged?"obsolete":"current")];if(latest&&latest.briefId!==active.briefId){lines.push(buildStatLine("latest generation",latest.status));if(latest.error){lines.push(buildStatLine("latest error",latest.error))}}return lines}async function buildFocusStatusText(params){const lines=[...buildHeaderLines(),"","\u{1F3AF} Lossless Claw Focus",""];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")}const store=new FocusBriefStore(params.db);const active=await store.getActiveFocusBrief(current.stats.conversationId);const latest=await store.getLatestFocusBrief(current.stats.conversationId);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")]),"");if(!active&&!latest){lines.push(buildSection("\u{1F3AF} Focus",[buildStatLine("status","none"),buildStatLine("usage",formatCommand(`${VISIBLE_COMMAND} focus <prompt>`)),buildStatLine("behavior","generates an active focus brief overlay")]));return lines.join("\n")}const primary=active??latest;if(!primary){return lines.join("\n")}const sources=await store.getFocusBriefSources(primary.briefId);const cited=sources.filter(source=>source.role==="cited").map(source=>source.summaryId);const diagnostics=await store.getFocusBriefDiagnostics(primary);lines.push(buildSection(active?"\u{1F3AF} Active focus brief":"\u{1F3AF} Latest focus brief",[buildStatLine("brief id",formatCommand(primary.briefId)),buildStatLine("status",primary.status),buildStatLine("created",formatFocusBriefTime(primary.createdAt,params.config.timezone)),buildStatLine("prompt",JSON.stringify(formatFocusPreview(primary.prompt,240))),buildStatLine("tokens",formatNumber(primary.tokenCount)),buildStatLine("target tokens",formatNumber(primary.targetTokens)),buildStatLine("source summaries",formatNumber(sources.filter(source=>source.role==="active_input").length)),buildStatLine("cited summaries",cited.length>0?cited.slice(0,8).join(", "):"none"),buildStatLine("generator run",primary.generatorRunId??"unknown"),buildStatLine("delta since focus",formatFocusDelta(diagnostics)),buildStatLine("stale",formatBoolean(diagnostics.stale)),buildStatLine("truncated",formatBoolean(diagnostics.truncated)),buildStatLine("source snapshot",diagnostics.sourceContextChanged?"obsolete":"current")]));if(latest&&active&&latest.briefId!==active.briefId){lines.push("",buildSection("\u26A0\uFE0F Latest generation",[buildStatLine("latest generation",latest.status),buildStatLine("brief id",formatCommand(latest.briefId)),...latest.error?[buildStatLine("error",latest.error)]:[]]))}else if(primary.error){lines.push("",buildSection("\u26A0\uFE0F Error",[primary.error]))}if(primary.content.trim()){lines.push("",buildSection("\u{1F4DD} Preview",[formatFocusPreview(primary.content)]))}return lines.join("\n")}async function buildFocusGenerateText(params){const lines=[...buildHeaderLines(),"","\u{1F3AF} Lossless Claw Focus",""];if(!params.deps||!params.getLcm){lines.push(buildSection("\u{1F6E0}\uFE0F Focus",[buildStatLine("status","unavailable"),buildStatLine("reason","Focus generation requires runtime dependencies for pre-focus compaction and delegated subagents.")]));return lines.join("\n")}const requesterSessionKey=normalizeIdentity(params.ctx.sessionKey);if(!requesterSessionKey){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason","OpenClaw must expose the active session key for Lossless Claw to spawn a focus subagent.")]));return lines.join("\n")}let 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")}const preFocusCompaction=await runFocusLifecycleCompaction({ctx:params.ctx,deps:params.deps,getLcm:params.getLcm,config:params.config,current,sessionKey:requesterSessionKey});if(preFocusCompaction.status!=="ok"){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(requesterSessionKey,44)))]),"",buildSection("\u{1F9F9} Pre-focus compaction",[buildStatLine("status",preFocusCompaction.status),buildStatLine("reason",preFocusCompaction.reason)]));return lines.join("\n")}current=await resolveCurrentConversation({ctx:params.ctx,db:params.db});if(current.kind==="unavailable"){lines.push(buildSection("\u{1F9F9} Pre-focus compaction",[buildStatLine("status","completed"),buildStatLine("result",preFocusCompaction.result.reason??"done")]),"",buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason)]));return lines.join("\n")}const store=new FocusBriefStore(params.db);const summaries=await store.getActiveContextSummaries(current.stats.conversationId);if(summaries.length===0){lines.push(buildSection("\u{1F3AF} Focus",[buildStatLine("status","unavailable"),buildStatLine("reason","The current conversation has no active summary context items to focus.")]));return lines.join("\n")}const sourceContextHash=hashFocusSourceContext(summaries);const watermark=await store.getCoveredWatermark(current.stats.conversationId);const generation=await runDelegatedFocusBrief({deps:params.deps,requesterSessionKey,conversationId:current.stats.conversationId,focusPrompt:params.prompt,summaries});const ordinalBySummaryId=new Map(summaries.map(summary=>[summary.summaryId,summary.ordinal]));const sources=[...summaries.map(summary=>({summaryId:summary.summaryId,ordinal:summary.ordinal,role:"active_input"})),...generation.citedSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"cited"})),...generation.expandedSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"expanded"})),...generation.irrelevantSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"irrelevant"}))];const ok=generation.status==="ok";const brief=await store.createFocusBrief({conversationId:current.stats.conversationId,sessionKey:requesterSessionKey,prompt:params.prompt,content:ok?generation.briefMarkdown:"",status:ok?"active":"failed",tokenCount:generation.tokenCount,targetTokens:generation.targetTokens,coveredLatestAt:watermark.coveredLatestAt,coveredMessageSeq:watermark.coveredMessageSeq,sourceContextHash,generatorRunId:generation.runId,generatorSessionKey:generation.childSessionKey,rawResultJson:generation.rawResultJson??JSON.stringify({status:generation.status,error:generation.error,rawReply:generation.rawReply}),error:generation.error??null,sources,supersedeCurrentDrafts:ok});lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(requesterSessionKey,44))),buildStatLine("source summaries",formatNumber(summaries.length)),buildStatLine("source context hash",sourceContextHash.slice(0,16))]),"",buildSection("\u{1F9F9} Pre-focus compaction",[buildStatLine("status","completed"),buildStatLine("compacted",formatBoolean(preFocusCompaction.result.compacted)),buildStatLine("result",preFocusCompaction.result.reason??"done")]),"",buildSection("\u{1F3AF} Focus brief",[buildStatLine("brief id",formatCommand(brief.briefId)),buildStatLine("status",brief.status),buildStatLine("prompt",JSON.stringify(formatFocusPreview(params.prompt,240))),buildStatLine("tokens",formatNumber(brief.tokenCount)),buildStatLine("target tokens",formatNumber(brief.targetTokens)),buildStatLine("generator run",generation.runId),buildStatLine("generator session",truncateMiddle(generation.childSessionKey,60)),buildStatLine("truncated",formatBoolean(generation.truncated))]));if(!ok){lines.push("",buildSection("\u26A0\uFE0F Generation failed",[generation.error??"Focus brief generation failed without a specific error."]));return lines.join("\n")}lines.push("",buildSection("\u{1F4DD} Preview",[formatFocusPreview(generation.briefMarkdown)]));return lines.join("\n")}function isSummaryAfterFocusWatermark(summary,brief){if(brief.coveredMessageSeq!=null&&summary.maxSourceSeq!=null){return summary.maxSourceSeq>brief.coveredMessageSeq}if(!brief.coveredLatestAt){return true}const timestamp=summary.latestAt??summary.createdAt;const parsed=Date.parse(timestamp);if(!Number.isFinite(parsed)){return true}return parsed>brief.coveredLatestAt.getTime()}async function buildRefocusText(params){const lines=[...buildHeaderLines(),"","\u{1F3AF} Lossless Claw Refocus",""];if(!params.deps||!params.getLcm){lines.push(buildSection("\u{1F6E0}\uFE0F Refocus",[buildStatLine("status","unavailable"),buildStatLine("reason","Refocus requires runtime dependencies for pre-refocus compaction and delegated subagents.")]));return lines.join("\n")}const requesterSessionKey=normalizeIdentity(params.ctx.sessionKey);if(!requesterSessionKey){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason","OpenClaw must expose the active session key for Lossless Claw to refocus.")]));return lines.join("\n")}let 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")}const store=new FocusBriefStore(params.db);const active=await store.getActiveFocusBrief(current.stats.conversationId);if(!active?.content.trim()){lines.push(buildSection("\u{1F3AF} Refocus",[buildStatLine("status","unavailable"),buildStatLine("reason","The current conversation has no active focus brief to refresh.")]));return lines.join("\n")}const preRefocusCompaction=await runFocusLifecycleCompaction({ctx:params.ctx,deps:params.deps,getLcm:params.getLcm,config:params.config,current,sessionKey:requesterSessionKey});if(preRefocusCompaction.status!=="ok"){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(requesterSessionKey,44)))]),"",buildSection("\u{1F9F9} Pre-refocus compaction",[buildStatLine("status",preRefocusCompaction.status),buildStatLine("reason",preRefocusCompaction.reason)]));return lines.join("\n")}current=await resolveCurrentConversation({ctx:params.ctx,db:params.db});if(current.kind==="unavailable"){lines.push(buildSection("\u{1F9F9} Pre-refocus compaction",[buildStatLine("status","completed"),buildStatLine("result",preRefocusCompaction.result.reason??"done")]),"",buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason)]));return lines.join("\n")}const activeSummaries=await store.getActiveContextSummaries(current.stats.conversationId);const deltaSummaries=activeSummaries.filter(summary=>isSummaryAfterFocusWatermark(summary,active));if(deltaSummaries.length===0){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(requesterSessionKey,44)))]),"",buildSection("\u{1F9F9} Pre-refocus compaction",[buildStatLine("status","completed"),buildStatLine("compacted",formatBoolean(preRefocusCompaction.result.compacted)),buildStatLine("result",preRefocusCompaction.result.reason??"done")]),"",buildSection("\u{1F3AF} Refocus",[buildStatLine("status","already current"),buildStatLine("active brief",formatCommand(active.briefId)),buildStatLine("delta summaries","0")]));return lines.join("\n")}const sourceContextHash=hashFocusSourceContext(activeSummaries);const watermark=await store.getCoveredWatermark(current.stats.conversationId);const generation=await runDelegatedRefocusBrief({deps:params.deps,requesterSessionKey,conversationId:current.stats.conversationId,focusPrompt:active.prompt,existingBriefMarkdown:active.content,deltaSummaries});const ordinalBySummaryId=new Map(activeSummaries.map(summary=>[summary.summaryId,summary.ordinal]));const sources=[...deltaSummaries.map(summary=>({summaryId:summary.summaryId,ordinal:summary.ordinal,role:"active_input"})),...generation.citedSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"cited"})),...generation.expandedSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"expanded"})),...generation.irrelevantSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"irrelevant"}))];const ok=generation.status==="ok";const brief=await store.createFocusBrief({conversationId:current.stats.conversationId,sessionKey:requesterSessionKey,prompt:active.prompt,content:ok?generation.briefMarkdown:"",status:ok?"active":"failed",tokenCount:generation.tokenCount,targetTokens:generation.targetTokens,coveredLatestAt:watermark.coveredLatestAt,coveredMessageSeq:watermark.coveredMessageSeq,sourceContextHash,generatorRunId:generation.runId,generatorSessionKey:generation.childSessionKey,rawResultJson:generation.rawResultJson??JSON.stringify({status:generation.status,error:generation.error,rawReply:generation.rawReply}),error:generation.error??null,sources,supersedeCurrentDrafts:ok});lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(requesterSessionKey,44))),buildStatLine("active brief",formatCommand(active.briefId)),buildStatLine("delta summaries",formatNumber(deltaSummaries.length)),buildStatLine("source context hash",sourceContextHash.slice(0,16))]),"",buildSection("\u{1F9F9} Pre-refocus compaction",[buildStatLine("status","completed"),buildStatLine("compacted",formatBoolean(preRefocusCompaction.result.compacted)),buildStatLine("result",preRefocusCompaction.result.reason??"done")]),"",buildSection("\u{1F3AF} Focus brief",[buildStatLine("brief id",formatCommand(brief.briefId)),buildStatLine("status",brief.status),buildStatLine("prompt",JSON.stringify(formatFocusPreview(active.prompt,240))),buildStatLine("tokens",formatNumber(brief.tokenCount)),buildStatLine("target tokens",formatNumber(brief.targetTokens)),buildStatLine("generator run",generation.runId),buildStatLine("generator session",truncateMiddle(generation.childSessionKey,60)),buildStatLine("truncated",formatBoolean(generation.truncated))]));if(!ok){lines.push("",buildSection("\u26A0\uFE0F Generation failed",[generation.error??"Refocus brief generation failed without a specific error."]));return lines.join("\n")}lines.push("",buildSection("\u{1F4DD} Preview",[formatFocusPreview(generation.briefMarkdown)]));return lines.join("\n")}async function buildUnfocusText(params){const lines=[...buildHeaderLines(),"","\u{1F3AF} Lossless Claw Focus",""];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")}const store=new FocusBriefStore(params.db);const active=await store.getActiveFocusBrief(current.stats.conversationId);if(!active){lines.push(buildSection("\u{1F3AF} Focus",[buildStatLine("status","none active"),buildStatLine("deactivated briefs","0")]));return lines.join("\n")}const deactivated=await store.deactivateActiveFocusBriefs(current.stats.conversationId);const postUnfocusCompaction=await runFocusLifecycleCompaction({ctx:params.ctx,deps:params.deps,getLcm:params.getLcm,config:params.config,current,sessionKey:normalizeIdentity(params.ctx.sessionKey)??normalizeIdentity(current.stats.sessionKey??void 0)});lines.push(buildSection("\u{1F3AF} Focus",[buildStatLine("status",deactivated>0?"inactive":"none active"),buildStatLine("deactivated briefs",formatNumber(deactivated))]));lines.push("",buildSection("\u{1F9F9} Post-unfocus compaction",[buildStatLine("status",postUnfocusCompaction.status==="ok"?"completed":postUnfocusCompaction.status),...postUnfocusCompaction.status==="ok"?[buildStatLine("compacted",formatBoolean(postUnfocusCompaction.result.compacted)),buildStatLine("result",postUnfocusCompaction.result.reason??"done")]:[buildStatLine("reason",postUnfocusCompaction.reason)]]));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"focus_status":return{text:await buildFocusStatusText({ctx,db:await getDb(),config:params.config})};case"focus_generate":return{text:await buildFocusGenerateText({ctx,db:await getDb(),config:params.config,deps:params.deps,getLcm:params.getLcm,prompt:parsed.prompt})};case"refocus":return{text:await buildRefocusText({ctx,db:await getDb(),config:params.config,deps:params.deps,getLcm:params.getLcm})};case"unfocus":return{text:await buildUnfocusText({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"}function readRuntimeConfigSnapshot(api){const configApi=api.runtime.config;if(!configApi){return void 0}if(typeof configApi.current==="function"){return configApi.current()}if(typeof configApi.loadConfig==="function"){return configApi.loadConfig()}return void 0}function getRuntimeAgentSessionApi(api){const runtime=api.runtime;const sessionApi=runtime.agent?.session??runtime.channel?.session;if(!sessionApi){return void 0}if(typeof sessionApi.resolveStorePath!=="function"||typeof sessionApi.loadSessionStore!=="function"||typeof sessionApi.resolveSessionFilePath!=="function"){return void 0}return sessionApi}function listConfiguredAgentIds(config){const agents=isRecord2(config)?config.agents:void 0;const list=isRecord2(agents)&&Array.isArray(agents.list)?agents.list:[];const seen=new Set;const ids=[];for(const entry of list){if(!isRecord2(entry)||entry.enabled===false||typeof entry.id!=="string"){continue}const agentId=normalizeAgentId(entry.id);if(seen.has(agentId)){continue}seen.add(agentId);ids.push(agentId)}return ids.length>0?ids:["main"]}function getStringField(record,key){const value=record?.[key];return typeof value==="string"&&value.trim()?value.trim():void 0}function toNonNegativeInteger(value){if(typeof value!=="number"||!Number.isFinite(value)||value<0){return void 0}return Math.floor(value)}var RECOVERED_SYSTEM_PROMPT_TOKEN_FLOOR=4096;function estimateRecoveredSessionTotalTokens(params){const entry=params.sessionEntry;const inputTokens=toNonNegativeInteger(entry.inputTokens)??toNonNegativeInteger(entry.input)??toNonNegativeInteger(entry.promptTokens)??toNonNegativeInteger(entry.prompt_tokens)??0;const cacheRead=toNonNegativeInteger(entry.cacheRead)??toNonNegativeInteger(entry.cache_read)??0;const cacheWrite=toNonNegativeInteger(entry.cacheWrite)??toNonNegativeInteger(entry.cache_write)??0;const contextTokens=Math.max(0,Math.floor(params.contextTokenEstimate));const runtimePromptTokens=inputTokens+cacheRead+cacheWrite;return Math.max(RECOVERED_SYSTEM_PROMPT_TOKEN_FLOOR,contextTokens+runtimePromptTokens)}function hasFreshTotalTokens(sessionEntry){return sessionEntry.totalTokensFresh===true&&toNonNegativeInteger(sessionEntry.totalTokens)!==void 0}var RUNTIME_LLM_PR_URL="https://github.com/openclaw/openclaw/pull/64294";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 regular expressions and literal patterns that use regex syntax.','- Full-text queries are not regexes. Alternation (`A|B`), regex wildcards (`.*`), character classes (`[abc]`), and anchors (`^foo`, `foo$`) require `mode: "regex"`.',"- 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.","","## Compacted Conversation Context","","If compacted summaries appear above, treat them 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.',"","For exact commands, SHAs, paths, timestamps, config values, or causal chains, expand for details before answering.","","State uncertainty instead of guessing from compacted summaries.","","**Precision flow:**","1. `lcm_grep` to find the relevant summaries or messages","2. `lcm_expand_query` when you need exact evidence before answering","3. Answer from the retrieved evidence instead of summary paraphrase","","**Uncertainty checklist:**","- Am I making an exact factual claim from compacted context?","- Could compaction have omitted a crucial detail?","- Would I need an expansion step if the user asks for proof or exact text?","","If yes to any item, expand first or explicitly say that you need to expand.","","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 isRecord2(value){return!!value&&typeof value==="object"&&!Array.isArray(value)}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 detectProviderBridgeError(error){const statusCode=extractErrorStatusCode(error);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_error",...statusCode!==void 0?{statusCode}:{},...directCode?{code:directCode}:{},message:truncateErrorMessage(describeLogError(error))}}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=readRuntimeConfigSnapshot(api);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 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 getRuntimeLlm(api){const runtime=api.runtime;return typeof runtime.llm?.complete==="function"?runtime.llm:void 0}function buildRuntimeLlmUnavailableError(){return{kind:"provider_error",message:`[lcm] OpenClaw runtime.llm.complete is unavailable. Install an OpenClaw build with Plugin SDK runtime LLM support (${RUNTIME_LLM_PR_URL}).`}}function toRuntimeLlmMessages(messages){return messages.filter(message=>message.role==="system"||message.role==="user"||message.role==="assistant").map(message=>({role:message.role,content:stringifyRuntimeLlmContent(message.content)}))}function stringifyRuntimeLlmContent(content){if(typeof content==="string"){return content}if(content===null||content===void 0){return""}if(typeof content==="number"||typeof content==="boolean"||typeof content==="bigint"){return String(content)}try{return JSON.stringify(content)}catch{return String(content)}}function buildRuntimeModelRef(provider,model){const modelId=model.trim();if(!modelId){return void 0}const slash=modelId.indexOf("/");if(slash>0&&slash<modelId.length-1){const directProvider=modelId.slice(0,slash).trim();const directModel=modelId.slice(slash+1).trim();return directProvider&&directModel?`${directProvider}/${directModel}`:void 0}const providerId=provider?.trim();return providerId?`${providerId}/${modelId}`:modelId}function buildRuntimeLlmPolicySnippet(modelRef){return JSON.stringify({plugins:{entries:{"lossless-claw":{llm:{allowModelOverride:true,allowedModels:[modelRef]}}}}},null,2)}function isRuntimeLlmModelPolicyDenial(error){const text=describeLogError(error);return/Plugin LLM completion (cannot override the target model|model override .*not allowlisted|model override allowlist|model override allowlist requires)/i.test(text)}function buildRuntimeLlmPolicyError(override,error){const detail=truncateErrorMessage(describeLogError(error),200);return{kind:"runtime_llm_policy",code:"runtime_llm_model_override_denied",configField:override.configField,configPath:override.configPath,modelRef:override.modelRef,message:`[lcm] OpenClaw denied the Lossless runtime LLM model override from ${override.configPath} (${override.configField}). Requested model: ${override.modelRef}. Configure plugins.entries.lossless-claw.llm.allowModelOverride and plugins.entries.lossless-claw.llm.allowedModels, or run "openclaw doctor --fix". Minimal config:
|
|
1389
|
+
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 resolveRuntimeSessionId(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 resolveLifecycleCompactionTokenBudget(config){return config.maxAssemblyTokenBudget&&config.maxAssemblyTokenBudget>0?Math.floor(config.maxAssemblyTokenBudget):128e3}async function runFocusLifecycleCompaction(params){if(!params.deps||!params.getLcm){return{status:"unavailable",reason:"Focus lifecycle compaction requires the runtime-backed LCM engine."}}const sessionKey=params.sessionKey??normalizeIdentity(params.ctx.sessionKey);const sessionId=await resolveRuntimeSessionId({ctx:params.ctx,deps:params.deps,current:params.current});if(!sessionId){return{status:"unavailable",reason:"Lossless Claw resolved the active conversation, but OpenClaw did not expose or resolve a runtime session id for compaction."}}const engine=await params.getLcm();if(typeof engine.compact!=="function"){return{status:"unavailable",reason:"The runtime-backed LCM engine does not expose compaction to commands."}}let sessionFile="";try{sessionFile=await params.deps.resolveSessionTranscriptFile({sessionId,sessionKey})??""}catch{sessionFile=""}const tokenBudget=resolveLifecycleCompactionTokenBudget(params.config);try{const result=await engine.compact({sessionId,sessionKey,sessionFile,tokenBudget,currentTokenCount:params.current.stats.contextTokenCount,compactionTarget:"threshold",runtimeContext:{manualCompaction:true,tokenBudget,currentTokenCount:params.current.stats.contextTokenCount},force:true});return result.ok?{status:"ok",sessionId,result}:{status:"failed",reason:result.reason??result.error??"focus lifecycle compaction failed"}}catch(error){return{status:"failed",reason:formatFailureReason(error)}}}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"}function resolveDbSizeLabel(dbPath){if(typeof dbPath!=="string")return"unknown";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} focus <prompt>`),"Generate an active focus brief with a delegated recall sub-agent."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} focus`),"Show the latest focus brief for the current conversation."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} refocus`),"Refresh the active focus brief from post-focus summary deltas."),buildStatLine(formatCommand(`${VISIBLE_COMMAND} unfocus`),"Deactivate the active focus overlay without deleting focus history."),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 focusLines=await buildFocusSummaryLines({store:new FocusBriefStore(params.db),conversationId:current.stats.conversationId,timezone:params.config.timezone});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{1F3AF} Focus",focusLines));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){if(typeof databasePath!=="string")return"Invalid database path.";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 resolveRuntimeSessionId({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")}function formatFocusPreview(content,maxChars=1200){const trimmed=content.trim();if(trimmed.length<=maxChars){return trimmed}return`${trimmed.slice(0,Math.max(0,maxChars-3)).trimEnd()}...`}function formatFocusBriefTime(value,timezone){return value?formatTimestamp(value,timezone):"unknown"}function formatFocusDelta(diagnostics){return[`${formatNumber(diagnostics.postFocusMessageCount)} messages`,`${formatNumber(diagnostics.postFocusSummaryCount)} summaries`,`~${formatNumber(diagnostics.postFocusTokenCount)} tokens`].join(", ")}async function buildFocusSummaryLines(params){const active=await params.store.getActiveFocusBrief(params.conversationId);const latest=await params.store.getLatestFocusBrief(params.conversationId);if(!active){return[buildStatLine("status","none"),...latest?[buildStatLine("latest generation",latest.status),buildStatLine("latest brief id",formatCommand(latest.briefId))]:[]]}const diagnostics=await params.store.getFocusBriefDiagnostics(active);const lines=[buildStatLine("status","active"),buildStatLine("brief id",formatCommand(active.briefId)),buildStatLine("created",formatFocusBriefTime(active.createdAt,params.timezone)),buildStatLine("prompt",JSON.stringify(formatFocusPreview(active.prompt,160))),buildStatLine("tokens",`${formatNumber(active.tokenCount)} / ${formatNumber(active.targetTokens)}`),buildStatLine("delta since focus",formatFocusDelta(diagnostics)),buildStatLine("stale",formatBoolean(diagnostics.stale)),buildStatLine("truncated",formatBoolean(diagnostics.truncated)),buildStatLine("source snapshot",diagnostics.sourceContextChanged?"obsolete":"current")];if(latest&&latest.briefId!==active.briefId){lines.push(buildStatLine("latest generation",latest.status));if(latest.error){lines.push(buildStatLine("latest error",latest.error))}}return lines}async function buildFocusStatusText(params){const lines=[...buildHeaderLines(),"","\u{1F3AF} Lossless Claw Focus",""];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")}const store=new FocusBriefStore(params.db);const active=await store.getActiveFocusBrief(current.stats.conversationId);const latest=await store.getLatestFocusBrief(current.stats.conversationId);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")]),"");if(!active&&!latest){lines.push(buildSection("\u{1F3AF} Focus",[buildStatLine("status","none"),buildStatLine("usage",formatCommand(`${VISIBLE_COMMAND} focus <prompt>`)),buildStatLine("behavior","generates an active focus brief overlay")]));return lines.join("\n")}const primary=active??latest;if(!primary){return lines.join("\n")}const sources=await store.getFocusBriefSources(primary.briefId);const cited=sources.filter(source=>source.role==="cited").map(source=>source.summaryId);const diagnostics=await store.getFocusBriefDiagnostics(primary);lines.push(buildSection(active?"\u{1F3AF} Active focus brief":"\u{1F3AF} Latest focus brief",[buildStatLine("brief id",formatCommand(primary.briefId)),buildStatLine("status",primary.status),buildStatLine("created",formatFocusBriefTime(primary.createdAt,params.config.timezone)),buildStatLine("prompt",JSON.stringify(formatFocusPreview(primary.prompt,240))),buildStatLine("tokens",formatNumber(primary.tokenCount)),buildStatLine("target tokens",formatNumber(primary.targetTokens)),buildStatLine("source summaries",formatNumber(sources.filter(source=>source.role==="active_input").length)),buildStatLine("cited summaries",cited.length>0?cited.slice(0,8).join(", "):"none"),buildStatLine("generator run",primary.generatorRunId??"unknown"),buildStatLine("delta since focus",formatFocusDelta(diagnostics)),buildStatLine("stale",formatBoolean(diagnostics.stale)),buildStatLine("truncated",formatBoolean(diagnostics.truncated)),buildStatLine("source snapshot",diagnostics.sourceContextChanged?"obsolete":"current")]));if(latest&&active&&latest.briefId!==active.briefId){lines.push("",buildSection("\u26A0\uFE0F Latest generation",[buildStatLine("latest generation",latest.status),buildStatLine("brief id",formatCommand(latest.briefId)),...latest.error?[buildStatLine("error",latest.error)]:[]]))}else if(primary.error){lines.push("",buildSection("\u26A0\uFE0F Error",[primary.error]))}if(primary.content.trim()){lines.push("",buildSection("\u{1F4DD} Preview",[formatFocusPreview(primary.content)]))}return lines.join("\n")}async function buildFocusGenerateText(params){const lines=[...buildHeaderLines(),"","\u{1F3AF} Lossless Claw Focus",""];if(!params.deps||!params.getLcm){lines.push(buildSection("\u{1F6E0}\uFE0F Focus",[buildStatLine("status","unavailable"),buildStatLine("reason","Focus generation requires runtime dependencies for pre-focus compaction and delegated subagents.")]));return lines.join("\n")}const requesterSessionKey=normalizeIdentity(params.ctx.sessionKey);if(!requesterSessionKey){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason","OpenClaw must expose the active session key for Lossless Claw to spawn a focus subagent.")]));return lines.join("\n")}let 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")}const preFocusCompaction=await runFocusLifecycleCompaction({ctx:params.ctx,deps:params.deps,getLcm:params.getLcm,config:params.config,current,sessionKey:requesterSessionKey});if(preFocusCompaction.status!=="ok"){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(requesterSessionKey,44)))]),"",buildSection("\u{1F9F9} Pre-focus compaction",[buildStatLine("status",preFocusCompaction.status),buildStatLine("reason",preFocusCompaction.reason)]));return lines.join("\n")}current=await resolveCurrentConversation({ctx:params.ctx,db:params.db});if(current.kind==="unavailable"){lines.push(buildSection("\u{1F9F9} Pre-focus compaction",[buildStatLine("status","completed"),buildStatLine("result",preFocusCompaction.result.reason??"done")]),"",buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason)]));return lines.join("\n")}const store=new FocusBriefStore(params.db);const summaries=await store.getActiveContextSummaries(current.stats.conversationId);if(summaries.length===0){lines.push(buildSection("\u{1F3AF} Focus",[buildStatLine("status","unavailable"),buildStatLine("reason","The current conversation has no active summary context items to focus.")]));return lines.join("\n")}const sourceContextHash=hashFocusSourceContext(summaries);const watermark=await store.getCoveredWatermark(current.stats.conversationId);const generation=await runDelegatedFocusBrief({deps:params.deps,requesterSessionKey,conversationId:current.stats.conversationId,focusPrompt:params.prompt,summaries});const ordinalBySummaryId=new Map(summaries.map(summary=>[summary.summaryId,summary.ordinal]));const sources=[...summaries.map(summary=>({summaryId:summary.summaryId,ordinal:summary.ordinal,role:"active_input"})),...generation.citedSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"cited"})),...generation.expandedSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"expanded"})),...generation.irrelevantSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"irrelevant"}))];const ok=generation.status==="ok";const brief=await store.createFocusBrief({conversationId:current.stats.conversationId,sessionKey:requesterSessionKey,prompt:params.prompt,content:ok?generation.briefMarkdown:"",status:ok?"active":"failed",tokenCount:generation.tokenCount,targetTokens:generation.targetTokens,coveredLatestAt:watermark.coveredLatestAt,coveredMessageSeq:watermark.coveredMessageSeq,sourceContextHash,generatorRunId:generation.runId,generatorSessionKey:generation.childSessionKey,rawResultJson:generation.rawResultJson??JSON.stringify({status:generation.status,error:generation.error,rawReply:generation.rawReply}),error:generation.error??null,sources,supersedeCurrentDrafts:ok});lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(requesterSessionKey,44))),buildStatLine("source summaries",formatNumber(summaries.length)),buildStatLine("source context hash",sourceContextHash.slice(0,16))]),"",buildSection("\u{1F9F9} Pre-focus compaction",[buildStatLine("status","completed"),buildStatLine("compacted",formatBoolean(preFocusCompaction.result.compacted)),buildStatLine("result",preFocusCompaction.result.reason??"done")]),"",buildSection("\u{1F3AF} Focus brief",[buildStatLine("brief id",formatCommand(brief.briefId)),buildStatLine("status",brief.status),buildStatLine("prompt",JSON.stringify(formatFocusPreview(params.prompt,240))),buildStatLine("tokens",formatNumber(brief.tokenCount)),buildStatLine("target tokens",formatNumber(brief.targetTokens)),buildStatLine("generator run",generation.runId),buildStatLine("generator session",truncateMiddle(generation.childSessionKey,60)),buildStatLine("truncated",formatBoolean(generation.truncated))]));if(generation.warning){lines.push("",buildSection("\u26A0\uFE0F Generation warning",[generation.warning]))}if(!ok){lines.push("",buildSection("\u26A0\uFE0F Generation failed",[generation.error??"Focus brief generation failed without a specific error."]));return lines.join("\n")}lines.push("",buildSection("\u{1F4DD} Preview",[formatFocusPreview(generation.briefMarkdown)]));return lines.join("\n")}function isSummaryAfterFocusWatermark(summary,brief){if(brief.coveredMessageSeq!=null&&summary.maxSourceSeq!=null){return summary.maxSourceSeq>brief.coveredMessageSeq}if(!brief.coveredLatestAt){return true}const timestamp=summary.latestAt??summary.createdAt;const parsed=Date.parse(timestamp);if(!Number.isFinite(parsed)){return true}return parsed>brief.coveredLatestAt.getTime()}async function buildRefocusText(params){const lines=[...buildHeaderLines(),"","\u{1F3AF} Lossless Claw Refocus",""];if(!params.deps||!params.getLcm){lines.push(buildSection("\u{1F6E0}\uFE0F Refocus",[buildStatLine("status","unavailable"),buildStatLine("reason","Refocus requires runtime dependencies for pre-refocus compaction and delegated subagents.")]));return lines.join("\n")}const requesterSessionKey=normalizeIdentity(params.ctx.sessionKey);if(!requesterSessionKey){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason","OpenClaw must expose the active session key for Lossless Claw to refocus.")]));return lines.join("\n")}let 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")}const store=new FocusBriefStore(params.db);const active=await store.getActiveFocusBrief(current.stats.conversationId);if(!active?.content.trim()){lines.push(buildSection("\u{1F3AF} Refocus",[buildStatLine("status","unavailable"),buildStatLine("reason","The current conversation has no active focus brief to refresh.")]));return lines.join("\n")}const preRefocusCompaction=await runFocusLifecycleCompaction({ctx:params.ctx,deps:params.deps,getLcm:params.getLcm,config:params.config,current,sessionKey:requesterSessionKey});if(preRefocusCompaction.status!=="ok"){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(requesterSessionKey,44)))]),"",buildSection("\u{1F9F9} Pre-refocus compaction",[buildStatLine("status",preRefocusCompaction.status),buildStatLine("reason",preRefocusCompaction.reason)]));return lines.join("\n")}current=await resolveCurrentConversation({ctx:params.ctx,db:params.db});if(current.kind==="unavailable"){lines.push(buildSection("\u{1F9F9} Pre-refocus compaction",[buildStatLine("status","completed"),buildStatLine("result",preRefocusCompaction.result.reason??"done")]),"",buildSection("\u{1F4CD} Current conversation",[buildStatLine("status","unavailable"),buildStatLine("reason",current.reason)]));return lines.join("\n")}const activeSummaries=await store.getActiveContextSummaries(current.stats.conversationId);const deltaSummaries=activeSummaries.filter(summary=>isSummaryAfterFocusWatermark(summary,active));if(deltaSummaries.length===0){lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(requesterSessionKey,44)))]),"",buildSection("\u{1F9F9} Pre-refocus compaction",[buildStatLine("status","completed"),buildStatLine("compacted",formatBoolean(preRefocusCompaction.result.compacted)),buildStatLine("result",preRefocusCompaction.result.reason??"done")]),"",buildSection("\u{1F3AF} Refocus",[buildStatLine("status","already current"),buildStatLine("active brief",formatCommand(active.briefId)),buildStatLine("delta summaries","0")]));return lines.join("\n")}const sourceContextHash=hashFocusSourceContext(activeSummaries);const watermark=await store.getCoveredWatermark(current.stats.conversationId);const generation=await runDelegatedRefocusBrief({deps:params.deps,requesterSessionKey,conversationId:current.stats.conversationId,focusPrompt:active.prompt,existingBriefMarkdown:active.content,deltaSummaries});const ordinalBySummaryId=new Map(activeSummaries.map(summary=>[summary.summaryId,summary.ordinal]));const sources=[...deltaSummaries.map(summary=>({summaryId:summary.summaryId,ordinal:summary.ordinal,role:"active_input"})),...generation.citedSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"cited"})),...generation.expandedSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"expanded"})),...generation.irrelevantSummaryIds.map(summaryId=>({summaryId,ordinal:ordinalBySummaryId.get(summaryId)??null,role:"irrelevant"}))];const ok=generation.status==="ok";const brief=await store.createFocusBrief({conversationId:current.stats.conversationId,sessionKey:requesterSessionKey,prompt:active.prompt,content:ok?generation.briefMarkdown:"",status:ok?"active":"failed",tokenCount:generation.tokenCount,targetTokens:generation.targetTokens,coveredLatestAt:watermark.coveredLatestAt,coveredMessageSeq:watermark.coveredMessageSeq,sourceContextHash,generatorRunId:generation.runId,generatorSessionKey:generation.childSessionKey,rawResultJson:generation.rawResultJson??JSON.stringify({status:generation.status,error:generation.error,rawReply:generation.rawReply}),error:generation.error??null,sources,supersedeCurrentDrafts:ok});lines.push(buildSection("\u{1F4CD} Current conversation",[buildStatLine("conversation id",formatNumber(current.stats.conversationId)),buildStatLine("session key",formatCommand(truncateMiddle(requesterSessionKey,44))),buildStatLine("active brief",formatCommand(active.briefId)),buildStatLine("delta summaries",formatNumber(deltaSummaries.length)),buildStatLine("source context hash",sourceContextHash.slice(0,16))]),"",buildSection("\u{1F9F9} Pre-refocus compaction",[buildStatLine("status","completed"),buildStatLine("compacted",formatBoolean(preRefocusCompaction.result.compacted)),buildStatLine("result",preRefocusCompaction.result.reason??"done")]),"",buildSection("\u{1F3AF} Focus brief",[buildStatLine("brief id",formatCommand(brief.briefId)),buildStatLine("status",brief.status),buildStatLine("prompt",JSON.stringify(formatFocusPreview(active.prompt,240))),buildStatLine("tokens",formatNumber(brief.tokenCount)),buildStatLine("target tokens",formatNumber(brief.targetTokens)),buildStatLine("generator run",generation.runId),buildStatLine("generator session",truncateMiddle(generation.childSessionKey,60)),buildStatLine("truncated",formatBoolean(generation.truncated))]));if(generation.warning){lines.push("",buildSection("\u26A0\uFE0F Generation warning",[generation.warning]))}if(!ok){lines.push("",buildSection("\u26A0\uFE0F Generation failed",[generation.error??"Refocus brief generation failed without a specific error."]));return lines.join("\n")}lines.push("",buildSection("\u{1F4DD} Preview",[formatFocusPreview(generation.briefMarkdown)]));return lines.join("\n")}async function buildUnfocusText(params){const lines=[...buildHeaderLines(),"","\u{1F3AF} Lossless Claw Focus",""];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")}const store=new FocusBriefStore(params.db);const active=await store.getActiveFocusBrief(current.stats.conversationId);if(!active){lines.push(buildSection("\u{1F3AF} Focus",[buildStatLine("status","none active"),buildStatLine("deactivated briefs","0")]));return lines.join("\n")}const deactivated=await store.deactivateActiveFocusBriefs(current.stats.conversationId);const postUnfocusCompaction=await runFocusLifecycleCompaction({ctx:params.ctx,deps:params.deps,getLcm:params.getLcm,config:params.config,current,sessionKey:normalizeIdentity(params.ctx.sessionKey)??normalizeIdentity(current.stats.sessionKey??void 0)});lines.push(buildSection("\u{1F3AF} Focus",[buildStatLine("status",deactivated>0?"inactive":"none active"),buildStatLine("deactivated briefs",formatNumber(deactivated))]));lines.push("",buildSection("\u{1F9F9} Post-unfocus compaction",[buildStatLine("status",postUnfocusCompaction.status==="ok"?"completed":postUnfocusCompaction.status),...postUnfocusCompaction.status==="ok"?[buildStatLine("compacted",formatBoolean(postUnfocusCompaction.result.compacted)),buildStatLine("result",postUnfocusCompaction.result.reason??"done")]:[buildStatLine("reason",postUnfocusCompaction.reason)]]));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"focus_status":return{text:await buildFocusStatusText({ctx,db:await getDb(),config:params.config})};case"focus_generate":return{text:await buildFocusGenerateText({ctx,db:await getDb(),config:params.config,deps:params.deps,getLcm:params.getLcm,prompt:parsed.prompt})};case"refocus":return{text:await buildRefocusText({ctx,db:await getDb(),config:params.config,deps:params.deps,getLcm:params.getLcm})};case"unfocus":return{text:await buildUnfocusText({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"}function readRuntimeConfigSnapshot(api){const configApi=api.runtime.config;if(!configApi){return void 0}if(typeof configApi.current==="function"){return configApi.current()}if(typeof configApi.loadConfig==="function"){return configApi.loadConfig()}return void 0}function getRuntimeAgentSessionApi(api){const runtime=api.runtime;const sessionApi=runtime.agent?.session??runtime.channel?.session;if(!sessionApi){return void 0}if(typeof sessionApi.resolveStorePath!=="function"||typeof sessionApi.loadSessionStore!=="function"||typeof sessionApi.resolveSessionFilePath!=="function"){return void 0}return sessionApi}function listConfiguredAgentIds(config){const agents=isRecord2(config)?config.agents:void 0;const list=isRecord2(agents)&&Array.isArray(agents.list)?agents.list:[];const seen=new Set;const ids=[];for(const entry of list){if(!isRecord2(entry)||entry.enabled===false||typeof entry.id!=="string"){continue}const agentId=normalizeAgentId(entry.id);if(seen.has(agentId)){continue}seen.add(agentId);ids.push(agentId)}return ids.length>0?ids:["main"]}function getStringField(record,key){const value=record?.[key];return typeof value==="string"&&value.trim()?value.trim():void 0}function toNonNegativeInteger(value){if(typeof value!=="number"||!Number.isFinite(value)||value<0){return void 0}return Math.floor(value)}var RECOVERED_SYSTEM_PROMPT_TOKEN_FLOOR=4096;function estimateRecoveredSessionTotalTokens(params){const entry=params.sessionEntry;const inputTokens=toNonNegativeInteger(entry.inputTokens)??toNonNegativeInteger(entry.input)??toNonNegativeInteger(entry.promptTokens)??toNonNegativeInteger(entry.prompt_tokens)??0;const cacheRead=toNonNegativeInteger(entry.cacheRead)??toNonNegativeInteger(entry.cache_read)??0;const cacheWrite=toNonNegativeInteger(entry.cacheWrite)??toNonNegativeInteger(entry.cache_write)??0;const contextTokens=Math.max(0,Math.floor(params.contextTokenEstimate));const runtimePromptTokens=inputTokens+cacheRead+cacheWrite;return Math.max(RECOVERED_SYSTEM_PROMPT_TOKEN_FLOOR,contextTokens+runtimePromptTokens)}function hasFreshTotalTokens(sessionEntry){return sessionEntry.totalTokensFresh===true&&toNonNegativeInteger(sessionEntry.totalTokens)!==void 0}var RUNTIME_LLM_PR_URL="https://github.com/openclaw/openclaw/pull/64294";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 regular expressions and literal patterns that use regex syntax.','- Full-text queries are not regexes. Alternation (`A|B`), regex wildcards (`.*`), character classes (`[abc]`), and anchors (`^foo`, `foo$`) require `mode: "regex"`.',"- 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.","","## Compacted Conversation Context","","If compacted summaries appear above, treat them 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.',"","For exact commands, SHAs, paths, timestamps, config values, or causal chains, expand for details before answering.","","State uncertainty instead of guessing from compacted summaries.","","**Precision flow:**","1. `lcm_grep` to find the relevant summaries or messages","2. `lcm_expand_query` when you need exact evidence before answering","3. Answer from the retrieved evidence instead of summary paraphrase","","**Uncertainty checklist:**","- Am I making an exact factual claim from compacted context?","- Could compaction have omitted a crucial detail?","- Would I need an expansion step if the user asks for proof or exact text?","","If yes to any item, expand first or explicitly say that you need to expand.","","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 isRecord2(value){return!!value&&typeof value==="object"&&!Array.isArray(value)}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 detectProviderBridgeError(error){const statusCode=extractErrorStatusCode(error);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_error",...statusCode!==void 0?{statusCode}:{},...directCode?{code:directCode}:{},message:truncateErrorMessage(describeLogError(error))}}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=readRuntimeConfigSnapshot(api);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 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 getRuntimeLlm(api){const runtime=api.runtime;return typeof runtime.llm?.complete==="function"?runtime.llm:void 0}function buildRuntimeLlmUnavailableError(){return{kind:"provider_error",message:`[lcm] OpenClaw runtime.llm.complete is unavailable. Install an OpenClaw build with Plugin SDK runtime LLM support (${RUNTIME_LLM_PR_URL}).`}}function toRuntimeLlmMessages(messages){return messages.filter(message=>message.role==="system"||message.role==="user"||message.role==="assistant").map(message=>({role:message.role,content:stringifyRuntimeLlmContent(message.content)}))}function stringifyRuntimeLlmContent(content){if(typeof content==="string"){return content}if(content===null||content===void 0){return""}if(typeof content==="number"||typeof content==="boolean"||typeof content==="bigint"){return String(content)}try{return JSON.stringify(content)}catch{return String(content)}}function buildRuntimeModelRef(provider,model){const modelId=model.trim();if(!modelId){return void 0}const slash=modelId.indexOf("/");if(slash>0&&slash<modelId.length-1){const directProvider=modelId.slice(0,slash).trim();const directModel=modelId.slice(slash+1).trim();return directProvider&&directModel?`${directProvider}/${directModel}`:void 0}const providerId=provider?.trim();return providerId?`${providerId}/${modelId}`:modelId}function buildRuntimeLlmPolicySnippet(modelRef){return JSON.stringify({plugins:{entries:{"lossless-claw":{llm:{allowModelOverride:true,allowedModels:[modelRef]}}}}},null,2)}function isRuntimeLlmModelPolicyDenial(error){const text=describeLogError(error);return/Plugin LLM completion (cannot override the target model|model override .*not allowlisted|model override allowlist|model override allowlist requires)/i.test(text)}function buildRuntimeLlmPolicyError(override,error){const detail=truncateErrorMessage(describeLogError(error),200);return{kind:"runtime_llm_policy",code:"runtime_llm_model_override_denied",configField:override.configField,configPath:override.configPath,modelRef:override.modelRef,message:`[lcm] OpenClaw denied the Lossless runtime LLM model override from ${override.configPath} (${override.configField}). Requested model: ${override.modelRef}. Configure plugins.entries.lossless-claw.llm.allowModelOverride and plugins.entries.lossless-claw.llm.allowedModels, or run "openclaw doctor --fix". Minimal config:
|
|
1390
1390
|
${buildRuntimeLlmPolicySnippet(override.modelRef)}
|
|
1391
1391
|
Host error: ${detail}`}}function buildConfiguredModelRequirement(params){const modelId=typeof params.model==="string"?params.model.trim():"";if(!modelId){return void 0}const modelRef=buildRuntimeModelRef(typeof params.provider==="string"?params.provider.trim():void 0,modelId);if(!modelRef?.includes("/")){return{unresolved:{configField:params.configField,configPath:params.configPath,reason:`${params.configPath} is a bare model without a provider. Use provider/model or set the matching provider field so openclaw doctor --fix can update plugins.entries.lossless-claw.llm.allowedModels.`}}}return{configField:params.configField,configPath:params.configPath,modelRef}}function collectRuntimeLlmPolicyRequirements(config){const required=[];const unresolved=[];const add=candidate=>{if(!candidate){return}if("unresolved"in candidate){unresolved.push(candidate.unresolved);return}required.push(candidate)};add(buildConfiguredModelRequirement({configField:"summaryModel",configPath:"plugins.entries.lossless-claw.config.summaryModel",provider:config.summaryProvider,model:config.summaryModel}));add(buildConfiguredModelRequirement({configField:"largeFileSummaryModel",configPath:"plugins.entries.lossless-claw.config.largeFileSummaryModel",provider:config.largeFileSummaryProvider,model:config.largeFileSummaryModel}));for(const[index,fallback]of config.fallbackProviders.entries()){add(buildConfiguredModelRequirement({configField:"fallbackProviders",configPath:`plugins.entries.lossless-claw.config.fallbackProviders[${index}]`,provider:fallback.provider,model:fallback.model}))}const seen=new Set;return{required:required.filter(entry=>{const key=`${entry.configField}\0${entry.modelRef}`;if(seen.has(key)){return false}seen.add(key);return true}),unresolved}}function readRuntimeLlmPolicy(openClawConfig){const plugins=isRecord2(openClawConfig)?openClawConfig.plugins:void 0;const entries=isRecord2(plugins)?plugins.entries:void 0;const entry=isRecord2(entries)?entries["lossless-claw"]:void 0;const llm=isRecord2(entry)?entry.llm:void 0;if(!isRecord2(llm)){return{allowModelOverride:false,allowedModels:new Set,allowAnyModel:false,available:false}}const allowed=Array.isArray(llm.allowedModels)?llm.allowedModels.filter(model=>typeof model==="string"):[];return{allowModelOverride:llm.allowModelOverride===true,allowedModels:new Set(allowed),allowAnyModel:allowed.includes("*"),available:true}}function checkRuntimeLlmPolicyRequirements(params){const{required,unresolved}=collectRuntimeLlmPolicyRequirements(params.config);const policy=readRuntimeLlmPolicy(params.openClawConfig);return{required,unresolved,missingAllowModelOverride:required.length>0&&policy.allowModelOverride!==true,missingAllowedModels:policy.allowAnyModel?[]:required.filter(entry=>!policy.allowedModels.has(entry.modelRef)),policyAvailable:policy.available}}function formatRuntimeLlmPolicyStartupWarning(check){if(check.required.length===0&&check.unresolved.length===0){return void 0}if(check.policyAvailable&&!check.missingAllowModelOverride&&check.missingAllowedModels.length===0&&check.unresolved.length===0){return void 0}const parts=["[lcm] Runtime LLM model override policy may block configured Lossless summary models.",'Run "openclaw doctor --fix" to repair plugins.entries.lossless-claw.llm.',"Required config path: plugins.entries.lossless-claw.llm.allowModelOverride and plugins.entries.lossless-claw.llm.allowedModels."];if(!check.policyAvailable){parts.push("Host policy was not visible in the plugin registration config; using best-effort validation.")}if(check.missingAllowModelOverride){parts.push("Missing: plugins.entries.lossless-claw.llm.allowModelOverride = true.")}if(check.missingAllowedModels.length>0){parts.push(`Missing allowedModels entries: ${check.missingAllowedModels.map(entry=>`${entry.configField}=${entry.modelRef}`).join(", ")}.`)}if(check.unresolved.length>0){parts.push(`Unresolved model refs: ${check.unresolved.map(entry=>`${entry.configPath} (${entry.reason})`).join("; ")}.`)}return parts.join(" ")}function createLcmDependencies(api,registrationConfig=resolveRegistrationConfig(api)){const envSnapshot=snapshotPluginEnv();envSnapshot.openclawDefaultModel=readDefaultModelFromConfig(registrationConfig.openClawConfig);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()}}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 runtimeLlmUnavailableError=buildRuntimeLlmUnavailableError();if(!getRuntimeLlm(api)){logStartupBannerOnce({key:"runtime-llm-unavailable",log:message=>log.warn(message),message:runtimeLlmUnavailableError.message??"[lcm] OpenClaw runtime.llm.complete is unavailable."})}const runtimeLlmPolicyWarning=formatRuntimeLlmPolicyStartupWarning(checkRuntimeLlmPolicyRequirements({config,openClawConfig:registrationConfig.openClawConfig}));if(runtimeLlmPolicyWarning){logStartupBannerOnce({key:"runtime-llm-policy-summary-models",log:message=>log.warn(message),message:runtimeLlmPolicyWarning})}return{config,configDiagnostics:diagnostics,complete:async({provider,model,runtimeModelOverride,runtimeLlmComplete,agentId,messages,system,maxTokens,temperature,reasoning,reasoningIfSupported})=>{const providerId=provider?.trim();const modelId=model.trim();const modelRef=runtimeModelOverride?.modelRef.trim();const runtimeLlm=runtimeLlmComplete??getRuntimeLlm(api)?.complete;const isBoundRuntimeLlm=!!runtimeLlmComplete;const requestMetadata={request_provider:providerId??"(runtime)",request_model:modelId||"(runtime)",request_api:"runtime.llm",request_reasoning:reasoning?.trim()||reasoningIfSupported?.trim()||"(host-managed)",request_has_system:typeof system==="string"&&system.trim().length>0?"true":"false",request_temperature:typeof temperature==="number"&&Number.isFinite(temperature)?String(temperature):"(omitted)",request_temperature_sent:typeof temperature==="number"&&Number.isFinite(temperature)?"true":"false"};if(!runtimeLlm){return{content:[],error:runtimeLlmUnavailableError,...requestMetadata}}try{const result=await runtimeLlm({messages:toRuntimeLlmMessages(messages),...modelRef?{model:modelRef}:{},...typeof maxTokens==="number"&&Number.isFinite(maxTokens)?{maxTokens}:{},...typeof temperature==="number"&&Number.isFinite(temperature)?{temperature}:{},...typeof system==="string"&&system.trim()?{systemPrompt:system.trim()}:{},purpose:"lossless-claw compaction summarization",...isBoundRuntimeLlm&&agentId?.trim()?{agentId:agentId.trim()}:{}});const text=typeof result.text==="string"?result.text:"";return{content:text?[{type:"text",text}]:[],provider:result.provider,model:result.model,agentId:result.agentId,usage:result.usage,audit:result.audit,...requestMetadata}}catch(err){log.error(`[lcm] runtime.llm.complete error: ${describeLogError(err)}`);if(runtimeModelOverride&&isRuntimeLlmModelPolicyDenial(err)){return{content:[],error:buildRuntimeLlmPolicyError(runtimeModelOverride,err),...requestMetadata}}const authError=detectProviderAuthError(err);return{content:[],error:authError??detectProviderBridgeError(err),...requestMetadata}}},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}},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 sessionApi=getRuntimeAgentSessionApi(api);if(!sessionApi){return void 0}const cfg=readRuntimeConfigSnapshot(api);const sessionConfig=isRecord2(cfg)&&isRecord2(cfg.session)?cfg.session:void 0;const parsed=parseAgentSessionKey(key);const agentId=normalizeAgentId(parsed?.agentId);const storePath=sessionApi.resolveStorePath(getStringField(sessionConfig,"store"),{agentId});const store=sessionApi.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 sessionApi=getRuntimeAgentSessionApi(api);if(!sessionApi){return void 0}const cfg=readRuntimeConfigSnapshot(api);const sessionConfig=isRecord2(cfg)&&isRecord2(cfg.session)?cfg.session:void 0;const normalizedSessionKey=sessionKey?.trim();const parsed=normalizedSessionKey?parseAgentSessionKey(normalizedSessionKey):null;const agentId=normalizeAgentId(parsed?.agentId);const storePath=sessionApi.resolveStorePath(getStringField(sessionConfig,"store"),{agentId});const store=sessionApi.loadSessionStore(storePath);const entry=(normalizedSessionKey?store[normalizedSessionKey]:void 0)??Object.values(store).find(candidate=>candidate?.sessionId===normalizedSessionId);const transcriptPath=sessionApi.resolveSessionFilePath(normalizedSessionId,entry,{agentId,storePath});return transcriptPath.trim()||void 0}catch{return void 0}},listStartupSessionFileCandidates:async()=>{const sessionApi=getRuntimeAgentSessionApi(api);if(!sessionApi){return[]}let cfg=registrationConfig.openClawConfig;try{const liveConfig=readRuntimeConfigSnapshot(api);if(liveConfig!==void 0){cfg=liveConfig}}catch{}const sessionConfig=isRecord2(cfg)&&isRecord2(cfg.session)?cfg.session:void 0;const storeConfig=getStringField(sessionConfig,"store");const candidates=[];const seen=new Set;for(const agentId of listConfiguredAgentIds(cfg)){let storePath;let store;try{storePath=sessionApi.resolveStorePath(storeConfig,{agentId});store=sessionApi.loadSessionStore(storePath)}catch{continue}for(const[rawSessionKey,rawEntry]of Object.entries(store)){const sessionKey=rawSessionKey.trim();if(!sessionKey||!isRecord2(rawEntry)){continue}const parsed=parseAgentSessionKey(sessionKey);if(parsed?.agentId&&normalizeAgentId(parsed.agentId)!==agentId){continue}const sessionId=getStringField(rawEntry,"sessionId");if(!sessionId){continue}let sessionFile;try{sessionFile=sessionApi.resolveSessionFilePath(sessionId,rawEntry,{agentId,storePath}).trim()}catch{continue}if(!sessionFile){continue}const dedupeKey=`${sessionId}\0${sessionKey}\0${sessionFile}`;if(seen.has(dedupeKey)){continue}seen.add(dedupeKey);candidates.push({sessionId,sessionKey,sessionFile,agentId,storePath})}}return candidates},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.registerTool(ctx=>createLcmGrepTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey}),{name:"lcm_grep"});api.registerTool(ctx=>createLcmDescribeTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey}),{name:"lcm_describe"});api.registerTool(ctx=>createLcmExpandTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey}),{name:"lcm_expand"});api.registerTool(ctx=>createLcmExpandQueryTool({deps,getLcm:shared.waitForEngine,sessionKey:ctx.sessionKey,requesterSessionKey:ctx.sessionKey}),{name:"lcm_expand_query"});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 threshold 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.debug(`[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 scheduleStartupAutoRotate(nextEngine){void nextEngine.autoRotateManagedSessionFilesAtStartup().catch(error=>{deps.log.warn(`[lcm] auto-rotate: phase=startup action=warn durationMs=0 reason=startup-scan-failed error=${describeLogError(error).replace(/\s+/g,"_")}`)})}async function recoverStartupSessionTotalTokens(nextEngine){const sessionApi=getRuntimeAgentSessionApi(api);if(!sessionApi){return}let cfg=registrationConfig.openClawConfig;try{const liveConfig=readRuntimeConfigSnapshot(api);if(liveConfig!==void 0){cfg=liveConfig}}catch{}const sessionConfig=isRecord2(cfg)&&isRecord2(cfg.session)?cfg.session:void 0;const storeConfig=getStringField(sessionConfig,"store");const activeConversations=await nextEngine.getConversationStore().listActiveConversations();if(activeConversations.length===0){return}const loadedStores=new Map;const pendingUpdates=new Map;for(const conversation of activeConversations){const sessionId=conversation.sessionId?.trim();if(!sessionId){continue}const sessionKey=conversation.sessionKey?.trim();const parsed=sessionKey?parseAgentSessionKey(sessionKey):null;const agentId=normalizeAgentId(parsed?.agentId);let storePath;try{storePath=sessionApi.resolveStorePath(storeConfig,{agentId}).trim()}catch{continue}if(!storePath){continue}let store=loadedStores.get(storePath);if(!store){try{store=sessionApi.loadSessionStore(storePath)}catch{continue}loadedStores.set(storePath,store)}const lookupKey=(sessionKey&&isRecord2(store[sessionKey])?sessionKey:void 0)??Object.entries(store).find(([,entry])=>{if(!isRecord2(entry)){return false}const entrySessionId=entry.sessionId;return typeof entrySessionId==="string"&&entrySessionId.trim()===sessionId})?.[0];if(!lookupKey){continue}const rawEntry=store[lookupKey];if(!isRecord2(rawEntry)){continue}const sessionEntry=rawEntry;if(hasFreshTotalTokens(sessionEntry)){continue}const contextTokenEstimate=await nextEngine.getSummaryStore().getContextTokenCount(conversation.conversationId);const estimatedTotalTokens=estimateRecoveredSessionTotalTokens({contextTokenEstimate,sessionEntry});let storeUpdates=pendingUpdates.get(storePath);if(!storeUpdates){storeUpdates=new Map;pendingUpdates.set(storePath,storeUpdates)}storeUpdates.set(lookupKey,estimatedTotalTokens)}let recovered=0;for(const[storePath,storeUpdates]of pendingUpdates){let currentStore;try{currentStore=sessionApi.loadSessionStore(storePath)}catch{continue}let changed=false;for(const[lookupKey,estimatedTotalTokens]of storeUpdates){const rawEntry=currentStore[lookupKey];if(!isRecord2(rawEntry)){continue}const sessionEntry=rawEntry;if(hasFreshTotalTokens(sessionEntry)){continue}currentStore[lookupKey]={...sessionEntry,totalTokens:estimatedTotalTokens,totalTokensFresh:true};changed=true;recovered+=1}if(changed){await writeFile2(storePath,`${JSON.stringify(currentStore,null,2)}
|
|
1392
1392
|
`,"utf8")}}if(recovered>0){deps.log.info(`[lcm] startup totalTokens recovery updated ${recovered} session ${recovered===1?"entry":"entries"}`)}}function scheduleStartupSessionTotalTokensRecovery(nextEngine){void recoverStartupSessionTotalTokens(nextEngine).catch(error=>{deps.log.warn(`[lcm] startup totalTokens recovery failed: ${describeLogError(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`);scheduleStartupAutoRotate(nextEngine);scheduleStartupSessionTotalTokensRecovery(nextEngine);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{plugin_default as default};
|