beeos-claw 0.5.70 → 0.5.72

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.
@@ -1 +1 @@
1
- import{createHash,randomUUID}from"node:crypto";import{dispatchRuntimeReplyWithRoute,hasRuntimeReplyApi}from"./runtime/reply-router.js";import{createImReplySink}from"./runtime/im-reply-sink.js";import{SerializedCallbackQueue}from"./runtime/callback-queue.js";import{promptRunKey}from"./runtime/prompt-run-store.js";import{classifyAgentRuntimeFailure}from"./runtime/agent-runtime-failure-classifier.js";import{SESSION_RECOVERY_REQUIRED_CODE,SESSION_RECOVERY_REQUIRED_MESSAGE}from"./runtime/session-mutation-coordinator.js";import{interceptAgentRuntimeFailures,messageStopReasonForRuntimeFailure,SESSION_BUSY_PUBLIC_MESSAGE}from"./runtime/im-runtime-failure-policy.js";const normalizePromptTimeoutMs=e=>{if("number"!=typeof e||!Number.isFinite(e))return;const n=Math.max(0,Math.trunc(e));return n>0?n:void 0},formatErrMessage=e=>{if(e instanceof Error)return e.message;if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}},deterministicMessageId=(e,n,r,a)=>`${e}_${createHash("sha256").update(`${n}:${r}:${a}`).digest("hex").slice(0,32)}`;export const dispatchImInboundPrompt=async e=>{const{runtime:n,prompt:r,client:a,logger:t,promptRunStore:i,sessionMutationCoordinator:s,abortTransport:o,activeRunAuthority:d}=e;if(!hasRuntimeReplyApi(n))return t.warn?.(`[im] runtime dispatch skipped reason=reply_api_unavailable channel=${r.channelId} in_reply_to=${r.inboundMessageId}`),e.onLifecycleEvent?.({type:"skipped",reason:"reply_api_unavailable",channelId:r.channelId,inboundMessageId:r.inboundMessageId}),!1;const c=`im_req_${randomUUID().replace(/-/g,"")}`,l=randomUUID(),u=Date.now(),m=e.origin??"im",p={protocol:"im",requestId:c,sessionId:r.sessionKey??"agent:main",sourceMessageId:r.inboundMessageId,chatId:r.channelId,origin:m},I=normalizePromptTimeoutMs(e.promptTimeoutMs),h=promptRunKey(r.channelId,r.inboundMessageId),g=r.sessionKey??"agent:main",y=new AbortController;let _,f,E;const R=new Promise((e,n)=>{E=n}),b=async e=>{if(f??=e,y.abort(e),!_)return{ok:!0};const n=await s.requestCancel(_,o);return n.ok?n.terminalObservation.then(e=>{e.ok||E(new Error(SESSION_RECOVERY_REQUIRED_CODE))}):E(new Error(SESSION_RECOVERY_REQUIRED_CODE)),{ok:n.ok}};if(!i.register(h,{requestId:c,channelId:r.channelId,requestCancel:b,startedAt:u,sessionKey:g}))return t.warn?.(`[im] runtime dispatch rejected duplicate inboundMessageId=${r.inboundMessageId} requestId=${c} channel=${r.channelId}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,error:"duplicate_inbound_message_id",cause:"abort"}),!1;const $=a.messages.startStream({conversationId:r.channelId,id:deterministicMessageId("asst",r.channelId,r.inboundMessageId,r.selfPrincipalId),replyTo:e.inReplyTo??r.inboundMessageId,type:"agent_reply"},{onError:(e,n)=>{const a="terminal"===n?t.warn:t.debug;a?.(`[im] runtime stream ${n} PATCH error requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId}: ${e.message}`)}},{sender:r.selfPrincipalId});let w,M=!1;try{M=!0===(await $.opened()).idempotent}catch(e){t.debug?.(`[im] runtime reply stream open probe failed requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId}: ${formatErrMessage(e)}; continuing so terminal fallback can land an error row`)}if(M)return t.info?.(`[im] runtime dispatch skipped existing deterministic reply requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId}`),e.onLifecycleEvent?.({type:"skipped",reason:"idempotent_reply_exists",channelId:r.channelId,inboundMessageId:r.inboundMessageId}),i.unregister(h),!1;const S=new SerializedCallbackQueue,v=createImReplySink({stream:$,openReasoningStream:()=>(w=a.messages.startStream({conversationId:r.channelId,id:deterministicMessageId("rsn",r.channelId,r.inboundMessageId,r.selfPrincipalId),replyTo:e.inReplyTo??r.inboundMessageId,type:"agent_reasoning"},{onError:(e,n)=>{const a="terminal"===n?t.warn:t.debug;a?.(`[im] runtime reasoning stream ${n} PATCH error requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId}: ${e.message}`)}},{sender:r.selfPrincipalId}),w),abortSignal:y.signal,callbackQueue:S,logger:t,requestId:c,runId:l,channelId:r.channelId,inboundMessageId:r.inboundMessageId,origin:m,onAgentRunStart:e=>{s.bindRun(_,e)}}),q=interceptAgentRuntimeFailures(v,"im_runtime",e=>t.warn?.(`[im] runtime failure reply suppressed requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId} error_code=${e.errorCode}`)),k=q.sink,C=async(e,n)=>{if(!w)return!1;try{return"cancel"===e?await w.cancel({stopReason:"user_stop"}):"fail"===e?await w.fail(n?{stopReason:n}:void 0):await w.finalize({stopReason:"end_turn"}),!1}catch(e){return t.warn?.(`[im] runtime reasoning stream terminal write failed requestId=${c} channel=${r.channelId}: ${formatErrMessage(e)}`),!0}};let O,D,U=!1;const A=async e=>{k.dispatcher.markComplete(e);try{await k.dispatcher.waitForIdle()}catch{}},T=()=>{if(!y.signal.aborted)return;const e=y.signal.reason;throw e instanceof Error?e:new Error(String(e??"runtime dispatch aborted"))};let K,F,P;const N=async e=>{if(!_)throw new Error("session_mutation_not_acquired");const n=await s.converge(_,e);return n.ok?(K=n.permit,!0):(t.error?.(`[im] session mutation recovery required requestId=${c} sessionKey=${g} reason=${n.recovery.reason}`),F={code:n.recovery.code,reason:n.recovery.reason,sessionKey:n.recovery.sessionKey,operationId:n.recovery.operationId,surface:"message_service",...n.recovery.terminalKind?{terminalKind:n.recovery.terminalKind}:{}},!1)};try{T();const a=s.tryStartInteractive({sessionKey:g,label:"im_chat_message"},"message_service");if(!a.ok){try{await $.fail({body:SESSION_BUSY_PUBLIC_MESSAGE,stopReason:"error"})}catch(e){t.warn?.(`[im] session busy terminal write failed channel=${r.channelId} in_reply_to=${r.inboundMessageId}: ${formatErrMessage(e)}`)}return t.warn?.(`[im] session write gate busy sessionKey=${g} channel=${r.channelId} in_reply_to=${r.inboundMessageId} active_operation=${a.activeOperationId??"unknown"}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,error:"session_busy",cause:"runtime_error"}),!1}if(_=a.token,s.bindRun(_,l),d){const e=s.snapshot(g);P={runtimeConversationUid:r.channelId,runtimeSessionKey:r.channelId,historyGeneration:d.historyGeneration(r.channelId),targetMessageId:r.inboundMessageId,runtimeRunId:l,activeRunRegistrationId:`im:${e?.operationId??l}`},d.activeRuns.register(P,async()=>(await b(`chat_cancel:activeRun:${P.activeRunRegistrationId}`)).ok?"accepted":"recovery_required")}T(),t.info?.(`[im] runtime dispatching requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId} origin=${m}`),e.onLifecycleEvent?.({type:"dispatch_start",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId});const o=dispatchRuntimeReplyWithRoute({runtime:n,pluginConfig:e.pluginConfig,preparedPrompt:r.dispatchInput,replyRoute:p,replySinks:{im:k},onDispatchInvoked:()=>{U=!0}});void 0!==I&&(O=setTimeout(()=>{D=new Error(`IM runtime dispatch timed out after ${I}ms`),t.warn?.(`[im] runtime dispatch timeout requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId} timeout_ms=${I}`),b(D)},I));const y=Promise.race([o,R]),f=await y.finally(()=>{O&&(clearTimeout(O),O=void 0)}),E=q.detectedFailure();if(E)throw new Error(E.diagnosticMessage);if(T(),await A("success"),T(),!i.claimTerminal(h,"completion")){if(T(),"cancelling"===i.phase(h))throw new Error("cancellation in progress");throw new Error("terminal outcome already claimed")}if(!await N("completed"))return await C("fail"),await $.fail({body:SESSION_RECOVERY_REQUIRED_MESSAGE,stopReason:"error"}).catch(()=>{}),e.onLifecycleEvent?.({type:"dispatch_error",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,error:SESSION_RECOVERY_REQUIRED_CODE,cause:"runtime_error",...F?{recovery:F}:{}}),!1;const w=await C("complete");let M=!1;try{await $.finalize({stopReason:"end_turn"})}catch(e){M=!0,t.warn?.(`[im] runtime reply stream finalize failed requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId}: ${formatErrMessage(e)}`)}return d&&P&&d.activeRuns.markTerminal(P,"completed"),t.info?.(`[im] runtime dispatch completed requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId} counts=${JSON.stringify(f.counts)} elapsed_ms=${Date.now()-u}`),e.onLifecycleEvent?.({type:"dispatch_complete",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,counts:f.counts,...M?{terminalWriteFailed:!0}:{},...w?{reasoningTerminalWriteFailed:!0}:{}}),!0}catch(n){await A("failure");const a=y.signal.aborted,s=a?y.signal.reason:void 0,o="cancelling"===i.phase(h),l=void 0!==D,u=s??f,m=!l&&"string"==typeof u&&u.startsWith("chat_cancel");let p="runtime_error";l?p="timeout":(a||o)&&(p="abort");const I=o||m||l||a?"cancellation":"completion";if(!i.claimTerminal(h,I))throw t.warn?.(`[im] terminal write skipped because another outcome already committed requestId=${c} channel=${r.channelId}`),n;const g=m?"cancelled":l?"timeout":"error";if(d&&P&&d.activeRuns.markTerminal(P,"cancelled"===g?"cancelled":"failed"),_&&!await N(g))throw await C("fail"),await $.fail({body:SESSION_RECOVERY_REQUIRED_MESSAGE,stopReason:"error"}).catch(()=>{}),e.onLifecycleEvent?.({type:"dispatch_error",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,error:SESSION_RECOVERY_REQUIRED_CODE,cause:p,...F?{recovery:F}:{}}),n;const E=classifyAgentRuntimeFailure({raw:n,source:"im_runtime",runtimeKind:"openclaw",requestAborted:m}),R=m?E:q.detectedFailure()??E;m?await C("cancel"):l?await C("fail","timeout"):await C("fail");try{m?await $.cancel({stopReason:"user_stop"}):await $.fail({body:R.publicMessage,stopReason:messageStopReasonForRuntimeFailure(R)})}catch(e){t.warn?.(`[im] runtime stream terminal write failed requestId=${c} channel=${r.channelId}: ${formatErrMessage(e)}`)}throw t.warn?.(`[im] runtime dispatch failed requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId} cause=${p} dispatchInvoked=${U} error_code=${R.errorCode}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,error:R.errorCode,cause:p}),n}finally{i.unregister(h),U?K&&s.release(K):s.releaseBeforeRuntime(_)}};
1
+ import{createHash,randomUUID}from"node:crypto";import{dispatchRuntimeReplyWithRoute,hasRuntimeReplyApi}from"./runtime/reply-router.js";import{createImReplySink}from"./runtime/im-reply-sink.js";import{SerializedCallbackQueue}from"./runtime/callback-queue.js";import{promptRunKey}from"./runtime/prompt-run-store.js";import{classifyAgentRuntimeFailure}from"./runtime/agent-runtime-failure-classifier.js";import{SESSION_RECOVERY_REQUIRED_CODE,SESSION_RECOVERY_REQUIRED_MESSAGE}from"./runtime/session-mutation-coordinator.js";import{interceptAgentRuntimeFailures,messageStopReasonForRuntimeFailure,SESSION_BUSY_PUBLIC_MESSAGE}from"./runtime/im-runtime-failure-policy.js";const normalizePromptTimeoutMs=e=>{if("number"!=typeof e||!Number.isFinite(e))return;const n=Math.max(0,Math.trunc(e));return n>0?n:void 0},formatErrMessage=e=>{if(e instanceof Error)return e.message;if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}},deterministicMessageId=(e,n,r,a)=>`${e}_${createHash("sha256").update(`${n}:${r}:${a}`).digest("hex").slice(0,32)}`;export const dispatchImInboundPrompt=async e=>{const{runtime:n,prompt:r,client:a,logger:t,promptRunStore:i,sessionMutationCoordinator:s,abortTransport:o,activeRunAuthority:d}=e;if(!hasRuntimeReplyApi(n))return t.warn?.(`[im] runtime dispatch skipped reason=reply_api_unavailable channel=${r.channelId} in_reply_to=${r.inboundMessageId}`),e.onLifecycleEvent?.({type:"skipped",reason:"reply_api_unavailable",channelId:r.channelId,inboundMessageId:r.inboundMessageId}),!1;const c=`im_req_${randomUUID().replace(/-/g,"")}`,l=randomUUID(),u=Date.now(),m=e.origin??"im",p={protocol:"im",requestId:c,sessionId:r.sessionKey??"agent:main",sourceMessageId:r.inboundMessageId,chatId:r.channelId,origin:m},I=normalizePromptTimeoutMs(e.promptTimeoutMs),h=promptRunKey(r.channelId,r.inboundMessageId),g=r.sessionKey??"agent:main",y=new AbortController;let _,f,E;const b=new Promise((e,n)=>{E=n}),R=async e=>{if(f??=e,y.abort(e),!_)return{ok:!0};const n=await s.requestCancel(_,o);return n.ok?n.terminalObservation.then(e=>{e.ok||E(new Error(SESSION_RECOVERY_REQUIRED_CODE))}):E(new Error(SESSION_RECOVERY_REQUIRED_CODE)),{ok:n.ok}};if(!i.register(h,{requestId:c,channelId:r.channelId,requestCancel:R,startedAt:u,sessionKey:g}))return t.warn?.(`[im] runtime dispatch rejected duplicate inboundMessageId=${r.inboundMessageId} requestId=${c} channel=${r.channelId}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,error:"duplicate_inbound_message_id",cause:"abort"}),!1;const $=a.messages.startStream({conversationId:r.channelId,id:deterministicMessageId("asst",r.channelId,r.inboundMessageId,r.selfPrincipalId),replyTo:e.inReplyTo??r.inboundMessageId,type:"agent_reply"},{onError:(e,n)=>{const a="terminal"===n?t.warn:t.debug;a?.(`[im] runtime stream ${n} PATCH error requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId}: ${e.message}`)}},{sender:r.selfPrincipalId});let w,M=!1;try{M=!0===(await $.opened()).idempotent}catch(e){t.debug?.(`[im] runtime reply stream open probe failed requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId}: ${formatErrMessage(e)}; continuing so terminal fallback can land an error row`)}if(M)return t.info?.(`[im] runtime dispatch skipped existing deterministic reply requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId}`),e.onLifecycleEvent?.({type:"skipped",reason:"idempotent_reply_exists",channelId:r.channelId,inboundMessageId:r.inboundMessageId}),i.unregister(h),!1;const S=new SerializedCallbackQueue,v=createImReplySink({stream:$,openReasoningStream:()=>(w=a.messages.startStream({conversationId:r.channelId,id:deterministicMessageId("rsn",r.channelId,r.inboundMessageId,r.selfPrincipalId),replyTo:e.inReplyTo??r.inboundMessageId,type:"agent_reasoning"},{onError:(e,n)=>{const a="terminal"===n?t.warn:t.debug;a?.(`[im] runtime reasoning stream ${n} PATCH error requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId}: ${e.message}`)}},{sender:r.selfPrincipalId}),w),abortSignal:y.signal,callbackQueue:S,logger:t,requestId:c,runId:l,channelId:r.channelId,inboundMessageId:r.inboundMessageId,origin:m,onAgentRunStart:e=>{s.bindRun(_,e)}}),q=interceptAgentRuntimeFailures(v,"im_runtime",e=>t.warn?.(`[im] runtime failure reply suppressed requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId} error_code=${e.errorCode}`)),k=q.sink,C=async(e,n)=>{if(!w)return!1;try{return"cancel"===e?await w.cancel({stopReason:"user_stop"}):"fail"===e?await w.fail(n?{stopReason:n}:void 0):await w.finalize({stopReason:"end_turn"}),!1}catch(e){return t.warn?.(`[im] runtime reasoning stream terminal write failed requestId=${c} channel=${r.channelId}: ${formatErrMessage(e)}`),!0}};let O,D,U=!1;const A=async e=>{k.dispatcher.markComplete(e);try{await k.dispatcher.waitForIdle()}catch{}},T=()=>{if(!y.signal.aborted)return;const e=y.signal.reason;throw e instanceof Error?e:new Error(String(e??"runtime dispatch aborted"))};let K,F,P;const N=async e=>{if(!_)throw new Error("session_mutation_not_acquired");const n=await s.converge(_,e);return n.ok?(K=n.permit,!0):(t.error?.(`[im] session mutation recovery required requestId=${c} sessionKey=${g} reason=${n.recovery.reason}`),F={code:n.recovery.code,reason:n.recovery.reason,sessionKey:n.recovery.sessionKey,operationId:n.recovery.operationId,surface:"message_service",...n.recovery.terminalKind?{terminalKind:n.recovery.terminalKind}:{}},!1)};try{T();const a=s.tryStartInteractive({sessionKey:g,label:"im_chat_message"},"message_service");if(!a.ok){try{await $.fail({body:SESSION_BUSY_PUBLIC_MESSAGE,stopReason:"error"})}catch(e){t.warn?.(`[im] session busy terminal write failed channel=${r.channelId} in_reply_to=${r.inboundMessageId}: ${formatErrMessage(e)}`)}return t.warn?.(`[im] session write gate busy sessionKey=${g} channel=${r.channelId} in_reply_to=${r.inboundMessageId} active_operation=${a.activeOperationId??"unknown"}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,error:"session_busy",cause:"runtime_error"}),!1}if(_=a.token,s.bindRun(_,l),d){const e=s.snapshot(g);P={runtimeConversationUid:r.channelId,runtimeSessionKey:r.channelId,historyGeneration:d.historyGeneration(r.channelId),targetMessageId:r.inboundMessageId,runtimeRunId:l,activeRunRegistrationId:`im:${e?.operationId??l}`},d.activeRuns.register(P,async()=>{const e=`chat_cancel:activeRun:${P.activeRunRegistrationId}`,n=await i.abort(h,e);return n.ok||"already_aborted"===n.reason?"accepted":"terminal_committing"===n.reason||"not_found"===n.reason?"already_terminal":"recovery_required"})}T(),t.info?.(`[im] runtime dispatching requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId} origin=${m}`),e.onLifecycleEvent?.({type:"dispatch_start",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId});const o=dispatchRuntimeReplyWithRoute({runtime:n,pluginConfig:e.pluginConfig,preparedPrompt:r.dispatchInput,replyRoute:p,replySinks:{im:k},onDispatchInvoked:()=>{U=!0}});void 0!==I&&(O=setTimeout(()=>{D=new Error(`IM runtime dispatch timed out after ${I}ms`),t.warn?.(`[im] runtime dispatch timeout requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId} timeout_ms=${I}`),R(D)},I));const y=Promise.race([o,b]),f=await y.finally(()=>{O&&(clearTimeout(O),O=void 0)}),E=q.detectedFailure();if(E)throw new Error(E.diagnosticMessage);if(T(),await A("success"),T(),!i.claimTerminal(h,"completion")){if(T(),"cancelling"===i.phase(h))throw new Error("cancellation in progress");throw new Error("terminal outcome already claimed")}if(!await N("completed"))return await C("fail"),await $.fail({body:SESSION_RECOVERY_REQUIRED_MESSAGE,stopReason:"error"}).catch(()=>{}),e.onLifecycleEvent?.({type:"dispatch_error",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,error:SESSION_RECOVERY_REQUIRED_CODE,cause:"runtime_error",...F?{recovery:F}:{}}),!1;const w=await C("complete");let M=!1;try{await $.finalize({stopReason:"end_turn"})}catch(e){M=!0,t.warn?.(`[im] runtime reply stream finalize failed requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId}: ${formatErrMessage(e)}`)}return d&&P&&d.activeRuns.markTerminal(P,"completed"),t.info?.(`[im] runtime dispatch completed requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId} counts=${JSON.stringify(f.counts)} elapsed_ms=${Date.now()-u}`),e.onLifecycleEvent?.({type:"dispatch_complete",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,counts:f.counts,...M?{terminalWriteFailed:!0}:{},...w?{reasoningTerminalWriteFailed:!0}:{}}),!0}catch(n){await A("failure");const a=y.signal.aborted,s=a?y.signal.reason:void 0,o="cancelling"===i.phase(h),l=void 0!==D,u=s??f,m=!l&&"string"==typeof u&&u.startsWith("chat_cancel");let p="runtime_error";l?p="timeout":(a||o)&&(p="abort");const I=o||m||l||a?"cancellation":"completion";if(!i.claimTerminal(h,I))throw t.warn?.(`[im] terminal write skipped because another outcome already committed requestId=${c} channel=${r.channelId}`),n;const g=m?"cancelled":l?"timeout":"error";if(d&&P&&d.activeRuns.markTerminal(P,"cancelled"===g?"cancelled":"failed"),_&&!await N(g))throw await C("fail"),await $.fail({body:SESSION_RECOVERY_REQUIRED_MESSAGE,stopReason:"error"}).catch(()=>{}),e.onLifecycleEvent?.({type:"dispatch_error",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,error:SESSION_RECOVERY_REQUIRED_CODE,cause:p,...F?{recovery:F}:{}}),n;const E=classifyAgentRuntimeFailure({raw:n,source:"im_runtime",runtimeKind:"openclaw",requestAborted:m}),b=m?E:q.detectedFailure()??E;m?await C("cancel"):l?await C("fail","timeout"):await C("fail");try{m?await $.cancel({stopReason:"user_stop"}):await $.fail({body:b.publicMessage,stopReason:messageStopReasonForRuntimeFailure(b)})}catch(e){t.warn?.(`[im] runtime stream terminal write failed requestId=${c} channel=${r.channelId}: ${formatErrMessage(e)}`)}throw t.warn?.(`[im] runtime dispatch failed requestId=${c} channel=${r.channelId} in_reply_to=${r.inboundMessageId} cause=${p} dispatchInvoked=${U} error_code=${b.errorCode}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:c,channelId:r.channelId,inboundMessageId:r.inboundMessageId,error:b.errorCode,cause:p}),n}finally{i.unregister(h),U?K&&s.release(K):s.releaseBeforeRuntime(_)}};
@@ -1 +1 @@
1
- import{canonicalizeJcs,verifyAndDeriveCoreExecutionAttempt}from"@beeos-ai/beeos-types/runtime";const TRUSTED_CORE_ATTEMPT=Symbol("beeos.trusted-core-attempt"),VERIFIED_MESSAGE_GRANT=Symbol("beeos.verified-message-grant");export function createAcpCoreExecutionAttempt(e){if(e.historyBoundary&&"local"!==e.historyBoundary.kind)throw new Error("ACP attempt cannot use a Message Service history boundary");return Object.freeze({...e,origin:"acp",[TRUSTED_CORE_ATTEMPT]:!0})}export async function verifyAndCreateServiceCoreExecutionAttempt(e){let t;try{t=verifyAndDeriveCoreExecutionAttempt(e.authorization,e.derivationContext,e.verifier)}catch{return{ok:!1,violations:["MALFORMED_EXECUTION_AUTHORIZATION"]}}if(!t.ok)return t;await e.recordVerifiedAttempt(t.attempt);const r=await e.resolvePorts();if(r.historyBoundary&&"message-service"!==r.historyBoundary.kind)throw new Error("Service attempt cannot fall back to local conversation history");return{ok:!0,context:Object.freeze({operationId:e.operationId,runtimeEpoch:e.runtimeEpoch,fence:e.fence,resources:r.resources,...r.historyBoundary?{historyBoundary:r.historyBoundary}:{},...r.canvasControl?{canvasControl:r.canvasControl}:{},...e.abortSignal?{abortSignal:e.abortSignal}:{},verifiedAttempt:t.attempt,origin:"service",[TRUSTED_CORE_ATTEMPT]:!0})}}export async function verifyAndCreateMessageServiceCoreExecutionAttempt(e){const t=e.verifier.verifyAndDecodeGrant(e.executionGrant);if(!t)return{ok:!1,violations:["GRANT_SIGNATURE_INVALID"]};if(t.compactHash!==e.request.executionGrantHash)return{ok:!1,violations:["GRANT_HASH_MISMATCH"]};const r=t.claims,o=validateMessageGrant(r,e.request,e.lease,e.nowEpochSeconds??Math.floor(Date.now()/1e3),!0===e.allowExpiredGrant);if(o.length)return{ok:!1,violations:o};const n=await e.resolvePorts();if(n.historyBoundary&&"message-service"!==n.historyBoundary.kind)throw new Error("Service attempt cannot fall back to local conversation history");const a=Object.freeze({[VERIFIED_MESSAGE_GRANT]:!0,claims:Object.freeze({...r}),compactHash:t.compactHash});return{ok:!0,grant:a,context:Object.freeze({operationId:e.request.operationId,runtimeEpoch:e.runtimeEpoch,resources:n.resources,...n.historyBoundary?{historyBoundary:n.historyBoundary}:{},...n.canvasControl?{canvasControl:n.canvasControl}:{},...e.abortSignal?{abortSignal:e.abortSignal}:{},verifiedMessageGrant:a,origin:"service",[TRUSTED_CORE_ATTEMPT]:!0})}}export function assertTrustedCoreExecutionAttempt(e,t){if(!e||!0!==e[TRUSTED_CORE_ATTEMPT]||e.operationId!==t.operationId||e.runtimeEpoch!==t.runtimeEpoch)throw new Error("untrusted or mismatched Core execution attempt context");if(!("service"!==e.origin||e.verifiedMessageGrant||e.fence&&e.verifiedAttempt))throw new Error("Service Core execution attempt lacks verified authorization")}function validateMessageGrant(e,t,r,o,n){if(!e||"object"!=typeof e)return["MALFORMED_EXECUTION_GRANT"];if(!exactKeys(e,["iss","aud","purpose","sub","jti","iat","exp","operationId","requestMessageId","instanceId","handlerIdentity","dispatchEpoch","method","requestHash","paramsHash","commandHash","idempotencyKeyHash","callerUserId","callerIdentityId","scope","command","executionMode",..."instance"===e.scope?[]:"agent"===e.scope?["platformAgentId","runtimeAgentUid"]:"conversation"===e.scope?["platformConversationId","runtimeConversationUid","runtimeSessionKey"]:[]]))return["GRANT_FIELDS_INVALID"];const a=[];"beeos-gateway"===e.iss&&"beeos-runtime-command"===e.aud&&"runtime-execution-grant"===e.purpose&&e.sub===t.runtimeHandlerIdentity&&e.handlerIdentity===t.runtimeHandlerIdentity&&"start"===e.executionMode||a.push("GRANT_IDENTITY_MISMATCH"),(!Number.isSafeInteger(e.iat)||!Number.isSafeInteger(e.exp)||"string"!=typeof e.jti||0===e.jti.length||e.iat>o||e.exp<=e.iat||!n&&e.exp<=o||e.exp-e.iat>60)&&a.push("GRANT_TIME_INVALID");return[[e.operationId,t.operationId],[e.requestMessageId,t.requestMessageId],[e.instanceId,t.instanceId],[e.dispatchEpoch,t.dispatchEpoch],[e.method,t.method],[e.requestHash,t.requestHash],[e.paramsHash,t.paramsHash],[e.commandHash,t.commandHash],[e.idempotencyKeyHash,t.idempotencyKeyHash],[e.callerUserId,t.callerUserId],[e.callerIdentityId,t.callerIdentityId],[r.instanceId,t.instanceId],[r.handlerIdentity,t.runtimeHandlerIdentity],[r.runtimeEpoch,t.dispatchEpoch]].some(([e,t])=>e!==t)&&a.push("GRANT_REQUEST_MISMATCH"),semanticEqual(e.command,t.command)||a.push("GRANT_COMMAND_MISMATCH"),targetMatches(e,t)||a.push("GRANT_TARGET_MISMATCH"),a}function semanticEqual(e,t){try{return canonicalizeJcs(e)===canonicalizeJcs(t)}catch{return!1}}function targetMatches(e,t){const r=t.command.context,o=t.request.params;return!(!r||r.scope!==e.scope)&&("instance"===r.scope||("agent"===r.scope?r.agent.runtimeAgentUid===e.runtimeAgentUid&&null!==o&&"object"==typeof o&&!Array.isArray(o)&&o.platformAgentId===e.platformAgentId:r.conversation.runtimeConversationUid===e.runtimeConversationUid&&r.conversation?.runtimeSessionKey===e.runtimeSessionKey&&null!==o&&"object"==typeof o&&!Array.isArray(o)&&o.conversationId===e.platformConversationId))}function exactKeys(e,t){const r=Object.keys(e).sort(),o=[...t].sort();return r.length===o.length&&r.every((e,t)=>e===o[t])}
1
+ import{canonicalizeJcs,verifyAndDeriveCoreExecutionAttempt}from"@beeos-ai/beeos-types/runtime";const TRUSTED_CORE_ATTEMPT=Symbol("beeos.trusted-core-attempt"),VERIFIED_MESSAGE_GRANT=Symbol("beeos.verified-message-grant");export function createAcpCoreExecutionAttempt(e){if(e.historyBoundary&&"local"!==e.historyBoundary.kind)throw new Error("ACP attempt cannot use a Message Service history boundary");return Object.freeze({...e,origin:"acp",[TRUSTED_CORE_ATTEMPT]:!0})}export async function verifyAndCreateServiceCoreExecutionAttempt(e){let t;try{t=verifyAndDeriveCoreExecutionAttempt(e.authorization,e.derivationContext,e.verifier)}catch{return{ok:!1,violations:["MALFORMED_EXECUTION_AUTHORIZATION"]}}if(!t.ok)return t;await e.recordVerifiedAttempt(t.attempt);const r=await e.resolvePorts();if(r.historyBoundary&&"message-service"!==r.historyBoundary.kind)throw new Error("Service attempt cannot fall back to local conversation history");return{ok:!0,context:Object.freeze({operationId:e.operationId,runtimeEpoch:e.runtimeEpoch,fence:e.fence,resources:r.resources,...r.historyBoundary?{historyBoundary:r.historyBoundary}:{},...r.canvasControl?{canvasControl:r.canvasControl}:{},...e.abortSignal?{abortSignal:e.abortSignal}:{},verifiedAttempt:t.attempt,origin:"service",[TRUSTED_CORE_ATTEMPT]:!0})}}export async function verifyAndCreateMessageServiceCoreExecutionAttempt(e){const t=e.verifier.verifyAndDecodeGrant(e.executionGrant);if(!t)return{ok:!1,violations:["GRANT_SIGNATURE_INVALID"]};if(t.compactHash!==e.request.executionGrantHash)return{ok:!1,violations:["GRANT_HASH_MISMATCH"]};const r=t.claims,n=validateMessageGrant(r,e.request,e.lease,e.nowEpochSeconds??Math.floor(Date.now()/1e3),!0===e.allowExpiredGrant);if(n.length)return{ok:!1,violations:n};const o=await e.resolvePorts();if(o.historyBoundary&&"message-service"!==o.historyBoundary.kind)throw new Error("Service attempt cannot fall back to local conversation history");const i=Object.freeze({[VERIFIED_MESSAGE_GRANT]:!0,claims:Object.freeze({...r}),compactHash:t.compactHash});return{ok:!0,grant:i,context:Object.freeze({operationId:e.request.operationId,runtimeEpoch:e.runtimeEpoch,resources:o.resources,...o.historyBoundary?{historyBoundary:o.historyBoundary}:{},...o.canvasControl?{canvasControl:o.canvasControl}:{},...e.abortSignal?{abortSignal:e.abortSignal}:{},verifiedMessageGrant:i,origin:"service",[TRUSTED_CORE_ATTEMPT]:!0})}}export function assertTrustedCoreExecutionAttempt(e,t){if(!e||!0!==e[TRUSTED_CORE_ATTEMPT]||e.operationId!==t.operationId||e.runtimeEpoch!==t.runtimeEpoch)throw new Error("untrusted or mismatched Core execution attempt context");if(!("service"!==e.origin||e.verifiedMessageGrant||e.fence&&e.verifiedAttempt))throw new Error("Service Core execution attempt lacks verified authorization")}function validateMessageGrant(e,t,r,n,o){if(!e||"object"!=typeof e)return["MALFORMED_EXECUTION_GRANT"];const i="historyGeneration"in e?e.historyGeneration:void 0;if(!exactKeys(e,["iss","aud","purpose","sub","jti","iat","exp","operationId","requestMessageId","instanceId","handlerIdentity","dispatchEpoch","method","requestHash","paramsHash","commandHash","idempotencyKeyHash","callerUserId","callerIdentityId","scope","command","executionMode",..."instance"===e.scope?[]:"agent"===e.scope?["platformAgentId","runtimeAgentUid"]:"conversation"===e.scope?["platformConversationId","runtimeConversationUid","runtimeSessionKey","platformAgentId","runtimeAgentUid",...void 0!==i?["historyGeneration"]:[]]:[]]))return["GRANT_FIELDS_INVALID"];const a=[];"beeos-gateway"===e.iss&&"beeos-runtime-command"===e.aud&&"runtime-execution-grant"===e.purpose&&e.sub===t.runtimeHandlerIdentity&&e.handlerIdentity===t.runtimeHandlerIdentity&&"start"===e.executionMode||a.push("GRANT_IDENTITY_MISMATCH"),(!Number.isSafeInteger(e.iat)||!Number.isSafeInteger(e.exp)||"string"!=typeof e.jti||0===e.jti.length||e.iat>n||e.exp<=e.iat||!o&&e.exp<=n||e.exp-e.iat>60)&&a.push("GRANT_TIME_INVALID");if([[e.operationId,t.operationId],[e.requestMessageId,t.requestMessageId],[e.instanceId,t.instanceId],[e.dispatchEpoch,t.dispatchEpoch],[e.method,t.method],[e.requestHash,t.requestHash],[e.paramsHash,t.paramsHash],[e.commandHash,t.commandHash],[e.idempotencyKeyHash,t.idempotencyKeyHash],[e.callerUserId,t.callerUserId],[e.callerIdentityId,t.callerIdentityId],[r.instanceId,t.instanceId],[r.handlerIdentity,t.runtimeHandlerIdentity],[r.runtimeEpoch,t.dispatchEpoch]].some(([e,t])=>e!==t)&&a.push("GRANT_REQUEST_MISMATCH"),semanticEqual(e.command,t.command)||a.push("GRANT_COMMAND_MISMATCH"),targetMatches(e,t)||a.push("GRANT_TARGET_MISMATCH"),"conversation"===e.scope){const r=t.command.context,n=r?.agent;r&&"conversation"===r.scope&&n?.platformAgentId===e.platformAgentId&&n?.runtimeAgentUid===e.runtimeAgentUid||a.push("GRANT_TARGET_MISMATCH");const o=r?.historyGeneration;"session/cancel"===e.method?"string"==typeof i&&0!==i.length&&i===o||a.push("GRANT_HISTORY_GENERATION_MISMATCH"):void 0!==i&&a.push("GRANT_HISTORY_GENERATION_MISMATCH")}return a}function semanticEqual(e,t){try{return canonicalizeJcs(e)===canonicalizeJcs(t)}catch{return!1}}function targetMatches(e,t){const r=t.command.context,n=t.request.params;if(!r||r.scope!==e.scope)return!1;if("instance"===r.scope)return!0;if("agent"===r.scope)return r.agent.runtimeAgentUid===e.runtimeAgentUid&&null!==n&&"object"==typeof n&&!Array.isArray(n)&&n.platformAgentId===e.platformAgentId;const o=null===n||"object"!=typeof n||Array.isArray(n)?void 0:"string"==typeof n.conversationId?n.conversationId:"string"==typeof n.sessionId?n.sessionId:void 0;return r.conversation.runtimeConversationUid===e.runtimeConversationUid&&r.conversation?.runtimeSessionKey===e.runtimeSessionKey&&o===e.platformConversationId}function exactKeys(e,t){const r=Object.keys(e).sort(),n=[...t].sort();return r.length===n.length&&r.every((e,t)=>e===n[t])}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beeos-claw",
3
- "version": "0.5.70",
3
+ "version": "0.5.72",
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>",