beeos-claw 0.6.30 → 0.6.32

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.
@@ -0,0 +1 @@
1
+ import{isSilentReplyPayloadText,startsWithSilentToken,stripHeartbeatToken,stripLeadingSilentToken,stripSilentToken}from"../auto-reply-tokens.js";const MESSAGE_TOOL_NAME="message";export function sanitizeEgressText(t){if(!t)return"";const e=stripHeartbeatToken(t,{mode:"message"});if(e.shouldSkip)return"";let n=e.text;return isSilentReplyPayloadText(n)?"":(startsWithSilentToken(n)&&(n=stripLeadingSilentToken(n)),n=stripSilentToken(n),n.trim())}export function classifyMediaRef(t){const e=t.trim();return e?/^https?:\/\//i.test(e)||/^beeos-file:\/\//i.test(e)?"remote":/^file:\/\//i.test(e)||e.startsWith("/")?"local":"unusable":"unusable"}export function localPathFromRef(t){const e=t.trim();return/^file:\/\//i.test(e)?decodeURI(e.slice(7)):e}function asNonEmptyString(t){return"string"==typeof t&&t.trim()?t.trim():void 0}export function extractMessageToolAttachments(t,e){if("message"!==t)return[];if(!e||"object"!=typeof e)return[];const n=e,r=[],s=(t,e,n)=>{t&&r.push({uri:t,...e?{name:e}:{},...n?{mimeType:n}:{}})},i=n.attachments;if(Array.isArray(i))for(const t of i){if(!t||"object"!=typeof t)continue;const e=t;s(asNonEmptyString(e.media)??asNonEmptyString(e.mediaUrl)??asNonEmptyString(e.url)??asNonEmptyString(e.fileUrl)??asNonEmptyString(e.path)??asNonEmptyString(e.filePath),asNonEmptyString(e.name),asNonEmptyString(e.mimeType))}return s(asNonEmptyString(n.path)??asNonEmptyString(n.filePath),void 0,asNonEmptyString(n.mimeType)),r}export function extractMessageToolCaption(t,e){if("message"!==t)return;if(!e||"object"!=typeof e)return;const n=e;return asNonEmptyString(n.message)??asNonEmptyString(n.caption)??asNonEmptyString(n.text)}export function buildBackgroundRunImEgress(t){if(!0!==t.backgroundRunAdopted)return{publish:!1,reason:"not_background_run"};if(t.cronJobId)return{publish:!1,reason:"cron_owned"};const e=t.channelId?.trim();if(!e)return{publish:!1,reason:"no_origin_conversation"};const n=t.currentRunId?.trim();if(!n)return{publish:!1,reason:"no_run_id"};const r=sanitizeEgressText(t.agentAssistantTextSoFar??t.chatAssistantTextSoFar)||sanitizeEgressText(t.backgroundRunCaption),s=dedupeArtifacts(t.backgroundRunArtifacts??[]);if(!r&&0===s.length)return{publish:!1,reason:"no_publishable_content"};const i=t.inboundMessageId?.trim();return{publish:!0,egress:{conversationId:e,runId:n,text:r,artifacts:s,...i?{replyTo:i}:{}}}}function dedupeArtifacts(t){const e=new Set,n=[];for(const r of t){const t=r?.uri?.trim();t&&!e.has(t)&&("unusable"!==classifyMediaRef(t)&&(e.add(t),n.push(r)))}return n}export async function resolveEgressMediaUrls(t,e){const n=[],r=[],s=new Set,i=t=>{s.has(t)||(s.add(t),n.push(t))};for(const n of t){const t=n?.uri?.trim();if(t)switch(classifyMediaRef(t)){case"remote":i(t);break;case"local":{if(!e){r.push(t);break}const s=await e(localPathFromRef(t),n.name);s?i(s):r.push(t);break}default:r.push(t)}}return{mediaUrls:n,unresolved:r}}export function backgroundRunEgressMessageId(t){return`bgrun_${t}`}export function backgroundRunEgressContent(t){return{...t.text?{text:t.text}:{},...t.mediaUrls.length>0?{media_urls:[...t.mediaUrls]}:{},background_run_id:t.runId}}
@@ -1 +1 @@
1
- import{createHash,randomUUID}from"node:crypto";import{Errors}from"../errors/index.js";import{BEEOS_CHANNEL_TAG_RE,decodeBeeosChannelId,encodeBeeosChannelTag}from"./bridge-core.js";import{classifyAgentRuntimeFailure}from"../runtime/agent-runtime-failure-classifier.js";import{stripTransportMetadata,normalizeTransportText,previewSanitizedText}from"../message-sanitization/transport-metadata-sanitizer.js";import{classifyHeartbeatFilter}from"../message-sanitization/message-classifier.js";import{emitNormalizedToolResultForTurn}from"./tool-result-emitter.js";import{buildToolCallPayload}from"./tool-call-payload-builder.js";import{DEFAULT_STREAM_IDLE_TIMEOUT_MS,DEFAULT_STREAM_STALE_TIMEOUT_MS}from"./types.js";import{MessageQueue}from"../utils/mq.js";import{observeLifecyclePromise}from"../runtime/lifecycle-promise-observer.js";export function lifecycleEndFailureMessage(e){if(!e)return;const t=!0===e.isError||!0===e.is_error,s=e.error,o=s&&"object"==typeof s?s:void 0,n="string"==typeof s||void 0!==o||"string"==typeof e.message||"string"==typeof e.reason;if(t||n){if(!t){const t="string"==typeof e.stopReason?e.stopReason:"";if("error"!==t&&"timeout"!==t&&"aborted"!==t)return}return("string"==typeof e.message?e.message:void 0)??("string"==typeof s?s:void 0)??("string"==typeof o?.message?o.message:void 0)??("string"==typeof e.reason?e.reason:void 0)??(o?JSON.stringify(o):void 0)??"gateway lifecycle error"}}function asString(e){if("string"==typeof e){return e.trim()||void 0}}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function normalizeText(e){if("string"==typeof e)return normalizeTransportText(e.replace(/\r\n/g,"\n").replace(/\r/g,"\n"))}const DEDUP_HASH_THRESHOLD=256;function dedupKey(e,...t){const s=`${e}:${t.join(":")}`;if(s.length<=256)return s;return`${e}:h:${createHash("sha256").update(s).digest("hex").slice(0,24)}`}function toISO(e){if(!(null==e||e<=0))try{return new Date(e).toISOString()}catch{return}}function resolveToolArgs(e){const t=e.arguments??e.args??e.input;if(isRecord(t))return t;if("string"==typeof t){const e=t.trim();if(e.startsWith("{")||e.startsWith("["))try{return JSON.parse(e)}catch{}}return{}}export function resolveTurnId(e){if(e.currentRunId)return e.currentRunId;const t=e.pendingPromptId;return void 0!==t?"string"==typeof t?`req:${t}`:`req:${String(t)}`:void 0}export function roleFromSessionUpdate(e){const t=e.sessionUpdate;if(t)return"user_message_chunk"===t?"user":"system_message_chunk"===t?"system":t.startsWith("agent_")||t.startsWith("tool_")?"assistant":"history_turn"===t?"user"===e.role?"user":"system"===e.role?"system":"assistant":void 0}export function recordTurnIdForRole(e,t,s){if(!s)return;const o=roleFromSessionUpdate(t);o&&(e.lastTurnIdByRole||(e.lastTurnIdByRole={}),e.lastTurnIdByRole[o]=s)}export function recordToolCallTurnForUpdate(e,t,s){s&&"tool_call"===t.sessionUpdate&&t.toolCallId&&(e.toolCallTurns??=new Map,e.toolCallTurns.set(t.toolCallId,{turnId:s,..."string"==typeof t.name&&t.name?{toolName:t.name}:{}}))}export class AcpGatewayEvents{state;transport;config;logger;writeObs;completePrompt;failPrompt;interruptPrompt;schedulePromptTimeout;adoptBackgroundMutation;abortGatewayRun;maybeCompletePromptFromChatState;agentFetchFn;getMessageClient;getMsgPrincipalId;gatewayRequest;getCanvasState;cronChannelCache;constructor(e){this.state=e.state,this.transport=e.transport,this.config=e.config,this.logger=e.logger,this.writeObs=e.writeObs,this.completePrompt=e.completePrompt,this.failPrompt=e.failPrompt,this.interruptPrompt=e.interruptPrompt,this.schedulePromptTimeout=e.schedulePromptTimeout,this.adoptBackgroundMutation=e.adoptBackgroundMutation,this.abortGatewayRun=e.abortGatewayRun,this.maybeCompletePromptFromChatState=e.maybeCompletePromptFromChatState,this.agentFetchFn=e.agentFetch,this.getMessageClient=e.getMessageClient,this.getMsgPrincipalId=e.getMsgPrincipalId,this.gatewayRequest=e.gatewayRequest,this.getCanvasState=e.getCanvasState,this.cronChannelCache=e.cronChannelCache}observeLifecycle(e,t,s){observeLifecyclePromise(e,this.logger,{component:"gateway-events",action:t,sessionId:s.sessionId,gatewaySessionKey:s.gatewaySessionKey})}touchStreamActivity(e){e.lastStreamActivityTs=Date.now(),this.resetStreamIdleTimer(e)}resetStreamIdleTimer(e){this.state.clearStreamIdleTimer(e);const t=this.config.streamIdleTimeoutMs??DEFAULT_STREAM_IDLE_TIMEOUT_MS,s=this.config.streamStaleTimeoutMs??DEFAULT_STREAM_STALE_TIMEOUT_MS;e.streamIdleTimer=setTimeout(()=>{if(!e.lastStreamActivityTs)return;const t=Date.now()-e.lastStreamActivityTs;t>s&&(this.logger.warn?.(`[gateway-events] Stream stale timeout sessionId=${e.sessionId} stale=${t}ms`),this.observeLifecycle(this.interruptPrompt(e,classifyAgentRuntimeFailure({raw:`Stream stale timeout after ${t}ms`,source:"live_gateway",runtimeKind:"openclaw"})),"stream_stale_timeout",e))},t),"object"==typeof e.streamIdleTimer&&"unref"in e.streamIdleTimer&&e.streamIdleTimer.unref()}sendTurnUpdate(e,t){const s=resolveTurnId(e);return s&&void 0===t._turnId&&(t._turnId=s),recordTurnIdForRole(e,t,s),recordToolCallTurnForUpdate(e,t,s),!!e.sessionLoadInProgress||this.transport.sendSessionUpdate(e.sessionId,t,{turnId:s})}sendToolCallSpacer(e,t){const s={sessionUpdate:"agent_message_chunk",content:{type:"text",text:"\n"},...t?{timestamp:t}:{}};this.sendTurnUpdate(e,s),e.assistantMq?.push(s)}resolveToolCallId(e,t,s){const o=asString(t.toolCallId)??asString(t.tool_call_id)??asString(t.callId)??asString(t.id);if(o){const t=this.state.toolCallIdMap.get(o);return t?(e.sessionId&&this.state.toolCallToSessionMap.set(t,e.sessionId),t):(this.state.toolCallIdMap.set(o,o),e.sessionId&&this.state.toolCallToSessionMap.set(o,e.sessionId),o)}const n=`tc_${e.currentRunId??"unknown"}_${this.state.nextToolCallSeq++}`;return e.sessionId&&this.state.toolCallToSessionMap.set(n,e.sessionId),n}handleChatEvent(e){const t=(e.runId?this.state.promptsByRunId.get(e.runId):void 0)??this.state.findSessionByKey(e.sessionKey);if(!t)return;if(!this.state.isCurrentStreamOwner(t,e.runId)){const s=!t.currentRunId&&void 0===t.pendingPromptId;if(!e.runId||!s||this.state.isRunCompleted(e.runId))return;if(!this.adoptBackgroundRun(t,e.runId))return}t.sessionId;const s=e.message;if(s){this.touchStreamActivity(t);if("assistant"===s.role){if(!Array.isArray(s.content))return;for(const o of s.content){const n=o;if(!isRecord(n))continue;const a=asString(n.type);if(!a)continue;const i=toISO(s.timestamp);if("thinking"===a){if(t.hasAgentThinkingStream)continue;const e=normalizeText(n.thinking)??normalizeText(n.text);if(!e)continue;const s=dedupKey("chat:thinking",e);if(t.chatReplayDedupKeys.has(s))continue;t.chatReplayDedupKeys.add(s);const o={sessionUpdate:"agent_thought_chunk",content:{type:"text",text:e},...i?{timestamp:i}:{}};this.sendTurnUpdate(t,o)&&t.assistantMq?.push(o);continue}if("toolCall"===a){if(this.sendToolCallSpacer(t,i),t.hasAgentToolStartStream)continue;const e=this.resolveToolCallId(t,n,"start"),s=asString(n.name)??asString(n.toolName)??asString(n.tool_name)??"tool",o=resolveToolArgs(n),a=dedupKey("chat:tool_start",e,JSON.stringify(o));if(t.chatReplayDedupKeys.has(a))continue;t.chatReplayDedupKeys.add(a);const r=buildToolCallPayload({toolCallId:e,toolName:s,args:o,timestamp:i});this.sendTurnUpdate(t,r)&&t.assistantMq?.push(r);continue}if("toolResult"===a){if(this.sendToolCallSpacer(t,i),t.hasAgentToolResultStream)continue;const e=this.resolveToolCallId(t,n,"result"),s=asString(n.name)??asString(n.toolName)??asString(n.tool_name)??"tool",o=n.result,a=normalizeText(n.text)??normalizeText(n.result)??(isRecord(o)||Array.isArray(o)?JSON.stringify(o,null,2):void 0);if(!a)continue;const r=dedupKey("chat:tool_result",e,a);if(t.chatReplayDedupKeys.has(r))continue;t.chatReplayDedupKeys.add(r),this.emitNormalizedToolResult(t,{toolCallId:e,toolName:s,rawText:a,rawResult:o,timestamp:i}).catch(e=>{this.logger.warn?.(`[gateway-events] Tool result normalization failed: ${e instanceof Error?e.message:e}`)});continue}if("text"===a&&n.text){if(t.hasAgentAssistantStream||t.agentAssistantTextSoFar)continue;const s=stripTransportMetadata(n.text);if(!s)continue;const o=classifyHeartbeatFilter(s);if(o.filtered){this.logHeartbeatSkip({source:"chat-text",reason:o.reason,sessionId:t.sessionId,runId:e.runId,cumulative:s});continue}const a=dedupKey("chat:text",s);if(t.chatReplayDedupKeys.has(a))continue;t.chatReplayDedupKeys.add(a);const r=t.chatAssistantTextSoFar??"";let l;if(t.chatAssistantTextSoFar=s,s.startsWith(r))l=s.slice(r.length);else{if(r.startsWith(s))continue;l=s}if(!l)continue;this.logger.debug?.(`[gateway-events] chat.text delta seq=${e.seq} runId=${e.runId} len=${l.length} prevLen=${r.length}`);const c={sessionUpdate:"agent_message_chunk",content:{type:"text",text:l},...i?{timestamp:i}:{}};this.sendTurnUpdate(t,c),t.assistantMq?.push(c)}}}}else"delta"===e.state&&this.touchStreamActivity(t);if(this.maybeCompletePromptFromChatState(t,e),!t.promptDone)if("final"===e.state)this.observeLifecycle(this.completePrompt(t,e.stopReason||"end_turn"),"chat_final",t);else if("aborted"===e.state||"cancelled"===e.state||"cancel"===e.state)this.observeLifecycle(this.completePrompt(t,"cancelled"),"chat_cancelled",t);else if("error"===e.state){const s=e.errorMessage||Errors.AgentError.message,o=classifyAgentRuntimeFailure({raw:s,source:"chat_state",runtimeKind:"openclaw"});"interrupted"===o.kind?this.observeLifecycle(this.interruptPrompt(t,o),"chat_interrupt",t):this.observeLifecycle(this.failPrompt(t,Errors.AgentError.rpcCode,o.publicMessage),"chat_failure",t)}}handleAgentEvent(e){const t=(e.runId?this.state.promptsByRunId.get(e.runId):void 0)??(e.sessionKey?this.state.findSessionByKey(e.sessionKey):void 0);if(!t)return;if(!this.state.isCurrentStreamOwner(t,e.runId)){const s=!t.currentRunId&&void 0===t.pendingPromptId;if(!e.runId||!s||this.state.isRunCompleted(e.runId))return;if(!this.adoptBackgroundRun(t,e.runId))return}e.runId&&t.cronJobId&&!this.state.runIdToCronJobId.has(e.runId)&&this.state.setRunCronJobId(e.runId,t.cronJobId);t.sessionId;this.touchStreamActivity(t);const s=toISO(e.ts),o=e=>{this.sendTurnUpdate(t,e),t.assistantMq?.push(e)};if("assistant"===e.stream){t.hasAgentAssistantStream=!0;const n=this.state.extractAgentAssistantDelta(t,e.data??{});if(n){const a=normalizeTransportText(n);if(a){const n=t.agentAssistantTextSoFar??a,i=classifyHeartbeatFilter(n);i.filtered?this.logHeartbeatSkip({source:"assistant-delta",reason:i.reason,sessionId:t.sessionId,runId:e.runId,cumulative:n,delta:a}):(this.logger.debug?.(`[gateway-events] agent.assistant delta seq=${e.seq} runId=${e.runId} len=${a.length} source=${e.data?.delta?"delta":"cumulative"}`),o({sessionUpdate:"agent_message_chunk",content:{type:"text",text:a},...s?{timestamp:s}:{}}))}}const a=[],i=e.data;i&&(Array.isArray(i.content)?a.push(...i.content):isRecord(i.content)?a.push(i.content):"string"==typeof i.type&&a.push(i));for(const e of a){if(!isRecord(e))continue;const n=asString(e.type);if("thinking"===n){t.hasAgentThinkingStream=!0;const o=normalizeText(e.thinking)??normalizeText(e.text);if(o){const e={sessionUpdate:"agent_thought_chunk",content:{type:"text",text:o},...s?{timestamp:s}:{}};this.sendTurnUpdate(t,e)&&t.assistantMq?.push(e)}continue}if("toolCall"===n){this.sendToolCallSpacer(t,s),t.hasAgentToolStartStream=!0;const n=this.resolveToolCallId(t,e,"start"),a=asString(e.name)??asString(e.toolName)??asString(e.tool_name)??"tool",i=resolveToolArgs(e);o(buildToolCallPayload({toolCallId:n,toolName:a,args:i,timestamp:s}));continue}if("toolResult"===n){this.sendToolCallSpacer(t,s),t.hasAgentToolResultStream=!0;const n=this.resolveToolCallId(t,e,"result"),a=asString(e.name)??asString(e.toolName)??asString(e.tool_name)??"tool",i=e.result,r=normalizeText(e.text)??normalizeText(e.result)??(isRecord(i)||Array.isArray(i)?JSON.stringify(i,null,2):void 0);r&&this.emitNormalizedToolResult(t,{toolCallId:n,toolName:a,rawText:r,rawResult:i,timestamp:s,pushUpdate:o}).catch(e=>{this.logger.warn?.(`[gateway-events] Tool result normalization failed: ${e instanceof Error?e.message:e}`)});continue}}}else if("thinking"===e.stream){t.hasAgentThinkingStream=!0;const o=normalizeText(e.data?.delta)??normalizeText(e.data?.text);if(o){const e={sessionUpdate:"agent_thought_chunk",content:{type:"text",text:o},...s?{timestamp:s}:{}};this.sendTurnUpdate(t,e)&&t.assistantMq?.push(e)}}else if("tool"===e.stream){const n=e.data,a="string"==typeof n?.phase?n.phase:void 0;if("start"===a){this.sendToolCallSpacer(t,s),t.hasAgentToolStartStream=!0;const e=this.resolveToolCallId(t,n,"start"),a=asString(n?.name)??asString(n?.toolName)??asString(n?.tool_name)??"tool",i=resolveToolArgs(n);o(buildToolCallPayload({toolCallId:e,toolName:a,args:i,timestamp:s}))}else if("result"===a)this.sendToolCallSpacer(t,s),t.hasAgentToolResultStream=!0,this.handleToolResult(t,e,s).catch(e=>{this.logger.warn?.(`[gateway-events] Tool result handling failed: ${e instanceof Error?e.message:e}`)});else{const e=n?.toolCall;if(e){this.sendToolCallSpacer(t,s),t.hasAgentToolStartStream=!0;const a=asString(e?.name)??asString(n?.name)??asString(n?.toolName)??"tool",i={...n,...e},r=this.resolveToolCallId(t,i,"start"),l=resolveToolArgs(i);o(buildToolCallPayload({toolCallId:r,toolName:a,args:l,timestamp:s}))}}}else if("lifecycle"===e.stream){const s=e.data,o="string"==typeof s?.phase?s.phase:void 0,n=(o,n)=>{this.logger.warn?.(`[gateway-events] lifecycle error runId=${e.runId} sessionKey=${e.sessionKey} message=${o} data=${JSON.stringify(s)}`);const a=classifyAgentRuntimeFailure({raw:o,source:"live_gateway",runtimeKind:"openclaw"});"interrupted"===a.kind?this.observeLifecycle(this.interruptPrompt(t,a),"agent_interrupt",t):this.observeLifecycle(this.failPrompt(t,Errors.AgentError.rpcCode,a.publicMessage),n,t)};if("end"===o){const e=lifecycleEndFailureMessage(s);if(e)n(e,"agent_failure");else{const e="string"==typeof s?.stopReason?s.stopReason:void 0;this.observeLifecycle(this.completePrompt(t,e||"end_turn"),"agent_final",t)}}else if("cancelled"===o||"cancel"===o)this.observeLifecycle(this.completePrompt(t,"cancelled"),"agent_cancelled",t);else if("error"===o){const e=s?.error,t=e&&"object"==typeof e?e:void 0;n(("string"==typeof s?.message?s.message:void 0)??("string"==typeof e?e:void 0)??("string"==typeof t?.message?t.message:void 0)??("string"==typeof s?.reason?s.reason:void 0)??(t?JSON.stringify(t):void 0)??"gateway lifecycle error","agent_failure")}}}async handleToolResult(e,t,s){const o=t.data,n=o?.toolCall,a=("string"==typeof n?.id?n.id:void 0)??("string"==typeof o?.toolCallId?o.toolCallId:void 0),i=(a?this.state.toolCallIdMap.get(a):void 0)??a??`tc_${t.runId}_${t.seq}`,r=("string"==typeof n?.name?n.name:void 0)??("string"==typeof o?.name?o.name:void 0)??"tool",l="string"==typeof o?.text?o.text:void 0,c=a??i,d=o?.result;await this.emitNormalizedToolResult(e,{toolCallId:i,normalizeToolCallId:c,toolName:r,rawText:l,rawResult:d,timestamp:s})}async emitNormalizedToolResult(e,t){const s=t.pushUpdate??(t=>{this.sendTurnUpdate(e,t)&&e.assistantMq?.push(t)});await emitNormalizedToolResultForTurn({session:e,envelope:{toolCallId:t.toolCallId,toolName:t.toolName,rawText:t.rawText,rawResult:t.rawResult,timestamp:t.timestamp},normalizeToolCallId:t.normalizeToolCallId,turnId:resolveTurnId(e),config:this.config,logger:this.logger,writeObs:this.writeObs,getCanvasState:this.getCanvasState,sendUpdate:e=>(s(e),!0)})}adoptBackgroundRun(e,t){this.logger.debug?.(`[gateway-events] Adopting background run ${t} on session ${e.sessionId} (prev=${e.currentRunId})`);if(!this.adoptBackgroundMutation(e,t).ok)return this.observeLifecycle(this.abortGatewayRun(e.gatewaySessionKey,t),"background_run_conflict_abort",e),!1;e.currentRunId=t,e.promptDone=!1,this.state.promptsByRunId.set(t,e);const s=this.state.runIdToCronJobId.get(t);return s&&(e.cronJobId=s),e.assistantStreamStartedAt=Date.now(),e.lastStreamActivityTs=Date.now(),e.hasAgentAssistantStream=void 0,e.hasAgentThinkingStream=void 0,e.hasAgentToolStartStream=void 0,e.hasAgentToolResultStream=void 0,e.chatAssistantTextSoFar=void 0,e.agentAssistantTextSoFar=void 0,e.chatReplayDedupKeys?.clear(),e.presentedFileArtifactKeys=new Set,e.emittedToolResultKeys=new Set,e.assistantMq&&!e.assistantMq.closed||(e.assistantMq=new MessageQueue),this.schedulePromptTimeout(e),!0}handleCronEvent(e){this.transport.sendNotification("_beeos/cron_event",{payload:e});const t=e??{};"string"==typeof t.runId&&"string"==typeof t.jobId&&this.state.setRunCronJobId(t.runId,t.jobId),this.config.agentGatewayUrl&&this.agentFetchFn&&this.reportCronEventToAgentGateway(t),"added"===t.action&&this.maybeBackfillBeeosChannel(t),"finished"===t.action&&"string"==typeof t.summary&&t.summary&&this.publishCronResult(t)}async reportCronEventToAgentGateway(e){if(!this.config.agentGatewayUrl||!this.agentFetchFn)return;const t={...e},s="string"==typeof e.sessionKey?e.sessionKey:void 0;s&&null==t.sessionKey&&(t.sessionKey=s);const o=s?this.state.findSessionByKey(s)?.sessionId:void 0;if(o&&(t.sessionId=o),("string"!=typeof t.name||!t.name)&&"string"==typeof e.jobId&&e.jobId&&this.gatewayRequest)try{const s=await this.gatewayRequest("cron.list",{}),o=s?.jobs;if(Array.isArray(o))for(const s of o)if(isRecord(s)&&s.id===e.jobId&&"string"==typeof s.name&&s.name){t.name=s.name;break}}catch(e){this.logger.debug?.(`[gateway-events] cron.list lookup failed: ${e instanceof Error?e.message:e}`)}const n=`${this.config.agentGatewayUrl}/api/v1/agent/events`;try{await this.agentFetchFn(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({type:"cron",data:t})})}catch(e){this.logger.warn?.(`[gateway-events] event report failed: ${e instanceof Error?e.message:e}`)}}async maybeBackfillBeeosChannel(e){const t="string"==typeof e.jobId?e.jobId:void 0;if(!t)return;if(!this.gatewayRequest)return;if(this.cronChannelCache?.get(t))return;let s;try{const e=await this.gatewayRequest("cron.list",{}),o=e?.jobs;if(Array.isArray(o))for(const e of o){if(!e||"object"!=typeof e)continue;const o=e;if(o.id===t){s=o;break}}}catch(e){return void this.logger.debug?.(`[gateway-events] maybeBackfillBeeosChannel cron.list failed: ${e instanceof Error?e.message:e}`)}if(!s)return;const o="string"==typeof s.description?s.description:"";if(BEEOS_CHANNEL_TAG_RE.test(o)){const e=decodeBeeosChannelId(o);return void(e&&this.setCronChannelCacheLocal(t,e))}if("main"===("string"==typeof s.sessionTarget?s.sessionTarget:void 0))return;const n=isRecord(s.payload)?s.payload:void 0;if("systemEvent"===(n&&"string"==typeof n.kind?n.kind:void 0))return;const a=isRecord(s.delivery)?s.delivery:void 0;if(a&&"none"===a.mode)return;const i="string"==typeof s.sessionKey?s.sessionKey:void 0;if(!i)return void this.logger.debug?.(`[gateway-events] maybeBackfillBeeosChannel: job has no sessionKey job=${t}`);const r=this.state.findSessionByKey(i),l=r?.channelId;if(!l)return void this.logger.debug?.(`[gateway-events] maybeBackfillBeeosChannel: no channelId on ACPSession for sessionKey=${i} job=${t}`);const c=encodeBeeosChannelTag(o,l);try{await this.gatewayRequest("cron.update",{id:t,patch:{description:c}}),this.setCronChannelCacheLocal(t,l),this.logger.info?.(`[gateway-events] backfilled beeos:channel for LLM-created cron job=${t} channel=${l}`)}catch(e){this.logger.warn?.(`[gateway-events] maybeBackfillBeeosChannel cron.update failed: ${e instanceof Error?e.message:e}`)}}setCronChannelCacheLocal(e,t){this.cronChannelCache&&this.cronChannelCache.set(e,t)}async publishCronResult(e){const t=this.getMessageClient?.();if(!t)return;const s=this.getMsgPrincipalId?.();if(!s)return;const o="string"==typeof e.jobId?e.jobId:void 0;if(!o)return;const n=e.summary;let a=this.cronChannelCache?.get(o);if(!a&&this.gatewayRequest)try{const e=await this.gatewayRequest("cron.list",{}),t=e?.jobs;if(Array.isArray(t))for(const e of t){if(!e||"object"!=typeof e)continue;const t=e;if(t.id===o){a=decodeBeeosChannelId(t.description);break}}}catch(e){this.logger.debug?.(`[gateway-events] cron.list fallback failed: ${e instanceof Error?e.message:e}`)}if(!a)return;const i=randomUUID();try{await t.messages.send({conversationId:a,clientMessageId:i,idempotencyKey:i,type:"agent_reply",content:{text:n,cron_job_id:o,..."string"==typeof e.sessionKey?{session_key:e.sessionKey}:{}}}),this.logger.info?.(`[gateway-events] published cron result to channel=${a} job=${o}`)}catch(e){const t=e instanceof Error?e.message:String(e);if(isChannelGoneError(e,t))return this.logger.info?.(`[gateway-events] origin channel gone (session likely deleted), skipping publish: channel=${a} job=${o} err=${t}`),void this.cronChannelCache?.delete(o);this.logger.warn?.(`[gateway-events] publishCronResult failed: ${t}`)}}logHeartbeatSkip(e){const t=previewSanitizedText(e.cumulative),s=void 0!==e.delta?previewSanitizedText(e.delta):void 0;this.logger.info?.(`[gateway-events] SKIP heartbeat ${e.source} reason=${e.reason} sessionId=${e.sessionId} runId=${e.runId??"n/a"} cumLen=${e.cumulative.length}`+(void 0!==e.delta?` deltaLen=${e.delta.length}`:"")+` cumulative="${t}"`+(void 0!==s?` delta="${s}"`:"")),this.writeObs({component:"gateway-events",domain:"lifecycle",name:"heartbeat_filter_skip",severity:"info",summary:`heartbeat ${e.source} drop (${e.reason})`,payload:{source:e.source,reason:e.reason,sessionId:e.sessionId,runId:e.runId,cumulativeLen:e.cumulative.length,cumulativePreview:t,...void 0!==e.delta?{deltaLen:e.delta.length,deltaPreview:s}:{}}})}}export function isChannelGoneError(e,t){const s=t.toLowerCase();if(s.includes("not found")||s.includes("no such channel")||s.includes("channel does not exist")||s.includes("channel gone")||s.includes("410")||/\b404\b/.test(s))return!0;if(isRecord(e)){const t=e.status??e.statusCode??e.code;if(404===t||410===t)return!0}return!1}
1
+ import{createHash,randomUUID}from"node:crypto";import{Errors}from"../errors/index.js";import{BEEOS_CHANNEL_TAG_RE,decodeBeeosChannelId,encodeBeeosChannelTag}from"./bridge-core.js";import{classifyAgentRuntimeFailure}from"../runtime/agent-runtime-failure-classifier.js";import{stripTransportMetadata,normalizeTransportText,previewSanitizedText}from"../message-sanitization/transport-metadata-sanitizer.js";import{classifyHeartbeatFilter}from"../message-sanitization/message-classifier.js";import{emitNormalizedToolResultForTurn}from"./tool-result-emitter.js";import{backgroundRunEgressContent,backgroundRunEgressMessageId,buildBackgroundRunImEgress,extractMessageToolAttachments,extractMessageToolCaption,resolveEgressMediaUrls}from"./background-run-im-egress.js";import{getUploadDeps,uploadLocalFile}from"../upload/upload-file.js";import{buildToolCallPayload}from"./tool-call-payload-builder.js";import{DEFAULT_STREAM_IDLE_TIMEOUT_MS,DEFAULT_STREAM_STALE_TIMEOUT_MS}from"./types.js";import{MessageQueue}from"../utils/mq.js";import{observeLifecyclePromise}from"../runtime/lifecycle-promise-observer.js";export function lifecycleEndFailureMessage(e){if(!e)return;const t=!0===e.isError||!0===e.is_error,s=e.error,n=s&&"object"==typeof s?s:void 0,o="string"==typeof s||void 0!==n||"string"==typeof e.message||"string"==typeof e.reason;if(t||o){if(!t){const t="string"==typeof e.stopReason?e.stopReason:"";if("error"!==t&&"timeout"!==t&&"aborted"!==t)return}return("string"==typeof e.message?e.message:void 0)??("string"==typeof s?s:void 0)??("string"==typeof n?.message?n.message:void 0)??("string"==typeof e.reason?e.reason:void 0)??(n?JSON.stringify(n):void 0)??"gateway lifecycle error"}}function asString(e){if("string"==typeof e){return e.trim()||void 0}}function isRecord(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function normalizeText(e){if("string"==typeof e)return normalizeTransportText(e.replace(/\r\n/g,"\n").replace(/\r/g,"\n"))}const DEDUP_HASH_THRESHOLD=256;function dedupKey(e,...t){const s=`${e}:${t.join(":")}`;if(s.length<=256)return s;return`${e}:h:${createHash("sha256").update(s).digest("hex").slice(0,24)}`}function toISO(e){if(!(null==e||e<=0))try{return new Date(e).toISOString()}catch{return}}function resolveToolArgs(e){const t=e.arguments??e.args??e.input;if(isRecord(t))return t;if("string"==typeof t){const e=t.trim();if(e.startsWith("{")||e.startsWith("["))try{return JSON.parse(e)}catch{}}return{}}export function resolveTurnId(e){if(e.currentRunId)return e.currentRunId;const t=e.pendingPromptId;return void 0!==t?"string"==typeof t?`req:${t}`:`req:${String(t)}`:void 0}export function roleFromSessionUpdate(e){const t=e.sessionUpdate;if(t)return"user_message_chunk"===t?"user":"system_message_chunk"===t?"system":t.startsWith("agent_")||t.startsWith("tool_")?"assistant":"history_turn"===t?"user"===e.role?"user":"system"===e.role?"system":"assistant":void 0}export function recordTurnIdForRole(e,t,s){if(!s)return;const n=roleFromSessionUpdate(t);n&&(e.lastTurnIdByRole||(e.lastTurnIdByRole={}),e.lastTurnIdByRole[n]=s)}export function recordToolCallTurnForUpdate(e,t,s){s&&"tool_call"===t.sessionUpdate&&t.toolCallId&&(e.toolCallTurns??=new Map,e.toolCallTurns.set(t.toolCallId,{turnId:s,..."string"==typeof t.name&&t.name?{toolName:t.name}:{}}))}export class AcpGatewayEvents{state;transport;config;logger;writeObs;completePrompt;failPrompt;interruptPrompt;schedulePromptTimeout;adoptBackgroundMutation;abortGatewayRun;maybeCompletePromptFromChatState;agentFetchFn;getMessageClient;getMsgPrincipalId;gatewayRequest;getCanvasState;cronChannelCache;constructor(e){this.state=e.state,this.transport=e.transport,this.config=e.config,this.logger=e.logger,this.writeObs=e.writeObs,this.completePrompt=e.completePrompt,this.failPrompt=e.failPrompt,this.interruptPrompt=e.interruptPrompt,this.schedulePromptTimeout=e.schedulePromptTimeout,this.adoptBackgroundMutation=e.adoptBackgroundMutation,this.abortGatewayRun=e.abortGatewayRun,this.maybeCompletePromptFromChatState=e.maybeCompletePromptFromChatState,this.agentFetchFn=e.agentFetch,this.getMessageClient=e.getMessageClient,this.getMsgPrincipalId=e.getMsgPrincipalId,this.gatewayRequest=e.gatewayRequest,this.getCanvasState=e.getCanvasState,this.cronChannelCache=e.cronChannelCache}observeLifecycle(e,t,s){observeLifecyclePromise(e,this.logger,{component:"gateway-events",action:t,sessionId:s.sessionId,gatewaySessionKey:s.gatewaySessionKey})}touchStreamActivity(e){e.lastStreamActivityTs=Date.now(),this.resetStreamIdleTimer(e)}resetStreamIdleTimer(e){this.state.clearStreamIdleTimer(e);const t=this.config.streamIdleTimeoutMs??DEFAULT_STREAM_IDLE_TIMEOUT_MS,s=this.config.streamStaleTimeoutMs??DEFAULT_STREAM_STALE_TIMEOUT_MS;e.streamIdleTimer=setTimeout(()=>{if(!e.lastStreamActivityTs)return;const t=Date.now()-e.lastStreamActivityTs;t>s&&(this.logger.warn?.(`[gateway-events] Stream stale timeout sessionId=${e.sessionId} stale=${t}ms`),this.observeLifecycle(this.interruptPrompt(e,classifyAgentRuntimeFailure({raw:`Stream stale timeout after ${t}ms`,source:"live_gateway",runtimeKind:"openclaw"})),"stream_stale_timeout",e))},t),"object"==typeof e.streamIdleTimer&&"unref"in e.streamIdleTimer&&e.streamIdleTimer.unref()}sendTurnUpdate(e,t){const s=resolveTurnId(e);return s&&void 0===t._turnId&&(t._turnId=s),recordTurnIdForRole(e,t,s),recordToolCallTurnForUpdate(e,t,s),!!e.sessionLoadInProgress||this.transport.sendSessionUpdate(e.sessionId,t,{turnId:s})}sendToolCallSpacer(e,t){const s={sessionUpdate:"agent_message_chunk",content:{type:"text",text:"\n"},...t?{timestamp:t}:{}};this.sendTurnUpdate(e,s),e.assistantMq?.push(s)}resolveToolCallId(e,t,s){const n=asString(t.toolCallId)??asString(t.tool_call_id)??asString(t.callId)??asString(t.id);if(n){const t=this.state.toolCallIdMap.get(n);return t?(e.sessionId&&this.state.toolCallToSessionMap.set(t,e.sessionId),t):(this.state.toolCallIdMap.set(n,n),e.sessionId&&this.state.toolCallToSessionMap.set(n,e.sessionId),n)}const o=`tc_${e.currentRunId??"unknown"}_${this.state.nextToolCallSeq++}`;return e.sessionId&&this.state.toolCallToSessionMap.set(o,e.sessionId),o}handleChatEvent(e){const t=(e.runId?this.state.promptsByRunId.get(e.runId):void 0)??this.state.findSessionByKey(e.sessionKey);if(!t)return;if(!this.state.isCurrentStreamOwner(t,e.runId)){const s=!t.currentRunId&&void 0===t.pendingPromptId;if(!e.runId||!s||this.state.isRunCompleted(e.runId))return;if(!this.adoptBackgroundRun(t,e.runId))return}t.sessionId;const s=e.message;if(s){this.touchStreamActivity(t);if("assistant"===s.role){if(!Array.isArray(s.content))return;for(const n of s.content){const o=n;if(!isRecord(o))continue;const a=asString(o.type);if(!a)continue;const r=toISO(s.timestamp);if("thinking"===a){if(t.hasAgentThinkingStream)continue;const e=normalizeText(o.thinking)??normalizeText(o.text);if(!e)continue;const s=dedupKey("chat:thinking",e);if(t.chatReplayDedupKeys.has(s))continue;t.chatReplayDedupKeys.add(s);const n={sessionUpdate:"agent_thought_chunk",content:{type:"text",text:e},...r?{timestamp:r}:{}};this.sendTurnUpdate(t,n)&&t.assistantMq?.push(n);continue}if("toolCall"===a){if(this.sendToolCallSpacer(t,r),t.hasAgentToolStartStream)continue;const e=this.resolveToolCallId(t,o,"start"),s=asString(o.name)??asString(o.toolName)??asString(o.tool_name)??"tool",n=resolveToolArgs(o),a=dedupKey("chat:tool_start",e,JSON.stringify(n));if(t.chatReplayDedupKeys.has(a))continue;t.chatReplayDedupKeys.add(a);const i=buildToolCallPayload({toolCallId:e,toolName:s,args:n,timestamp:r});this.sendTurnUpdate(t,i)&&t.assistantMq?.push(i);continue}if("toolResult"===a){if(this.sendToolCallSpacer(t,r),t.hasAgentToolResultStream)continue;const e=this.resolveToolCallId(t,o,"result"),s=asString(o.name)??asString(o.toolName)??asString(o.tool_name)??"tool",n=o.result,a=normalizeText(o.text)??normalizeText(o.result)??(isRecord(n)||Array.isArray(n)?JSON.stringify(n,null,2):void 0);if(!a)continue;const i=dedupKey("chat:tool_result",e,a);if(t.chatReplayDedupKeys.has(i))continue;t.chatReplayDedupKeys.add(i),this.emitNormalizedToolResult(t,{toolCallId:e,toolName:s,rawText:a,rawResult:n,timestamp:r}).catch(e=>{this.logger.warn?.(`[gateway-events] Tool result normalization failed: ${e instanceof Error?e.message:e}`)});continue}if("text"===a&&o.text){if(t.hasAgentAssistantStream||t.agentAssistantTextSoFar)continue;const s=stripTransportMetadata(o.text);if(!s)continue;const n=classifyHeartbeatFilter(s);if(n.filtered){this.logHeartbeatSkip({source:"chat-text",reason:n.reason,sessionId:t.sessionId,runId:e.runId,cumulative:s});continue}const a=dedupKey("chat:text",s);if(t.chatReplayDedupKeys.has(a))continue;t.chatReplayDedupKeys.add(a);const i=t.chatAssistantTextSoFar??"";let l;if(t.chatAssistantTextSoFar=s,s.startsWith(i))l=s.slice(i.length);else{if(i.startsWith(s))continue;l=s}if(!l)continue;this.logger.debug?.(`[gateway-events] chat.text delta seq=${e.seq} runId=${e.runId} len=${l.length} prevLen=${i.length}`);const d={sessionUpdate:"agent_message_chunk",content:{type:"text",text:l},...r?{timestamp:r}:{}};this.sendTurnUpdate(t,d),t.assistantMq?.push(d)}}}}else"delta"===e.state&&this.touchStreamActivity(t);if(this.maybeCompletePromptFromChatState(t,e),!t.promptDone)if("final"===e.state)this.maybePublishBackgroundRunToIm(t),this.observeLifecycle(this.completePrompt(t,e.stopReason||"end_turn"),"chat_final",t);else if("aborted"===e.state||"cancelled"===e.state||"cancel"===e.state)this.observeLifecycle(this.completePrompt(t,"cancelled"),"chat_cancelled",t);else if("error"===e.state){const s=e.errorMessage||Errors.AgentError.message,n=classifyAgentRuntimeFailure({raw:s,source:"chat_state",runtimeKind:"openclaw"});"interrupted"===n.kind?this.observeLifecycle(this.interruptPrompt(t,n),"chat_interrupt",t):this.observeLifecycle(this.failPrompt(t,Errors.AgentError.rpcCode,n.publicMessage),"chat_failure",t)}}handleAgentEvent(e){const t=(e.runId?this.state.promptsByRunId.get(e.runId):void 0)??(e.sessionKey?this.state.findSessionByKey(e.sessionKey):void 0);if(!t)return;if(!this.state.isCurrentStreamOwner(t,e.runId)){const s=!t.currentRunId&&void 0===t.pendingPromptId;if(!e.runId||!s||this.state.isRunCompleted(e.runId))return;if(!this.adoptBackgroundRun(t,e.runId))return}e.runId&&t.cronJobId&&!this.state.runIdToCronJobId.has(e.runId)&&this.state.setRunCronJobId(e.runId,t.cronJobId);t.sessionId;this.touchStreamActivity(t);const s=toISO(e.ts),n=e=>{this.sendTurnUpdate(t,e),t.assistantMq?.push(e)};if("assistant"===e.stream){t.hasAgentAssistantStream=!0;const o=this.state.extractAgentAssistantDelta(t,e.data??{});if(o){const a=normalizeTransportText(o);if(a){const o=t.agentAssistantTextSoFar??a,r=classifyHeartbeatFilter(o);r.filtered?this.logHeartbeatSkip({source:"assistant-delta",reason:r.reason,sessionId:t.sessionId,runId:e.runId,cumulative:o,delta:a}):(this.logger.debug?.(`[gateway-events] agent.assistant delta seq=${e.seq} runId=${e.runId} len=${a.length} source=${e.data?.delta?"delta":"cumulative"}`),n({sessionUpdate:"agent_message_chunk",content:{type:"text",text:a},...s?{timestamp:s}:{}}))}}const a=[],r=e.data;r&&(Array.isArray(r.content)?a.push(...r.content):isRecord(r.content)?a.push(r.content):"string"==typeof r.type&&a.push(r));for(const e of a){if(!isRecord(e))continue;const o=asString(e.type);if("thinking"===o){t.hasAgentThinkingStream=!0;const n=normalizeText(e.thinking)??normalizeText(e.text);if(n){const e={sessionUpdate:"agent_thought_chunk",content:{type:"text",text:n},...s?{timestamp:s}:{}};this.sendTurnUpdate(t,e)&&t.assistantMq?.push(e)}continue}if("toolCall"===o){this.sendToolCallSpacer(t,s),t.hasAgentToolStartStream=!0;const o=this.resolveToolCallId(t,e,"start"),a=asString(e.name)??asString(e.toolName)??asString(e.tool_name)??"tool",r=resolveToolArgs(e);n(buildToolCallPayload({toolCallId:o,toolName:a,args:r,timestamp:s}));continue}if("toolResult"===o){this.sendToolCallSpacer(t,s),t.hasAgentToolResultStream=!0;const o=this.resolveToolCallId(t,e,"result"),a=asString(e.name)??asString(e.toolName)??asString(e.tool_name)??"tool",r=e.result,i=normalizeText(e.text)??normalizeText(e.result)??(isRecord(r)||Array.isArray(r)?JSON.stringify(r,null,2):void 0);i&&this.emitNormalizedToolResult(t,{toolCallId:o,toolName:a,rawText:i,rawResult:r,timestamp:s,pushUpdate:n}).catch(e=>{this.logger.warn?.(`[gateway-events] Tool result normalization failed: ${e instanceof Error?e.message:e}`)});continue}}}else if("thinking"===e.stream){t.hasAgentThinkingStream=!0;const n=normalizeText(e.data?.delta)??normalizeText(e.data?.text);if(n){const e={sessionUpdate:"agent_thought_chunk",content:{type:"text",text:n},...s?{timestamp:s}:{}};this.sendTurnUpdate(t,e)&&t.assistantMq?.push(e)}}else if("tool"===e.stream){const o=e.data,a="string"==typeof o?.phase?o.phase:void 0;if("start"===a){this.sendToolCallSpacer(t,s),t.hasAgentToolStartStream=!0;const e=this.resolveToolCallId(t,o,"start"),a=asString(o?.name)??asString(o?.toolName)??asString(o?.tool_name)??"tool",r=resolveToolArgs(o);this.captureBackgroundRunAttachments(t,a,r),n(buildToolCallPayload({toolCallId:e,toolName:a,args:r,timestamp:s}))}else if("result"===a)this.sendToolCallSpacer(t,s),t.hasAgentToolResultStream=!0,this.handleToolResult(t,e,s).catch(e=>{this.logger.warn?.(`[gateway-events] Tool result handling failed: ${e instanceof Error?e.message:e}`)});else{const e=o?.toolCall;if(e){this.sendToolCallSpacer(t,s),t.hasAgentToolStartStream=!0;const a=asString(e?.name)??asString(o?.name)??asString(o?.toolName)??"tool",r={...o,...e},i=this.resolveToolCallId(t,r,"start"),l=resolveToolArgs(r);this.captureBackgroundRunAttachments(t,a,l),n(buildToolCallPayload({toolCallId:i,toolName:a,args:l,timestamp:s}))}}}else if("lifecycle"===e.stream){const s=e.data,n="string"==typeof s?.phase?s.phase:void 0,o=(n,o)=>{this.logger.warn?.(`[gateway-events] lifecycle error runId=${e.runId} sessionKey=${e.sessionKey} message=${n} data=${JSON.stringify(s)}`);const a=classifyAgentRuntimeFailure({raw:n,source:"live_gateway",runtimeKind:"openclaw"});"interrupted"===a.kind?this.observeLifecycle(this.interruptPrompt(t,a),"agent_interrupt",t):this.observeLifecycle(this.failPrompt(t,Errors.AgentError.rpcCode,a.publicMessage),o,t)};if("end"===n){const e=lifecycleEndFailureMessage(s);if(e)o(e,"agent_failure");else{const e="string"==typeof s?.stopReason?s.stopReason:void 0;this.maybePublishBackgroundRunToIm(t),this.observeLifecycle(this.completePrompt(t,e||"end_turn"),"agent_final",t)}}else if("cancelled"===n||"cancel"===n)this.observeLifecycle(this.completePrompt(t,"cancelled"),"agent_cancelled",t);else if("error"===n){const e=s?.error,t=e&&"object"==typeof e?e:void 0;o(("string"==typeof s?.message?s.message:void 0)??("string"==typeof e?e:void 0)??("string"==typeof t?.message?t.message:void 0)??("string"==typeof s?.reason?s.reason:void 0)??(t?JSON.stringify(t):void 0)??"gateway lifecycle error","agent_failure")}}}async handleToolResult(e,t,s){const n=t.data,o=n?.toolCall,a=("string"==typeof o?.id?o.id:void 0)??("string"==typeof n?.toolCallId?n.toolCallId:void 0),r=(a?this.state.toolCallIdMap.get(a):void 0)??a??`tc_${t.runId}_${t.seq}`,i=("string"==typeof o?.name?o.name:void 0)??("string"==typeof n?.name?n.name:void 0)??"tool",l="string"==typeof n?.text?n.text:void 0,d=a??r,c=n?.result;await this.emitNormalizedToolResult(e,{toolCallId:r,normalizeToolCallId:d,toolName:i,rawText:l,rawResult:c,timestamp:s})}async emitNormalizedToolResult(e,t){const s=t.pushUpdate??(t=>{this.sendTurnUpdate(e,t)&&e.assistantMq?.push(t)}),n=await emitNormalizedToolResultForTurn({session:e,envelope:{toolCallId:t.toolCallId,toolName:t.toolName,rawText:t.rawText,rawResult:t.rawResult,timestamp:t.timestamp},normalizeToolCallId:t.normalizeToolCallId,turnId:resolveTurnId(e),config:this.config,logger:this.logger,writeObs:this.writeObs,getCanvasState:this.getCanvasState,sendUpdate:e=>(s(e),!0)});!0===e.backgroundRunAdopted&&n.resourceLinks?.length&&(e.backgroundRunArtifacts??=[]).push(...n.resourceLinks)}adoptBackgroundRun(e,t){this.logger.debug?.(`[gateway-events] Adopting background run ${t} on session ${e.sessionId} (prev=${e.currentRunId})`);if(!this.adoptBackgroundMutation(e,t).ok)return this.observeLifecycle(this.abortGatewayRun(e.gatewaySessionKey,t),"background_run_conflict_abort",e),!1;e.currentRunId=t,e.promptDone=!1,this.state.promptsByRunId.set(t,e);const s=this.state.runIdToCronJobId.get(t);return s&&(e.cronJobId=s),e.assistantStreamStartedAt=Date.now(),e.lastStreamActivityTs=Date.now(),e.hasAgentAssistantStream=void 0,e.hasAgentThinkingStream=void 0,e.hasAgentToolStartStream=void 0,e.hasAgentToolResultStream=void 0,e.chatAssistantTextSoFar=void 0,e.agentAssistantTextSoFar=void 0,e.chatReplayDedupKeys?.clear(),e.presentedFileArtifactKeys=new Set,e.emittedToolResultKeys=new Set,e.backgroundRunAdopted=!0,e.backgroundRunArtifacts=[],e.assistantMq&&!e.assistantMq.closed||(e.assistantMq=new MessageQueue),this.schedulePromptTimeout(e),!0}maybePublishBackgroundRunToIm(e){const t=buildBackgroundRunImEgress(e);t.publish?(e.backgroundRunAdopted=!1,e.backgroundRunArtifacts=void 0,e.backgroundRunCaption=void 0,this.observeLifecycle(this.publishBackgroundRunResult(t.egress),"background_run_im_egress",e)):"not_background_run"!==t.reason&&"cron_owned"!==t.reason&&this.logger.debug?.(`[gateway-events] background run not published to IM (reason=${t.reason} sessionId=${e.sessionId} runId=${e.currentRunId??"n/a"})`)}captureBackgroundRunAttachments(e,t,s){if(!0!==e.backgroundRunAdopted)return;const n=extractMessageToolAttachments(t,s);n.length>0&&(e.backgroundRunArtifacts??=[]).push(...n);const o=extractMessageToolCaption(t,s);o&&(e.backgroundRunCaption=o)}async uploadEgressArtifact(e,t){const s=getUploadDeps();if(s)try{return(await uploadLocalFile(e,s.gatewayUrl,s.keys,{...t?{fileNameOverride:t}:{}})).uri}catch(t){return void this.logger.warn?.(`[gateway-events] background run artifact upload failed path=${e}: ${t instanceof Error?t.message:String(t)}`)}else this.logger.warn?.("[gateway-events] cannot upload background run artifact: upload deps unset")}async publishBackgroundRunResult(e){const t=this.getMessageClient?.();if(!t)return;const{mediaUrls:s,unresolved:n}=await resolveEgressMediaUrls(e.artifacts,(e,t)=>this.uploadEgressArtifact(e,t));if(n.length>0&&this.logger.warn?.(`[gateway-events] background run has ${n.length} unresolved artifact(s) run=${e.runId}: ${n.join(", ")}`),!e.text&&0===s.length)return void this.writeObs({component:"gateway-events",domain:"lifecycle",name:"background_run_im_egress.unresolved",severity:"warn",summary:`no publishable artifact for run ${e.runId}`,payload:{conversationId:e.conversationId,runId:e.runId,unresolvedCount:n.length}});const o=backgroundRunEgressMessageId(e.runId);try{await t.messages.send({conversationId:e.conversationId,clientMessageId:o,idempotencyKey:o,type:"agent_reply",content:backgroundRunEgressContent({runId:e.runId,text:e.text,mediaUrls:s}),...e.replyTo?{replyTo:e.replyTo}:{}}),this.logger.info?.(`[gateway-events] published background run to conversation=${e.conversationId} run=${e.runId} mediaUrls=${s.length} textLen=${e.text.length}`),this.writeObs({component:"gateway-events",domain:"lifecycle",name:"background_run_im_egress.published",severity:"info",summary:`background run published to ${e.conversationId}`,payload:{conversationId:e.conversationId,runId:e.runId,mediaUrlCount:s.length,textLen:e.text.length,hasReplyTo:Boolean(e.replyTo)}})}catch(t){const s=t instanceof Error?t.message:String(t);if(isChannelGoneError(t,s))return void this.logger.info?.(`[gateway-events] origin conversation gone, skipping background run publish: conversation=${e.conversationId} run=${e.runId} err=${s}`);this.logger.warn?.(`[gateway-events] publishBackgroundRunResult failed: ${s}`),this.writeObs({component:"gateway-events",domain:"lifecycle",name:"background_run_im_egress.failed",severity:"warn",summary:s,payload:{conversationId:e.conversationId,runId:e.runId}})}}handleCronEvent(e){this.transport.sendNotification("_beeos/cron_event",{payload:e});const t=e??{};"string"==typeof t.runId&&"string"==typeof t.jobId&&this.state.setRunCronJobId(t.runId,t.jobId),this.config.agentGatewayUrl&&this.agentFetchFn&&this.reportCronEventToAgentGateway(t),"added"===t.action&&this.maybeBackfillBeeosChannel(t),"finished"===t.action&&"string"==typeof t.summary&&t.summary&&this.publishCronResult(t)}async reportCronEventToAgentGateway(e){if(!this.config.agentGatewayUrl||!this.agentFetchFn)return;const t={...e},s="string"==typeof e.sessionKey?e.sessionKey:void 0;s&&null==t.sessionKey&&(t.sessionKey=s);const n=s?this.state.findSessionByKey(s)?.sessionId:void 0;if(n&&(t.sessionId=n),("string"!=typeof t.name||!t.name)&&"string"==typeof e.jobId&&e.jobId&&this.gatewayRequest)try{const s=await this.gatewayRequest("cron.list",{}),n=s?.jobs;if(Array.isArray(n))for(const s of n)if(isRecord(s)&&s.id===e.jobId&&"string"==typeof s.name&&s.name){t.name=s.name;break}}catch(e){this.logger.debug?.(`[gateway-events] cron.list lookup failed: ${e instanceof Error?e.message:e}`)}const o=`${this.config.agentGatewayUrl}/api/v1/agent/events`;try{await this.agentFetchFn(o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({type:"cron",data:t})})}catch(e){this.logger.warn?.(`[gateway-events] event report failed: ${e instanceof Error?e.message:e}`)}}async maybeBackfillBeeosChannel(e){const t="string"==typeof e.jobId?e.jobId:void 0;if(!t)return;if(!this.gatewayRequest)return;if(this.cronChannelCache?.get(t))return;let s;try{const e=await this.gatewayRequest("cron.list",{}),n=e?.jobs;if(Array.isArray(n))for(const e of n){if(!e||"object"!=typeof e)continue;const n=e;if(n.id===t){s=n;break}}}catch(e){return void this.logger.debug?.(`[gateway-events] maybeBackfillBeeosChannel cron.list failed: ${e instanceof Error?e.message:e}`)}if(!s)return;const n="string"==typeof s.description?s.description:"";if(BEEOS_CHANNEL_TAG_RE.test(n)){const e=decodeBeeosChannelId(n);return void(e&&this.setCronChannelCacheLocal(t,e))}if("main"===("string"==typeof s.sessionTarget?s.sessionTarget:void 0))return;const o=isRecord(s.payload)?s.payload:void 0;if("systemEvent"===(o&&"string"==typeof o.kind?o.kind:void 0))return;const a=isRecord(s.delivery)?s.delivery:void 0;if(a&&"none"===a.mode)return;const r="string"==typeof s.sessionKey?s.sessionKey:void 0;if(!r)return void this.logger.debug?.(`[gateway-events] maybeBackfillBeeosChannel: job has no sessionKey job=${t}`);const i=this.state.findSessionByKey(r),l=i?.channelId;if(!l)return void this.logger.debug?.(`[gateway-events] maybeBackfillBeeosChannel: no channelId on ACPSession for sessionKey=${r} job=${t}`);const d=encodeBeeosChannelTag(n,l);try{await this.gatewayRequest("cron.update",{id:t,patch:{description:d}}),this.setCronChannelCacheLocal(t,l),this.logger.info?.(`[gateway-events] backfilled beeos:channel for LLM-created cron job=${t} channel=${l}`)}catch(e){this.logger.warn?.(`[gateway-events] maybeBackfillBeeosChannel cron.update failed: ${e instanceof Error?e.message:e}`)}}setCronChannelCacheLocal(e,t){this.cronChannelCache&&this.cronChannelCache.set(e,t)}async publishCronResult(e){const t=this.getMessageClient?.();if(!t)return;const s=this.getMsgPrincipalId?.();if(!s)return;const n="string"==typeof e.jobId?e.jobId:void 0;if(!n)return;const o=e.summary;let a=this.cronChannelCache?.get(n);if(!a&&this.gatewayRequest)try{const e=await this.gatewayRequest("cron.list",{}),t=e?.jobs;if(Array.isArray(t))for(const e of t){if(!e||"object"!=typeof e)continue;const t=e;if(t.id===n){a=decodeBeeosChannelId(t.description);break}}}catch(e){this.logger.debug?.(`[gateway-events] cron.list fallback failed: ${e instanceof Error?e.message:e}`)}if(!a)return;const r=randomUUID();try{await t.messages.send({conversationId:a,clientMessageId:r,idempotencyKey:r,type:"agent_reply",content:{text:o,cron_job_id:n,..."string"==typeof e.sessionKey?{session_key:e.sessionKey}:{}}}),this.logger.info?.(`[gateway-events] published cron result to channel=${a} job=${n}`)}catch(e){const t=e instanceof Error?e.message:String(e);if(isChannelGoneError(e,t))return this.logger.info?.(`[gateway-events] origin channel gone (session likely deleted), skipping publish: channel=${a} job=${n} err=${t}`),void this.cronChannelCache?.delete(n);this.logger.warn?.(`[gateway-events] publishCronResult failed: ${t}`)}}logHeartbeatSkip(e){const t=previewSanitizedText(e.cumulative),s=void 0!==e.delta?previewSanitizedText(e.delta):void 0;this.logger.info?.(`[gateway-events] SKIP heartbeat ${e.source} reason=${e.reason} sessionId=${e.sessionId} runId=${e.runId??"n/a"} cumLen=${e.cumulative.length}`+(void 0!==e.delta?` deltaLen=${e.delta.length}`:"")+` cumulative="${t}"`+(void 0!==s?` delta="${s}"`:"")),this.writeObs({component:"gateway-events",domain:"lifecycle",name:"heartbeat_filter_skip",severity:"info",summary:`heartbeat ${e.source} drop (${e.reason})`,payload:{source:e.source,reason:e.reason,sessionId:e.sessionId,runId:e.runId,cumulativeLen:e.cumulative.length,cumulativePreview:t,...void 0!==e.delta?{deltaLen:e.delta.length,deltaPreview:s}:{}}})}}export function isChannelGoneError(e,t){const s=t.toLowerCase();if(s.includes("not found")||s.includes("no such channel")||s.includes("channel does not exist")||s.includes("channel gone")||s.includes("410")||/\b404\b/.test(s))return!0;if(isRecord(e)){const t=e.status??e.statusCode??e.code;if(404===t||410===t)return!0}return!1}
@@ -1 +1 @@
1
- import{MessageQueue}from"../utils/mq.js";import{isExternalInvocationSessionKey}from"./external-protocol-tags.js";const MAX_TOOL_CALL_MAP_ENTRIES=5e3,MAX_COMPLETED_RUN_IDS=200;export class AcpGatewaySessionState{sessions=new Map;promptsByRunId=new Map;promptsByGatewayRequestId=new Map;sessionsByGatewayKey=new Map;deletedGatewaySessionKeys=new Set;toolCallIdMap=new Map;toolCallToSessionMap=new Map;runIdToCronJobId=new Map;nextToolCallSeq=0;completedRunIds=new Set;lastActiveSessionId;sessionGcTimer=null;MAX_IDLE_SESSION_MS=864e5;EXTERNAL_SESSION_IDLE_MS=3e5;SESSION_GC_INTERVAL_MS=3e5;logger;constructor(e){this.logger=e}findSessionByKey(e){return this.sessionsByGatewayKey.get(e)}resolveSessionFromParams(e){const s="string"==typeof e?.sessionId?e.sessionId:void 0;if(s)return this.sessions.get(s)}isCurrentStreamOwner(e,s){return!s||!!e.currentRunId&&s===e.currentRunId}markRunCompleted(e){if(this.completedRunIds.add(e),this.completedRunIds.size>200){const e=this.completedRunIds.values().next().value;e&&this.completedRunIds.delete(e)}}isRunCompleted(e){return this.completedRunIds.has(e)}setRunCronJobId(e,s){if(this.runIdToCronJobId.set(e,s),this.runIdToCronJobId.size>400){const e=this.runIdToCronJobId.keys().next().value;void 0!==e&&this.runIdToCronJobId.delete(e)}}clearPromptTimeout(e){e.promptTimeoutTimer&&(clearTimeout(e.promptTimeoutTimer),e.promptTimeoutTimer=void 0)}clearStreamIdleTimer(e){e.streamIdleTimer&&(clearTimeout(e.streamIdleTimer),e.streamIdleTimer=void 0)}resetForNewRun(e,s,t){this.clearStreamIdleTimer(e),e.currentRunId&&(this.promptsByRunId.delete(e.currentRunId),this.runIdToCronJobId.delete(e.currentRunId)),e.gatewayRequestId&&this.promptsByGatewayRequestId.delete(e.gatewayRequestId),e.currentRunId=void 0,e.gatewayRequestId=void 0,e.assistantMq&&!e.assistantMq.closed&&(this.logger.warn?.(`[session-state] resetForNewRun discarding stale assistantMq sessionId=${s}`),e.assistantMq.close()),e.assistantMq=new MessageQueue,e.pendingUserTurnUpdates=[],e.chatReplayDedupKeys.clear(),e.hasAgentAssistantStream=!1,e.hasAgentThinkingStream=!1,e.hasAgentToolStartStream=!1,e.hasAgentToolResultStream=!1,e.chatAssistantTextSoFar=void 0,e.agentAssistantTextSoFar=void 0,e.cronJobId=void 0,e.presentedFileArtifactKeys=new Set,e.emittedToolResultKeys=new Set,e.promptDone=!1,t.resetSessionUpdateCount(s),this.enforceToolCallMapLimits()}enforceToolCallMapLimits(){if(this.toolCallIdMap.size>5e3){const e=this.toolCallIdMap.size-5e3;let s=0;for(const t of this.toolCallIdMap.keys()){if(s>=e)break;this.toolCallToSessionMap.delete(this.toolCallIdMap.get(t)),this.toolCallIdMap.delete(t),s++}}if(this.toolCallToSessionMap.size>5e3){const e=this.toolCallToSessionMap.size-5e3;let s=0;for(const t of this.toolCallToSessionMap.keys()){if(s>=e)break;this.toolCallToSessionMap.delete(t),s++}}}extractAgentAssistantDelta(e,s){const t=(e.chatAssistantTextSoFar??"").length;if(s.delta){const o=e.agentAssistantTextSoFar??"",i=o+s.delta;if(e.agentAssistantTextSoFar=i,t>0&&o.length<t){if(i.length<=t)return;return i.slice(t)}return s.delta}const o=s.text;if(!o)return;const i=e.agentAssistantTextSoFar??"";e.agentAssistantTextSoFar=o;const n=Math.max(i.length,t);if(!(o.length<=n)){if(o.startsWith(i)||0===n)return o.slice(n)||void 0;if(!i.startsWith(o))return o}}startSessionGc(e,s){this.sessionGcTimer=setInterval(()=>this.gcSessions(e,s),this.SESSION_GC_INTERVAL_MS),"object"==typeof this.sessionGcTimer&&"unref"in this.sessionGcTimer&&this.sessionGcTimer.unref()}gcSessions(e,s){const t=Date.now();let o=0;for(const[i,n]of this.sessions){if(void 0!==n.pendingPromptId)continue;(n.lastStreamActivityTs??n.createdAt)<t-(isExternalInvocationSessionKey(n.gatewaySessionKey)?this.EXTERNAL_SESSION_IDLE_MS:this.MAX_IDLE_SESSION_MS)&&(e(n),s?.(n),this.sessions.delete(i),this.sessionsByGatewayKey.delete(n.gatewaySessionKey),o++)}const i=new Set(Array.from(this.sessions.values()).map(e=>e.sessionId));for(const[e,s]of this.toolCallToSessionMap)i.has(s)||this.toolCallToSessionMap.delete(e);for(const[e,s]of this.toolCallIdMap)this.toolCallToSessionMap.has(s)||this.toolCallIdMap.delete(e);o>0&&(this.lastActiveSessionId&&!this.sessions.has(this.lastActiveSessionId)&&(this.lastActiveSessionId=void 0),this.logger.debug?.(`[session-state] GC evicted ${o} idle sessions, remaining=${this.sessions.size}`))}destroy(){this.sessionGcTimer&&(clearInterval(this.sessionGcTimer),this.sessionGcTimer=null);for(const e of this.sessions.values())this.clearPromptTimeout(e),this.clearStreamIdleTimer(e),e.assistantMq?.close();this.promptsByRunId.clear(),this.promptsByGatewayRequestId.clear(),this.runIdToCronJobId.clear(),this.completedRunIds.clear(),this.toolCallIdMap.clear(),this.toolCallToSessionMap.clear(),this.sessionsByGatewayKey.clear(),this.deletedGatewaySessionKeys.clear(),this.sessions.clear(),this.lastActiveSessionId=void 0}}
1
+ import{MessageQueue}from"../utils/mq.js";import{isExternalInvocationSessionKey}from"./external-protocol-tags.js";const MAX_TOOL_CALL_MAP_ENTRIES=5e3,MAX_COMPLETED_RUN_IDS=200;export class AcpGatewaySessionState{sessions=new Map;promptsByRunId=new Map;promptsByGatewayRequestId=new Map;sessionsByGatewayKey=new Map;deletedGatewaySessionKeys=new Set;toolCallIdMap=new Map;toolCallToSessionMap=new Map;runIdToCronJobId=new Map;nextToolCallSeq=0;completedRunIds=new Set;lastActiveSessionId;sessionGcTimer=null;MAX_IDLE_SESSION_MS=864e5;EXTERNAL_SESSION_IDLE_MS=3e5;SESSION_GC_INTERVAL_MS=3e5;logger;constructor(e){this.logger=e}findSessionByKey(e){return this.sessionsByGatewayKey.get(e)}resolveSessionFromParams(e){const s="string"==typeof e?.sessionId?e.sessionId:void 0;if(s)return this.sessions.get(s)}isCurrentStreamOwner(e,s){return!s||!!e.currentRunId&&s===e.currentRunId}markRunCompleted(e){if(this.completedRunIds.add(e),this.completedRunIds.size>200){const e=this.completedRunIds.values().next().value;e&&this.completedRunIds.delete(e)}}isRunCompleted(e){return this.completedRunIds.has(e)}setRunCronJobId(e,s){if(this.runIdToCronJobId.set(e,s),this.runIdToCronJobId.size>400){const e=this.runIdToCronJobId.keys().next().value;void 0!==e&&this.runIdToCronJobId.delete(e)}}clearPromptTimeout(e){e.promptTimeoutTimer&&(clearTimeout(e.promptTimeoutTimer),e.promptTimeoutTimer=void 0)}clearStreamIdleTimer(e){e.streamIdleTimer&&(clearTimeout(e.streamIdleTimer),e.streamIdleTimer=void 0)}resetForNewRun(e,s,t){this.clearStreamIdleTimer(e),e.currentRunId&&(this.promptsByRunId.delete(e.currentRunId),this.runIdToCronJobId.delete(e.currentRunId)),e.gatewayRequestId&&this.promptsByGatewayRequestId.delete(e.gatewayRequestId),e.currentRunId=void 0,e.gatewayRequestId=void 0,e.assistantMq&&!e.assistantMq.closed&&(this.logger.warn?.(`[session-state] resetForNewRun discarding stale assistantMq sessionId=${s}`),e.assistantMq.close()),e.assistantMq=new MessageQueue,e.pendingUserTurnUpdates=[],e.chatReplayDedupKeys.clear(),e.hasAgentAssistantStream=!1,e.hasAgentThinkingStream=!1,e.hasAgentToolStartStream=!1,e.hasAgentToolResultStream=!1,e.chatAssistantTextSoFar=void 0,e.agentAssistantTextSoFar=void 0,e.cronJobId=void 0,e.presentedFileArtifactKeys=new Set,e.emittedToolResultKeys=new Set,e.backgroundRunAdopted=!1,e.backgroundRunArtifacts=void 0,e.backgroundRunCaption=void 0,e.promptDone=!1,t.resetSessionUpdateCount(s),this.enforceToolCallMapLimits()}enforceToolCallMapLimits(){if(this.toolCallIdMap.size>5e3){const e=this.toolCallIdMap.size-5e3;let s=0;for(const t of this.toolCallIdMap.keys()){if(s>=e)break;this.toolCallToSessionMap.delete(this.toolCallIdMap.get(t)),this.toolCallIdMap.delete(t),s++}}if(this.toolCallToSessionMap.size>5e3){const e=this.toolCallToSessionMap.size-5e3;let s=0;for(const t of this.toolCallToSessionMap.keys()){if(s>=e)break;this.toolCallToSessionMap.delete(t),s++}}}extractAgentAssistantDelta(e,s){const t=(e.chatAssistantTextSoFar??"").length;if(s.delta){const o=e.agentAssistantTextSoFar??"",i=o+s.delta;if(e.agentAssistantTextSoFar=i,t>0&&o.length<t){if(i.length<=t)return;return i.slice(t)}return s.delta}const o=s.text;if(!o)return;const i=e.agentAssistantTextSoFar??"";e.agentAssistantTextSoFar=o;const n=Math.max(i.length,t);if(!(o.length<=n)){if(o.startsWith(i)||0===n)return o.slice(n)||void 0;if(!i.startsWith(o))return o}}startSessionGc(e,s){this.sessionGcTimer=setInterval(()=>this.gcSessions(e,s),this.SESSION_GC_INTERVAL_MS),"object"==typeof this.sessionGcTimer&&"unref"in this.sessionGcTimer&&this.sessionGcTimer.unref()}gcSessions(e,s){const t=Date.now();let o=0;for(const[i,n]of this.sessions){if(void 0!==n.pendingPromptId)continue;(n.lastStreamActivityTs??n.createdAt)<t-(isExternalInvocationSessionKey(n.gatewaySessionKey)?this.EXTERNAL_SESSION_IDLE_MS:this.MAX_IDLE_SESSION_MS)&&(e(n),s?.(n),this.sessions.delete(i),this.sessionsByGatewayKey.delete(n.gatewaySessionKey),o++)}const i=new Set(Array.from(this.sessions.values()).map(e=>e.sessionId));for(const[e,s]of this.toolCallToSessionMap)i.has(s)||this.toolCallToSessionMap.delete(e);for(const[e,s]of this.toolCallIdMap)this.toolCallToSessionMap.has(s)||this.toolCallIdMap.delete(e);o>0&&(this.lastActiveSessionId&&!this.sessions.has(this.lastActiveSessionId)&&(this.lastActiveSessionId=void 0),this.logger.debug?.(`[session-state] GC evicted ${o} idle sessions, remaining=${this.sessions.size}`))}destroy(){this.sessionGcTimer&&(clearInterval(this.sessionGcTimer),this.sessionGcTimer=null);for(const e of this.sessions.values())this.clearPromptTimeout(e),this.clearStreamIdleTimer(e),e.assistantMq?.close();this.promptsByRunId.clear(),this.promptsByGatewayRequestId.clear(),this.runIdToCronJobId.clear(),this.completedRunIds.clear(),this.toolCallIdMap.clear(),this.toolCallToSessionMap.clear(),this.sessionsByGatewayKey.clear(),this.deletedGatewaySessionKeys.clear(),this.sessions.clear(),this.lastActiveSessionId=void 0}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beeos-claw",
3
- "version": "0.6.30",
3
+ "version": "0.6.32",
4
4
  "description": "OpenClaw plugin that bridges the BeeOS platform with the local OpenClaw Gateway, providing file transfer, ACP bridge, and observability.",
5
5
  "license": "MIT",
6
6
  "author": "BeeOS <dev@beeos.ai>",