beeos-claw 0.6.33 → 0.6.35-staging.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/agent-auth.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as crypto from"node:crypto";import*as fs from"node:fs";import*as path from"node:path";const ED25519_PKCS8_PREFIX=Buffer.from("302e020100300506032b657004220420","hex");function wrapPrivateKey(e){return 32===e.length?Buffer.concat([ED25519_PKCS8_PREFIX,Buffer.from(e)]):Buffer.from(e)}const ED25519_SPKI_PREFIX=Buffer.from("302a300506032b6570032100","hex");function derivePublicKey(e){const r=crypto.createPrivateKey({key:wrapPrivateKey(e),format:"der",type:"pkcs8"}),t=crypto.createPublicKey(r).export({type:"spki",format:"der"});return 44===t.length?new Uint8Array(t.subarray(12)):new Uint8Array(t)}export function loadAgentKeyPair(e){if(!fs.existsSync(e))return generateAgentKeyPair(e);const r=fs.readFileSync(e,"utf-8").trim();try{const e=JSON.parse(r);if(e.publicKey&&e.privateKey)return{publicKey:new Uint8Array(Buffer.from(e.publicKey,"base64")),privateKey:new Uint8Array(Buffer.from(e.privateKey,"base64"))}}catch{}const t=new Uint8Array(Buffer.from(r,"base64"));if(32===t.length)return{publicKey:derivePublicKey(t),privateKey:t};throw new Error(`Invalid key file format at ${e}`)}function generateAgentKeyPair(e){const r=crypto.generateKeyPairSync("ed25519",{publicKeyEncoding:{type:"spki",format:"der"},privateKeyEncoding:{type:"pkcs8",format:"der"}}),t=r.publicKey,n=r.privateKey,o=new Uint8Array(44===t.length?t.subarray(12):t),a=new Uint8Array(48===n.length?n.subarray(16):n),i=path.dirname(e);return fs.existsSync(i)||fs.mkdirSync(i,{recursive:!0}),fs.writeFileSync(e,JSON.stringify({publicKey:Buffer.from(o).toString("base64"),privateKey:Buffer.from(a).toString("base64")},null,2),{mode:384}),{publicKey:o,privateKey:a}}export function signAgentMessage(e,r){const t=crypto.createPrivateKey({key:wrapPrivateKey(r),format:"der",type:"pkcs8"});return new Uint8Array(crypto.sign(null,Buffer.from(e),t))}export function
|
|
1
|
+
import*as crypto from"node:crypto";import*as fs from"node:fs";import*as path from"node:path";export const EMPTY_BODY_SHA256="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";const ED25519_PKCS8_PREFIX=Buffer.from("302e020100300506032b657004220420","hex");function wrapPrivateKey(e){return 32===e.length?Buffer.concat([ED25519_PKCS8_PREFIX,Buffer.from(e)]):Buffer.from(e)}const ED25519_SPKI_PREFIX=Buffer.from("302a300506032b6570032100","hex");function derivePublicKey(e){const r=crypto.createPrivateKey({key:wrapPrivateKey(e),format:"der",type:"pkcs8"}),t=crypto.createPublicKey(r).export({type:"spki",format:"der"});return 44===t.length?new Uint8Array(t.subarray(12)):new Uint8Array(t)}export function loadAgentKeyPair(e){if(!fs.existsSync(e))return generateAgentKeyPair(e);const r=fs.readFileSync(e,"utf-8").trim();try{const e=JSON.parse(r);if(e.publicKey&&e.privateKey)return{publicKey:new Uint8Array(Buffer.from(e.publicKey,"base64")),privateKey:new Uint8Array(Buffer.from(e.privateKey,"base64"))}}catch{}const t=new Uint8Array(Buffer.from(r,"base64"));if(32===t.length)return{publicKey:derivePublicKey(t),privateKey:t};throw new Error(`Invalid key file format at ${e}`)}function generateAgentKeyPair(e){const r=crypto.generateKeyPairSync("ed25519",{publicKeyEncoding:{type:"spki",format:"der"},privateKeyEncoding:{type:"pkcs8",format:"der"}}),t=r.publicKey,n=r.privateKey,o=new Uint8Array(44===t.length?t.subarray(12):t),a=new Uint8Array(48===n.length?n.subarray(16):n),i=path.dirname(e);return fs.existsSync(i)||fs.mkdirSync(i,{recursive:!0}),fs.writeFileSync(e,JSON.stringify({publicKey:Buffer.from(o).toString("base64"),privateKey:Buffer.from(a).toString("base64")},null,2),{mode:384}),{publicKey:o,privateKey:a}}export function signAgentMessage(e,r){const t=crypto.createPrivateKey({key:wrapPrivateKey(r),format:"der",type:"pkcs8"});return new Uint8Array(crypto.sign(null,Buffer.from(e),t))}export function bodyHashHex(e){const r=null==e?Buffer.alloc(0):"string"==typeof e?Buffer.from(e,"utf8"):Buffer.from(e);return crypto.createHash("sha256").update(r).digest("hex")}export function agentAuthHeaders(e,r,t,n){const o=Math.floor(Date.now()/1e3).toString(),a=crypto.randomUUID(),i=bodyHashHex(n),f=signAgentMessage(`${e.toUpperCase()}|${r}||${i}|${o}|${a}`,t.privateKey);return{"X-Agent-Public-Key":Buffer.from(t.publicKey).toString("base64"),"X-Agent-Signature":Buffer.from(f).toString("base64"),"X-Agent-Timestamp":o,"X-Agent-Nonce":a}}export function agentBoundAuthHeaders(e,r,t,n){return agentAuthHeaders(e,r,n,t)}export async function agentFetch(e,r,t){const n="string"==typeof e?new URL(e):e,o=t?.method?.toUpperCase()??"GET",a=decodeURIComponent(n.pathname);let i;if(void 0!==t?.body&&null!==t.body){if(!("string"==typeof t.body||t.body instanceof Uint8Array))throw new Error("agent-authenticated request body must be string or Uint8Array for exact signing");i=t.body}const f=agentAuthHeaders(o,a,r,i),s=new Headers(t?.headers);for(const[e,r]of Object.entries(f))s.set(e,r);s.delete("X-Agent-Body-SHA256");const c=await fetch(n,{...t,method:o,headers:s,redirect:"error"});return assertFixedOrigin(n,c),c}export async function agentBoundFetch(e,r,t){if(""!==("string"==typeof e?new URL(e):e).search)throw new Error("body-bound agent authority routes forbid query parameters");return agentFetch(e,r,t)}function assertFixedOrigin(e,r){if(r.url&&new URL(r.url).origin!==e.origin)throw new Error("agent-authenticated response origin changed")}
|
|
@@ -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";import{maybeRenameImConversationTitle}from"./runtime/conversation-title.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},ABORT_TERMINAL_GRACE_MS=1e4,formatErrMessage=e=>{if(e instanceof Error)return e.message;if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}},failMessageStream=async(e,n)=>{void 0!==n.body&&e.setBody(n.body),await e.fail(void 0===n.stopReason?void 0:{stopReason:n.stopReason})};export const deterministicReplyMessageId=(e,n,t,a)=>`${e}_${createHash("sha256").update(`${n}:${t}:${a}`).digest("hex").slice(0,32)}`;export const dispatchImInboundPrompt=async e=>{const{runtime:n,prompt:t,client:a,logger:r,promptRunStore:i,sessionMutationCoordinator:s,abortTransport:o,activeRunAuthority:c}=e;if(!hasRuntimeReplyApi(n))return r.warn?.(`[im] runtime dispatch skipped reason=reply_api_unavailable channel=${t.channelId} in_reply_to=${t.inboundMessageId}`),e.onLifecycleEvent?.({type:"skipped",reason:"reply_api_unavailable",channelId:t.channelId,inboundMessageId:t.inboundMessageId}),!1;const d=`im_req_${randomUUID().replace(/-/g,"")}`,l=randomUUID(),u=Date.now(),m=e.origin??"im",p={protocol:"im",requestId:d,sessionId:t.sessionKey??"agent:main",sourceMessageId:t.inboundMessageId,chatId:t.channelId,origin:m},I=normalizePromptTimeoutMs(e.promptTimeoutMs),g=promptRunKey(t.channelId,t.inboundMessageId),h=t.sessionKey??"agent:main",y=new AbortController;let _,f,R;const E=new Promise((e,n)=>{R=n});let w;const b=()=>{void 0!==w&&(clearTimeout(w),w=void 0)},M=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||R(new Error(SESSION_RECOVERY_REQUIRED_CODE))}):R(new Error(SESSION_RECOVERY_REQUIRED_CODE)),{ok:n.ok}};if(!i.register(g,{requestId:d,channelId:t.channelId,requestCancel:M,startedAt:u,sessionKey:h}))return r.warn?.(`[im] runtime dispatch rejected duplicate inboundMessageId=${t.inboundMessageId} requestId=${d} channel=${t.channelId}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,error:"duplicate_inbound_message_id",cause:"abort"}),!1;const $=deterministicReplyMessageId("asst",t.channelId,t.inboundMessageId,t.selfPrincipalId),S=a.messages.startStream({conversationId:t.channelId,clientMessageId:$,idempotencyKey:$,replyTo:e.inReplyTo??t.inboundMessageId,type:"agent_reply",content:{}});let v,q=!1;try{q="duplicate"===(await S.opened()).outcome}catch(n){let s="unconfirmed";try{s=(await a.messages.getEnvelope(t.channelId,$)).state}catch{}return r.warn?.(`[im] runtime reply stream open outcome unknown requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} reply_id=${$} reconciled_state=${s}: ${formatErrMessage(n)}; runtime_not_invoked`),e.onLifecycleEvent?.({type:"skipped",reason:"reply_open_outcome_unknown",channelId:t.channelId,inboundMessageId:t.inboundMessageId}),i.unregister(g),!1}if(q)return r.info?.(`[im] runtime dispatch skipped existing deterministic reply requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId}`),e.onLifecycleEvent?.({type:"skipped",reason:"idempotent_reply_exists",channelId:t.channelId,inboundMessageId:t.inboundMessageId}),i.unregister(g),!1;const k=new SerializedCallbackQueue,C=createImReplySink({stream:S,openReasoningStream:()=>{const n=deterministicReplyMessageId("rsn",t.channelId,t.inboundMessageId,t.selfPrincipalId);return v=a.messages.startStream({conversationId:t.channelId,clientMessageId:n,idempotencyKey:n,replyTo:e.inReplyTo??t.inboundMessageId,type:"agent_reasoning",content:{}}),v},abortSignal:y.signal,callbackQueue:k,logger:r,requestId:d,runId:l,channelId:t.channelId,inboundMessageId:t.inboundMessageId,origin:m,onAgentRunStart:e=>{s.bindRun(_,e)}}),O=interceptAgentRuntimeFailures(C,"im_runtime",e=>r.warn?.(`[im] runtime failure reply suppressed requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} error_code=${e.errorCode}`)),T=O.sink,A=async(e,n)=>{if(!v)return!1;try{return"cancel"===e?await v.cancel({stopReason:"user_stop"}):"fail"===e?await v.fail(n?{stopReason:n}:void 0):await v.finalize({stopReason:"end_turn"}),!1}catch(e){return r.warn?.(`[im] runtime reasoning stream terminal write failed requestId=${d} channel=${t.channelId}: ${formatErrMessage(e)}`),!0}};let D,U,K=!1;const N=async e=>{T.dispatcher.markComplete(e);try{await T.dispatcher.waitForIdle()}catch{}},F=()=>{b();const n=normalizePromptTimeoutMs(e.abortTerminalGraceMs)??1e4;w=setTimeout(()=>{w=void 0,(async()=>{if(S.isTerminated)return;const e=y.signal.reason??f,n=void 0!==U,a=!n&&"string"==typeof e&&e.startsWith("chat_cancel");if(await N("failure"),!S.isTerminated)try{a?(await A("cancel"),await S.cancel({stopReason:"user_stop"})):n?(await A("fail","timeout"),await failMessageStream(S,{body:U?.message??"IM runtime dispatch timed out",stopReason:"timeout"})):(await A("fail"),await failMessageStream(S,{body:SESSION_RECOVERY_REQUIRED_MESSAGE,stopReason:"error"})),r.warn?.(`[im] abort settlement watchdog terminalized reply requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} user_cancel=${a} timeout=${n}`)}catch(e){r.warn?.(`[im] abort settlement watchdog terminal write failed requestId=${d} channel=${t.channelId}: ${formatErrMessage(e)}`)}})()},n)};y.signal.aborted?F():y.signal.addEventListener("abort",F,{once:!0});const L=()=>{if(!y.signal.aborted)return;const e=y.signal.reason;throw e instanceof Error?e:new Error(String(e??"runtime dispatch aborted"))};let Q,P,Y;const G=async e=>{if(!_)throw new Error("session_mutation_not_acquired");const n=await s.converge(_,e);return n.ok?(Q=n.permit,!0):(r.error?.(`[im] session mutation recovery required requestId=${d} sessionKey=${h} reason=${n.recovery.reason}`),P={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{L();const o=s.tryStartInteractive({sessionKey:h,label:"im_chat_message"},"message_service");if(!o.ok){try{await failMessageStream(S,{body:SESSION_BUSY_PUBLIC_MESSAGE,stopReason:"error"})}catch(e){r.warn?.(`[im] session busy terminal write failed channel=${t.channelId} in_reply_to=${t.inboundMessageId}: ${formatErrMessage(e)}`)}return r.warn?.(`[im] session write gate busy sessionKey=${h} channel=${t.channelId} in_reply_to=${t.inboundMessageId} active_operation=${o.activeOperationId??"unknown"}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,error:"session_busy",cause:"runtime_error"}),!1}if(_=o.token,s.bindRun(_,l),c){const e=s.snapshot(h);Y={runtimeConversationUid:t.channelId,runtimeSessionKey:t.channelId,historyGeneration:c.historyGeneration(t.channelId),targetMessageId:t.inboundMessageId,runtimeRunId:l,activeRunRegistrationId:`im:${e?.operationId??l}`},c.activeRuns.register(Y,async()=>{const e=`chat_cancel:activeRun:${Y.activeRunRegistrationId}`,n=await i.abort(g,e);return n.ok||"already_aborted"===n.reason?"accepted":"terminal_committing"===n.reason||"not_found"===n.reason?"already_terminal":"recovery_required"})}L(),r.info?.(`[im] runtime dispatching requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} origin=${m}`),e.onLifecycleEvent?.({type:"dispatch_start",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId});const y=dispatchRuntimeReplyWithRoute({runtime:n,pluginConfig:e.pluginConfig,preparedPrompt:t.dispatchInput,replyRoute:p,replySinks:{im:T},onDispatchInvoked:()=>{K=!0}});void 0!==I&&(D=setTimeout(()=>{U=new Error(`IM runtime dispatch timed out after ${I}ms`),r.warn?.(`[im] runtime dispatch timeout requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} timeout_ms=${I}`),M(U)},I));const f=Promise.race([y,E]),R=await f.finally(()=>{D&&(clearTimeout(D),D=void 0)}),w=O.detectedFailure();if(w)throw new Error(w.diagnosticMessage);if(L(),await N("success"),L(),!i.claimTerminal(g,"completion")){if(L(),"cancelling"===i.phase(g))throw new Error("cancellation in progress");throw new Error("terminal outcome already claimed")}if(!await G("completed"))return await A("fail"),await failMessageStream(S,{body:SESSION_RECOVERY_REQUIRED_MESSAGE,stopReason:"error"}).catch(()=>{}),e.onLifecycleEvent?.({type:"dispatch_error",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,error:SESSION_RECOVERY_REQUIRED_CODE,cause:"runtime_error",...P?{recovery:P}:{}}),!1;const b=await A("complete");let $=!1;try{await S.finalize({stopReason:"end_turn"})}catch(e){$=!0,r.warn?.(`[im] runtime reply stream finalize outcome unknown requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId}: ${formatErrMessage(e)}`)}c&&Y&&c.activeRuns.markTerminal(Y,"completed"),r.info?.(`[im] runtime dispatch completed requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} counts=${JSON.stringify(R.counts)} elapsed_ms=${Date.now()-u}`),e.onLifecycleEvent?.({type:"dispatch_complete",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,counts:R.counts,...$?{terminalWriteFailed:!0}:{},...b?{reasoningTerminalWriteFailed:!0}:{}});const v="string"==typeof t.dispatchInput.message?t.dispatchInput.message:"",q=T.dispatcher.getAccumulatedBody?.()??"";return maybeRenameImConversationTitle({client:a,conversationId:t.channelId,question:v,answer:q,logger:r}),!0}catch(n){await N("failure");const a=y.signal.aborted,s=a?y.signal.reason:void 0,o="cancelling"===i.phase(g),l=void 0!==U,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(g,I)){if(r.warn?.(`[im] terminal claim raced requestId=${d} channel=${t.channelId}; best-effort envelope terminal if still streaming`),!S.isTerminated)try{m?(await A("cancel"),await S.cancel({stopReason:"user_stop"})):l?(await A("fail","timeout"),await failMessageStream(S,{body:U?.message??formatErrMessage(n),stopReason:"timeout"})):(await A("fail"),await failMessageStream(S,{body:formatErrMessage(n),stopReason:"error"}))}catch(e){r.warn?.(`[im] raced terminal write failed requestId=${d}: ${formatErrMessage(e)}`)}throw n}const h=m?"cancelled":l?"timeout":"error";if(c&&Y&&c.activeRuns.markTerminal(Y,"cancelled"===h?"cancelled":"failed"),_&&!await G(h))throw m?(await A("cancel"),await S.cancel({stopReason:"user_stop"}).catch(()=>{})):(await A("fail"),await failMessageStream(S,{body:SESSION_RECOVERY_REQUIRED_MESSAGE,stopReason:"error"}).catch(()=>{})),e.onLifecycleEvent?.({type:"dispatch_error",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,error:SESSION_RECOVERY_REQUIRED_CODE,cause:p,...P?{recovery:P}:{}}),n;const R=classifyAgentRuntimeFailure({raw:n,source:"im_runtime",runtimeKind:"openclaw",requestAborted:m}),E=m?R:O.detectedFailure()??R;m?await A("cancel"):l?await A("fail","timeout"):await A("fail");try{m?await S.cancel({stopReason:"user_stop"}):await failMessageStream(S,{body:E.publicMessage,stopReason:messageStopReasonForRuntimeFailure(E)})}catch(e){r.warn?.(`[im] runtime stream terminal write failed requestId=${d} channel=${t.channelId}: ${formatErrMessage(e)}`)}throw r.warn?.(`[im] runtime dispatch failed requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} cause=${p} dispatchInvoked=${K} error_code=${E.errorCode}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,error:E.errorCode,cause:p}),n}finally{b(),i.unregister(g),K?Q&&s.release(Q):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";import{maybeRenameImConversationTitle}from"./runtime/conversation-title.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},ABORT_TERMINAL_GRACE_MS=1e4,formatErrMessage=e=>{if(e instanceof Error)return e.message;if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}},failMessageStream=async(e,n)=>{void 0!==n.body&&e.setBody(n.body),await e.fail(void 0===n.stopReason?void 0:{stopReason:n.stopReason})};export const deterministicReplyMessageId=(e,n,t,a)=>`${e}_${createHash("sha256").update(`${n}:${t}:${a}`).digest("hex").slice(0,32)}`;export const dispatchImInboundPrompt=async e=>{const{runtime:n,prompt:t,client:a,logger:r,promptRunStore:i,sessionMutationCoordinator:s,abortTransport:o,activeRunAuthority:c}=e;if(!hasRuntimeReplyApi(n))return r.warn?.(`[im] runtime dispatch skipped reason=reply_api_unavailable channel=${t.channelId} in_reply_to=${t.inboundMessageId}`),e.onLifecycleEvent?.({type:"skipped",reason:"reply_api_unavailable",channelId:t.channelId,inboundMessageId:t.inboundMessageId}),!1;const d=`im_req_${randomUUID().replace(/-/g,"")}`,l=randomUUID(),u=Date.now(),m=e.origin??"im",p={protocol:"im",requestId:d,sessionId:t.sessionKey??"agent:main",sourceMessageId:t.inboundMessageId,chatId:t.channelId,origin:m},I=normalizePromptTimeoutMs(e.promptTimeoutMs),g=promptRunKey(t.channelId,t.inboundMessageId),h=t.sessionKey??"agent:main",y=new AbortController;let _,f,R;const w=new Promise((e,n)=>{R=n});let E;const b=()=>{void 0!==E&&(clearTimeout(E),E=void 0)},M=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||R(new Error(SESSION_RECOVERY_REQUIRED_CODE))}):R(new Error(SESSION_RECOVERY_REQUIRED_CODE)),{ok:n.ok}};if(!i.register(g,{requestId:d,channelId:t.channelId,requestCancel:M,startedAt:u,sessionKey:h}))return r.warn?.(`[im] runtime dispatch rejected duplicate inboundMessageId=${t.inboundMessageId} requestId=${d} channel=${t.channelId}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,error:"duplicate_inbound_message_id",cause:"abort"}),!1;const $=deterministicReplyMessageId("asst",t.channelId,t.inboundMessageId,t.selfPrincipalId),S=a.messages.startStream({conversationId:t.channelId,clientMessageId:$,idempotencyKey:$,replyTo:e.inReplyTo??t.inboundMessageId,type:"agent_reply",content:{}});let v,q=!1;try{q="duplicate"===(await S.opened()).outcome}catch(n){let s="unconfirmed";try{s=(await a.messages.getEnvelope(t.channelId,$)).state}catch{}return r.warn?.(`[im] runtime reply stream open outcome unknown requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} reply_id=${$} reconciled_state=${s}: ${formatErrMessage(n)}; runtime_not_invoked`),e.onLifecycleEvent?.({type:"skipped",reason:"reply_open_outcome_unknown",channelId:t.channelId,inboundMessageId:t.inboundMessageId}),i.unregister(g),!1}if(q)return r.info?.(`[im] runtime dispatch skipped existing deterministic reply requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId}`),e.onLifecycleEvent?.({type:"skipped",reason:"idempotent_reply_exists",channelId:t.channelId,inboundMessageId:t.inboundMessageId}),i.unregister(g),!1;const k=new SerializedCallbackQueue,C=createImReplySink({stream:S,openReasoningStream:()=>{const n=deterministicReplyMessageId("rsn",t.channelId,t.inboundMessageId,t.selfPrincipalId);return v=a.messages.startStream({conversationId:t.channelId,clientMessageId:n,idempotencyKey:n,replyTo:e.inReplyTo??t.inboundMessageId,type:"agent_reasoning",content:{}}),v},abortSignal:y.signal,callbackQueue:k,logger:r,requestId:d,runId:l,channelId:t.channelId,inboundMessageId:t.inboundMessageId,origin:m,onAgentRunStart:e=>{s.bindRun(_,e)}}),O=interceptAgentRuntimeFailures(C,"im_runtime",e=>r.warn?.(`[im] runtime failure reply suppressed requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} error_code=${e.errorCode}`)),T=O.sink,A=async(e,n)=>{if(!v)return!1;try{return"cancel"===e?await v.cancel({stopReason:"user_stop"}):"fail"===e?await v.fail(n?{stopReason:n}:void 0):await v.finalize({stopReason:"end_turn"}),!1}catch(e){return r.warn?.(`[im] runtime reasoning stream terminal write failed requestId=${d} channel=${t.channelId}: ${formatErrMessage(e)}`),!0}};let D,U,K=!1;const N=async e=>{T.dispatcher.markComplete(e);try{await T.dispatcher.waitForIdle()}catch{}},F=()=>{b();const n=normalizePromptTimeoutMs(e.abortTerminalGraceMs)??1e4;E=setTimeout(()=>{E=void 0,(async()=>{if(S.isTerminated)return;const e=y.signal.reason??f,n=void 0!==U,a=!n&&"string"==typeof e&&e.startsWith("chat_cancel");if(await N("failure"),!S.isTerminated)try{a?(await A("cancel"),await S.cancel({stopReason:"user_stop"})):n?(await A("fail","timeout"),await failMessageStream(S,{body:U?.message??"IM runtime dispatch timed out",stopReason:"timeout"})):(await A("fail"),await failMessageStream(S,{body:SESSION_RECOVERY_REQUIRED_MESSAGE,stopReason:"error"})),r.warn?.(`[im] abort settlement watchdog terminalized reply requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} user_cancel=${a} timeout=${n}`)}catch(e){r.warn?.(`[im] abort settlement watchdog terminal write failed requestId=${d} channel=${t.channelId}: ${formatErrMessage(e)}`)}})()},n)};y.signal.aborted?F():y.signal.addEventListener("abort",F,{once:!0});const L=()=>{if(!y.signal.aborted)return;const e=y.signal.reason;throw e instanceof Error?e:new Error(String(e??"runtime dispatch aborted"))};let Q,P,Y;const G=async e=>{if(!_)throw new Error("session_mutation_not_acquired");const n=await s.converge(_,e);return n.ok?(Q=n.permit,!0):(r.error?.(`[im] session mutation recovery required requestId=${d} sessionKey=${h} reason=${n.recovery.reason}`),P={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{L();const o=s.tryStartInteractive({sessionKey:h,label:"im_chat_message"},"message_service");if(!o.ok){try{await failMessageStream(S,{body:SESSION_BUSY_PUBLIC_MESSAGE,stopReason:"error"})}catch(e){r.warn?.(`[im] session busy terminal write failed channel=${t.channelId} in_reply_to=${t.inboundMessageId}: ${formatErrMessage(e)}`)}return r.warn?.(`[im] session write gate busy sessionKey=${h} channel=${t.channelId} in_reply_to=${t.inboundMessageId} active_operation=${o.activeOperationId??"unknown"}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,error:"session_busy",cause:"runtime_error"}),!1}if(_=o.token,s.bindRun(_,l),c){const e=s.snapshot(h);Y={runtimeConversationUid:t.channelId,runtimeSessionKey:t.channelId,historyGeneration:c.historyGeneration(t.channelId),targetMessageId:t.inboundMessageId,runtimeRunId:l,activeRunRegistrationId:`im:${e?.operationId??l}`},c.activeRuns.register(Y,async()=>{const e=`chat_cancel:activeRun:${Y.activeRunRegistrationId}`,n=await i.abort(g,e);return n.ok||"already_aborted"===n.reason?"accepted":"terminal_committing"===n.reason||"not_found"===n.reason?"already_terminal":"recovery_required"})}L(),r.info?.(`[im] runtime dispatching requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} origin=${m}`),e.onLifecycleEvent?.({type:"dispatch_start",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId});const y=dispatchRuntimeReplyWithRoute({runtime:n,pluginConfig:e.pluginConfig,preparedPrompt:t.dispatchInput,replyRoute:p,replySinks:{im:T},onDispatchInvoked:()=>{K=!0}});void 0!==I&&(D=setTimeout(()=>{U=new Error(`IM runtime dispatch timed out after ${I}ms`),r.warn?.(`[im] runtime dispatch timeout requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} timeout_ms=${I}`),M(U)},I));const f=Promise.race([y,w]),R=await f.finally(()=>{D&&(clearTimeout(D),D=void 0)}),E=O.detectedFailure();if(E)throw new Error(E.diagnosticMessage);if(L(),await N("success"),L(),!i.claimTerminal(g,"completion")){if(L(),"cancelling"===i.phase(g))throw new Error("cancellation in progress");throw new Error("terminal outcome already claimed")}if(!await G("completed"))return await A("fail"),await failMessageStream(S,{body:SESSION_RECOVERY_REQUIRED_MESSAGE,stopReason:"error"}).catch(()=>{}),e.onLifecycleEvent?.({type:"dispatch_error",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,error:SESSION_RECOVERY_REQUIRED_CODE,cause:"runtime_error",...P?{recovery:P}:{}}),!1;const b=T.dispatcher.getTerminalErrorText?.();if(void 0!==b){await A("fail");let n=!1;try{await failMessageStream(S,{body:b,stopReason:"error"})}catch(e){n=!0,r.warn?.(`[im] runtime reply stream error-terminal write outcome unknown requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId}: ${formatErrMessage(e)}`)}return c&&Y&&c.activeRuns.markTerminal(Y,"failed"),r.warn?.(`[im] runtime dispatch ended with an error terminal requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} counts=${JSON.stringify(R.counts)} terminalWriteFailed=${n} elapsed_ms=${Date.now()-u}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,error:"runtime_error_terminal_reply",cause:"runtime_error"}),!1}const $=await A("complete");let v=!1;try{await S.finalize({stopReason:"end_turn"})}catch(e){v=!0,r.warn?.(`[im] runtime reply stream finalize outcome unknown requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId}: ${formatErrMessage(e)}`)}c&&Y&&c.activeRuns.markTerminal(Y,"completed"),r.info?.(`[im] runtime dispatch completed requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} counts=${JSON.stringify(R.counts)} elapsed_ms=${Date.now()-u}`),e.onLifecycleEvent?.({type:"dispatch_complete",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,counts:R.counts,...v?{terminalWriteFailed:!0}:{},...$?{reasoningTerminalWriteFailed:!0}:{}});const q="string"==typeof t.dispatchInput.message?t.dispatchInput.message:"",k=T.dispatcher.getAccumulatedBody?.()??"";return maybeRenameImConversationTitle({client:a,conversationId:t.channelId,question:q,answer:k,logger:r}),!0}catch(n){await N("failure");const a=y.signal.aborted,s=a?y.signal.reason:void 0,o="cancelling"===i.phase(g),l=void 0!==U,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(g,I)){if(r.warn?.(`[im] terminal claim raced requestId=${d} channel=${t.channelId}; best-effort envelope terminal if still streaming`),!S.isTerminated)try{m?(await A("cancel"),await S.cancel({stopReason:"user_stop"})):l?(await A("fail","timeout"),await failMessageStream(S,{body:U?.message??formatErrMessage(n),stopReason:"timeout"})):(await A("fail"),await failMessageStream(S,{body:formatErrMessage(n),stopReason:"error"}))}catch(e){r.warn?.(`[im] raced terminal write failed requestId=${d}: ${formatErrMessage(e)}`)}throw n}const h=m?"cancelled":l?"timeout":"error";if(c&&Y&&c.activeRuns.markTerminal(Y,"cancelled"===h?"cancelled":"failed"),_&&!await G(h))throw m?(await A("cancel"),await S.cancel({stopReason:"user_stop"}).catch(()=>{})):(await A("fail"),await failMessageStream(S,{body:SESSION_RECOVERY_REQUIRED_MESSAGE,stopReason:"error"}).catch(()=>{})),e.onLifecycleEvent?.({type:"dispatch_error",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,error:SESSION_RECOVERY_REQUIRED_CODE,cause:p,...P?{recovery:P}:{}}),n;const R=classifyAgentRuntimeFailure({raw:n,source:"im_runtime",runtimeKind:"openclaw",requestAborted:m}),w=m?R:O.detectedFailure()??R;m?await A("cancel"):l?await A("fail","timeout"):await A("fail");try{m?await S.cancel({stopReason:"user_stop"}):await failMessageStream(S,{body:w.publicMessage,stopReason:messageStopReasonForRuntimeFailure(w)})}catch(e){r.warn?.(`[im] runtime stream terminal write failed requestId=${d} channel=${t.channelId}: ${formatErrMessage(e)}`)}throw r.warn?.(`[im] runtime dispatch failed requestId=${d} channel=${t.channelId} in_reply_to=${t.inboundMessageId} cause=${p} dispatchInvoked=${K} error_code=${w.errorCode}`),e.onLifecycleEvent?.({type:"dispatch_error",requestId:d,channelId:t.channelId,inboundMessageId:t.inboundMessageId,error:w.errorCode,cause:p}),n}finally{b(),i.unregister(g),K?Q&&s.release(Q):s.releaseBeforeRuntime(_)}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{toMessagePart}from"../message-client-types.js";import{resolveRuntimeToolArguments,resolveRuntimeToolCallId,resolveRuntimeToolName}from"./tool-envelope-metadata.js";const isNonEmptyString=e=>"string"==typeof e&&e.length>0,extractBodyUpdate=(e,t)=>{if(!isNonEmptyString(t))return{kind:"noop"};if(t===e.text)return{kind:"noop"};if(t.startsWith(e.text)){const n=t.slice(e.text.length);return e.text=t,{kind:"append",text:n}}return e.text.startsWith(t)?{kind:"noop"}:(e.text=t,{kind:"replace",text:t})};export function createImReplySink(e){const t={text:""};let n,r="",o="";const s=new Map,i=new Map,a=[],l=[];let d=0,u=0;const g=(t,n,r)=>{const o=u;return e.stream.appendToolUse(t,n,toMessagePart(r),"streaming"),u+=1,o},m=()=>(d+=1,`tool_${e.requestId}_${d}`),c=e=>{const t=a.indexOf(e);t>=0&&a.splice(t,1)},p=e=>{const t=e?a.filter(t=>s.get(t)?.name===e):a;return 1===t.length?t[0]:void 0},f=e=>{const t=l.map((e,t)=>({hint:e,index:t})).filter(({hint:t})=>!e||t.name===e);if(1!==t.length)return;const[{hint:n,index:r}]=t;return l.splice(r,1),n},h=(e,t)=>{i.set(e,t)},I=e=>i.get(e)??e,y=e=>null!=e&&("object"!=typeof e||(Array.isArray(e)?e.length>0:Object.keys(e).length>0)),v=(t,n,r,o)=>{const i=s.get(t);if(i){const s="tool"===i.name&&"tool"!==n?n:i.name,l=!y(i.arguments)&&y(r)?r:i.arguments;return s===i.name&&l===i.arguments||(e.stream.replacePart(i.partIndex,toMessagePart({type:"tool_use",id:i.id,name:s,arguments:l,state:i.state})),i.name=s,i.arguments=l),o&&!a.includes(t)&&"streaming"===i.state&&a.push(t),i}const l={id:t,name:n,arguments:r,partIndex:g(t,n,r),state:"streaming",itemEventObserved:!1,toolStartObserved:!1};return s.set(t,l),o&&a.push(t),l}
|
|
1
|
+
import{toMessagePart}from"../message-client-types.js";import{resolveRuntimeToolArguments,resolveRuntimeToolCallId,resolveRuntimeToolName}from"./tool-envelope-metadata.js";const isNonEmptyString=e=>"string"==typeof e&&e.length>0,extractBodyUpdate=(e,t)=>{if(!isNonEmptyString(t))return{kind:"noop"};if(t===e.text)return{kind:"noop"};if(t.startsWith(e.text)){const n=t.slice(e.text.length);return e.text=t,{kind:"append",text:n}}return e.text.startsWith(t)?{kind:"noop"}:(e.text=t,{kind:"replace",text:t})};export function createImReplySink(e){const t={text:""};let n,r="",o="";const s=new Map,i=new Map,a=[],l=[];let d=0,u=0;const g=(t,n,r)=>{const o=u;return e.stream.appendToolUse(t,n,toMessagePart(r),"streaming"),u+=1,o},m=()=>(d+=1,`tool_${e.requestId}_${d}`),c=e=>{const t=a.indexOf(e);t>=0&&a.splice(t,1)},p=e=>{const t=e?a.filter(t=>s.get(t)?.name===e):a;return 1===t.length?t[0]:void 0},f=e=>{const t=l.map((e,t)=>({hint:e,index:t})).filter(({hint:t})=>!e||t.name===e);if(1!==t.length)return;const[{hint:n,index:r}]=t;return l.splice(r,1),n},h=(e,t)=>{i.set(e,t)},I=e=>i.get(e)??e,y=e=>null!=e&&("object"!=typeof e||(Array.isArray(e)?e.length>0:Object.keys(e).length>0)),v=(t,n,r,o)=>{const i=s.get(t);if(i){const s="tool"===i.name&&"tool"!==n?n:i.name,l=!y(i.arguments)&&y(r)?r:i.arguments;return s===i.name&&l===i.arguments||(e.stream.replacePart(i.partIndex,toMessagePart({type:"tool_use",id:i.id,name:s,arguments:l,state:i.state})),i.name=s,i.arguments=l),o&&!a.includes(t)&&"streaming"===i.state&&a.push(t),i}const l={id:t,name:n,arguments:r,partIndex:g(t,n,r),state:"streaming",itemEventObserved:!1,toolStartObserved:!1};return s.set(t,l),o&&a.push(t),l},x=t=>{"done"!==t.state&&(e.stream.replacePart(t.partIndex,toMessagePart({type:"tool_use",id:t.id,name:t.name,arguments:t.arguments,state:"done"})),t.state="done")},$=e=>{if(null===e||"object"!=typeof e)return JSON.stringify(e)??String(e);if(Array.isArray(e))return`[${e.map($).join(",")}]`;return`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${$(t)}`).join(",")}}`},b=(e,t,n)=>{const r=i.get(e);if(r)return v(r,t??"tool",n??{},!1);if(s.has(e))return v(e,t??"tool",n??{},!1);const o=p(t);return o?(h(e,o),v(o,t??"tool",n??{},!1)):v(e,t??"tool",n??{},!1)},_=(e,t)=>{const n=i.get(e);if(n)return v(n,t,{},!1);if(s.has(e))return v(e,t,{},!1);const r=(e=>{const t=a.filter(t=>{const n=s.get(t);return!(void 0===n||e&&n.name!==e||n.itemEventObserved)});return 1===t.length?t[0]:void 0})(t);if(r)return h(e,r),v(r,t,{},!1);const o=f(t);return v(e,t,o?.arguments??{},!1)},k={tool:0,block:0,final:0};let S,R=!1;const E=(t,n)=>{e.callbackQueue.enqueueSync(()=>{if((t=>e.abortSignal.aborted?(e.logger.debug?.(`[im-sink] ${t} ignored after abort requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`),!1):e.stream.isTerminated?(e.logger.debug?.(`[im-sink] ${t} ignored after stream_terminated requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`),!1):!R||(e.logger.debug?.(`[im-sink] ${t} ignored after mark_complete requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`),!1))(t))try{n()}catch(n){const r=n instanceof Error?n.message:String(n);e.logger.warn?.(`[im-sink] ${t} mapping failed requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId} error=${r}`)}})};return{dispatcher:{sendToolResult:t=>(E("tool_progress",()=>{const n=resolveRuntimeToolCallId(t),r=resolveRuntimeToolName(t),o=n?void 0:r?p(r):p(),i=n||o?void 0:f(r);if(!n&&!o&&!i)return void e.logger.debug?.(`[im-sink] ambiguous id-less tool progress ignored requestId=${e.requestId} channel=${e.channelId} tool=${r??"unknown"} pending=${a.length}`);const l=n?b(n,r,resolveRuntimeToolArguments(t)):v(o??m(),r??s.get(o??"")?.name??i.name,y(resolveRuntimeToolArguments(t))?resolveRuntimeToolArguments(t):i?.arguments??{},!1);k.tool+=1,((t,n,r)=>{const o=`${r?"1":"0"}:${$(n)}`;if(t.progressSignature===o)return;const s=toMessagePart({type:"custom",kind:"tool_progress",data:{tool_use_id:t.id,content:n,...r?{is_error:!0}:{}}});if(void 0===t.progressPartIndex){const n=u;return e.stream.addPart(s),t.progressPartIndex=n,t.progressSignature=o,void(u+=1)}e.stream.replacePart(t.progressPartIndex,s),t.progressSignature=o})(l,(e=>{const t=[e.mediaUrl,...e.mediaUrls??[]].filter(e=>isNonEmptyString(e));return isNonEmptyString(e.text)&&t.length>0?{text:e.text,media_urls:t}:isNonEmptyString(e.text)?e.text:1===t.length?t[0]:t.length>1?{media_urls:t}:!0===e.isError?"Tool execution failed.":""})(t),!0===t.isError),x(l),c(l.id)}),!0),sendBlockReply:n=>(E("block_reply",()=>{k.block+=1,isNonEmptyString(n.text)&&(!0!==n.isError?(S=void 0,e.stream.setBody(n.text),t.text=n.text):S=n.text)}),!0),sendFinalReply:n=>(E("final_reply",()=>{k.final+=1,isNonEmptyString(n.text)&&(!0!==n.isError?(S=void 0,e.stream.setBody(n.text),t.text=n.text):S=n.text)}),!0),waitForIdle:()=>e.callbackQueue.waitForIdle(),getQueuedCounts:()=>({...k}),getAccumulatedBody:()=>t.text,getTerminalErrorText:()=>S,markComplete:t=>{if(1===l.length){const e=l.shift();v(m(),e.name,e.arguments,!1)}for(const n of s.values())try{"success"===t&&x(n),c(n.id)}catch(t){const r=t instanceof Error?t.message:String(t);e.logger.warn?.(`[im-sink] tool finalization failed requestId=${e.requestId} toolUseId=${n.id} error=${r}`)}l.length=0,R=!0}},replyOptions:{...e.runId?{runId:e.runId}:{},abortSignal:e.abortSignal,onAgentRunStart:t=>{e.onAgentRunStart?.(t),e.logger.info?.(`[im-sink] run_start requestId=${e.requestId} runId=${t} channel=${e.channelId} in_reply_to=${e.inboundMessageId} origin=${e.origin??"im"}`)},onPartialReply:n=>{E("partial",()=>{const r=extractBodyUpdate(t,n.text);switch(r.kind){case"append":e.stream.appendBody(r.text);break;case"replace":e.stream.setBody(r.text)}})},onReasoningStream:t=>{E("reasoning",()=>{if(!isNonEmptyString(t.text))return;if(!n&&(n=e.openReasoningStream?.(),!n))return;const s=t.text;""===o&&""!==r&&(n.appendBody("\n"),r+="\n"),s!==o&&(s.startsWith(o)?(n.appendBody(s.slice(o.length)),o=s):o.startsWith(s)||(n.setBody(r+s),o=s))})},onReasoningEnd:()=>{E("reasoning_end",()=>{var t;""!==o&&(t=o,e.stream.appendThinking(t,"done"),u+=1,r+=o,o="")})},onAssistantMessageStart:()=>{e.logger.debug?.(`[im-sink] assistant_message_start requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`)},onToolStart:t=>{E("tool_start",()=>{const n="string"==typeof t.phase?t.phase:"start",r=resolveRuntimeToolName(t)??"tool",o=resolveRuntimeToolCallId(t);if("update"===n){if(o){const e=I(o);s.has(e)&&v(e,r,resolveRuntimeToolArguments(t),!0)}return}const i=resolveRuntimeToolArguments(t);if(o){const e=b(o,r,i);return e.toolStartObserved=!0,void(a.includes(e.id)||"streaming"!==e.state||a.push(e.id))}const d=(u=r,a.map(e=>s.get(e)).filter(e=>void 0!==e&&(!u||e.name===u)&&e.itemEventObserved));var u;if(1===d.length){return void(v(d[0].id,r,i,!0).toolStartObserved=!0)}d.length>1?e.logger.debug?.(`[im-sink] ambiguous id-less tool start ignored requestId=${e.requestId} channel=${e.channelId} tool=${r} candidates=${d.length}`):l.push({name:r,arguments:i})})},onItemEvent:e=>{E("item_event",()=>{const t="string"==typeof e.kind?e.kind.toLowerCase():"";if(t&&"tool"!==t)return;const n="string"==typeof e.phase?e.phase.toLowerCase():"update",r=resolveRuntimeToolCallId(e)??("string"==typeof e.itemId&&e.itemId.trim()?e.itemId.trim():void 0),o=resolveRuntimeToolName(e)??("string"==typeof e.title&&e.title.trim()?e.title.trim():void 0);if(!r||!o)return;if("update"===n){const e=I(r),t=s.get(e);return void(t&&(v(t.id,o,{},!0).itemEventObserved=!0))}const i=_(r,o);i.itemEventObserved=!0,a.includes(i.id)||"streaming"!==i.state||a.push(i.id)})}}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "beeos-claw",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.35-staging.0",
|
|
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>",
|