beeos-claw 0.6.23 → 0.6.24

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{deterministicReplyMessageId}from"./im-runtime-dispatch.js";export class MessageProjectionInboundConsumer{delivered=new Set;cancelledTargets=new Set;inFlightMessages=new Set;inFlightCancels=new Set;client;bindings;logger;executionJournal;maxConcurrentConversations;conversationQueue=[];queuedConversations=new Set;activeConversations=new Set;rerunConversations=new Set;laneTasks=new Set;cancelTasks=new Set;unsubscribe;activeConversationCount=0;started=!1;constructor(e){this.client=e.client,this.bindings=e.bindings,this.logger=e.logger,this.executionJournal=e.executionJournal,this.maxConcurrentConversations=Math.max(1,Math.floor(e.maxConcurrentConversations??16))}start(){this.started||(this.started=!0,this.unsubscribe=this.client.subscribe(()=>this.schedule()),this.schedule())}async stop(){this.started=!1,this.unsubscribe?.(),this.unsubscribe=void 0,this.conversationQueue.length=0,this.queuedConversations.clear(),this.rerunConversations.clear(),await Promise.allSettled([...this.laneTasks,...this.cancelTasks])}refresh(){this.schedule()}schedule(){if(!this.started)return;const e=Object.values(this.client.getSnapshot().messages).filter(isInbound).sort(compareProjectionOrder);for(const n of e)"chat_cancel"===n.type&&this.dispatchCancel(n,e);for(const n of new Set(e.filter(e=>"chat_message"===e.type).map(e=>e.conversationId)))this.enqueueConversation(n);this.pumpConversationQueue()}enqueueConversation(e){this.activeConversations.has(e)?this.rerunConversations.add(e):this.queuedConversations.has(e)||(this.queuedConversations.add(e),this.conversationQueue.push(e))}pumpConversationQueue(){for(;this.started&&this.activeConversationCount<this.maxConcurrentConversations&&this.conversationQueue.length>0;){const e=this.conversationQueue.shift();this.queuedConversations.delete(e),this.activeConversations.add(e),this.activeConversationCount+=1;const n=this.drainConversation(e).catch(n=>{this.logger.warn?.(`[beeos-claw] projected inbound lane failed conversation=${e}: ${n instanceof Error?n.message:String(n)}`)}).finally(()=>{this.laneTasks.delete(n),this.activeConversations.delete(e),this.activeConversationCount-=1,this.rerunConversations.delete(e)&&this.started&&this.enqueueConversation(e),this.pumpConversationQueue()});this.laneTasks.add(n)}}async drainConversation(e){const n=Object.values(this.client.getSnapshot().messages).filter(n=>"chat_message"===n.type&&n.conversationId===e).sort(compareProjectionOrder);for(const e of n){if(!this.started)break;const n=resolveExecutionBinding(e,this.bindings());if(!n)continue;const t=`${e.conversationId}:${e.id}`;if(this.cancelledTargets.has(t)){this.delivered.add(t);continue}if(this.delivered.has(t)||this.inFlightMessages.has(t))continue;const i=await this.reconcileRequest(e,n);if(!this.started)break;if("handled"===i){this.delivered.add(t);continue}if("pending"===i)break;if(!sameBinding(n,resolveExecutionBinding(e,this.bindings())))break;let s;try{s=await this.executionJournal.claim(t)}catch(n){this.logger.warn?.(`[beeos-claw] inbound execution claim failed conversation=${e.conversationId} message_id=${e.id}: ${n instanceof Error?n.message:String(n)}`);break}if(!this.started||"existing"===s)break;if(!sameBinding(n,resolveExecutionBinding(e,this.bindings())))break;this.inFlightMessages.add(t);try{await n.inbound.onChatMessage(e),this.delivered.add(t)}catch(n){this.logger.warn?.(`[beeos-claw] projected inbound handler failed conversation=${e.conversationId} message_id=${e.id}: ${n instanceof Error?n.message:String(n)}`);break}finally{this.inFlightMessages.delete(t)}}}dispatchCancel(e,n){const t=`${e.conversationId}:${e.id}`;if(this.delivered.has(t)||this.inFlightCancels.has(t))return;const i=resolveCancelTarget(e,n,this.bindings());if(!i)return;this.cancelledTargets.add(`${i.message.conversationId}:${i.message.id}`),this.inFlightCancels.add(t);const s=i.binding.inbound.onChatCancel(e).then(()=>{this.delivered.add(t)}).catch(n=>{this.logger.warn?.(`[beeos-claw] projected inbound cancel failed conversation=${e.conversationId} message_id=${e.id}: ${n instanceof Error?n.message:String(n)}`)}).finally(()=>{this.cancelTasks.delete(s),this.inFlightCancels.delete(t)});this.cancelTasks.add(s)}async reconcileRequest(e,n){const t=Object.values(this.client.getSnapshot().messages),i=t.filter(t=>isReplyFor(t,e,n.targetAgentId));if(i.some(isTerminalReply))return"handled";if(i.length>0)return"pending";if(t.some(t=>isReasoningFor(t,e,n.targetAgentId)))return"pending";const s=deterministicReplyMessageId("asst",e.conversationId,e.id,n.principalId);try{const t=await this.client.messages.getEnvelope(e.conversationId,s);return isReplyFor(t,e,n.targetAgentId)?isTerminalReply(t)?"handled":"pending":(this.logger.warn?.(`[beeos-claw] deterministic reply reconciliation mismatch conversation=${e.conversationId} message_id=${e.id} reply_id=${s}`),"pending")}catch(n){return 404===httpStatus(n)?"execute":(this.logger.warn?.(`[beeos-claw] deterministic reply reconciliation failed conversation=${e.conversationId} message_id=${e.id}: ${n instanceof Error?n.message:String(n)}`),"pending")}}}function isInbound(e){return"chat_message"===e.type||"chat_cancel"===e.type}function resolveExecutionBinding(e,n){if(!e.id)return;const t=asRecord(e.content),i=asRecord(t?.metadata),s=nonEmptyString(i?.delivery_principal),o=nonEmptyString(i?.target_agent_id),r=epochValue(i?.runtime_epoch);if(!s||!o||void 0===r)return;let a,c;for(const e of n){if(e.principalId!==s)continue;if(e.targetAgentId!==o)continue;const n=epochValue(e.runtimeEpoch);void 0===n||r>n||(void 0===c||n>c)&&(a=e,c=n)}return a}function epochValue(e){const n=nonEmptyString(e);if(void 0!==n&&/^\d+$/.test(n))return BigInt(n)}function sameBinding(e,n){return void 0!==n&&n.principalId===e.principalId&&n.targetAgentId===e.targetAgentId&&n.runtimeEpoch===e.runtimeEpoch&&n.inbound===e.inbound}function resolveCancelTarget(e,n,t){const i=nonEmptyString(asRecord(e.content)?.target_message_id);if(!i)return;const s=n.find(n=>"chat_message"===n.type&&n.id===i&&n.conversationId===e.conversationId);if(!s)return;const o=resolveExecutionBinding(s,t),r=resolveExecutionBinding(e,t);return o&&r&&o.principalId===r.principalId&&o.targetAgentId===r.targetAgentId&&o.runtimeEpoch===r.runtimeEpoch?{message:s,binding:o}:void 0}function isReplyFor(e,n,t){return"agent_reply"===e.type&&e.conversationId===n.conversationId&&e.replyTo===n.id&&e.senderId===t}function isReasoningFor(e,n,t){return"agent_reasoning"===e.type&&e.conversationId===n.conversationId&&e.replyTo===n.id&&e.senderId===t}function isTerminalReply(e){return"agent_reply"===e.type&&("completed"===e.state||"failed"===e.state||"refused"===e.state||"cancelled"===e.state)}function httpStatus(e){return null!==e&&"object"==typeof e&&"status"in e&&"number"==typeof e.status?e.status:void 0}function asRecord(e){return null===e||"object"!=typeof e||Array.isArray(e)?void 0:e}function nonEmptyString(e){return"string"==typeof e&&e.length>0?e:void 0}function compareProjectionOrder(e,n){try{const t=BigInt(e.offset)-BigInt(n.offset);if(0n!==t)return t<0n?-1:1}catch{const t=e.offset.localeCompare(n.offset);if(0!==t)return t}return e.id.localeCompare(n.id)}
1
+ import{deterministicReplyMessageId}from"./im-runtime-dispatch.js";export class MessageProjectionInboundConsumer{delivered=new Set;cancelledTargets=new Set;inFlightMessages=new Set;inFlightCancels=new Set;client;bindings;logger;executionJournal;maxConcurrentConversations;conversationQueue=[];queuedConversations=new Set;activeConversations=new Set;rerunConversations=new Set;laneTasks=new Set;cancelTasks=new Set;unsubscribe;activeConversationCount=0;started=!1;constructor(e){this.client=e.client,this.bindings=e.bindings,this.logger=e.logger,this.executionJournal=e.executionJournal,this.maxConcurrentConversations=Math.max(1,Math.floor(e.maxConcurrentConversations??16))}start(){this.started||(this.started=!0,this.unsubscribe=this.client.subscribe(()=>this.schedule()),this.schedule())}async stop(){this.started=!1,this.unsubscribe?.(),this.unsubscribe=void 0,this.conversationQueue.length=0,this.queuedConversations.clear(),this.rerunConversations.clear(),await Promise.allSettled([...this.laneTasks,...this.cancelTasks])}refresh(){this.schedule()}schedule(){if(!this.started)return;const e=Object.values(this.client.getSnapshot().messages).filter(isInbound).sort(compareProjectionOrder);for(const n of e)"chat_cancel"===n.type&&this.dispatchCancel(n,e);for(const n of new Set(e.filter(e=>"chat_message"===e.type).map(e=>e.conversationId)))this.enqueueConversation(n);this.pumpConversationQueue()}enqueueConversation(e){this.activeConversations.has(e)?this.rerunConversations.add(e):this.queuedConversations.has(e)||(this.queuedConversations.add(e),this.conversationQueue.push(e))}pumpConversationQueue(){for(;this.started&&this.activeConversationCount<this.maxConcurrentConversations&&this.conversationQueue.length>0;){const e=this.conversationQueue.shift();this.queuedConversations.delete(e),this.activeConversations.add(e),this.activeConversationCount+=1;const n=this.drainConversation(e).catch(n=>{this.logger.warn?.(`[beeos-claw] projected inbound lane failed conversation=${e}: ${n instanceof Error?n.message:String(n)}`)}).finally(()=>{this.laneTasks.delete(n),this.activeConversations.delete(e),this.activeConversationCount-=1,this.rerunConversations.delete(e)&&this.started&&this.enqueueConversation(e),this.pumpConversationQueue()});this.laneTasks.add(n)}}async drainConversation(e){const n=Object.values(this.client.getSnapshot().messages).filter(n=>"chat_message"===n.type&&n.conversationId===e).sort(compareProjectionOrder);for(const e of n){if(!this.started)break;const n=resolveExecutionBinding(e,this.bindings());if(!n)continue;const t=`${e.conversationId}:${e.id}`;if(this.cancelledTargets.has(t)){this.delivered.add(t);continue}if(this.delivered.has(t)||this.inFlightMessages.has(t))continue;const i=await this.reconcileRequest(e,n);if(!this.started)break;if("handled"===i){this.delivered.add(t);continue}if("pending"===i)break;if(!sameBinding(n,resolveExecutionBinding(e,this.bindings())))break;let s;try{s=await this.executionJournal.claim(t)}catch(n){this.logger.warn?.(`[beeos-claw] inbound execution claim failed conversation=${e.conversationId} message_id=${e.id}: ${n instanceof Error?n.message:String(n)}`);break}if(!this.started)break;if("existing"===s){this.logger.warn?.(`[beeos-claw] projected inbound skip claimed conversation=${e.conversationId} message_id=${e.id}`),this.delivered.add(t);continue}if(!sameBinding(n,resolveExecutionBinding(e,this.bindings())))break;this.inFlightMessages.add(t);try{await n.inbound.onChatMessage(e),this.delivered.add(t)}catch(n){this.logger.warn?.(`[beeos-claw] projected inbound handler failed conversation=${e.conversationId} message_id=${e.id}: ${n instanceof Error?n.message:String(n)}`);break}finally{this.inFlightMessages.delete(t)}}}dispatchCancel(e,n){const t=`${e.conversationId}:${e.id}`;if(this.delivered.has(t)||this.inFlightCancels.has(t))return;const i=resolveCancelTarget(e,n,this.bindings());if(!i)return;this.cancelledTargets.add(`${i.message.conversationId}:${i.message.id}`),this.inFlightCancels.add(t);const s=i.binding.inbound.onChatCancel(e).then(()=>{this.delivered.add(t)}).catch(n=>{this.logger.warn?.(`[beeos-claw] projected inbound cancel failed conversation=${e.conversationId} message_id=${e.id}: ${n instanceof Error?n.message:String(n)}`)}).finally(()=>{this.cancelTasks.delete(s),this.inFlightCancels.delete(t)});this.cancelTasks.add(s)}async reconcileRequest(e,n){const t=Object.values(this.client.getSnapshot().messages),i=t.filter(t=>isReplyFor(t,e,n.targetAgentId));if(i.some(isTerminalReply))return"handled";if(i.length>0)return"pending";if(t.some(t=>isReasoningFor(t,e,n.targetAgentId)))return"pending";const s=deterministicReplyMessageId("asst",e.conversationId,e.id,n.principalId);try{const n=await this.client.messages.getEnvelope(e.conversationId,s);return"agent_reply"!==n.type||n.conversationId!==e.conversationId||void 0!==n.replyTo&&n.replyTo.length>0&&n.replyTo!==e.id?(this.logger.warn?.(`[beeos-claw] deterministic reply reconciliation mismatch conversation=${e.conversationId} message_id=${e.id} reply_id=${s}`),"pending"):isTerminalReply(n)?"handled":"pending"}catch(n){return 404===httpStatus(n)?"execute":(this.logger.warn?.(`[beeos-claw] deterministic reply reconciliation failed conversation=${e.conversationId} message_id=${e.id}: ${n instanceof Error?n.message:String(n)}`),"pending")}}}function isInbound(e){return"chat_message"===e.type||"chat_cancel"===e.type}function resolveExecutionBinding(e,n){if(!e.id)return;const t=asRecord(e.content),i=asRecord(t?.metadata),s=nonEmptyString(i?.delivery_principal),o=nonEmptyString(i?.target_agent_id),r=epochValue(i?.runtime_epoch);if(!s||!o||void 0===r)return;let a,c;for(const e of n){if(e.principalId!==s)continue;if(e.targetAgentId!==o)continue;const n=epochValue(e.runtimeEpoch);void 0===n||r>n||(void 0===c||n>c)&&(a=e,c=n)}return a}function epochValue(e){const n=nonEmptyString(e);if(void 0!==n&&/^\d+$/.test(n))return BigInt(n)}function sameBinding(e,n){return void 0!==n&&n.principalId===e.principalId&&n.targetAgentId===e.targetAgentId&&n.runtimeEpoch===e.runtimeEpoch&&n.inbound===e.inbound}function resolveCancelTarget(e,n,t){const i=nonEmptyString(asRecord(e.content)?.target_message_id);if(!i)return;const s=n.find(n=>"chat_message"===n.type&&n.id===i&&n.conversationId===e.conversationId);if(!s)return;const o=resolveExecutionBinding(s,t),r=resolveExecutionBinding(e,t);return o&&r&&o.principalId===r.principalId&&o.targetAgentId===r.targetAgentId&&o.runtimeEpoch===r.runtimeEpoch?{message:s,binding:o}:void 0}function isReplyFor(e,n,t){if("agent_reply"!==e.type||e.conversationId!==n.conversationId||e.replyTo!==n.id)return!1;if(e.senderId===t)return!0;if(!isTerminalReply(e))return!1;const i=nonEmptyString(asRecord(asRecord(n.content)?.metadata)?.delivery_principal);return void 0!==i&&e.senderId===i}function isReasoningFor(e,n,t){return"agent_reasoning"===e.type&&e.conversationId===n.conversationId&&e.replyTo===n.id&&e.senderId===t}function isTerminalReply(e){return"agent_reply"===e.type&&("completed"===e.state||"failed"===e.state||"refused"===e.state||"cancelled"===e.state)}function httpStatus(e){return null!==e&&"object"==typeof e&&"status"in e&&"number"==typeof e.status?e.status:void 0}function asRecord(e){return null===e||"object"!=typeof e||Array.isArray(e)?void 0:e}function nonEmptyString(e){return"string"==typeof e&&e.length>0?e:void 0}function compareProjectionOrder(e,n){try{const t=BigInt(e.offset)-BigInt(n.offset);if(0n!==t)return t<0n?-1:1}catch{const t=e.offset.localeCompare(n.offset);if(0!==t)return t}return e.id.localeCompare(n.id)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beeos-claw",
3
- "version": "0.6.23",
3
+ "version": "0.6.24",
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>",
@@ -63,7 +63,7 @@
63
63
  "dependencies": {
64
64
  "@beeos-ai/beeos-types": "4.2.0",
65
65
  "@beeos-ai/bridge-client": "^0.1.0",
66
- "@beeos-ai/message-sdk": "2.0.3",
66
+ "@beeos-ai/message-sdk": "2.0.4",
67
67
  "@modelcontextprotocol/sdk": "^1.29.0",
68
68
  "adm-zip": "^0.6.0",
69
69
  "ws": "^8.18.0"