beeos-claw 0.6.93 → 0.6.95
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/config.js +1 -1
- package/dist/gateway-client.js +1 -1
- package/dist/index.js +1 -1
- package/dist/runtime/central-native-composition.js +1 -1
- package/dist/runtime/central-native-context-engine.js +1 -1
- package/dist/runtime/central-native-credentials.js +1 -1
- package/dist/runtime/central-native-host.js +1 -1
- package/dist/runtime/central-native-output-files.js +1 -0
- package/dist/runtime/central-native-production.js +1 -1
- package/dist/runtime/native-cloud-prompt-bridge.js +1 -1
- package/dist/runtime/native-output-file-attempt.js +1 -1
- package/dist/runtime/prepare-openclaw-tool-catalog.js +1 -1
- package/dist/runtime/sandbox-native-activation.js +1 -1
- package/dist/upload/native-output-tool-hook.js +1 -1
- package/dist/upload/tool.js +1 -1
- package/dist/upload/upload-file.js +1 -1
- package/openclaw.plugin.json +4 -0
- package/package.json +6 -3
package/dist/config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mkdirSync,writeFileSync}from"node:fs";import{homedir}from"node:os";import{dirname,join}from"node:path";function trimStr(e){if("string"==typeof e){const
|
|
1
|
+
import{mkdirSync,writeFileSync}from"node:fs";import{homedir}from"node:os";import{dirname,join}from"node:path";function trimStr(e){if("string"==typeof e){const a=e.trim();return a.length>0?a:void 0}}function readInt(e){if("number"==typeof e&&Number.isFinite(e))return Math.trunc(e);if("string"==typeof e){const a=parseInt(e,10);return Number.isFinite(a)?a:void 0}}function readBool(e){return"boolean"==typeof e?e:"true"===e||"false"!==e&&void 0}function pick(e,a){for(const a of e)if(void 0!==a.value)return{value:a.value,source:a.source};return a}const CURRENT_CONFIG_PROTOCOL=1;function shouldTrustOperationalConfig(e){const a=e._generator;if(!a)return!1;return("number"==typeof a.configProtocol?a.configProtocol:0)>=1}const DEFAULT_GATEWAY_URL="ws://127.0.0.1:18789",DEFAULT_LOG_DIR=join(process.env.OPENCLAW_HOME||join(homedir(),".openclaw"),"beeos-logs"),DEFAULT_OPENCLAW_CONFIG_PATH=join(homedir(),".openclaw","openclaw.json");export function resolveConfigWithMeta(e){const a=e.pluginConfig??{},o=e.openclawConfig??{},r=e.openclawConfigPath??DEFAULT_OPENCLAW_CONFIG_PATH,l=shouldTrustOperationalConfig(a),n=pick([{source:"pluginConfig",value:trimStr(a.agentGatewayUrl)},{source:"pluginConfig",value:trimStr(a.platformUrl)},{source:"env",value:trimStr(process.env.AGENT_GATEWAY_URL)}],{source:"default",value:""}),u=a.gateway??{},s=(o.gateway??{}).auth??{},t=pick([...l?[{source:"pluginConfig",value:trimStr(u.url)}]:[],{source:"env",value:trimStr(process.env.BEEOS_GATEWAY_URL)}],{source:"default",value:DEFAULT_GATEWAY_URL}),i=pick([{source:"openclawConfig",value:trimStr(s.token)},{source:"pluginConfig",value:trimStr(u.token)},{source:"env",value:trimStr(process.env.BEEOS_GATEWAY_TOKEN)}],{source:"default",value:""}),c=pick([...l?[{source:"pluginConfig",value:readInt(u.protocol)}]:[]],{source:"default",value:3}),v=pick([...l?[{source:"pluginConfig",value:trimStr(u.clientId)}]:[]],{source:"default",value:`beeos-claw-${process.pid}`}),p=pick([...l?[{source:"pluginConfig",value:trimStr(u.agentId)}]:[]],{source:"default",value:""}),d=a.bridge??{},g=pick([{source:"pluginConfig",value:trimStr(a.keyFile)},{source:"pluginConfig",value:trimStr(d.keyFile)},{source:"env",value:trimStr(process.env.BRIDGE_KEY_FILE)}],{source:"default",value:""}),E=pick([{source:"env",value:trimStr(process.env.BRIDGE_URL)}],{source:"default",value:""}),f=pick([...l?[{source:"pluginConfig",value:trimStr(d.service)}]:[],{source:"env",value:trimStr(process.env.BRIDGE_SERVICE)}],{source:"default",value:"acp"}),m=d.shell??{},_=pick([...l?[{source:"pluginConfig",value:readBool(m.enabled)}]:[],{source:"env",value:readBool(process.env.BEEOS_SHELL_ENABLED)}],{source:"default",value:!0}),S=a.retry??{},A=pick([...l?[{source:"pluginConfig",value:readInt(S.baseMs)}]:[]],{source:"default",value:1e3}),C=pick([...l?[{source:"pluginConfig",value:readInt(S.maxMs)}]:[]],{source:"default",value:6e5}),O=pick([...l?[{source:"pluginConfig",value:readInt(S.maxAttempts)}]:[]],{source:"default",value:0}),I=a.log??{},y=pick([...l?[{source:"pluginConfig",value:readBool(I.enabled)}]:[],{source:"env",value:readBool(process.env.BEEOS_LOG_ENABLED)}],{source:"default",value:!0}),w=pick([...l?[{source:"pluginConfig",value:readBool(I.verbose)}]:[]],{source:"default",value:!1}),T=pick([{source:"pluginConfig",value:trimStr(I.dir)}],{source:"default",value:DEFAULT_LOG_DIR}),R=pick([...l?[{source:"pluginConfig",value:readInt(a.terminalWsPort)}]:[],{source:"env",value:readInt(process.env.BEEOS_TERMINAL_WS_PORT)}],{source:"default",value:18801}),B=(l?trimStr(a.terminalWsAllowedOrigins):void 0)??trimStr(process.env.BEEOS_TERMINAL_WS_ALLOWED_ORIGINS),L=B?B.split(",").map(e=>e.trim()).filter(Boolean):void 0,M=pick([{source:B?"pluginConfig":"default",value:L?.length?L:void 0}],{source:"default",value:["localhost","127.0.0.1","::1"]}),b=!0===readBool(process.env.BEEOS_OPENCLAW_DESKTOP)||"1"===process.env.BEEOS_OPENCLAW_DESKTOP,k=pick([{source:"env",value:readBool(process.env.BEEOS_TERMINAL_SERVICE_ENABLED)},...l&&!0===a.terminalServiceEnabled?[{source:"pluginConfig",value:!0}]:[]],{source:"default",value:b}),h=pick([...l?[{source:"pluginConfig",value:readBool(a.legacyTerminalWsEnabled)}]:[],{source:"env",value:readBool(process.env.BEEOS_LEGACY_TERMINAL_WS_ENABLED)}],{source:"default",value:!1}),N=pick([...l?[{source:"pluginConfig",value:readInt(a.streamIdleTimeoutMs)}]:[],{source:"env",value:readInt(process.env.BEEOS_STREAM_IDLE_TIMEOUT_MS)}],{source:"default",value:15e3}),G=pick([...l?[{source:"pluginConfig",value:readInt(a.streamStaleTimeoutMs)}]:[],{source:"env",value:readInt(process.env.BEEOS_STREAM_STALE_TIMEOUT_MS)}],{source:"default",value:6e5}),W=pick([...l?[{source:"pluginConfig",value:readInt(a.cronSignalWindowMs)}]:[],{source:"env",value:readInt(process.env.BEEOS_CRON_SIGNAL_WINDOW_MS)}],{source:"default",value:6e4}),P=pick([{source:"env",value:trimStr(process.env.CANVAS_RELAY_URL)},{source:"pluginConfig",value:trimStr(a.canvasRelayUrl)}],{source:"default",value:"https://canvas-relay.beeos.ai"}),U=pick([...l?[{source:"pluginConfig",value:readBool(a.canvasEnabled)}]:[],{source:"env",value:readBool(process.env.BEEOS_CANVAS_ENABLED)}],{source:"default",value:!0}),D=pick([...l?[{source:"pluginConfig",value:readBool(a.openclawCanvasCompat)}]:[],{source:"env",value:readBool(process.env.BEEOS_OPENCLAW_CANVAS_COMPAT)}],{source:"default",value:!1}),F=a.messageBus??{},x=pick([{source:"pluginConfig",value:trimStr(F.serviceUrl)},{source:"env",value:trimStr(process.env.MESSAGE_SERVICE_URL)}],{source:"default",value:""}),j=pick([{source:"pluginConfig",value:trimStr(F.principalId)},{source:"env",value:trimStr(process.env.BEEOS_PRINCIPAL_ID)}],{source:"default",value:""}),Y=pick([{source:"pluginConfig",value:readBool(F.a2aEnabled)},{source:"env",value:readBool(process.env.BEEOS_A2A_ENABLED)}],{source:"default",value:!0}),H=pick([{source:"pluginConfig",value:readBool(F.enabled)},{source:"env",value:readBool(process.env.BEEOS_MESSAGE_BUS_ENABLED)}],{source:"default",value:!(!x.value&&!n.value)}),$={agentGatewayUrl:n.value.replace(/\/+$/,""),keyFile:g.value,bridge:{url:E.value,service:f.value,mode:trimStr(d.mode),shell:{enabled:_.value}},gateway:{url:t.value,token:i.value,protocol:c.value,clientId:v.value,agentId:p.value},retry:{baseMs:Math.max(0,A.value),maxMs:Math.max(0,C.value),maxAttempts:Math.max(0,O.value)},log:{enabled:y.value,verbose:w.value,dir:T.value},terminalWsPort:R.value,terminalWsAllowedOrigins:M.value,terminalServiceEnabled:k.value,legacyTerminalWsEnabled:h.value,streamIdleTimeoutMs:Math.max(0,N.value),streamStaleTimeoutMs:Math.max(0,G.value),cronSignalWindowMs:Math.max(0,W.value),canvasRelayUrl:P.value.replace(/\/+$/,""),canvasEnabled:U.value,openclawCanvasCompat:D.value,messageBus:{enabled:H.value,serviceUrl:x.value,principalId:j.value,a2aEnabled:Y.value}},V={agentGatewayUrl:n.source,keyFile:g.source,bridge:{url:E.source,service:f.source,shell:{enabled:_.source}},gateway:{url:t.source,token:i.source,protocol:c.source,clientId:v.source,agentId:p.source},retry:{baseMs:A.source,maxMs:C.source,maxAttempts:O.source},log:{enabled:y.source,verbose:w.source,dir:T.source},terminalWsPort:R.source,terminalWsAllowedOrigins:M.source,terminalServiceEnabled:k.source,legacyTerminalWsEnabled:h.source,streamIdleTimeoutMs:N.source,streamStaleTimeoutMs:G.source,cronSignalWindowMs:W.source,canvasRelayUrl:P.source,canvasEnabled:U.source,openclawCanvasCompat:D.source,messageBus:{enabled:H.source,serviceUrl:x.source,principalId:j.source,a2aEnabled:Y.source}},K=[];$.agentGatewayUrl||K.push({code:"CONFIG_AGENT_GATEWAY_URL_MISSING",severity:"error",message:"agentGatewayUrl is required for file uploads and Agent Gateway callbacks",nextSteps:[`Set plugins.entries.beeos-claw.config.agentGatewayUrl in ${r}`,"Or set the AGENT_GATEWAY_URL environment variable"]}),$.gateway.token||K.push({code:"CONFIG_GATEWAY_TOKEN_MISSING",severity:"warn",message:"gateway.token is empty; Gateway auth may fail if authentication is enabled",nextSteps:[`Set gateway.auth.token in ${r}`,`Or set plugins.entries.beeos-claw.config.gateway.token in ${r}`]});const q=o.tools,J=q&&"object"==typeof q&&!Array.isArray(q)?q.allow:void 0;return Array.isArray(J)&&0===J.length&&K.push({code:"CONFIG_TOOLS_ALLOW_EMPTY",severity:"warn",message:'openclaw.json tools.allow is an empty array; OpenClaw treats an explicit empty allowlist as no tools, so the model only sees tool_search/tool_call/tool_describe and every real tool call fails with "Unknown tool id"',nextSteps:[`Remove tools.allow from ${r}, or list the tools the agent may call`,"Restart the Gateway after changing openclaw.json"]}),{config:$,sources:V,validation:K,openclawConfigPath:r}}export function resolveConfig(e){const{config:a,validation:o}=resolveConfigWithMeta({pluginConfig:e}),r=o.find(e=>"error"===e.severity);if(r)throw new Error(`[beeos-claw] ${r.message}`);return a}const MIRROR_PATH=join(process.env.OPENCLAW_HOME||join(homedir(),".openclaw"),"beeos-claw","openclaw.json");export function mirrorOpenClawConfig(e){if(!e||"object"!=typeof e||Array.isArray(e))return{copied:!1,destinationPath:MIRROR_PATH,reason:"config_invalid"};try{return mkdirSync(dirname(MIRROR_PATH),{recursive:!0}),writeFileSync(MIRROR_PATH,JSON.stringify(e,null,2)+"\n",{encoding:"utf8",mode:384}),{copied:!0,destinationPath:MIRROR_PATH}}catch(e){return{copied:!1,destinationPath:MIRROR_PATH,reason:e instanceof Error?e.message:"write_failed"}}}
|
package/dist/gateway-client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{WebSocket}from"ws";import{EventEmitter}from"node:events";import{randomUUID,createHash}from"node:crypto";import{loadOrCreateDeviceIdentity,buildDeviceAuthPayload,signDeviceAuth,ensureDevicePaired,warmupCryptoSign}from"./device-identity.js";const MIN_PROTOCOL_VERSION=3,MAX_PROTOCOL_VERSION=4,CONNECT_TIMEOUT_MS=3e4,HEARTBEAT_INTERVAL_MS=15e3,LIVENESS_TIMEOUT_MS=6e4,CHAT_HISTORY_PAGE_TIMEOUT_MS=1e4,AUTH_FAILURE_CLOSE_CODE=4001,EL_LAG_INTERVAL_MS=200,EL_LAG_THRESHOLD_MS=500,RECONNECT_NOTIFY_MIN_MS=6e4,RECONNECT_NOTIFY_MAX_MS=18e4,RECONNECT_NOTIFY_METHOD="server/reconnect";export class GatewayHandshakeError extends Error{code;retryable;retryAfterMs;constructor(e){super(e?.message||"Gateway connect rejected"),this.name="GatewayHandshakeError",this.code=e?.code,this.retryable=!0===e?.retryable||"UNAVAILABLE"===e?.code,this.retryAfterMs="number"==typeof e?.retryAfterMs?e.retryAfterMs:void 0}}export function decodeChatAbortResult(e){if("object"!=typeof e||null===e||Array.isArray(e))throw new Error("Invalid chat.abort response: expected object");const t=e;if("boolean"!=typeof t.aborted)throw new Error("Invalid chat.abort response: expected boolean aborted");if(!Array.isArray(t.runIds)||t.runIds.some(e=>"string"!=typeof e))throw new Error("Invalid chat.abort response: expected string[] runIds");return{aborted:t.aborted,runIds:[...t.runIds]}}function wsUrlToHttpBase(e){try{const t=new URL(e),n="wss:"===t.protocol?"https:":"ws:"===t.protocol?"http:":null;return n?`${n}//${t.host}`:null}catch{return null}}const MANUAL_RECONNECT_SIGNAL="SIGUSR1";function registerReconnectSignal(e,t,n){detachReconnectSignal(e),e.handler=t;try{process.on("SIGUSR1",t),n?.info?.("[gateway] manual reconnect enabled signal=SIGUSR1")}catch{n?.warn?.("[gateway] manual reconnect signal not supported")}}function detachReconnectSignal(e){if(e.handler){try{process.off("SIGUSR1",e.handler)}catch{}e.handler=null}}export class GatewayClient extends EventEmitter{ws=null;config;pending=new Map;connected=!1;stopped=!1;authFailed=!1;connectPromise=null;reconnectTimer=null;reconnectAttempt=0;nextReconnectDelayHintMs=null;signalState={handler:null};deviceIdentity;heartbeatTimer=null;lastPongTs=0;_connectionSeq=0;_currentConnectionId=null;_lastReadyAt=0;reconnectNotifyTimer=null;constructor(e){super(),this.config=e,this.deviceIdentity=loadOrCreateDeviceIdentity();try{ensureDevicePaired(this.deviceIdentity)}catch(e){}Date.now();warmupCryptoSign(this.deviceIdentity)}async start(){this.stopped=!1,this.reconnectAttempt=0,registerReconnectSignal(this.signalState,()=>{this.stopped||(this.emit("manual-reconnect"),this.reconnectNow())}),await this.connect()}stop(){this.stopped=!0,this.stopHeartbeat(),this.clearReconnectNotify(),detachReconnectSignal(this.signalState),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.close()}async connect(){if(this.connectPromise)return this.connectPromise;this.connectPromise=this._connect();try{await this.connectPromise}finally{this.connectPromise=null}}_connect(){return new Promise((e,t)=>{if(this.authFailed)return void t(new Error("Authentication failed — not retrying"));const n=Date.now();this.emit("transport",{event:"connect_start",url:this.config.url,attempt:this.reconnectAttempt});const s=new WebSocket(this.config.url);this.ws=s;let r,i=null,o=!1;const c=setTimeout(()=>{this.emit("transport",{event:"connect_fail",reason:"timeout",durationMs:Date.now()-n}),s.close(),t(new Error("Gateway connection timeout"))},3e4),a=t=>{clearTimeout(c),o=!0,this.connected=!0,this.reconnectAttempt=0,this.authFailed=!1,this._connectionSeq++,this._currentConnectionId=randomUUID(),this._lastReadyAt=Date.now(),this.startHeartbeat(),this.emit("transport",{event:"connect_ok",connectionSeq:this._connectionSeq,connectionId:this._currentConnectionId,durationMs:Date.now()-n}),this.emit("connected",{...t,connectionSeq:this._connectionSeq,connectionId:this._currentConnectionId}),e()},h=e=>{const r="string"==typeof e?e:e.message;clearTimeout(c),this.authFailed=!0,this.emit("transport",{event:"connect_fail",reason:r,durationMs:Date.now()-n}),this.emit("auth-failed",{reason:r}),s.close(),t("string"==typeof e?new Error(e):e)};s.on("open",()=>{this.emit("transport",{event:"ws_open",durationMs:Date.now()-n})}),s.on("message",e=>{const o="string"==typeof e?e:e.toString("utf-8");if("pong"===o)return void(this.lastPongTs=Date.now());let l;this.emitMessageHash(o);try{l=JSON.parse(o)}catch{return}const d=l.method;d&&!l.id&&(this.isReconnectNotification(d)?this.scheduleReconnectNotify():this.reconnectNotifyTimer&&this.clearReconnectNotify(),this.emit("notification",d,l.params));const u=l.type;if("event"===u&&this.reconnectNotifyTimer&&this.clearReconnectNotify(),"event"===u){const e=l.event,t=l.payload;if("connect.challenge"===e){const e=Date.now();this.emit("transport",{event:"handshake.challenge_recv",durationMs:e-n});const s=t?.nonce;i=this._sendConnect(s),this.emit("transport",{event:"handshake.connect_sent",durationMs:Date.now()-n}),r?.();let o=0;const c=setInterval(()=>{o++},200),a=Date.now(),h=setInterval(()=>{const e=Date.now()-a,t=e-200*o;t>500&&this.emit("transport",{event:"eventloop_lag",lagMs:t,elapsedMs:e,probeSeq:o})},200);let l;const d=()=>{clearInterval(c),clearInterval(h),l&&clearTimeout(l),this.off("connected",d),r===d&&(r=void 0)};r=d,l=setTimeout(d,3e4),this.once("connected",d)}else"chat"===e?this.emit("chat",t):"agent"===e?this.emit("agent",t):"cron"===e?this.emit("cron",t):"canvas"===e?this.emit("canvas",t):"session.message"===e?this.emit("sessionMessage",t):this.emit("gateway-event",e,t)}else if("hello-ok"===u)this.emit("transport",{event:"handshake.hello_ok_recv",durationMs:Date.now()-n}),a(l);else if("hello-error"===u||"connect-error"===u)h("Authentication rejected by Gateway");else if("res"===u){const e=l.id;if(e&&e===i){if(this.emit("transport",{event:"handshake.connect_res_recv",ok:!!l.ok,durationMs:Date.now()-n}),l.ok){const e=l.payload;a(e??l)}else{const e=l.error,r=new GatewayHandshakeError(e);r.retryable?(clearTimeout(c),this.emit("transport",{event:"connect_fail",reason:r.message,retryable:!0,retryAfterMs:r.retryAfterMs,durationMs:Date.now()-n}),"number"==typeof r.retryAfterMs&&r.retryAfterMs>0&&(this.nextReconnectDelayHintMs=r.retryAfterMs),s.close(),t(r)):h(r)}return}const r=this.pending.get(e);if(r)if(this.pending.delete(e),clearTimeout(r.timer),l.ok)r.resolve(l.payload);else{const e=l.error;r.reject(new Error(e?.message||"Gateway request failed"))}else this.emit("response",l)}}),s.on("pong",()=>{this.lastPongTs=Date.now()}),s.on("close",e=>{const s=o;r?.(),this.stopHeartbeat(),this.clearReconnectNotify(),this.emit("transport",{event:"close",code:e,durationMs:Date.now()-n}),this.connected=!1,this.connectPromise=null;for(const[,e]of this.pending)clearTimeout(e.timer),e.reject(new Error("Connection closed"));this.pending.clear(),s||(clearTimeout(c),t(new Error(`Connection closed during handshake (code=${e})`))),4001===e&&(this.authFailed=!0,this.emit("auth-failed",{code:e})),s&&this.emit("disconnected"),this.stopped||this.authFailed||this.scheduleReconnect()}),s.on("error",e=>{this.emit("transport",{event:"error",message:e.message,durationMs:Date.now()-n}),this.stopped?clearTimeout(c):(this.connected||(clearTimeout(c),t(e)),this.emit("error",e))})})}emitMessageHash(e){if(e.length<32)return;const t=createHash("sha256").update(e).digest("hex").slice(0,16);this.emit("transport",{event:"message_recv",hash:t,size:e.length})}startHeartbeat(){this.stopHeartbeat(),this.lastPongTs=Date.now(),this.heartbeatTimer=setInterval(()=>{if(!this.ws||!this.connected)return;try{this.ws.ping()}catch{}const e=Date.now()-this.lastPongTs;e>6e4&&(this.emit("liveness-timeout",{elapsed:e}),this.ws.close())},15e3),"object"==typeof this.heartbeatTimer&&"unref"in this.heartbeatTimer&&this.heartbeatTimer.unref()}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}isReconnectNotification(e){return"server/reconnect"===e||e.endsWith("/reconnect")}scheduleReconnectNotify(){this.clearReconnectNotify();const e=6e4+12e4*Math.random();this.emit("reconnect-notify-scheduled",{delayMs:Math.round(e)}),this.reconnectNotifyTimer=setTimeout(()=>{this.reconnectNotifyTimer=null,!this.stopped&&this.connected&&(this.emit("reconnect-notify-fired"),this.reconnectNow())},e),"object"==typeof this.reconnectNotifyTimer&&"unref"in this.reconnectNotifyTimer&&this.reconnectNotifyTimer.unref()}clearReconnectNotify(){this.reconnectNotifyTimer&&(clearTimeout(this.reconnectNotifyTimer),this.reconnectNotifyTimer=null)}scheduleReconnect(){if(this.stopped)return;if(this.reconnectTimer)return;const e=this.config.retry??{baseMs:1e3,maxMs:6e5,maxAttempts:0};if(e.maxAttempts>0&&this.reconnectAttempt>=e.maxAttempts)return void this.emit("reconnect-exhausted",this.reconnectAttempt);let t;const n=this.nextReconnectDelayHintMs,s=null!==n&&n>0;s?(t=Math.min(n,e.maxMs),this.nextReconnectDelayHintMs=null):(t=Math.min(e.baseMs*Math.pow(2,this.reconnectAttempt)+500*Math.random(),e.maxMs),this.reconnectAttempt++),this.emit("reconnecting",{attempt:s?this.reconnectAttempt+1:this.reconnectAttempt,delayMs:t}),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.stopped||this.connect().catch(e=>{this.emitReconnectFailure(e)})},t),"object"==typeof this.reconnectTimer&&"unref"in this.reconnectTimer&&this.reconnectTimer.unref()}reconnectNow(){this.stopped||(this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.close(),this.reconnectAttempt=0,this.connect().catch(e=>{this.emitReconnectFailure(e)}))}emitReconnectFailure(e){this.stopped||this.authFailed||this.emit("error",e instanceof Error?e:new Error(String(e)))}_sendConnect(e){const t=Date.now(),n=Date.now(),s="operator",r=["operator.admin","operator.approvals","operator.pairing"],i={id:this.deviceIdentity.deviceId,publicKey:this.deviceIdentity.publicKeyB64url,signedAt:n};if(e){const t=Date.now(),o=buildDeviceAuthPayload({deviceId:this.deviceIdentity.deviceId,clientId:"cli",clientMode:"cli",role:s,scopes:r,signedAtMs:n,token:this.config.token,nonce:e}),c=Date.now()-t,a=Date.now();i.nonce=e,i.signature=signDeviceAuth(this.deviceIdentity,o);const h=Date.now()-a;this.emit("transport",{event:"handshake.sign_done",buildPayloadMs:c,signMs:h})}const o=randomUUID(),c={type:"req",id:o,method:"connect",params:{minProtocol:3,maxProtocol:4,client:{id:"cli",displayName:"BeeOS Platform Bridge",version:"0.1.0",platform:"beeos",mode:"cli"},caps:this.config.openclawCanvasCompat?["tool-events","approvals","canvas"]:["tool-events","approvals"],role:s,scopes:r,auth:{token:this.config.token},device:i}},a=Date.now(),h=JSON.stringify(c),l=Date.now()-a,d=Date.now();this.ws?.send(h);const u=Date.now()-d;return this.emit("transport",{event:"handshake._sendConnect_done",totalMs:Date.now()-t,serializeMs:l,sendMs:u}),o}async request(e,t,n=6e4){if(!this.ws||!this.connected)throw new Error("Not connected to Gateway");const s=randomUUID(),r={type:"req",id:s,method:e,params:t};return new Promise((t,i)=>{const o=setTimeout(()=>{this.pending.delete(s),i(new Error(`Gateway request timeout: ${e}`))},n);this.pending.set(s,{resolve:t,reject:i,timer:o}),this.ws.send(JSON.stringify(r))})}async agentSend(e,t,n,s,r){const i={agentId:n,sessionKey:e,message:t,deliver:!1,idempotencyKey:randomUUID()};s?.length&&(i.attachments=s),r&&(i.inputProvenance=r);return await this.request("agent",i,12e4)}async chatSend(e,t,n){const s={sessionKey:e,message:t,deliver:!1,idempotencyKey:randomUUID()};n?.length&&(s.attachments=n);return await this.request("chat.send",s,12e4)}async chatAbort(e,t){const n={sessionKey:e};t&&(n.runId=t);return decodeChatAbortResult(await this.request("chat.abort",n))}sendFrame(e){if(!this.ws||!this.connected)return!1;try{return this.ws.send(JSON.stringify(e)),!0}catch{return!1}}agentCancel(e,t){const n={sessionKey:e};t?.runId&&(n.runId=t.runId);const s=`abort_${t?.runId??t?.requestId??e}`;return this.sendFrame({type:"req",id:s,method:"chat.abort",params:n})}async chatHistory(e,t){return this.request("chat.history",{sessionKey:e,limit:t})}async chatHistoryPage(e,t){const n=wsUrlToHttpBase(this.config.url);if(!n)return null;let s;try{s=new URL(`${n}/sessions/${encodeURIComponent(e)}/history`)}catch{return null}null!=t?.limit&&s.searchParams.set("limit",String(t.limit)),t?.cursor&&s.searchParams.set("cursor",t.cursor);try{const e=await fetch(s,{method:"GET",headers:{accept:"application/json",authorization:`Bearer ${this.config.token}`},signal:AbortSignal.timeout(1e4)});if(!e.ok)return null;const t=await e.json(),n=Array.isArray(t.messages)?t.messages:Array.isArray(t.items)?t.items:[];return{messages:n.filter(e=>"object"==typeof e&&null!==e),nextCursor:"string"==typeof t.nextCursor&&t.nextCursor.length>0?t.nextCursor:void 0,hasMore:!0===t.hasMore}}catch{return null}}async sessionsMessagesSubscribe(e){return this.request("sessions.messages.subscribe",{key:e})}async sessionsMessagesUnsubscribe(e){return this.request("sessions.messages.unsubscribe",{key:e})}async skillsStatus(e){return this.request("skills.status",e?{agentId:e}:{})}async sessionsList(){return this.request("sessions.list",{includeDerivedTitles:!0})}async sessionsResolve(e){return this.request("sessions.resolve",{sessionKey:e})}async sessionsPatch(e,t){return this.request("sessions.patch",{key:e,...t})}async sessionsDelete(e){return this.request("sessions.delete",{key:e})}async sessionsReset(e){return this.request("sessions.reset",{key:e,reason:"new"})}close(){if(this.ws)try{this.ws.close()}catch{}this.ws=null,this.connected=!1,this.connectPromise=null,this._currentConnectionId=null}get isConnected(){return this.connected}get connectionSeq(){return this._connectionSeq}get currentConnectionId(){return this._currentConnectionId}get lastReadyAt(){return this._lastReadyAt}}
|
|
1
|
+
import{WebSocket}from"ws";import{EventEmitter}from"node:events";import{randomUUID,createHash}from"node:crypto";import{loadOrCreateDeviceIdentity,buildDeviceAuthPayload,signDeviceAuth,ensureDevicePaired,warmupCryptoSign}from"./device-identity.js";const MIN_PROTOCOL_VERSION=3,MAX_PROTOCOL_VERSION=4,CONNECT_TIMEOUT_MS=3e4,HEARTBEAT_INTERVAL_MS=15e3,LIVENESS_TIMEOUT_MS=6e4,CHAT_HISTORY_PAGE_TIMEOUT_MS=1e4,AUTH_FAILURE_CLOSE_CODE=4001,EL_LAG_INTERVAL_MS=200,EL_LAG_THRESHOLD_MS=500,RECONNECT_NOTIFY_MIN_MS=6e4,RECONNECT_NOTIFY_MAX_MS=18e4,RECONNECT_NOTIFY_METHOD="server/reconnect";export class GatewayHandshakeError extends Error{code;retryable;retryAfterMs;constructor(e){super(e?.message||"Gateway connect rejected"),this.name="GatewayHandshakeError",this.code=e?.code,this.retryable=!0===e?.retryable||"UNAVAILABLE"===e?.code,this.retryAfterMs="number"==typeof e?.retryAfterMs?e.retryAfterMs:void 0}}export function decodeChatAbortResult(e){if("object"!=typeof e||null===e||Array.isArray(e))throw new Error("Invalid chat.abort response: expected object");const t=e;if("boolean"!=typeof t.aborted)throw new Error("Invalid chat.abort response: expected boolean aborted");if(!Array.isArray(t.runIds)||t.runIds.some(e=>"string"!=typeof e))throw new Error("Invalid chat.abort response: expected string[] runIds");return{aborted:t.aborted,runIds:[...t.runIds]}}function wsUrlToHttpBase(e){try{const t=new URL(e),n="wss:"===t.protocol?"https:":"ws:"===t.protocol?"http:":null;return n?`${n}//${t.host}`:null}catch{return null}}const MANUAL_RECONNECT_SIGNAL="SIGUSR1";function registerReconnectSignal(e,t,n){detachReconnectSignal(e),e.handler=t;try{process.on("SIGUSR1",t),n?.info?.("[gateway] manual reconnect enabled signal=SIGUSR1")}catch{n?.warn?.("[gateway] manual reconnect signal not supported")}}function detachReconnectSignal(e){if(e.handler){try{process.off("SIGUSR1",e.handler)}catch{}e.handler=null}}export function waitForGatewayConnected(e,t){return e.isConnected?Promise.resolve():new Promise((n,s)=>{const r=()=>{clearTimeout(o),n()},o=setTimeout(()=>{e.off("connected",r),s(new Error("OpenClaw gateway is not connected"))},t);o.unref?.(),e.once("connected",r)})}export class GatewayClient extends EventEmitter{ws=null;config;pending=new Map;connected=!1;stopped=!1;authFailed=!1;connectPromise=null;reconnectTimer=null;reconnectAttempt=0;nextReconnectDelayHintMs=null;signalState={handler:null};deviceIdentity;heartbeatTimer=null;lastPongTs=0;_connectionSeq=0;_currentConnectionId=null;_lastReadyAt=0;reconnectNotifyTimer=null;constructor(e){super(),this.config=e,this.deviceIdentity=loadOrCreateDeviceIdentity();try{ensureDevicePaired(this.deviceIdentity)}catch(e){}Date.now();warmupCryptoSign(this.deviceIdentity)}async start(){this.stopped=!1,this.reconnectAttempt=0,registerReconnectSignal(this.signalState,()=>{this.stopped||(this.emit("manual-reconnect"),this.reconnectNow())}),await this.connect()}stop(){this.stopped=!0,this.stopHeartbeat(),this.clearReconnectNotify(),detachReconnectSignal(this.signalState),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.close()}async connect(){if(this.connectPromise)return this.connectPromise;this.connectPromise=this._connect();try{await this.connectPromise}finally{this.connectPromise=null}}_connect(){return new Promise((e,t)=>{if(this.authFailed)return void t(new Error("Authentication failed — not retrying"));const n=Date.now();this.emit("transport",{event:"connect_start",url:this.config.url,attempt:this.reconnectAttempt});const s=new WebSocket(this.config.url);this.ws=s;let r,o=null,i=!1;const c=setTimeout(()=>{this.emit("transport",{event:"connect_fail",reason:"timeout",durationMs:Date.now()-n}),s.close(),t(new Error("Gateway connection timeout"))},3e4),a=t=>{clearTimeout(c),i=!0,this.connected=!0,this.reconnectAttempt=0,this.authFailed=!1,this._connectionSeq++,this._currentConnectionId=randomUUID(),this._lastReadyAt=Date.now(),this.startHeartbeat(),this.emit("transport",{event:"connect_ok",connectionSeq:this._connectionSeq,connectionId:this._currentConnectionId,durationMs:Date.now()-n}),this.emit("connected",{...t,connectionSeq:this._connectionSeq,connectionId:this._currentConnectionId}),e()},h=e=>{const r="string"==typeof e?e:e.message;clearTimeout(c),this.authFailed=!0,this.emit("transport",{event:"connect_fail",reason:r,durationMs:Date.now()-n}),this.emit("auth-failed",{reason:r}),s.close(),t("string"==typeof e?new Error(e):e)};s.on("open",()=>{this.emit("transport",{event:"ws_open",durationMs:Date.now()-n})}),s.on("message",e=>{const i="string"==typeof e?e:e.toString("utf-8");if("pong"===i)return void(this.lastPongTs=Date.now());let l;this.emitMessageHash(i);try{l=JSON.parse(i)}catch{return}const d=l.method;d&&!l.id&&(this.isReconnectNotification(d)?this.scheduleReconnectNotify():this.reconnectNotifyTimer&&this.clearReconnectNotify(),this.emit("notification",d,l.params));const u=l.type;if("event"===u&&this.reconnectNotifyTimer&&this.clearReconnectNotify(),"event"===u){const e=l.event,t=l.payload;if("connect.challenge"===e){const e=Date.now();this.emit("transport",{event:"handshake.challenge_recv",durationMs:e-n});const s=t?.nonce;o=this._sendConnect(s),this.emit("transport",{event:"handshake.connect_sent",durationMs:Date.now()-n}),r?.();let i=0;const c=setInterval(()=>{i++},200),a=Date.now(),h=setInterval(()=>{const e=Date.now()-a,t=e-200*i;t>500&&this.emit("transport",{event:"eventloop_lag",lagMs:t,elapsedMs:e,probeSeq:i})},200);let l;const d=()=>{clearInterval(c),clearInterval(h),l&&clearTimeout(l),this.off("connected",d),r===d&&(r=void 0)};r=d,l=setTimeout(d,3e4),this.once("connected",d)}else"chat"===e?this.emit("chat",t):"agent"===e?this.emit("agent",t):"cron"===e?this.emit("cron",t):"canvas"===e?this.emit("canvas",t):"session.message"===e?this.emit("sessionMessage",t):this.emit("gateway-event",e,t)}else if("hello-ok"===u)this.emit("transport",{event:"handshake.hello_ok_recv",durationMs:Date.now()-n}),a(l);else if("hello-error"===u||"connect-error"===u)h("Authentication rejected by Gateway");else if("res"===u){const e=l.id;if(e&&e===o){if(this.emit("transport",{event:"handshake.connect_res_recv",ok:!!l.ok,durationMs:Date.now()-n}),l.ok){const e=l.payload;a(e??l)}else{const e=l.error,r=new GatewayHandshakeError(e);r.retryable?(clearTimeout(c),this.emit("transport",{event:"connect_fail",reason:r.message,retryable:!0,retryAfterMs:r.retryAfterMs,durationMs:Date.now()-n}),"number"==typeof r.retryAfterMs&&r.retryAfterMs>0&&(this.nextReconnectDelayHintMs=r.retryAfterMs),s.close(),t(r)):h(r)}return}const r=this.pending.get(e);if(r)if(this.pending.delete(e),clearTimeout(r.timer),l.ok)r.resolve(l.payload);else{const e=l.error;r.reject(new Error(e?.message||"Gateway request failed"))}else this.emit("response",l)}}),s.on("pong",()=>{this.lastPongTs=Date.now()}),s.on("close",e=>{const s=i;r?.(),this.stopHeartbeat(),this.clearReconnectNotify(),this.emit("transport",{event:"close",code:e,durationMs:Date.now()-n}),this.connected=!1,this.connectPromise=null;for(const[,e]of this.pending)clearTimeout(e.timer),e.reject(new Error("Connection closed"));this.pending.clear(),s||(clearTimeout(c),t(new Error(`Connection closed during handshake (code=${e})`))),4001===e&&(this.authFailed=!0,this.emit("auth-failed",{code:e})),s&&this.emit("disconnected"),this.stopped||this.authFailed||this.scheduleReconnect()}),s.on("error",e=>{this.emit("transport",{event:"error",message:e.message,durationMs:Date.now()-n}),this.stopped?clearTimeout(c):(this.connected||(clearTimeout(c),t(e)),this.emit("error",e))})})}emitMessageHash(e){if(e.length<32)return;const t=createHash("sha256").update(e).digest("hex").slice(0,16);this.emit("transport",{event:"message_recv",hash:t,size:e.length})}startHeartbeat(){this.stopHeartbeat(),this.lastPongTs=Date.now(),this.heartbeatTimer=setInterval(()=>{if(!this.ws||!this.connected)return;try{this.ws.ping()}catch{}const e=Date.now()-this.lastPongTs;e>6e4&&(this.emit("liveness-timeout",{elapsed:e}),this.ws.close())},15e3),"object"==typeof this.heartbeatTimer&&"unref"in this.heartbeatTimer&&this.heartbeatTimer.unref()}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}isReconnectNotification(e){return"server/reconnect"===e||e.endsWith("/reconnect")}scheduleReconnectNotify(){this.clearReconnectNotify();const e=6e4+12e4*Math.random();this.emit("reconnect-notify-scheduled",{delayMs:Math.round(e)}),this.reconnectNotifyTimer=setTimeout(()=>{this.reconnectNotifyTimer=null,!this.stopped&&this.connected&&(this.emit("reconnect-notify-fired"),this.reconnectNow())},e),"object"==typeof this.reconnectNotifyTimer&&"unref"in this.reconnectNotifyTimer&&this.reconnectNotifyTimer.unref()}clearReconnectNotify(){this.reconnectNotifyTimer&&(clearTimeout(this.reconnectNotifyTimer),this.reconnectNotifyTimer=null)}scheduleReconnect(){if(this.stopped)return;if(this.reconnectTimer)return;const e=this.config.retry??{baseMs:1e3,maxMs:6e5,maxAttempts:0};if(e.maxAttempts>0&&this.reconnectAttempt>=e.maxAttempts)return void this.emit("reconnect-exhausted",this.reconnectAttempt);let t;const n=this.nextReconnectDelayHintMs,s=null!==n&&n>0;s?(t=Math.min(n,e.maxMs),this.nextReconnectDelayHintMs=null):(t=Math.min(e.baseMs*Math.pow(2,this.reconnectAttempt)+500*Math.random(),e.maxMs),this.reconnectAttempt++),this.emit("reconnecting",{attempt:s?this.reconnectAttempt+1:this.reconnectAttempt,delayMs:t}),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.stopped||this.connect().catch(e=>{this.emitReconnectFailure(e)})},t),"object"==typeof this.reconnectTimer&&"unref"in this.reconnectTimer&&this.reconnectTimer.unref()}reconnectNow(){this.stopped||(this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.close(),this.reconnectAttempt=0,this.connect().catch(e=>{this.emitReconnectFailure(e)}))}emitReconnectFailure(e){this.stopped||this.authFailed||this.emit("error",e instanceof Error?e:new Error(String(e)))}_sendConnect(e){const t=Date.now(),n=Date.now(),s="operator",r=["operator.admin","operator.approvals","operator.pairing"],o={id:this.deviceIdentity.deviceId,publicKey:this.deviceIdentity.publicKeyB64url,signedAt:n};if(e){const t=Date.now(),i=buildDeviceAuthPayload({deviceId:this.deviceIdentity.deviceId,clientId:"cli",clientMode:"cli",role:s,scopes:r,signedAtMs:n,token:this.config.token,nonce:e}),c=Date.now()-t,a=Date.now();o.nonce=e,o.signature=signDeviceAuth(this.deviceIdentity,i);const h=Date.now()-a;this.emit("transport",{event:"handshake.sign_done",buildPayloadMs:c,signMs:h})}const i=randomUUID(),c={type:"req",id:i,method:"connect",params:{minProtocol:3,maxProtocol:4,client:{id:"cli",displayName:"BeeOS Platform Bridge",version:"0.1.0",platform:"beeos",mode:"cli"},caps:this.config.openclawCanvasCompat?["tool-events","approvals","canvas"]:["tool-events","approvals"],role:s,scopes:r,auth:{token:this.config.token},device:o}},a=Date.now(),h=JSON.stringify(c),l=Date.now()-a,d=Date.now();this.ws?.send(h);const u=Date.now()-d;return this.emit("transport",{event:"handshake._sendConnect_done",totalMs:Date.now()-t,serializeMs:l,sendMs:u}),i}async request(e,t,n=6e4){if(!this.ws||!this.connected)throw new Error("Not connected to Gateway");const s=randomUUID(),r={type:"req",id:s,method:e,params:t};return new Promise((t,o)=>{const i=setTimeout(()=>{this.pending.delete(s),o(new Error(`Gateway request timeout: ${e}`))},n);this.pending.set(s,{resolve:t,reject:o,timer:i}),this.ws.send(JSON.stringify(r))})}async agentSend(e,t,n,s,r){const o={agentId:n,sessionKey:e,message:t,deliver:!1,idempotencyKey:randomUUID()};s?.length&&(o.attachments=s),r&&(o.inputProvenance=r);return await this.request("agent",o,12e4)}async chatSend(e,t,n){const s={sessionKey:e,message:t,deliver:!1,idempotencyKey:randomUUID()};n?.length&&(s.attachments=n);return await this.request("chat.send",s,12e4)}async chatAbort(e,t){const n={sessionKey:e};t&&(n.runId=t);return decodeChatAbortResult(await this.request("chat.abort",n))}sendFrame(e){if(!this.ws||!this.connected)return!1;try{return this.ws.send(JSON.stringify(e)),!0}catch{return!1}}agentCancel(e,t){const n={sessionKey:e};t?.runId&&(n.runId=t.runId);const s=`abort_${t?.runId??t?.requestId??e}`;return this.sendFrame({type:"req",id:s,method:"chat.abort",params:n})}async chatHistory(e,t){return this.request("chat.history",{sessionKey:e,limit:t})}async chatHistoryPage(e,t){const n=wsUrlToHttpBase(this.config.url);if(!n)return null;let s;try{s=new URL(`${n}/sessions/${encodeURIComponent(e)}/history`)}catch{return null}null!=t?.limit&&s.searchParams.set("limit",String(t.limit)),t?.cursor&&s.searchParams.set("cursor",t.cursor);try{const e=await fetch(s,{method:"GET",headers:{accept:"application/json",authorization:`Bearer ${this.config.token}`},signal:AbortSignal.timeout(1e4)});if(!e.ok)return null;const t=await e.json(),n=Array.isArray(t.messages)?t.messages:Array.isArray(t.items)?t.items:[];return{messages:n.filter(e=>"object"==typeof e&&null!==e),nextCursor:"string"==typeof t.nextCursor&&t.nextCursor.length>0?t.nextCursor:void 0,hasMore:!0===t.hasMore}}catch{return null}}async sessionsMessagesSubscribe(e){return this.request("sessions.messages.subscribe",{key:e})}async sessionsMessagesUnsubscribe(e){return this.request("sessions.messages.unsubscribe",{key:e})}async skillsStatus(e){return this.request("skills.status",e?{agentId:e}:{})}async sessionsList(){return this.request("sessions.list",{includeDerivedTitles:!0})}async sessionsResolve(e){return this.request("sessions.resolve",{sessionKey:e})}async sessionsPatch(e,t){return this.request("sessions.patch",{key:e,...t})}async sessionsDelete(e){return this.request("sessions.delete",{key:e})}async sessionsReset(e){return this.request("sessions.reset",{key:e,reason:"new"})}close(){if(this.ws)try{this.ws.close()}catch{}this.ws=null,this.connected=!1,this.connectPromise=null,this._currentConnectionId=null}get isConnected(){return this.connected}waitForConnected(e=3e4){return waitForGatewayConnected(this,e)}get connectionSeq(){return this._connectionSeq}get currentConnectionId(){return this._currentConnectionId}get lastReadyAt(){return this._lastReadyAt}}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{claimedSandboxId,identityLaneFromEnvironment}from"./runtime/identity-lane-lease.js";import{createCentralNativeComposition,requireCentralNativeSessionHost}from"./runtime/central-native-composition.js";import{createSandboxNativeTargetLookup,registerSandboxNativeActivation}from"./runtime/sandbox-native-activation.js";import{registerCentralNativeMemoryTools}from"./runtime/central-native-memory.js";import{harnessConnectorToolCaller}from"./connectors/harness-connector-mcp.js";import{registerCentralNativeContextEngine,centralNativeChatEnabled}from"./runtime/central-native-runtime.js";import{relayCentralAskUser}from"./runtime/central-native-interactions.js";import{consumeNativeOutputTool,nativeHtmlDeliveryForRun}from"./runtime/native-output-file-attempt.js";import{uploadNativeOutputFile}from"./upload/upload-file.js";import{nativeOutputToolCallGate}from"./upload/native-output-tool-hook.js";import{NativeInputFilesHttpClient}from"./runtime/native-input-files-http.js";import{fileDeliveryFinalizeDecision}from"./upload/finalize-hook.js";import{resolveConfigWithMeta,mirrorOpenClawConfig}from"./config.js";import{hasRuntimeReplyApi}from"./runtime/reply-router.js";import{PromptRunStore}from"./runtime/prompt-run-store.js";import{createMcpNativeProjectionNudge,fingerprintMcpServers}from"./acp-gateway/mcp-native-projection-nudge.js";import{createImHotPathDeferral}from"./runtime/im-hot-path-deferral.js";import{SessionWriteGate}from"./acp-gateway/session-write-gate.js";import{OpenClawSessionWriteQuiescence}from"./runtime/openclaw-session-write-quiescence.js";import{SessionMutationCoordinator}from"./runtime/session-mutation-coordinator.js";import{scheduleProcessRuntimeRestart}from"./runtime/runtime-restart-scheduler.js";import{createImInboundHandler}from"./im-inbound-handler.js";import{AgentGatewayClient,NodeRuntimeDeliveryPort,agentIdentityFromKeyPair,loadAgentKeyPair,signAgentMessage}from"@beeos-ai/cloud-harness-sdk";import{MessageServiceConversationRunBoundary}from"./runtime/message-service-conversation-run-boundary.js";import{AutomationTurnPolicy}from"./automation/turn-policy.js";import{registerAutomationTools}from"./automation/tools.js";import{extractBeeosConversationIdFromSessionKey}from"./runtime/openclaw-session-key-resolution.js";import{setOpenClawConfigSnapshot}from"./runtime/openclaw-session-model.js";import{BeeosClawMessageClientProcessOwner,createBeeosClawMessageTokenProvider}from"./message-client-composition.js";import{MessageProjectionInboundConsumer}from"./message-projection-inbound-consumer.js";import{MessageClientTerminalStateRecovery}from"./runtime/message-client-terminal-state-recovery.js";import{RuntimeAuthorityMessageBusLifecycle}from"./runtime/runtime-authority-message-bus-lifecycle.js";import{createNativeCloudChatComposition,nativeCloudChatAuthorityFromRuntimeAuthority}from"./runtime/native-cloud-chat-composition.js";import{MSConnectionStatusSnapshot}from"./runtime/ms-connection-status.js";import{FileInboundExecutionJournal}from"./inbound-execution-journal.js";import{completeA2ATask,registerA2ATools,TaskHandleRegistry}from"./a2a/tools.js";import{BEEOS_UPLOAD_TOOL_NAME,BEEOS_UPLOAD_TOOL_SCHEMA,BEEOS_UPLOAD_TOOL_DESCRIPTION,REQUEST_TIMEOUT_MS as BEEOS_UPLOAD_REQUEST_TIMEOUT_MS,executeUpload}from"./upload/tool.js";import{BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,BEEOS_DESKTOP_SCREENSHOT_TOOL_SCHEMA,BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION,executeDesktopScreenshot}from"./upload/desktop-screenshot-tool.js";import{BEEOS_LIST_FILES_TOOL_NAME,BEEOS_LIST_FILES_TOOL_SCHEMA,BEEOS_LIST_FILES_TOOL_DESCRIPTION,executeListFiles}from"./files/list-tool.js";import{BEEOS_FETCH_FILE_TOOL_NAME,BEEOS_FETCH_FILE_TOOL_SCHEMA,BEEOS_FETCH_FILE_TOOL_DESCRIPTION,executeFetchFile}from"./files/fetch-tool.js";import{writeUploadToolResult,cleanupUploadToolResultCache}from"./upload/result-cache.js";import{handleFileStage}from"./upload/file-stage.js";import{handleStatusRequest}from"./status.js";import{ACPServer}from"./acp-server.js";import{GatewayClient}from"./gateway-client.js";import{createObsEventWriter}from"./observability.js";import{resolvePluginVersion}from"./plugin-version.js";import{createTerminalWebSocketService}from"./terminal/websocket.js";import{TerminalManager}from"./terminal/session-manager.js";import{readDiscoveryCache,writeDiscoveryCache}from"./discovery-cache.js";import{setClaimedCloudRuntimeInstanceId,setUploadDeps}from"./upload/upload-file.js";import{registerLocalFileExtractor}from"./upload/local-file-extractors.js";import{browserScreenshotExtractor}from"./browser/screenshot-extractor.js";import{deliverableFileExtractor}from"./upload/deliverable-extractor.js";import{observeToolCallForDelivery,rememberDeliveryWorkspace}from"./upload/delivery-observe.js";import{BEEOS_FILE_RESOURCE_ROUTING_RULE}from"./files/beeos-file-uri.js";import{marksFullRuntimeRegistered,planPluginRegistration,replayCachedPluginTools,resolveCapabilityToolReplay}from"./plugin-registration-plan.js";import{buildAppendSystemContext,buildToolRoutingHint,canvasToolBlockReason}from"./prompt-system-context.js";import{CanvasStateManager}from"./canvas/state.js";import{createStaticCanvasHtmlPublisher}from"./canvas/static-html.js";import{CanvasRelayClient}from"./canvas/relay-client.js";import{createSandboxCanvasTokenProvider}from"./canvas/runtime-lease-token.js";import{createCanvasRelayService}from"./canvas/relay-service.js";import{RENDER_UI_TOOL_NAME,RENDER_UI_TOOL_DESCRIPTION,RENDER_UI_TOOL_SCHEMA,CLOSE_UI_TOOL_NAME,CLOSE_UI_TOOL_DESCRIPTION,CLOSE_UI_TOOL_SCHEMA,createRenderUiToolExecutor,createCloseUiHandler,CANVAS_PRESENTATION_GATE,CANVAS_SYSTEM_PROMPT}from"./canvas/tools.js";import{FormSchemaRegistry}from"./surface/form-schema-registry.js";import{buildCronSchemas}from"./surface/cron-schemas.js";import{RENDER_FORM_TOOL_NAME,RENDER_FORM_TOOL_SCHEMA,buildRenderFormDescription,createRenderFormHandler}from"./surface/render-form-tool.js";import{ResourceDescriptorRegistry}from"./surface/resource-descriptor-registry.js";import{CRON_RESOURCE}from"./surface/cron-resource.js";import{generateActionTools}from"./surface/action-tool-generator.js";import{buildThirdPartyChannelSet,isThirdPartyChannel}from"./channel-detection.js";import{registerArouterMediaProviders}from"./media/index.js";import{homedir}from"node:os";import{join}from"node:path";import{RuntimeProductionAuthority,cloudRuntimeTargetInstanceId}from"./runtime/runtime-production-authority.js";import{FileRuntimeCommandJournal}from"./runtime/runtime-command-journal.js";import{FileRuntimePoisonDeliveryJournal}from"./runtime/runtime-poison-delivery-journal.js";import{OpenClawNativeMcpProjection}from"./acp-gateway/openclaw-native-mcp-projection.js";import{LocalEncryptedCredentialReferenceVault}from"./acp-gateway/mcp-credential-reference-port.js";import{AgentGatewayGrantJwksReadinessAdapter,CloudRuntimeServiceTransportReadinessAdapter,RuntimeServiceTransportReadinessAdapter,createRuntimeServiceProductionCandidate}from"./runtime/runtime-service-production-candidate.js";import{fetchRuntimeLeaseAttempt}from"./runtime/message-service-runtime-authenticated-fetch.js";import{MessageServiceCronDeliveryHttpAuthority}from"./runtime/message-service-cron-delivery-http-authority.js";import{AgentMappingRegistry}from"./runtime/agent-mapping-registry.js";import{OpenClawRuntimeProcessOwner}from"./runtime/openclaw-runtime-process-owner.js";import{AgentGatewayHttpProjectionTransport,AgentGatewayTemplateOriginReporter,AgentProjectionProduction,OpenClawAgentProjectionSource}from"./runtime/agent-projection-production.js";import{MessageServiceRunOutputChannel}from"./runtime/message-service-run-output-channel.js";import{AssistantMessageCommitRouter}from"./runtime/assistant-message-commit-router.js";import{OpenClawApprovalBridge}from"./approval/bridge.js";import{APPROVAL_DECISION_MESSAGE_TYPE,isApprovalDocument}from"./approval/protocol.generated.js";import{isQuestionResponseDocument,OpenClawQuestionBridge}from"./question/bridge.js";import{ToolResultObservationRouter}from"./runtime/tool-result-observation-router.js";import{ModelCallObservationRouter,registerModelCallObservationHooks}from"./runtime/model-call-observability.js";import{registerArouterLatencyRouting}from"./runtime/arouter-latency-routing.js";import{createPeerRunOutputRouterFactory}from"./runtime/run-output-composition.js";const PLUGIN_VERSION=resolvePluginVersion();let agentKeys=null,agentGateway=null,sharedCanvasState=null,sharedAcpServer=null;const sharedSessionWriteGate=new SessionWriteGate,sharedPromptRunStore=new PromptRunStore,sharedAutomationTurnPolicy=new AutomationTurnPolicy;let lastOpenclawConfig;const sharedMcpNativeProjectionNudge=createMcpNativeProjectionNudge({getActiveImRunCount:()=>sharedPromptRunStore.size(),nudge:()=>{sharedAcpServer?.nudgeMcpNativeProjection()}}),sharedImHotPathDeferral=createImHotPathDeferral({getActiveImRunCount:()=>sharedPromptRunStore.size()});sharedPromptRunStore.setOnBecameIdle(()=>{sharedMcpNativeProjectionNudge.flushIfIdle({fingerprint:fingerprintMcpServers(lastOpenclawConfig)}),sharedImHotPathDeferral.notifyIdle()});const sharedAssistantMessageCommitRouter=new AssistantMessageCommitRouter,sharedToolResultObservationRouter=new ToolResultObservationRouter;let approvalLogger;const sharedApprovalBridge=new OpenClawApprovalBridge({request:(e,t)=>sharedGatewayClient?sharedGatewayClient.request(e,t):Promise.reject(new Error("Not connected to Gateway")),logger:{info:e=>approvalLogger?.info?.(e),warn:e=>approvalLogger?.warn?.(e)}}),sharedQuestionBridge=new OpenClawQuestionBridge({request:(e,t)=>sharedGatewayClient?sharedGatewayClient.request(e,t):Promise.reject(new Error("Not connected to Gateway")),logger:{info:e=>approvalLogger?.info?.(e),warn:e=>approvalLogger?.warn?.(e)}}),sharedModelCallObservationRouter=new ModelCallObservationRouter;let sharedSessionMutationCoordinator,sharedCentralPrompt,sharedRuntimeAuthority,sharedNativeChatService,sharedNativeCloudChat,sharedWriteObs=()=>{};const sharedMSConnectionStatus=new MSConnectionStatusSnapshot,sharedAgentMappings=new AgentMappingRegistry;let sharedGatewayClient,sharedRuntimeOwner,sharedAgentProjection,sharedRuntimeAgentCapabilities,sharedMcpProjection,sharedMcpCredentialVault;const sharedMessageClientOwner=new BeeosClawMessageClientProcessOwner;let sharedActiveMessageConsumer,sharedInboundExecutionJournal;const sharedTerminalManager=new TerminalManager;let _initializing=!1,_pluginRegisteredAt=0,_fullRuntimeRegistered=!1;const cachedCapabilityTools=[];let rawRegisterTool,wrappedRegisterTool;const cachedRuntimeServices=[],cachedRuntimeHooks=[];let rawRegisterService,wrappedRegisterService,rawOn,wrappedOn;function cacheRuntimeRegistrations(e){const t=e.registerService===wrappedRegisterService?rawRegisterService:e.registerService;if(rawRegisterService=t,wrappedRegisterService=r=>{cachedRuntimeServices.push(r),t.call(e,r)},e.registerService=wrappedRegisterService,cachedRuntimeServices.length=0,cachedRuntimeHooks.length=0,e.on){const t=e.on===wrappedOn?rawOn:e.on;rawOn=t,wrappedOn=(...r)=>{cachedRuntimeHooks.push(r),t.call(e,...r)},e.on=wrappedOn}}function replayRuntimeRegistrations(e){const t=e.registerService===wrappedRegisterService?rawRegisterService:e.registerService,r=e.on===wrappedOn?rawOn:e.on;for(const t of cachedRuntimeHooks)r.call(e,...t);for(const r of cachedRuntimeServices)t.call(e,r)}const ensureRegisterToolCache=e=>{const t=e.registerTool===wrappedRegisterTool?rawRegisterTool:e.registerTool;rawRegisterTool=t.bind(e),wrappedRegisterTool=(e,t)=>(cachedCapabilityTools.push({tool:e,options:t}),rawRegisterTool(e,t)),e.registerTool=wrappedRegisterTool};function agentKeyPairToIdentity(e){return{publicKeyBase64:()=>Buffer.from(e.publicKey).toString("base64"),sign:async t=>signAgentMessage(t,e.privateKey)}}let sharedPluginContext=null,unhandledRejectionObserverInstalled=!1;function installUnhandledRejectionObserver(e,t,r){unhandledRejectionObserverInstalled||(unhandledRejectionObserverInstalled=!0,process.on("unhandledRejection",r=>{const o=r instanceof Error?r.message:String(r),a=r instanceof Error?r.stack:void 0;e.logger.error?.(`[beeos-claw] unhandledRejection: ${o}${a?`\n${a}`:""}`),t({component:"plugin",domain:"fatal",name:"unhandled_rejection",severity:"error",summary:o,error:{code:"unhandled_rejection",message:o,...a?{stack:a}:{}}})}),process.on("uncaughtException",r=>{const o=r instanceof Error?r.message:String(r);e.logger.error?.(`[beeos-claw] uncaughtException: ${r instanceof Error?r.stack??r.message:String(r)}`),t({component:"plugin",domain:"fatal",name:"uncaught_exception",severity:"error",summary:o,error:{code:"uncaught_exception",message:o}})}))}function initializePlugin(e){let t,r;try{t=e.runtime?.config?.loadConfig?.()}catch{}try{r=resolveConfigWithMeta({pluginConfig:e.pluginConfig??{},openclawConfig:t})}catch(t){return e.logger.error?.(`[beeos-claw] Failed to resolve config: ${t instanceof Error?t.message:String(t)}`),null}const o=r.config,a=buildThirdPartyChannelSet(t);a.size>0&&e.logger.info?.(`[beeos-claw] Third-party channels detected: ${[...a].join(", ")}`);const n=o.log.enabled?createObsEventWriter({dir:o.log.dir,redaction:{gatewayToken:o.gateway.token},logger:e.logger}):()=>{};n({component:"plugin",domain:"lifecycle",name:"lifecycle.startup",severity:"info",payload:{pluginVersion:PLUGIN_VERSION,pid:process.pid,nodeVersion:process.version,cwd:process.cwd()}}),n({component:"plugin",domain:"config",name:"config.resolved",severity:"info",payload:{config:o,sources:r.sources,openclawConfigPath:r.openclawConfigPath}});for(const t of r.validation)n({component:"plugin",domain:"config",name:"config.validation",severity:t.severity,summary:t.message,error:{code:t.code,message:t.message,nextSteps:t.nextSteps}}),"error"===t.severity?e.logger.error?.(`[beeos-claw] ${t.message}`):e.logger.warn?.(`[beeos-claw] ${t.message}`);if(r.validation.some(e=>"error"===e.severity)&&e.logger.error?.("[beeos-claw] Plugin has configuration errors — some features may not work."),o.keyFile)try{agentKeys=loadAgentKeyPair(o.keyFile),agentGateway=o.agentGatewayUrl?new AgentGatewayClient({baseUrl:o.agentGatewayUrl,identity:agentIdentityFromKeyPair(agentKeys),onRetry:({method:t,path:r,attempt:o,delayMs:a,error:n})=>e.logger.warn?.(`[beeos-claw] Agent Gateway ${t} ${r} retry ${o} in ${a}ms: ${n instanceof Error?n.message:String(n)}`)}):null;const t=Buffer.from(agentKeys.publicKey).toString("base64");e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (publicKey: ${t})`)}catch(t){e.logger.warn?.(`[beeos-claw] Failed to load agent key pair: ${t}`),e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (no key pair — signed requests disabled)`)}else e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (no keyFile configured)`);return agentGateway&&(setUploadDeps({gateway:agentGateway,logger:e.logger}),registerLocalFileExtractor(browserScreenshotExtractor),registerLocalFileExtractor(deliverableFileExtractor),e.logger.info?.("[beeos-claw] Upload deps + local file extractors registered")),lastOpenclawConfig=t,sharedWriteObs=n,setOpenClawConfigSnapshot(t),{cfg:o,writeObs:n,thirdPartyChannels:a,openclawConfig:t}}function registerUploadTools(e,t,r){const{cfg:o,writeObs:a}=t,n=Boolean(pluginCloudRuntimeTarget(e));if(n){if(!e.on)throw new Error("native output Files Host hook unavailable");e.on("before_tool_call",nativeOutputToolCallGate)}cleanupUploadToolResultCache().catch(t=>{e.logger.warn?.(`[beeos_upload_file] cache cleanup failed on startup: ${String(t)}`)}),e.registerTool({name:BEEOS_UPLOAD_TOOL_NAME,description:BEEOS_UPLOAD_TOOL_DESCRIPTION,parameters:BEEOS_UPLOAD_TOOL_SCHEMA,async execute(t,r,i){const s=n?consumeNativeOutputTool(t):void 0,l=await executeUpload(r,agentGateway,i,s?(e,t)=>uploadNativeOutputFile(e,o.agentGatewayUrl,s,t,i,BEEOS_UPLOAD_REQUEST_TIMEOUT_MS):void 0,e.logger);return e.logger.debug?.(`[beeos_upload_file] toolCallId=${t} ok=${l.ok}`),a({component:"upload-tool",domain:"tool",name:l.ok?"upload.success":"upload.failure",severity:l.ok?"info":"warn",payload:{toolCallId:t,ok:l.ok,fileCount:l.files?.length??0,error:l.error}}),(async r=>{try{await writeUploadToolResult(t,BEEOS_UPLOAD_TOOL_NAME,r),await cleanupUploadToolResultCache()}catch(r){e.logger.warn?.(`[beeos_upload_file] persist cache failed toolCallId=${t}: ${String(r)}`)}return r})(l)}}),e.registerTool({name:BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,description:BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION,parameters:BEEOS_DESKTOP_SCREENSHOT_TOOL_SCHEMA,async execute(t,r,o){e.logger.debug?.(`[beeos_desktop_screenshot] toolCallId=${t} params=${JSON.stringify(r)}`);const n=await executeDesktopScreenshot(r,agentGateway,o);return e.logger.debug?.(`[beeos_desktop_screenshot] toolCallId=${t} ok=${n.ok}`),a({component:"desktop-screenshot-tool",domain:"tool",name:n.ok?"desktop_screenshot.success":"desktop_screenshot.failure",severity:n.ok?"info":"warn",payload:{toolCallId:t,ok:n.ok,path:n.path,fileCount:n.files?.length??0,error:n.error}}),(async r=>{try{await writeUploadToolResult(t,BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,r),await cleanupUploadToolResultCache()}catch(r){e.logger.warn?.(`[beeos_desktop_screenshot] persist cache failed toolCallId=${t}: ${String(r)}`)}return r})(n)}}),e.registerHttpRoute({path:"/beeos/files/stage",auth:"gateway",async handler(e,r){await handleFileStage(e,r,t.cfg)}}),e.registerHttpRoute({path:"/beeos/status",auth:"plugin",handler(e,t){handleStatusRequest(e,t,{publicKey:agentKeys?.publicKey??null,pluginVersion:PLUGIN_VERSION})}}),e.registerTool({name:BEEOS_LIST_FILES_TOOL_NAME,description:BEEOS_LIST_FILES_TOOL_DESCRIPTION,parameters:BEEOS_LIST_FILES_TOOL_SCHEMA,async execute(t,r,o){e.logger.debug?.(`[beeos_list_files] toolCallId=${t} params=${JSON.stringify(r)}`);const n=await executeListFiles(r,agentGateway,o);return a({component:"file-list-tool",domain:"tool",name:n.ok?"list_files.success":"list_files.failure",severity:n.ok?"info":"warn",payload:{toolCallId:t,ok:n.ok,fileCount:n.files?.length??0,error:n.error}}),n}}),e.registerTool(t=>({name:BEEOS_FETCH_FILE_TOOL_NAME,description:BEEOS_FETCH_FILE_TOOL_DESCRIPTION,parameters:BEEOS_FETCH_FILE_TOOL_SCHEMA,async execute(r,i,s){e.logger.debug?.(`[beeos_fetch_file] toolCallId=${r} params=${JSON.stringify(i)}`);const l=await executeFetchFile(i,agentGateway,{signal:s,workspaceDir:t.workspaceDir,...n?{native:{gatewayUrl:o.agentGatewayUrl,capability:consumeNativeOutputTool(r)}}:{}});return a({component:"file-fetch-tool",domain:"tool",name:l.ok?"fetch_file.success":"fetch_file.failure",severity:l.ok?"info":"warn",payload:{toolCallId:r,ok:l.ok,path:l.path,size:l.size,error:l.error}}),l}}),{name:BEEOS_FETCH_FILE_TOOL_NAME})}function registerServices(e,t,r){const{cfg:o,writeObs:a,thirdPartyChannels:n}=t,i=centralNativeChatEnabled()?requireCentralNativeSessionHost(e.runtime):void 0;if(sharedAutomationTurnPolicy.disable(),"function"==typeof e.on)try{e.on("before_tool_call",(e,t)=>sharedAutomationTurnPolicy.check(e.toolName,{sessionKey:t?.sessionKey,runId:t?.runId??e.runId}),{priority:100}),sharedAutomationTurnPolicy.enable()}catch{e.logger.warn?.("[beeos-claw] Automation Wake disabled: tool guard unavailable")}if("function"!=typeof e.on){if(o.messageBus.enabled)throw new Error("openclaw_before_message_write_hook_unavailable")}else registerModelCallObservationHooks((t,r)=>e.on(t,r),sharedModelCallObservationRouter),e.on("before_message_write",(t,r)=>{const o=t.sessionKey??r.sessionKey;if(!o)return void e.logger.debug?.("[before_message_write] ignored assistant write without sessionKey");sharedAssistantMessageCommitRouter.route(o,t.message)||e.logger.debug?.(`[before_message_write] no active IM commit target sessionKey=${o} active_targets=${sharedAssistantMessageCommitRouter.size()}`)}),e.on("before_tool_call",(e,t)=>{if("ask_user"!==(e.toolName||t.toolName))return;const r={sessionKey:t.sessionKey,runId:t.runId??e.runId,toolCallId:t.toolCallId??e.toolCallId};sharedQuestionBridge.observeAskUser(r),relayCentralAskUser((e,t)=>sharedGatewayClient?sharedGatewayClient.request(e,t):Promise.reject(new Error("Not connected to Gateway")),r).catch(e=>approvalLogger?.warn?.(`[question] central relay failed: ${e instanceof Error?e.message:String(e)}`))}),e.on("after_tool_call",(t,r)=>{const o=r.sessionKey,a=t.toolCallId??r.toolCallId,n=t.toolName||r.toolName;if(t.runId&&r.runId&&t.runId!==r.runId||t.toolCallId&&r.toolCallId&&t.toolCallId!==r.toolCallId||nativeHtmlDeliveryForRun(t.runId??r.runId)?.observe(n,t.params,t.result,Boolean(t.error),a),!o||!a||!n)return void e.logger.debug?.(`[after_tool_call] ignored structured result without correlation sessionKey=${o??"missing"} toolCallId=${a??"missing"}`);observeToolCallForDelivery(t,o);sharedToolResultObservationRouter.route(o,{toolCallId:a,toolName:n,rawResult:t.result,isError:Boolean(t.error)})||e.logger.debug?.(`[after_tool_call] no active IM observation target sessionKey=${o} active_targets=${sharedToolResultObservationRouter.size()}`)});const s=agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):void 0,l=join(process.env.OPENCLAW_HOME||join(homedir(),".openclaw"),"beeos"),c=sharedInboundExecutionJournal??=new FileInboundExecutionJournal(join(l,"inbound-execution-journal.v1.jsonl"));sharedMcpProjection??=new OpenClawNativeMcpProjection,!sharedMcpCredentialVault&&agentKeys&&s&&(sharedMcpCredentialVault=new LocalEncryptedCredentialReferenceVault(join(l,"mcp-credential-vault.json"),s,agentKeys.privateKey));const u=pluginCloudRuntimeTarget(e);if(setClaimedCloudRuntimeInstanceId(u),u&&(!agentKeys||!agentGateway))throw new Error("Cloud runtime authority requires an agent identity and gateway transport");const d=sharedRuntimeAuthority?.cloudTargetInstanceId;if(d&&u&&d!==u)throw new Error("Cloud runtime authority target changed during process lifetime");if(sharedRuntimeAuthority&&!d&&u&&sharedRuntimeAuthority.bindCloudTarget(u),!sharedRuntimeAuthority&&agentKeys&&agentGateway&&(sharedRuntimeAuthority=new RuntimeProductionAuthority({stateDirectory:l,gateway:agentGateway,keys:agentKeys,targetInstanceId:u,logger:e.logger,getMSConnectionStatus:e=>sharedMSConnectionStatus.get(e),identityLane:identityLaneFromEnvironment()})),sharedGatewayClient||(sharedGatewayClient=new GatewayClient({url:o.gateway.url,token:o.gateway.token||"",clientId:o.gateway.clientId,openclawCanvasCompat:!!o.openclawCanvasCompat,retry:{baseMs:o.retry.baseMs,maxMs:o.retry.maxMs,maxAttempts:o.retry.maxAttempts}}),sharedGatewayClient.on("gateway-event",(e,t)=>{sharedApprovalBridge.onGatewayEvent(e,t),sharedQuestionBridge.onGatewayEvent(e,t)})),approvalLogger??=e.logger,sharedRuntimeAgentCapabilities??={canvas:o.canvasEnabled,terminal:!1,webSsh:!1,fileSystem:!0,image:!0,audio:!1,mcp:!0,cron:!0,streaming:!0,pushNotifications:o.messageBus.enabled,...o.messageBus.enabled&&sharedAutomationTurnPolicy.isReady()&&agentGateway?{automationWake:!0}:{}},!sharedAgentProjection&&sharedRuntimeAuthority&&agentGateway){const t=sharedRuntimeAuthority;sharedAgentProjection=new AgentProjectionProduction({authority:t,stateFile:join(t.stateDirectory,"runtime-agent-projection.json"),journal:t.journal,identities:t.identities,source:new OpenClawAgentProjectionSource(()=>sharedGatewayClient),transport:new AgentGatewayHttpProjectionTransport({gateway:agentGateway,getRuntimeLeaseCredential:e=>{const r=t.authorityLease;if(!r||r.instanceId!==e.instanceId||r.leaseId!==e.leaseId||r.runtimeEpoch!==e.runtimeEpoch||r.handlerIdentity!==e.handlerIdentity)throw new Error("agent projection fenced by current runtime lease");return r.runtimeLeaseCredential},onAccepted:t=>{0!==t.size&&sharedAgentMappings.replace(t).catch(t=>{e.logger.warn?.("[agent-projection] mapping publication failed: "+(t instanceof Error?t.message:String(t)))})}}),capabilities:sharedRuntimeAgentCapabilities,logger:e.logger})}sharedRuntimeOwner??=new OpenClawRuntimeProcessOwner(sharedGatewayClient,sharedAgentProjection,e.logger);const g=sharedRuntimeOwner;sharedSessionMutationCoordinator??=new SessionMutationCoordinator(sharedSessionWriteGate,new OpenClawSessionWriteQuiescence(e.logger,{agentId:o.gateway.agentId||"main",...i?{nativeWritersQuiescent:e=>i.nativeWritersQuiescent({sessionKey:e})}:{}}),e.logger,{onRecoveryRequired:t=>{scheduleProcessRuntimeRestart(t,e.logger)}});const m=sharedSessionMutationCoordinator;if(i&&!sharedCentralPrompt){if(!sharedRuntimeAuthority?.cloudTargetInstanceId)throw new Error("central native chat requires the provisioned Cloud runtime authority");sharedCentralPrompt=createCentralNativeComposition({runtime:e.runtime,host:i,gatewayOrigin:o.agentGatewayUrl,stateDirectory:l,authority:sharedRuntimeAuthority,coordinator:m,logger:e.logger})}if(i&®isterCentralNativeMemoryTools(e),!sharedAcpServer){const t=sharedRuntimeAuthority&&agentGateway?new AgentGatewayTemplateOriginReporter({gateway:agentGateway}):void 0;sharedAcpServer=new ACPServer(o,e.logger,m,a,agentGateway??void 0,s,n,sharedTerminalManager,sharedRuntimeAuthority,void 0,sharedMcpProjection,sharedMcpCredentialVault,{gateway:g.client,agentProjection:sharedAgentProjection,markAgentProjectionDirty:()=>sharedAgentProjection?.markDirty(),templateOriginReporter:t,agentMappings:sharedAgentMappings,agentCapabilities:sharedRuntimeAgentCapabilities,createRunOutputRouter:createPeerRunOutputRouterFactory(new MessageServiceRunOutputChannel({getClient:()=>sharedMessageClientOwner.current?.client??null,logger:e.logger,writeObs:a})),runExclusive:(t,r,o)=>sharedImHotPathDeferral.runExclusive(t,r,e.logger,o)})}const p=sharedAcpServer,h=()=>sharedAgentMappings.snapshot()?.values().next().value;r.current=p,sharedMcpNativeProjectionNudge.request({registrationMode:e.registrationMode,fingerprint:fingerprintMcpServers(t.openclawConfig),logger:e.logger});const y=sharedPromptRunStore,{enabled:v,principalId:w,a2aEnabled:f}=o.messageBus;let C;!u&&o.agentGatewayUrl&&agentKeys&&(C=createBeeosClawMessageTokenProvider({agentGatewayUrl:o.agentGatewayUrl,identity:agentKeyPairToIdentity(agentKeys)}));const R=process.env.MESSAGE_RUNTIME_DELIVERY_KEY?.trim(),b=w||process.env.BEEOS_PRINCIPAL_ID||"",S=C?sharedMessageClientOwner.configure({tokenProvider:C,identityId:b,...o.messageBus.serviceUrl?{serviceUrl:o.messageBus.serviceUrl}:{},logger:e.logger,...sharedRuntimeAuthority&&R?{runtimeDelivery:{scopedDeliveryKey:R,authority:{currentLease:()=>{const e=sharedRuntimeAuthority?.authorityLease,t=sharedRuntimeAuthority?.currentConsumerBinding();return e&&t?{...e,journalStoreId:t.journalStoreId,journalGeneration:t.journalGeneration}:null}}}}:{}}):void 0,E=u&&o.messageBus.serviceUrl&&sharedRuntimeAuthority?new NodeRuntimeDeliveryPort({serviceOrigin:async()=>o.messageBus.serviceUrl},{currentLease:()=>{const e=sharedRuntimeAuthority?.authorityLease,t=sharedRuntimeAuthority?.currentConsumerBinding();return e&&t&&e.instanceId===u?{...e,journalStoreId:t.journalStoreId,journalGeneration:t.journalGeneration}:null},subscribeAuthority:e=>sharedRuntimeAuthority.subscribeAuthority(e)}):void 0;attachNativeCloudChat(e,o);const O=sharedRuntimeAuthority,_=o.messageBus.serviceUrl;S&&O&&_&&R?p.setCronConversationDelivery({deliver:async e=>{const t=O.authorityLease;if(!t)throw new Error("current runtime authority lease unavailable for cron delivery");const r=new MessageServiceCronDeliveryHttpAuthority({messageServiceUrl:_,scopedDeliveryKey:R,fetchAuthorized:(e,t)=>fetchRuntimeLeaseAttempt(e,t??{})});return await r.deliver({...e,runtimeLeaseCredential:t.runtimeLeaseCredential})}}):p.setCronConversationDelivery(void 0);const A=sharedRuntimeAuthority?.journal??new FileRuntimeCommandJournal(join(l,"runtime-command-journal.json"),void 0,void 0,{onMaintenanceError:t=>e.logger.error?.(`[runtime-journal] event=checkpoint_failed trigger=threshold error=${t instanceof Error?t.message:String(t)}`)}),I=g.createRegistrationToken();e.registerService({id:"beeos-acp",async start(){const t=Date.now(),r=_pluginRegisteredAt?t-_pluginRegisteredAt:-1;e.logger.info?.(`[beeos-claw] beeos-acp service start() begin, sincePluginRegister=${r}ms, bridge.url=${o.bridge.url||"(empty)"}`);const a=await createRuntimeServiceProductionCandidate({...agentGateway?{authorizationAdapter:new AgentGatewayGrantJwksReadinessAdapter({gateway:agentGateway})}:{},onGrantJwksWarm:t=>{t.ready?e.logger.info?.("[beeos-claw] Gateway grant keyset loaded"):e.logger.warn?.(`[beeos-claw] Gateway grant keyset not ready yet (attempt ${t.attempt}): ${t.error instanceof Error?t.error.message:String(t.error)}`)},...S&&agentGateway&&R?{transportAdapter:new RuntimeServiceTransportReadinessAdapter({gateway:agentGateway,messageService:S.nodeTransport,messageClient:S.client,configuredServiceUrl:o.messageBus.serviceUrl,scopedDeliveryKey:R})}:{},...E&&agentGateway&&o.messageBus.serviceUrl?{cloudTransportAdapter:new CloudRuntimeServiceTransportReadinessAdapter({gateway:agentGateway,configuredServiceUrl:o.messageBus.serviceUrl,runtimeDelivery:E,...sharedCentralPrompt?{centralPrompt:sharedCentralPrompt}:{},...sharedNativeCloudChat?{sessionNewConversation:sharedNativeCloudChat.sessionNewConversation,nativePrompt:{http:sharedNativeCloudChat.http,inputFiles:new NativeInputFilesHttpClient(o.agentGatewayUrl,()=>sharedRuntimeAuthority.authorityLease,(e,t)=>fetch(e,t)),runBoundary:new MessageServiceConversationRunBoundary({transport:{start:e=>E.startConversationRun(e),finish:e=>E.finishConversationRun(e)}}),host:{htmlDeliveryEnabled:o.canvasEnabled,resolveNativePromptSessionKey:(e,t)=>p.resolveNativePromptSessionKey(e,t),prepareNativePromptModel:(e,t,r)=>p.prepareNativePromptModel(e,t,r),runtime:e.runtime,pluginConfig:o,logger:e.logger,promptRunStore:y,assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,approvalStreams:sharedApprovalBridge,questionStreams:sharedQuestionBridge,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:m,abortTransport:{chatAbort:(e,t)=>p.chatAbort(e,t)},activeRunAuthority:p.getActiveRunAuthority(),waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{})}}}:{}})}:{},commandJournal:A,poisonJournal:new FileRuntimePoisonDeliveryJournal(join(l,"runtime-poison-deliveries.json")),onConsumerDeliveryError:t=>{const r=null!==t&&"object"==typeof t?t:{},o=e=>"string"==typeof e&&e.length>0&&e.length<=256&&!/[\u0000-\u001f\u007f]/.test(e)?JSON.stringify(e):JSON.stringify("unavailable"),a="string"==typeof r.code&&/^[A-Za-z0-9_.:-]{1,64}$/.test(r.code)?r.code:"unavailable",n="number"==typeof r.status&&Number.isInteger(r.status)&&r.status>=100&&r.status<=599?String(r.status):"unavailable";e.logger.error?.(`[runtime-service] delivery worker failed before acknowledgement; delivery retained for retry: operation_id=${o(r.operationId)} delivery_id=${o(r.deliveryId)} code=${a} status=${n}`)},onConsumerLeaseStarvation:({starvedForMs:t,recovered:r})=>{const o=Math.round(t/1e3);r?e.logger.info?.(`[runtime-service] runtime authority lease restored after ${o}s without delivery reads`):e.logger.warn?.(`[runtime-service] no runtime authority lease for ${o}s; delivery reads suspended, queued runtime operations (model switch, session control) will not be consumed`)},onConsumerRequestFailure:t=>e.logger.error?.(`[runtime-service] request failed operationId=${t.operationId} method=${t.method}: ${t.error instanceof Error?t.error.stack??t.error.message:String(t.error)}`)});if(sharedRuntimeAuthority?.setRuntimeServiceMethods("ready"===a.status?a.serviceMethods:[]),sharedRuntimeAuthority?.setRuntimeResourceBindingContractRevision("ready"===a.status?a.resourceBindingContractRevision:void 0),p.setRuntimeRpcConsumerFactory("ready"===a.status?a.factory:void 0),"unavailable"===a.status?e.logger.warn?.("[runtime-service] capability fenced: "+a.blockers.map(e=>e.id).join(",")):a.capabilityBlockers.length&&e.logger.warn?.("[runtime-service] method capability fenced: "+a.capabilityBlockers.map(e=>e.method).join(",")),!o.bridge.url&&agentGateway){const t=Date.now(),r=await agentGateway.bridge.config();if(e.logger.info?.(`[beeos-claw] bridge discovery took ${Date.now()-t}ms result=${r?.url??"null"}`),r)o.bridge.url=r.url,writeDiscoveryCache({bridge:{url:r.url,discoveredAt:Date.now()}}),e.logger.info?.(`[beeos-claw] Bridge URL discovered from Agent Gateway: ${r.url}`);else{const t=readDiscoveryCache();t?.bridge?.url?(o.bridge.url=t.bridge.url,e.logger.info?.(`[beeos-claw] Bridge URL from cache (GW unreachable): ${t.bridge.url}`)):e.logger.debug?.("[beeos-claw] Bridge URL not available (no GW, no cache) — bridge disabled")}}await g.acquire(I);try{await p.start(o.bridge.url||void 0)}catch(e){throw await g.release(I),e}e.logger.info?.(`[beeos-claw] ACP Server started (total service start: ${Date.now()-t}ms)`)},async stop(){try{await g.release(I)}finally{await p.stop()}await A.checkpoint(),e.logger.info?.("[runtime-service] command journal checkpoint completed"),e.logger.info?.("[beeos-claw] ACP Server stopped")}});if(v&&void 0!==C&&C){const t=sharedMessageClientOwner.createRegistrationToken(),r=async(e,t)=>{const r=await C(e);if(!r.identityId||r.identityId!==e)throw new Error("Message SDK token identity did not match the current runtime authority");return{principalId:e,runtimeEpoch:t}},o=(e,t,r)=>({getLocalAgentId:()=>t,resolveLocalAgentId:e=>e===r?t:void 0,getDefaultPlatformAgent:()=>({instanceId:e.principalId}),ensureImInboundSession:(e,t,r,o)=>{p.ensureImInboundSession(e,t,r,o)},chatAbort:(e,t)=>p.chatAbort(e,t)}),n=sharedRuntimeAuthority?new RuntimeAuthorityMessageBusLifecycle({authority:sharedRuntimeAuthority,logger:e.logger,bus:{connect:async n=>{await sharedMessageClientOwner.acquire(t,async t=>{const i=await r(n.instanceId,n.runtimeEpoch),s=t.client,l={leaseId:n.leaseId,runtimeEpoch:n.runtimeEpoch};sharedMSConnectionStatus.bind(l);const u=new Map,d=new MessageProjectionInboundConsumer({client:s,bindings:()=>{const t=sharedRuntimeAuthority?.authorityLease;if(!t||t.instanceId!==i.principalId||t.runtimeEpoch!==i.runtimeEpoch)return[];const r=sharedAgentMappings.snapshot();return r?[...r.entries()].flatMap(([r,n])=>{if(!n.id||n.instanceId!==i.principalId)return[];let l=u.get(n.id);return l&&l.localAgentId===r||(l={localAgentId:r,inbound:createImInboundHandler({automationTurnPolicy:sharedAutomationTurnPolicy,runtime:e.runtime,pluginConfig:e.pluginConfig,client:s,localServer:o(i,r,n.id),promptRunStore:y,waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{}),assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,approvalStreams:sharedApprovalBridge,questionStreams:sharedQuestionBridge,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:m,logger:e.logger,writeObs:a,principalIdOverride:i.principalId,activeRunAuthority:p.getActiveRunAuthority(),applyTurnModel:(e,t)=>p.applyImTurnModel(e,t),restoreTurnModel:e=>p.restoreImTurnModel(e),...agentGateway?{completeA2ATask:(t,r,o)=>completeA2ATask({gateway:agentGateway,logger:e.logger},t,r,o)}:{}})},u.set(n.id,l)),[{principalId:i.principalId,targetAgentId:n.id,runtimeEpoch:t.runtimeEpoch,inbound:l.inbound}]}):[]},executionJournal:c,logger:e.logger}),g=sharedAgentMappings.subscribe(()=>{sharedActiveMessageConsumer===d&&d.refresh()}),h=sharedRuntimeAuthority?.subscribeAuthority(()=>{sharedActiveMessageConsumer===d&&d.refresh()})??(()=>{}),v=new MessageClientTerminalStateRecovery({logger:e.logger,isCurrent:()=>{if(sharedActiveMessageConsumer!==d)return!1;const e=sharedRuntimeAuthority?.authorityLease;return null!=e&&e.instanceId===i.principalId&&e.runtimeEpoch===i.runtimeEpoch&&e.leaseId===n.leaseId&&e.handlerIdentity===n.handlerIdentity},reconnect:async()=>{if("failed"===s.getSnapshot().connection){await s.connect();try{await p.rebindRuntimeDelivery()}catch(t){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient recovery: ${t instanceof Error?t.message:String(t)}`)}}}});let w=s.getSnapshot().connection;sharedMSConnectionStatus.setIfCurrent(l,w);const f=s.subscribe(()=>{const t=s.getSnapshot();t.connection!==w&&(w=t.connection,sharedMSConnectionStatus.setIfCurrent(l,t.connection),"connected"===t.connection?(v.notifyConnected(),e.logger.info?.(`[beeos-claw] connection transport=message_service_realtime state=connected localAgentId=${p.getLocalAgentId()} principalId=${i.principalId}`)):"failed"===t.connection?(e.logger.warn?.(`[beeos-claw] connection transport=message_service_realtime state=failed principalId=${i.principalId} recoveryError=${t.recoveryError??"unknown"}`),v.notifyFailed()):"disconnected"!==t.connection&&"reconnecting"!==t.connection||e.logger.warn?.(`[beeos-claw] connection transport=message_service_realtime state=${t.connection} principalId=${i.principalId}; SDK owns reconnect/recovery`))});sharedActiveMessageConsumer=d,d.start();try{await s.connect()}catch(e){throw sharedActiveMessageConsumer===d&&(sharedActiveMessageConsumer=void 0),sharedMSConnectionStatus.resetIfCurrent(l),v.dispose(),await d.stop(),g(),h(),f(),await s.disconnect().catch(()=>{}),e}try{await p.rebindRuntimeDelivery()}catch(t){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient connect: ${t instanceof Error?t.message:String(t)}`)}return async()=>{sharedActiveMessageConsumer===d&&(sharedActiveMessageConsumer=void 0),sharedMSConnectionStatus.resetIfCurrent(l),v.dispose(),await d.stop(),h(),f(),await s.disconnect(),e.logger.info?.("[beeos-claw] MessageClient disconnected")}})},disconnect:async()=>{await sharedMessageClientOwner.release(t)}}}):void 0;e.registerService({id:"beeos-message-bus",async start(){n?n.start():e.logger.warn?.("[beeos-claw] Message bus requires runtime authority; waiting is unavailable without Agent Gateway runtime identity")},async stop(){await(n?.stop())}})}else v?e.logger.warn?.("[beeos-claw] Message bus enabled but Agent Gateway token provider is unavailable — disabled"):e.logger.info?.(`[beeos-claw] Message bus disabled (enabled=${v})`);if(o.messageBus.enabled&&u&&!sharedNativeCloudChat&&e.logger.warn?.("[beeos-claw] Cloud message bus enabled but native composition unavailable (messageBus.serviceUrl or runtime authority missing) — disabled"),!1!==f&&agentGateway){const t=e=>p.getGatewaySessionKeyForToolCall(e),r=e=>p.getMentionsForToolCall(e),o=(e,t)=>{p.broadcastNotification(e,t)},a=new TaskHandleRegistry;registerA2ATools(e,{gateway:agentGateway,logger:e.logger},a,t,r,o,()=>h()?.instanceId),e.logger.info?.("[beeos-claw] A2A tools registered (beeos_discover_agents, beeos_call_agent) via REST")}if(agentGateway&&(registerAutomationTools(e,{gateway:agentGateway,callConnectorTool:harnessConnectorToolCaller(),logger:e.logger,getDefaultAgent:()=>{const e=h();return e?{id:e.id,instanceId:e.instanceId}:void 0},getCurrentConversationId:e=>{const t=p.getGatewaySessionKeyForToolCall(e);return t?extractBeeosConversationIdFromSessionKey(t):void 0}}),e.logger.info?.("[beeos-claw] Automation tools registered (create/create_webhook/capabilities/preflight/list/get/run/runs/get_run)")),o.canvasEnabled){sharedCanvasState||(sharedCanvasState=new CanvasStateManager);const t=sharedCanvasState;if(agentGateway&&agentKeys){t.setLogger(e.logger);const r=claimedSandboxId(),a=createSandboxCanvasTokenProvider(agentGateway,r,()=>sharedRuntimeAuthority?.authorityLease),n=n=>{const i=new CanvasRelayClient({canvasRelayUrl:o.canvasRelayUrl,agentKeys:agentKeys,...r?{}:{agentId:n.id},displayName:n.displayName,avatarUrl:n.avatarUrl,tokenProvider:a,onConnected:()=>p.flushPendingCanvasLinks(),onReconnect:()=>p.onRelayReconnected(),logger:e.logger});t.setRelayClient(i),t.setAgentId(n.id),p.wireRelayActionHandler(),i.connect(),e.logger.info?.(`[beeos-claw] Canvas Relay multiplexed client connected (agentId=${n.id}, name=${n.name??"none"})`)};e.registerService(createCanvasRelayService({getAgent:r?()=>({id:`sandbox:${r}`}):h,onceAgentReady:e=>sharedAgentMappings.onceReady(e),initRelay:n,stopRelay:()=>t.getRelayClient()?.disconnect(),logger:e.logger})),e.logger.info?.("[beeos-claw] Canvas Relay configured")}else e.logger.warn?.("[beeos-claw] Canvas Relay unavailable: agentGatewayUrl or agentKeys missing");const r={stateManager:t,logger:e.logger,writeObs:e=>a(e),getActiveSessionId:e=>p.getSessionIdForToolCall(e),getPlatformAgentId:e=>p.getPlatformAgentIdForToolCall(e),getGatewaySessionKey:e=>p.getGatewaySessionKeyForToolCall(e),waitForAgentSync:()=>sharedAgentMappings.waitForSynchronization(),publishStaticHtml:createStaticCanvasHtmlPublisher(pluginCloudRuntimeTarget(e)?o.agentGatewayUrl:void 0)},i=new FormSchemaRegistry,s=buildCronSchemas(n);i.register(s.create),i.register(s.update);const l=new ResourceDescriptorRegistry;l.register(CRON_RESOURCE);const c=e=>async(t,r,o)=>(p.preMapToolCallSession(t),e(t,r));e.registerTool({name:RENDER_UI_TOOL_NAME,description:RENDER_UI_TOOL_DESCRIPTION,parameters:RENDER_UI_TOOL_SCHEMA,execute:c(createRenderUiToolExecutor(r))}),e.registerTool({name:CLOSE_UI_TOOL_NAME,description:CLOSE_UI_TOOL_DESCRIPTION,parameters:CLOSE_UI_TOOL_SCHEMA,execute:c(createCloseUiHandler(r))}),p.setCanvasState(t,{schemaRegistry:i,descriptorRegistry:l});const u=p.getFormBuilder();u&&e.registerTool({name:RENDER_FORM_TOOL_NAME,description:buildRenderFormDescription(i),parameters:RENDER_FORM_TOOL_SCHEMA,execute:c(createRenderFormHandler({registry:i,builder:u,logger:e.logger}))});const d=p.getResourceRenderer();if(d){generateActionTools(l,e,async(e,t)=>p.gatewayRequest(e,t),d,e.logger)}const g=buildToolRoutingHint(BEEOS_FILE_RESOURCE_ROUTING_RULE,BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME),m=new Set([RENDER_UI_TOOL_NAME,CLOSE_UI_TOOL_NAME,RENDER_FORM_TOOL_NAME]),y=256,v=new Map;if("function"==typeof e.on){try{e.on("before_prompt_build",(e,t)=>{if(t?.sessionKey){if(v.size>=y&&!v.has(t.sessionKey)){const e=v.keys().next().value;void 0!==e&&v.delete(e)}v.set(t.sessionKey,t.channelId),rememberDeliveryWorkspace(t.sessionKey,t.workspaceDir)}const r=isThirdPartyChannel(n,{sessionKey:t?.sessionKey,channelId:t?.channelId});return t?.sessionKey||r?{appendSystemContext:buildAppendSystemContext({thirdParty:r,canvasSystemPrompt:`${CANVAS_PRESENTATION_GATE}\n\n${CANVAS_SYSTEM_PROMPT}`,toolRoutingHint:g})}:{appendSystemContext:g}}),e.logger.debug?.("[beeos-claw] Canvas system prompt hook registered: before_prompt_build")}catch{e.logger.debug?.("[beeos-claw] before_prompt_build hook not supported")}try{e.on("before_tool_call",(e,t)=>{if(t?.sessionKey&&p.setPendingToolCallSessionKey(t.sessionKey),!m.has(e.toolName))return;const r=t?.sessionKey?v.get(t.sessionKey):void 0,o=isThirdPartyChannel(n,{sessionKey:t?.sessionKey,channelId:r}),a=canvasToolBlockReason({thirdParty:o,hasSession:Boolean(t?.sessionKey)});return a?{block:!0,blockReason:a}:void 0}),e.logger.debug?.("[beeos-claw] Canvas tool guard registered: before_tool_call")}catch{e.logger.debug?.("[beeos-claw] before_tool_call hook not supported")}}e.logger.info?.("[beeos-claw] Canvas tools registered (render_ui, close_ui, render_form + auto-action tools)")}else e.logger.info?.("[beeos-claw] Canvas disabled by config (canvasEnabled=false)");if(o.bridge.shell.enabled&&!0===o.legacyTerminalWsEnabled){const t=createTerminalWebSocketService({config:{port:o.terminalWsPort,token:agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):"",allowedOrigins:o.terminalWsAllowedOrigins},terminalMgr:sharedTerminalManager,logger:e.logger,writeObs:a});e.registerService({id:"beeos-terminal-ws",start(){t.start(),e.logger.info?.(`[beeos-claw] Terminal WS started on port ${o.terminalWsPort}`)},stop(){t.stop(),e.logger.info?.("[beeos-claw] Terminal WS stopped")}})}else o.bridge.shell.enabled?e.logger.info?.("[beeos-claw] Legacy static-token Terminal WS disabled (default)"):e.logger.info?.("[beeos-claw] Terminal/shell disabled by config (bridge.shell.enabled=false)");if(t.openclawConfig){const r=mirrorOpenClawConfig(t.openclawConfig);r.copied?e.logger.info?.(`[beeos-claw] mirrored openclaw config to ${r.destinationPath}`):e.logger.debug?.(`[beeos-claw] openclaw config mirror skipped: ${r.reason}`)}}export function pluginCloudRuntimeTarget(e){const t=e.pluginConfig?.cloudRuntimeInstanceId;return cloudRuntimeTargetInstanceId("string"==typeof t?t:claimedSandboxId())}function attachNativeCloudChat(e,t){if(sharedNativeChatService)return e.registerService(sharedNativeChatService),sharedNativeCloudChat;const r=sharedRuntimeAuthority,o=t.messageBus.serviceUrl,a=sharedAcpServer,n=sharedSessionMutationCoordinator;if(!(r&&r.cloudTargetInstanceId&&o&&a&&n))return sharedNativeCloudChat;const i=sharedNativeCloudChat??createNativeCloudChatComposition({authority:nativeCloudChatAuthorityFromRuntimeAuthority(r),serviceUrl:o,logger:e.logger});if(sharedNativeCloudChat=i,!t.messageBus.enabled)return i;const s=i,l=r;let c;const u=new Map,d=new RuntimeAuthorityMessageBusLifecycle({authority:l,logger:e.logger,bus:{connect:async t=>{c?.(),u.clear(),c=s.adapter.listen({eventTypes:["message.created"]},r=>{if(r.type===APPROVAL_DECISION_MESSAGE_TYPE&&r.senderId?.startsWith("user:")&&isApprovalDocument(r.content))return void sharedApprovalBridge.onDecision(r.content);if("user.continue"===r.type&&isQuestionResponseDocument(r.content))return void sharedQuestionBridge.onResponse(r);const o=(r.content??{}).metadata??{},i="string"==typeof o.target_agent_id?o.target_agent_id:"",l=i?((t,r)=>{const o=sharedAgentMappings.snapshot();if(o)for(const[i,l]of o.entries()){if(l.id!==r)continue;if(l.instanceId!==t.instanceId)continue;const o=`${i}\0${l.id}`;let c=u.get(o);return c||(c={localAgentId:i,inbound:createImInboundHandler({runtime:e.runtime,pluginConfig:e.pluginConfig,client:s.adapter,localServer:{getLocalAgentId:()=>i,resolveLocalAgentId:e=>e===l.id?i:void 0,getDefaultPlatformAgent:()=>({instanceId:t.instanceId}),ensureImInboundSession:(e,t,r,o)=>{a.ensureImInboundSession(e,t,r,o)},chatAbort:(e,t)=>a.chatAbort(e,t)},promptRunStore:sharedPromptRunStore,waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{}),assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,approvalStreams:sharedApprovalBridge,questionStreams:sharedQuestionBridge,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:n,logger:e.logger,writeObs:sharedWriteObs,principalIdOverride:t.instanceId,activeRunAuthority:a.getActiveRunAuthority(),applyTurnModel:(e,t)=>a.applyImTurnModel(e,t),restoreTurnModel:e=>a.restoreImTurnModel(e),...agentGateway?{completeA2ATask:(t,r,o)=>completeA2ATask({gateway:agentGateway,logger:e.logger},t,r,o)}:{}})},u.set(o,c)),c}})(t,i):void 0;if(!l)return void e.logger.warn?.(`[beeos-claw] native cloud chat dropped unresolvable target_agent_id=${i||"missing"} message_id=${r.id}`);("chat_cancel"===r.type?l.inbound.onChatCancel(r):l.inbound.onChatMessage(r)).catch(t=>{e.logger.error?.(`[beeos-claw] native cloud chat dispatch failed message_id=${r.id}: ${t instanceof Error?t.message:String(t)}`)})});try{await s.adapter.connect()}catch(e){throw c?.(),c=void 0,e}},disconnect:async()=>{c?.(),c=void 0,u.clear(),await s.adapter.disconnect()}}});return sharedNativeChatService={id:"beeos-native-cloud-chat",async start(){d.start()},async stop(){await d.stop()}},e.registerService(sharedNativeChatService),e.logger.info?.("[beeos-claw] native Cloud personal-chat composition registered"),i}const plugin={id:"beeos-claw",name:"beeos-claw",description:"BeeOS platform bridge plugin for OpenClaw. Provides file upload/download, ACP bridge, and observability.",version:PLUGIN_VERSION,register(e){if(_initializing)return;registerCentralNativeContextEngine(e),registerSandboxNativeActivation(e,()=>{if(!sharedSessionMutationCoordinator)throw new Error("native session writer coordinator is unavailable");return sharedSessionMutationCoordinator.activeMutationCount},createSandboxNativeTargetLookup(()=>sharedRuntimeAuthority,()=>sharedGatewayClient),async()=>{if(!sharedGatewayClient?.isConnected)throw new Error("OpenClaw gateway is not connected");await sharedGatewayClient.request("secrets.reload",{})});const t=pluginCloudRuntimeTarget(e),r=void 0!==t&&t!==sharedRuntimeAuthority?.cloudTargetInstanceId,o=planPluginRegistration(e.registrationMode,_fullRuntimeRegistered,r);if("skip"!==o){_initializing=!0;try{if(!hasRuntimeReplyApi(e.runtime))throw e.logger.error?.("[beeos-claw] FATAL: OpenClaw runtime.channel.reply.dispatchReplyFromConfig not exposed. Upgrade OpenClaw or revert beeos-claw."),new Error("openclaw_runtime_reply_api_unavailable");const t=(t,r)=>{registerUploadTools(e,t,r),registerArouterLatencyRouting(e),registerArouterMediaProviders(e)};if("capabilities"===o&&sharedPluginContext){if(cachedCapabilityTools.length>0){const t=resolveCapabilityToolReplay({currentRegisterTool:e.registerTool,wrappedRegisterTool:wrappedRegisterTool,originalRegisterTool:rawRegisterTool}),r=replayCachedPluginTools((r,o)=>t.call(e,r,o),cachedCapabilityTools);return registerArouterLatencyRouting(e),registerArouterMediaProviders(e),void e.logger.info?.(`[beeos-claw] capability re-register mode=${e.registrationMode} tools_only count=${r}`)}const r={current:sharedAcpServer??null};return t(sharedPluginContext,r),registerServices(e,sharedPluginContext,r),void e.logger.info?.(`[beeos-claw] capability re-register mode=${e.registrationMode} capabilities_only`)}const r=initializePlugin(e);if(!r)return;const a={current:null};installUnhandledRejectionObserver(e,r.writeObs,a),ensureRegisterToolCache(e),cacheRuntimeRegistrations(e),cachedCapabilityTools.length=0,t(r,a),agentGateway&&(e.on?e.on("before_agent_finalize",async(e,t)=>{if(await fileDeliveryFinalizeDecision(e),!e.runId||!t?.runId||e.runId===t.runId)return nativeHtmlDeliveryForRun(e.runId??t?.runId)?.beforeFinalize(e)}):e.logger.warn?.("[file-delivery] OpenClaw plugin hooks unavailable; finalization check disabled")),registerServices(e,r,a),sharedPluginContext=r,marksFullRuntimeRegistered(e.registrationMode,o)&&(_fullRuntimeRegistered=!0),_pluginRegisteredAt=Date.now(),e.logger.info?.("[beeos-claw] Plugin registered successfully")}finally{_initializing=!1}}else if(!e.registrationMode||"full"===e.registrationMode){const t=resolveCapabilityToolReplay({currentRegisterTool:e.registerTool,wrappedRegisterTool:wrappedRegisterTool,originalRegisterTool:rawRegisterTool});replayCachedPluginTools((r,o)=>t.call(e,r,o),cachedCapabilityTools),replayRuntimeRegistrations(e),registerArouterLatencyRouting(e),registerArouterMediaProviders(e)}}};export default plugin;
|
|
1
|
+
import{claimedSandboxId,identityLaneFromEnvironment}from"./runtime/identity-lane-lease.js";import{createCentralNativeComposition,requireCentralNativeSessionHost}from"./runtime/central-native-composition.js";import{createSandboxNativeTargetLookup,registerSandboxNativeActivation}from"./runtime/sandbox-native-activation.js";import{registerCentralNativeMemoryTools}from"./runtime/central-native-memory.js";import{harnessConnectorToolCaller}from"./connectors/harness-connector-mcp.js";import{registerCentralNativeContextEngine,centralNativeChatEnabled}from"./runtime/central-native-runtime.js";import{relayCentralAskUser}from"./runtime/central-native-interactions.js";import{consumeNativeOutputTool,nativeHtmlDeliveryForRun}from"./runtime/native-output-file-attempt.js";import{uploadNativeOutputFile}from"./upload/upload-file.js";import{nativeOutputToolCallGate}from"./upload/native-output-tool-hook.js";import{NativeInputFilesHttpClient}from"./runtime/native-input-files-http.js";import{fileDeliveryFinalizeDecision}from"./upload/finalize-hook.js";import{resolveConfigWithMeta,mirrorOpenClawConfig}from"./config.js";import{hasRuntimeReplyApi}from"./runtime/reply-router.js";import{PromptRunStore}from"./runtime/prompt-run-store.js";import{createMcpNativeProjectionNudge,fingerprintMcpServers}from"./acp-gateway/mcp-native-projection-nudge.js";import{createImHotPathDeferral}from"./runtime/im-hot-path-deferral.js";import{SessionWriteGate}from"./acp-gateway/session-write-gate.js";import{OpenClawSessionWriteQuiescence}from"./runtime/openclaw-session-write-quiescence.js";import{SessionMutationCoordinator}from"./runtime/session-mutation-coordinator.js";import{scheduleProcessRuntimeRestart}from"./runtime/runtime-restart-scheduler.js";import{createImInboundHandler}from"./im-inbound-handler.js";import{AgentGatewayClient,NodeRuntimeDeliveryPort,agentIdentityFromKeyPair,loadAgentKeyPair,signAgentMessage}from"@beeos-ai/cloud-harness-sdk";import{MessageServiceConversationRunBoundary}from"./runtime/message-service-conversation-run-boundary.js";import{AutomationTurnPolicy}from"./automation/turn-policy.js";import{registerAutomationTools}from"./automation/tools.js";import{extractBeeosConversationIdFromSessionKey}from"./runtime/openclaw-session-key-resolution.js";import{setOpenClawConfigSnapshot}from"./runtime/openclaw-session-model.js";import{BeeosClawMessageClientProcessOwner,createBeeosClawMessageTokenProvider}from"./message-client-composition.js";import{MessageProjectionInboundConsumer}from"./message-projection-inbound-consumer.js";import{MessageClientTerminalStateRecovery}from"./runtime/message-client-terminal-state-recovery.js";import{RuntimeAuthorityMessageBusLifecycle}from"./runtime/runtime-authority-message-bus-lifecycle.js";import{createNativeCloudChatComposition,nativeCloudChatAuthorityFromRuntimeAuthority}from"./runtime/native-cloud-chat-composition.js";import{MSConnectionStatusSnapshot}from"./runtime/ms-connection-status.js";import{FileInboundExecutionJournal}from"./inbound-execution-journal.js";import{completeA2ATask,registerA2ATools,TaskHandleRegistry}from"./a2a/tools.js";import{BEEOS_UPLOAD_TOOL_NAME,BEEOS_UPLOAD_TOOL_SCHEMA,BEEOS_UPLOAD_TOOL_DESCRIPTION,REQUEST_TIMEOUT_MS as BEEOS_UPLOAD_REQUEST_TIMEOUT_MS,executeUpload}from"./upload/tool.js";import{BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,BEEOS_DESKTOP_SCREENSHOT_TOOL_SCHEMA,BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION,executeDesktopScreenshot}from"./upload/desktop-screenshot-tool.js";import{BEEOS_LIST_FILES_TOOL_NAME,BEEOS_LIST_FILES_TOOL_SCHEMA,BEEOS_LIST_FILES_TOOL_DESCRIPTION,executeListFiles}from"./files/list-tool.js";import{BEEOS_FETCH_FILE_TOOL_NAME,BEEOS_FETCH_FILE_TOOL_SCHEMA,BEEOS_FETCH_FILE_TOOL_DESCRIPTION,executeFetchFile}from"./files/fetch-tool.js";import{writeUploadToolResult,cleanupUploadToolResultCache}from"./upload/result-cache.js";import{handleFileStage}from"./upload/file-stage.js";import{handleStatusRequest}from"./status.js";import{ACPServer}from"./acp-server.js";import{GatewayClient}from"./gateway-client.js";import{createObsEventWriter}from"./observability.js";import{resolvePluginVersion}from"./plugin-version.js";import{createTerminalWebSocketService}from"./terminal/websocket.js";import{TerminalManager}from"./terminal/session-manager.js";import{readDiscoveryCache,writeDiscoveryCache}from"./discovery-cache.js";import{setClaimedCloudRuntimeInstanceId,setUploadDeps}from"./upload/upload-file.js";import{registerLocalFileExtractor}from"./upload/local-file-extractors.js";import{browserScreenshotExtractor}from"./browser/screenshot-extractor.js";import{deliverableFileExtractor}from"./upload/deliverable-extractor.js";import{observeToolCallForDelivery,rememberDeliveryWorkspace}from"./upload/delivery-observe.js";import{sessionWorkspaceDir}from"./upload/delivery-ledger.js";import{BEEOS_FILE_RESOURCE_ROUTING_RULE}from"./files/beeos-file-uri.js";import{marksFullRuntimeRegistered,planPluginRegistration,replayCachedPluginTools,resolveCapabilityToolReplay}from"./plugin-registration-plan.js";import{buildAppendSystemContext,buildToolRoutingHint,canvasToolBlockReason}from"./prompt-system-context.js";import{CanvasStateManager}from"./canvas/state.js";import{createStaticCanvasHtmlPublisher}from"./canvas/static-html.js";import{CanvasRelayClient}from"./canvas/relay-client.js";import{createSandboxCanvasTokenProvider}from"./canvas/runtime-lease-token.js";import{createCanvasRelayService}from"./canvas/relay-service.js";import{RENDER_UI_TOOL_NAME,RENDER_UI_TOOL_DESCRIPTION,RENDER_UI_TOOL_SCHEMA,CLOSE_UI_TOOL_NAME,CLOSE_UI_TOOL_DESCRIPTION,CLOSE_UI_TOOL_SCHEMA,createRenderUiToolExecutor,createCloseUiHandler,CANVAS_PRESENTATION_GATE,CANVAS_SYSTEM_PROMPT}from"./canvas/tools.js";import{FormSchemaRegistry}from"./surface/form-schema-registry.js";import{buildCronSchemas}from"./surface/cron-schemas.js";import{RENDER_FORM_TOOL_NAME,RENDER_FORM_TOOL_SCHEMA,buildRenderFormDescription,createRenderFormHandler}from"./surface/render-form-tool.js";import{ResourceDescriptorRegistry}from"./surface/resource-descriptor-registry.js";import{CRON_RESOURCE}from"./surface/cron-resource.js";import{generateActionTools}from"./surface/action-tool-generator.js";import{buildThirdPartyChannelSet,isThirdPartyChannel}from"./channel-detection.js";import{registerArouterMediaProviders}from"./media/index.js";import{homedir}from"node:os";import{join}from"node:path";import{RuntimeProductionAuthority,cloudRuntimeTargetInstanceId}from"./runtime/runtime-production-authority.js";import{FileRuntimeCommandJournal}from"./runtime/runtime-command-journal.js";import{FileRuntimePoisonDeliveryJournal}from"./runtime/runtime-poison-delivery-journal.js";import{OpenClawNativeMcpProjection}from"./acp-gateway/openclaw-native-mcp-projection.js";import{LocalEncryptedCredentialReferenceVault}from"./acp-gateway/mcp-credential-reference-port.js";import{AgentGatewayGrantJwksReadinessAdapter,CloudRuntimeServiceTransportReadinessAdapter,RuntimeServiceTransportReadinessAdapter,createRuntimeServiceProductionCandidate}from"./runtime/runtime-service-production-candidate.js";import{fetchRuntimeLeaseAttempt}from"./runtime/message-service-runtime-authenticated-fetch.js";import{MessageServiceCronDeliveryHttpAuthority}from"./runtime/message-service-cron-delivery-http-authority.js";import{AgentMappingRegistry}from"./runtime/agent-mapping-registry.js";import{OpenClawRuntimeProcessOwner}from"./runtime/openclaw-runtime-process-owner.js";import{AgentGatewayHttpProjectionTransport,AgentGatewayTemplateOriginReporter,AgentProjectionProduction,OpenClawAgentProjectionSource}from"./runtime/agent-projection-production.js";import{MessageServiceRunOutputChannel}from"./runtime/message-service-run-output-channel.js";import{AssistantMessageCommitRouter}from"./runtime/assistant-message-commit-router.js";import{OpenClawApprovalBridge}from"./approval/bridge.js";import{APPROVAL_DECISION_MESSAGE_TYPE,isApprovalDocument}from"./approval/protocol.generated.js";import{isQuestionResponseDocument,OpenClawQuestionBridge}from"./question/bridge.js";import{ToolResultObservationRouter}from"./runtime/tool-result-observation-router.js";import{ModelCallObservationRouter,registerModelCallObservationHooks}from"./runtime/model-call-observability.js";import{registerArouterLatencyRouting}from"./runtime/arouter-latency-routing.js";import{createPeerRunOutputRouterFactory}from"./runtime/run-output-composition.js";const PLUGIN_VERSION=resolvePluginVersion();let agentKeys=null,agentGateway=null,sharedCanvasState=null,sharedAcpServer=null;const sharedSessionWriteGate=new SessionWriteGate,sharedPromptRunStore=new PromptRunStore,sharedAutomationTurnPolicy=new AutomationTurnPolicy;let lastOpenclawConfig;const sharedMcpNativeProjectionNudge=createMcpNativeProjectionNudge({getActiveImRunCount:()=>sharedPromptRunStore.size(),nudge:()=>{sharedAcpServer?.nudgeMcpNativeProjection()}}),sharedImHotPathDeferral=createImHotPathDeferral({getActiveImRunCount:()=>sharedPromptRunStore.size()});sharedPromptRunStore.setOnBecameIdle(()=>{sharedMcpNativeProjectionNudge.flushIfIdle({fingerprint:fingerprintMcpServers(lastOpenclawConfig)}),sharedImHotPathDeferral.notifyIdle()});const sharedAssistantMessageCommitRouter=new AssistantMessageCommitRouter,sharedToolResultObservationRouter=new ToolResultObservationRouter;let approvalLogger;const sharedApprovalBridge=new OpenClawApprovalBridge({request:(e,t)=>sharedGatewayClient?sharedGatewayClient.request(e,t):Promise.reject(new Error("Not connected to Gateway")),logger:{info:e=>approvalLogger?.info?.(e),warn:e=>approvalLogger?.warn?.(e)}}),sharedQuestionBridge=new OpenClawQuestionBridge({request:(e,t)=>sharedGatewayClient?sharedGatewayClient.request(e,t):Promise.reject(new Error("Not connected to Gateway")),logger:{info:e=>approvalLogger?.info?.(e),warn:e=>approvalLogger?.warn?.(e)}}),sharedModelCallObservationRouter=new ModelCallObservationRouter;let sharedSessionMutationCoordinator,sharedCentralPrompt,sharedRuntimeAuthority,sharedNativeChatService,sharedNativeCloudChat,sharedWriteObs=()=>{};const sharedMSConnectionStatus=new MSConnectionStatusSnapshot,sharedAgentMappings=new AgentMappingRegistry;let sharedGatewayClient,sharedRuntimeOwner,sharedAgentProjection,sharedRuntimeAgentCapabilities,sharedMcpProjection,sharedMcpCredentialVault;const sharedMessageClientOwner=new BeeosClawMessageClientProcessOwner;let sharedActiveMessageConsumer,sharedInboundExecutionJournal;const sharedTerminalManager=new TerminalManager;let _initializing=!1,_pluginRegisteredAt=0,_fullRuntimeRegistered=!1;const cachedCapabilityTools=[];let rawRegisterTool,wrappedRegisterTool;const cachedRuntimeServices=[],cachedRuntimeHooks=[];let rawRegisterService,wrappedRegisterService,rawOn,wrappedOn;function cacheRuntimeRegistrations(e){const t=e.registerService===wrappedRegisterService?rawRegisterService:e.registerService;if(rawRegisterService=t,wrappedRegisterService=r=>{cachedRuntimeServices.push(r),t.call(e,r)},e.registerService=wrappedRegisterService,cachedRuntimeServices.length=0,cachedRuntimeHooks.length=0,e.on){const t=e.on===wrappedOn?rawOn:e.on;rawOn=t,wrappedOn=(...r)=>{cachedRuntimeHooks.push(r),t.call(e,...r)},e.on=wrappedOn}}function replayRuntimeRegistrations(e){const t=e.registerService===wrappedRegisterService?rawRegisterService:e.registerService,r=e.on===wrappedOn?rawOn:e.on;for(const t of cachedRuntimeHooks)r.call(e,...t);for(const r of cachedRuntimeServices)t.call(e,r)}const ensureRegisterToolCache=e=>{const t=e.registerTool===wrappedRegisterTool?rawRegisterTool:e.registerTool;rawRegisterTool=t.bind(e),wrappedRegisterTool=(e,t)=>(cachedCapabilityTools.push({tool:e,options:t}),rawRegisterTool(e,t)),e.registerTool=wrappedRegisterTool};function agentKeyPairToIdentity(e){return{publicKeyBase64:()=>Buffer.from(e.publicKey).toString("base64"),sign:async t=>signAgentMessage(t,e.privateKey)}}let sharedPluginContext=null,unhandledRejectionObserverInstalled=!1;function installUnhandledRejectionObserver(e,t,r){unhandledRejectionObserverInstalled||(unhandledRejectionObserverInstalled=!0,process.on("unhandledRejection",r=>{const o=r instanceof Error?r.message:String(r),a=r instanceof Error?r.stack:void 0;e.logger.error?.(`[beeos-claw] unhandledRejection: ${o}${a?`\n${a}`:""}`),t({component:"plugin",domain:"fatal",name:"unhandled_rejection",severity:"error",summary:o,error:{code:"unhandled_rejection",message:o,...a?{stack:a}:{}}})}),process.on("uncaughtException",r=>{const o=r instanceof Error?r.message:String(r);e.logger.error?.(`[beeos-claw] uncaughtException: ${r instanceof Error?r.stack??r.message:String(r)}`),t({component:"plugin",domain:"fatal",name:"uncaught_exception",severity:"error",summary:o,error:{code:"uncaught_exception",message:o}})}))}function initializePlugin(e){let t,r;try{t=e.runtime?.config?.loadConfig?.()}catch{}try{r=resolveConfigWithMeta({pluginConfig:e.pluginConfig??{},openclawConfig:t})}catch(t){return e.logger.error?.(`[beeos-claw] Failed to resolve config: ${t instanceof Error?t.message:String(t)}`),null}const o=r.config,a=buildThirdPartyChannelSet(t);a.size>0&&e.logger.info?.(`[beeos-claw] Third-party channels detected: ${[...a].join(", ")}`);const n=o.log.enabled?createObsEventWriter({dir:o.log.dir,redaction:{gatewayToken:o.gateway.token},logger:e.logger}):()=>{};n({component:"plugin",domain:"lifecycle",name:"lifecycle.startup",severity:"info",payload:{pluginVersion:PLUGIN_VERSION,pid:process.pid,nodeVersion:process.version,cwd:process.cwd()}}),n({component:"plugin",domain:"config",name:"config.resolved",severity:"info",payload:{config:o,sources:r.sources,openclawConfigPath:r.openclawConfigPath}});for(const t of r.validation)n({component:"plugin",domain:"config",name:"config.validation",severity:t.severity,summary:t.message,error:{code:t.code,message:t.message,nextSteps:t.nextSteps}}),"error"===t.severity?e.logger.error?.(`[beeos-claw] ${t.message}`):e.logger.warn?.(`[beeos-claw] ${t.message}`);if(r.validation.some(e=>"error"===e.severity)&&e.logger.error?.("[beeos-claw] Plugin has configuration errors — some features may not work."),o.keyFile)try{agentKeys=loadAgentKeyPair(o.keyFile),agentGateway=o.agentGatewayUrl?new AgentGatewayClient({baseUrl:o.agentGatewayUrl,identity:agentIdentityFromKeyPair(agentKeys),onRetry:({method:t,path:r,attempt:o,delayMs:a,error:n})=>e.logger.warn?.(`[beeos-claw] Agent Gateway ${t} ${r} retry ${o} in ${a}ms: ${n instanceof Error?n.message:String(n)}`)}):null;const t=Buffer.from(agentKeys.publicKey).toString("base64");e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (publicKey: ${t})`)}catch(t){e.logger.warn?.(`[beeos-claw] Failed to load agent key pair: ${t}`),e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (no key pair — signed requests disabled)`)}else e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (no keyFile configured)`);return agentGateway&&(setUploadDeps({gateway:agentGateway,logger:e.logger}),registerLocalFileExtractor(browserScreenshotExtractor),registerLocalFileExtractor(deliverableFileExtractor),e.logger.info?.("[beeos-claw] Upload deps + local file extractors registered")),lastOpenclawConfig=t,sharedWriteObs=n,setOpenClawConfigSnapshot(t),{cfg:o,writeObs:n,thirdPartyChannels:a,openclawConfig:t}}function registerUploadTools(e,t,r){const{cfg:o,writeObs:a}=t,n=Boolean(pluginCloudRuntimeTarget(e));if(n){if(!e.on)throw new Error("native output Files Host hook unavailable");e.on("before_tool_call",(t,r)=>nativeOutputToolCallGate(t,r,e.logger))}cleanupUploadToolResultCache().catch(t=>{e.logger.warn?.(`[beeos_upload_file] cache cleanup failed on startup: ${String(t)}`)}),e.registerTool(t=>({name:BEEOS_UPLOAD_TOOL_NAME,description:BEEOS_UPLOAD_TOOL_DESCRIPTION,parameters:BEEOS_UPLOAD_TOOL_SCHEMA,async execute(r,i,s){const l=n?consumeNativeOutputTool(r):void 0,c=t.workspaceDir??sessionWorkspaceDir(t.sessionKey),u=await executeUpload(i,agentGateway,s,l?(e,t)=>uploadNativeOutputFile(e,o.agentGatewayUrl,l,t,s,BEEOS_UPLOAD_REQUEST_TIMEOUT_MS):void 0,e.logger,l?c:void 0);return e.logger.debug?.(`[beeos_upload_file] toolCallId=${r} ok=${u.ok}`),a({component:"upload-tool",domain:"tool",name:u.ok?"upload.success":"upload.failure",severity:u.ok?"info":"warn",payload:{toolCallId:r,ok:u.ok,fileCount:u.files?.length??0,error:u.error}}),(async t=>{try{await writeUploadToolResult(r,BEEOS_UPLOAD_TOOL_NAME,t),await cleanupUploadToolResultCache()}catch(t){e.logger.warn?.(`[beeos_upload_file] persist cache failed toolCallId=${r}: ${String(t)}`)}return t})(u)}}),{name:BEEOS_UPLOAD_TOOL_NAME}),e.registerTool({name:BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,description:BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION,parameters:BEEOS_DESKTOP_SCREENSHOT_TOOL_SCHEMA,async execute(t,r,o){e.logger.debug?.(`[beeos_desktop_screenshot] toolCallId=${t} params=${JSON.stringify(r)}`);const n=await executeDesktopScreenshot(r,agentGateway,o);return e.logger.debug?.(`[beeos_desktop_screenshot] toolCallId=${t} ok=${n.ok}`),a({component:"desktop-screenshot-tool",domain:"tool",name:n.ok?"desktop_screenshot.success":"desktop_screenshot.failure",severity:n.ok?"info":"warn",payload:{toolCallId:t,ok:n.ok,path:n.path,fileCount:n.files?.length??0,error:n.error}}),(async r=>{try{await writeUploadToolResult(t,BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,r),await cleanupUploadToolResultCache()}catch(r){e.logger.warn?.(`[beeos_desktop_screenshot] persist cache failed toolCallId=${t}: ${String(r)}`)}return r})(n)}}),e.registerHttpRoute({path:"/beeos/files/stage",auth:"gateway",async handler(e,r){await handleFileStage(e,r,t.cfg)}}),e.registerHttpRoute({path:"/beeos/status",auth:"plugin",handler(e,t){handleStatusRequest(e,t,{publicKey:agentKeys?.publicKey??null,pluginVersion:PLUGIN_VERSION})}}),e.registerTool({name:BEEOS_LIST_FILES_TOOL_NAME,description:BEEOS_LIST_FILES_TOOL_DESCRIPTION,parameters:BEEOS_LIST_FILES_TOOL_SCHEMA,async execute(t,r,o){e.logger.debug?.(`[beeos_list_files] toolCallId=${t} params=${JSON.stringify(r)}`);const n=await executeListFiles(r,agentGateway,o);return a({component:"file-list-tool",domain:"tool",name:n.ok?"list_files.success":"list_files.failure",severity:n.ok?"info":"warn",payload:{toolCallId:t,ok:n.ok,fileCount:n.files?.length??0,error:n.error}}),n}}),e.registerTool(t=>({name:BEEOS_FETCH_FILE_TOOL_NAME,description:BEEOS_FETCH_FILE_TOOL_DESCRIPTION,parameters:BEEOS_FETCH_FILE_TOOL_SCHEMA,async execute(r,i,s){e.logger.debug?.(`[beeos_fetch_file] toolCallId=${r} params=${JSON.stringify(i)}`);const l=await executeFetchFile(i,agentGateway,{signal:s,workspaceDir:t.workspaceDir,...n?{native:{gatewayUrl:o.agentGatewayUrl,capability:consumeNativeOutputTool(r)}}:{}});return a({component:"file-fetch-tool",domain:"tool",name:l.ok?"fetch_file.success":"fetch_file.failure",severity:l.ok?"info":"warn",payload:{toolCallId:r,ok:l.ok,path:l.path,size:l.size,error:l.error}}),l}}),{name:BEEOS_FETCH_FILE_TOOL_NAME})}function registerServices(e,t,r){const{cfg:o,writeObs:a,thirdPartyChannels:n}=t,i=centralNativeChatEnabled()?requireCentralNativeSessionHost(e.runtime):void 0;if(sharedAutomationTurnPolicy.disable(),"function"==typeof e.on)try{e.on("before_tool_call",(e,t)=>sharedAutomationTurnPolicy.check(e.toolName,{sessionKey:t?.sessionKey,runId:t?.runId??e.runId}),{priority:100}),sharedAutomationTurnPolicy.enable()}catch{e.logger.warn?.("[beeos-claw] Automation Wake disabled: tool guard unavailable")}if("function"!=typeof e.on){if(o.messageBus.enabled)throw new Error("openclaw_before_message_write_hook_unavailable")}else registerModelCallObservationHooks((t,r)=>e.on(t,r),sharedModelCallObservationRouter),e.on("before_message_write",(t,r)=>{const o=t.sessionKey??r.sessionKey;if(!o)return void e.logger.debug?.("[before_message_write] ignored assistant write without sessionKey");sharedAssistantMessageCommitRouter.route(o,t.message)||e.logger.debug?.(`[before_message_write] no active IM commit target sessionKey=${o} active_targets=${sharedAssistantMessageCommitRouter.size()}`)}),e.on("before_tool_call",(e,t)=>{if("ask_user"!==(e.toolName||t.toolName))return;const r={sessionKey:t.sessionKey,runId:t.runId??e.runId,toolCallId:t.toolCallId??e.toolCallId};sharedQuestionBridge.observeAskUser(r),relayCentralAskUser((e,t)=>sharedGatewayClient?sharedGatewayClient.request(e,t):Promise.reject(new Error("Not connected to Gateway")),r).catch(e=>approvalLogger?.warn?.(`[question] central relay failed: ${e instanceof Error?e.message:String(e)}`))}),e.on("after_tool_call",(t,r)=>{const o=r.sessionKey,a=t.toolCallId??r.toolCallId,n=t.toolName||r.toolName;if(t.runId&&r.runId&&t.runId!==r.runId||t.toolCallId&&r.toolCallId&&t.toolCallId!==r.toolCallId||nativeHtmlDeliveryForRun(t.runId??r.runId)?.observe(n,t.params,t.result,Boolean(t.error),a),!o||!a||!n)return void e.logger.debug?.(`[after_tool_call] ignored structured result without correlation sessionKey=${o??"missing"} toolCallId=${a??"missing"}`);observeToolCallForDelivery(t,o);sharedToolResultObservationRouter.route(o,{toolCallId:a,toolName:n,rawResult:t.result,isError:Boolean(t.error)})||e.logger.debug?.(`[after_tool_call] no active IM observation target sessionKey=${o} active_targets=${sharedToolResultObservationRouter.size()}`)});const s=agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):void 0,l=join(process.env.OPENCLAW_HOME||join(homedir(),".openclaw"),"beeos"),c=sharedInboundExecutionJournal??=new FileInboundExecutionJournal(join(l,"inbound-execution-journal.v1.jsonl"));sharedMcpProjection??=new OpenClawNativeMcpProjection,!sharedMcpCredentialVault&&agentKeys&&s&&(sharedMcpCredentialVault=new LocalEncryptedCredentialReferenceVault(join(l,"mcp-credential-vault.json"),s,agentKeys.privateKey));const u=pluginCloudRuntimeTarget(e);if(setClaimedCloudRuntimeInstanceId(u),u&&(!agentKeys||!agentGateway))throw new Error("Cloud runtime authority requires an agent identity and gateway transport");const d=sharedRuntimeAuthority?.cloudTargetInstanceId;if(d&&u&&d!==u)throw new Error("Cloud runtime authority target changed during process lifetime");if(sharedRuntimeAuthority&&!d&&u&&sharedRuntimeAuthority.bindCloudTarget(u),!sharedRuntimeAuthority&&agentKeys&&agentGateway&&(sharedRuntimeAuthority=new RuntimeProductionAuthority({stateDirectory:l,gateway:agentGateway,keys:agentKeys,targetInstanceId:u,logger:e.logger,getMSConnectionStatus:e=>sharedMSConnectionStatus.get(e),identityLane:identityLaneFromEnvironment()})),sharedGatewayClient||(sharedGatewayClient=new GatewayClient({url:o.gateway.url,token:o.gateway.token||"",clientId:o.gateway.clientId,openclawCanvasCompat:!!o.openclawCanvasCompat,retry:{baseMs:o.retry.baseMs,maxMs:o.retry.maxMs,maxAttempts:o.retry.maxAttempts}}),sharedGatewayClient.on("gateway-event",(e,t)=>{sharedApprovalBridge.onGatewayEvent(e,t),sharedQuestionBridge.onGatewayEvent(e,t)})),approvalLogger??=e.logger,sharedRuntimeAgentCapabilities??={canvas:o.canvasEnabled,terminal:!1,webSsh:!1,fileSystem:!0,image:!0,audio:!1,mcp:!0,cron:!0,streaming:!0,pushNotifications:o.messageBus.enabled,...o.messageBus.enabled&&sharedAutomationTurnPolicy.isReady()&&agentGateway?{automationWake:!0}:{}},!sharedAgentProjection&&sharedRuntimeAuthority&&agentGateway){const t=sharedRuntimeAuthority;sharedAgentProjection=new AgentProjectionProduction({authority:t,stateFile:join(t.stateDirectory,"runtime-agent-projection.json"),journal:t.journal,identities:t.identities,source:new OpenClawAgentProjectionSource(()=>sharedGatewayClient),transport:new AgentGatewayHttpProjectionTransport({gateway:agentGateway,getRuntimeLeaseCredential:e=>{const r=t.authorityLease;if(!r||r.instanceId!==e.instanceId||r.leaseId!==e.leaseId||r.runtimeEpoch!==e.runtimeEpoch||r.handlerIdentity!==e.handlerIdentity)throw new Error("agent projection fenced by current runtime lease");return r.runtimeLeaseCredential},onAccepted:t=>{0!==t.size&&sharedAgentMappings.replace(t).catch(t=>{e.logger.warn?.("[agent-projection] mapping publication failed: "+(t instanceof Error?t.message:String(t)))})}}),capabilities:sharedRuntimeAgentCapabilities,logger:e.logger})}sharedRuntimeOwner??=new OpenClawRuntimeProcessOwner(sharedGatewayClient,sharedAgentProjection,e.logger);const g=sharedRuntimeOwner;sharedSessionMutationCoordinator??=new SessionMutationCoordinator(sharedSessionWriteGate,new OpenClawSessionWriteQuiescence(e.logger,{agentId:o.gateway.agentId||"main",...i?{nativeWritersQuiescent:e=>i.nativeWritersQuiescent({sessionKey:e})}:{}}),e.logger,{onRecoveryRequired:t=>{scheduleProcessRuntimeRestart(t,e.logger)}});const m=sharedSessionMutationCoordinator;if(i&&!sharedCentralPrompt){if(!sharedRuntimeAuthority?.cloudTargetInstanceId)throw new Error("central native chat requires the provisioned Cloud runtime authority");sharedCentralPrompt=createCentralNativeComposition({runtime:e.runtime,host:i,gatewayOrigin:o.agentGatewayUrl,stateDirectory:l,authority:sharedRuntimeAuthority,coordinator:m,logger:e.logger})}if(i&®isterCentralNativeMemoryTools(e),!sharedAcpServer){const t=sharedRuntimeAuthority&&agentGateway?new AgentGatewayTemplateOriginReporter({gateway:agentGateway}):void 0;sharedAcpServer=new ACPServer(o,e.logger,m,a,agentGateway??void 0,s,n,sharedTerminalManager,sharedRuntimeAuthority,void 0,sharedMcpProjection,sharedMcpCredentialVault,{gateway:g.client,agentProjection:sharedAgentProjection,markAgentProjectionDirty:()=>sharedAgentProjection?.markDirty(),templateOriginReporter:t,agentMappings:sharedAgentMappings,agentCapabilities:sharedRuntimeAgentCapabilities,createRunOutputRouter:createPeerRunOutputRouterFactory(new MessageServiceRunOutputChannel({getClient:()=>sharedMessageClientOwner.current?.client??null,logger:e.logger,writeObs:a})),runExclusive:(t,r,o)=>sharedImHotPathDeferral.runExclusive(t,r,e.logger,o)})}const p=sharedAcpServer,h=()=>sharedAgentMappings.snapshot()?.values().next().value;r.current=p,sharedMcpNativeProjectionNudge.request({registrationMode:e.registrationMode,fingerprint:fingerprintMcpServers(t.openclawConfig),logger:e.logger});const y=sharedPromptRunStore,{enabled:v,principalId:w,a2aEnabled:f}=o.messageBus;let C;!u&&o.agentGatewayUrl&&agentKeys&&(C=createBeeosClawMessageTokenProvider({agentGatewayUrl:o.agentGatewayUrl,identity:agentKeyPairToIdentity(agentKeys)}));const R=process.env.MESSAGE_RUNTIME_DELIVERY_KEY?.trim(),b=w||process.env.BEEOS_PRINCIPAL_ID||"",S=C?sharedMessageClientOwner.configure({tokenProvider:C,identityId:b,...o.messageBus.serviceUrl?{serviceUrl:o.messageBus.serviceUrl}:{},logger:e.logger,...sharedRuntimeAuthority&&R?{runtimeDelivery:{scopedDeliveryKey:R,authority:{currentLease:()=>{const e=sharedRuntimeAuthority?.authorityLease,t=sharedRuntimeAuthority?.currentConsumerBinding();return e&&t?{...e,journalStoreId:t.journalStoreId,journalGeneration:t.journalGeneration}:null}}}}:{}}):void 0,E=u&&o.messageBus.serviceUrl&&sharedRuntimeAuthority?new NodeRuntimeDeliveryPort({serviceOrigin:async()=>o.messageBus.serviceUrl},{currentLease:()=>{const e=sharedRuntimeAuthority?.authorityLease,t=sharedRuntimeAuthority?.currentConsumerBinding();return e&&t&&e.instanceId===u?{...e,journalStoreId:t.journalStoreId,journalGeneration:t.journalGeneration}:null},subscribeAuthority:e=>sharedRuntimeAuthority.subscribeAuthority(e)}):void 0;attachNativeCloudChat(e,o);const O=sharedRuntimeAuthority,_=o.messageBus.serviceUrl;S&&O&&_&&R?p.setCronConversationDelivery({deliver:async e=>{const t=O.authorityLease;if(!t)throw new Error("current runtime authority lease unavailable for cron delivery");const r=new MessageServiceCronDeliveryHttpAuthority({messageServiceUrl:_,scopedDeliveryKey:R,fetchAuthorized:(e,t)=>fetchRuntimeLeaseAttempt(e,t??{})});return await r.deliver({...e,runtimeLeaseCredential:t.runtimeLeaseCredential})}}):p.setCronConversationDelivery(void 0);const A=sharedRuntimeAuthority?.journal??new FileRuntimeCommandJournal(join(l,"runtime-command-journal.json"),void 0,void 0,{onMaintenanceError:t=>e.logger.error?.(`[runtime-journal] event=checkpoint_failed trigger=threshold error=${t instanceof Error?t.message:String(t)}`)}),I=g.createRegistrationToken();e.registerService({id:"beeos-acp",async start(){const t=Date.now(),r=_pluginRegisteredAt?t-_pluginRegisteredAt:-1;e.logger.info?.(`[beeos-claw] beeos-acp service start() begin, sincePluginRegister=${r}ms, bridge.url=${o.bridge.url||"(empty)"}`);const a=await createRuntimeServiceProductionCandidate({...agentGateway?{authorizationAdapter:new AgentGatewayGrantJwksReadinessAdapter({gateway:agentGateway})}:{},onGrantJwksWarm:t=>{t.ready?e.logger.info?.("[beeos-claw] Gateway grant keyset loaded"):e.logger.warn?.(`[beeos-claw] Gateway grant keyset not ready yet (attempt ${t.attempt}): ${t.error instanceof Error?t.error.message:String(t.error)}`)},...S&&agentGateway&&R?{transportAdapter:new RuntimeServiceTransportReadinessAdapter({gateway:agentGateway,messageService:S.nodeTransport,messageClient:S.client,configuredServiceUrl:o.messageBus.serviceUrl,scopedDeliveryKey:R})}:{},...E&&agentGateway&&o.messageBus.serviceUrl?{cloudTransportAdapter:new CloudRuntimeServiceTransportReadinessAdapter({gateway:agentGateway,configuredServiceUrl:o.messageBus.serviceUrl,runtimeDelivery:E,...sharedCentralPrompt?{centralPrompt:sharedCentralPrompt}:{},...sharedNativeCloudChat?{sessionNewConversation:sharedNativeCloudChat.sessionNewConversation,nativePrompt:{http:sharedNativeCloudChat.http,inputFiles:new NativeInputFilesHttpClient(o.agentGatewayUrl,()=>sharedRuntimeAuthority.authorityLease,(e,t)=>fetch(e,t)),runBoundary:new MessageServiceConversationRunBoundary({transport:{start:e=>E.startConversationRun(e),finish:e=>E.finishConversationRun(e)}}),host:{htmlDeliveryEnabled:o.canvasEnabled,resolveNativePromptSessionKey:(e,t)=>p.resolveNativePromptSessionKey(e,t),prepareNativePromptModel:(e,t,r)=>p.prepareNativePromptModel(e,t,r),runtime:e.runtime,pluginConfig:o,logger:e.logger,promptRunStore:y,assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,approvalStreams:sharedApprovalBridge,questionStreams:sharedQuestionBridge,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:m,abortTransport:{chatAbort:(e,t)=>p.chatAbort(e,t)},activeRunAuthority:p.getActiveRunAuthority(),waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{})}}}:{}})}:{},commandJournal:A,poisonJournal:new FileRuntimePoisonDeliveryJournal(join(l,"runtime-poison-deliveries.json")),onConsumerDeliveryError:t=>{const r=null!==t&&"object"==typeof t?t:{},o=e=>"string"==typeof e&&e.length>0&&e.length<=256&&!/[\u0000-\u001f\u007f]/.test(e)?JSON.stringify(e):JSON.stringify("unavailable"),a="string"==typeof r.code&&/^[A-Za-z0-9_.:-]{1,64}$/.test(r.code)?r.code:"unavailable",n="number"==typeof r.status&&Number.isInteger(r.status)&&r.status>=100&&r.status<=599?String(r.status):"unavailable";e.logger.error?.(`[runtime-service] delivery worker failed before acknowledgement; delivery retained for retry: operation_id=${o(r.operationId)} delivery_id=${o(r.deliveryId)} code=${a} status=${n}`)},onConsumerLeaseStarvation:({starvedForMs:t,recovered:r})=>{const o=Math.round(t/1e3);r?e.logger.info?.(`[runtime-service] runtime authority lease restored after ${o}s without delivery reads`):e.logger.warn?.(`[runtime-service] no runtime authority lease for ${o}s; delivery reads suspended, queued runtime operations (model switch, session control) will not be consumed`)},onConsumerRequestFailure:t=>e.logger.error?.(`[runtime-service] request failed operationId=${t.operationId} method=${t.method}: ${t.error instanceof Error?t.error.stack??t.error.message:String(t.error)}`)});if(sharedRuntimeAuthority?.setRuntimeServiceMethods("ready"===a.status?a.serviceMethods:[]),sharedRuntimeAuthority?.setRuntimeResourceBindingContractRevision("ready"===a.status?a.resourceBindingContractRevision:void 0),p.setRuntimeRpcConsumerFactory("ready"===a.status?a.factory:void 0),"unavailable"===a.status?e.logger.warn?.("[runtime-service] capability fenced: "+a.blockers.map(e=>e.id).join(",")):a.capabilityBlockers.length&&e.logger.warn?.("[runtime-service] method capability fenced: "+a.capabilityBlockers.map(e=>e.method).join(",")),!o.bridge.url&&agentGateway){const t=Date.now(),r=await agentGateway.bridge.config();if(e.logger.info?.(`[beeos-claw] bridge discovery took ${Date.now()-t}ms result=${r?.url??"null"}`),r)o.bridge.url=r.url,writeDiscoveryCache({bridge:{url:r.url,discoveredAt:Date.now()}}),e.logger.info?.(`[beeos-claw] Bridge URL discovered from Agent Gateway: ${r.url}`);else{const t=readDiscoveryCache();t?.bridge?.url?(o.bridge.url=t.bridge.url,e.logger.info?.(`[beeos-claw] Bridge URL from cache (GW unreachable): ${t.bridge.url}`)):e.logger.debug?.("[beeos-claw] Bridge URL not available (no GW, no cache) — bridge disabled")}}await g.acquire(I);try{await p.start(o.bridge.url||void 0)}catch(e){throw await g.release(I),e}e.logger.info?.(`[beeos-claw] ACP Server started (total service start: ${Date.now()-t}ms)`)},async stop(){try{await g.release(I)}finally{await p.stop()}await A.checkpoint(),e.logger.info?.("[runtime-service] command journal checkpoint completed"),e.logger.info?.("[beeos-claw] ACP Server stopped")}});if(v&&void 0!==C&&C){const t=sharedMessageClientOwner.createRegistrationToken(),r=async(e,t)=>{const r=await C(e);if(!r.identityId||r.identityId!==e)throw new Error("Message SDK token identity did not match the current runtime authority");return{principalId:e,runtimeEpoch:t}},o=(e,t,r)=>({getLocalAgentId:()=>t,resolveLocalAgentId:e=>e===r?t:void 0,getDefaultPlatformAgent:()=>({instanceId:e.principalId}),ensureImInboundSession:(e,t,r,o)=>{p.ensureImInboundSession(e,t,r,o)},chatAbort:(e,t)=>p.chatAbort(e,t)}),n=sharedRuntimeAuthority?new RuntimeAuthorityMessageBusLifecycle({authority:sharedRuntimeAuthority,logger:e.logger,bus:{connect:async n=>{await sharedMessageClientOwner.acquire(t,async t=>{const i=await r(n.instanceId,n.runtimeEpoch),s=t.client,l={leaseId:n.leaseId,runtimeEpoch:n.runtimeEpoch};sharedMSConnectionStatus.bind(l);const u=new Map,d=new MessageProjectionInboundConsumer({client:s,bindings:()=>{const t=sharedRuntimeAuthority?.authorityLease;if(!t||t.instanceId!==i.principalId||t.runtimeEpoch!==i.runtimeEpoch)return[];const r=sharedAgentMappings.snapshot();return r?[...r.entries()].flatMap(([r,n])=>{if(!n.id||n.instanceId!==i.principalId)return[];let l=u.get(n.id);return l&&l.localAgentId===r||(l={localAgentId:r,inbound:createImInboundHandler({automationTurnPolicy:sharedAutomationTurnPolicy,runtime:e.runtime,pluginConfig:e.pluginConfig,client:s,localServer:o(i,r,n.id),promptRunStore:y,waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{}),assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,approvalStreams:sharedApprovalBridge,questionStreams:sharedQuestionBridge,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:m,logger:e.logger,writeObs:a,principalIdOverride:i.principalId,activeRunAuthority:p.getActiveRunAuthority(),applyTurnModel:(e,t)=>p.applyImTurnModel(e,t),restoreTurnModel:e=>p.restoreImTurnModel(e),...agentGateway?{completeA2ATask:(t,r,o)=>completeA2ATask({gateway:agentGateway,logger:e.logger},t,r,o)}:{}})},u.set(n.id,l)),[{principalId:i.principalId,targetAgentId:n.id,runtimeEpoch:t.runtimeEpoch,inbound:l.inbound}]}):[]},executionJournal:c,logger:e.logger}),g=sharedAgentMappings.subscribe(()=>{sharedActiveMessageConsumer===d&&d.refresh()}),h=sharedRuntimeAuthority?.subscribeAuthority(()=>{sharedActiveMessageConsumer===d&&d.refresh()})??(()=>{}),v=new MessageClientTerminalStateRecovery({logger:e.logger,isCurrent:()=>{if(sharedActiveMessageConsumer!==d)return!1;const e=sharedRuntimeAuthority?.authorityLease;return null!=e&&e.instanceId===i.principalId&&e.runtimeEpoch===i.runtimeEpoch&&e.leaseId===n.leaseId&&e.handlerIdentity===n.handlerIdentity},reconnect:async()=>{if("failed"===s.getSnapshot().connection){await s.connect();try{await p.rebindRuntimeDelivery()}catch(t){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient recovery: ${t instanceof Error?t.message:String(t)}`)}}}});let w=s.getSnapshot().connection;sharedMSConnectionStatus.setIfCurrent(l,w);const f=s.subscribe(()=>{const t=s.getSnapshot();t.connection!==w&&(w=t.connection,sharedMSConnectionStatus.setIfCurrent(l,t.connection),"connected"===t.connection?(v.notifyConnected(),e.logger.info?.(`[beeos-claw] connection transport=message_service_realtime state=connected localAgentId=${p.getLocalAgentId()} principalId=${i.principalId}`)):"failed"===t.connection?(e.logger.warn?.(`[beeos-claw] connection transport=message_service_realtime state=failed principalId=${i.principalId} recoveryError=${t.recoveryError??"unknown"}`),v.notifyFailed()):"disconnected"!==t.connection&&"reconnecting"!==t.connection||e.logger.warn?.(`[beeos-claw] connection transport=message_service_realtime state=${t.connection} principalId=${i.principalId}; SDK owns reconnect/recovery`))});sharedActiveMessageConsumer=d,d.start();try{await s.connect()}catch(e){throw sharedActiveMessageConsumer===d&&(sharedActiveMessageConsumer=void 0),sharedMSConnectionStatus.resetIfCurrent(l),v.dispose(),await d.stop(),g(),h(),f(),await s.disconnect().catch(()=>{}),e}try{await p.rebindRuntimeDelivery()}catch(t){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient connect: ${t instanceof Error?t.message:String(t)}`)}return async()=>{sharedActiveMessageConsumer===d&&(sharedActiveMessageConsumer=void 0),sharedMSConnectionStatus.resetIfCurrent(l),v.dispose(),await d.stop(),h(),f(),await s.disconnect(),e.logger.info?.("[beeos-claw] MessageClient disconnected")}})},disconnect:async()=>{await sharedMessageClientOwner.release(t)}}}):void 0;e.registerService({id:"beeos-message-bus",async start(){n?n.start():e.logger.warn?.("[beeos-claw] Message bus requires runtime authority; waiting is unavailable without Agent Gateway runtime identity")},async stop(){await(n?.stop())}})}else v?e.logger.warn?.("[beeos-claw] Message bus enabled but Agent Gateway token provider is unavailable — disabled"):e.logger.info?.(`[beeos-claw] Message bus disabled (enabled=${v})`);if(o.messageBus.enabled&&u&&!sharedNativeCloudChat&&e.logger.warn?.("[beeos-claw] Cloud message bus enabled but native composition unavailable (messageBus.serviceUrl or runtime authority missing) — disabled"),!1!==f&&agentGateway){const t=e=>p.getGatewaySessionKeyForToolCall(e),r=e=>p.getMentionsForToolCall(e),o=(e,t)=>{p.broadcastNotification(e,t)},a=new TaskHandleRegistry;registerA2ATools(e,{gateway:agentGateway,logger:e.logger},a,t,r,o,()=>h()?.instanceId),e.logger.info?.("[beeos-claw] A2A tools registered (beeos_discover_agents, beeos_call_agent) via REST")}if(agentGateway&&(registerAutomationTools(e,{gateway:agentGateway,callConnectorTool:harnessConnectorToolCaller(),logger:e.logger,getDefaultAgent:()=>{const e=h();return e?{id:e.id,instanceId:e.instanceId}:void 0},getCurrentConversationId:e=>{const t=p.getGatewaySessionKeyForToolCall(e);return t?extractBeeosConversationIdFromSessionKey(t):void 0}}),e.logger.info?.("[beeos-claw] Automation tools registered (create/create_webhook/capabilities/preflight/list/get/run/runs/get_run)")),o.canvasEnabled){sharedCanvasState||(sharedCanvasState=new CanvasStateManager);const t=sharedCanvasState;if(agentGateway&&agentKeys){t.setLogger(e.logger);const r=claimedSandboxId(),a=createSandboxCanvasTokenProvider(agentGateway,r,()=>sharedRuntimeAuthority?.authorityLease),n=n=>{const i=new CanvasRelayClient({canvasRelayUrl:o.canvasRelayUrl,agentKeys:agentKeys,...r?{}:{agentId:n.id},displayName:n.displayName,avatarUrl:n.avatarUrl,tokenProvider:a,onConnected:()=>p.flushPendingCanvasLinks(),onReconnect:()=>p.onRelayReconnected(),logger:e.logger});t.setRelayClient(i),t.setAgentId(n.id),p.wireRelayActionHandler(),i.connect(),e.logger.info?.(`[beeos-claw] Canvas Relay multiplexed client connected (agentId=${n.id}, name=${n.name??"none"})`)};e.registerService(createCanvasRelayService({getAgent:r?()=>({id:`sandbox:${r}`}):h,onceAgentReady:e=>sharedAgentMappings.onceReady(e),initRelay:n,stopRelay:()=>t.getRelayClient()?.disconnect(),logger:e.logger})),e.logger.info?.("[beeos-claw] Canvas Relay configured")}else e.logger.warn?.("[beeos-claw] Canvas Relay unavailable: agentGatewayUrl or agentKeys missing");const r={stateManager:t,logger:e.logger,writeObs:e=>a(e),getActiveSessionId:e=>p.getSessionIdForToolCall(e),getPlatformAgentId:e=>p.getPlatformAgentIdForToolCall(e),getGatewaySessionKey:e=>p.getGatewaySessionKeyForToolCall(e),waitForAgentSync:()=>sharedAgentMappings.waitForSynchronization(),publishStaticHtml:createStaticCanvasHtmlPublisher(pluginCloudRuntimeTarget(e)?o.agentGatewayUrl:void 0)},i=new FormSchemaRegistry,s=buildCronSchemas(n);i.register(s.create),i.register(s.update);const l=new ResourceDescriptorRegistry;l.register(CRON_RESOURCE);const c=e=>async(t,r,o)=>(p.preMapToolCallSession(t),e(t,r));e.registerTool({name:RENDER_UI_TOOL_NAME,description:RENDER_UI_TOOL_DESCRIPTION,parameters:RENDER_UI_TOOL_SCHEMA,execute:c(createRenderUiToolExecutor(r))}),e.registerTool({name:CLOSE_UI_TOOL_NAME,description:CLOSE_UI_TOOL_DESCRIPTION,parameters:CLOSE_UI_TOOL_SCHEMA,execute:c(createCloseUiHandler(r))}),p.setCanvasState(t,{schemaRegistry:i,descriptorRegistry:l});const u=p.getFormBuilder();u&&e.registerTool({name:RENDER_FORM_TOOL_NAME,description:buildRenderFormDescription(i),parameters:RENDER_FORM_TOOL_SCHEMA,execute:c(createRenderFormHandler({registry:i,builder:u,logger:e.logger}))});const d=p.getResourceRenderer();if(d){generateActionTools(l,e,async(e,t)=>p.gatewayRequest(e,t),d,e.logger)}const g=buildToolRoutingHint(BEEOS_FILE_RESOURCE_ROUTING_RULE,BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME),m=new Set([RENDER_UI_TOOL_NAME,CLOSE_UI_TOOL_NAME,RENDER_FORM_TOOL_NAME]),y=256,v=new Map;if("function"==typeof e.on){try{e.on("before_prompt_build",(e,t)=>{if(t?.sessionKey){if(v.size>=y&&!v.has(t.sessionKey)){const e=v.keys().next().value;void 0!==e&&v.delete(e)}v.set(t.sessionKey,t.channelId),rememberDeliveryWorkspace(t.sessionKey,t.workspaceDir)}const r=isThirdPartyChannel(n,{sessionKey:t?.sessionKey,channelId:t?.channelId});return t?.sessionKey||r?{appendSystemContext:buildAppendSystemContext({thirdParty:r,canvasSystemPrompt:`${CANVAS_PRESENTATION_GATE}\n\n${CANVAS_SYSTEM_PROMPT}`,toolRoutingHint:g})}:{appendSystemContext:g}}),e.logger.debug?.("[beeos-claw] Canvas system prompt hook registered: before_prompt_build")}catch{e.logger.debug?.("[beeos-claw] before_prompt_build hook not supported")}try{e.on("before_tool_call",(e,t)=>{if(t?.sessionKey&&p.setPendingToolCallSessionKey(t.sessionKey),!m.has(e.toolName))return;const r=t?.sessionKey?v.get(t.sessionKey):void 0,o=isThirdPartyChannel(n,{sessionKey:t?.sessionKey,channelId:r}),a=canvasToolBlockReason({thirdParty:o,hasSession:Boolean(t?.sessionKey)});return a?{block:!0,blockReason:a}:void 0}),e.logger.debug?.("[beeos-claw] Canvas tool guard registered: before_tool_call")}catch{e.logger.debug?.("[beeos-claw] before_tool_call hook not supported")}}e.logger.info?.("[beeos-claw] Canvas tools registered (render_ui, close_ui, render_form + auto-action tools)")}else e.logger.info?.("[beeos-claw] Canvas disabled by config (canvasEnabled=false)");if(o.bridge.shell.enabled&&!0===o.legacyTerminalWsEnabled){const t=createTerminalWebSocketService({config:{port:o.terminalWsPort,token:agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):"",allowedOrigins:o.terminalWsAllowedOrigins},terminalMgr:sharedTerminalManager,logger:e.logger,writeObs:a});e.registerService({id:"beeos-terminal-ws",start(){t.start(),e.logger.info?.(`[beeos-claw] Terminal WS started on port ${o.terminalWsPort}`)},stop(){t.stop(),e.logger.info?.("[beeos-claw] Terminal WS stopped")}})}else o.bridge.shell.enabled?e.logger.info?.("[beeos-claw] Legacy static-token Terminal WS disabled (default)"):e.logger.info?.("[beeos-claw] Terminal/shell disabled by config (bridge.shell.enabled=false)");if(t.openclawConfig){const r=mirrorOpenClawConfig(t.openclawConfig);r.copied?e.logger.info?.(`[beeos-claw] mirrored openclaw config to ${r.destinationPath}`):e.logger.debug?.(`[beeos-claw] openclaw config mirror skipped: ${r.reason}`)}}export function pluginCloudRuntimeTarget(e){const t=e.pluginConfig?.cloudRuntimeInstanceId;return cloudRuntimeTargetInstanceId("string"==typeof t?t:claimedSandboxId())}function attachNativeCloudChat(e,t){if(sharedNativeChatService)return e.registerService(sharedNativeChatService),sharedNativeCloudChat;const r=sharedRuntimeAuthority,o=t.messageBus.serviceUrl,a=sharedAcpServer,n=sharedSessionMutationCoordinator;if(!(r&&r.cloudTargetInstanceId&&o&&a&&n))return sharedNativeCloudChat;const i=sharedNativeCloudChat??createNativeCloudChatComposition({authority:nativeCloudChatAuthorityFromRuntimeAuthority(r),serviceUrl:o,logger:e.logger});if(sharedNativeCloudChat=i,!t.messageBus.enabled)return i;const s=i,l=r;let c;const u=new Map,d=new RuntimeAuthorityMessageBusLifecycle({authority:l,logger:e.logger,bus:{connect:async t=>{c?.(),u.clear(),c=s.adapter.listen({eventTypes:["message.created"]},r=>{if(r.type===APPROVAL_DECISION_MESSAGE_TYPE&&r.senderId?.startsWith("user:")&&isApprovalDocument(r.content))return void sharedApprovalBridge.onDecision(r.content);if("user.continue"===r.type&&isQuestionResponseDocument(r.content))return void sharedQuestionBridge.onResponse(r);const o=(r.content??{}).metadata??{},i="string"==typeof o.target_agent_id?o.target_agent_id:"",l=i?((t,r)=>{const o=sharedAgentMappings.snapshot();if(o)for(const[i,l]of o.entries()){if(l.id!==r)continue;if(l.instanceId!==t.instanceId)continue;const o=`${i}\0${l.id}`;let c=u.get(o);return c||(c={localAgentId:i,inbound:createImInboundHandler({runtime:e.runtime,pluginConfig:e.pluginConfig,client:s.adapter,localServer:{getLocalAgentId:()=>i,resolveLocalAgentId:e=>e===l.id?i:void 0,getDefaultPlatformAgent:()=>({instanceId:t.instanceId}),ensureImInboundSession:(e,t,r,o)=>{a.ensureImInboundSession(e,t,r,o)},chatAbort:(e,t)=>a.chatAbort(e,t)},promptRunStore:sharedPromptRunStore,waitIfExclusive:(t,r)=>sharedImHotPathDeferral.waitIfExclusive(t,e.logger,r).then(()=>{}),assistantMessageCommitRouter:sharedAssistantMessageCommitRouter,toolResultObservationRouter:sharedToolResultObservationRouter,approvalStreams:sharedApprovalBridge,questionStreams:sharedQuestionBridge,modelCallObservationRouter:sharedModelCallObservationRouter,sessionMutationCoordinator:n,logger:e.logger,writeObs:sharedWriteObs,principalIdOverride:t.instanceId,activeRunAuthority:a.getActiveRunAuthority(),applyTurnModel:(e,t)=>a.applyImTurnModel(e,t),restoreTurnModel:e=>a.restoreImTurnModel(e),...agentGateway?{completeA2ATask:(t,r,o)=>completeA2ATask({gateway:agentGateway,logger:e.logger},t,r,o)}:{}})},u.set(o,c)),c}})(t,i):void 0;if(!l)return void e.logger.warn?.(`[beeos-claw] native cloud chat dropped unresolvable target_agent_id=${i||"missing"} message_id=${r.id}`);("chat_cancel"===r.type?l.inbound.onChatCancel(r):l.inbound.onChatMessage(r)).catch(t=>{e.logger.error?.(`[beeos-claw] native cloud chat dispatch failed message_id=${r.id}: ${t instanceof Error?t.message:String(t)}`)})});try{await s.adapter.connect()}catch(e){throw c?.(),c=void 0,e}},disconnect:async()=>{c?.(),c=void 0,u.clear(),await s.adapter.disconnect()}}});return sharedNativeChatService={id:"beeos-native-cloud-chat",async start(){d.start()},async stop(){await d.stop()}},e.registerService(sharedNativeChatService),e.logger.info?.("[beeos-claw] native Cloud personal-chat composition registered"),i}const plugin={id:"beeos-claw",name:"beeos-claw",description:"BeeOS platform bridge plugin for OpenClaw. Provides file upload/download, ACP bridge, and observability.",version:PLUGIN_VERSION,register(e){if(_initializing)return;registerCentralNativeContextEngine(e),registerSandboxNativeActivation(e,()=>{if(!sharedSessionMutationCoordinator)throw new Error("native session writer coordinator is unavailable");return sharedSessionMutationCoordinator.activeMutationCount},createSandboxNativeTargetLookup(()=>sharedRuntimeAuthority,()=>sharedGatewayClient,{logger:e.logger}),async()=>{const e=sharedGatewayClient;if(!e)throw new Error("OpenClaw gateway is not connected");await e.waitForConnected(3e4),await e.request("secrets.reload",{})});const t=pluginCloudRuntimeTarget(e),r=void 0!==t&&t!==sharedRuntimeAuthority?.cloudTargetInstanceId,o=planPluginRegistration(e.registrationMode,_fullRuntimeRegistered,r);if("skip"!==o){_initializing=!0;try{if(!hasRuntimeReplyApi(e.runtime))throw e.logger.error?.("[beeos-claw] FATAL: OpenClaw runtime.channel.reply.dispatchReplyFromConfig not exposed. Upgrade OpenClaw or revert beeos-claw."),new Error("openclaw_runtime_reply_api_unavailable");const t=(t,r)=>{registerUploadTools(e,t,r),registerArouterLatencyRouting(e),registerArouterMediaProviders(e)};if("capabilities"===o&&sharedPluginContext){if(cachedCapabilityTools.length>0){const t=resolveCapabilityToolReplay({currentRegisterTool:e.registerTool,wrappedRegisterTool:wrappedRegisterTool,originalRegisterTool:rawRegisterTool}),r=replayCachedPluginTools((r,o)=>t.call(e,r,o),cachedCapabilityTools);return registerArouterLatencyRouting(e),registerArouterMediaProviders(e),void e.logger.info?.(`[beeos-claw] capability re-register mode=${e.registrationMode} tools_only count=${r}`)}const r={current:sharedAcpServer??null};return t(sharedPluginContext,r),registerServices(e,sharedPluginContext,r),void e.logger.info?.(`[beeos-claw] capability re-register mode=${e.registrationMode} capabilities_only`)}const r=initializePlugin(e);if(!r)return;const a={current:null};installUnhandledRejectionObserver(e,r.writeObs,a),ensureRegisterToolCache(e),cacheRuntimeRegistrations(e),cachedCapabilityTools.length=0,t(r,a),agentGateway&&(e.on?e.on("before_agent_finalize",async(e,t)=>{if(await fileDeliveryFinalizeDecision(e),!e.runId||!t?.runId||e.runId===t.runId)return nativeHtmlDeliveryForRun(e.runId??t?.runId)?.beforeFinalize(e)}):e.logger.warn?.("[file-delivery] OpenClaw plugin hooks unavailable; finalization check disabled")),registerServices(e,r,a),sharedPluginContext=r,marksFullRuntimeRegistered(e.registrationMode,o)&&(_fullRuntimeRegistered=!0),_pluginRegisteredAt=Date.now(),e.logger.info?.("[beeos-claw] Plugin registered successfully")}finally{_initializing=!1}}else if(!e.registrationMode||"full"===e.registrationMode){const t=resolveCapabilityToolReplay({currentRegisterTool:e.registerTool,wrappedRegisterTool:wrappedRegisterTool,originalRegisterTool:rawRegisterTool});replayCachedPluginTools((r,o)=>t.call(e,r,o),cachedCapabilityTools),replayRuntimeRegistrations(e),registerArouterLatencyRouting(e),registerArouterMediaProviders(e)}}};export default plugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{RuntimeChatStore,RuntimeLeaseHttp,RuntimeOriginalIntent,RuntimeMemory,createCloudGrantVerifier}from"@beeos-ai/cloud-harness-sdk";import{StateCentralNativeStore}from"./central-native-production.js";import{FileCentralNativePendingJournal}from"./central-native-pending-journal.js";import{installCentralNativeRuntime}from"./central-native-runtime.js";import{createCentralNativeHost}from"./central-native-host.js";import{NativeInputFilesHttpClient}from"./native-input-files-http.js";import{join}from"node:path";import{CentralNativeCredentials}from"./central-native-credentials.js";import{installSandboxNativeExecutionResolver}from"./sandbox-native-activation.js";import{createSandboxNativeExecutionResolver}from"./sandbox-native-execution-resolver.js";import{installCentralNativeMemoryCall}from"./central-native-memory.js";import{DECISION_ROUTE}from"./central-native-interactions.js";import{generateAndRecordSessionTitle,RuntimeLeaseHttpSessionTitles}from"./central-native-titles.js";import{resolveArouterApiKey,resolveArouterBaseUrl}from"../media/arouter-config.js";export function requireCentralNativeSessionHost(e){const t=e,r=t?.agent?.session;for(const e of["readNativeTranscript","pendingNativeTurns","nativeWritersQuiescent","drainNativeTurns","replaceNativeTranscript","compactNativeTranscript"])if("function"!=typeof r?.[e])throw new Error(`pinned OpenClaw central native API unavailable: ${e}`);if("function"!=typeof t?.config?.current)throw new Error("pinned OpenClaw current config API unavailable");return r}export function createCentralNativeComposition(e){const t=()=>e.authority.authorityLease,r=new CentralNativeCredentials({authority:e.authority,http:new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1})}),n=new StateCentralNativeStore(new RuntimeChatStore(new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1})),e=>r.credential(e),new RuntimeLeaseHttpSessionTitles(new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1}))),i=new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1}),a=new FileCentralNativePendingJournal(join(e.stateDirectory,"central-native-pending")),o=new RuntimeMemory(new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1}));installCentralNativeMemoryCall(async(e,t,i,a,s)=>{try{const l=await o.call(t,await r.credential(e),r.execution(e),i,a,s);if("recall"===t){if("string"!=typeof l.read_watermark||!l.read_watermark)throw new Error("native Memory read returned no original watermark");n.recordMemoryRead(e,{status:"read",watermark:l.read_watermark})}return l}catch(r){throw"recall"===t&&n.recordMemoryRead(e,{status:"unavailable",watermark:null}),r}});const s=new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1}),l=(e,t,n,i)=>r.bind(e,t,n,i);return installSandboxNativeExecutionResolver(createSandboxNativeExecutionResolver({authority:e.authority,original:new RuntimeOriginalIntent(new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1})),verifier:createCloudGrantVerifier(e.gatewayOrigin),bindCredential:l})),installCentralNativeRuntime({store:n,pending:a,host:e.host,activeWriters:()=>e.coordinator.activeMutationCount,observe:(e,t)=>n.bindExecutionObservation(e,t)}),{store:n,pending:a,bindCredential:l,recordGeneratedTitle:({binding:t,question:r,answer:i})=>{generateAndRecordSessionTitle({recordGeneratedTitle:(e,t)=>n.recordGeneratedTitle(e,t),binding:t,question:r,answer:i,resolveModelCredential:()=>{const t=e.runtime.config.current(),r=resolveArouterApiKey(t)??process.env.AROUTER_API_KEY??process.env.OPENAI_API_KEY;return r?{apiKey:r,baseUrl:resolveArouterBaseUrl(t)}:void 0},logger:e.logger})},host:createCentralNativeHost({runtime:e.runtime,native:e.host,currentConfig:()=>e.runtime.config.current(),coordinator:e.coordinator,getLease:t,logger:e.logger,publishDelta:async(e,t)=>{const n=await i.postJson("/api/v1/runtime/chat-store/stream",await r.credential(e),{context:e.context,session_id:e.sessionId,history_generation:e.historyGeneration,branch_id:e.branchId,response_id:e.responseId,attempt_id:e.attemptId,writer:e.writer,...t},{retry:!1});if(await(n.body?.cancel()),!n.ok)throw new Error(`central output delta rejected (${n.status})`)},recordPublicEvent:(e,t)=>(n.recordPublicEvent(e,t),n.commitPublicProgress(e,a)),decideInteraction:async(e,t)=>{const n=await s.postJson(DECISION_ROUTE,await r.credential(e),{context:e.context,session_id:e.sessionId,history_generation:e.historyGeneration,branch_id:e.branchId,response_id:e.responseId,interaction_id:t},{retry:!1});if(!n.ok)throw new Error(`central Interaction decision read failed (${n.status})`);const i=await n.json();return i.decision?.reply??null},inputFiles:new NativeInputFilesHttpClient(e.gatewayOrigin,t,(e,t)=>fetch(e,t))})}}
|
|
1
|
+
import{RuntimeChatStore,RuntimeLeaseHttp,RuntimeOriginalIntent,RuntimeMemory,RuntimeOperationFiles,createCloudGrantVerifier}from"@beeos-ai/cloud-harness-sdk";import{StateCentralNativeStore}from"./central-native-production.js";import{FileCentralNativePendingJournal}from"./central-native-pending-journal.js";import{installCentralNativeRuntime}from"./central-native-runtime.js";import{createCentralNativeHost}from"./central-native-host.js";import{NativeInputFilesHttpClient}from"./native-input-files-http.js";import{join}from"node:path";import{CentralNativeCredentials}from"./central-native-credentials.js";import{centralNativeOutputFileResolver}from"./central-native-output-files.js";import{installSandboxNativeExecutionResolver}from"./sandbox-native-activation.js";import{createSandboxNativeExecutionResolver}from"./sandbox-native-execution-resolver.js";import{installCentralNativeMemoryCall}from"./central-native-memory.js";import{DECISION_ROUTE}from"./central-native-interactions.js";import{generateAndRecordSessionTitle,RuntimeLeaseHttpSessionTitles}from"./central-native-titles.js";import{resolveArouterApiKey,resolveArouterBaseUrl}from"../media/arouter-config.js";export function requireCentralNativeSessionHost(e){const t=e,r=t?.agent?.session;for(const e of["readNativeTranscript","pendingNativeTurns","nativeWritersQuiescent","drainNativeTurns","replaceNativeTranscript","compactNativeTranscript"])if("function"!=typeof r?.[e])throw new Error(`pinned OpenClaw central native API unavailable: ${e}`);if("function"!=typeof t?.config?.current)throw new Error("pinned OpenClaw current config API unavailable");return r}export function createCentralNativeComposition(e){const t=()=>e.authority.authorityLease,r=new CentralNativeCredentials({authority:e.authority,http:new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1})}),n=new StateCentralNativeStore(new RuntimeChatStore(new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1})),e=>r.credential(e),new RuntimeLeaseHttpSessionTitles(new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1})),centralNativeOutputFileResolver(new RuntimeOperationFiles(new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1})),r)),i=new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1}),a=new FileCentralNativePendingJournal(join(e.stateDirectory,"central-native-pending")),o=new RuntimeMemory(new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1}));installCentralNativeMemoryCall(async(e,t,i,a,s)=>{try{const l=await o.call(t,await r.credential(e),r.execution(e),i,a,s);if("recall"===t){if("string"!=typeof l.read_watermark||!l.read_watermark)throw new Error("native Memory read returned no original watermark");n.recordMemoryRead(e,{status:"read",watermark:l.read_watermark})}return l}catch(r){throw"recall"===t&&n.recordMemoryRead(e,{status:"unavailable",watermark:null}),r}});const s=new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1}),l=(e,t,n,i)=>r.bind(e,t,n,i);return installSandboxNativeExecutionResolver(createSandboxNativeExecutionResolver({authority:e.authority,original:new RuntimeOriginalIntent(new RuntimeLeaseHttp({origin:e.gatewayOrigin,retry:!1})),verifier:createCloudGrantVerifier(e.gatewayOrigin),bindCredential:l})),installCentralNativeRuntime({store:n,pending:a,host:e.host,activeWriters:()=>e.coordinator.activeMutationCount,observe:(e,t)=>n.bindExecutionObservation(e,t)}),{store:n,pending:a,bindCredential:l,recordGeneratedTitle:({binding:t,question:r,answer:i})=>{generateAndRecordSessionTitle({recordGeneratedTitle:(e,t)=>n.recordGeneratedTitle(e,t),binding:t,question:r,answer:i,resolveModelCredential:()=>{const t=e.runtime.config.current(),r=resolveArouterApiKey(t)??process.env.AROUTER_API_KEY??process.env.OPENAI_API_KEY;return r?{apiKey:r,baseUrl:resolveArouterBaseUrl(t)}:void 0},logger:e.logger})},host:createCentralNativeHost({runtime:e.runtime,native:e.host,currentConfig:()=>e.runtime.config.current(),coordinator:e.coordinator,getLease:t,logger:e.logger,publishDelta:async(e,t)=>{const n=await i.postJson("/api/v1/runtime/chat-store/stream",await r.credential(e),{context:e.context,session_id:e.sessionId,history_generation:e.historyGeneration,branch_id:e.branchId,response_id:e.responseId,attempt_id:e.attemptId,writer:e.writer,...t},{retry:!1});if(await(n.body?.cancel()),!n.ok)throw new Error(`central output delta rejected (${n.status})`)},recordPublicEvent:(e,t)=>(n.recordPublicEvent(e,t),n.commitPublicProgress(e,a)),decideInteraction:async(e,t)=>{const n=await s.postJson(DECISION_ROUTE,await r.credential(e),{context:e.context,session_id:e.sessionId,history_generation:e.historyGeneration,branch_id:e.branchId,response_id:e.responseId,interaction_id:t},{retry:!1});if(!n.ok)throw new Error(`central Interaction decision read failed (${n.status})`);const i=await n.json();return i.decision?.reply??null},inputFiles:new NativeInputFilesHttpClient(e.gatewayOrigin,t,(e,t)=>fetch(e,t))})}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash}from"node:crypto";import{isDeepStrictEqual}from"node:util";export const CENTRAL_NATIVE_ENGINE_ID="beeos-central-chat";export const OPENCLAW_NATIVE_CODEC="openclaw-session-events-v1";export function nativePayloadDigest(e){const t=e=>Array.isArray(e)?e.map(t):null!==e&&"object"==typeof e?Object.fromEntries(Object.entries(e).sort(([e],[t])=>e<t?-1:e>t?1:0).map(([e,n])=>[e,t(n)])):e;return createHash("sha256").update(JSON.stringify(t(e))).digest("hex")}export function nativeBindingDigest(e){const{context:t,...n}=e;return nativePayloadDigest({...n,tenant_ref:t.tenant_ref,scope_ref:t.scope_ref})}export function assertCentralNativeReceipt(e,t){const n=e.wire,i=n.events;if(!Array.isArray(i)||i.some(e=>!e||"object"!=typeof e||"string"!=typeof e.event_id))throw new Error("central native append has invalid prepared State event identities");if(!(t.receipt_id&&t.idempotency_key===e.idempotencyKey&&t.payload_sha256===e.payloadDigest&&t.read_watermark&&t.operation_id===e.binding.operationId&&t.session_id===e.binding.sessionId&&t.history_generation===e.binding.historyGeneration&&t.branch_id===e.binding.branchId&&isDeepStrictEqual(t.writer,e.binding.writer)&&t.previous_watermark===e.expectedWatermark&&isDeepStrictEqual(t.terminal,n.terminal)&&isDeepStrictEqual(t.event_ids,i.map(e=>e.event_id))&&/^(0|[1-9][0-9]*)$/.test(t.read_watermark)&&t.read_watermark===String(BigInt(e.expectedWatermark)+BigInt(i.length))))throw new Error("central native append returned no matching durable transaction receipt")}export class CentralNativeContextEngine{options;info={id:"beeos-central-chat",name:"BeeOS central native chat",version:"1",failureMode:"strict",acceptedHostParams:["sessionKey","sessionTarget","runtimeContext","runtimeSettings","prompt"],transcriptSemantics:{currentTurnFence:"before-current-turn-entry-v1",turnAdvancementIdempotency:"atomic-idempotent-v1",nativeEvents:"lossless-v1"}};terminalOperations=new Set;loaded=new Map;constructor(e){this.options=e}source(e){const t=this.loaded.get(e);if(!t)throw new Error("central native session has no loaded source");return structuredClone(t)}forBindings(e){const t=new CentralNativeContextEngine({...this.options,resolveBinding:e});for(const[e,n]of this.loaded)t.loaded.set(e,structuredClone(n));for(const e of this.terminalOperations)t.terminalOperations.add(e);return t}binding(e){if(!e)throw new Error("central native session key is required");return this.options.resolveBinding(e)}async hydrateNativeSession(e){const t=this.binding(e.sessionKey);for(const e of await this.options.pending.list(t.sessionId)){const n=await this.options.store.receipt({...e,binding:{...e.binding,context:t.context}});if(!n)throw new Error("central native append outcome is unknown");this.acceptReceipt(e,n),await this.options.pending.complete(e,n)}const n=await this.options.store.load(t);if(n.codec!==OPENCLAW_NATIVE_CODEC||!Array.isArray(n.events)||!isDeepStrictEqual(n.writer,t.writer)||!n.watermark)throw new Error("central native load does not match the authorized codec/fence");return n.terminal?.response_id===t.responseId&&this.terminalOperations.add(t.operationId),this.loaded.set(e.sessionKey,structuredClone(n)),{events:structuredClone(n.events)}}async bootstrap(){return{bootstrapped:!0}}async ingest(){throw new Error("central native writes require an atomic native turn commit")}async assemble(e){if(this.binding(e.sessionKey),!e.sessionKey||!this.loaded.has(e.sessionKey))throw new Error("central native context was not hydrated by the pinned host");return{messages:e.messages,estimatedTokens:0}}async admitTurn(e){const{admission:t}=e,n=this.binding(t.sessionKey);if(this.terminalOperations.has(n.operationId))throw new Error("original Response is already terminal; new native admission is forbidden");const i=await this.options.readNativeEvents(t.sessionKey);if(!Number.isSafeInteger(t.rawSeq)||t.rawSeq<0||t.rawSeq>=i.length)throw new Error("native admission has no exact transcript row");await this.commitSnapshot(t.sessionKey,n,`admit:${n.operationId}:${t.logicalTurnId}`,i.slice(0,t.rawSeq+1),t)}nativeTranscriptBase(e){const t=this.source(e.sessionKey);return{eventCount:t.events.length,snapshotDigest:nativePayloadDigest(t.events),bindingDigest:nativeBindingDigest(this.binding(e.sessionKey))}}async commitTurn(e){const t=this.binding(e.sessionKey);if(!e.nativeEvents)throw new Error("pinned host omitted native transcript events");const n=e.nativeBase;if(n?.bindingDigest!==nativeBindingDigest(t))throw new Error("native accepted-turn binding changed");const i=0===n?.eventCount?[]:this.source(e.sessionKey).events;if(!n||!Number.isSafeInteger(n.eventCount)||n.eventCount<0||n.eventCount>i.length||nativePayloadDigest(i.slice(0,n.eventCount))!==n.snapshotDigest)throw new Error("native accepted-turn base differs from the exact central prefix");const a=[...i.slice(0,n.eventCount),...e.nativeEvents];if(!e.nativeOutcome)throw new Error("pinned host omitted actual native terminal outcome");return this.commitSnapshot(e.sessionKey,t,e.advancementKey,a,e.terminal,e.nativeOutcome)}async finalizeNativeOutcome(e){const t=this.binding(e.sessionKey),n=await this.options.readNativeEvents(e.sessionKey);await this.commitSnapshot(e.sessionKey,t,`outcome:${t.operationId}:${nativePayloadDigest(e.nativeOutcome)}`,n,e.terminal,e.nativeOutcome)}async commitSnapshot(e,t,n,i,a,r){return this.options.store.withWrite(t,()=>this.commitSnapshotUnserialized(e,t,n,i,a,r))}async commitSnapshotUnserialized(e,t,n,i,a,r){const s=await this.options.pending.completed(n);if(s){const{context:e,...o}=s.binding,{context:c,...d}=t;if(!isDeepStrictEqual(o,d)||e.tenant_ref!==c.tenant_ref||e.scope_ref!==c.scope_ref)throw new Error("central native duplicate binding changed");if(s.nativeSnapshotDigest!==nativePayloadDigest({events:i,nativeTerminalAnchor:a??null,nativeOutcome:r??null}))throw new Error("central native duplicate turn has different native events");const p=await this.options.store.receipt({binding:{...s.binding,context:t.context},idempotencyKey:n,payloadDigest:s.receipt.payload_sha256});if(!p||!isDeepStrictEqual(p,s.receipt))throw new Error("central native duplicate receipt is unavailable or changed");return p.terminal&&this.terminalOperations.add(s.binding.operationId),this.options.onReceipt?.(s.binding,p),{status:"duplicate"}}const o=await this.options.pending.get(n);if(o){const{context:e,...n}=o.binding,{context:s,...c}=t;if(!isDeepStrictEqual(n,c)||e.tenant_ref!==s.tenant_ref||e.scope_ref!==s.scope_ref||o.nativeSnapshotDigest!==nativePayloadDigest({events:i,nativeTerminalAnchor:a??null,nativeOutcome:r??null}))throw new Error("central native idempotency conflict: pending advancement changed");const d=await this.options.store.receipt({...o,binding:t});if(!d)throw new Error("central native append outcome is unknown");return this.acceptReceipt(o,d),await this.options.pending.complete(o,d),{status:"duplicate"}}if(!this.loaded.has(e))throw new Error("central native commit has no exact loaded source");const c=await this.options.store.load(t);if(c.codec!==OPENCLAW_NATIVE_CODEC||!isDeepStrictEqual(c.writer,t.writer))throw new Error("central native refreshed source changed its codec/writer");if(c.terminal?.response_id===t.responseId&&this.terminalOperations.add(t.operationId),this.loaded.set(e,structuredClone(c)),this.terminalOperations.has(t.operationId))throw new Error("original Response is already terminal; new native advancement is forbidden");if(i.length<c.events.length||!isDeepStrictEqual(i.slice(0,c.events.length),c.events))throw new Error("native cache diverged from the exact central transcript prefix");const d=nativePayloadDigest({events:i,nativeTerminalAnchor:a??null,nativeOutcome:r??null});let p=c;if(i.length===p.events.length&&!r)throw new Error("native advancement contains no new native events");let l=!1;for(;p.events.length<i.length||r&&!l;){const s=p.events.length,o=i.length-s,c=this.options.store.nativeEventCapacity(t,!1),h=this.options.store.nativeEventCapacity(t,Boolean(r)),m=r&&o>h?s+Math.min(c,o-1):Math.min(s+h,i.length),v=m===i.length?n:`${n}:native:${s}`,u={binding:t,expectedWatermark:p.watermark,idempotencyKey:v,nativeSnapshotDigest:d,events:i.slice(s,m),...a?{nativeTerminalAnchor:a}:{},...r&&m===i.length?{nativeOutcome:r}:{}},g=await this.options.pending.get(v),w=g??this.options.store.prepareAppend(u),{context:f,...y}=w.binding,{context:E,...b}=t;if(w.idempotencyKey!==v||w.nativeSnapshotDigest!==u.nativeSnapshotDigest||w.expectedWatermark!==p.watermark||!isDeepStrictEqual(y,b)||f.tenant_ref!==E.tenant_ref||f.scope_ref!==E.scope_ref||!isDeepStrictEqual(w.events,u.events)||!isDeepStrictEqual(w.nativeOutcome,u.nativeOutcome))throw new Error("central native SDK changed the prepared native append identity");let _;if(g){const e=await this.options.store.receipt({...g,binding:t});if(!e)throw new Error("central native append outcome is unknown");_=e}else await this.options.pending.put(w),_=await this.options.store.append(w);this.acceptReceipt(w,_),p={...p,events:structuredClone(i.slice(0,m)),watermark:_.read_watermark},this.loaded.set(e,p),await this.options.pending.complete(w,_),l=Boolean(r&&m===i.length)}return{status:"committed"}}acceptReceipt(e,t){assertCentralNativeReceipt(e,t),t.terminal&&this.terminalOperations.add(e.binding.operationId),this.options.onReceipt?.(e.binding,t)}async compact(e){const t="string"==typeof e.sessionKey?e.sessionKey:void 0,n=this.binding(t);if(this.terminalOperations.has(n.operationId))return{ok:!0,compacted:!1,reason:"central terminal already committed; compaction requires another admitted operation"};const i=await this.options.compact(e);if(i.ok&&i.compacted){const e=await this.options.readNativeEvents(t);await this.commitSnapshot(t,n,`compact:${n.operationId}:${nativePayloadDigest(e)}`,e)}return i}}
|
|
1
|
+
import{createHash}from"node:crypto";import{isDeepStrictEqual}from"node:util";export const CENTRAL_NATIVE_ENGINE_ID="beeos-central-chat";export const OPENCLAW_NATIVE_CODEC="openclaw-session-events-v1";export function nativePayloadDigest(e){const t=e=>Array.isArray(e)?e.map(t):null!==e&&"object"==typeof e?Object.fromEntries(Object.entries(e).sort(([e],[t])=>e<t?-1:e>t?1:0).map(([e,n])=>[e,t(n)])):e;return createHash("sha256").update(JSON.stringify(t(e))).digest("hex")}export function nativeBindingDigest(e){const{context:t,...n}=e;return nativePayloadDigest({...n,tenant_ref:t.tenant_ref,scope_ref:t.scope_ref})}export function assertCentralNativeReceipt(e,t){const n=e.wire,i=n.events;if(!Array.isArray(i)||i.some(e=>!e||"object"!=typeof e||"string"!=typeof e.event_id))throw new Error("central native append has invalid prepared State event identities");if(!(t.receipt_id&&t.idempotency_key===e.idempotencyKey&&t.payload_sha256===e.payloadDigest&&t.read_watermark&&t.operation_id===e.binding.operationId&&t.session_id===e.binding.sessionId&&t.history_generation===e.binding.historyGeneration&&t.branch_id===e.binding.branchId&&isDeepStrictEqual(t.writer,e.binding.writer)&&t.previous_watermark===e.expectedWatermark&&isDeepStrictEqual(t.terminal,n.terminal)&&isDeepStrictEqual(t.event_ids,i.map(e=>e.event_id))&&/^(0|[1-9][0-9]*)$/.test(t.read_watermark)&&t.read_watermark===String(BigInt(e.expectedWatermark)+BigInt(i.length))))throw new Error("central native append returned no matching durable transaction receipt")}export class CentralNativeContextEngine{options;info={id:"beeos-central-chat",name:"BeeOS central native chat",version:"1",failureMode:"strict",acceptedHostParams:["sessionKey","sessionTarget","runtimeContext","runtimeSettings","prompt"],transcriptSemantics:{currentTurnFence:"before-current-turn-entry-v1",turnAdvancementIdempotency:"atomic-idempotent-v1",nativeEvents:"lossless-v1"}};terminalOperations=new Set;loaded=new Map;constructor(e){this.options=e}source(e){const t=this.loaded.get(e);if(!t)throw new Error("central native session has no loaded source");return structuredClone(t)}forBindings(e){const t=new CentralNativeContextEngine({...this.options,resolveBinding:e});for(const[e,n]of this.loaded)t.loaded.set(e,structuredClone(n));for(const e of this.terminalOperations)t.terminalOperations.add(e);return t}binding(e){if(!e)throw new Error("central native session key is required");return this.options.resolveBinding(e)}async hydrateNativeSession(e){const t=this.binding(e.sessionKey);for(const e of await this.options.pending.list(t.sessionId)){const n=await this.options.store.receipt({...e,binding:{...e.binding,context:t.context}});if(!n)throw new Error("central native append outcome is unknown");this.acceptReceipt(e,n),await this.options.pending.complete(e,n)}const n=await this.options.store.load(t);if(n.codec!==OPENCLAW_NATIVE_CODEC||!Array.isArray(n.events)||!isDeepStrictEqual(n.writer,t.writer)||!n.watermark)throw new Error("central native load does not match the authorized codec/fence");return n.terminal?.response_id===t.responseId&&this.terminalOperations.add(t.operationId),this.loaded.set(e.sessionKey,structuredClone(n)),{events:structuredClone(n.events)}}async bootstrap(){return{bootstrapped:!0}}async ingest(){throw new Error("central native writes require an atomic native turn commit")}async assemble(e){if(this.binding(e.sessionKey),!e.sessionKey||!this.loaded.has(e.sessionKey))throw new Error("central native context was not hydrated by the pinned host");return{messages:e.messages,estimatedTokens:0}}async admitTurn(e){const{admission:t}=e,n=this.binding(t.sessionKey);if(this.terminalOperations.has(n.operationId))throw new Error("original Response is already terminal; new native admission is forbidden");const i=await this.options.readNativeEvents(t.sessionKey);if(!Number.isSafeInteger(t.rawSeq)||t.rawSeq<0||t.rawSeq>=i.length)throw new Error("native admission has no exact transcript row");await this.commitSnapshot(t.sessionKey,n,`admit:${n.operationId}:${t.logicalTurnId}`,i.slice(0,t.rawSeq+1),t)}nativeTranscriptBase(e){const t=this.source(e.sessionKey);return{eventCount:t.events.length,snapshotDigest:nativePayloadDigest(t.events),bindingDigest:nativeBindingDigest(this.binding(e.sessionKey))}}async commitTurn(e){const t=this.binding(e.sessionKey);if(!e.nativeEvents)throw new Error("pinned host omitted native transcript events");const n=e.nativeBase;if(n?.bindingDigest!==nativeBindingDigest(t))throw new Error("native accepted-turn binding changed");const i=0===n?.eventCount?[]:this.source(e.sessionKey).events;if(!n||!Number.isSafeInteger(n.eventCount)||n.eventCount<0||n.eventCount>i.length||nativePayloadDigest(i.slice(0,n.eventCount))!==n.snapshotDigest)throw new Error("native accepted-turn base differs from the exact central prefix");const a=[...i.slice(0,n.eventCount),...e.nativeEvents];if(!e.nativeOutcome)throw new Error("pinned host omitted actual native terminal outcome");return this.commitSnapshot(e.sessionKey,t,e.advancementKey,a,e.terminal,e.nativeOutcome)}async finalizeNativeOutcome(e){const t=this.binding(e.sessionKey),n=await this.options.readNativeEvents(e.sessionKey);await this.commitSnapshot(e.sessionKey,t,`outcome:${t.operationId}:${nativePayloadDigest(e.nativeOutcome)}`,n,e.terminal,e.nativeOutcome)}async commitSnapshot(e,t,n,i,a,r){return this.options.store.withWrite(t,()=>this.commitSnapshotUnserialized(e,t,n,i,a,r))}async commitSnapshotUnserialized(e,t,n,i,a,r){const s=await this.options.pending.completed(n);if(s){const{context:e,...o}=s.binding,{context:c,...d}=t;if(!isDeepStrictEqual(o,d)||e.tenant_ref!==c.tenant_ref||e.scope_ref!==c.scope_ref)throw new Error("central native duplicate binding changed");if(s.nativeSnapshotDigest!==nativePayloadDigest({events:i,nativeTerminalAnchor:a??null,nativeOutcome:r??null}))throw new Error("central native duplicate turn has different native events");const p=await this.options.store.receipt({binding:{...s.binding,context:t.context},idempotencyKey:n,payloadDigest:s.receipt.payload_sha256});if(!p||!isDeepStrictEqual(p,s.receipt))throw new Error("central native duplicate receipt is unavailable or changed");return p.terminal&&this.terminalOperations.add(s.binding.operationId),this.options.onReceipt?.(s.binding,p),{status:"duplicate"}}const o=await this.options.pending.get(n);if(o){const{context:e,...n}=o.binding,{context:s,...c}=t;if(!isDeepStrictEqual(n,c)||e.tenant_ref!==s.tenant_ref||e.scope_ref!==s.scope_ref||o.nativeSnapshotDigest!==nativePayloadDigest({events:i,nativeTerminalAnchor:a??null,nativeOutcome:r??null}))throw new Error("central native idempotency conflict: pending advancement changed");const d=await this.options.store.receipt({...o,binding:t});if(!d)throw new Error("central native append outcome is unknown");return this.acceptReceipt(o,d),await this.options.pending.complete(o,d),{status:"duplicate"}}if(!this.loaded.has(e))throw new Error("central native commit has no exact loaded source");const c=await this.options.store.load(t);if(c.codec!==OPENCLAW_NATIVE_CODEC||!isDeepStrictEqual(c.writer,t.writer))throw new Error("central native refreshed source changed its codec/writer");if(c.terminal?.response_id===t.responseId&&this.terminalOperations.add(t.operationId),this.loaded.set(e,structuredClone(c)),this.terminalOperations.has(t.operationId))throw new Error("original Response is already terminal; new native advancement is forbidden");if(i.length<c.events.length||!isDeepStrictEqual(i.slice(0,c.events.length),c.events))throw new Error("native cache diverged from the exact central transcript prefix");const d=nativePayloadDigest({events:i,nativeTerminalAnchor:a??null,nativeOutcome:r??null});let p=c;if(i.length===p.events.length&&!r)throw new Error("native advancement contains no new native events");let l=!1;for(;p.events.length<i.length||r&&!l;){const s=p.events.length,o=i.length-s,c=this.options.store.nativeEventCapacity(t,!1),h=this.options.store.nativeEventCapacity(t,Boolean(r)),m=r&&o>h?s+Math.min(c,o-1):Math.min(s+h,i.length),v=m===i.length?n:`${n}:native:${s}`,u={binding:t,expectedWatermark:p.watermark,idempotencyKey:v,nativeSnapshotDigest:d,events:i.slice(s,m),...a?{nativeTerminalAnchor:a}:{},...r&&m===i.length?{nativeOutcome:r}:{}},g=await this.options.pending.get(v),w=g??await this.options.store.prepareAppend(u),{context:f,...y}=w.binding,{context:E,...b}=t;if(w.idempotencyKey!==v||w.nativeSnapshotDigest!==u.nativeSnapshotDigest||w.expectedWatermark!==p.watermark||!isDeepStrictEqual(y,b)||f.tenant_ref!==E.tenant_ref||f.scope_ref!==E.scope_ref||!isDeepStrictEqual(w.events,u.events)||!isDeepStrictEqual(w.nativeOutcome,u.nativeOutcome))throw new Error("central native SDK changed the prepared native append identity");let _;if(g){const e=await this.options.store.receipt({...g,binding:t});if(!e)throw new Error("central native append outcome is unknown");_=e}else await this.options.pending.put(w),_=await this.options.store.append(w);this.acceptReceipt(w,_),p={...p,events:structuredClone(i.slice(0,m)),watermark:_.read_watermark},this.loaded.set(e,p),await this.options.pending.complete(w,_),l=Boolean(r&&m===i.length)}return{status:"committed"}}acceptReceipt(e,t){assertCentralNativeReceipt(e,t),t.terminal&&this.terminalOperations.add(e.binding.operationId),this.options.onReceipt?.(e.binding,t)}async compact(e){const t="string"==typeof e.sessionKey?e.sessionKey:void 0,n=this.binding(t);if(this.terminalOperations.has(n.operationId))return{ok:!0,compacted:!1,reason:"central terminal already committed; compaction requires another admitted operation"};const i=await this.options.compact(e);if(i.ok&&i.compacted){const e=await this.options.readNativeEvents(t);await this.commitSnapshot(t,n,`compact:${n.operationId}:${nativePayloadDigest(e)}`,e)}return i}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{RuntimeOriginalIntent}from"@beeos-ai/cloud-harness-sdk";import{nativeBindingDigest}from"./central-native-context-engine.js";import{verifyCentralNativeIntent}from"./central-native-response.js";export class CentralNativeCredentials{options;sources=new Map;original;constructor(e){this.options=e,this.original=new RuntimeOriginalIntent(e.http)}bind(e,t,i,n){const r=nativeBindingDigest(e),a=this.sources.get(e.operationId),s=n.verifier.verifyAndDecodeGrant(t),o=this.options.authority.authorityLease,d=s?.claims;if(!t||!i||!n.requestMessageId||!s||!o||d?.instanceId!==o.instanceId||d.leaseId!==o.leaseId||d.handlerIdentity!==o.handlerIdentity||d.dispatchEpoch!==o.runtimeEpoch||!Number.isSafeInteger(s.claims.exp)||"string"!=typeof s.claims.runtimeAgentUid||!s.claims.runtimeAgentUid||s.claims.requestHash!==i||s.claims.requestMessageId!==n.requestMessageId||a&&(a.identity!==r||a.hash!==i||a.requestMessageId!==n.requestMessageId||a.runtimeAgentUid!==s.claims.runtimeAgentUid))throw new Error("original central native execution grant changed");this.sources.set(e.operationId,{identity:r,grant:t,hash:i,requestMessageId:n.requestMessageId,expiresAt:1e3*s.claims.exp,runtimeAgentUid:s.claims.runtimeAgentUid,leaseId:o.leaseId,instanceId:o.instanceId,handlerIdentity:o.handlerIdentity,runtimeEpoch:o.runtimeEpoch,verifier:n.verifier})}execution(e){const{source:t}=this.current(e);return{operation_id:e.operationId,request_message_id:t.requestMessageId,native_request_hash:t.hash,attempt_id:e.attemptId}}current(e){const t=this.sources.get(e.operationId),i=this.options.authority.authorityLease;if(!i?.runtimeLeaseCredential||!Number.isFinite(Date.parse(i.leaseExpiresAt))||Date.parse(i.leaseExpiresAt)<=Date.now()||!t||t.identity!==nativeBindingDigest(e)||t.instanceId!==i.instanceId||t.leaseId!==i.leaseId||t.handlerIdentity!==i.handlerIdentity||t.runtimeEpoch!==i.runtimeEpoch)throw new Error("central native current lease/original execution grant is unavailable");return{lease:i,source:t}}async credential(e){const{lease:t,source:i}=this.current(e);i.expiresAt<=Date.now()+5e3&&(i.refreshing??=(async()=>{const n=await this.original.read(t,{operation_id:e.operationId,request_message_id:i.requestMessageId,native_request_hash:i.hash});await i.verifier.refresh();const r=verifyCentralNativeIntent({request:n.request,executionGrant:n.execution_grant,lease:t,getLease:()=>this.options.authority.authorityLease,verifier:i.verifier});if(nativeBindingDigest(r.binding)!==i.identity||n.native_request_hash!==i.hash)throw new Error("renewed original native binding changed");const a=i.verifier.verifyAndDecodeGrant(n.execution_grant);if(a.claims.runtimeAgentUid!==i.runtimeAgentUid)throw new Error("renewed original native target changed");if(1e3*a.claims.exp!==Date.parse(n.execution_grant_expires_at))throw new Error("renewed native grant expiry differs from its signed source");i.grant=n.execution_grant,i.expiresAt=1e3*a.claims.exp})().finally(()=>{i.refreshing=void 0}),await i.refreshing);const n=this.options.authority.authorityLease;if(!n||n.instanceId!==t.instanceId||n.leaseId!==t.leaseId||n.handlerIdentity!==t.handlerIdentity||n.runtimeEpoch!==t.runtimeEpoch||Date.parse(n.leaseExpiresAt)<=Date.now())throw new Error("central native execution is fenced");return{runtimeLeaseCredential:n.runtimeLeaseCredential,executionGrant:i.grant}}}
|
|
1
|
+
import{RuntimeOriginalIntent}from"@beeos-ai/cloud-harness-sdk";import{nativeBindingDigest}from"./central-native-context-engine.js";import{verifyCentralNativeIntent}from"./central-native-response.js";export class CentralNativeCredentials{options;sources=new Map;original;constructor(e){this.options=e,this.original=new RuntimeOriginalIntent(e.http)}bind(e,t,i,n){const r=nativeBindingDigest(e),a=this.sources.get(e.operationId),s=n.verifier.verifyAndDecodeGrant(t),o=this.options.authority.authorityLease,d=s?.claims,c=d?.paramsHash;if(!t||!i||!n.requestMessageId||!s||!o||d?.operationId!==e.operationId||"string"!=typeof c||!/^[0-9a-f]{64}$/.test(c)||d?.instanceId!==o.instanceId||d.leaseId!==o.leaseId||d.handlerIdentity!==o.handlerIdentity||d.dispatchEpoch!==o.runtimeEpoch||!Number.isSafeInteger(s.claims.exp)||"string"!=typeof s.claims.runtimeAgentUid||!s.claims.runtimeAgentUid||s.claims.requestHash!==i||s.claims.requestMessageId!==n.requestMessageId||a&&(a.identity!==r||a.hash!==i||a.paramsHash!==c||a.requestMessageId!==n.requestMessageId||a.runtimeAgentUid!==s.claims.runtimeAgentUid))throw new Error("original central native execution grant changed");this.sources.set(e.operationId,{identity:r,grant:t,hash:i,paramsHash:c,requestMessageId:n.requestMessageId,expiresAt:1e3*s.claims.exp,runtimeAgentUid:s.claims.runtimeAgentUid,leaseId:o.leaseId,instanceId:o.instanceId,handlerIdentity:o.handlerIdentity,runtimeEpoch:o.runtimeEpoch,verifier:n.verifier})}execution(e){const{source:t}=this.current(e);return{operation_id:e.operationId,request_message_id:t.requestMessageId,native_request_hash:t.hash,attempt_id:e.attemptId}}outputFileBinding(e){const{source:t}=this.current(e);return{requestMessageId:t.requestMessageId,paramsHash:t.paramsHash,activeRunRegistrationId:e.operationId}}current(e){const t=this.sources.get(e.operationId),i=this.options.authority.authorityLease;if(!i?.runtimeLeaseCredential||!Number.isFinite(Date.parse(i.leaseExpiresAt))||Date.parse(i.leaseExpiresAt)<=Date.now()||!t||t.identity!==nativeBindingDigest(e)||t.instanceId!==i.instanceId||t.leaseId!==i.leaseId||t.handlerIdentity!==i.handlerIdentity||t.runtimeEpoch!==i.runtimeEpoch)throw new Error("central native current lease/original execution grant is unavailable");return{lease:i,source:t}}async credential(e){const{lease:t,source:i}=this.current(e);i.expiresAt<=Date.now()+5e3&&(i.refreshing??=(async()=>{const n=await this.original.read(t,{operation_id:e.operationId,request_message_id:i.requestMessageId,native_request_hash:i.hash});await i.verifier.refresh();const r=verifyCentralNativeIntent({request:n.request,executionGrant:n.execution_grant,lease:t,getLease:()=>this.options.authority.authorityLease,verifier:i.verifier});if(nativeBindingDigest(r.binding)!==i.identity||n.native_request_hash!==i.hash)throw new Error("renewed original native binding changed");const a=i.verifier.verifyAndDecodeGrant(n.execution_grant);if(a.claims.runtimeAgentUid!==i.runtimeAgentUid)throw new Error("renewed original native target changed");if(a.claims.paramsHash!==i.paramsHash)throw new Error("renewed original native params changed");if(1e3*a.claims.exp!==Date.parse(n.execution_grant_expires_at))throw new Error("renewed native grant expiry differs from its signed source");i.grant=n.execution_grant,i.expiresAt=1e3*a.claims.exp})().finally(()=>{i.refreshing=void 0}),await i.refreshing);const n=this.options.authority.authorityLease;if(!n||n.instanceId!==t.instanceId||n.leaseId!==t.leaseId||n.handlerIdentity!==t.handlerIdentity||n.runtimeEpoch!==t.runtimeEpoch||Date.parse(n.leaseExpiresAt)<=Date.now())throw new Error("central native execution is fenced");return{runtimeLeaseCredential:n.runtimeLeaseCredential,executionGrant:i.grant}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{RUNTIME_HASH_DOMAINS}from"@beeos-ai/beeos-types/runtime";import{centralNativeRuntime}from"./central-native-runtime.js";import{createCentralNativeMemoryAttempt}from"./central-native-memory.js";import{preparedSandboxNativeExecution}from"./sandbox-native-activation.js";import{dispatchRuntimeReplyWithRoute}from"./reply-router.js";import{prepareNativePromptInput}from"./native-prompt-preflight.js";import{downloadNativeInputFile}from"./native-input-files.js";import{runtimeMessageHash}from"./runtime-message-channel-contract.js";import{createCentralNativeDeltaStream}from"./central-native-delta.js";import{bindCentralInteractions}from"./central-native-interactions.js";export function createCentralNativeHost(e){return{async run(t){t.assertCurrent(),t.signal.throwIfAborted();const n=preparedSandboxNativeExecution(t.params,t.binding),r=t.params.runtimeRunId;if("string"!=typeof r||!r)throw new Error("original native RunID is unavailable");const
|
|
1
|
+
import{RUNTIME_HASH_DOMAINS}from"@beeos-ai/beeos-types/runtime";import{centralNativeRuntime}from"./central-native-runtime.js";import{createCentralNativeMemoryAttempt}from"./central-native-memory.js";import{createNativeOutputFileAttempt,registerNativeOutputRunContext}from"./native-output-file-attempt.js";import{preparedSandboxNativeExecution}from"./sandbox-native-activation.js";import{dispatchRuntimeReplyWithRoute}from"./reply-router.js";import{prepareNativePromptInput}from"./native-prompt-preflight.js";import{downloadNativeInputFile}from"./native-input-files.js";import{runtimeMessageHash}from"./runtime-message-channel-contract.js";import{createCentralNativeDeltaStream}from"./central-native-delta.js";import{bindCentralInteractions}from"./central-native-interactions.js";export function createCentralNativeHost(e){return{async run(t){t.assertCurrent(),t.signal.throwIfAborted();const n=preparedSandboxNativeExecution(t.params,t.binding),r=t.params.runtimeRunId;if("string"!=typeof r||!r)throw new Error("original native RunID is unavailable");const i=e.coordinator.tryStartExclusive({sessionKey:n.sessionKey,label:t.binding.operationId},"message_service");if(!i.ok)throw new Error("central native physical session is busy");const a=i.token;let s=!1;const o=new AbortController,l=AbortSignal.any([t.signal,o.signal]),p=createCentralNativeMemoryAttempt({binding:t.binding,signal:l,assertCurrent:t.assertCurrent}),d=runtimeMessageHash(RUNTIME_HASH_DOMAINS.params,{method:"session/prompt",params:t.params}),c=createNativeOutputFileAttempt({operationId:t.binding.operationId,requestMessageId:t.requestMessageId,paramsHash:d,activeRunRegistrationId:t.binding.operationId,responseId:t.binding.responseId,attemptId:t.binding.attemptId,sessionKey:n.sessionKey,getLease:()=>{const t=e.getLease();if(!t)throw new Error("central native output lease is unavailable");return t},assertAttempt:t.assertCurrent,signal:l}),m=registerNativeOutputRunContext({runId:r,sessionKey:n.sessionKey,operationId:t.binding.operationId,activeRunRegistrationId:t.binding.operationId,responseId:t.binding.responseId,attemptId:t.binding.attemptId}),u=new Set;let g;const I=(n,r)=>{if(centralNativeRuntime().receipt(t.binding.operationId)?.terminal)return;const i={type:"response.beeos.part",response_id:t.binding.responseId,kind:n,data:JSON.stringify(r)};let a;try{a=e.recordPublicEvent(t.binding,i)}catch(e){a=Promise.reject(e)}u.add(a),a.then(()=>u.delete(a),e=>{u.delete(a),g??=e,o.abort(e)})},b=createCentralNativeDeltaStream(t.binding,e.publishDelta,t=>{e.logger.warn?.(`central output delta was not published: ${t instanceof Error?t.name:"error"}`)}),v=()=>centralNativeRuntime().receipt(t.binding.operationId)?.terminal,y=e=>{v()||b.partial(e.text)},f=e=>{v()||b.block(e.text)},h=()=>{v()||b.beginMessage()};let w="";const R=(e,n)=>(t.assertCurrent(),"final"===e&&"string"==typeof n.text&&n.text.length>0&&(w=w?`${w}\n${n.text}`:n.text),I(e,n),!0),C={sendToolResult:e=>R("tool",e),sendBlockReply:e=>{const t=R("block",e);return t&&f(e),t},sendFinalReply:e=>R("final",e),waitForIdle:async()=>{},getQueuedCounts:()=>({tool:0,block:0,final:0}),markComplete:()=>{}};try{const i=t.params.parts,o=Array.isArray(i)?prepareNativePromptInput(i):"string"==typeof t.params.text?{message:t.params.text,files:[]}:void 0;if(!o)throw new Error("central native signed prompt parts are unavailable");await centralNativeRuntime().prepare(n.sessionKey,t.binding);const m=[],v=[];for(const n of o.files){t.assertCurrent();const r=e.getLease();if(!r)throw new Error("central native input Files lease is unavailable");const i=await e.inputFiles.resolve({operationId:t.binding.operationId,requestMessageId:t.requestMessageId,paramsHash:d,partIndex:n.partIndex,lease:r,signal:t.signal}),a=await downloadNativeInputFile({fileId:n.fileId,...i,signal:t.signal,assertAttempt:t.assertCurrent});m.push(a.path),v.push(a.mimeType)}let R;t.assertCurrent(),t.signal.throwIfAborted();const N=bindCentralInteractions(n.sessionKey,{responseId:t.binding.responseId,attemptId:t.binding.attemptId,mode:t.params.approvalMode,signal:l,publish:n=>e.recordPublicEvent(t.binding,{type:"response.interaction",response_id:t.binding.responseId,interaction:n}),decide:n=>e.decideInteraction(t.binding,n)});try{await dispatchRuntimeReplyWithRoute({runtime:{...e.runtime,config:{loadConfig:e.currentConfig}},preparedPrompt:{message:o.message,mediaPaths:m,mediaTypes:v,nativeSystemContext:n.systemPrompt},replyRoute:{protocol:"acp",requestId:t.binding.operationId,sessionId:n.sessionKey,sourceMessageId:t.requestMessageId,originatingChannel:"webchat",originatingTo:n.localAgentId,accountId:n.localAgentId,origin:"beeos-central-response"},replySinks:{acp:{dispatcher:C,replyOptions:{runId:r,abortSignal:l,disableBlockStreaming:!1,onAgentRunStart:t=>{e.coordinator.bindRun(a,t),p.bindHostRun(t),c.bindHostRun(t)},onPartialReply:y,onBlockReplyQueued:e=>{f(e)},onAssistantMessageStart:h,onReasoningStream:e=>{I("reasoning",e)},onToolStart:e=>{I("tool.start",e)},onItemEvent:e=>{I("item",e)}}}},onDispatchInvoked:()=>{s=!0}})}catch(e){R=e}try{await N()}catch(e){R??=e}await Promise.allSettled([...u,b.close()]),R??=g;const x=t.signal.aborted,S=centralNativeRuntime().receipt(t.binding.operationId)?.terminal,A=await e.coordinator.converge(a,x?"cancelled":"completed"===S?.status?"completed":"error");if(!A.ok)throw new Error("central native physical writer did not quiesce");if(t.assertCurrent(),!e.native.nativeWritersQuiescent({sessionKey:n.sessionKey}))throw new Error("central native admission still owns the physical writer");if(R&&!x)throw R;const E=centralNativeRuntime().receipt(t.binding.operationId)?.terminal;if(!E||E.response_id!==t.binding.responseId)throw new Error("native outcome has no original central terminal transaction receipt");const M=E.status;return t.assertCurrent(),e.coordinator.release(A.permit),{status:M,...w?{finalText:w}:{}}}catch(t){throw s?e.coordinator.snapshot(n.sessionKey)&&e.coordinator.requireRecovery(a,"terminal_not_observed"):e.coordinator.releaseBeforeRuntime(a),t}finally{p.close(),c.close(),m()}}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{HarnessProtocolError}from"@beeos-ai/cloud-harness-sdk";import{parseBeeosFileUri}from"../files/beeos-file-uri.js";const object=e=>null!==e&&"object"==typeof e&&!Array.isArray(e),fileIdPattern=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;export class NativeArtifactDeliveryFailure extends Error{constructor(){super("The native output artifact could not be delivered.")}}export function nativeOutputFileIds(e){const t=[];if(void 0!==e.mediaUrl&&null!==e.mediaUrl&&""!==e.mediaUrl&&t.push(e.mediaUrl),void 0!==e.mediaUrls&&null!==e.mediaUrls){if(!Array.isArray(e.mediaUrls))throw new NativeArtifactDeliveryFailure;t.push(...e.mediaUrls)}return t.map(e=>{const t="string"==typeof e?parseBeeosFileUri(e).fileId:void 0;if(!t||e!==`beeos-file://${t}`||!fileIdPattern.test(t)||"00000000-0000-0000-0000-000000000000"===t)throw new NativeArtifactDeliveryFailure;return t})}function isDefiniteFileNotFound(e){if(!(e instanceof HarnessProtocolError&&404===e.status&&e.body))return!1;let t;try{t=JSON.parse(e.body)}catch{return!1}return object(t)&&"not_found"===t.code&&"file not found"===t.message}export function centralNativeOutputFileResolver(e,t){return async(i,r)=>{const a=await t.credential(i),n=t.outputFileBinding(i);let s;try{s=await e.resolveOutput(a,i.operationId,{...n,fileId:r})}catch(e){if(t.outputFileBinding(i),isDefiniteFileNotFound(e))throw new NativeArtifactDeliveryFailure;throw e}if(t.outputFileBinding(i),!object(s)||s.operationId!==i.operationId||s.requestMessageId!==n.requestMessageId||s.paramsHash!==n.paramsHash||s.activeRunRegistrationId!==n.activeRunRegistrationId||!object(s.file))throw new Error("native output Files response binding invalid");const o=s.file;if(o.file_id!==r||"ready"!==o.status||"string"!=typeof o.filename||!o.filename||"string"!=typeof o.content_type||!o.content_type||"number"!=typeof o.size_bytes||!Number.isSafeInteger(o.size_bytes)||o.size_bytes<0||"string"!=typeof o.checksum_sha256||!/^[0-9a-f]{64}$/.test(o.checksum_sha256)||"string"!=typeof o.created_at||!Number.isFinite(Date.parse(o.created_at)))throw new Error("native output Files metadata invalid");if([...o.filename].length>256||[...o.content_type].length>128||o.size_bytes>67108864)throw new NativeArtifactDeliveryFailure;return{id:r,filename:o.filename,media_type:o.content_type,size_bytes:o.size_bytes,sha256:o.checksum_sha256,status:"ready",owner_scope:"org",owner_id:null,created_at:o.created_at,expires_at:null}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash}from"node:crypto";import{isDeepStrictEqual}from"node:util";import{ChatStoreHttpError,chatAppendDigest,decodeNativeChatEvent,encodeNativeChatEvent}from"@beeos-ai/cloud-harness-sdk";import{OPENCLAW_NATIVE_CODEC,assertCentralNativeReceipt,nativePayloadDigest}from"./central-native-context-engine.js";import{generatedSessionName}from"./central-native-titles.js";const codec={name:"openclaw-session-events",version:"1"};export const CENTRAL_RESPONSE_CONTROL_CODEC={name:"beeos-response-control",version:"1"};const executionObservationType="response.beeos.execution_observation",decimal=e=>"string"==typeof e&&/^(0|[1-9][0-9]*)$/.test(e),key=e=>JSON.stringify([e.context.tenant_ref,e.context.scope_ref,e.sessionId,e.historyGeneration,e.branchId]),operationKey=e=>JSON.stringify([key(e),e.operationId,e.responseId,e.attemptId]),object=e=>null!==e&&"object"==typeof e&&!Array.isArray(e),publicId=e=>"string"==typeof e&&/^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/.test(e)?e:null;export function publicModelRoute(e,t){if("string"==typeof e&&e.includes("/")){const t=e.indexOf("/");return[publicId(e.slice(0,t)),publicId(e.slice(t+1))]}return[publicId(t),publicId(e)]}function executedRoute(e){const t=object(e.meta.agentMeta)?e.meta.agentMeta:{},n=object(t.terminalReceipt)?t.terminalReceipt:{},i=object(n.effective)?n.effective:{},r=object(e.meta.executionTrace)?e.meta.executionTrace:{};return"string"==typeof i.responseModel?i.responseModel:"string"==typeof r.winnerModel?r.winnerModel:i.model}export function publicModelId(e){if("string"==typeof e&&0!==e.length)return publicId(e.includes("/")?`arouter_${e.replaceAll("/","_")}`:e)??void 0}function executedFacts(e){const t=object(e.meta.agentMeta)?e.meta.agentMeta:{},n=object(t.terminalReceipt)?t.terminalReceipt:{},i=object(n.effective)?n.effective:{},r=object(e.meta.executionTrace)?e.meta.executionTrace:{},o=object(e.meta.requestShaping)?e.meta.requestShaping:{},a="string"==typeof n.runId?n.runId:void 0,[s,d]=publicModelRoute(executedRoute(e),"string"==typeof i.provider?i.provider:r.winnerProvider);if(a&&s&&d)return{nativeRunId:a,facts:{actual_provider_id:s,actual_model_id:d,..."boolean"==typeof r.fallbackUsed?{fallback_used:r.fallbackUsed}:{},..."string"==typeof o.reasoning?{reasoning:o.reasoning}:{}}}}function terminalOutputItem(e){const t="string"==typeof e.toolCallId?e.toolCallId:"string"==typeof e.tool_call_id?e.tool_call_id:void 0,n="string"==typeof e.toolName?e.toolName:"string"==typeof e.tool_name?e.tool_name:void 0;if(t||n){if(!t||!n)throw new Error("native tool result lacks its tool call identity");return{type:"tool_summary",tool_call_id:t,tool_name:n,outcome:!0===e.isError?"failed":!1===e.isError?"succeeded":"unknown",summary:"string"==typeof e.text?e.text.slice(0,4096):""}}return"string"==typeof e.text&&e.text.length>0?{type:"output_text",text:e.text}:void 0}function terminalUsage(e){const t=object(e.meta.agentMeta)?e.meta.agentMeta:{},n=object(t.usage)?t.usage:void 0;if(!n)return;const i=e=>"number"==typeof e&&Number.isSafeInteger(e)&&e>=0?e:void 0,r=i(n.input),o=i(n.output);if(void 0===r&&void 0===o)return;const a=publicModelId(executedRoute(e));return{input_tokens:r??0,output_tokens:o??0,source:"provider",...a?{actual_model_id:a}:{}}}function terminalProjection(e,t){const n=t.outcome,i=["cancelled","aborted","superseded"].includes(n.reason)?"cancelled":["hard_timeout","timed_out","abandoned"].includes(n.reason)||["max_tokens","length","max_output_tokens"].includes(n.stopReason??"")?"incomplete":"completed"===n.reason&&"ok"===n.status?"completed":"failed",r=[];for(const e of t.payloads){if(!object(e))throw new Error("native terminal payload is not a typed reply");if(e.mediaUrl||Array.isArray(e.mediaUrls)&&e.mediaUrls.length>0)throw new Error("native media output requires its authorized central file projection");const t=terminalOutputItem(e);t&&r.push(t)}const o=object(t.meta.agentMeta)?t.meta.agentMeta:{},a=terminalUsage(t);return{status:i,event:{type:"cancelled"===i?"response.failed":`response.${i}`,response:{id:e.responseId,status:i,output:r,..."string"==typeof o.model&&o.model.length>0?{model:o.model}:{},...a?{usage:a}:{},error:"failed"===i?{type:"harness_error",code:"harness_error",message:n.error||"The native harness could not complete this response."}:null,incomplete_details:"incomplete"===i?{reason:"completed"===n.reason?"max_output_tokens":"runtime_interrupted"}:null}}}}export class StateCentralNativeStore{client;credential;titles;writes=new Map;heads=new Map;publicEvents=new Map;memoryReads=new Map;executionObservations=new Map;constructor(e,t,n){this.client=e,this.credential=t,this.titles=n}async recordGeneratedTitle(e,t){if(!this.titles)throw new Error("generated Session titles are unavailable");const n=generatedSessionName(t);if(!n)throw new Error("generated Session title is empty");return await this.titles.title(await this.credential(e),{context:e.context,session_id:e.sessionId,history_generation:e.historyGeneration,branch_id:e.branchId,name:n,idempotency_key:`title:${e.operationId}`})}withWrite(e,t){const n=key(e),i=(this.writes.get(n)??Promise.resolve()).then(t);return this.writes.set(n,i),i}async commitPublicProgress(e,t){await this.withWrite(e,async()=>{if(!this.publicEvents.get(operationKey(e))?.length)return;if(0!==(await t.list(e.sessionId)).length)throw new Error("native progress has unresolved original writes");const n=await this.load(e);if(n.terminal?.response_id===e.responseId)throw new Error("original native Response is already terminal");const i=structuredClone(this.publicEvents.get(operationKey(e))??[]),r=nativePayloadDigest(i),o=this.prepareAppend({binding:e,events:[],expectedWatermark:n.watermark,publicProgress:!0,idempotencyKey:`progress:${e.operationId}:${n.watermark}:${r}`,nativeSnapshotDigest:r});await t.put(o);const a=await this.append(o);assertCentralNativeReceipt(o,a),await t.complete(o,a)})}recordPublicEvent(e,t){const n=operationKey(e),i=this.publicEvents.get(n)??[];i.push(structuredClone(t)),this.publicEvents.set(n,i)}recordMemoryRead(e,t){if("read"===t.status&&!t.watermark)throw new Error("actual Memory recall omitted its read watermark");this.memoryReads.set(operationKey(e),structuredClone(t))}bindExecutionObservation(e,t){if(t.admission.attemptId!==e.attemptId)throw new Error("native observation does not bind the original attempt");const n=operationKey(e),i=this.executionObservations.get(n);if(i&&!isDeepStrictEqual(i.source,t))throw new Error("native loaded observation changed");i||this.executionObservations.set(n,{source:structuredClone(t),loaded:!1})}nativeEventCapacity(e,t){const n=this.executionObservations.get(operationKey(e));return 200-(t?1:0)-(n&&!n.loaded?1:0)}async load(e){let t=null,n="0",i=null;const r=[];for(;;){const o=await this.client.load(await this.credential(e),{context:e.context,session_id:e.sessionId,history_generation:e.historyGeneration,branch_id:e.branchId,watermark:t,after:n,limit:200});this.assertPage(o,e,t,n),t=o.watermark;for(const e of o.events){if(e.sequence!==String(BigInt(n)+1n))throw new Error("central native event sequence has a gap");const t=decodeNativeChatEvent(e);if(isDeepStrictEqual(e.codec,codec))r.push(JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(t)));else if(!isDeepStrictEqual(e.codec,CENTRAL_RESPONSE_CONTROL_CODEC))throw new Error("central native event codec is not supported by this pinned Harness");n=e.sequence,i=e.event_id}if(o.next_after!==n||o.has_more&&BigInt(n)>=BigInt(t))throw new Error("central native page cursor does not match its fixed source");if(!o.has_more){if(n!==t)throw new Error("central native source ended before its fixed watermark");return this.heads.set(key(e),{watermark:t,lastEventId:i}),{codec:OPENCLAW_NATIVE_CODEC,events:r,watermark:t,writer:o.writer,terminal:o.terminal}}if(0===o.events.length)throw new Error("central native source made no page progress")}}prepareAppend(e){if(e.events.length>this.nativeEventCapacity(e.binding,Boolean(e.nativeOutcome)))throw new Error("native suffix must reserve its actual observation and terminal control rows");const t=this.heads.get(key(e.binding));if(!t||t.watermark!==e.expectedWatermark)throw new Error("native append has no exact loaded central source");let n=t.lastEventId;const i=e.events.map((t,i)=>{const r=Buffer.from(JSON.stringify(t),"utf8"),o=createHash("sha256").update(JSON.stringify([e.binding.sessionId,e.binding.historyGeneration,e.binding.branchId,String(BigInt(e.expectedWatermark)+BigInt(i)+1n)])).update(r).digest("hex"),a=encodeNativeChatEvent({eventId:`oc-${o}`,parentId:n,kind:t&&"object"==typeof t&&"type"in t&&"string"==typeof t.type?t.type:"native",codec:codec,content:r});return n=a.event_id,a});let r=null;const o=structuredClone(this.publicEvents.get(operationKey(e.binding))??[]),a=this.executionObservations.get(operationKey(e.binding)),s=(t,n,i)=>{const r=a.source,s="executed"===t?this.memoryReads.get(operationKey(e.binding)):void 0;o.push({type:executionObservationType,response_id:e.binding.responseId,attempt_id:e.binding.attemptId,resolved_request_hash:r.resolvedRequestHash,payload:{phase:t,attempt:{...r.admission,...i?{nativeRunId:i.nativeRunId}:{}},read_watermark:r.readWatermark,source_ref:{id:n.event_id,digest:n.sha256},session_config_receipt:"loaded"===t?r.sessionConfigReceipt:null,runtime:null,partial_effective:{...r.loadedFacts,...i?.facts??{},...s?{memory_observation:s.status,memory_read_watermark:s.watermark}:{}}}})};if(a&&!a.loaded){const t=Buffer.from(JSON.stringify({type:"configuration.applied",...a.source}),"utf8"),r=`oc-loaded-${createHash("sha256").update(e.idempotencyKey).update(t).digest("hex")}`,o=encodeNativeChatEvent({eventId:r,parentId:n,kind:"configuration.applied",codec:CENTRAL_RESPONSE_CONTROL_CODEC,content:t});i.push(o),n=r,s("loaded",o)}if(e.publicProgress){if(e.nativeOutcome||0!==e.events.length||0===o.length)throw new Error("public native progress has invalid effect shape");const t=Buffer.from(JSON.stringify({type:"response.progress",response_id:e.binding.responseId,operation_id:e.binding.operationId,public_events_sha256:nativePayloadDigest(o)}),"utf8"),r=`oc-progress-${createHash("sha256").update(e.idempotencyKey).digest("hex")}`;i.push(encodeNativeChatEvent({eventId:r,parentId:n,kind:"response.progress",codec:CENTRAL_RESPONSE_CONTROL_CODEC,content:t})),n=r}if(e.nativeOutcome){const t=terminalProjection(e.binding,e.nativeOutcome),d=`oc-terminal-${createHash("sha256").update(e.idempotencyKey).digest("hex")}`,c={type:"response.terminal",operation_id:e.binding.operationId,response_id:e.binding.responseId,attempt_id:e.binding.attemptId,native_outcome:e.nativeOutcome},l=encodeNativeChatEvent({eventId:d,parentId:n,kind:"response.terminal",codec:CENTRAL_RESPONSE_CONTROL_CODEC,content:Buffer.from(JSON.stringify(c),"utf8")});i.push(l),r={response_id:e.binding.responseId,status:t.status,event_id:d};const p=a?executedFacts(e.nativeOutcome):void 0;p&&s("executed",l,p),o.push(t.event)}const d={context:e.binding.context,session_id:e.binding.sessionId,history_generation:e.binding.historyGeneration,branch_id:e.binding.branchId,response_id:e.binding.responseId,attempt_id:e.binding.attemptId,public_events:o,writer:e.binding.writer,expected_watermark:e.expectedWatermark,operation_id:e.binding.operationId,idempotency_key:e.idempotencyKey,events:i,terminal:r},c=chatAppendDigest(d),l={...d,payload_sha256:c};return{...structuredClone(e),codec:OPENCLAW_NATIVE_CODEC,payloadDigest:c,wire:l}}async append(e){const t=e.wire;if(chatAppendDigest(t)!==e.payloadDigest||t.payload_sha256!==e.payloadDigest)throw new Error("pending native append no longer matches its original digest");const n=await this.client.append(await this.credential(e.binding),t);return this.accept(e.binding,t,n),n}async receipt(e){const t=e.binding;try{const n=await this.client.receipt(await this.credential(t),{context:t.context,session_id:t.sessionId,history_generation:t.historyGeneration,branch_id:t.branchId,idempotency_key:e.idempotencyKey,payload_sha256:e.payloadDigest});if(n.operation_id!==t.operationId||!isDeepStrictEqual(n.writer,t.writer))throw new Error("original native receipt belongs to another operation/writer");return n}catch(e){if(e instanceof ChatStoreHttpError&&404===e.status&&"not_found"===e.code)return null;throw e}}assertPage(e,t,n,i){if(e.session_id!==t.sessionId||e.history_generation!==t.historyGeneration||e.branch_id!==t.branchId||!decimal(e.watermark)||null!==n&&e.watermark!==n||BigInt(e.watermark)<BigInt(i)||!Array.isArray(e.events)||"boolean"!=typeof e.has_more||!isDeepStrictEqual(e.writer,t.writer))throw new Error("central native load does not match the authorized fixed source/writer")}accept(e,t,n){if(!(n.operation_id===e.operationId&&n.previous_watermark===t.expected_watermark&&decimal(n.read_watermark)&&n.read_watermark===String(BigInt(t.expected_watermark)+BigInt(t.events.length))&&isDeepStrictEqual(n.event_ids,t.events.map(e=>e.event_id))&&isDeepStrictEqual(n.terminal,t.terminal)&&isDeepStrictEqual(n.writer,e.writer)))throw new Error("native append returned a receipt for different committed content");const i=this.heads.get(key(e));this.heads.set(key(e),{watermark:n.read_watermark,lastEventId:n.event_ids.at(-1)??i?.lastEventId??null});const r=operationKey(e),o=this.executionObservations.get(r);o&&t.public_events.some(e=>e.type===executionObservationType&&object(e.payload)&&"loaded"===e.payload.phase)&&(o.loaded=!0);const a=this.publicEvents.get(r);if(a){const e=t.public_events.filter(e=>e.type!==executionObservationType),i=e.slice(0,e.length-(t.terminal?1:0));if(!isDeepStrictEqual(a.slice(0,i.length),i))throw new Error("confirmed public events differ from their pending native buffer");n.terminal||a.length===i.length?this.publicEvents.delete(r):this.publicEvents.set(r,a.slice(i.length))}}}
|
|
1
|
+
import{createHash}from"node:crypto";import{isDeepStrictEqual}from"node:util";import{ChatStoreHttpError,chatAppendDigest,decodeNativeChatEvent,encodeNativeChatEvent}from"@beeos-ai/cloud-harness-sdk";import{OPENCLAW_NATIVE_CODEC,assertCentralNativeReceipt,nativePayloadDigest}from"./central-native-context-engine.js";import{generatedSessionName}from"./central-native-titles.js";import{nativeOutputFileIds,NativeArtifactDeliveryFailure}from"./central-native-output-files.js";const codec={name:"openclaw-session-events",version:"1"};export const CENTRAL_RESPONSE_CONTROL_CODEC={name:"beeos-response-control",version:"1"};const executionObservationType="response.beeos.execution_observation",decimal=e=>"string"==typeof e&&/^(0|[1-9][0-9]*)$/.test(e),key=e=>JSON.stringify([e.context.tenant_ref,e.context.scope_ref,e.sessionId,e.historyGeneration,e.branchId]),operationKey=e=>JSON.stringify([key(e),e.operationId,e.responseId,e.attemptId]),object=e=>null!==e&&"object"==typeof e&&!Array.isArray(e),publicId=e=>"string"==typeof e&&/^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/.test(e)?e:null;export function publicModelRoute(e,t){if("string"==typeof e&&e.includes("/")){const t=e.indexOf("/");return[publicId(e.slice(0,t)),publicId(e.slice(t+1))]}return[publicId(t),publicId(e)]}function executedRoute(e){const t=object(e.meta.agentMeta)?e.meta.agentMeta:{},n=object(t.terminalReceipt)?t.terminalReceipt:{},i=object(n.effective)?n.effective:{},r=object(e.meta.executionTrace)?e.meta.executionTrace:{};return"string"==typeof i.responseModel?i.responseModel:"string"==typeof r.winnerModel?r.winnerModel:i.model}export function publicModelId(e){if("string"==typeof e&&0!==e.length)return publicId(e.includes("/")?`arouter_${e.replaceAll("/","_")}`:e)??void 0}function executedFacts(e){const t=object(e.meta.agentMeta)?e.meta.agentMeta:{},n=object(t.terminalReceipt)?t.terminalReceipt:{},i=object(n.effective)?n.effective:{},r=object(e.meta.executionTrace)?e.meta.executionTrace:{},o=object(e.meta.requestShaping)?e.meta.requestShaping:{},a="string"==typeof n.runId?n.runId:void 0,[s,d]=publicModelRoute(executedRoute(e),"string"==typeof i.provider?i.provider:r.winnerProvider);if(a&&s&&d)return{nativeRunId:a,facts:{actual_provider_id:s,actual_model_id:d,..."boolean"==typeof r.fallbackUsed?{fallback_used:r.fallbackUsed}:{},..."string"==typeof o.reasoning?{reasoning:o.reasoning}:{}}}}function terminalOutputItem(e){const t="string"==typeof e.toolCallId?e.toolCallId:"string"==typeof e.tool_call_id?e.tool_call_id:void 0,n="string"==typeof e.toolName?e.toolName:"string"==typeof e.tool_name?e.tool_name:void 0;if(t||n){if(!t||!n)throw new Error("native tool result lacks its tool call identity");return{type:"tool_summary",tool_call_id:t,tool_name:n,outcome:!0===e.isError?"failed":!1===e.isError?"succeeded":"unknown",summary:"string"==typeof e.text?e.text.slice(0,4096):""}}return"string"==typeof e.text&&e.text.length>0?{type:"output_text",text:e.text}:void 0}function terminalUsage(e){const t=object(e.meta.agentMeta)?e.meta.agentMeta:{},n=object(t.usage)?t.usage:void 0;if(!n)return;const i=e=>"number"==typeof e&&Number.isSafeInteger(e)&&e>=0?e:void 0,r=i(n.input),o=i(n.output);if(void 0===r&&void 0===o)return;const a=publicModelId(executedRoute(e));return{input_tokens:r??0,output_tokens:o??0,source:"provider",...a?{actual_model_id:a}:{}}}async function terminalProjection(e,t,n){const i=t.outcome;let r=["cancelled","aborted","superseded"].includes(i.reason)?"cancelled":["hard_timeout","timed_out","abandoned"].includes(i.reason)||["max_tokens","length","max_output_tokens"].includes(i.stopReason??"")?"incomplete":"completed"===i.reason&&"ok"===i.status?"completed":"failed";const o=[];let a;const s=new Set;try{for(const i of t.payloads){if(!object(i))throw new Error("native terminal payload is not a typed reply");const t=terminalOutputItem(i);t&&o.push(t);for(const t of nativeOutputFileIds(i))if(!s.has(t)){if(!n)throw new Error("authorized native output Files resolver is unavailable");o.push({type:"output_file",file:await n(e,t)}),s.add(t)}}}catch(e){if(!(e instanceof NativeArtifactDeliveryFailure))throw e;a=e,"completed"===r&&(r="failed")}const d=object(t.meta.agentMeta)?t.meta.agentMeta:{},c=terminalUsage(t);return{status:r,event:{type:"cancelled"===r?"response.failed":`response.${r}`,response:{id:e.responseId,status:r,output:o,..."string"==typeof d.model&&d.model.length>0?{model:d.model}:{},...c?{usage:c}:{},error:"failed"===r?{type:"harness_error",code:a?"artifact_delivery_failed":"harness_error",message:a?.message??(i.error||"The native harness could not complete this response.")}:null,incomplete_details:"incomplete"===r?{reason:"completed"===i.reason?"max_output_tokens":"runtime_interrupted"}:null}}}}export class StateCentralNativeStore{client;credential;titles;resolveOutputFile;writes=new Map;heads=new Map;publicEvents=new Map;memoryReads=new Map;executionObservations=new Map;constructor(e,t,n,i){this.client=e,this.credential=t,this.titles=n,this.resolveOutputFile=i}async recordGeneratedTitle(e,t){if(!this.titles)throw new Error("generated Session titles are unavailable");const n=generatedSessionName(t);if(!n)throw new Error("generated Session title is empty");return await this.titles.title(await this.credential(e),{context:e.context,session_id:e.sessionId,history_generation:e.historyGeneration,branch_id:e.branchId,name:n,idempotency_key:`title:${e.operationId}`})}withWrite(e,t){const n=key(e),i=(this.writes.get(n)??Promise.resolve()).then(t);return this.writes.set(n,i),i}async commitPublicProgress(e,t){await this.withWrite(e,async()=>{if(!this.publicEvents.get(operationKey(e))?.length)return;if(0!==(await t.list(e.sessionId)).length)throw new Error("native progress has unresolved original writes");const n=await this.load(e);if(n.terminal?.response_id===e.responseId)throw new Error("original native Response is already terminal");const i=structuredClone(this.publicEvents.get(operationKey(e))??[]),r=nativePayloadDigest(i),o=await this.prepareAppend({binding:e,events:[],expectedWatermark:n.watermark,publicProgress:!0,idempotencyKey:`progress:${e.operationId}:${n.watermark}:${r}`,nativeSnapshotDigest:r});await t.put(o);const a=await this.append(o);assertCentralNativeReceipt(o,a),await t.complete(o,a)})}recordPublicEvent(e,t){const n=operationKey(e),i=this.publicEvents.get(n)??[];i.push(structuredClone(t)),this.publicEvents.set(n,i)}recordMemoryRead(e,t){if("read"===t.status&&!t.watermark)throw new Error("actual Memory recall omitted its read watermark");this.memoryReads.set(operationKey(e),structuredClone(t))}bindExecutionObservation(e,t){if(t.admission.attemptId!==e.attemptId)throw new Error("native observation does not bind the original attempt");const n=operationKey(e),i=this.executionObservations.get(n);if(i&&!isDeepStrictEqual(i.source,t))throw new Error("native loaded observation changed");i||this.executionObservations.set(n,{source:structuredClone(t),loaded:!1})}nativeEventCapacity(e,t){const n=this.executionObservations.get(operationKey(e));return 200-(t?1:0)-(n&&!n.loaded?1:0)}async load(e){let t=null,n="0",i=null;const r=[];for(;;){const o=await this.client.load(await this.credential(e),{context:e.context,session_id:e.sessionId,history_generation:e.historyGeneration,branch_id:e.branchId,watermark:t,after:n,limit:200});this.assertPage(o,e,t,n),t=o.watermark;for(const e of o.events){if(e.sequence!==String(BigInt(n)+1n))throw new Error("central native event sequence has a gap");const t=decodeNativeChatEvent(e);if(isDeepStrictEqual(e.codec,codec))r.push(JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(t)));else if(!isDeepStrictEqual(e.codec,CENTRAL_RESPONSE_CONTROL_CODEC))throw new Error("central native event codec is not supported by this pinned Harness");n=e.sequence,i=e.event_id}if(o.next_after!==n||o.has_more&&BigInt(n)>=BigInt(t))throw new Error("central native page cursor does not match its fixed source");if(!o.has_more){if(n!==t)throw new Error("central native source ended before its fixed watermark");return this.heads.set(key(e),{watermark:t,lastEventId:i}),{codec:OPENCLAW_NATIVE_CODEC,events:r,watermark:t,writer:o.writer,terminal:o.terminal}}if(0===o.events.length)throw new Error("central native source made no page progress")}}async prepareAppend(e){if((e=structuredClone(e)).events.length>this.nativeEventCapacity(e.binding,Boolean(e.nativeOutcome)))throw new Error("native suffix must reserve its actual observation and terminal control rows");const t=this.heads.get(key(e.binding));if(!t||t.watermark!==e.expectedWatermark)throw new Error("native append has no exact loaded central source");let n=t.lastEventId;const i=e.events.map((t,i)=>{const r=Buffer.from(JSON.stringify(t),"utf8"),o=createHash("sha256").update(JSON.stringify([e.binding.sessionId,e.binding.historyGeneration,e.binding.branchId,String(BigInt(e.expectedWatermark)+BigInt(i)+1n)])).update(r).digest("hex"),a=encodeNativeChatEvent({eventId:`oc-${o}`,parentId:n,kind:t&&"object"==typeof t&&"type"in t&&"string"==typeof t.type?t.type:"native",codec:codec,content:r});return n=a.event_id,a});let r=null;const o=structuredClone(this.publicEvents.get(operationKey(e.binding))??[]),a=this.executionObservations.get(operationKey(e.binding)),s=(t,n,i)=>{const r=a.source,s="executed"===t?this.memoryReads.get(operationKey(e.binding)):void 0;o.push({type:executionObservationType,response_id:e.binding.responseId,attempt_id:e.binding.attemptId,resolved_request_hash:r.resolvedRequestHash,payload:{phase:t,attempt:{...r.admission,...i?{nativeRunId:i.nativeRunId}:{}},read_watermark:r.readWatermark,source_ref:{id:n.event_id,digest:n.sha256},session_config_receipt:"loaded"===t?r.sessionConfigReceipt:null,runtime:null,partial_effective:{...r.loadedFacts,...i?.facts??{},...s?{memory_observation:s.status,memory_read_watermark:s.watermark}:{}}}})};if(a&&!a.loaded){const t=Buffer.from(JSON.stringify({type:"configuration.applied",...a.source}),"utf8"),r=`oc-loaded-${createHash("sha256").update(e.idempotencyKey).update(t).digest("hex")}`,o=encodeNativeChatEvent({eventId:r,parentId:n,kind:"configuration.applied",codec:CENTRAL_RESPONSE_CONTROL_CODEC,content:t});i.push(o),n=r,s("loaded",o)}if(e.publicProgress){if(e.nativeOutcome||0!==e.events.length||0===o.length)throw new Error("public native progress has invalid effect shape");const t=Buffer.from(JSON.stringify({type:"response.progress",response_id:e.binding.responseId,operation_id:e.binding.operationId,public_events_sha256:nativePayloadDigest(o)}),"utf8"),r=`oc-progress-${createHash("sha256").update(e.idempotencyKey).digest("hex")}`;i.push(encodeNativeChatEvent({eventId:r,parentId:n,kind:"response.progress",codec:CENTRAL_RESPONSE_CONTROL_CODEC,content:t})),n=r}if(e.nativeOutcome){const t=await terminalProjection(e.binding,e.nativeOutcome,this.resolveOutputFile),d=`oc-terminal-${createHash("sha256").update(e.idempotencyKey).digest("hex")}`,c={type:"response.terminal",operation_id:e.binding.operationId,response_id:e.binding.responseId,attempt_id:e.binding.attemptId,native_outcome:e.nativeOutcome},l=encodeNativeChatEvent({eventId:d,parentId:n,kind:"response.terminal",codec:CENTRAL_RESPONSE_CONTROL_CODEC,content:Buffer.from(JSON.stringify(c),"utf8")});i.push(l),r={response_id:e.binding.responseId,status:t.status,event_id:d};const p=a?executedFacts(e.nativeOutcome):void 0;p&&s("executed",l,p),o.push(t.event)}const d={context:e.binding.context,session_id:e.binding.sessionId,history_generation:e.binding.historyGeneration,branch_id:e.binding.branchId,response_id:e.binding.responseId,attempt_id:e.binding.attemptId,public_events:o,writer:e.binding.writer,expected_watermark:e.expectedWatermark,operation_id:e.binding.operationId,idempotency_key:e.idempotencyKey,events:i,terminal:r},c=chatAppendDigest(d),l={...d,payload_sha256:c};return{...structuredClone(e),codec:OPENCLAW_NATIVE_CODEC,payloadDigest:c,wire:l}}async append(e){const t=e.wire;if(chatAppendDigest(t)!==e.payloadDigest||t.payload_sha256!==e.payloadDigest)throw new Error("pending native append no longer matches its original digest");const n=await this.client.append(await this.credential(e.binding),t);return this.accept(e.binding,t,n),n}async receipt(e){const t=e.binding;try{const n=await this.client.receipt(await this.credential(t),{context:t.context,session_id:t.sessionId,history_generation:t.historyGeneration,branch_id:t.branchId,idempotency_key:e.idempotencyKey,payload_sha256:e.payloadDigest});if(n.operation_id!==t.operationId||!isDeepStrictEqual(n.writer,t.writer))throw new Error("original native receipt belongs to another operation/writer");return n}catch(e){if(e instanceof ChatStoreHttpError&&404===e.status&&"not_found"===e.code)return null;throw e}}assertPage(e,t,n,i){if(e.session_id!==t.sessionId||e.history_generation!==t.historyGeneration||e.branch_id!==t.branchId||!decimal(e.watermark)||null!==n&&e.watermark!==n||BigInt(e.watermark)<BigInt(i)||!Array.isArray(e.events)||"boolean"!=typeof e.has_more||!isDeepStrictEqual(e.writer,t.writer))throw new Error("central native load does not match the authorized fixed source/writer")}accept(e,t,n){if(!(n.operation_id===e.operationId&&n.previous_watermark===t.expected_watermark&&decimal(n.read_watermark)&&n.read_watermark===String(BigInt(t.expected_watermark)+BigInt(t.events.length))&&isDeepStrictEqual(n.event_ids,t.events.map(e=>e.event_id))&&isDeepStrictEqual(n.terminal,t.terminal)&&isDeepStrictEqual(n.writer,e.writer)))throw new Error("native append returned a receipt for different committed content");const i=this.heads.get(key(e));this.heads.set(key(e),{watermark:n.read_watermark,lastEventId:n.event_ids.at(-1)??i?.lastEventId??null});const r=operationKey(e),o=this.executionObservations.get(r);o&&t.public_events.some(e=>e.type===executionObservationType&&object(e.payload)&&"loaded"===e.payload.phase)&&(o.loaded=!0);const a=this.publicEvents.get(r);if(a){const e=t.public_events.filter(e=>e.type!==executionObservationType),i=e.slice(0,e.length-(t.terminal?1:0));if(!isDeepStrictEqual(a.slice(0,i.length),i))throw new Error("confirmed public events differ from their pending native buffer");n.terminal||a.length===i.length?this.publicEvents.delete(r):this.publicEvents.set(r,a.slice(i.length))}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{HtmlDeliveryGuard}from"../canvas/html-delivery.js";import{createNativeOutputFileAttempt}from"./native-output-file-attempt.js";import{downloadNativeInputFile}from"./native-input-files.js";import{bindExistingRuntimeChatReply}from"@beeos-ai/cloud-harness-sdk";import{RUNTIME_HASH_DOMAINS}from"@beeos-ai/beeos-types/runtime";import{dispatchImInboundPrompt}from"../im-runtime-dispatch.js";import{prepareNativePromptInput}from"./native-prompt-preflight.js";import{verifyNativePromptAuthority}from"./native-prompt-authority.js";import{RuntimeCommandError}from"./runtime-command-dispatcher.js";import{runtimeCommandResultHash}from"./runtime-command-journal.js";import{runtimeMessageBase,runtimeMessageHash,semanticEqual}from"./runtime-message-channel-contract.js";import{openClawSessionModePatch}from"./runtime-session-control-service.js";export const nativePromptCancellationReason="chat_cancel:runtime_operation_cancel_requested";export const nativePromptExecutionDeadlineReason="deadline exceeded: the Cloud turn execution budget is about to expire";const nativePromptWrapUpMarginMs=3e4;export class NativeCloudPromptBridge{options;constructor(e){if(this.options=e,"function"!=typeof e.host.resolveNativePromptSessionKey)throw new RuntimeCommandError("INVALID_PARAMS","native Core target resolver required");if("function"!=typeof e.host.prepareNativePromptModel)throw new RuntimeCommandError("INVALID_PARAMS","native Core model preparation required");if(!e.runBoundary)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native MS run boundary required")}async execute(e){const{options:t}=this;if(await t.verifier.refresh(),!e.delivery.executionGrant)throw new RuntimeCommandError("INVALID_PARAMS","native grant missing");const a=e.delivery.message.payload,n="string"==typeof a.operationId?await t.journal.get(a.operationId):null,i=!!n&&"session.prompt"===n.command&&["started","effect_committed","projection_committed","failed"].includes(n.phase)&&n.paramsHash===a.paramsHash&&n.messageBinding?.requestMessageId===a.requestMessageId&&n.messageBinding?.requestHash===a.requestHash,r=verifyNativePromptAuthority({request:e.delivery.message.payload,decoded:t.verifier.verifyAndDecodeGrant(e.delivery.executionGrant),lease:e.lease,lineage:t.getLineage(),allowExpiredReadOnly:i}),{params:o}=r,s=r.request;try{const a=e.delivery.message;if("runtime_rpc_request"!==a.type||"completed"!==a.state||a.message_id!==s.requestMessageId||a.channel_id!==s.operationId||void 0!==a.in_reply_to)throw new RuntimeCommandError("INVALID_PARAMS","native envelope binding invalid");let n;void 0!==o.mode&&openClawSessionModePatch(o.mode);try{if(void 0!==o.mentions)throw new TypeError("native host per-prompt optional binding not implemented");n=prepareNativePromptInput(o.parts)}catch(e){throw new RuntimeCommandError(i?"OUTCOME_UNKNOWN":"INVALID_PARAMS","native host part unsupported",void 0,{cause:e})}const d=n.message;if(!t.host.activeRunAuthority)throw new RuntimeCommandError("EXECUTION_FAILED","native existing active-run authority unavailable");const m=()=>{const a=t.getLease(),n=t.getLineage();if(!a||a.instanceId!==e.lease.instanceId||a.handlerIdentity!==e.lease.handlerIdentity||a.runtimeEpoch!==o.runtimeLease.runtimeEpoch||a.leaseId!==o.runtimeLease.leaseId||n.journalStoreId!==o.runtimeLease.journalStoreId||n.journalGeneration!==o.runtimeLease.journalGeneration||Date.parse(a.leaseExpiresAt)<=Date.now())throw new RuntimeCommandError("INSTANCE_EPOCH_MISMATCH","native prompt attempt fenced")};m();const l=await t.channel.history({operationId:s.operationId,lease:e.lease,currentNativePrompt:r});if(m(),"found"!==l.status||l.snapshot.requestHash!==s.requestHash||l.snapshot.requestMessageId!==s.requestMessageId||!semanticEqual(l.snapshot.request.payload,s))throw new RuntimeCommandError("INVALID_PARAMS","native retained request mismatch");let u,p=await t.journal.get(s.operationId);if(m(),p&&("session.prompt"!==p.command||p.paramsHash!==s.paramsHash||p.runtimeEpoch!==o.runtimeLease.runtimeEpoch||p.messageBinding?.requestMessageId!==s.requestMessageId||p.messageBinding.requestHash!==s.requestHash))throw new RuntimeCommandError("OUTCOME_UNKNOWN","native existing journal binding mismatch");if(!t.http.getMessage)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native task snapshot unavailable");try{u=await t.http.getMessage(t.getLease(),{conversationId:o.conversationId,messageId:o.taskRequestMessageId})}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original task snapshot unavailable",void 0,{cause:e})}if(m(),u.messageId!==o.taskRequestMessageId||u.conversationId!==o.conversationId||"chat_message"!==u.type||u.body!==d)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original task snapshot mismatch");const c=async()=>{if(!t.http.getMessage)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native single snapshot unavailable");m();const e=await t.http.getMessage(t.getLease(),{conversationId:o.conversationId,messageId:o.replyMessageId});return m(),this.assertReply(e,r),e};if(l.snapshot.started||p&&"prepared"!==p.phase){const e=l.snapshot.runBoundary?.finishedReceipt,a=l.snapshot.final;if(!(p&&["started","effect_committed","projection_committed","failed"].includes(p.phase)&&e&&"finished"===e.state&&e.activeRunRegistrationId===o.taskId&&a))throw new RuntimeCommandError("OUTCOME_UNKNOWN","native durable MS finish audit or original result unavailable");const n=await c();if("agent_reply"!==n.type||n.state!==e.replyState||n.stopReason!==e.replyStopReason||n.updatedAt!==e.replyUpdatedAt)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original terminal does not match finished audit");const i=this.terminal(n,r);if(a.payload.outcome!==i.outcome||"final_message"!==l.snapshot.terminalSource)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original final outcome mismatch");const d=a.payload.response;if("2.0"!==d.jsonrpc||d.id!==s.request.id)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original final RPC binding mismatch");const u=runtimeCommandResultHash(i.result);if(p.resultReceipt&&p.resultReceipt.resultHash!==u||void 0!==p.result&&!semanticEqual(p.result,i.result))throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original result conflicts with local receipt");if(void 0===d.result)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original canonical result evidence unavailable");{const e=l.snapshot.effectCommitted?.payload,t=runtimeMessageHash(RUNTIME_HASH_DOMAINS.coreResult,{method:s.method,result:d.result});if("succeeded"!==i.outcome||void 0!==d.error||!semanticEqual(d.result,i.result)||!e||e.effectRecord.coreResultHash!==t||e.effectRecord.coreResultRef!==`sha256:${t}`||a.payload.effectRecordHash!==e.effectRecordHash||a.payload.serviceResultHash!==runtimeMessageHash(RUNTIME_HASH_DOMAINS.serviceResult,{method:s.method,result:d.result}))throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original final result hash evidence mismatch")}const h=d.result;return m(),"started"===p.phase&&(p=await t.journal.transition({operationId:s.operationId,expectedRevision:p.revision,phase:"succeeded"===i.outcome?"effect_committed":"failed",result:h}),m()),{request:s,outcome:i.outcome,result:h,replayedFinal:a}}if(n.files.length&&!t.inputFiles)throw new RuntimeCommandError("EXECUTION_FAILED","native authorized input file resolver unavailable");if(l.snapshot.terminal||e.signal.aborted||l.snapshot.cancelRequested||await t.journal.getCancellation(s.operationId))throw new RuntimeCommandError("OPERATION_CANCELLED","native prompt cancelled before effect");const h=await t.host.resolveNativePromptSessionKey(r,m);if(m(),p=await t.journal.acceptMessageRequest({operationId:s.operationId,command:"session.prompt",paramsHash:s.paramsHash,runtimeEpoch:o.runtimeLease.runtimeEpoch,requestMessageId:s.requestMessageId,requestHash:s.requestHash}),m(),"prepared"!==p.phase)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native task already started");let v;const g=await bindExistingRuntimeChatReply({authority:{currentLease:t.getLease},http:t.http,binding:{conversationId:o.conversationId,messageId:o.replyMessageId,taskRequestMessageId:o.taskRequestMessageId,assertAttempt:m,assertPreparedClear:e=>{if(m(),!v||e.activeRunRegistrationId!==v||e.historyGeneration!==r.historyGeneration||e.runtimeEpoch!==o.runtimeLease.runtimeEpoch)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native prepared clear does not freeze this registered attempt")},mutationKey:e=>`native-reply:${s.operationId}:${o.runtimeLease.journalStoreId}:${o.runtimeLease.journalGeneration}:${e}`}});if(m(),e.signal.aborted||await t.journal.getCancellation(s.operationId))throw new RuntimeCommandError("OPERATION_CANCELLED","native prompt cancelled before start");await t.channel.append({operationId:s.operationId,lease:t.getLease(),currentNativePrompt:r,executionGrant:e.delivery.executionGrant,type:"runtime_operation_started",payload:{...runtimeMessageBase(s),executionGrantHash:s.executionGrantHash,handlerIdentity:e.lease.handlerIdentity,executionMode:"start",claimedAt:p.updatedAt}}),m(),p=await t.journal.transition({operationId:s.operationId,expectedRevision:p.revision,phase:"started"}),m();const I=()=>{m();const e=t.getLease();return{leaseId:e.leaseId,handlerIdentity:e.handlerIdentity,runtimeEpoch:e.runtimeEpoch,runtimeLeaseCredential:e.runtimeLeaseCredential}},f={operationId:s.operationId,requestMessageId:s.requestMessageId,conversationId:r.command.context.conversation.runtimeConversationUid,historyGeneration:r.historyGeneration,runtimeRunId:o.runtimeRunId},R=await t.runBoundary.start({...f,lease:I()});if(m(),"registered"!==R.status||R.historyGeneration!==r.historyGeneration||R.activeRunRegistrationId!==o.taskId)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native MS run start did not register the original task");v=R.activeRunRegistrationId;const N=new AbortController,w=()=>N.abort(e.signal.reason);if(e.signal.addEventListener("abort",w,{once:!0}),e.signal.aborted&&w(),e.setCancel(e=>N.abort(e)),await t.journal.getCancellation(s.operationId)&&N.abort(nativePromptCancellationReason),m(),N.signal.aborted){if(e.signal.removeEventListener("abort",w),N.signal.reason===nativePromptCancellationReason)throw new RuntimeCommandError("OPERATION_CANCELLED","native prompt cancelled before host invocation");throw new RuntimeCommandError("OUTCOME_UNKNOWN","native registered run stopped before host invocation")}const E=[];let y;const C=JSON.parse((await g.opened()).rawText),O=C.parts?.length??0,M=async e=>{const t=await e;return m(),this.assertReply(t,r),y=t,t},_={id:g.id,get isTerminated(){return g.isTerminated},get parts(){return E},opened:async()=>({messageId:g.id,outcome:"bound"}),appendBody:e=>g.appendBody(e),setBody:e=>g.setBody(e),addPart:e=>{E.push(e),g.addPart(e)},replacePart:(e,t)=>{E[e]=t,g.replacePart(O+e,t)},appendToolResult:(e,t,a)=>{const n={type:"tool_result",tool_use_id:e,content:t,...a?{is_error:!0}:{}};E.push(n),g.addPart(n)},finalize:e=>M(g.finalize(e)),fail:e=>M(g.fail(e)),cancel:e=>M(g.cancel(e))},b={message:d,mediaPaths:[],mediaTypes:[]};let U,A;const q=t.host.htmlDeliveryEnabled?new HtmlDeliveryGuard(!1):void 0,T=createNativeOutputFileAttempt({htmlDelivery:q,operationId:s.operationId,requestMessageId:s.requestMessageId,paramsHash:s.paramsHash,activeRunRegistrationId:v,getLease:()=>(m(),t.getLease()),assertAttempt:m,signal:N.signal}),P=setTimeout(()=>N.abort(nativePromptExecutionDeadlineReason),Math.max(0,Math.min(Date.parse(s.executionDeadlineAt)-3e4-Date.now(),2147483647)));P.unref?.();try{await dispatchImInboundPrompt({...t.host,htmlDelivery:q,runtimeRunId:o.runtimeRunId,onNativeAgentRunStart:e=>T.bindHostRun(e),nativeActiveRunRegistration:{runtimeConversationUid:f.conversationId,runtimeSessionKey:r.command.context.conversation.runtimeSessionKey,historyGeneration:R.historyGeneration,targetMessageId:o.taskRequestMessageId,runtimeRunId:o.runtimeRunId,activeRunRegistrationId:R.activeRunRegistrationId},assertNativeTarget:async()=>{if(await t.host.resolveNativePromptSessionKey(r,m)!==h)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native prompt target changed before host invocation")},prepareNativeModel:async e=>{m(),await t.host.prepareNativePromptModel(r,e,m),m();for(const e of n.files){if(!t.inputFiles)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native authorized input file resolver unavailable");const a=await t.inputFiles.resolve({operationId:s.operationId,requestMessageId:s.requestMessageId,paramsHash:s.paramsHash,partIndex:e.partIndex,lease:t.getLease(),signal:N.signal});m();const n=await downloadNativeInputFile({fileId:e.fileId,...a,signal:N.signal,assertAttempt:m});b.mediaPaths.push(n.path),b.mediaTypes.push(n.mimeType)}m()},onNativeRunCompletion:e=>{A=e},retainedStream:_,abortSignal:N.signal,inReplyTo:o.taskRequestMessageId,prompt:{channelId:o.conversationId,inboundMessageId:o.taskRequestMessageId,requestId:s.requestMessageId,selfPrincipalId:e.lease.instanceId,sessionKey:h,dispatchInput:b},client:{messages:{startStream(){throw new Error("native reply POST forbidden")},getEnvelope:async()=>({state:(await c()).state})},getSnapshot:()=>({connection:"connected",messages:{},conversations:{}})}})}catch(e){U=e}finally{clearTimeout(P),T.close(),e.signal.removeEventListener("abort",w)}if(!A&&U)throw U;if(!A||A.runtimeRunId!==o.runtimeRunId||A.token.sessionKey!==h)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native physical host completion unavailable");let S;try{await A.completion}catch(e){S=e}if(m(),!y)throw new RuntimeCommandError("OUTCOME_UNKNOWN",void 0!==S?"native host/abort/drain did not converge":"native kernel settled without verified original reply terminal",void 0,{cause:S??U});const H=this.terminal(y,r),L=await c();g.assertTerminalSnapshot(L);const x="completed"===L.state?"completed":"cancelled"===L.state?"cancelled":"failed",K=await t.runBoundary.finish({...f,activeRunRegistrationId:v,terminalState:x,source:"runtime",lease:I()});if(m(),"finished"!==K.status&&"idempotent"!==K.status||K.activeRunRegistrationId!==v)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native MS run finish was not acknowledged");return await t.journal.transition({operationId:s.operationId,expectedRevision:p.revision,phase:"succeeded"===H.outcome?"effect_committed":"failed",result:H.result}),m(),{request:s,...H}}catch(e){throw new NativePromptExecutionFailure(s,e)}}assertReply(e,t){if(e.messageId!==t.params.replyMessageId||e.conversationId!==t.params.conversationId||e.replyTo!==t.params.taskRequestMessageId)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native durable reply binding mismatch")}terminal(e,t){if(!e.stopReason||!["completed","failed","refused","cancelled"].includes(e.state))throw new RuntimeCommandError("OUTCOME_UNKNOWN","native durable terminal absent");const a="cancelled"===e.state&&"user_stop"===e.stopReason?"cancelled":"completed"===e.state&&"end_turn"===e.stopReason?"succeeded":"failed";return{outcome:a,result:{runtimeRunId:t.params.runtimeRunId,stopReason:e.stopReason,requestAborted:"cancelled"===e.state&&"user_stop"===e.stopReason,..."failed"===a?{error:e.body}:{}}}}}export const NATIVE_PROMPT_UNKNOWN_REASONS=new Set(["native MS run boundary required","native existing journal binding mismatch","native task snapshot unavailable","native original task snapshot unavailable","native original task snapshot mismatch","native single snapshot unavailable","native durable MS finish audit or original result unavailable","native original terminal does not match finished audit","native original final outcome mismatch","native original final RPC binding mismatch","native original result conflicts with local receipt","native original final result hash evidence mismatch","native original canonical result evidence unavailable","native task already started","native prepared clear does not freeze this registered attempt","native MS run start did not register the original task","native registered run stopped before host invocation","native prompt target changed before host invocation","native authorized input file resolver unavailable","native physical host completion unavailable","native host/abort/drain did not converge","native kernel settled without verified original reply terminal","native MS run finish was not acknowledged","native durable reply binding mismatch","native durable terminal absent"]);export function nativePromptUnknownReason(e){return e instanceof RuntimeCommandError&&"OUTCOME_UNKNOWN"===e.code?NATIVE_PROMPT_UNKNOWN_REASONS.has(e.message)?e.message:"unlisted":"not_unknown"}export class NativePromptExecutionFailure extends Error{request;failure;constructor(e,t){super(t instanceof Error?t.message:String(t),{cause:t}),this.request=e,this.failure=t}}
|
|
1
|
+
import{HtmlDeliveryGuard}from"../canvas/html-delivery.js";import{createNativeOutputFileAttempt,registerNativeOutputRunContext}from"./native-output-file-attempt.js";import{downloadNativeInputFile}from"./native-input-files.js";import{bindExistingRuntimeChatReply}from"@beeos-ai/cloud-harness-sdk";import{RUNTIME_HASH_DOMAINS}from"@beeos-ai/beeos-types/runtime";import{dispatchImInboundPrompt}from"../im-runtime-dispatch.js";import{prepareNativePromptInput}from"./native-prompt-preflight.js";import{verifyNativePromptAuthority}from"./native-prompt-authority.js";import{RuntimeCommandError}from"./runtime-command-dispatcher.js";import{runtimeCommandResultHash}from"./runtime-command-journal.js";import{runtimeMessageBase,runtimeMessageHash,semanticEqual}from"./runtime-message-channel-contract.js";import{openClawSessionModePatch}from"./runtime-session-control-service.js";export const nativePromptCancellationReason="chat_cancel:runtime_operation_cancel_requested";export const nativePromptExecutionDeadlineReason="deadline exceeded: the Cloud turn execution budget is about to expire";const nativePromptWrapUpMarginMs=3e4;export class NativeCloudPromptBridge{options;constructor(e){if(this.options=e,"function"!=typeof e.host.resolveNativePromptSessionKey)throw new RuntimeCommandError("INVALID_PARAMS","native Core target resolver required");if("function"!=typeof e.host.prepareNativePromptModel)throw new RuntimeCommandError("INVALID_PARAMS","native Core model preparation required");if(!e.runBoundary)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native MS run boundary required")}async execute(e){const{options:t}=this;if(await t.verifier.refresh(),!e.delivery.executionGrant)throw new RuntimeCommandError("INVALID_PARAMS","native grant missing");const a=e.delivery.message.payload,n="string"==typeof a.operationId?await t.journal.get(a.operationId):null,i=!!n&&"session.prompt"===n.command&&["started","effect_committed","projection_committed","failed"].includes(n.phase)&&n.paramsHash===a.paramsHash&&n.messageBinding?.requestMessageId===a.requestMessageId&&n.messageBinding?.requestHash===a.requestHash,r=verifyNativePromptAuthority({request:e.delivery.message.payload,decoded:t.verifier.verifyAndDecodeGrant(e.delivery.executionGrant),lease:e.lease,lineage:t.getLineage(),allowExpiredReadOnly:i}),{params:o}=r,s=r.request;try{const a=e.delivery.message;if("runtime_rpc_request"!==a.type||"completed"!==a.state||a.message_id!==s.requestMessageId||a.channel_id!==s.operationId||void 0!==a.in_reply_to)throw new RuntimeCommandError("INVALID_PARAMS","native envelope binding invalid");let n;void 0!==o.mode&&openClawSessionModePatch(o.mode);try{if(void 0!==o.mentions)throw new TypeError("native host per-prompt optional binding not implemented");n=prepareNativePromptInput(o.parts)}catch(e){throw new RuntimeCommandError(i?"OUTCOME_UNKNOWN":"INVALID_PARAMS","native host part unsupported",void 0,{cause:e})}const d=n.message;if(!t.host.activeRunAuthority)throw new RuntimeCommandError("EXECUTION_FAILED","native existing active-run authority unavailable");const m=()=>{const a=t.getLease(),n=t.getLineage();if(!a||a.instanceId!==e.lease.instanceId||a.handlerIdentity!==e.lease.handlerIdentity||a.runtimeEpoch!==o.runtimeLease.runtimeEpoch||a.leaseId!==o.runtimeLease.leaseId||n.journalStoreId!==o.runtimeLease.journalStoreId||n.journalGeneration!==o.runtimeLease.journalGeneration||Date.parse(a.leaseExpiresAt)<=Date.now())throw new RuntimeCommandError("INSTANCE_EPOCH_MISMATCH","native prompt attempt fenced")};m();const u=await t.channel.history({operationId:s.operationId,lease:e.lease,currentNativePrompt:r});if(m(),"found"!==u.status||u.snapshot.requestHash!==s.requestHash||u.snapshot.requestMessageId!==s.requestMessageId||!semanticEqual(u.snapshot.request.payload,s))throw new RuntimeCommandError("INVALID_PARAMS","native retained request mismatch");let l,p=await t.journal.get(s.operationId);if(m(),p&&("session.prompt"!==p.command||p.paramsHash!==s.paramsHash||p.runtimeEpoch!==o.runtimeLease.runtimeEpoch||p.messageBinding?.requestMessageId!==s.requestMessageId||p.messageBinding.requestHash!==s.requestHash))throw new RuntimeCommandError("OUTCOME_UNKNOWN","native existing journal binding mismatch");if(!t.http.getMessage)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native task snapshot unavailable");try{l=await t.http.getMessage(t.getLease(),{conversationId:o.conversationId,messageId:o.taskRequestMessageId})}catch(e){throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original task snapshot unavailable",void 0,{cause:e})}if(m(),l.messageId!==o.taskRequestMessageId||l.conversationId!==o.conversationId||"chat_message"!==l.type||l.body!==d)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original task snapshot mismatch");const c=async()=>{if(!t.http.getMessage)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native single snapshot unavailable");m();const e=await t.http.getMessage(t.getLease(),{conversationId:o.conversationId,messageId:o.replyMessageId});return m(),this.assertReply(e,r),e};if(u.snapshot.started||p&&"prepared"!==p.phase){const e=u.snapshot.runBoundary?.finishedReceipt,a=u.snapshot.final;if(!(p&&["started","effect_committed","projection_committed","failed"].includes(p.phase)&&e&&"finished"===e.state&&e.activeRunRegistrationId===o.taskId&&a))throw new RuntimeCommandError("OUTCOME_UNKNOWN","native durable MS finish audit or original result unavailable");const n=await c();if("agent_reply"!==n.type||n.state!==e.replyState||n.stopReason!==e.replyStopReason||n.updatedAt!==e.replyUpdatedAt)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original terminal does not match finished audit");const i=this.terminal(n,r);if(a.payload.outcome!==i.outcome||"final_message"!==u.snapshot.terminalSource)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original final outcome mismatch");const d=a.payload.response;if("2.0"!==d.jsonrpc||d.id!==s.request.id)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original final RPC binding mismatch");const l=runtimeCommandResultHash(i.result);if(p.resultReceipt&&p.resultReceipt.resultHash!==l||void 0!==p.result&&!semanticEqual(p.result,i.result))throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original result conflicts with local receipt");if(void 0===d.result)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original canonical result evidence unavailable");{const e=u.snapshot.effectCommitted?.payload,t=runtimeMessageHash(RUNTIME_HASH_DOMAINS.coreResult,{method:s.method,result:d.result});if("succeeded"!==i.outcome||void 0!==d.error||!semanticEqual(d.result,i.result)||!e||e.effectRecord.coreResultHash!==t||e.effectRecord.coreResultRef!==`sha256:${t}`||a.payload.effectRecordHash!==e.effectRecordHash||a.payload.serviceResultHash!==runtimeMessageHash(RUNTIME_HASH_DOMAINS.serviceResult,{method:s.method,result:d.result}))throw new RuntimeCommandError("OUTCOME_UNKNOWN","native original final result hash evidence mismatch")}const h=d.result;return m(),"started"===p.phase&&(p=await t.journal.transition({operationId:s.operationId,expectedRevision:p.revision,phase:"succeeded"===i.outcome?"effect_committed":"failed",result:h}),m()),{request:s,outcome:i.outcome,result:h,replayedFinal:a}}if(n.files.length&&!t.inputFiles)throw new RuntimeCommandError("EXECUTION_FAILED","native authorized input file resolver unavailable");if(u.snapshot.terminal||e.signal.aborted||u.snapshot.cancelRequested||await t.journal.getCancellation(s.operationId))throw new RuntimeCommandError("OPERATION_CANCELLED","native prompt cancelled before effect");const h=await t.host.resolveNativePromptSessionKey(r,m);if(m(),p=await t.journal.acceptMessageRequest({operationId:s.operationId,command:"session.prompt",paramsHash:s.paramsHash,runtimeEpoch:o.runtimeLease.runtimeEpoch,requestMessageId:s.requestMessageId,requestHash:s.requestHash}),m(),"prepared"!==p.phase)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native task already started");let v;const g=await bindExistingRuntimeChatReply({authority:{currentLease:t.getLease},http:t.http,binding:{conversationId:o.conversationId,messageId:o.replyMessageId,taskRequestMessageId:o.taskRequestMessageId,assertAttempt:m,assertPreparedClear:e=>{if(m(),!v||e.activeRunRegistrationId!==v||e.historyGeneration!==r.historyGeneration||e.runtimeEpoch!==o.runtimeLease.runtimeEpoch)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native prepared clear does not freeze this registered attempt")},mutationKey:e=>`native-reply:${s.operationId}:${o.runtimeLease.journalStoreId}:${o.runtimeLease.journalGeneration}:${e}`}});if(m(),e.signal.aborted||await t.journal.getCancellation(s.operationId))throw new RuntimeCommandError("OPERATION_CANCELLED","native prompt cancelled before start");await t.channel.append({operationId:s.operationId,lease:t.getLease(),currentNativePrompt:r,executionGrant:e.delivery.executionGrant,type:"runtime_operation_started",payload:{...runtimeMessageBase(s),executionGrantHash:s.executionGrantHash,handlerIdentity:e.lease.handlerIdentity,executionMode:"start",claimedAt:p.updatedAt}}),m(),p=await t.journal.transition({operationId:s.operationId,expectedRevision:p.revision,phase:"started"}),m();const I=()=>{m();const e=t.getLease();return{leaseId:e.leaseId,handlerIdentity:e.handlerIdentity,runtimeEpoch:e.runtimeEpoch,runtimeLeaseCredential:e.runtimeLeaseCredential}},f={operationId:s.operationId,requestMessageId:s.requestMessageId,conversationId:r.command.context.conversation.runtimeConversationUid,historyGeneration:r.historyGeneration,runtimeRunId:o.runtimeRunId},R=await t.runBoundary.start({...f,lease:I()});if(m(),"registered"!==R.status||R.historyGeneration!==r.historyGeneration||R.activeRunRegistrationId!==o.taskId)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native MS run start did not register the original task");v=R.activeRunRegistrationId;const N=new AbortController,w=()=>N.abort(e.signal.reason);if(e.signal.addEventListener("abort",w,{once:!0}),e.signal.aborted&&w(),e.setCancel(e=>N.abort(e)),await t.journal.getCancellation(s.operationId)&&N.abort(nativePromptCancellationReason),m(),N.signal.aborted){if(e.signal.removeEventListener("abort",w),N.signal.reason===nativePromptCancellationReason)throw new RuntimeCommandError("OPERATION_CANCELLED","native prompt cancelled before host invocation");throw new RuntimeCommandError("OUTCOME_UNKNOWN","native registered run stopped before host invocation")}const y=[];let E;const C=JSON.parse((await g.opened()).rawText),O=C.parts?.length??0,M=async e=>{const t=await e;return m(),this.assertReply(t,r),E=t,t},_={id:g.id,get isTerminated(){return g.isTerminated},get parts(){return y},opened:async()=>({messageId:g.id,outcome:"bound"}),appendBody:e=>g.appendBody(e),setBody:e=>g.setBody(e),addPart:e=>{y.push(e),g.addPart(e)},replacePart:(e,t)=>{y[e]=t,g.replacePart(O+e,t)},appendToolResult:(e,t,a)=>{const n={type:"tool_result",tool_use_id:e,content:t,...a?{is_error:!0}:{}};y.push(n),g.addPart(n)},finalize:e=>M(g.finalize(e)),fail:e=>M(g.fail(e)),cancel:e=>M(g.cancel(e))},b={message:d,mediaPaths:[],mediaTypes:[]};let U,A;const q=t.host.htmlDeliveryEnabled?new HtmlDeliveryGuard(!1):void 0,T=createNativeOutputFileAttempt({htmlDelivery:q,sessionKey:h,operationId:s.operationId,requestMessageId:s.requestMessageId,paramsHash:s.paramsHash,activeRunRegistrationId:v,attemptId:v,getLease:()=>(m(),t.getLease()),assertAttempt:m,signal:N.signal}),P=registerNativeOutputRunContext({runId:o.runtimeRunId,sessionKey:h,operationId:s.operationId,activeRunRegistrationId:v,attemptId:v}),S=setTimeout(()=>N.abort(nativePromptExecutionDeadlineReason),Math.max(0,Math.min(Date.parse(s.executionDeadlineAt)-3e4-Date.now(),2147483647)));S.unref?.();try{await dispatchImInboundPrompt({...t.host,htmlDelivery:q,runtimeRunId:o.runtimeRunId,onNativeAgentRunStart:e=>T.bindHostRun(e),nativeActiveRunRegistration:{runtimeConversationUid:f.conversationId,runtimeSessionKey:r.command.context.conversation.runtimeSessionKey,historyGeneration:R.historyGeneration,targetMessageId:o.taskRequestMessageId,runtimeRunId:o.runtimeRunId,activeRunRegistrationId:R.activeRunRegistrationId},assertNativeTarget:async()=>{if(await t.host.resolveNativePromptSessionKey(r,m)!==h)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native prompt target changed before host invocation")},prepareNativeModel:async e=>{m(),await t.host.prepareNativePromptModel(r,e,m),m();for(const e of n.files){if(!t.inputFiles)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native authorized input file resolver unavailable");const a=await t.inputFiles.resolve({operationId:s.operationId,requestMessageId:s.requestMessageId,paramsHash:s.paramsHash,partIndex:e.partIndex,lease:t.getLease(),signal:N.signal});m();const n=await downloadNativeInputFile({fileId:e.fileId,...a,signal:N.signal,assertAttempt:m});b.mediaPaths.push(n.path),b.mediaTypes.push(n.mimeType)}m()},onNativeRunCompletion:e=>{A=e},retainedStream:_,abortSignal:N.signal,inReplyTo:o.taskRequestMessageId,prompt:{channelId:o.conversationId,inboundMessageId:o.taskRequestMessageId,requestId:s.requestMessageId,selfPrincipalId:e.lease.instanceId,sessionKey:h,dispatchInput:b},client:{messages:{startStream(){throw new Error("native reply POST forbidden")},getEnvelope:async()=>({state:(await c()).state})},getSnapshot:()=>({connection:"connected",messages:{},conversations:{}})}})}catch(e){U=e}finally{clearTimeout(S),T.close(),P(),e.signal.removeEventListener("abort",w)}if(!A&&U)throw U;if(!A||A.runtimeRunId!==o.runtimeRunId||A.token.sessionKey!==h)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native physical host completion unavailable");let x;try{await A.completion}catch(e){x=e}if(m(),!E)throw new RuntimeCommandError("OUTCOME_UNKNOWN",void 0!==x?"native host/abort/drain did not converge":"native kernel settled without verified original reply terminal",void 0,{cause:x??U});const H=this.terminal(E,r),L=await c();g.assertTerminalSnapshot(L);const K="completed"===L.state?"completed":"cancelled"===L.state?"cancelled":"failed",j=await t.runBoundary.finish({...f,activeRunRegistrationId:v,terminalState:K,source:"runtime",lease:I()});if(m(),"finished"!==j.status&&"idempotent"!==j.status||j.activeRunRegistrationId!==v)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native MS run finish was not acknowledged");return await t.journal.transition({operationId:s.operationId,expectedRevision:p.revision,phase:"succeeded"===H.outcome?"effect_committed":"failed",result:H.result}),m(),{request:s,...H}}catch(e){throw new NativePromptExecutionFailure(s,e)}}assertReply(e,t){if(e.messageId!==t.params.replyMessageId||e.conversationId!==t.params.conversationId||e.replyTo!==t.params.taskRequestMessageId)throw new RuntimeCommandError("OUTCOME_UNKNOWN","native durable reply binding mismatch")}terminal(e,t){if(!e.stopReason||!["completed","failed","refused","cancelled"].includes(e.state))throw new RuntimeCommandError("OUTCOME_UNKNOWN","native durable terminal absent");const a="cancelled"===e.state&&"user_stop"===e.stopReason?"cancelled":"completed"===e.state&&"end_turn"===e.stopReason?"succeeded":"failed";return{outcome:a,result:{runtimeRunId:t.params.runtimeRunId,stopReason:e.stopReason,requestAborted:"cancelled"===e.state&&"user_stop"===e.stopReason,..."failed"===a?{error:e.body}:{}}}}}export const NATIVE_PROMPT_UNKNOWN_REASONS=new Set(["native MS run boundary required","native existing journal binding mismatch","native task snapshot unavailable","native original task snapshot unavailable","native original task snapshot mismatch","native single snapshot unavailable","native durable MS finish audit or original result unavailable","native original terminal does not match finished audit","native original final outcome mismatch","native original final RPC binding mismatch","native original result conflicts with local receipt","native original final result hash evidence mismatch","native original canonical result evidence unavailable","native task already started","native prepared clear does not freeze this registered attempt","native MS run start did not register the original task","native registered run stopped before host invocation","native prompt target changed before host invocation","native authorized input file resolver unavailable","native physical host completion unavailable","native host/abort/drain did not converge","native kernel settled without verified original reply terminal","native MS run finish was not acknowledged","native durable reply binding mismatch","native durable terminal absent"]);export function nativePromptUnknownReason(e){return e instanceof RuntimeCommandError&&"OUTCOME_UNKNOWN"===e.code?NATIVE_PROMPT_UNKNOWN_REASONS.has(e.message)?e.message:"unlisted":"not_unknown"}export class NativePromptExecutionFailure extends Error{request;failure;constructor(e,t){super(t instanceof Error?t.message:String(t),{cause:t}),this.request=e,this.failure=t}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const runs=new Map,tools=new Map,consumed=new Set;export function createNativeOutputFileAttempt(t){let e,
|
|
1
|
+
export class NativeOutputToolBindingError extends Error{missing;constructor(t,e){super(t),this.missing=e,this.name="NativeOutputToolBindingError"}}const runs=new Map,sessions=new Map,tools=new Map,consumed=new Set,diagnostics=new Map,contextKey=(t,e)=>t+":"+e;export function registerNativeOutputRunContext(t){const e={operationId:t.operationId,activeRunRegistrationId:t.activeRunRegistrationId,...t.responseId?{responseId:t.responseId}:{},...t.attemptId?{attemptId:t.attemptId}:{}},s=[...t.runId?[contextKey("run",t.runId)]:[],...t.sessionKey?[contextKey("session",t.sessionKey)]:[]];for(const t of s)diagnostics.set(t,e);return()=>{for(const t of s)diagnostics.get(t)===e&&diagnostics.delete(t)}}export function nativeOutputBindingDiagnostic(t){const e=(t.runId?diagnostics.get(contextKey("run",t.runId)):void 0)??(t.sessionKey?diagnostics.get(contextKey("session",t.sessionKey)):void 0),s=t.error instanceof NativeOutputToolBindingError?[...t.error.missing]:["hostCapability"];return{response_id:e?.responseId??"unknown",operation_id:e?.operationId??"unknown",attempt_id:e?.attemptId??e?.activeRunRegistrationId??"unknown",run_id:t.runId??"missing",tool_call_id:t.toolCallId??"missing",session_key:t.sessionKey??"missing",missing:s,reason:t.error instanceof Error?t.error.message:"unknown"}}export function createNativeOutputFileAttempt(t){let e,s=!0;const o={...t,assertAttempt(){if(!s)throw new Error("native output file attempt finished");t.signal.throwIfAborted(),t.assertAttempt();const e=t.getLease();if(!e.runtimeLeaseCredential||!Number.isFinite(Date.parse(e.leaseExpiresAt))||Date.parse(e.leaseExpiresAt)<=Date.now())throw new Error("native output file lease fenced")},getLease:()=>(o.assertAttempt(),t.getLease())};return{bindHostRun(s){if(o.assertAttempt(),!s||void 0!==e||runs.has(s))throw new Error("native output file Host run binding ambiguous");const n=t.sessionKey;if(n&&sessions.has(n)&&sessions.get(n)!==o)throw new Error("native output file Host session binding ambiguous");e=s,runs.set(s,o),n&&sessions.set(n,o)},close(){s=!1,e&&runs.get(e)===o&&runs.delete(e),t.sessionKey&&sessions.get(t.sessionKey)===o&&sessions.delete(t.sessionKey);for(const[t,e]of tools)e.assertAttempt===o.assertAttempt&&tools.delete(t);for(const e of consumed)e.startsWith(t.operationId+"\0")&&consumed.delete(e)}}}export function prepareNativeOutputTool(t,e,s){if(!e)throw new NativeOutputToolBindingError("native output file trusted Host tool binding missing",["toolCallId"]);let o;if(t){if(o=runs.get(t),!o)throw new NativeOutputToolBindingError("native output file trusted run missing",["hostRunBinding"])}else{if(!s)throw new NativeOutputToolBindingError("native output file Host run binding missing",["runId"]);if(o=sessions.get(s),!o)throw new NativeOutputToolBindingError("native output file trusted session run missing",["sessionBinding"])}o.assertAttempt();const n=o.operationId+"\0"+e;if(tools.has(e)||consumed.has(n))throw new Error("native output file tool binding ambiguous or consumed");tools.set(e,{...o,toolCallId:e})}export function consumeNativeOutputTool(t){const e=tools.get(t);if(tools.delete(t),!e)throw new Error("native output file tool capability missing");return e.assertAttempt(),consumed.add(e.operationId+"\0"+t),e}export function nativeHtmlDeliveryForRun(t){const e=t?runs.get(t):void 0;if(e)return e.assertAttempt(),e.htmlDelivery}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{logChatLatency}from"../chat-latency.js";export const classifyCatalogSessionKey=o=>{if(!o)return"boot";if(o.includes(":beeos-conversation:"))return"im_conversation";const e=o.split(":");return 3===e.length&&"agent"===e[0]?"acp_uuid":"other"};const TOOL_HINT_KEYS=new Set(["description","parameters","schema","inputSchema","function"]),NESTED_INVENTORY_KEYS=["tools","groups","entries","items","catalog","result","payload","inventory","profiles"],toolRecordName=o=>"string"==typeof o.name&&o.name.length>0?o.name:"string"==typeof o.id&&o.id.length>0?o.id:"",looksLikeTool=o=>{if(!o||"object"!=typeof o||Array.isArray(o))return!1;const e=o;if(!toolRecordName(e))return!1;for(const o of TOOL_HINT_KEYS)if(void 0!==e[o])return!0;return!1},collectToolRecords=(o,e,t,s)=>{if(null==o||s>6)return;if("object"!=typeof o)return;if(t.has(o))return;if(t.add(o),looksLikeTool(o)){const t=o;if(!Array.isArray(t.tools)&&!Array.isArray(t.groups))return void e.push(o)}if(Array.isArray(o)){for(const
|
|
1
|
+
import{logChatLatency}from"../chat-latency.js";export const classifyCatalogSessionKey=o=>{if(!o)return"boot";if(o.includes(":beeos-conversation:"))return"im_conversation";const e=o.split(":");return 3===e.length&&"agent"===e[0]?"acp_uuid":"other"};const TOOL_HINT_KEYS=new Set(["description","parameters","schema","inputSchema","function"]),NESTED_INVENTORY_KEYS=["tools","groups","entries","items","catalog","result","payload","inventory","profiles"],toolRecordName=o=>"string"==typeof o.name&&o.name.length>0?o.name:"string"==typeof o.id&&o.id.length>0?o.id:"",looksLikeTool=o=>{if(!o||"object"!=typeof o||Array.isArray(o))return!1;const e=o;if(!toolRecordName(e))return!1;for(const o of TOOL_HINT_KEYS)if(void 0!==e[o])return!0;return!1},collectToolRecords=(o,e,t,s)=>{if(null==o||s>6)return;if("object"!=typeof o)return;if(t.has(o))return;if(t.add(o),looksLikeTool(o)){const t=o;if(!Array.isArray(t.tools)&&!Array.isArray(t.groups))return void e.push(o)}if(Array.isArray(o)){for(const a of o)collectToolRecords(a,e,t,s+1);return}const a=o;for(const o of NESTED_INVENTORY_KEYS)o in a&&collectToolRecords(a[o],e,t,s+1);if(!(e.length>0))for(const o of Object.values(a))collectToolRecords(o,e,t,s+1)};export const extractToolRecords=o=>{const e=[];return collectToolRecords(o,e,new Set,0),e};export const summarizeCatalogPayloadKeys=o=>null==o?"null":Array.isArray(o)?`array:${o.length}`:"object"!=typeof o?typeof o:Object.keys(o).slice(0,16).join(",");export const summarizeCatalogTools=(o,e=8)=>{const t=extractToolRecords(o).map(o=>{const e=JSON.stringify(o)??"";return{name:o&&"object"==typeof o&&toolRecordName(o)||"?",bytes:e.length}});return t.sort((o,e)=>e.bytes-o.bytes),{toolCount:t.length,catalogBytes:t.reduce((o,e)=>o+e.bytes,0),topTools:t.slice(0,e).map(o=>`${o.name}:${o.bytes}`).join(",")}};const resolveMode=(o,e)=>o||(e?"both":"catalog");export async function prepareOpenClawToolCatalog(o){const e=Date.now(),t=resolveMode(o.mode,o.sessionKey),s=o.keyKind??classifyCatalogSessionKey(o.sessionKey),a=[];try{let r,n;"catalog"!==t&&"both"!==t||(r=await o.request("tools.catalog",{agentId:o.agentId}),a.push("catalog")),"effective"!==t&&"both"!==t||!o.sessionKey||(n=await o.request("tools.effective",{agentId:o.agentId,sessionKey:o.sessionKey}),a.push("effective"));const l=r??n,i=void 0===l?void 0:summarizeCatalogTools(l);o.logger?.info?.(`[runtime-core] prepared tool catalog agent=${o.agentId}`+(o.sessionKey?` session=${o.sessionKey}`:"")+` key_kind=${s} mode=${t} elapsed_ms=`+(Date.now()-e)),i&&0===i.toolCount&&void 0!==l&&o.logger?.warn?.(`[runtime-core] tool catalog is EMPTY agent=${o.agentId}`+(o.sessionKey?` session=${o.sessionKey}`:"")+` key_kind=${s} mode=${t}`+` payload_keys=${summarizeCatalogPayloadKeys(l)}; the model will see only tool_search/tool_call/tool_describe and every real tool call will fail with "Unknown tool id" — check the agent tool policy (openclaw.json tools.allow must not be an empty array)`),o.logger&&logChatLatency(o.logger,"claw.catalog.prepare",s,e,{key_kind:s,mode:t,methods:a.join(","),...i?{tool_count:i.toolCount,catalog_bytes:i.catalogBytes,top_tools:i.topTools}:{},...i&&0===i.toolCount&&void 0!==l?{payload_keys:summarizeCatalogPayloadKeys(l)}:{}})}catch(e){o.logger?.warn?.(`[runtime-core] tool catalog prepare failed agent=${o.agentId}: ${e instanceof Error?e.message:String(e)}`)}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash,timingSafeEqual}from"node:crypto";import{readFile}from"node:fs/promises";import{isDeepStrictEqual}from"node:util";import{centralNativeRuntime}from"./central-native-runtime.js";import{resolveSyncAgentName}from"../agent-sync.js";import{injectOpenClawCredentials}from"./sandbox-native-credentials.js";function unboundActivation(e){const{execution_binding_version:t,...i}=e;return{...i,request_hash:""}}let executionResolver;export function installSandboxNativeExecutionResolver(e){if(executionResolver)throw new Error("native original execution authority is already installed");executionResolver=e}export function createSandboxNativeTargetLookup(e,t){return async({localAgentId:i,activation:n})=>{const r=e(),a=r?.authorityLease,o=t();if(!r||!a?.runtimeLeaseCredential||Date.parse(a.leaseExpiresAt)<=Date.now()||a.instanceId!==n.sandbox_id||!o?.isConnected)throw new Error("current native target projection authority/catalog transport is unavailable");const s=await o.request("agents.list",{}),c=s.agents?.filter(e=>e.id===i)??[];if(1!==c.length)throw new Error("actual native target catalog entry is missing or ambiguous");if(resolveSyncAgentName(c[0])!==i)throw new Error("actual native catalog key differs from the current identity projection key");const l=await r.identities.resolveOrCreate(i),d=r.authorityLease;if(e()!==r||!d||Date.parse(d.leaseExpiresAt)<=Date.now()||d.instanceId!==a.instanceId||d.leaseId!==a.leaseId||d.runtimeEpoch!==a.runtimeEpoch||d.handlerIdentity!==a.handlerIdentity)throw new Error("native target projection authority changed during observation");return{runtimeAgentUid:l,runtimeLocalKey:i,runtimeEpoch:d.runtimeEpoch,leaseIdentity:JSON.stringify({instanceId:d.instanceId,leaseId:d.leaseId,runtimeEpoch:d.runtimeEpoch,handlerIdentity:d.handlerIdentity})}}}const object=e=>null!==e&&"object"==typeof e&&!Array.isArray(e),sha256=e=>createHash("sha256").update(e).digest("hex"),ref=e=>`native:${sha256(JSON.stringify(e))}`,nonempty=e=>"string"==typeof e&&e.length>0,secretRef=e=>object(e)&&3===Object.keys(e).length&&("env"===e.source||"file"===e.source||"exec"===e.source)&&nonempty(e.provider)&&nonempty(e.id);export function containsApplied(e,t){return secretRef(t)?isDeepStrictEqual(e,t)||nonempty(e):Array.isArray(t)?Array.isArray(e)&&e.length===t.length&&t.every((t,i)=>containsApplied(e[i],t)):object(t)?object(e)&&Object.entries(t).every(([t,i])=>containsApplied(e[t],i)):isDeepStrictEqual(e,t)}export function sessionConfigObservation(e){const{activation:t,allocation:i,native:n,execution:r,receipt:a}=e,o=n.config_components;if(!(object(o)&&object(r.loadAuthority)&&Number.isSafeInteger(i.epoch)&&nonempty(t.resolved_request_hash)&&nonempty(t.central_read_watermark)))throw new Error("actual SessionConfigReceipt inputs (components/authority/allocation/selection) are unavailable");const s=structuredClone(r.loadAuthority),c=i.id,l=r.sessionKey,d={session_load_receipt:e.sessionLoadReceipt,prepared:a.receipt_id},u=ref({config:a.receipt_id,session:l,authority:s}),p={contractVersion:"1",revision:t.config_revision,manifestRef:{id:t.config_manifest.manifest_id,digest:t.config_sha256},appliedAt:a.prepared_at,sessionId:t.session_id,applyAt:"session_start",components:structuredClone(o),binding:{bindingId:t.binding_id,agentId:t.agent_id,harnessId:t.harness,sandboxId:t.sandbox_id,allocationId:i.id,allocationEpoch:i.epoch},applicationState:"applied",authority:s,hostInstanceId:c,nativeSessionId:l,receiptId:u,mutationScope:"session_private"};return{resolvedRequestHash:t.resolved_request_hash,readWatermark:t.central_read_watermark,admission:{attemptId:r.binding.attemptId,hostInstanceId:c,executionBindingVersion:t.execution_binding_version,nativeSessionId:l,nativeIncarnation:`${process.pid}@${i.boot_id}`,requestHash:t.request_hash},sessionConfigReceipt:{receiptId:u,commandId:t.command_id,authority:s,hostInstanceId:c,nativeSessionId:l,configuration:p,evidenceRef:{id:e.sessionLoadReceipt,digest:sha256(JSON.stringify(d))},preparedConfigReceiptId:a.receipt_id},loadedFacts:{loaded_model_id:null,actual_provider_id:null,actual_model_id:null,endpoint_ref:null,api_mode:null,reasoning:null,fallback_used:null,skills_digest:null,tool_schema_digest:null,credential_activation_revision:a.credential_activation_revision,components:[],memory_observation:"not_read",memory_read_watermark:null}}}export class SandboxNativeActivation{config;activeWriters;activationFile;targetLookup;reloadSecrets;logger;prepared;materialized;boundNativeRequestHash;targetAuthority;persona;credentialReceipt;reloadedCredentialsReceipt;control=Promise.resolve();serialize(e){const t=this.control.then(e,e);return this.control=t.catch(()=>{}),t}constructor(e,t,i,n,r,a){this.config=e,this.activeWriters=t,this.activationFile=i,this.targetLookup=n,this.reloadSecrets=r,this.logger=a}reloadSecretsAfterInjection(e){this.reloadSecrets&&this.reloadedCredentialsReceipt!==e&&(this.reloadedCredentialsReceipt=e,Promise.resolve().then(()=>this.reloadSecrets()).catch(e=>this.logger?.warn?.(`[beeos-claw] secrets reload after credential delivery failed: ${e instanceof Error?e.message:String(e)}`)))}prepare(e){return this.serialize(()=>this.apply(e))}target(e){return this.serialize(()=>this.apply(e,!0))}async assertEnvelope(e,t=!1){const i=JSON.parse(await readFile(this.activationFile,"utf8")),{activation:n,allocation:r,config_manifest:a}=e,o=!t&&"execution"===n.kind&&"execution"===i.activation?.kind&&""===i.activation.request_hash&&nonempty(n.request_hash)&&isDeepStrictEqual(unboundActivation(i.activation),unboundActivation(n));if(!isDeepStrictEqual(i.activation,n)&&!o||!isDeepStrictEqual(i.allocation,r)||!isDeepStrictEqual(i.config_manifest,a))throw new Error("native preparation does not match the current immutable activation");if(!nonempty(n.preparation_id)||!nonempty(r.id)||!nonempty(r.boot_id)||!Number.isFinite(Date.parse(n.deadline_at))||Date.parse(n.deadline_at)<=Date.now())throw new Error("native preparation authority/deadline is unavailable");if(!isDeepStrictEqual(JSON.parse(await readFile(e.config_manifest_path,"utf8")),a))throw new Error("native configuration bytes differ from the verified manifest");if("credential_activation"in a)throw new Error("private credential inputs must use transient authenticated delivery");if("central_chat"in a||"centralChat"in a)throw new Error("immutable native configuration must not contain per-execution chat authority")}credentials(e){return this.serialize(async()=>{if(await this.assertEnvelope(e),0!==this.activeWriters())throw new Error("native writers must drain before credential injection");if(this.materialized&&!this.credentialReceipt)throw new Error("credentials must be injected before native provider construction");const t=injectOpenClawCredentials({delivery:e.credential_delivery,activation:e.activation,allocation:e.allocation,previous:this.credentialReceipt,mcpCredentialSlots:e.config_manifest.mcp_credential_slots});return this.credentialReceipt=t,this.reloadSecretsAfterInjection(t.receipt_id),structuredClone(t)})}async apply(e,t=!1){await this.assertEnvelope(e,t);const{activation:i,allocation:n,config_manifest:r}=e;if(!this.credentialReceipt)throw new Error("actual native credential injection receipt is required, including empty credentials");if("execution"===i.kind){if(!nonempty(i.public_request_hash))throw new Error("original public request hash is required");if(t&&(""!==i.request_hash||void 0!==this.boundNativeRequestHash))throw new Error("target observation requires the original unbound native request hash");const e=i.execution_binding_version;if(t?void 0!==e&&0!==e:!(Number.isSafeInteger(e)&&e>=1))throw new Error("State execution binding version must be unbound at target and positive at Session load");if(!t&&(!nonempty(i.request_hash)||void 0!==this.boundNativeRequestHash&&this.boundNativeRequestHash!==i.request_hash))throw new Error("native canonical request hash is missing or changed")}const{execution_grant:a,credential_delivery:o,...s}=e,c={...s,activation:unboundActivation(i)};if(this.materialized&&!isDeepStrictEqual(this.materialized,c))throw new Error("a different native materialization requires a drained process restart");let l;if("execution"===i.kind&&!t){if(!nonempty(e.execution_grant)||!executionResolver)throw new Error("authenticated original canonical execution request producer is unavailable");if(l=await executionResolver(e),!this.targetAuthority||!this.targetLookup)throw new Error("the original work has no observed native target");const t=await this.targetLookup({localAgentId:r.local_agent_id,activation:i,allocation:n});if(!isDeepStrictEqual(t,this.targetAuthority))throw new Error("native target/current runtime lease changed before session load");if(l.nativeRequestHash!==i.request_hash||l.binding.sessionId!==i.session_id||l.binding.responseId!==i.response_id||l.binding.operationId!==i.operation_id||l.runtimeAgentUid!==this.targetAuthority.runtimeAgentUid||!l.sessionKey.startsWith(`agent:${r.local_agent_id}:`))throw new Error("original execution request differs from the current native activation");this.assertSelection(l.params,e)}if(!t&&this.prepared&&isDeepStrictEqual(this.prepared.envelope,s)){if(!isDeepStrictEqual(this.prepared.execution,l))throw new Error("original execution binding changed");return l&&await centralNativeRuntime().prepareReadOnly(l.sessionKey,l.binding),structuredClone(this.prepared.receipt)}if(0!==this.activeWriters())throw new Error("native writers must drain before applying configuration");if(!["configuration","credential_restart","execution"].includes(i.kind))throw new Error("unsupported native activation kind");if(1!==r.schema_version||!nonempty(r.local_agent_id)||!object(r.openclaw_config))throw new Error("resolved OpenClaw native configuration v1 is required");const d=r.mcp_credential_slots;if(void 0!==d&&(!Array.isArray(d)||d.some(e=>"string"!=typeof e||!/^[a-z][a-z0-9_]{0,63}$/.test(e)||"openai_api_key"===e)||new Set(d).size!==d.length))throw new Error("resolved MCP credential slots are invalid");const u=new Set(["agents","models","tools","skills","mcp"]);if(Object.keys(r.openclaw_config).some(e=>!u.has(e)))throw new Error("native config may only apply agent/model/tool/Skill/MCP settings");const p=r.openclaw_config.agents;if(!object(p)||!object(p.entries)||!object(p.entries[r.local_agent_id]))throw new Error("local_agent_id is not present in the resolved native agent catalog");if(this.prepared&&!isDeepStrictEqual(this.prepared.envelope,s))throw new Error("a different native activation requires a drained process restart");if(r.persona&&(!nonempty(r.persona.persona_id)||!nonempty(r.persona.revision)||!nonempty(r.persona.source_receipt_ref)||sha256(r.persona.content)!==r.persona.sha256))throw new Error("resolved Persona source/revision/content digest is invalid");if("execution"!==i.kind&&(i.session_id||i.response_id||i.execution_binding_version))throw new Error("non-execution preparation must not manufacture a Session or Response");if(t&&"execution"!==i.kind)throw new Error("target observation requires the original execution preparation");this.materialized||await this.config.mutateConfigFile({afterWrite:{mode:"auto"},mutate:e=>{for(const[t,i]of Object.entries(r.openclaw_config))e[t]=structuredClone(i)}});const h=this.config.current();if(!containsApplied(h,r.openclaw_config))throw new Error("native config has not been applied by OpenClaw");const f=h.agents;if(!object(f)||!object(f.entries)||!object(f.entries[r.local_agent_id]))throw new Error("local_agent_id is not present in the actual resolved native agent catalog");if(this.persona=r.persona?{localAgentId:r.local_agent_id,content:r.persona.content}:void 0,this.materialized=structuredClone(c),t){if(!this.targetLookup)throw new Error("actual native target identity producer is unavailable");const e=await this.targetLookup({localAgentId:r.local_agent_id,activation:i,allocation:n});if(!nonempty(e.runtimeAgentUid)||e.runtimeLocalKey!==r.local_agent_id||!/^[1-9][0-9]*$/.test(e.runtimeEpoch)||!nonempty(e.leaseIdentity))throw new Error("actual native catalog/identity projection does not match the applied target");return this.targetAuthority=structuredClone(e),{runtime_agent_uid:e.runtimeAgentUid,runtime_local_key:e.runtimeLocalKey,harness:"openclaw",config_digest:i.config_sha256,runtime_epoch:e.runtimeEpoch}}let g="";if("execution"===i.kind){if(!l)throw new Error("original central native execution authority is unavailable");this.boundNativeRequestHash=l.nativeRequestHash,await centralNativeRuntime().prepareReadOnly(l.sessionKey,l.binding),g=ref({session_key:l.sessionKey,binding:l.binding,source:centralNativeRuntime().source(l.sessionKey)})}const _=(new Date).toISOString(),v={preparation_id:i.preparation_id,kind:i.kind,binding_id:i.binding_id,config_revision:i.config_revision,config_sha256:i.config_sha256,target_intent_digest:i.target_intent_digest,authority_ref:i.authority_ref,config_manifest:i.config_manifest,credential_set_id:i.credential_set_id,credential_set_version:i.credential_set_version,credential_activation_revision:this.credentialReceipt.config.revision,receipt_scope:"configuration"===i.kind?"current_config":"activation",credential_activation_receipt_ref:this.credentialReceipt.receipt_id,host_instance_id:n.id,runtime_lineage_ref:n.boot_id,session_load_receipt_ref:g,prepared_at:_,..."execution"===i.kind?{execution_binding_version:i.execution_binding_version}:{},receipt_id:ref({activation:i,allocation:n,config:r.openclaw_config,persona:r.persona?.sha256??null,credential_receipt:this.credentialReceipt.receipt_id,sessionLoadReceipt:g})};return l&¢ralNativeRuntime().bindExecutionObservation(l.binding,sessionConfigObservation({activation:i,allocation:n,native:r,execution:l,receipt:v,sessionLoadReceipt:g})),this.prepared={envelope:structuredClone(s),execution:l&&structuredClone(l),receipt:v},v}execution(e,t){const i=this.prepared,n=i?.envelope.config_manifest,r=i?.execution;if(!(i&&"execution"===i.envelope.activation.kind&&n&&r&&isDeepStrictEqual(r.binding,t)&&containsApplied(this.config.current(),n.openclaw_config)))throw new Error("central execution does not match actual applied native configuration/Persona/binding");if(this.assertSelection(e,i.envelope),!isDeepStrictEqual(e,r.params))throw new Error("central execution differs from the prepared original request");return{sessionKey:r.sessionKey,localAgentId:n.local_agent_id,systemPrompt:n.persona?.content??""}}assertSelection(e,t){const i=e.centralChat,n=t.config_manifest.persona;if(!object(i)||!this.credentialReceipt||!isDeepStrictEqual(i.config_pin,this.credentialReceipt.config)||!isDeepStrictEqual(i.persona_ref,n?{persona_id:n.persona_id,revision:n.revision}:null)||Object.hasOwn(i,"effective_config")||Object.hasOwn(i,"persona"))throw new Error("central selection differs from the actual prepared native configuration/Persona source")}promptContext(e){if(this.persona&&object(e)&&e.agentId===this.persona.localAgentId)return{appendSystemContext:this.persona.content}}drain(e){return this.serialize(()=>this.quiesce(e))}async quiesce(e){if(!(this.prepared&&isDeepStrictEqual(e.activation,this.prepared.envelope.activation)&&isDeepStrictEqual(e.allocation,this.prepared.envelope.allocation)&&nonempty(e.command_id)))throw new Error("native drain does not match the actual prepared activation");const t=await centralNativeRuntime().drain();if(1!==t.sourceWatermarks.length)throw new Error("Runtime drain contract requires one actual central session watermark; configuration-only quiescence is not representable");const i=t.sourceWatermarks[0].watermark,n=ref({command_id:e.command_id,prepared:this.prepared.receipt.receipt_id,allocation:e.allocation,sources:t.sourceWatermarks});return{receipt_id:ref({quiesce:n,watermark:i}),central_committed_watermark:i,pending_writes:0,all_writers_quiesced:!0,quiesce_ref:n}}}let controller;async function body(e){const t=[];let i=0;for await(const n of e){const e=Buffer.isBuffer(n)?n:Buffer.from(n);if(i+=e.length,i>4194304)throw new Error("native activation payload exceeds 4 MiB");t.push(e)}try{return JSON.parse(Buffer.concat(t).toString("utf8"))}catch{throw new Error("native control request is not valid JSON")}}export function registerSandboxNativeActivation(e,t,i,n){const r=process.env.BEEOS_SANDBOX_ACTIVATION_FILE;if(!r)return;const a=e.runtime?.config;if(!a?.current||!a.mutateConfigFile)throw new Error("pinned OpenClaw native config APIs are required for Sandbox activation");controller??=new SandboxNativeActivation(a,t,r,i,n,e.logger);for(const t of["credentials","target","prepare","drain"])e.registerHttpRoute({path:`/beeos/sandbox-v1/${t}`,auth:"plugin",async handler(e,i){const n=e,r=i,a=(e,t)=>{r.writeHead(e,{"content-type":"application/json","cache-control":"no-store"}),r.end(JSON.stringify(t))};if("POST"!==n.method)return void a(405,{error:{code:"method_not_allowed"}});const o=n.socket.remoteAddress;if(["127.0.0.1","::1","::ffff:127.0.0.1"].includes(o??""))try{const e=process.env.BEEOS_SANDBOX_NATIVE_TOKEN_FILE;if(!e)throw new Error("native control token file is unavailable");const i=(await readFile(e,"utf8")).trim(),r=Buffer.from(`Bearer ${i}`),o=Buffer.from(n.headers.authorization??"");if(!i||o.length!==r.length||!timingSafeEqual(o,r))return void a(401,{error:{code:"native_control_unauthorized"}});const s=await body(n);if(!object(s))throw new Error("native control request must be an object");a(200,"credentials"===t?await controller.credentials(s):"target"===t?await controller.target(s):"prepare"===t?await controller.prepare(s):await controller.drain(s))}catch(e){a(503,{error:{code:"native_preparation_unavailable",message:e instanceof Error?e.message:String(e)}})}else a(403,{error:{code:"native_loopback_required"}})}})}export function preparedSandboxNativeExecution(e,t){if(!controller)throw new Error("actual native Sandbox activation is unavailable");return controller.execution(e,t)}
|
|
1
|
+
import{createHash,timingSafeEqual}from"node:crypto";import{readFile}from"node:fs/promises";import{isDeepStrictEqual}from"node:util";import{centralNativeRuntime}from"./central-native-runtime.js";import{resolveSyncAgentName}from"../agent-sync.js";import{injectOpenClawCredentials}from"./sandbox-native-credentials.js";function unboundActivation(e){const{execution_binding_version:t,...i}=e;return{...i,request_hash:""}}let executionResolver;export function installSandboxNativeExecutionResolver(e){if(executionResolver)throw new Error("native original execution authority is already installed");executionResolver=e}const TARGET_LOOKUP_INTERVAL_MS=250,TARGET_LOOKUP_STARTUP_TIMEOUT_MS=6e4,TARGET_LOOKUP_RUNTIME_TIMEOUT_MS=1e4;export function createSandboxNativeTargetLookup(e,t,i={}){const n=i.intervalMs??250,r={startup:i.startupTimeoutMs??6e4,runtime:i.runtimeTimeoutMs??1e4},a=i.now??Date.now,o=i.sleep??(e=>new Promise(t=>setTimeout(t,e)));let s=!1;return async({localAgentId:c,activation:l})=>{const d=s?"runtime":"startup",u=a();let p=0,h=[],f="";for(;;){p+=1;const _=e(),g=_?.authorityLease,v=t(),m=[];if(_||m.push("authority_missing"),_&&!g?.runtimeLeaseCredential&&m.push("lease_credential_missing"),g&&Date.parse(g.leaseExpiresAt)<=a()&&m.push("lease_expired"),g&&g.instanceId!==l.sandbox_id&&m.push("instance_mismatch"),v?.isConnected||m.push("gateway_disconnected"),_&&g&&v&&0===m.length){const t=await v.request("agents.list",{}),i=t.agents?.filter(e=>e.id===c)??[];if(1!==i.length)throw new Error("actual native target catalog entry is missing or ambiguous");if(resolveSyncAgentName(i[0])!==c)throw new Error("actual native catalog key differs from the current identity projection key");const n=await _.identities.resolveOrCreate(c),r=_.authorityLease;if(e()!==_||!r||Date.parse(r.leaseExpiresAt)<=a()||r.instanceId!==g.instanceId||r.leaseId!==g.leaseId||r.runtimeEpoch!==g.runtimeEpoch||r.handlerIdentity!==g.handlerIdentity)throw new Error("native target projection authority changed during observation");return s=!0,{runtimeAgentUid:n,runtimeLocalKey:c,runtimeEpoch:r.runtimeEpoch,leaseIdentity:JSON.stringify({instanceId:r.instanceId,leaseId:r.leaseId,runtimeEpoch:r.runtimeEpoch,handlerIdentity:r.handlerIdentity})}}h=m;const w=a()-u,y=m.join(",");if(y!==f&&(f=y,i.logger?.warn?.(`[beeos-claw] native target lookup pending: phase=${d} reason=${m[m.length-1]} unmet=${y} attempt=${p} elapsed_ms=${w} sandbox_id=${l.sandbox_id} instance_id=${g?.instanceId??"none"} lease_expires_at=${g?.leaseExpiresAt??"none"} lease_credential=${g?.runtimeLeaseCredential?"present":"missing"} gateway_connected=${!0===v?.isConnected}`)),w>=r[d])throw new Error(`current native target projection authority/catalog transport is unavailable: native target lookup timed out after ${r[d]}ms (phase=${d}, last_reason=${h[h.length-1]}, unmet=${h.join(",")}, attempts=${p}, sandbox_id=${l.sandbox_id})`);await o(Math.min(n,r[d]-w))}}}const object=e=>null!==e&&"object"==typeof e&&!Array.isArray(e),sha256=e=>createHash("sha256").update(e).digest("hex"),ref=e=>`native:${sha256(JSON.stringify(e))}`,nonempty=e=>"string"==typeof e&&e.length>0,secretRef=e=>object(e)&&3===Object.keys(e).length&&("env"===e.source||"file"===e.source||"exec"===e.source)&&nonempty(e.provider)&&nonempty(e.id);export function containsApplied(e,t){return secretRef(t)?isDeepStrictEqual(e,t)||nonempty(e):Array.isArray(t)?Array.isArray(e)&&e.length===t.length&&t.every((t,i)=>containsApplied(e[i],t)):object(t)?object(e)&&Object.entries(t).every(([t,i])=>containsApplied(e[t],i)):isDeepStrictEqual(e,t)}export function sessionConfigObservation(e){const{activation:t,allocation:i,native:n,execution:r,receipt:a}=e,o=n.config_components;if(!(object(o)&&object(r.loadAuthority)&&Number.isSafeInteger(i.epoch)&&nonempty(t.resolved_request_hash)&&nonempty(t.central_read_watermark)))throw new Error("actual SessionConfigReceipt inputs (components/authority/allocation/selection) are unavailable");const s=structuredClone(r.loadAuthority),c=i.id,l=r.sessionKey,d={session_load_receipt:e.sessionLoadReceipt,prepared:a.receipt_id},u=ref({config:a.receipt_id,session:l,authority:s}),p={contractVersion:"1",revision:t.config_revision,manifestRef:{id:t.config_manifest.manifest_id,digest:t.config_sha256},appliedAt:a.prepared_at,sessionId:t.session_id,applyAt:"session_start",components:structuredClone(o),binding:{bindingId:t.binding_id,agentId:t.agent_id,harnessId:t.harness,sandboxId:t.sandbox_id,allocationId:i.id,allocationEpoch:i.epoch},applicationState:"applied",authority:s,hostInstanceId:c,nativeSessionId:l,receiptId:u,mutationScope:"session_private"};return{resolvedRequestHash:t.resolved_request_hash,readWatermark:t.central_read_watermark,admission:{attemptId:r.binding.attemptId,hostInstanceId:c,executionBindingVersion:t.execution_binding_version,nativeSessionId:l,nativeIncarnation:`${process.pid}@${i.boot_id}`,requestHash:t.request_hash},sessionConfigReceipt:{receiptId:u,commandId:t.command_id,authority:s,hostInstanceId:c,nativeSessionId:l,configuration:p,evidenceRef:{id:e.sessionLoadReceipt,digest:sha256(JSON.stringify(d))},preparedConfigReceiptId:a.receipt_id},loadedFacts:{loaded_model_id:null,actual_provider_id:null,actual_model_id:null,endpoint_ref:null,api_mode:null,reasoning:null,fallback_used:null,skills_digest:null,tool_schema_digest:null,credential_activation_revision:a.credential_activation_revision,components:[],memory_observation:"not_read",memory_read_watermark:null}}}export class SandboxNativeActivation{config;activeWriters;activationFile;targetLookup;reloadSecrets;logger;prepared;materialized;boundNativeRequestHash;targetAuthority;persona;credentialReceipt;reloadedCredentialsReceipt;control=Promise.resolve();serialize(e){const t=this.control.then(e,e);return this.control=t.catch(()=>{}),t}constructor(e,t,i,n,r,a){this.config=e,this.activeWriters=t,this.activationFile=i,this.targetLookup=n,this.reloadSecrets=r,this.logger=a}reloadSecretsAfterInjection(e){this.reloadSecrets&&this.reloadedCredentialsReceipt!==e&&(this.reloadedCredentialsReceipt=e,Promise.resolve().then(()=>this.reloadSecrets()).catch(t=>{this.reloadedCredentialsReceipt===e&&(this.reloadedCredentialsReceipt=void 0),this.logger?.warn?.(`[beeos-claw] secrets reload after credential delivery failed: ${t instanceof Error?t.message:String(t)}`)}))}prepare(e){return this.serialize(()=>this.apply(e))}target(e){return this.serialize(()=>this.apply(e,!0))}async assertEnvelope(e,t=!1){const i=JSON.parse(await readFile(this.activationFile,"utf8")),{activation:n,allocation:r,config_manifest:a}=e,o=!t&&"execution"===n.kind&&"execution"===i.activation?.kind&&""===i.activation.request_hash&&nonempty(n.request_hash)&&isDeepStrictEqual(unboundActivation(i.activation),unboundActivation(n));if(!isDeepStrictEqual(i.activation,n)&&!o||!isDeepStrictEqual(i.allocation,r)||!isDeepStrictEqual(i.config_manifest,a))throw new Error("native preparation does not match the current immutable activation");if(!nonempty(n.preparation_id)||!nonempty(r.id)||!nonempty(r.boot_id)||!Number.isFinite(Date.parse(n.deadline_at))||Date.parse(n.deadline_at)<=Date.now())throw new Error("native preparation authority/deadline is unavailable");if(!isDeepStrictEqual(JSON.parse(await readFile(e.config_manifest_path,"utf8")),a))throw new Error("native configuration bytes differ from the verified manifest");if("credential_activation"in a)throw new Error("private credential inputs must use transient authenticated delivery");if("central_chat"in a||"centralChat"in a)throw new Error("immutable native configuration must not contain per-execution chat authority")}credentials(e){return this.serialize(async()=>{if(await this.assertEnvelope(e),0!==this.activeWriters())throw new Error("native writers must drain before credential injection");if(this.materialized&&!this.credentialReceipt)throw new Error("credentials must be injected before native provider construction");const t=injectOpenClawCredentials({delivery:e.credential_delivery,activation:e.activation,allocation:e.allocation,previous:this.credentialReceipt,mcpCredentialSlots:e.config_manifest.mcp_credential_slots});return this.credentialReceipt=t,this.reloadSecretsAfterInjection(t.receipt_id),structuredClone(t)})}async apply(e,t=!1){await this.assertEnvelope(e,t);const{activation:i,allocation:n,config_manifest:r}=e;if(!this.credentialReceipt)throw new Error("actual native credential injection receipt is required, including empty credentials");if("execution"===i.kind){if(!nonempty(i.public_request_hash))throw new Error("original public request hash is required");if(t&&(""!==i.request_hash||void 0!==this.boundNativeRequestHash))throw new Error("target observation requires the original unbound native request hash");const e=i.execution_binding_version;if(t?void 0!==e&&0!==e:!(Number.isSafeInteger(e)&&e>=1))throw new Error("State execution binding version must be unbound at target and positive at Session load");if(!t&&(!nonempty(i.request_hash)||void 0!==this.boundNativeRequestHash&&this.boundNativeRequestHash!==i.request_hash))throw new Error("native canonical request hash is missing or changed")}const{execution_grant:a,credential_delivery:o,...s}=e,c={...s,activation:unboundActivation(i)};if(this.materialized&&!isDeepStrictEqual(this.materialized,c))throw new Error("a different native materialization requires a drained process restart");let l;if("execution"===i.kind&&!t){if(!nonempty(e.execution_grant)||!executionResolver)throw new Error("authenticated original canonical execution request producer is unavailable");if(l=await executionResolver(e),!this.targetAuthority||!this.targetLookup)throw new Error("the original work has no observed native target");const t=await this.targetLookup({localAgentId:r.local_agent_id,activation:i,allocation:n});if(!isDeepStrictEqual(t,this.targetAuthority))throw new Error("native target/current runtime lease changed before session load");if(l.nativeRequestHash!==i.request_hash||l.binding.sessionId!==i.session_id||l.binding.responseId!==i.response_id||l.binding.operationId!==i.operation_id||l.runtimeAgentUid!==this.targetAuthority.runtimeAgentUid||!l.sessionKey.startsWith(`agent:${r.local_agent_id}:`))throw new Error("original execution request differs from the current native activation");this.assertSelection(l.params,e)}if(!t&&this.prepared&&isDeepStrictEqual(this.prepared.envelope,s)){if(!isDeepStrictEqual(this.prepared.execution,l))throw new Error("original execution binding changed");return l&&await centralNativeRuntime().prepareReadOnly(l.sessionKey,l.binding),structuredClone(this.prepared.receipt)}if(0!==this.activeWriters())throw new Error("native writers must drain before applying configuration");if(!["configuration","credential_restart","execution"].includes(i.kind))throw new Error("unsupported native activation kind");if(1!==r.schema_version||!nonempty(r.local_agent_id)||!object(r.openclaw_config))throw new Error("resolved OpenClaw native configuration v1 is required");const d=r.mcp_credential_slots;if(void 0!==d&&(!Array.isArray(d)||d.some(e=>"string"!=typeof e||!/^[a-z][a-z0-9_]{0,63}$/.test(e)||"openai_api_key"===e)||new Set(d).size!==d.length))throw new Error("resolved MCP credential slots are invalid");const u=new Set(["agents","models","tools","skills","mcp"]);if(Object.keys(r.openclaw_config).some(e=>!u.has(e)))throw new Error("native config may only apply agent/model/tool/Skill/MCP settings");const p=r.openclaw_config.agents;if(!object(p)||!object(p.entries)||!object(p.entries[r.local_agent_id]))throw new Error("local_agent_id is not present in the resolved native agent catalog");if(this.prepared&&!isDeepStrictEqual(this.prepared.envelope,s))throw new Error("a different native activation requires a drained process restart");if(r.persona&&(!nonempty(r.persona.persona_id)||!nonempty(r.persona.revision)||!nonempty(r.persona.source_receipt_ref)||sha256(r.persona.content)!==r.persona.sha256))throw new Error("resolved Persona source/revision/content digest is invalid");if("execution"!==i.kind&&(i.session_id||i.response_id||i.execution_binding_version))throw new Error("non-execution preparation must not manufacture a Session or Response");if(t&&"execution"!==i.kind)throw new Error("target observation requires the original execution preparation");this.materialized||await this.config.mutateConfigFile({afterWrite:{mode:"auto"},mutate:e=>{for(const[t,i]of Object.entries(r.openclaw_config))e[t]=structuredClone(i)}});const h=this.config.current();if(!containsApplied(h,r.openclaw_config))throw new Error("native config has not been applied by OpenClaw");const f=h.agents;if(!object(f)||!object(f.entries)||!object(f.entries[r.local_agent_id]))throw new Error("local_agent_id is not present in the actual resolved native agent catalog");if(this.persona=r.persona?{localAgentId:r.local_agent_id,content:r.persona.content}:void 0,this.materialized=structuredClone(c),t){if(!this.targetLookup)throw new Error("actual native target identity producer is unavailable");const e=await this.targetLookup({localAgentId:r.local_agent_id,activation:i,allocation:n});if(!nonempty(e.runtimeAgentUid)||e.runtimeLocalKey!==r.local_agent_id||!/^[1-9][0-9]*$/.test(e.runtimeEpoch)||!nonempty(e.leaseIdentity))throw new Error("actual native catalog/identity projection does not match the applied target");return this.targetAuthority=structuredClone(e),{runtime_agent_uid:e.runtimeAgentUid,runtime_local_key:e.runtimeLocalKey,harness:"openclaw",config_digest:i.config_sha256,runtime_epoch:e.runtimeEpoch}}let _="";if("execution"===i.kind){if(!l)throw new Error("original central native execution authority is unavailable");this.boundNativeRequestHash=l.nativeRequestHash,await centralNativeRuntime().prepareReadOnly(l.sessionKey,l.binding),_=ref({session_key:l.sessionKey,binding:l.binding,source:centralNativeRuntime().source(l.sessionKey)})}const g=(new Date).toISOString(),v={preparation_id:i.preparation_id,kind:i.kind,binding_id:i.binding_id,config_revision:i.config_revision,config_sha256:i.config_sha256,target_intent_digest:i.target_intent_digest,authority_ref:i.authority_ref,config_manifest:i.config_manifest,credential_set_id:i.credential_set_id,credential_set_version:i.credential_set_version,credential_activation_revision:this.credentialReceipt.config.revision,receipt_scope:"configuration"===i.kind?"current_config":"activation",credential_activation_receipt_ref:this.credentialReceipt.receipt_id,host_instance_id:n.id,runtime_lineage_ref:n.boot_id,session_load_receipt_ref:_,prepared_at:g,..."execution"===i.kind?{execution_binding_version:i.execution_binding_version}:{},receipt_id:ref({activation:i,allocation:n,config:r.openclaw_config,persona:r.persona?.sha256??null,credential_receipt:this.credentialReceipt.receipt_id,sessionLoadReceipt:_})};return l&¢ralNativeRuntime().bindExecutionObservation(l.binding,sessionConfigObservation({activation:i,allocation:n,native:r,execution:l,receipt:v,sessionLoadReceipt:_})),this.prepared={envelope:structuredClone(s),execution:l&&structuredClone(l),receipt:v},v}execution(e,t){const i=this.prepared,n=i?.envelope.config_manifest,r=i?.execution;if(!(i&&"execution"===i.envelope.activation.kind&&n&&r&&isDeepStrictEqual(r.binding,t)&&containsApplied(this.config.current(),n.openclaw_config)))throw new Error("central execution does not match actual applied native configuration/Persona/binding");if(this.assertSelection(e,i.envelope),!isDeepStrictEqual(e,r.params))throw new Error("central execution differs from the prepared original request");return{sessionKey:r.sessionKey,localAgentId:n.local_agent_id,systemPrompt:n.persona?.content??""}}assertSelection(e,t){const i=e.centralChat,n=t.config_manifest.persona;if(!object(i)||!this.credentialReceipt||!isDeepStrictEqual(i.config_pin,this.credentialReceipt.config)||!isDeepStrictEqual(i.persona_ref,n?{persona_id:n.persona_id,revision:n.revision}:null)||Object.hasOwn(i,"effective_config")||Object.hasOwn(i,"persona"))throw new Error("central selection differs from the actual prepared native configuration/Persona source")}promptContext(e){if(this.persona&&object(e)&&e.agentId===this.persona.localAgentId)return{appendSystemContext:this.persona.content}}drain(e){return this.serialize(()=>this.quiesce(e))}async quiesce(e){if(!(this.prepared&&isDeepStrictEqual(e.activation,this.prepared.envelope.activation)&&isDeepStrictEqual(e.allocation,this.prepared.envelope.allocation)&&nonempty(e.command_id)))throw new Error("native drain does not match the actual prepared activation");const t=await centralNativeRuntime().drain();if(1!==t.sourceWatermarks.length)throw new Error("Runtime drain contract requires one actual central session watermark; configuration-only quiescence is not representable");const i=t.sourceWatermarks[0].watermark,n=ref({command_id:e.command_id,prepared:this.prepared.receipt.receipt_id,allocation:e.allocation,sources:t.sourceWatermarks});return{receipt_id:ref({quiesce:n,watermark:i}),central_committed_watermark:i,pending_writes:0,all_writers_quiesced:!0,quiesce_ref:n}}}let controller;async function body(e){const t=[];let i=0;for await(const n of e){const e=Buffer.isBuffer(n)?n:Buffer.from(n);if(i+=e.length,i>4194304)throw new Error("native activation payload exceeds 4 MiB");t.push(e)}try{return JSON.parse(Buffer.concat(t).toString("utf8"))}catch{throw new Error("native control request is not valid JSON")}}export function registerSandboxNativeActivation(e,t,i,n){const r=process.env.BEEOS_SANDBOX_ACTIVATION_FILE;if(!r)return;const a=e.runtime?.config;if(!a?.current||!a.mutateConfigFile)throw new Error("pinned OpenClaw native config APIs are required for Sandbox activation");controller??=new SandboxNativeActivation(a,t,r,i,n,e.logger);for(const t of["credentials","target","prepare","drain"])e.registerHttpRoute({path:`/beeos/sandbox-v1/${t}`,auth:"plugin",async handler(e,i){const n=e,r=i,a=(e,t)=>{r.writeHead(e,{"content-type":"application/json","cache-control":"no-store"}),r.end(JSON.stringify(t))};if("POST"!==n.method)return void a(405,{error:{code:"method_not_allowed"}});const o=n.socket.remoteAddress;if(["127.0.0.1","::1","::ffff:127.0.0.1"].includes(o??""))try{const e=process.env.BEEOS_SANDBOX_NATIVE_TOKEN_FILE;if(!e)throw new Error("native control token file is unavailable");const i=(await readFile(e,"utf8")).trim(),r=Buffer.from(`Bearer ${i}`),o=Buffer.from(n.headers.authorization??"");if(!i||o.length!==r.length||!timingSafeEqual(o,r))return void a(401,{error:{code:"native_control_unauthorized"}});const s=await body(n);if(!object(s))throw new Error("native control request must be an object");a(200,"credentials"===t?await controller.credentials(s):"target"===t?await controller.target(s):"prepare"===t?await controller.prepare(s):await controller.drain(s))}catch(e){a(503,{error:{code:"native_preparation_unavailable",message:e instanceof Error?e.message:String(e)}})}else a(403,{error:{code:"native_loopback_required"}})}})}export function preparedSandboxNativeExecution(e,t){if(!controller)throw new Error("actual native Sandbox activation is unavailable");return controller.execution(e,t)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{prepareNativeOutputTool,nativeHtmlDeliveryForRun}from"../runtime/native-output-file-attempt.js";import{RENDER_UI_TOOL_NAME}from"../canvas/tools.js";import{BEEOS_FETCH_FILE_TOOL_NAME}from"../files/fetch-tool.js";import{BEEOS_UPLOAD_TOOL_NAME}from"./tool.js";export function needsNativeOutputCapability(t,o){return t===BEEOS_UPLOAD_TOOL_NAME||t===BEEOS_FETCH_FILE_TOOL_NAME||t===RENDER_UI_TOOL_NAME&&Object.prototype.hasOwnProperty.call(o,"html")}export function nativeOutputToolCallGate(t,o){if(needsNativeOutputCapability(t.toolName,t.params))
|
|
1
|
+
import{prepareNativeOutputTool,nativeHtmlDeliveryForRun,nativeOutputBindingDiagnostic}from"../runtime/native-output-file-attempt.js";import{RENDER_UI_TOOL_NAME}from"../canvas/tools.js";import{BEEOS_FETCH_FILE_TOOL_NAME}from"../files/fetch-tool.js";import{BEEOS_UPLOAD_TOOL_NAME}from"./tool.js";export function needsNativeOutputCapability(t,o){return t===BEEOS_UPLOAD_TOOL_NAME||t===BEEOS_FETCH_FILE_TOOL_NAME||t===RENDER_UI_TOOL_NAME&&Object.prototype.hasOwnProperty.call(o,"html")}export function nativeOutputToolCallGate(t,o,e){if(!needsNativeOutputCapability(t.toolName,t.params))return;const l=t.runId??o.runId,i=t.toolCallId??o.toolCallId,a=o.sessionKey;if(t.runId&&o.runId&&t.runId!==o.runId||t.toolCallId&&o.toolCallId&&t.toolCallId!==o.toolCallId)return e?.warn?.("[beeos-claw] native output capability blocked "+JSON.stringify(nativeOutputBindingDiagnostic({runId:l,toolCallId:i,sessionKey:a,error:new Error("native output file Host correlation conflict")}))),{block:!0,blockReason:"native output file Host correlation conflict"};try{if(nativeHtmlDeliveryForRun(l)?.observeAttempt(t.toolName,t.params),t.toolName===RENDER_UI_TOOL_NAME&&nativeHtmlDeliveryForRun(l)?.publishedFileId)return{block:!0,blockReason:"The HTML file for this reply is already published. Use that result; do not generate or upload another copy."};prepareNativeOutputTool(l,i,a)}catch(t){return e?.warn?.("[beeos-claw] native output capability blocked "+JSON.stringify(nativeOutputBindingDiagnostic({runId:l,toolCallId:i,sessionKey:a,error:t}))),{block:!0,blockReason:"native output file trusted capability unavailable"}}}
|
package/dist/upload/tool.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{constants}from"node:fs";import{access,stat}from"node:fs/promises";import{uploadLocalFile,NativeOutputFilesError}from"./upload-file.js";import{isBeeosFileUri}from"../files/beeos-file-uri.js";export const BEEOS_UPLOAD_TOOL_NAME="beeos_upload_file";export const BEEOS_UPLOAD_TOOL_DESCRIPTION="Upload 1-5 local files from this machine to the user via the BeeOS platform. This is the only way to deliver a file to the user: whenever you produce or modify a file the user asked for, call this tool with its path. Writing the file to disk or printing it through a shell command does not deliver it. Accepts only local filesystem paths; never pass beeos-file:// URIs because they are already BeeOS platform resources. If the call succeeds, the files are already delivered to the user — do not use any other tool to send them again. Upload modified deliverables again even if the same path was uploaded earlier; unchanged contents may reuse an existing platform file. Any file type is accepted: text, images, documents, PDFs, archives, binaries.";export const BEEOS_UPLOAD_TOOL_SCHEMA={title:"BeeOS file upload",type:"object",description:BEEOS_UPLOAD_TOOL_DESCRIPTION,additionalProperties:!1,required:["paths"],properties:{paths:{type:"array",minItems:1,maxItems:5,description:"Local filesystem paths (1-5). Absolute or workspace-relative. Do not pass beeos-file:// URIs.",items:{type:"string",minLength:1,description:"Single local filesystem path, not a beeos-file:// URI."}}}};const MAX_PATHS=5;export const REQUEST_TIMEOUT_MS=12e4;const MAX_CONCURRENCY=3,BEEOS_FILE_URI_UPLOAD_ERROR="beeos-file:// is already a BeeOS platform file URI, not a local path. Do not upload it; display it directly.";async function runWithConcurrency(e,t){const r=new Array(e.length);let a=0;async function o(){for(;a<e.length;){const t=a++;r[t]=await e[t]()}}const i=[];for(let r=0;r<Math.min(t,e.length);r++)i.push(o());return await Promise.all(i),r}async function validateFiles(e){return Promise.all(e.map(async e=>{try{await access(e,constants.R_OK);return(await stat(e)).isFile()?{path:e,ok:!0}:{path:e,ok:!1,error:"not a regular file"}}catch(t){const r=t.code;let a;return a="ENOENT"===r?"file not found":"ENOTDIR"===r?"path component is not a directory":"EACCES"===r?"permission denied":t instanceof Error?t.message:String(t),{path:e,ok:!1,error:a}}}))}export async function executeUpload(e,t,r,a,o){const
|
|
1
|
+
import{constants}from"node:fs";import{access,stat}from"node:fs/promises";import{uploadLocalFile,NativeOutputFilesError,nativeOutputPathWithinWorkspace}from"./upload-file.js";import{isBeeosFileUri}from"../files/beeos-file-uri.js";export const BEEOS_UPLOAD_TOOL_NAME="beeos_upload_file";export const BEEOS_UPLOAD_TOOL_DESCRIPTION="Upload 1-5 local files from this machine to the user via the BeeOS platform. This is the only way to deliver a file to the user: whenever you produce or modify a file the user asked for, call this tool with its path. Writing the file to disk or printing it through a shell command does not deliver it. Accepts only local filesystem paths; never pass beeos-file:// URIs because they are already BeeOS platform resources. If the call succeeds, the files are already delivered to the user — do not use any other tool to send them again. Upload modified deliverables again even if the same path was uploaded earlier; unchanged contents may reuse an existing platform file. Any file type is accepted: text, images, documents, PDFs, archives, binaries.";export const BEEOS_UPLOAD_TOOL_SCHEMA={title:"BeeOS file upload",type:"object",description:BEEOS_UPLOAD_TOOL_DESCRIPTION,additionalProperties:!1,required:["paths"],properties:{paths:{type:"array",minItems:1,maxItems:5,description:"Local filesystem paths (1-5). Absolute or workspace-relative. Do not pass beeos-file:// URIs.",items:{type:"string",minLength:1,description:"Single local filesystem path, not a beeos-file:// URI."}}}};const MAX_PATHS=5;export const REQUEST_TIMEOUT_MS=12e4;const MAX_CONCURRENCY=3,BEEOS_FILE_URI_UPLOAD_ERROR="beeos-file:// is already a BeeOS platform file URI, not a local path. Do not upload it; display it directly.";async function runWithConcurrency(e,t){const r=new Array(e.length);let a=0;async function o(){for(;a<e.length;){const t=a++;r[t]=await e[t]()}}const i=[];for(let r=0;r<Math.min(t,e.length);r++)i.push(o());return await Promise.all(i),r}async function validateFiles(e){return Promise.all(e.map(async e=>{try{await access(e,constants.R_OK);return(await stat(e)).isFile()?{path:e,ok:!0}:{path:e,ok:!1,error:"not a regular file"}}catch(t){const r=t.code;let a;return a="ENOENT"===r?"file not found":"ENOTDIR"===r?"path component is not a directory":"EACCES"===r?"permission denied":t instanceof Error?t.message:String(t),{path:e,ok:!1,error:a}}}))}export async function executeUpload(e,t,r,a,o,i){const s=parseParams(e);if(!s.ok)return errorResult(s.error);if(!t&&!a)return errorResult("Agent Gateway client unavailable — file upload requires agentGatewayUrl and a key pair");let n=s.paths;if(a){const e=[];for(const t of n)try{e.push(await nativeOutputPathWithinWorkspace(t,i))}catch(e){return errorResult(`${t}: ${e instanceof Error?e.message:String(e)}`)}n=e}const l=(await validateFiles(n)).find(e=>!e.ok);if(l)return errorResult(`${l.path}: ${l.error}`);const c=[],p=n.map((e,i)=>async()=>{try{if(a){const t=await a(e,i);return{fileId:t.fileId,downloadUrl:"",fileName:t.name,mimeType:t.mimeType,size:t.size}}return await uploadSingleFile(e,t,r)}catch(t){if(r?.aborted)throw t;const{category:s,detail:n}=classifyUploadFailure(t,Boolean(a));return o?.warn?.(`[beeos_upload_file] upload failed index=${i} native=${Boolean(a)} category=${s} ${n}`),c.push(a?t instanceof NativeOutputFilesError?t.message:"native output Files transport or local read failed":`${e}: ${t instanceof Error?t.message:String(t)}`),null}}),u=(await runWithConcurrency(p,3)).filter(e=>null!==e);if(0===u.length)return errorResult(`All uploads failed: ${c.join("; ")}`);const f=u.map(e=>({uri:`beeos-file://${e.fileId}`,name:e.fileName,mimeType:e.mimeType,fileId:e.fileId})),m=u.length===n.length?`Uploaded ${u.length} file(s): ${f.map(e=>e.name).join(", ")}`:`Uploaded ${u.length}/${n.length} file(s): ${f.map(e=>e.name).join(", ")}. Failed: ${c.join("; ")}`,d={ok:!0,files:f};return{...d,content:[{type:"text",text:m},...f.map(e=>({type:"resource_link",uri:e.uri,name:e.name,mimeType:e.mimeType}))],output:d,result:d,details:d,isError:!1}}async function uploadSingleFile(e,t,r){const a=await uploadLocalFile(e,t,{signal:r,timeoutMs:12e4});return{fileId:a.fileId,downloadUrl:"",fileName:a.name,mimeType:a.mimeType,size:a.size}}function parseParams(e){if(!e||"object"!=typeof e)return{ok:!1,error:"params must be an object"};const t=e;if(Object.keys(t).filter(e=>"paths"!==e).length>0)return{ok:!1,error:"only paths is allowed"};if(!Array.isArray(t.paths))return{ok:!1,error:"paths must be an array"};if(t.paths.length<1)return{ok:!1,error:"paths must contain at least 1 item"};if(t.paths.length>5)return{ok:!1,error:"paths must contain no more than 5 items"};const r=[];for(let e=0;e<t.paths.length;e++){const a=t.paths[e];if("string"!=typeof a||""===a.trim())return{ok:!1,error:`paths[${e}] must be a non-empty string`};const o=a.trim();if(isBeeosFileUri(o))return{ok:!1,error:BEEOS_FILE_URI_UPLOAD_ERROR};r.push(o)}return{ok:!0,paths:r}}function classifyUploadFailure(e,t){const r=e instanceof Error?e.message:String(e),a=e instanceof Error&&e.cause instanceof Error?` cause=${e.cause.message}`:"";if(e instanceof NativeOutputFilesError)return{category:e.category,detail:`${e.detail??""} message=${r}`.trim()};if(e instanceof DOMException&&("AbortError"===e.name||"TimeoutError"===e.name))return{category:"aborted",detail:`name=${e.name} message=${r}`};if(e instanceof TypeError)return{category:"transport_rejected",detail:`message=${r}${a}`};const o=e?.code;return"string"==typeof o?{category:"local_read_failed",detail:`code=${o} message=${r}`}:{category:t?"attempt_or_lease_fenced":"unclassified",detail:`message=${r}${a}`}}function errorResult(e){const t={ok:!1,error:e};return{...t,content:[{type:"text",text:e}],output:t,result:t,details:t,isError:!0}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{access,constants,readFile,stat}from"node:fs/promises";import{request as httpsRequest}from"node:https";import{createHash}from"node:crypto";import{basename,extname,resolve}from"node:path";import{HarnessProtocolError,RuntimeLeaseHttp,RuntimeOperationFiles,putPresignedUpload}from"@beeos-ai/cloud-harness-sdk";import{noteUploadedDeliverable}from"./delivery-ledger.js";const DEFAULT_TIMEOUT_MS=3e4,UPLOAD_REUSE_TTL_MS=18e5,MAX_REUSED_UPLOADS=256,completedUploads=new Map;let claimedCloudRuntimeInstanceId,_deps=null;export function setClaimedCloudRuntimeInstanceId(e){claimedCloudRuntimeInstanceId=e}export function setUploadDeps(e){_deps=e}export function getUploadDeps(){return _deps}export async function uploadLocalFile(e,t,r){if(void 0!==claimedCloudRuntimeInstanceId)throw new Error("native output file trusted tool capability required");await access(e,constants.R_OK);if(!(await stat(e)).isFile())throw new Error("not a regular file");const i=basename(e),a=r?.fileNameOverride??i,s=inferMimeType(a),n=await readFile(e);r?.signal?.throwIfAborted();const o=createHash("sha256").update(n).digest("hex"),p=JSON.stringify([t.baseUrl.origin,resolve(e),a,o]),d=Date.now();for(const[e,t]of completedUploads)t.expiresAt<=d&&completedUploads.delete(e);const l=completedUploads.get(p);if(l)return noteUploadedDeliverable(e),{...l.result};const c=AbortSignal.timeout(r?.timeoutMs??3e4),u=r?.signal?AbortSignal.any([r.signal,c]):c,m=await t.files.upload({fileName:a,mimeType:s,data:n,signal:u}),f={fileId:m.fileId,uri:m.uri,name:m.fileName,mimeType:m.mimeType,size:n.byteLength};if(!f.fileId)throw new Error("confirm returned no fileId");return completedUploads.size>=256&&completedUploads.delete(completedUploads.keys().next().value),completedUploads.set(p,{result:f,expiresAt:Date.now()+18e5}),noteUploadedDeliverable(e),{...f}}export class NativeOutputFilesError extends Error{category;detail;constructor(e,t,r){super(e),this.category=t,this.detail=r,this.name="NativeOutputFilesError"}}export async function uploadNativeOutputFile(e,t,r,i,a,s){r.assertAttempt(),await access(e,constants.R_OK);const n=await stat(e);if(!n.isFile()||n.size<=0||n.size>104857600)throw new Error("native output file size invalid");const o=await readFile(e);if(r.assertAttempt(),o.byteLength!==n.size)throw new Error("native output file changed while reading");const p=basename(e),d=inferMimeType(p),l=createHash("sha256").update(o).digest("hex"),c=createHash("sha256").update("beeos/native-output-file/v1\0"+r.operationId+"\0"+r.toolCallId+"\0"+i).digest("hex"),u=new URL(t);if(!["http:","https:"].includes(u.protocol)||u.username||u.password||"/"!==u.pathname||u.search||u.hash)throw new Error("native output Files origin invalid");const m=AbortSignal.any([r.signal,AbortSignal.timeout(s??3e4),...a?[a]:[]]),f={requestMessageId:r.requestMessageId,paramsHash:r.paramsHash,activeRunRegistrationId:r.activeRunRegistrationId,idempotencyKey:c},h=e=>!!e&&"object"==typeof e&&!Array.isArray(e),g=new RuntimeOperationFiles(new RuntimeLeaseHttp({origin:u.origin})),w=async(e,t)=>{r.assertAttempt();const i={runtimeLeaseCredential:r.getLease().runtimeLeaseCredential},a={...f,...t};let s;try{s="presign"===e?await g.presignOutput(i,r.operationId,a,m):await g.confirmOutput(i,r.operationId,a,m)}catch(t){if(t instanceof Error&&"runtime lease response origin changed"===t.message)throw new NativeOutputFilesError("native output Files response origin changed","control_response_origin",`stage=${e}`);if(!(t instanceof HarnessProtocolError))throw t;let r;const i=t.status??0;if(t.body)try{const e=JSON.parse(t.body);h(e)&&h(e.error)&&"string"==typeof e.error.code&&/^[A-Za-z0-9_.:-]{1,128}$/.test(e.error.code)&&(r=e.error.code)}catch(t){if(!(t instanceof SyntaxError))throw new NativeOutputFilesError("native output Files error decode failed","control_error_decode",`stage=${e} http_status=${i}`)}throw new NativeOutputFilesError("native output Files "+e+" failed ("+i+(r?","+r:"")+")","control_http_error",`stage=${e} http_status=${i} code=${r??"none"}`)}if(r.assertAttempt(),"string"==typeof s||void 0===s)throw new SyntaxError("native output Files response is not JSON");if(!h(n=s)||n.operationId!==r.operationId||n.requestMessageId!==f.requestMessageId||n.paramsHash!==f.paramsHash||n.activeRunRegistrationId!==f.activeRunRegistrationId)throw new NativeOutputFilesError("native output Files response binding invalid","control_response_binding",`stage=${e}`);var n;return s},y=await w("presign",{filename:p,content_type:d,size_bytes:o.byteLength,checksum_sha256:l}),v=y.upload,_=y.transferPolicy;if(!h(v)||!h(_)||"string"!=typeof _.allowedOrigin||"upload"!==v.direction||"PUT"!==v.http_method||"string"!=typeof v.file_id||!v.file_id||"string"!=typeof v.url||"string"!=typeof v.expires_at||!Number.isFinite(Date.parse(v.expires_at))||Date.parse(v.expires_at)<=Date.now()||v.content_type!==d||v.size_bytes!==o.byteLength||v.checksum_sha256!==l||!h(v.required_headers)||Object.values(v.required_headers).some(e=>"string"!=typeof e))throw new NativeOutputFilesError("native output Files transfer descriptor invalid","transfer_descriptor_invalid",descriptorDefect(v,_,d,o.byteLength,l));const b=new URL(v.url),x=new URL(_.allowedOrigin);if("https:"!==b.protocol||b.username||b.password||b.hash||"https:"!==x.protocol||x.username||x.password||"/"!==x.pathname||x.search||x.hash||x.origin!==_.allowedOrigin||b.origin!==x.origin)throw new NativeOutputFilesError("native output Files transfer origin invalid","transfer_origin_invalid",`target_matches_allowed=${b.origin===x.origin}`);r.assertAttempt();const I=v.required_headers,O=(await putPresignedUpload({url:b.toString(),allowedOrigin:x.origin,body:o,requiredHeaders:I,signal:m,fetchImpl:()=>putRequiredHeaders(b,I,o,m)})).status;if(r.assertAttempt(),O<200||O>=300)throw new NativeOutputFilesError("native output Files PUT failed ("+O+")","put_rejected",`http_status=${O} bytes=${o.byteLength} headers=${Object.keys(I).join(",")}`);let E;try{E=await w("confirm",{fileId:v.file_id,checksumSha256:l})}catch(e){if(r.assertAttempt(),m.throwIfAborted(),!(e instanceof TypeError||e instanceof SyntaxError))throw e;E=await w("confirm",{fileId:v.file_id,checksumSha256:l})}if(E.fileId!==v.file_id||E.fileName!==p||E.mimeType!==d||E.size!==o.byteLength)throw new NativeOutputFilesError("native output Files ready metadata mismatch","ready_metadata_mismatch",`fileId=${E.fileId===v.file_id} fileName=${E.fileName===p} mimeType=${E.mimeType===d} size=${E.size===o.byteLength}`);r.assertAttempt();const F={fileId:v.file_id,uri:"beeos-file://"+v.file_id,name:p,mimeType:d,size:o.byteLength};return noteUploadedDeliverable(e),F}function putRequiredHeaders(e,t,r,i){const a=Object.keys(t).find(e=>"content-length"===e.toLowerCase());if(void 0!==a&&t[a]!==String(r.byteLength))throw new NativeOutputFilesError("native output Files transfer descriptor invalid","transfer_descriptor_invalid",`field=required_headers.content-length bytes=${r.byteLength}`);return new Promise((a,s)=>{const n=e=>{s(e instanceof Error&&"AbortError"===e.name?e:new TypeError("fetch failed",{cause:e}))},o=httpsRequest(e,{method:"PUT",headers:t,signal:i},e=>{e.on("error",n),e.resume(),e.on("end",()=>a(new Response(null,{status:e.statusCode??0})))});o.on("error",n),o.end(r)})}function descriptorDefect(e,t,r,i,a){const s=e=>!!e&&"object"==typeof e&&!Array.isArray(e);if(!s(e))return"upload=absent";if(!s(t)||"string"!=typeof t.allowedOrigin)return"transferPolicy.allowedOrigin=invalid";const n=[["direction","upload"===e.direction],["http_method","PUT"===e.http_method],["file_id","string"==typeof e.file_id&&e.file_id.length>0],["url","string"==typeof e.url],["expires_at","string"==typeof e.expires_at&&Number.isFinite(Date.parse(e.expires_at))&&Date.parse(e.expires_at)>Date.now()],["content_type",e.content_type===r],["size_bytes",e.size_bytes===i],["checksum_sha256",e.checksum_sha256===a],["required_headers",s(e.required_headers)&&Object.values(e.required_headers).every(e=>"string"==typeof e)]];return`field=${n.find(([,e])=>!e)?.[0]??"none"} bytes=${i}`}function inferMimeType(e){switch(extname(e).toLowerCase()){case".txt":return"text/plain";case".md":return"text/markdown";case".json":return"application/json";case".html":return"text/html";case".css":return"text/css";case".js":case".mjs":case".cjs":return"text/javascript";case".ts":return"text/x.typescript";case".tsx":case".jsx":return"text/jsx";case".xml":return"application/xml";case".yaml":case".yml":return"application/yaml";case".toml":return"application/toml";case".pdf":return"application/pdf";case".doc":return"application/msword";case".docx":return"application/vnd.openxmlformats-officedocument.wordprocessingml.document";case".xls":return"application/vnd.ms-excel";case".xlsx":return"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";case".ppt":return"application/vnd.ms-powerpoint";case".pptx":return"application/vnd.openxmlformats-officedocument.presentationml.presentation";case".rtf":return"application/rtf";case".odt":return"application/vnd.oasis.opendocument.text";case".ods":return"application/vnd.oasis.opendocument.spreadsheet";case".odp":return"application/vnd.oasis.opendocument.presentation";case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".gif":return"image/gif";case".webp":return"image/webp";case".svg":return"image/svg+xml";case".mp4":return"video/mp4";case".mov":return"video/quicktime";case".webm":return"video/webm";case".mkv":return"video/x-matroska";case".avi":return"video/x-msvideo";case".m4v":return"video/x-m4v";case".mp3":return"audio/mpeg";case".wav":return"audio/wav";case".flac":return"audio/flac";case".aac":return"audio/aac";case".ogg":return"audio/ogg";case".m4a":return"audio/mp4";case".csv":return"text/csv";case".zip":return"application/zip";case".tar":return"application/x-tar";case".gz":case".tgz":return"application/gzip";default:return"application/octet-stream"}}
|
|
1
|
+
import{access,constants,readFile,realpath,stat}from"node:fs/promises";import{request as httpsRequest}from"node:https";import{createHash}from"node:crypto";import{basename,extname,isAbsolute,resolve,sep}from"node:path";import{HarnessProtocolError,RuntimeLeaseHttp,RuntimeOperationFiles,putPresignedUpload}from"@beeos-ai/cloud-harness-sdk";import{noteUploadedDeliverable}from"./delivery-ledger.js";const DEFAULT_TIMEOUT_MS=3e4,UPLOAD_REUSE_TTL_MS=18e5,MAX_REUSED_UPLOADS=256,completedUploads=new Map;let claimedCloudRuntimeInstanceId,_deps=null;export function setClaimedCloudRuntimeInstanceId(e){claimedCloudRuntimeInstanceId=e}export function setUploadDeps(e){_deps=e}export function getUploadDeps(){return _deps}export async function uploadLocalFile(e,t,r){if(void 0!==claimedCloudRuntimeInstanceId)throw new Error("native output file trusted tool capability required");await access(e,constants.R_OK);if(!(await stat(e)).isFile())throw new Error("not a regular file");const i=basename(e),a=r?.fileNameOverride??i,s=inferMimeType(a),n=await readFile(e);r?.signal?.throwIfAborted();const o=createHash("sha256").update(n).digest("hex"),p=JSON.stringify([t.baseUrl.origin,resolve(e),a,o]),l=Date.now();for(const[e,t]of completedUploads)t.expiresAt<=l&&completedUploads.delete(e);const c=completedUploads.get(p);if(c)return noteUploadedDeliverable(e),{...c.result};const d=AbortSignal.timeout(r?.timeoutMs??3e4),u=r?.signal?AbortSignal.any([r.signal,d]):d,m=await t.files.upload({fileName:a,mimeType:s,data:n,signal:u}),f={fileId:m.fileId,uri:m.uri,name:m.fileName,mimeType:m.mimeType,size:n.byteLength};if(!f.fileId)throw new Error("confirm returned no fileId");return completedUploads.size>=256&&completedUploads.delete(completedUploads.keys().next().value),completedUploads.set(p,{result:f,expiresAt:Date.now()+18e5}),noteUploadedDeliverable(e),{...f}}export class NativeOutputFilesError extends Error{category;detail;constructor(e,t,r){super(e),this.category=t,this.detail=r,this.name="NativeOutputFilesError"}}export async function nativeOutputPathWithinWorkspace(e,t){if(!t||!isAbsolute(t))throw new Error("native output workspace unavailable");const r=await realpath(t),i=isAbsolute(e)?e:resolve(r,e),a=await realpath(i);if(a!==r&&!a.startsWith(r+sep))throw new Error("native output file is outside this run's workspace");return a}export async function uploadNativeOutputFile(e,t,r,i,a,s){r.assertAttempt(),await access(e,constants.R_OK);const n=await stat(e);if(!n.isFile()||n.size<=0||n.size>104857600)throw new Error("native output file size invalid");const o=await readFile(e);if(r.assertAttempt(),o.byteLength!==n.size)throw new Error("native output file changed while reading");const p=basename(e),l=inferMimeType(p),c=createHash("sha256").update(o).digest("hex"),d=createHash("sha256").update("beeos/native-output-file/v1\0"+r.operationId+"\0"+r.toolCallId+"\0"+i).digest("hex"),u=new URL(t);if(!["http:","https:"].includes(u.protocol)||u.username||u.password||"/"!==u.pathname||u.search||u.hash)throw new Error("native output Files origin invalid");const m=AbortSignal.any([r.signal,AbortSignal.timeout(s??3e4),...a?[a]:[]]),f={requestMessageId:r.requestMessageId,paramsHash:r.paramsHash,activeRunRegistrationId:r.activeRunRegistrationId,idempotencyKey:d},h=e=>!!e&&"object"==typeof e&&!Array.isArray(e),g=new RuntimeOperationFiles(new RuntimeLeaseHttp({origin:u.origin})),w=async(e,t)=>{r.assertAttempt();const i={runtimeLeaseCredential:r.getLease().runtimeLeaseCredential},a={...f,...t};let s;try{s="presign"===e?await g.presignOutput(i,r.operationId,a,m):await g.confirmOutput(i,r.operationId,a,m)}catch(t){if(t instanceof Error&&"runtime lease response origin changed"===t.message)throw new NativeOutputFilesError("native output Files response origin changed","control_response_origin",`stage=${e}`);if(!(t instanceof HarnessProtocolError))throw t;let r;const i=t.status??0;if(t.body)try{const e=JSON.parse(t.body);h(e)&&h(e.error)&&"string"==typeof e.error.code&&/^[A-Za-z0-9_.:-]{1,128}$/.test(e.error.code)&&(r=e.error.code)}catch(t){if(!(t instanceof SyntaxError))throw new NativeOutputFilesError("native output Files error decode failed","control_error_decode",`stage=${e} http_status=${i}`)}throw new NativeOutputFilesError("native output Files "+e+" failed ("+i+(r?","+r:"")+")","control_http_error",`stage=${e} http_status=${i} code=${r??"none"}`)}if(r.assertAttempt(),"string"==typeof s||void 0===s)throw new SyntaxError("native output Files response is not JSON");if(!h(n=s)||n.operationId!==r.operationId||n.requestMessageId!==f.requestMessageId||n.paramsHash!==f.paramsHash||n.activeRunRegistrationId!==f.activeRunRegistrationId)throw new NativeOutputFilesError("native output Files response binding invalid","control_response_binding",`stage=${e}`);var n;return s},v=await w("presign",{filename:p,content_type:l,size_bytes:o.byteLength,checksum_sha256:c}),y=v.upload,_=v.transferPolicy;if(!h(y)||!h(_)||"string"!=typeof _.allowedOrigin||"upload"!==y.direction||"PUT"!==y.http_method||"string"!=typeof y.file_id||!y.file_id||"string"!=typeof y.url||"string"!=typeof y.expires_at||!Number.isFinite(Date.parse(y.expires_at))||Date.parse(y.expires_at)<=Date.now()||y.content_type!==l||y.size_bytes!==o.byteLength||y.checksum_sha256!==c||!h(y.required_headers)||Object.values(y.required_headers).some(e=>"string"!=typeof e))throw new NativeOutputFilesError("native output Files transfer descriptor invalid","transfer_descriptor_invalid",descriptorDefect(y,_,l,o.byteLength,c));const b=new URL(y.url),x=new URL(_.allowedOrigin);if("https:"!==b.protocol||b.username||b.password||b.hash||"https:"!==x.protocol||x.username||x.password||"/"!==x.pathname||x.search||x.hash||x.origin!==_.allowedOrigin||b.origin!==x.origin)throw new NativeOutputFilesError("native output Files transfer origin invalid","transfer_origin_invalid",`target_matches_allowed=${b.origin===x.origin}`);r.assertAttempt();const E=y.required_headers,I=(await putPresignedUpload({url:b.toString(),allowedOrigin:x.origin,body:o,requiredHeaders:E,signal:m,fetchImpl:()=>putRequiredHeaders(b,E,o,m)})).status;if(r.assertAttempt(),I<200||I>=300)throw new NativeOutputFilesError("native output Files PUT failed ("+I+")","put_rejected",`http_status=${I} bytes=${o.byteLength} headers=${Object.keys(E).join(",")}`);let O;try{O=await w("confirm",{fileId:y.file_id,checksumSha256:c})}catch(e){if(r.assertAttempt(),m.throwIfAborted(),!(e instanceof TypeError||e instanceof SyntaxError))throw e;O=await w("confirm",{fileId:y.file_id,checksumSha256:c})}if(O.fileId!==y.file_id||O.fileName!==p||O.mimeType!==l||O.size!==o.byteLength)throw new NativeOutputFilesError("native output Files ready metadata mismatch","ready_metadata_mismatch",`fileId=${O.fileId===y.file_id} fileName=${O.fileName===p} mimeType=${O.mimeType===l} size=${O.size===o.byteLength}`);r.assertAttempt();const F={fileId:y.file_id,uri:"beeos-file://"+y.file_id,name:p,mimeType:l,size:o.byteLength};return noteUploadedDeliverable(e),F}function putRequiredHeaders(e,t,r,i){const a=Object.keys(t).find(e=>"content-length"===e.toLowerCase());if(void 0!==a&&t[a]!==String(r.byteLength))throw new NativeOutputFilesError("native output Files transfer descriptor invalid","transfer_descriptor_invalid",`field=required_headers.content-length bytes=${r.byteLength}`);return new Promise((a,s)=>{const n=e=>{s(e instanceof Error&&"AbortError"===e.name?e:new TypeError("fetch failed",{cause:e}))},o=httpsRequest(e,{method:"PUT",headers:t,signal:i},e=>{e.on("error",n),e.resume(),e.on("end",()=>a(new Response(null,{status:e.statusCode??0})))});o.on("error",n),o.end(r)})}function descriptorDefect(e,t,r,i,a){const s=e=>!!e&&"object"==typeof e&&!Array.isArray(e);if(!s(e))return"upload=absent";if(!s(t)||"string"!=typeof t.allowedOrigin)return"transferPolicy.allowedOrigin=invalid";const n=[["direction","upload"===e.direction],["http_method","PUT"===e.http_method],["file_id","string"==typeof e.file_id&&e.file_id.length>0],["url","string"==typeof e.url],["expires_at","string"==typeof e.expires_at&&Number.isFinite(Date.parse(e.expires_at))&&Date.parse(e.expires_at)>Date.now()],["content_type",e.content_type===r],["size_bytes",e.size_bytes===i],["checksum_sha256",e.checksum_sha256===a],["required_headers",s(e.required_headers)&&Object.values(e.required_headers).every(e=>"string"==typeof e)]];return`field=${n.find(([,e])=>!e)?.[0]??"none"} bytes=${i}`}function inferMimeType(e){switch(extname(e).toLowerCase()){case".txt":return"text/plain";case".md":return"text/markdown";case".json":return"application/json";case".html":return"text/html";case".css":return"text/css";case".js":case".mjs":case".cjs":return"text/javascript";case".ts":return"text/x.typescript";case".tsx":case".jsx":return"text/jsx";case".xml":return"application/xml";case".yaml":case".yml":return"application/yaml";case".toml":return"application/toml";case".pdf":return"application/pdf";case".doc":return"application/msword";case".docx":return"application/vnd.openxmlformats-officedocument.wordprocessingml.document";case".xls":return"application/vnd.ms-excel";case".xlsx":return"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";case".ppt":return"application/vnd.ms-powerpoint";case".pptx":return"application/vnd.openxmlformats-officedocument.presentationml.presentation";case".rtf":return"application/rtf";case".odt":return"application/vnd.oasis.opendocument.text";case".ods":return"application/vnd.oasis.opendocument.spreadsheet";case".odp":return"application/vnd.oasis.opendocument.presentation";case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".gif":return"image/gif";case".webp":return"image/webp";case".svg":return"image/svg+xml";case".mp4":return"video/mp4";case".mov":return"video/quicktime";case".webm":return"video/webm";case".mkv":return"video/x-matroska";case".avi":return"video/x-msvideo";case".m4v":return"video/x-m4v";case".mp3":return"audio/mpeg";case".wav":return"audio/wav";case".flac":return"audio/flac";case".aac":return"audio/aac";case".ogg":return"audio/ogg";case".m4a":return"audio/mp4";case".csv":return"text/csv";case".zip":return"application/zip";case".tar":return"application/x-tar";case".gz":case".tgz":return"application/gzip";default:return"application/octet-stream"}}
|
package/openclaw.plugin.json
CHANGED
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"beeos_discover_agents",
|
|
19
19
|
"beeos_call_agent",
|
|
20
20
|
"beeos_get_task",
|
|
21
|
+
"beeos_memory_remember",
|
|
22
|
+
"beeos_memory_recall",
|
|
23
|
+
"beeos_memory_revise",
|
|
24
|
+
"beeos_memory_forget",
|
|
21
25
|
"beeos_automation_create",
|
|
22
26
|
"beeos_automation_create_webhook",
|
|
23
27
|
"beeos_automation_capabilities",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "beeos-claw",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.95",
|
|
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>",
|
|
@@ -88,7 +88,10 @@
|
|
|
88
88
|
"overrides": {
|
|
89
89
|
"fast-uri": ">=3.1.4",
|
|
90
90
|
"brace-expansion": ">=5.0.9",
|
|
91
|
-
"@beeos-ai/beeos-types": "$@beeos-ai/beeos-types"
|
|
91
|
+
"@beeos-ai/beeos-types": "$@beeos-ai/beeos-types",
|
|
92
|
+
"body-parser": "2.4.0",
|
|
93
|
+
"zod": "4.6.7",
|
|
94
|
+
"qs": "6.16.1"
|
|
92
95
|
},
|
|
93
|
-
"gitHead": "
|
|
96
|
+
"gitHead": "84948f8aa52e0d80d614cd6992d76947e6b7dc87"
|
|
94
97
|
}
|