beeos-claw 0.6.44-staging.2 → 0.6.44-staging.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{readUploadToolResult,writeEnrichmentCache}from"../upload/result-cache.js";import{BEEOS_UPLOAD_TOOL_NAME}from"../upload/tool.js";import{tryExtractLocalFiles}from"../upload/local-file-extractors.js";import{uploadLocalFile,getUploadDeps}from"../upload/upload-file.js";import{isPlainRecord as isRecord}from"../utils/text.js";import{buildToolResultSessionContentBlocks}from"./tool-result-blocks.js";import{projectBlocksToToolResultProjection}from"./tool-result-projection.js";export{buildToolResultSessionContentBlocks}from"./tool-result-blocks.js";const strategies=[{name:"beeos_upload_file_cache",canHandle:t=>t.toolName===BEEOS_UPLOAD_TOOL_NAME,resolve:strategyUploadCache},{name:"passthrough_gateway_result",canHandle:()=>!0,resolve:async t=>strategyPassthrough(t)}];export function registerToolResultStrategy(t,e){if(e?.prepend)strategies.unshift(t);else{const e=Math.max(0,strategies.length-1);strategies.splice(e,0,t)}}export function getToolResultStrategies(){return strategies}export async function resolveToolResultBlocks(t){let e=[];for(const o of strategies)if(o.canHandle(t))try{const l=await o.resolve(t);if(l&&l.length>0){e=l;break}}catch{}return enrichWithLocalFileUploads(t,e)}export async function normalizeToolResultForAcpUpdate(t){let e;try{e=await resolveToolResultBlocks(t)}catch{e=t.rawText?[{type:"content",content:{type:"text",text:t.rawText}}]:[]}0===e.length&&t.rawText&&(e=[{type:"content",content:{type:"text",text:t.rawText}}]);const o=projectBlocksToToolResultProjection({toolCallId:t.toolCallId,toolName:t.toolName,blocks:e,rawOutput:t.rawResult});return{blocks:e,outputText:o.outputText,rawOutput:t.rawResult,...o.resourceLinks?.length?{resourceLinks:o.resourceLinks}:{},projection:o}}async function enrichWithLocalFileUploads(t,e){const o=getUploadDeps();if(!o)return e;const l=tryExtractLocalFiles(t);if(0===l.length)return e;const r=[...e],a=[];for(const e of l)try{o.logger?.debug?.(`[enrich] Uploading local file ${e.filePath} for toolCallId=${t.toolCallId}`);const l=await uploadLocalFile(e.filePath,o.gatewayUrl,o.keys,{fileNameOverride:e.suggestedName});o.logger?.info?.(`[enrich] Uploaded: fileId=${l.fileId} toolCallId=${t.toolCallId}`);const s={uri:l.uri,name:l.name,...l.mimeType?{mimeType:l.mimeType}:{}};a.push(s),r.push({type:"content",content:{type:"resource_link",...s}}),r.push({type:"content",content:{type:"text",text:`[Auto-uploaded: ${l.name}. Do NOT call beeos_upload_file for this file.]`}})}catch(t){o.logger?.warn?.(`[enrich] Upload failed for ${e.filePath}: ${t instanceof Error?t.message:String(t)}, skipping`)}return a.length>0&&writeEnrichmentCache(t.toolCallId,a).catch(e=>{o.logger?.warn?.(`[enrich] Cache write failed for toolCallId=${t.toolCallId}: ${e instanceof Error?e.message:String(e)}`)}),r}async function strategyUploadCache(t){if(t.toolName!==BEEOS_UPLOAD_TOOL_NAME)return null;let e;try{e=await readUploadToolResult(t.toolCallId)}catch{return null}if(!e)return null;const o=pickUploadPayload(e);return buildToolResultSessionContentBlocks(t.toolName,o??e)}function strategyPassthrough(t){if(t.rawResult&&isRecord(t.rawResult)){const e=buildToolResultSessionContentBlocks(t.toolName,t.rawResult);if(e.length>0)return e}const e=t.rawText?.trim();if(!e)return[];try{const o=JSON.parse(e);if(isRecord(o)){const e=buildToolResultSessionContentBlocks(t.toolName,o);if(e.length>0)return e}}catch{}return[{type:"content",content:{type:"text",text:e}}]}function isUploadPayload(t){return!!isRecord(t)&&(!0===t.ok||!1===t.ok||"files"in t||Array.isArray(t.content)&&t.content.length>0)}function pickUploadPayload(t){if(isRecord(t)){for(const e of["output","result","details"]){const o=t[e];if(isUploadPayload(o))return o;if(isRecord(o))for(const t of["output","result","details"])if(isUploadPayload(o[t]))return o[t]}return Array.isArray(t.content)&&t.content.length>0||isUploadPayload(t)?t:void 0}}
1
+ import{readUploadToolResult}from"../upload/result-cache.js";import{BEEOS_UPLOAD_TOOL_NAME}from"../upload/tool.js";import{isUploadArtifactToolName,resolveToolArtifactLinks}from"../upload/tool-artifact-enrichment.js";import{isPlainRecord as isRecord}from"../utils/text.js";import{buildToolResultSessionContentBlocks}from"./tool-result-blocks.js";import{projectBlocksToToolResultProjection}from"./tool-result-projection.js";export{buildToolResultSessionContentBlocks}from"./tool-result-blocks.js";const strategies=[{name:"beeos_upload_file_cache",canHandle:t=>t.toolName===BEEOS_UPLOAD_TOOL_NAME,resolve:strategyUploadCache},{name:"passthrough_gateway_result",canHandle:()=>!0,resolve:async t=>strategyPassthrough(t)}];export function registerToolResultStrategy(t,o){if(o?.prepend)strategies.unshift(t);else{const o=Math.max(0,strategies.length-1);strategies.splice(o,0,t)}}export function getToolResultStrategies(){return strategies}export async function resolveToolResultBlocks(t){let o=[];for(const e of strategies)if(e.canHandle(t))try{const l=await e.resolve(t);if(l&&l.length>0){o=l;break}}catch{}return enrichWithLocalFileUploads(t,o)}export async function normalizeToolResultForAcpUpdate(t){let o;try{o=await resolveToolResultBlocks(t)}catch{o=t.rawText?[{type:"content",content:{type:"text",text:t.rawText}}]:[]}0===o.length&&t.rawText&&(o=[{type:"content",content:{type:"text",text:t.rawText}}]);const e=projectBlocksToToolResultProjection({toolCallId:t.toolCallId,toolName:t.toolName,blocks:o,rawOutput:t.rawResult});return{blocks:o,outputText:e.outputText,rawOutput:t.rawResult,...e.resourceLinks?.length?{resourceLinks:e.resourceLinks}:{},projection:e}}async function enrichWithLocalFileUploads(t,o){let e;try{e=await resolveToolArtifactLinks({toolCallId:t.toolCallId,toolName:t.toolName,rawResult:t.rawResult,rawText:t.rawText})}catch{return o}if(0===e.length)return o;const l=new Set;for(const t of o){if("content"!==t.type)continue;const o=t.content;"resource_link"===o?.type&&"string"==typeof o.uri&&l.add(o.uri)}const r=[...o],s=!isUploadArtifactToolName(t.toolName);for(const t of e)l.has(t.uri)||(r.push({type:"content",content:{type:"resource_link",...t}}),s&&r.push({type:"content",content:{type:"text",text:`[Auto-uploaded: ${t.name}. Do NOT call beeos_upload_file for this file.]`}}));return r}async function strategyUploadCache(t){if(t.toolName!==BEEOS_UPLOAD_TOOL_NAME)return null;let o;try{o=await readUploadToolResult(t.toolCallId)}catch{return null}if(!o)return null;const e=pickUploadPayload(o);return buildToolResultSessionContentBlocks(t.toolName,e??o)}function strategyPassthrough(t){if(t.rawResult&&isRecord(t.rawResult)){const o=buildToolResultSessionContentBlocks(t.toolName,t.rawResult);if(o.length>0)return o}const o=t.rawText?.trim();if(!o)return[];try{const e=JSON.parse(o);if(isRecord(e)){const o=buildToolResultSessionContentBlocks(t.toolName,e);if(o.length>0)return o}}catch{}return[{type:"content",content:{type:"text",text:o}}]}function isUploadPayload(t){return!!isRecord(t)&&(!0===t.ok||!1===t.ok||"files"in t||Array.isArray(t.content)&&t.content.length>0)}function pickUploadPayload(t){if(isRecord(t)){for(const o of["output","result","details"]){const e=t[o];if(isUploadPayload(e))return e;if(isRecord(e))for(const t of["output","result","details"])if(isUploadPayload(e[t]))return e[t]}return Array.isArray(t.content)&&t.content.length>0||isUploadPayload(t)?t:void 0}}
@@ -1 +1 @@
1
- const BROWSER_SCREENSHOT_ACTIONS=new Set(["screenshot","snapshot"]);export function isBrowserScreenshotEvent(t){if("browser"!==t.toolName)return!1;if(t.error)return!1;const e=t.params?.action;return"string"==typeof e&&BROWSER_SCREENSHOT_ACTIONS.has(e)}export function extractImagePath(t){if(!t||"object"!=typeof t)return null;const e=t.details;if(!e)return null;const r=e.media,n=[r?.mediaUrl,e.path,e.imagePath];for(const t of n)if("string"==typeof t&&t.length>0)return t;return null}
1
+ const BROWSER_SCREENSHOT_ACTIONS=new Set(["screenshot","snapshot"]);export function isBrowserScreenshotEvent(t){if("browser"!==t.toolName)return!1;if(t.error)return!1;const e=t.params?.action;return"string"==typeof e&&BROWSER_SCREENSHOT_ACTIONS.has(e)}export function extractImagePath(t){if(!t||"object"!=typeof t)return null;const e=t,r=[e];e.details&&"object"==typeof e.details&&!Array.isArray(e.details)&&r.unshift(e.details);for(const t of r){const e=t.media,r=[e?.mediaUrl,t.path,t.imagePath,t.mediaUrl];for(const t of r)if("string"==typeof t&&t.length>0)return t}return null}
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{resolveConfigWithMeta,mirrorOpenClawConfig}from"./config.js";import{hasRuntimeReplyApi}from"./runtime/reply-router.js";import{PromptRunStore}from"./runtime/prompt-run-store.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{createTokenProvider}from"@beeos-ai/message-sdk/auth";import{BeeosClawMessageClientProcessOwner}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{FileInboundExecutionJournal}from"./inbound-execution-journal.js";import{registerA2ATools,TaskHandleRegistry}from"./a2a/tools.js";import{BEEOS_UPLOAD_TOOL_NAME,BEEOS_UPLOAD_TOOL_SCHEMA,BEEOS_UPLOAD_TOOL_DESCRIPTION,executeUpload}from"./upload/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{createObsEventWriter}from"./observability.js";import{resolvePluginVersion}from"./plugin-version.js";import{createTerminalWebSocketService}from"./terminal/websocket.js";import{TerminalManager}from"./terminal/session-manager.js";import{loadAgentKeyPair,agentBoundFetch,agentFetch}from"./agent-auth.js";import{readDiscoveryCache,writeDiscoveryCache}from"./discovery-cache.js";import{discoverBridgeFromGW}from"./bridge-discovery.js";import{setUploadDeps}from"./upload/upload-file.js";import{registerLocalFileExtractor}from"./upload/local-file-extractors.js";import{browserScreenshotExtractor}from"./browser/screenshot-extractor.js";import{BEEOS_FILE_RESOURCE_ROUTING_RULE}from"./files/beeos-file-uri.js";import{CanvasStateManager}from"./canvas/state.js";import{CanvasRelayClient}from"./canvas/relay-client.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,createRenderUiHandler,createCloseUiHandler,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}from"./runtime/runtime-production-authority.js";import{FileRuntimeCommandJournal}from"./runtime/runtime-command-journal.js";import{FileRuntimePoisonDeliveryJournal}from"./runtime/runtime-poison-delivery-journal.js";import{InProcessMcpToolBridge}from"./acp-gateway/mcp-tool-bridge.js";import{LocalEncryptedCredentialReferenceVault}from"./acp-gateway/mcp-credential-reference-port.js";import{AgentGatewayGrantJwksReadinessAdapter,RuntimeServiceTransportReadinessAdapter,createRuntimeServiceProductionCandidate}from"./runtime/runtime-service-production-candidate.js";const PLUGIN_VERSION=resolvePluginVersion();let agentKeys=null,sharedCanvasState=null,sharedAcpServer=null;const sharedSessionWriteGate=new SessionWriteGate,sharedPromptRunStore=new PromptRunStore;let sharedSessionMutationCoordinator,sharedRuntimeAuthority,sharedMcpToolBridge,sharedMcpCredentialVault;const sharedMessageClientOwner=new BeeosClawMessageClientProcessOwner;let sharedActiveMessageConsumer,sharedInboundExecutionJournal;const sharedTerminalManager=new TerminalManager;let _initializing=!1,_pluginRegisteredAt=0;const ED25519_PKCS8_PREFIX=Buffer.from("302e020100300506032b657004220420","hex");function agentKeyPairToIdentity(e){return{publicKeyBase64:()=>Buffer.from(e.publicKey).toString("base64"),sign:async r=>{const{createPrivateKey:t,sign:o}=await import("node:crypto"),n=t({key:32===e.privateKey.length?Buffer.concat([ED25519_PKCS8_PREFIX,Buffer.from(e.privateKey)]):Buffer.from(e.privateKey),format:"der",type:"pkcs8"});return new Uint8Array(o(null,Buffer.from(r),n))}}}let unhandledRejectionObserverInstalled=!1;function installUnhandledRejectionObserver(e,r,t){unhandledRejectionObserverInstalled||(unhandledRejectionObserverInstalled=!0,process.on("unhandledRejection",t=>{const o=t instanceof Error?t.message:String(t),n=t instanceof Error?t.stack:void 0;e.logger.error?.(`[beeos-claw] unhandledRejection: ${o}${n?`\n${n}`:""}`),r({component:"plugin",domain:"fatal",name:"unhandled_rejection",severity:"error",summary:o,error:{code:"unhandled_rejection",message:o,...n?{stack:n}:{}}})}),process.on("uncaughtException",t=>{const o=t instanceof Error?t.message:String(t);e.logger.error?.(`[beeos-claw] uncaughtException: ${t instanceof Error?t.stack??t.message:String(t)}`),r({component:"plugin",domain:"fatal",name:"uncaught_exception",severity:"error",summary:o,error:{code:"uncaught_exception",message:o}})}))}function initializePlugin(e){let r,t;try{r=e.runtime?.config?.loadConfig?.()}catch{}try{t=resolveConfigWithMeta({pluginConfig:e.pluginConfig??{},openclawConfig:r})}catch(r){return e.logger.error?.(`[beeos-claw] Failed to resolve config: ${r instanceof Error?r.message:String(r)}`),null}const o=t.config,n=buildThirdPartyChannelSet(r);n.size>0&&e.logger.info?.(`[beeos-claw] Third-party channels detected: ${[...n].join(", ")}`);const a=o.log.enabled?createObsEventWriter({dir:o.log.dir,redaction:{gatewayToken:o.gateway.token},logger:e.logger}):()=>{};a({component:"plugin",domain:"lifecycle",name:"lifecycle.startup",severity:"info",payload:{pluginVersion:PLUGIN_VERSION,pid:process.pid,nodeVersion:process.version,cwd:process.cwd()}}),a({component:"plugin",domain:"config",name:"config.resolved",severity:"info",payload:{config:o,sources:t.sources,openclawConfigPath:t.openclawConfigPath}});for(const r of t.validation)a({component:"plugin",domain:"config",name:"config.validation",severity:r.severity,summary:r.message,error:{code:r.code,message:r.message,nextSteps:r.nextSteps}}),"error"===r.severity?e.logger.error?.(`[beeos-claw] ${r.message}`):e.logger.warn?.(`[beeos-claw] ${r.message}`);if(t.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);const r=Buffer.from(agentKeys.publicKey).toString("base64");e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (publicKey: ${r})`)}catch(r){e.logger.warn?.(`[beeos-claw] Failed to load agent key pair: ${r}`),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 agentKeys&&o.agentGatewayUrl&&(setUploadDeps({gatewayUrl:o.agentGatewayUrl,keys:agentKeys,logger:e.logger}),registerLocalFileExtractor(browserScreenshotExtractor),e.logger.info?.("[beeos-claw] Upload deps + browser screenshot extractor registered")),{cfg:o,writeObs:a,thirdPartyChannels:n,openclawConfig:r}}function registerUploadTools(e,r,t){const{cfg:o,writeObs:n}=r;cleanupUploadToolResultCache().catch(r=>{e.logger.warn?.(`[beeos_upload_file] cache cleanup failed on startup: ${String(r)}`)}),e.registerTool({name:BEEOS_UPLOAD_TOOL_NAME,description:BEEOS_UPLOAD_TOOL_DESCRIPTION,parameters:BEEOS_UPLOAD_TOOL_SCHEMA,async execute(r,t,a){e.logger.debug?.(`[beeos_upload_file] toolCallId=${r} params=${JSON.stringify(t)}`);const i=await executeUpload(t,o,agentKeys,a);return e.logger.debug?.(`[beeos_upload_file] toolCallId=${r} ok=${i.ok}`),n({component:"upload-tool",domain:"tool",name:i.ok?"upload.success":"upload.failure",severity:i.ok?"info":"warn",payload:{toolCallId:r,ok:i.ok,fileCount:i.files?.length??0,error:i.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})(i)}}),e.registerHttpRoute({path:"/beeos/files/stage",auth:"gateway",async handler(e,t){await handleFileStage(e,t,r.cfg)}}),e.registerHttpRoute({path:"/beeos/status",auth:"plugin",handler(e,r){handleStatusRequest(e,r,{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(r,t,a){e.logger.debug?.(`[beeos_list_files] toolCallId=${r} params=${JSON.stringify(t)}`);const i=await executeListFiles(t,o,agentKeys,a);return n({component:"file-list-tool",domain:"tool",name:i.ok?"list_files.success":"list_files.failure",severity:i.ok?"info":"warn",payload:{toolCallId:r,ok:i.ok,fileCount:i.files?.length??0,error:i.error}}),i}}),e.registerTool({name:BEEOS_FETCH_FILE_TOOL_NAME,description:BEEOS_FETCH_FILE_TOOL_DESCRIPTION,parameters:BEEOS_FETCH_FILE_TOOL_SCHEMA,async execute(r,t,a){e.logger.debug?.(`[beeos_fetch_file] toolCallId=${r} params=${JSON.stringify(t)}`);const i=await executeFetchFile(t,o,agentKeys,{signal:a,resolvePath:e.resolvePath});return n({component:"file-fetch-tool",domain:"tool",name:i.ok?"fetch_file.success":"fetch_file.failure",severity:i.ok?"info":"warn",payload:{toolCallId:r,ok:i.ok,path:i.path,size:i.size,error:i.error}}),i}})}function registerServices(e,r,t){const{cfg:o,writeObs:n,thirdPartyChannels:a}=r,i=agentKeys?(e,r)=>agentFetch(e,agentKeys,r):void 0,s=agentKeys?(e,r)=>agentBoundFetch(e,agentKeys,r):void 0,l=agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):void 0,c=join(process.env.OPENCLAW_HOME||join(homedir(),".openclaw"),"beeos"),g=sharedInboundExecutionJournal??=new FileInboundExecutionJournal(join(c,"inbound-execution-journal.v1.jsonl"));sharedMcpToolBridge??=new InProcessMcpToolBridge,!sharedMcpCredentialVault&&agentKeys&&l&&(sharedMcpCredentialVault=new LocalEncryptedCredentialReferenceVault(join(c,"mcp-credential-vault.json"),l,agentKeys.privateKey)),sharedMcpToolBridge.registerTools(e),!sharedRuntimeAuthority&&agentKeys&&o.agentGatewayUrl&&i&&s&&(sharedRuntimeAuthority=new RuntimeProductionAuthority({stateDirectory:c,agentGatewayUrl:o.agentGatewayUrl,agentFetch:i,boundAgentFetch:s,keys:agentKeys,logger:e.logger})),sharedSessionMutationCoordinator??=new SessionMutationCoordinator(sharedSessionWriteGate,new OpenClawSessionWriteQuiescence(e.logger,{agentId:o.gateway.agentId||"main"}),e.logger,{onRecoveryRequired:r=>{scheduleProcessRuntimeRestart(r,e.logger)}});const d=sharedSessionMutationCoordinator;sharedAcpServer||(sharedAcpServer=new ACPServer(o,e.logger,d,n,i,l,a,sharedTerminalManager,sharedRuntimeAuthority,void 0,sharedMcpToolBridge,sharedMcpCredentialVault,s));const u=sharedAcpServer;t.current=u,u.nudgeMcpNativeProjection();const m=sharedPromptRunStore,{enabled:p,principalId:y,a2aEnabled:f}=o.messageBus;let h;o.agentGatewayUrl&&agentKeys&&(h=createTokenProvider({agentGatewayUrl:o.agentGatewayUrl,identity:agentKeyPairToIdentity(agentKeys)}));const w=process.env.MESSAGE_RUNTIME_DELIVERY_KEY?.trim(),b=y||process.env.BEEOS_PRINCIPAL_ID||"",v=h?sharedMessageClientOwner.configure({tokenProvider:h,identityId:b,...o.messageBus.serviceUrl?{serviceUrl:o.messageBus.serviceUrl}:{},logger:e.logger,...sharedRuntimeAuthority&&w?{runtimeDelivery:{scopedDeliveryKey:w,authority:{currentLease:()=>{const e=sharedRuntimeAuthority?.authorityLease,r=sharedRuntimeAuthority?.currentConsumerBinding();return e&&r?{...e,journalStoreId:r.journalStoreId,journalGeneration:r.journalGeneration}:null}}}}:{}}):void 0;e.registerService({id:"beeos-acp",async start(){const r=Date.now(),t=_pluginRegisteredAt?r-_pluginRegisteredAt:-1;e.logger.info?.(`[beeos-claw] beeos-acp service start() begin, sincePluginRegister=${t}ms, bridge.url=${o.bridge.url||"(empty)"}`);const n=await createRuntimeServiceProductionCandidate({...o.agentGatewayUrl&&i?{authorizationAdapter:new AgentGatewayGrantJwksReadinessAdapter({agentGatewayUrl:o.agentGatewayUrl})}:{},...v&&o.agentGatewayUrl&&s&&w?{transportAdapter:new RuntimeServiceTransportReadinessAdapter({agentGatewayUrl:o.agentGatewayUrl,messageService:v.nodeTransport,messageClient:v.client,configuredServiceUrl:o.messageBus.serviceUrl,boundAgentFetch:s,scopedDeliveryKey:w})}:{},commandJournal:sharedRuntimeAuthority?.journal??new FileRuntimeCommandJournal(join(c,"runtime-command-journal.json")),poisonJournal:new FileRuntimePoisonDeliveryJournal(join(c,"runtime-poison-deliveries.json")),onConsumerDeliveryError:r=>{const t=r instanceof Error?`${r.name}: ${r.message}${"status"in r?` status=${r.status}`:""}${"code"in r?` code=${r.code}`:""}\n${r.stack??""}`:String(r);e.logger.error?.(`[runtime-service] delivery worker failed before acknowledgement; delivery retained for retry: ${t}`)},onConsumerLeaseStarvation:({starvedForMs:r,recovered:t})=>{const o=Math.round(r/1e3);t?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:r=>e.logger.error?.(`[runtime-service] request failed operationId=${r.operationId} method=${r.method}: ${r.error instanceof Error?r.error.stack??r.error.message:String(r.error)}`)});if(sharedRuntimeAuthority?.setRuntimeServiceMethods("ready"===n.status?n.serviceMethods:[]),sharedRuntimeAuthority?.setRuntimeResourceBindingContractRevision("ready"===n.status?n.resourceBindingContractRevision:void 0),u.setRuntimeRpcConsumerFactory("ready"===n.status?n.factory:void 0),"unavailable"===n.status?e.logger.warn?.("[runtime-service] capability fenced: "+n.blockers.map(e=>e.id).join(",")):n.capabilityBlockers.length&&e.logger.warn?.("[runtime-service] method capability fenced: "+n.capabilityBlockers.map(e=>e.method).join(",")),!o.bridge.url&&o.agentGatewayUrl&&i){const r=Date.now(),t=await discoverBridgeFromGW(o.agentGatewayUrl,i);if(e.logger.info?.(`[beeos-claw] bridge discovery took ${Date.now()-r}ms result=${t?.url??"null"}`),t)o.bridge.url=t.url,writeDiscoveryCache({bridge:{url:t.url,discoveredAt:Date.now()}}),e.logger.info?.(`[beeos-claw] Bridge URL discovered from Agent Gateway: ${t.url}`);else{const r=readDiscoveryCache();r?.bridge?.url?(o.bridge.url=r.bridge.url,e.logger.info?.(`[beeos-claw] Bridge URL from cache (GW unreachable): ${r.bridge.url}`)):e.logger.debug?.("[beeos-claw] Bridge URL not available (no GW, no cache) — bridge disabled")}}await u.start(o.bridge.url||void 0),e.logger.info?.(`[beeos-claw] ACP Server started (total service start: ${Date.now()-r}ms)`)},async stop(){await u.stop(),e.logger.info?.("[beeos-claw] ACP Server stopped")}});if(p&&void 0!==h&&h){const r=sharedMessageClientOwner.createRegistrationToken(),t=async(e,r)=>{const t=await h(e);if(!t.identityId||t.identityId!==e)throw new Error("Message SDK token identity did not match the current runtime authority");return{principalId:e,runtimeEpoch:r}},a=(e,r,t)=>({getLocalAgentId:()=>r,resolveLocalAgentId:e=>e===t?r:void 0,getDefaultPlatformAgent:()=>({instanceId:e.principalId}),ensureImInboundSession:(e,r,t)=>{u.ensureImInboundSession(e,r,t)},chatAbort:(e,r)=>u.chatAbort(e,r)}),i=sharedRuntimeAuthority?new RuntimeAuthorityMessageBusLifecycle({authority:sharedRuntimeAuthority,logger:e.logger,bus:{connect:async i=>{await sharedMessageClientOwner.acquire(r,async r=>{const s=await t(i.instanceId,i.runtimeEpoch),l=r.client;u.setMessageClient(l,s.principalId);const c=new Map,p=new MessageProjectionInboundConsumer({client:l,bindings:()=>{const r=sharedRuntimeAuthority?.authorityLease;return r&&r.instanceId===s.principalId&&r.runtimeEpoch===s.runtimeEpoch?u.getPlatformAgentMappings().flatMap(({localAgentId:t,platformAgent:i})=>{if(!i.id||i.instanceId!==s.principalId)return[];let g=c.get(i.id);return g&&g.localAgentId===t||(g={localAgentId:t,inbound:createImInboundHandler({runtime:e.runtime,pluginConfig:e.pluginConfig,client:l,localServer:a(s,t,i.id),promptRunStore:m,sessionMutationCoordinator:d,logger:e.logger,writeObs:n,principalIdOverride:s.principalId,promptTimeoutMs:o.promptTimeoutMs,activeRunAuthority:u.getActiveRunAuthority()})},c.set(i.id,g)),[{principalId:s.principalId,targetAgentId:i.id,runtimeEpoch:r.runtimeEpoch,inbound:g.inbound}]}):[]},executionJournal:g,logger:e.logger});u.onAgentMappingUpdated(()=>{sharedActiveMessageConsumer===p&&p.refresh()});const y=sharedRuntimeAuthority?.subscribeAuthority(()=>{sharedActiveMessageConsumer===p&&p.refresh()})??(()=>{}),f=new MessageClientTerminalStateRecovery({logger:e.logger,isCurrent:()=>{if(sharedActiveMessageConsumer!==p)return!1;const e=sharedRuntimeAuthority?.authorityLease;return null!=e&&e.instanceId===s.principalId&&e.runtimeEpoch===s.runtimeEpoch&&e.leaseId===i.leaseId&&e.handlerIdentity===i.handlerIdentity},reconnect:async()=>{if("failed"===l.getSnapshot().connection){await l.connect();try{await u.rebindRuntimeDelivery()}catch(r){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient recovery: ${r instanceof Error?r.message:String(r)}`)}}}});let h=l.getSnapshot().connection;const w=l.subscribe(()=>{const r=l.getSnapshot();r.connection!==h&&(h=r.connection,"connected"===r.connection?(f.notifyConnected(),e.logger.info?.(`[beeos-claw] MessageClient connected (localAgentId=${u.getLocalAgentId()}, principalId=${s.principalId})`)):"failed"===r.connection?(e.logger.warn?.(`[beeos-claw] MessageClient failed principalId=${s.principalId} recoveryError=${r.recoveryError??"unknown"}`),f.notifyFailed()):"disconnected"!==r.connection&&"reconnecting"!==r.connection||e.logger.warn?.(`[beeos-claw] MessageClient state=${r.connection} principalId=${s.principalId}; SDK owns reconnect/recovery`))});sharedActiveMessageConsumer=p,p.start();try{await l.connect()}catch(e){throw sharedActiveMessageConsumer===p&&(sharedActiveMessageConsumer=void 0),f.dispose(),await p.stop(),y(),w(),await l.disconnect().catch(()=>{}),e}try{await u.rebindRuntimeDelivery()}catch(r){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient connect: ${r instanceof Error?r.message:String(r)}`)}return async()=>{sharedActiveMessageConsumer===p&&(sharedActiveMessageConsumer=void 0),f.dispose(),await p.stop(),y(),w(),await l.disconnect(),e.logger.info?.("[beeos-claw] MessageClient disconnected")}})},disconnect:async()=>{await sharedMessageClientOwner.release(r)}}}):void 0;e.registerService({id:"beeos-message-bus",async start(){i?i.start():e.logger.warn?.("[beeos-claw] Message bus requires runtime authority; waiting is unavailable without Agent Gateway runtime identity")},async stop(){await(i?.stop())}})}else p?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=${p})`);if(!1!==f&&o.agentGatewayUrl){const r=e=>u.getGatewaySessionKeyForToolCall(e),t=e=>u.getMentionsForToolCall(e),n=(e,r)=>{u.broadcastNotification(e,r)},a=new TaskHandleRegistry;registerA2ATools(e,{agentGatewayUrl:o.agentGatewayUrl,agentKeys:agentKeys,logger:e.logger},a,r,t,n,()=>u?.getDefaultPlatformAgent()?.instanceId),e.logger.info?.("[beeos-claw] A2A tools registered (beeos_discover_agents, beeos_call_agent) via REST")}if(o.canvasEnabled){sharedCanvasState||(sharedCanvasState=new CanvasStateManager);const r=sharedCanvasState;if(o.agentGatewayUrl&&agentKeys){let t;r.setLogger(e.logger);{const e=o.agentGatewayUrl,r=agentKeys;t=async()=>{const t=await agentFetch(`${e}/api/v1/canvas/token`,r,{method:"POST"});if(!t.ok){const e=await t.text().catch(()=>"");throw new Error(`Canvas token returned ${t.status}: ${e}`)}return t.json()}}const n=n=>{const a=new CanvasRelayClient({canvasRelayUrl:o.canvasRelayUrl,agentKeys:agentKeys,agentId:n.id,displayName:n.displayName,avatarUrl:n.avatarUrl,tokenProvider:t,onReconnect:()=>u.onRelayReconnected(),logger:e.logger});a.connect(),r.setRelayClient(a),r.setAgentId(n.id),u.wireRelayActionHandler(),u.flushPendingCanvasLinks(),e.logger.info?.(`[beeos-claw] Canvas Relay multiplexed client connected (agentId=${n.id}, name=${n.name??"none"})`)};e.registerService({id:"beeos-canvas-relay",async start(){try{await u.waitForAgentMapping();const r=u.getDefaultPlatformAgent();if(r?.id)return void n(r);e.logger.info?.("[beeos-claw] Canvas Relay deferred: waiting for late agent sync..."),u.onceAgentMappingReady(()=>{const r=u.getDefaultPlatformAgent();if(r?.id)try{n(r)}catch(r){e.logger.warn?.(`[beeos-claw] Deferred Canvas Relay start failed: ${r}`)}else e.logger.warn?.("[beeos-claw] Agent mapping ready but no platform agent; Canvas Relay stays disabled")})}catch(r){e.logger.warn?.(`[beeos-claw] Failed to start Canvas Relay client: ${r}`)}},stop(){r.getRelayClient()?.disconnect()}}),e.logger.info?.("[beeos-claw] Canvas Relay configured")}else e.logger.warn?.("[beeos-claw] Canvas Relay unavailable: agentGatewayUrl or agentKeys missing");const t={stateManager:r,logger:e.logger,writeObs:e=>n(e),isCanvasActive:e=>!!e&&u.isCanvasActiveForGatewayKey(e),getActiveSessionId:e=>u.getSessionIdForToolCall(e),getPlatformAgentId:e=>u.getPlatformAgentIdForToolCall(e),getGatewaySessionKey:e=>u.getGatewaySessionKeyForToolCall(e),waitForAgentSync:()=>u.waitForAgentMapping()},i=new FormSchemaRegistry,s=buildCronSchemas(a,{capMs:o.cronMaxDurationCapMs});i.register(s.create),i.register(s.update);const l=new ResourceDescriptorRegistry;l.register(CRON_RESOURCE);const c=e=>async(r,t,o)=>(u.preMapToolCallSession(r),e(r,t));e.registerTool({name:RENDER_UI_TOOL_NAME,description:RENDER_UI_TOOL_DESCRIPTION,parameters:RENDER_UI_TOOL_SCHEMA,execute:c(createRenderUiHandler(t))}),e.registerTool({name:CLOSE_UI_TOOL_NAME,description:CLOSE_UI_TOOL_DESCRIPTION,parameters:CLOSE_UI_TOOL_SCHEMA,execute:c(createCloseUiHandler(t))}),u.setCanvasState(r,{schemaRegistry:i,descriptorRegistry:l});const g=u.getFormBuilder();g&&e.registerTool({name:RENDER_FORM_TOOL_NAME,description:buildRenderFormDescription(i),parameters:RENDER_FORM_TOOL_SCHEMA,execute:c(createRenderFormHandler({registry:i,builder:g,logger:e.logger}))});const d=u.getResourceRenderer();if(d){generateActionTools(l,e,async(e,r)=>u.gatewayRequest(e,r),d,e.logger)}const m=`\n\nTool selection guidance:\n- browser tool: Use when the user wants to OPEN, VISIT, NAVIGATE to a webpage, take SCREENSHOTS, interact with elements (click, type), or visually inspect pages.\n- beeos_search: Use ONLY for text-based information retrieval (fact-finding, research queries). Never for page interaction or screenshots.\n- beeos_fetch: Use ONLY to extract article text from a known URL. Never for visual content or screenshots.\n- ${BEEOS_FILE_RESOURCE_ROUTING_RULE}\nWhen the user says "open", "visit", "go to", "screenshot", or mentions seeing/viewing a webpage, ALWAYS prefer the browser tool.`,p=new Set([RENDER_UI_TOOL_NAME,CLOSE_UI_TOOL_NAME,RENDER_FORM_TOOL_NAME]),y=256,f=new Map;if("function"==typeof e.on){try{e.on("before_prompt_build",(e,r)=>{if(r?.sessionKey){if(f.size>=y&&!f.has(r.sessionKey)){const e=f.keys().next().value;void 0!==e&&f.delete(e)}f.set(r.sessionKey,r.channelId)}if(isThirdPartyChannel(a,{sessionKey:r?.sessionKey,channelId:r?.channelId}))return{appendSystemContext:'This conversation is in a third-party channel (Lark/Telegram/Discord/Slack); Canvas surfaces are not visible here. Do NOT use render_ui, close_ui, or render_form. Use built-in tools directly (e.g. the `cron` tool with `action:"add"` for scheduled tasks) and respond with plain text.'};if(!r?.sessionKey)return{appendSystemContext:m};return u.isCanvasActiveForGatewayKey(r.sessionKey)?{appendSystemContext:CANVAS_SYSTEM_PROMPT+m}:{appendSystemContext:"Canvas is closed by user. Do NOT use render_ui, close_ui, or render_form. Respond with plain text only."+m}}),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,r)=>{if(r?.sessionKey&&u.setPendingToolCallSessionKey(r.sessionKey),!p.has(e.toolName))return;const t=r?.sessionKey?f.get(r.sessionKey):void 0;return isThirdPartyChannel(a,{sessionKey:r?.sessionKey,channelId:t})?{block:!0,blockReason:"Canvas tools are not available in this channel. Respond with plain text only."}:r?.sessionKey?u.isCanvasActiveForGatewayKey(r.sessionKey)?void 0:{block:!0,blockReason:"Canvas is closed by user. Respond with plain text instead."}:{block:!0,blockReason:"Canvas session unknown. Respond with plain text instead."}}),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 r=createTerminalWebSocketService({config:{port:o.terminalWsPort,token:agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):"",allowedOrigins:o.terminalWsAllowedOrigins},terminalMgr:sharedTerminalManager,logger:e.logger,writeObs:n});e.registerService({id:"beeos-terminal-ws",start(){r.start(),e.logger.info?.(`[beeos-claw] Terminal WS started on port ${o.terminalWsPort}`)},stop(){r.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(r.openclawConfig){const t=mirrorOpenClawConfig(r.openclawConfig);t.copied?e.logger.info?.(`[beeos-claw] mirrored openclaw config to ${t.destinationPath}`):e.logger.debug?.(`[beeos-claw] openclaw config mirror skipped: ${t.reason}`)}}const CAPABILITY_REGISTRATION_MODES=new Set(["full","discovery","tool-discovery"]),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)if(!e.registrationMode||CAPABILITY_REGISTRATION_MODES.has(e.registrationMode)){_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 r=initializePlugin(e);if(!r)return;const t={current:null};installUnhandledRejectionObserver(e,r.writeObs,t),registerUploadTools(e,r,t),registerArouterMediaProviders(e),registerServices(e,r,t),_pluginRegisteredAt=Date.now(),e.logger.info?.("[beeos-claw] Plugin registered successfully")}finally{_initializing=!1}}else e.logger.debug?.(`[beeos-claw] Skipping registration (mode=${e.registrationMode})`)}};export default plugin;
1
+ import{resolveConfigWithMeta,mirrorOpenClawConfig}from"./config.js";import{hasRuntimeReplyApi}from"./runtime/reply-router.js";import{PromptRunStore}from"./runtime/prompt-run-store.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{createTokenProvider}from"@beeos-ai/message-sdk/auth";import{BeeosClawMessageClientProcessOwner}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{FileInboundExecutionJournal}from"./inbound-execution-journal.js";import{registerA2ATools,TaskHandleRegistry}from"./a2a/tools.js";import{BEEOS_UPLOAD_TOOL_NAME,BEEOS_UPLOAD_TOOL_SCHEMA,BEEOS_UPLOAD_TOOL_DESCRIPTION,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{createObsEventWriter}from"./observability.js";import{resolvePluginVersion}from"./plugin-version.js";import{createTerminalWebSocketService}from"./terminal/websocket.js";import{TerminalManager}from"./terminal/session-manager.js";import{loadAgentKeyPair,agentBoundFetch,agentFetch}from"./agent-auth.js";import{readDiscoveryCache,writeDiscoveryCache}from"./discovery-cache.js";import{discoverBridgeFromGW}from"./bridge-discovery.js";import{setUploadDeps}from"./upload/upload-file.js";import{registerLocalFileExtractor}from"./upload/local-file-extractors.js";import{browserScreenshotExtractor}from"./browser/screenshot-extractor.js";import{BEEOS_FILE_RESOURCE_ROUTING_RULE}from"./files/beeos-file-uri.js";import{CanvasStateManager}from"./canvas/state.js";import{CanvasRelayClient}from"./canvas/relay-client.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,createRenderUiHandler,createCloseUiHandler,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}from"./runtime/runtime-production-authority.js";import{FileRuntimeCommandJournal}from"./runtime/runtime-command-journal.js";import{FileRuntimePoisonDeliveryJournal}from"./runtime/runtime-poison-delivery-journal.js";import{InProcessMcpToolBridge}from"./acp-gateway/mcp-tool-bridge.js";import{LocalEncryptedCredentialReferenceVault}from"./acp-gateway/mcp-credential-reference-port.js";import{AgentGatewayGrantJwksReadinessAdapter,RuntimeServiceTransportReadinessAdapter,createRuntimeServiceProductionCandidate}from"./runtime/runtime-service-production-candidate.js";const PLUGIN_VERSION=resolvePluginVersion();let agentKeys=null,sharedCanvasState=null,sharedAcpServer=null;const sharedSessionWriteGate=new SessionWriteGate,sharedPromptRunStore=new PromptRunStore;let sharedSessionMutationCoordinator,sharedRuntimeAuthority,sharedMcpToolBridge,sharedMcpCredentialVault;const sharedMessageClientOwner=new BeeosClawMessageClientProcessOwner;let sharedActiveMessageConsumer,sharedInboundExecutionJournal;const sharedTerminalManager=new TerminalManager;let _initializing=!1,_pluginRegisteredAt=0;const ED25519_PKCS8_PREFIX=Buffer.from("302e020100300506032b657004220420","hex");function agentKeyPairToIdentity(e){return{publicKeyBase64:()=>Buffer.from(e.publicKey).toString("base64"),sign:async r=>{const{createPrivateKey:t,sign:o}=await import("node:crypto"),n=t({key:32===e.privateKey.length?Buffer.concat([ED25519_PKCS8_PREFIX,Buffer.from(e.privateKey)]):Buffer.from(e.privateKey),format:"der",type:"pkcs8"});return new Uint8Array(o(null,Buffer.from(r),n))}}}let unhandledRejectionObserverInstalled=!1;function installUnhandledRejectionObserver(e,r,t){unhandledRejectionObserverInstalled||(unhandledRejectionObserverInstalled=!0,process.on("unhandledRejection",t=>{const o=t instanceof Error?t.message:String(t),n=t instanceof Error?t.stack:void 0;e.logger.error?.(`[beeos-claw] unhandledRejection: ${o}${n?`\n${n}`:""}`),r({component:"plugin",domain:"fatal",name:"unhandled_rejection",severity:"error",summary:o,error:{code:"unhandled_rejection",message:o,...n?{stack:n}:{}}})}),process.on("uncaughtException",t=>{const o=t instanceof Error?t.message:String(t);e.logger.error?.(`[beeos-claw] uncaughtException: ${t instanceof Error?t.stack??t.message:String(t)}`),r({component:"plugin",domain:"fatal",name:"uncaught_exception",severity:"error",summary:o,error:{code:"uncaught_exception",message:o}})}))}function initializePlugin(e){let r,t;try{r=e.runtime?.config?.loadConfig?.()}catch{}try{t=resolveConfigWithMeta({pluginConfig:e.pluginConfig??{},openclawConfig:r})}catch(r){return e.logger.error?.(`[beeos-claw] Failed to resolve config: ${r instanceof Error?r.message:String(r)}`),null}const o=t.config,n=buildThirdPartyChannelSet(r);n.size>0&&e.logger.info?.(`[beeos-claw] Third-party channels detected: ${[...n].join(", ")}`);const a=o.log.enabled?createObsEventWriter({dir:o.log.dir,redaction:{gatewayToken:o.gateway.token},logger:e.logger}):()=>{};a({component:"plugin",domain:"lifecycle",name:"lifecycle.startup",severity:"info",payload:{pluginVersion:PLUGIN_VERSION,pid:process.pid,nodeVersion:process.version,cwd:process.cwd()}}),a({component:"plugin",domain:"config",name:"config.resolved",severity:"info",payload:{config:o,sources:t.sources,openclawConfigPath:t.openclawConfigPath}});for(const r of t.validation)a({component:"plugin",domain:"config",name:"config.validation",severity:r.severity,summary:r.message,error:{code:r.code,message:r.message,nextSteps:r.nextSteps}}),"error"===r.severity?e.logger.error?.(`[beeos-claw] ${r.message}`):e.logger.warn?.(`[beeos-claw] ${r.message}`);if(t.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);const r=Buffer.from(agentKeys.publicKey).toString("base64");e.logger.info?.(`[beeos-claw] v${PLUGIN_VERSION} registering (publicKey: ${r})`)}catch(r){e.logger.warn?.(`[beeos-claw] Failed to load agent key pair: ${r}`),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 agentKeys&&o.agentGatewayUrl&&(setUploadDeps({gatewayUrl:o.agentGatewayUrl,keys:agentKeys,logger:e.logger}),registerLocalFileExtractor(browserScreenshotExtractor),e.logger.info?.("[beeos-claw] Upload deps + browser screenshot extractor registered")),{cfg:o,writeObs:a,thirdPartyChannels:n,openclawConfig:r}}function registerUploadTools(e,r,t){const{cfg:o,writeObs:n}=r;cleanupUploadToolResultCache().catch(r=>{e.logger.warn?.(`[beeos_upload_file] cache cleanup failed on startup: ${String(r)}`)}),e.registerTool({name:BEEOS_UPLOAD_TOOL_NAME,description:BEEOS_UPLOAD_TOOL_DESCRIPTION,parameters:BEEOS_UPLOAD_TOOL_SCHEMA,async execute(r,t,a){e.logger.debug?.(`[beeos_upload_file] toolCallId=${r} params=${JSON.stringify(t)}`);const s=await executeUpload(t,o,agentKeys,a);return e.logger.debug?.(`[beeos_upload_file] toolCallId=${r} ok=${s.ok}`),n({component:"upload-tool",domain:"tool",name:s.ok?"upload.success":"upload.failure",severity:s.ok?"info":"warn",payload:{toolCallId:r,ok:s.ok,fileCount:s.files?.length??0,error:s.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})(s)}}),e.registerTool({name:BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,description:BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION,parameters:BEEOS_DESKTOP_SCREENSHOT_TOOL_SCHEMA,async execute(r,t,a){e.logger.debug?.(`[beeos_desktop_screenshot] toolCallId=${r} params=${JSON.stringify(t)}`);const s=await executeDesktopScreenshot(t,o,agentKeys,a);return e.logger.debug?.(`[beeos_desktop_screenshot] toolCallId=${r} ok=${s.ok}`),n({component:"desktop-screenshot-tool",domain:"tool",name:s.ok?"desktop_screenshot.success":"desktop_screenshot.failure",severity:s.ok?"info":"warn",payload:{toolCallId:r,ok:s.ok,path:s.path,fileCount:s.files?.length??0,error:s.error}}),(async t=>{try{await writeUploadToolResult(r,BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,t),await cleanupUploadToolResultCache()}catch(t){e.logger.warn?.(`[beeos_desktop_screenshot] persist cache failed toolCallId=${r}: ${String(t)}`)}return t})(s)}}),e.registerHttpRoute({path:"/beeos/files/stage",auth:"gateway",async handler(e,t){await handleFileStage(e,t,r.cfg)}}),e.registerHttpRoute({path:"/beeos/status",auth:"plugin",handler(e,r){handleStatusRequest(e,r,{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(r,t,a){e.logger.debug?.(`[beeos_list_files] toolCallId=${r} params=${JSON.stringify(t)}`);const s=await executeListFiles(t,o,agentKeys,a);return n({component:"file-list-tool",domain:"tool",name:s.ok?"list_files.success":"list_files.failure",severity:s.ok?"info":"warn",payload:{toolCallId:r,ok:s.ok,fileCount:s.files?.length??0,error:s.error}}),s}}),e.registerTool({name:BEEOS_FETCH_FILE_TOOL_NAME,description:BEEOS_FETCH_FILE_TOOL_DESCRIPTION,parameters:BEEOS_FETCH_FILE_TOOL_SCHEMA,async execute(r,t,a){e.logger.debug?.(`[beeos_fetch_file] toolCallId=${r} params=${JSON.stringify(t)}`);const s=await executeFetchFile(t,o,agentKeys,{signal:a,resolvePath:e.resolvePath});return n({component:"file-fetch-tool",domain:"tool",name:s.ok?"fetch_file.success":"fetch_file.failure",severity:s.ok?"info":"warn",payload:{toolCallId:r,ok:s.ok,path:s.path,size:s.size,error:s.error}}),s}})}function registerServices(e,r,t){const{cfg:o,writeObs:n,thirdPartyChannels:a}=r,s=agentKeys?(e,r)=>agentFetch(e,agentKeys,r):void 0,i=agentKeys?(e,r)=>agentBoundFetch(e,agentKeys,r):void 0,l=agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):void 0,c=join(process.env.OPENCLAW_HOME||join(homedir(),".openclaw"),"beeos"),d=sharedInboundExecutionJournal??=new FileInboundExecutionJournal(join(c,"inbound-execution-journal.v1.jsonl"));sharedMcpToolBridge??=new InProcessMcpToolBridge,!sharedMcpCredentialVault&&agentKeys&&l&&(sharedMcpCredentialVault=new LocalEncryptedCredentialReferenceVault(join(c,"mcp-credential-vault.json"),l,agentKeys.privateKey)),sharedMcpToolBridge.registerTools(e),!sharedRuntimeAuthority&&agentKeys&&o.agentGatewayUrl&&s&&i&&(sharedRuntimeAuthority=new RuntimeProductionAuthority({stateDirectory:c,agentGatewayUrl:o.agentGatewayUrl,agentFetch:s,boundAgentFetch:i,keys:agentKeys,logger:e.logger})),sharedSessionMutationCoordinator??=new SessionMutationCoordinator(sharedSessionWriteGate,new OpenClawSessionWriteQuiescence(e.logger,{agentId:o.gateway.agentId||"main"}),e.logger,{onRecoveryRequired:r=>{scheduleProcessRuntimeRestart(r,e.logger)}});const g=sharedSessionMutationCoordinator;sharedAcpServer||(sharedAcpServer=new ACPServer(o,e.logger,g,n,s,l,a,sharedTerminalManager,sharedRuntimeAuthority,void 0,sharedMcpToolBridge,sharedMcpCredentialVault,i));const u=sharedAcpServer;t.current=u,u.nudgeMcpNativeProjection();const p=sharedPromptRunStore,{enabled:m,principalId:y,a2aEnabled:f}=o.messageBus;let h;o.agentGatewayUrl&&agentKeys&&(h=createTokenProvider({agentGatewayUrl:o.agentGatewayUrl,identity:agentKeyPairToIdentity(agentKeys)}));const w=process.env.MESSAGE_RUNTIME_DELIVERY_KEY?.trim(),E=y||process.env.BEEOS_PRINCIPAL_ID||"",_=h?sharedMessageClientOwner.configure({tokenProvider:h,identityId:E,...o.messageBus.serviceUrl?{serviceUrl:o.messageBus.serviceUrl}:{},logger:e.logger,...sharedRuntimeAuthority&&w?{runtimeDelivery:{scopedDeliveryKey:w,authority:{currentLease:()=>{const e=sharedRuntimeAuthority?.authorityLease,r=sharedRuntimeAuthority?.currentConsumerBinding();return e&&r?{...e,journalStoreId:r.journalStoreId,journalGeneration:r.journalGeneration}:null}}}}:{}}):void 0;e.registerService({id:"beeos-acp",async start(){const r=Date.now(),t=_pluginRegisteredAt?r-_pluginRegisteredAt:-1;e.logger.info?.(`[beeos-claw] beeos-acp service start() begin, sincePluginRegister=${t}ms, bridge.url=${o.bridge.url||"(empty)"}`);const n=await createRuntimeServiceProductionCandidate({...o.agentGatewayUrl&&s?{authorizationAdapter:new AgentGatewayGrantJwksReadinessAdapter({agentGatewayUrl:o.agentGatewayUrl})}:{},..._&&o.agentGatewayUrl&&i&&w?{transportAdapter:new RuntimeServiceTransportReadinessAdapter({agentGatewayUrl:o.agentGatewayUrl,messageService:_.nodeTransport,messageClient:_.client,configuredServiceUrl:o.messageBus.serviceUrl,boundAgentFetch:i,scopedDeliveryKey:w})}:{},commandJournal:sharedRuntimeAuthority?.journal??new FileRuntimeCommandJournal(join(c,"runtime-command-journal.json")),poisonJournal:new FileRuntimePoisonDeliveryJournal(join(c,"runtime-poison-deliveries.json")),onConsumerDeliveryError:r=>{const t=r instanceof Error?`${r.name}: ${r.message}${"status"in r?` status=${r.status}`:""}${"code"in r?` code=${r.code}`:""}\n${r.stack??""}`:String(r);e.logger.error?.(`[runtime-service] delivery worker failed before acknowledgement; delivery retained for retry: ${t}`)},onConsumerLeaseStarvation:({starvedForMs:r,recovered:t})=>{const o=Math.round(r/1e3);t?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:r=>e.logger.error?.(`[runtime-service] request failed operationId=${r.operationId} method=${r.method}: ${r.error instanceof Error?r.error.stack??r.error.message:String(r.error)}`)});if(sharedRuntimeAuthority?.setRuntimeServiceMethods("ready"===n.status?n.serviceMethods:[]),sharedRuntimeAuthority?.setRuntimeResourceBindingContractRevision("ready"===n.status?n.resourceBindingContractRevision:void 0),u.setRuntimeRpcConsumerFactory("ready"===n.status?n.factory:void 0),"unavailable"===n.status?e.logger.warn?.("[runtime-service] capability fenced: "+n.blockers.map(e=>e.id).join(",")):n.capabilityBlockers.length&&e.logger.warn?.("[runtime-service] method capability fenced: "+n.capabilityBlockers.map(e=>e.method).join(",")),!o.bridge.url&&o.agentGatewayUrl&&s){const r=Date.now(),t=await discoverBridgeFromGW(o.agentGatewayUrl,s);if(e.logger.info?.(`[beeos-claw] bridge discovery took ${Date.now()-r}ms result=${t?.url??"null"}`),t)o.bridge.url=t.url,writeDiscoveryCache({bridge:{url:t.url,discoveredAt:Date.now()}}),e.logger.info?.(`[beeos-claw] Bridge URL discovered from Agent Gateway: ${t.url}`);else{const r=readDiscoveryCache();r?.bridge?.url?(o.bridge.url=r.bridge.url,e.logger.info?.(`[beeos-claw] Bridge URL from cache (GW unreachable): ${r.bridge.url}`)):e.logger.debug?.("[beeos-claw] Bridge URL not available (no GW, no cache) — bridge disabled")}}await u.start(o.bridge.url||void 0),e.logger.info?.(`[beeos-claw] ACP Server started (total service start: ${Date.now()-r}ms)`)},async stop(){await u.stop(),e.logger.info?.("[beeos-claw] ACP Server stopped")}});if(m&&void 0!==h&&h){const r=sharedMessageClientOwner.createRegistrationToken(),t=async(e,r)=>{const t=await h(e);if(!t.identityId||t.identityId!==e)throw new Error("Message SDK token identity did not match the current runtime authority");return{principalId:e,runtimeEpoch:r}},a=(e,r,t)=>({getLocalAgentId:()=>r,resolveLocalAgentId:e=>e===t?r:void 0,getDefaultPlatformAgent:()=>({instanceId:e.principalId}),ensureImInboundSession:(e,r,t)=>{u.ensureImInboundSession(e,r,t)},chatAbort:(e,r)=>u.chatAbort(e,r)}),s=sharedRuntimeAuthority?new RuntimeAuthorityMessageBusLifecycle({authority:sharedRuntimeAuthority,logger:e.logger,bus:{connect:async s=>{await sharedMessageClientOwner.acquire(r,async r=>{const i=await t(s.instanceId,s.runtimeEpoch),l=r.client;u.setMessageClient(l,i.principalId);const c=new Map,m=new MessageProjectionInboundConsumer({client:l,bindings:()=>{const r=sharedRuntimeAuthority?.authorityLease;return r&&r.instanceId===i.principalId&&r.runtimeEpoch===i.runtimeEpoch?u.getPlatformAgentMappings().flatMap(({localAgentId:t,platformAgent:s})=>{if(!s.id||s.instanceId!==i.principalId)return[];let d=c.get(s.id);return d&&d.localAgentId===t||(d={localAgentId:t,inbound:createImInboundHandler({runtime:e.runtime,pluginConfig:e.pluginConfig,client:l,localServer:a(i,t,s.id),promptRunStore:p,sessionMutationCoordinator:g,logger:e.logger,writeObs:n,principalIdOverride:i.principalId,promptTimeoutMs:o.promptTimeoutMs,activeRunAuthority:u.getActiveRunAuthority()})},c.set(s.id,d)),[{principalId:i.principalId,targetAgentId:s.id,runtimeEpoch:r.runtimeEpoch,inbound:d.inbound}]}):[]},executionJournal:d,logger:e.logger});u.onAgentMappingUpdated(()=>{sharedActiveMessageConsumer===m&&m.refresh()});const y=sharedRuntimeAuthority?.subscribeAuthority(()=>{sharedActiveMessageConsumer===m&&m.refresh()})??(()=>{}),f=new MessageClientTerminalStateRecovery({logger:e.logger,isCurrent:()=>{if(sharedActiveMessageConsumer!==m)return!1;const e=sharedRuntimeAuthority?.authorityLease;return null!=e&&e.instanceId===i.principalId&&e.runtimeEpoch===i.runtimeEpoch&&e.leaseId===s.leaseId&&e.handlerIdentity===s.handlerIdentity},reconnect:async()=>{if("failed"===l.getSnapshot().connection){await l.connect();try{await u.rebindRuntimeDelivery()}catch(r){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient recovery: ${r instanceof Error?r.message:String(r)}`)}}}});let h=l.getSnapshot().connection;const w=l.subscribe(()=>{const r=l.getSnapshot();r.connection!==h&&(h=r.connection,"connected"===r.connection?(f.notifyConnected(),e.logger.info?.(`[beeos-claw] MessageClient connected (localAgentId=${u.getLocalAgentId()}, principalId=${i.principalId})`)):"failed"===r.connection?(e.logger.warn?.(`[beeos-claw] MessageClient failed principalId=${i.principalId} recoveryError=${r.recoveryError??"unknown"}`),f.notifyFailed()):"disconnected"!==r.connection&&"reconnecting"!==r.connection||e.logger.warn?.(`[beeos-claw] MessageClient state=${r.connection} principalId=${i.principalId}; SDK owns reconnect/recovery`))});sharedActiveMessageConsumer=m,m.start();try{await l.connect()}catch(e){throw sharedActiveMessageConsumer===m&&(sharedActiveMessageConsumer=void 0),f.dispose(),await m.stop(),y(),w(),await l.disconnect().catch(()=>{}),e}try{await u.rebindRuntimeDelivery()}catch(r){e.logger.warn?.(`[beeos-claw] runtime Service delivery rebind failed after MessageClient connect: ${r instanceof Error?r.message:String(r)}`)}return async()=>{sharedActiveMessageConsumer===m&&(sharedActiveMessageConsumer=void 0),f.dispose(),await m.stop(),y(),w(),await l.disconnect(),e.logger.info?.("[beeos-claw] MessageClient disconnected")}})},disconnect:async()=>{await sharedMessageClientOwner.release(r)}}}):void 0;e.registerService({id:"beeos-message-bus",async start(){s?s.start():e.logger.warn?.("[beeos-claw] Message bus requires runtime authority; waiting is unavailable without Agent Gateway runtime identity")},async stop(){await(s?.stop())}})}else m?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=${m})`);if(!1!==f&&o.agentGatewayUrl){const r=e=>u.getGatewaySessionKeyForToolCall(e),t=e=>u.getMentionsForToolCall(e),n=(e,r)=>{u.broadcastNotification(e,r)},a=new TaskHandleRegistry;registerA2ATools(e,{agentGatewayUrl:o.agentGatewayUrl,agentKeys:agentKeys,logger:e.logger},a,r,t,n,()=>u?.getDefaultPlatformAgent()?.instanceId),e.logger.info?.("[beeos-claw] A2A tools registered (beeos_discover_agents, beeos_call_agent) via REST")}if(o.canvasEnabled){sharedCanvasState||(sharedCanvasState=new CanvasStateManager);const r=sharedCanvasState;if(o.agentGatewayUrl&&agentKeys){let t;r.setLogger(e.logger);{const e=o.agentGatewayUrl,r=agentKeys;t=async()=>{const t=await agentFetch(`${e}/api/v1/canvas/token`,r,{method:"POST"});if(!t.ok){const e=await t.text().catch(()=>"");throw new Error(`Canvas token returned ${t.status}: ${e}`)}return t.json()}}const n=n=>{const a=new CanvasRelayClient({canvasRelayUrl:o.canvasRelayUrl,agentKeys:agentKeys,agentId:n.id,displayName:n.displayName,avatarUrl:n.avatarUrl,tokenProvider:t,onReconnect:()=>u.onRelayReconnected(),logger:e.logger});a.connect(),r.setRelayClient(a),r.setAgentId(n.id),u.wireRelayActionHandler(),u.flushPendingCanvasLinks(),e.logger.info?.(`[beeos-claw] Canvas Relay multiplexed client connected (agentId=${n.id}, name=${n.name??"none"})`)};e.registerService({id:"beeos-canvas-relay",async start(){try{await u.waitForAgentMapping();const r=u.getDefaultPlatformAgent();if(r?.id)return void n(r);e.logger.info?.("[beeos-claw] Canvas Relay deferred: waiting for late agent sync..."),u.onceAgentMappingReady(()=>{const r=u.getDefaultPlatformAgent();if(r?.id)try{n(r)}catch(r){e.logger.warn?.(`[beeos-claw] Deferred Canvas Relay start failed: ${r}`)}else e.logger.warn?.("[beeos-claw] Agent mapping ready but no platform agent; Canvas Relay stays disabled")})}catch(r){e.logger.warn?.(`[beeos-claw] Failed to start Canvas Relay client: ${r}`)}},stop(){r.getRelayClient()?.disconnect()}}),e.logger.info?.("[beeos-claw] Canvas Relay configured")}else e.logger.warn?.("[beeos-claw] Canvas Relay unavailable: agentGatewayUrl or agentKeys missing");const t={stateManager:r,logger:e.logger,writeObs:e=>n(e),isCanvasActive:e=>!!e&&u.isCanvasActiveForGatewayKey(e),getActiveSessionId:e=>u.getSessionIdForToolCall(e),getPlatformAgentId:e=>u.getPlatformAgentIdForToolCall(e),getGatewaySessionKey:e=>u.getGatewaySessionKeyForToolCall(e),waitForAgentSync:()=>u.waitForAgentMapping()},s=new FormSchemaRegistry,i=buildCronSchemas(a,{capMs:o.cronMaxDurationCapMs});s.register(i.create),s.register(i.update);const l=new ResourceDescriptorRegistry;l.register(CRON_RESOURCE);const c=e=>async(r,t,o)=>(u.preMapToolCallSession(r),e(r,t));e.registerTool({name:RENDER_UI_TOOL_NAME,description:RENDER_UI_TOOL_DESCRIPTION,parameters:RENDER_UI_TOOL_SCHEMA,execute:c(createRenderUiHandler(t))}),e.registerTool({name:CLOSE_UI_TOOL_NAME,description:CLOSE_UI_TOOL_DESCRIPTION,parameters:CLOSE_UI_TOOL_SCHEMA,execute:c(createCloseUiHandler(t))}),u.setCanvasState(r,{schemaRegistry:s,descriptorRegistry:l});const d=u.getFormBuilder();d&&e.registerTool({name:RENDER_FORM_TOOL_NAME,description:buildRenderFormDescription(s),parameters:RENDER_FORM_TOOL_SCHEMA,execute:c(createRenderFormHandler({registry:s,builder:d,logger:e.logger}))});const g=u.getResourceRenderer();if(g){generateActionTools(l,e,async(e,r)=>u.gatewayRequest(e,r),g,e.logger)}const p=`\n\nTool selection guidance:\n- browser tool: Use when the user wants to OPEN, VISIT, NAVIGATE to a webpage, take SCREENSHOTS of web pages, interact with elements (click, type), or visually inspect pages.\n- ${BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME}: Use to capture the agent desktop (XFCE/VNC DISPLAY). Prefer this over shell/python X11 dumps; never invent raw Xlib/PIL capture.\n- beeos_search: Use ONLY for text-based information retrieval (fact-finding, research queries). Never for page interaction or screenshots.\n- beeos_fetch: Use ONLY to extract article text from a known URL. Never for visual content or screenshots.\n- ${BEEOS_FILE_RESOURCE_ROUTING_RULE}\nWhen the user says "open", "visit", "go to", or mentions seeing/viewing a webpage, ALWAYS prefer the browser tool. When they ask for a desktop / screen / VNC capture of the agent workspace, use beeos_desktop_screenshot.`,m=new Set([RENDER_UI_TOOL_NAME,CLOSE_UI_TOOL_NAME,RENDER_FORM_TOOL_NAME]),y=256,f=new Map;if("function"==typeof e.on){try{e.on("before_prompt_build",(e,r)=>{if(r?.sessionKey){if(f.size>=y&&!f.has(r.sessionKey)){const e=f.keys().next().value;void 0!==e&&f.delete(e)}f.set(r.sessionKey,r.channelId)}if(isThirdPartyChannel(a,{sessionKey:r?.sessionKey,channelId:r?.channelId}))return{appendSystemContext:'This conversation is in a third-party channel (Lark/Telegram/Discord/Slack); Canvas surfaces are not visible here. Do NOT use render_ui, close_ui, or render_form. Use built-in tools directly (e.g. the `cron` tool with `action:"add"` for scheduled tasks) and respond with plain text.'};if(!r?.sessionKey)return{appendSystemContext:p};return u.isCanvasActiveForGatewayKey(r.sessionKey)?{appendSystemContext:CANVAS_SYSTEM_PROMPT+p}:{appendSystemContext:"Canvas is closed by user. Do NOT use render_ui, close_ui, or render_form. Respond with plain text only."+p}}),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,r)=>{if(r?.sessionKey&&u.setPendingToolCallSessionKey(r.sessionKey),!m.has(e.toolName))return;const t=r?.sessionKey?f.get(r.sessionKey):void 0;return isThirdPartyChannel(a,{sessionKey:r?.sessionKey,channelId:t})?{block:!0,blockReason:"Canvas tools are not available in this channel. Respond with plain text only."}:r?.sessionKey?u.isCanvasActiveForGatewayKey(r.sessionKey)?void 0:{block:!0,blockReason:"Canvas is closed by user. Respond with plain text instead."}:{block:!0,blockReason:"Canvas session unknown. Respond with plain text instead."}}),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 r=createTerminalWebSocketService({config:{port:o.terminalWsPort,token:agentKeys?Buffer.from(agentKeys.publicKey).toString("base64"):"",allowedOrigins:o.terminalWsAllowedOrigins},terminalMgr:sharedTerminalManager,logger:e.logger,writeObs:n});e.registerService({id:"beeos-terminal-ws",start(){r.start(),e.logger.info?.(`[beeos-claw] Terminal WS started on port ${o.terminalWsPort}`)},stop(){r.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(r.openclawConfig){const t=mirrorOpenClawConfig(r.openclawConfig);t.copied?e.logger.info?.(`[beeos-claw] mirrored openclaw config to ${t.destinationPath}`):e.logger.debug?.(`[beeos-claw] openclaw config mirror skipped: ${t.reason}`)}}const CAPABILITY_REGISTRATION_MODES=new Set(["full","discovery","tool-discovery"]),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)if(!e.registrationMode||CAPABILITY_REGISTRATION_MODES.has(e.registrationMode)){_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 r=initializePlugin(e);if(!r)return;const t={current:null};installUnhandledRejectionObserver(e,r.writeObs,t),registerUploadTools(e,r,t),registerArouterMediaProviders(e),registerServices(e,r,t),_pluginRegisteredAt=Date.now(),e.logger.info?.("[beeos-claw] Plugin registered successfully")}finally{_initializing=!1}}else e.logger.debug?.(`[beeos-claw] Skipping registration (mode=${e.registrationMode})`)}};export default plugin;
@@ -1 +1 @@
1
- import{toMessagePart}from"../message-client-types.js";import{extractUploadResourceLinks}from"../upload/extract-upload-uris.js";import{resolveUploadToolResultForEnrichment}from"../upload/result-cache.js";import{BEEOS_UPLOAD_TOOL_NAME}from"../upload/tool.js";import{resolveRuntimeToolArguments,resolveRuntimeToolCallId,resolveRuntimeToolName}from"./tool-envelope-metadata.js";const isNonEmptyString=e=>"string"==typeof e&&e.length>0,extractBodyUpdate=(e,t)=>{if(!isNonEmptyString(t))return{kind:"noop"};if(t===e.text)return{kind:"noop"};if(t.startsWith(e.text)){const r=t.slice(e.text.length);return e.text=t,{kind:"append",text:r}}return e.text.startsWith(t)?{kind:"noop"}:(e.text=t,{kind:"replace",text:t})};export function createImReplySink(e){const t={text:""};let r,n="",o="";const s=new Map,i=new Map,a=[],l=[];let d=0,u=0;const m=new Set,g=(t,r,n)=>{const o=u;return e.stream.appendToolUse(t,r,toMessagePart(n),"streaming"),u+=1,o},c=()=>(d+=1,`tool_${e.requestId}_${d}`),p=e=>{const t=a.indexOf(e);t>=0&&a.splice(t,1)},f=e=>{const t=e?a.filter(t=>s.get(t)?.name===e):a;return 1===t.length?t[0]:void 0},h=e=>{const t=l.map((e,t)=>({hint:e,index:t})).filter(({hint:t})=>!e||t.name===e);if(1!==t.length)return;const[{hint:r,index:n}]=t;return l.splice(n,1),r},I=(e,t)=>{i.set(e,t)},y=e=>i.get(e)??e,$=e=>null!=e&&("object"!=typeof e||(Array.isArray(e)?e.length>0:Object.keys(e).length>0)),v=(t,r,n,o)=>{const i=s.get(t);if(i){const s="tool"===i.name&&"tool"!==r?r:i.name,l=!$(i.arguments)&&$(n)?n:i.arguments;return s===i.name&&l===i.arguments||(e.stream.replacePart(i.partIndex,toMessagePart({type:"tool_use",id:i.id,name:s,arguments:l,state:i.state})),i.name=s,i.arguments=l),o&&!a.includes(t)&&"streaming"===i.state&&a.push(t),i}const l={id:t,name:r,arguments:n,partIndex:g(t,r,n),state:"streaming",itemEventObserved:!1,toolStartObserved:!1};return s.set(t,l),o&&a.push(t),l},b=t=>{"done"!==t.state&&(e.stream.replacePart(t.partIndex,toMessagePart({type:"tool_use",id:t.id,name:t.name,arguments:t.arguments,state:"done"})),t.state="done")},x=e=>{if(null===e||"object"!=typeof e)return JSON.stringify(e)??String(e);if(Array.isArray(e))return`[${e.map(x).join(",")}]`;return`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${x(t)}`).join(",")}}`},k=(t,r,n)=>{const o=`${n?"1":"0"}:${x(r)}`;if(t.progressSignature===o)return;const s=toMessagePart({type:"custom",kind:"tool_progress",data:{tool_use_id:t.id,content:r,...n?{is_error:!0}:{}}});if(void 0===t.progressPartIndex){const r=u;return e.stream.addPart(s),t.progressPartIndex=r,t.progressSignature=o,void(u+=1)}e.stream.replacePart(t.progressPartIndex,s),t.progressSignature=o},_=e=>[e.mediaUrl,...e.mediaUrls??[]].filter(e=>isNonEmptyString(e)),E=(e,t=[])=>{const r=[...new Set([..._(e),...t])];return isNonEmptyString(e.text)&&r.length>0?{text:e.text,media_urls:r}:isNonEmptyString(e.text)?e.text:1===r.length?r[0]:r.length>1?{media_urls:r}:!0===e.isError?"Tool execution failed.":""},S=(t,r)=>{if(!(e=>{if(!e)return!1;if(e===BEEOS_UPLOAD_TOOL_NAME)return!0;const t=e.toLowerCase();return t.includes("beeos_upload")||t.includes("beeos upload file")||"beeos file upload"===t})(t.name))return;if(t.durableUploadFilesEmitted)return;e.logger.info?.(`[im-sink] schedule upload enrichment requestId=${e.requestId} toolUseId=${t.id} name=${t.name}`);const n=(async()=>{let n;try{n=await resolveUploadToolResultForEnrichment(t.id,BEEOS_UPLOAD_TOOL_NAME),null!=n&&e.logger.info?.(`[im-sink] upload cache hit requestId=${e.requestId} toolUseId=${t.id}`)}catch(r){const n=r instanceof Error?r.message:String(r);e.logger.warn?.(`[im-sink] resolveUploadToolResultForEnrichment failed requestId=${e.requestId} toolUseId=${t.id} error=${n}`)}null==n&&e.logger.warn?.(`[im-sink] upload cache miss requestId=${e.requestId} toolUseId=${t.id} name=${t.name}`);let o=null!=n?extractUploadResourceLinks(n):[];0===o.length&&(o=_(r).map(e=>({uri:e,name:e.startsWith("beeos-file://")?e.slice(13):"file"}))),0!==o.length?await new Promise(n=>{e.callbackQueue.enqueueSync(()=>{try{if(e.abortSignal.aborted||e.stream.isTerminated)return;const n=o.map(e=>e.uri);k(t,E(r,n),!0===r.isError),((t,r,n)=>{if(0!==r.length&&!t.durableUploadFilesEmitted){t.durableUploadFilesEmitted=!0,e.stream.appendToolResult(t.id,r.map(e=>({type:"resource_link",uri:e.uri,name:e.name,...e.mimeType?{mimeType:e.mimeType}:{}})),n),u+=1;for(const t of r)e.stream.addPart(toMessagePart({type:"resource_link",uri:t.uri,name:t.name,...t.mimeType?{mimeType:t.mimeType}:{}})),u+=1}})(t,o,!0===r.isError)}catch(r){const n=r instanceof Error?r.message:String(r);e.logger.warn?.(`[im-sink] upload enrichment apply failed requestId=${e.requestId} toolUseId=${t.id} error=${n}`)}finally{n()}})}):e.logger.warn?.(`[im-sink] upload enrichment found no links requestId=${e.requestId} toolUseId=${t.id}`)})().catch(r=>{const n=r instanceof Error?r.message:String(r);e.logger.warn?.(`[im-sink] upload enrichment failed requestId=${e.requestId} toolUseId=${t.id} error=${n}`)});m.add(n),n.finally(()=>{m.delete(n)})},T=(e,t,r)=>{const n=i.get(e);if(n)return v(n,t??"tool",r??{},!1);if(s.has(e))return v(e,t??"tool",r??{},!1);const o=f(t);return o?(I(e,o),v(o,t??"tool",r??{},!1)):v(e,t??"tool",r??{},!1)},q=(e,t)=>{const r=i.get(e);if(r)return v(r,t,{},!1);if(s.has(e))return v(e,t,{},!1);const n=(e=>{const t=a.filter(t=>{const r=s.get(t);return!(void 0===r||e&&r.name!==e||r.itemEventObserved)});return 1===t.length?t[0]:void 0})(t);if(n)return I(e,n),v(n,t,{},!1);const o=h(t);return v(e,t,o?.arguments??{},!1)},R={tool:0,block:0,final:0};let O,w=!1;const U=(t,r)=>{e.callbackQueue.enqueueSync(()=>{if((t=>e.abortSignal.aborted?(e.logger.debug?.(`[im-sink] ${t} ignored after abort requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`),!1):e.stream.isTerminated?(e.logger.debug?.(`[im-sink] ${t} ignored after stream_terminated requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`),!1):!w||(e.logger.debug?.(`[im-sink] ${t} ignored after mark_complete requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`),!1))(t))try{r()}catch(r){const n=r instanceof Error?r.message:String(r);e.logger.warn?.(`[im-sink] ${t} mapping failed requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId} error=${n}`)}})};return{dispatcher:{sendToolResult:t=>(U("tool_progress",()=>{const r=resolveRuntimeToolCallId(t),n=resolveRuntimeToolName(t),o=r?void 0:n?f(n):f(),i=r||o?void 0:h(n);if(!r&&!o&&!i)return void e.logger.debug?.(`[im-sink] ambiguous id-less tool progress ignored requestId=${e.requestId} channel=${e.channelId} tool=${n??"unknown"} pending=${a.length}`);const l=r?T(r,n,resolveRuntimeToolArguments(t)):v(o??c(),n??s.get(o??"")?.name??i.name,$(resolveRuntimeToolArguments(t))?resolveRuntimeToolArguments(t):i?.arguments??{},!1);R.tool+=1,k(l,E(t),!0===t.isError),b(l),p(l.id),S(l,t)}),!0),sendBlockReply:r=>(U("block_reply",()=>{R.block+=1,isNonEmptyString(r.text)&&(!0!==r.isError?(O=void 0,e.stream.setBody(r.text),t.text=r.text):O=r.text)}),!0),sendFinalReply:r=>(U("final_reply",()=>{R.final+=1,isNonEmptyString(r.text)&&(!0!==r.isError?(O=void 0,e.stream.setBody(r.text),t.text=r.text):O=r.text)}),!0),waitForIdle:async()=>{for(let t=0;t<16;t++){if(await e.callbackQueue.waitForIdle(),0===m.size)return;await Promise.allSettled([...m])}await e.callbackQueue.waitForIdle()},getQueuedCounts:()=>({...R}),getAccumulatedBody:()=>t.text,getTerminalErrorText:()=>O,markComplete:t=>{if(1===l.length){const e=l.shift();v(c(),e.name,e.arguments,!1)}for(const r of s.values())try{"success"===t&&b(r),p(r.id)}catch(t){const n=t instanceof Error?t.message:String(t);e.logger.warn?.(`[im-sink] tool finalization failed requestId=${e.requestId} toolUseId=${r.id} error=${n}`)}l.length=0,w=!0}},replyOptions:{...e.runId?{runId:e.runId}:{},abortSignal:e.abortSignal,onAgentRunStart:t=>{e.onAgentRunStart?.(t),e.logger.info?.(`[im-sink] run_start requestId=${e.requestId} runId=${t} channel=${e.channelId} in_reply_to=${e.inboundMessageId} origin=${e.origin??"im"}`)},onPartialReply:r=>{U("partial",()=>{const n=extractBodyUpdate(t,r.text);switch(n.kind){case"append":e.stream.appendBody(n.text);break;case"replace":e.stream.setBody(n.text)}})},onReasoningStream:t=>{U("reasoning",()=>{if(!isNonEmptyString(t.text))return;if(!r&&(r=e.openReasoningStream?.(),!r))return;const s=t.text;""===o&&""!==n&&(r.appendBody("\n"),n+="\n"),s!==o&&(s.startsWith(o)?(r.appendBody(s.slice(o.length)),o=s):o.startsWith(s)||(r.setBody(n+s),o=s))})},onReasoningEnd:()=>{U("reasoning_end",()=>{var t;""!==o&&(t=o,e.stream.appendThinking(t,"done"),u+=1,n+=o,o="")})},onAssistantMessageStart:()=>{e.logger.debug?.(`[im-sink] assistant_message_start requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`)},onToolStart:t=>{U("tool_start",()=>{const r="string"==typeof t.phase?t.phase:"start",n=resolveRuntimeToolName(t)??"tool",o=resolveRuntimeToolCallId(t);if("update"===r){if(o){const e=y(o);s.has(e)&&v(e,n,resolveRuntimeToolArguments(t),!0)}return}const i=resolveRuntimeToolArguments(t);if(o){const e=T(o,n,i);return e.toolStartObserved=!0,void(a.includes(e.id)||"streaming"!==e.state||a.push(e.id))}const d=(u=n,a.map(e=>s.get(e)).filter(e=>void 0!==e&&(!u||e.name===u)&&e.itemEventObserved));var u;if(1===d.length){return void(v(d[0].id,n,i,!0).toolStartObserved=!0)}d.length>1?e.logger.debug?.(`[im-sink] ambiguous id-less tool start ignored requestId=${e.requestId} channel=${e.channelId} tool=${n} candidates=${d.length}`):l.push({name:n,arguments:i})})},onItemEvent:e=>{U("item_event",()=>{const t="string"==typeof e.kind?e.kind.toLowerCase():"";if(t&&"tool"!==t)return;const r="string"==typeof e.phase?e.phase.toLowerCase():"update",n=resolveRuntimeToolCallId(e)??("string"==typeof e.itemId&&e.itemId.trim()?e.itemId.trim():void 0),o=resolveRuntimeToolName(e)??("string"==typeof e.title&&e.title.trim()?e.title.trim():void 0);if(!n||!o)return;if("update"===r){const e=y(n),t=s.get(e);return void(t&&(v(t.id,o,{},!0).itemEventObserved=!0))}const i=q(n,o);i.itemEventObserved=!0,a.includes(i.id)||"streaming"!==i.state||a.push(i.id)})}}}}
1
+ import{toMessagePart}from"../message-client-types.js";import{resolveToolArtifactLinks}from"../upload/tool-artifact-enrichment.js";import{resolveRuntimeToolArguments,resolveRuntimeToolCallId,resolveRuntimeToolName}from"./tool-envelope-metadata.js";const isNonEmptyString=e=>"string"==typeof e&&e.length>0,isPlainRecord=e=>"object"==typeof e&&null!==e&&!Array.isArray(e);function pickRawResultFromPayload(e){if(void 0!==e.rawResult)return e.rawResult;if(void 0!==e.result)return e.result;if(void 0!==e.details)return e.details;if(void 0!==e.toolResult)return e.toolResult;if(isPlainRecord(e.channelData)){const t=e.channelData;if(void 0!==t.rawResult)return t.rawResult;if(void 0!==t.result)return t.result;if(void 0!==t.details)return t.details}}const extractBodyUpdate=(e,t)=>{if(!isNonEmptyString(t))return{kind:"noop"};if(t===e.text)return{kind:"noop"};if(t.startsWith(e.text)){const r=t.slice(e.text.length);return e.text=t,{kind:"append",text:r}}return e.text.startsWith(t)?{kind:"noop"}:(e.text=t,{kind:"replace",text:t})};export function createImReplySink(e){const t={text:""};let r,n="",o="";const s=new Map,i=new Map,a=[],l=[];let d=0,u=0;const m=new Set,g=(t,r,n)=>{const o=u;return e.stream.appendToolUse(t,r,toMessagePart(n),"streaming"),u+=1,o},c=()=>(d+=1,`tool_${e.requestId}_${d}`),p=e=>{const t=a.indexOf(e);t>=0&&a.splice(t,1)},f=e=>{const t=e?a.filter(t=>s.get(t)?.name===e):a;return 1===t.length?t[0]:void 0},y=e=>{const t=l.map((e,t)=>({hint:e,index:t})).filter(({hint:t})=>!e||t.name===e);if(1!==t.length)return;const[{hint:r,index:n}]=t;return l.splice(n,1),r},I=(e,t)=>{i.set(e,t)},h=e=>i.get(e)??e,v=e=>null!=e&&("object"!=typeof e||(Array.isArray(e)?e.length>0:Object.keys(e).length>0)),$=(t,r,n,o)=>{const i=s.get(t);if(i){const s="tool"===i.name&&"tool"!==r?r:i.name,l=!v(i.arguments)&&v(n)?n:i.arguments;return s===i.name&&l===i.arguments||(e.stream.replacePart(i.partIndex,toMessagePart({type:"tool_use",id:i.id,name:s,arguments:l,state:i.state})),i.name=s,i.arguments=l),o&&!a.includes(t)&&"streaming"===i.state&&a.push(t),i}const l={id:t,name:r,arguments:n,partIndex:g(t,r,n),state:"streaming",itemEventObserved:!1,toolStartObserved:!1};return s.set(t,l),o&&a.push(t),l},k=t=>{"done"!==t.state&&(e.stream.replacePart(t.partIndex,toMessagePart({type:"tool_use",id:t.id,name:t.name,arguments:t.arguments,state:"done"})),t.state="done")},x=e=>{if(null===e||"object"!=typeof e)return JSON.stringify(e)??String(e);if(Array.isArray(e))return`[${e.map(x).join(",")}]`;return`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${x(t)}`).join(",")}}`},b=(t,r,n)=>{const o=`${n?"1":"0"}:${x(r)}`;if(t.progressSignature===o)return;const s=toMessagePart({type:"custom",kind:"tool_progress",data:{tool_use_id:t.id,content:r,...n?{is_error:!0}:{}}});if(void 0===t.progressPartIndex){const r=u;return e.stream.addPart(s),t.progressPartIndex=r,t.progressSignature=o,void(u+=1)}e.stream.replacePart(t.progressPartIndex,s),t.progressSignature=o},R=e=>[e.mediaUrl,...e.mediaUrls??[]].filter(e=>isNonEmptyString(e)),S=(e,t=[])=>{const r=[...new Set([...R(e),...t])];return isNonEmptyString(e.text)&&r.length>0?{text:e.text,media_urls:r}:isNonEmptyString(e.text)?e.text:1===r.length?r[0]:r.length>1?{media_urls:r}:!0===e.isError?"Tool execution failed.":""},_=(t,r)=>{if(t.durableUploadFilesEmitted)return;e.logger.info?.(`[im-sink] schedule tool artifact enrichment requestId=${e.requestId} toolUseId=${t.id} name=${t.name}`);const n=pickRawResultFromPayload(r),o=(async()=>{let o=[];try{o=await resolveToolArtifactLinks({toolCallId:t.id,toolName:t.name,rawResult:n,rawText:"string"==typeof r.text?r.text:void 0,payloadMediaUrls:R(r)})}catch(r){const n=r instanceof Error?r.message:String(r);return void e.logger.warn?.(`[im-sink] resolveToolArtifactLinks failed requestId=${e.requestId} toolUseId=${t.id} error=${n}`)}0!==o.length?(e.logger.info?.(`[im-sink] tool artifact enrichment resolved ${o.length} link(s) requestId=${e.requestId} toolUseId=${t.id}`),await new Promise(n=>{e.callbackQueue.enqueueSync(()=>{try{if(e.abortSignal.aborted||e.stream.isTerminated)return;const n=o.map(e=>e.uri);b(t,S(r,n),!0===r.isError),((t,r,n)=>{if(0!==r.length&&!t.durableUploadFilesEmitted){t.durableUploadFilesEmitted=!0,e.stream.appendToolResult(t.id,r.map(e=>({type:"resource_link",uri:e.uri,name:e.name,...e.mimeType?{mimeType:e.mimeType}:{}})),n),u+=1;for(const t of r)e.stream.addPart(toMessagePart({type:"resource_link",uri:t.uri,name:t.name,...t.mimeType?{mimeType:t.mimeType}:{}})),u+=1}})(t,o,!0===r.isError)}catch(r){const n=r instanceof Error?r.message:String(r);e.logger.warn?.(`[im-sink] tool artifact enrichment apply failed requestId=${e.requestId} toolUseId=${t.id} error=${n}`)}finally{n()}})})):e.logger.debug?.(`[im-sink] tool artifact enrichment found no links requestId=${e.requestId} toolUseId=${t.id} name=${t.name}`)})().catch(r=>{const n=r instanceof Error?r.message:String(r);e.logger.warn?.(`[im-sink] tool artifact enrichment failed requestId=${e.requestId} toolUseId=${t.id} error=${n}`)});m.add(o),o.finally(()=>{m.delete(o)})},T=(e,t,r)=>{const n=i.get(e);if(n)return $(n,t??"tool",r??{},!1);if(s.has(e))return $(e,t??"tool",r??{},!1);const o=f(t);return o?(I(e,o),$(o,t??"tool",r??{},!1)):$(e,t??"tool",r??{},!1)},q=(e,t)=>{const r=i.get(e);if(r)return $(r,t,{},!1);if(s.has(e))return $(e,t,{},!1);const n=(e=>{const t=a.filter(t=>{const r=s.get(t);return!(void 0===r||e&&r.name!==e||r.itemEventObserved)});return 1===t.length?t[0]:void 0})(t);if(n)return I(e,n),$(n,t,{},!1);const o=y(t);return $(e,t,o?.arguments??{},!1)},w={tool:0,block:0,final:0};let E,P=!1;const A=(t,r)=>{e.callbackQueue.enqueueSync(()=>{if((t=>e.abortSignal.aborted?(e.logger.debug?.(`[im-sink] ${t} ignored after abort requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`),!1):e.stream.isTerminated?(e.logger.debug?.(`[im-sink] ${t} ignored after stream_terminated requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`),!1):!P||(e.logger.debug?.(`[im-sink] ${t} ignored after mark_complete requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`),!1))(t))try{r()}catch(r){const n=r instanceof Error?r.message:String(r);e.logger.warn?.(`[im-sink] ${t} mapping failed requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId} error=${n}`)}})};return{dispatcher:{sendToolResult:t=>(A("tool_progress",()=>{const r=resolveRuntimeToolCallId(t),n=resolveRuntimeToolName(t),o=r?void 0:n?f(n):f(),i=r||o?void 0:y(n);if(!r&&!o&&!i)return void e.logger.debug?.(`[im-sink] ambiguous id-less tool progress ignored requestId=${e.requestId} channel=${e.channelId} tool=${n??"unknown"} pending=${a.length}`);const l=r?T(r,n,resolveRuntimeToolArguments(t)):$(o??c(),n??s.get(o??"")?.name??i.name,v(resolveRuntimeToolArguments(t))?resolveRuntimeToolArguments(t):i?.arguments??{},!1);w.tool+=1,b(l,S(t),!0===t.isError),k(l),p(l.id),_(l,t)}),!0),sendBlockReply:r=>(A("block_reply",()=>{w.block+=1,isNonEmptyString(r.text)&&(!0!==r.isError?(E=void 0,e.stream.setBody(r.text),t.text=r.text):E=r.text)}),!0),sendFinalReply:r=>(A("final_reply",()=>{w.final+=1,isNonEmptyString(r.text)&&(!0!==r.isError?(E=void 0,e.stream.setBody(r.text),t.text=r.text):E=r.text)}),!0),waitForIdle:async()=>{for(let t=0;t<16;t++){if(await e.callbackQueue.waitForIdle(),0===m.size)return;await Promise.allSettled([...m])}await e.callbackQueue.waitForIdle()},getQueuedCounts:()=>({...w}),getAccumulatedBody:()=>t.text,getTerminalErrorText:()=>E,markComplete:t=>{if(1===l.length){const e=l.shift();$(c(),e.name,e.arguments,!1)}for(const r of s.values())try{"success"===t&&k(r),p(r.id)}catch(t){const n=t instanceof Error?t.message:String(t);e.logger.warn?.(`[im-sink] tool finalization failed requestId=${e.requestId} toolUseId=${r.id} error=${n}`)}l.length=0,P=!0}},replyOptions:{...e.runId?{runId:e.runId}:{},abortSignal:e.abortSignal,onAgentRunStart:t=>{e.onAgentRunStart?.(t),e.logger.info?.(`[im-sink] run_start requestId=${e.requestId} runId=${t} channel=${e.channelId} in_reply_to=${e.inboundMessageId} origin=${e.origin??"im"}`)},onPartialReply:r=>{A("partial",()=>{const n=extractBodyUpdate(t,r.text);switch(n.kind){case"append":e.stream.appendBody(n.text);break;case"replace":e.stream.setBody(n.text)}})},onReasoningStream:t=>{A("reasoning",()=>{if(!isNonEmptyString(t.text))return;if(!r&&(r=e.openReasoningStream?.(),!r))return;const s=t.text;""===o&&""!==n&&(r.appendBody("\n"),n+="\n"),s!==o&&(s.startsWith(o)?(r.appendBody(s.slice(o.length)),o=s):o.startsWith(s)||(r.setBody(n+s),o=s))})},onReasoningEnd:()=>{A("reasoning_end",()=>{var t;""!==o&&(t=o,e.stream.appendThinking(t,"done"),u+=1,n+=o,o="")})},onAssistantMessageStart:()=>{e.logger.debug?.(`[im-sink] assistant_message_start requestId=${e.requestId} channel=${e.channelId} in_reply_to=${e.inboundMessageId}`)},onToolStart:t=>{A("tool_start",()=>{const r="string"==typeof t.phase?t.phase:"start",n=resolveRuntimeToolName(t)??"tool",o=resolveRuntimeToolCallId(t);if("update"===r){if(o){const e=h(o);s.has(e)&&$(e,n,resolveRuntimeToolArguments(t),!0)}return}const i=resolveRuntimeToolArguments(t);if(o){const e=T(o,n,i);return e.toolStartObserved=!0,void(a.includes(e.id)||"streaming"!==e.state||a.push(e.id))}const d=(u=n,a.map(e=>s.get(e)).filter(e=>void 0!==e&&(!u||e.name===u)&&e.itemEventObserved));var u;if(1===d.length){return void($(d[0].id,n,i,!0).toolStartObserved=!0)}d.length>1?e.logger.debug?.(`[im-sink] ambiguous id-less tool start ignored requestId=${e.requestId} channel=${e.channelId} tool=${n} candidates=${d.length}`):l.push({name:n,arguments:i})})},onItemEvent:e=>{A("item_event",()=>{const t="string"==typeof e.kind?e.kind.toLowerCase():"";if(t&&"tool"!==t)return;const r="string"==typeof e.phase?e.phase.toLowerCase():"update",n=resolveRuntimeToolCallId(e)??("string"==typeof e.itemId&&e.itemId.trim()?e.itemId.trim():void 0),o=resolveRuntimeToolName(e)??("string"==typeof e.title&&e.title.trim()?e.title.trim():void 0);if(!n||!o)return;if("update"===r){const e=h(n),t=s.get(e);return void(t&&($(t.id,o,{},!0).itemEventObserved=!0))}const i=q(n,o);i.itemEventObserved=!0,a.includes(i.id)||"streaming"!==i.state||a.push(i.id)})}}}}
@@ -0,0 +1 @@
1
+ import{access,constants}from"node:fs/promises";import{execFile}from"node:child_process";import{promisify}from"node:util";import{uploadLocalFile}from"./upload-file.js";const execFileAsync=promisify(execFile);export const BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME="beeos_desktop_screenshot";export const BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION="Capture the agent desktop (DISPLAY) via platform beeos-screenshot, then upload for the user. Prefer this over shell/python X11 dumps. Do not invent raw Xlib/PIL capture — those produce RGB striping. Requires openclaw-desktop image with scrot (or ImageMagick import) and /usr/local/bin/beeos-screenshot.";export const BEEOS_DESKTOP_SCREENSHOT_TOOL_SCHEMA={title:"BeeOS desktop screenshot",type:"object",description:BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION,additionalProperties:!1,properties:{path:{type:"string",minLength:1,description:"Local filesystem path for the PNG capture (default: /tmp/desktop.png)."},upload:{type:"boolean",description:"When true (default), upload the capture so the user sees a chat preview."}}};const DEFAULT_PATH="/tmp/desktop.png",REQUEST_TIMEOUT_MS=12e4,CAPTURE_TIMEOUT_MS=3e4,SCREENSHOT_BINARIES=["/usr/local/bin/beeos-screenshot","beeos-screenshot"],MISSING_BINARY_MSG="beeos-screenshot not found on PATH. Use the openclaw-desktop image with scrot installed, or install scrot + /usr/local/bin/beeos-screenshot. Do not fall back to raw Xlib/PIL capture.";let _deps={};export function setDesktopScreenshotDeps(e){_deps=e}export function resetDesktopScreenshotDeps(){_deps={}}export async function executeDesktopScreenshot(e,t,r,o){const s=parseParams(e);if(!s.ok)return errorResult(s.error);const{path:n,upload:a}=s,i=_deps.execFile??execFileAsync,p=_deps.resolveBinary?await _deps.resolveBinary():await resolveScreenshotBinary();if(!p)return errorResult(MISSING_BINARY_MSG);try{await i(p,[n],{timeout:3e4,env:{...process.env,DISPLAY:process.env.DISPLAY||":1"},signal:o})}catch(e){if(o?.aborted)throw e;if("ENOENT"===e.code)return errorResult(MISSING_BINARY_MSG);return errorResult(`desktop capture failed: ${e instanceof Error?e.message:String(e)}`)}try{await access(n,constants.R_OK)}catch{return errorResult(`capture produced no readable file at ${n}`)}if(!a){const e={ok:!0,path:n};return{...e,content:[{type:"text",text:`Desktop captured to ${n} (not uploaded)`}],output:e,result:e,details:e,isError:!1}}if(!t.agentGatewayUrl)return errorResult("agentGatewayUrl not configured — file upload requires Agent Gateway access");if(!r)return errorResult("agent key pair not available — cannot sign upload requests");const c=_deps.uploadLocalFile??uploadLocalFile;try{const e=await c(n,t.agentGatewayUrl,r,{signal:o,timeoutMs:12e4,fileNameOverride:`desktop-${Date.now()}.png`}),s=[{uri:e.uri,name:e.name,mimeType:e.mimeType,fileId:e.fileId}],a=`Desktop screenshot uploaded: ${s[0].name}`,i={ok:!0,path:n,files:s};return{...i,content:[{type:"text",text:a},{type:"resource_link",uri:s[0].uri,name:s[0].name,mimeType:s[0].mimeType}],output:i,result:i,details:i,isError:!1}}catch(e){if(o?.aborted)throw e;return errorResult(`capture ok at ${n} but upload failed: ${e instanceof Error?e.message:String(e)}`)}}async function resolveScreenshotBinary(){for(const e of SCREENSHOT_BINARIES){if(!e.includes("/"))return e;try{return await access(e,constants.X_OK),e}catch{continue}}return null}function parseParams(e){if(null==e)return{ok:!0,path:DEFAULT_PATH,upload:!0};if("object"!=typeof e)return{ok:!1,error:"params must be an object"};const t=e,r=new Set(["path","upload"]),o=Object.keys(t).filter(e=>!r.has(e));if(o.length>0)return{ok:!1,error:`unknown params: ${o.join(", ")}`};let s=DEFAULT_PATH;if(void 0!==t.path){if("string"!=typeof t.path||""===t.path.trim())return{ok:!1,error:"path must be a non-empty string"};s=t.path.trim()}let n=!0;if(void 0!==t.upload){if("boolean"!=typeof t.upload)return{ok:!1,error:"upload must be a boolean"};n=t.upload}return{ok:!0,path:s,upload:n}}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
- export{BEEOS_UPLOAD_TOOL_NAME,BEEOS_UPLOAD_TOOL_SCHEMA,BEEOS_UPLOAD_TOOL_DESCRIPTION,executeUpload}from"./tool.js";export{writeUploadToolResult,cleanupUploadToolResultCache,writeEnrichmentCache,readEnrichmentCache}from"./result-cache.js";export{extractUploadMediaUrls,extractUploadResourceLinks}from"./extract-upload-uris.js";export{handleFileStage}from"./file-stage.js";export{uploadLocalFile,setUploadDeps,getUploadDeps}from"./upload-file.js";export{registerLocalFileExtractor,tryExtractLocalFiles}from"./local-file-extractors.js";
1
+ export{BEEOS_UPLOAD_TOOL_NAME,BEEOS_UPLOAD_TOOL_SCHEMA,BEEOS_UPLOAD_TOOL_DESCRIPTION,executeUpload}from"./tool.js";export{BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME,BEEOS_DESKTOP_SCREENSHOT_TOOL_SCHEMA,BEEOS_DESKTOP_SCREENSHOT_TOOL_DESCRIPTION,executeDesktopScreenshot}from"./desktop-screenshot-tool.js";export{writeUploadToolResult,cleanupUploadToolResultCache,writeEnrichmentCache,readEnrichmentCache,resolveUploadToolResultForEnrichment}from"./result-cache.js";export{extractUploadMediaUrls,extractUploadResourceLinks}from"./extract-upload-uris.js";export{resolveToolArtifactLinks,isUploadArtifactToolName,isLocalMediaPath,isRemoteOrPlatformMediaUri}from"./tool-artifact-enrichment.js";export{handleFileStage}from"./file-stage.js";export{uploadLocalFile,setUploadDeps,getUploadDeps}from"./upload-file.js";export{registerLocalFileExtractor,tryExtractLocalFiles}from"./local-file-extractors.js";
@@ -1 +1 @@
1
- import{randomUUID}from"node:crypto";import{mkdir,readFile,rename,stat,unlink,readdir}from"node:fs/promises";import{writeFile}from"node:fs/promises";import{homedir}from"node:os";import{join}from"node:path";const CACHE_TTL_MS=864e5,ENRICHMENT_CACHE_TTL_MS=2592e6,ENRICHMENT_PREFIX="enrich_",CACHE_VERSION=1;function cacheDir(){return join(process.env.OPENCLAW_HOME||join(homedir(),".openclaw"),"beeos-claw","upload_meta")}function safeToolCallId(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_")}function cachePath(e){return join(cacheDir(),`${safeToolCallId(e)}.json`)}async function safeUnlink(e){try{await unlink(e)}catch{}}export async function writeUploadToolResult(e,t,a){await mkdir(cacheDir(),{recursive:!0,mode:448});const n={version:1,createdAt:Date.now(),toolCallId:e,toolName:t,result:a},r=async e=>{const t=`${e}.${randomUUID()}.tmp`;await writeFile(t,JSON.stringify(n),{encoding:"utf8",mode:384}),await rename(t,e)};await r(cachePath(e)),"beeos_upload_file"===t&&await r(cachePath("latest_beeos_upload_file"))}export async function readUploadToolResult(e){const t=cachePath(e);let a,n,r;try{a=await stat(t)}catch{return}if(Date.now()-a.mtimeMs>=864e5)await safeUnlink(t);else{try{n=await readFile(t,"utf8")}catch{return}try{r=JSON.parse(n)}catch{return void await safeUnlink(t)}if(r&&1===r.version&&"number"==typeof r.createdAt&&!(Date.now()-r.createdAt>=864e5))return r.result;await safeUnlink(t)}}export function uploadCacheIdCandidates(e){const t=e.trim();if(!t)return[];const a=t.startsWith("tool:")?t.slice(5):t,n=[t,a,safeToolCallId(t),safeToolCallId(a)];return[...new Set(n.filter(e=>e.length>0))]}export async function resolveUploadToolResultForEnrichment(e,t="beeos_upload_file",a){const n=Math.max(1,a?.attempts??6),r=Math.max(0,a?.delayMs??40),o=uploadCacheIdCandidates(e);for(let e=0;e<n;e++){for(const e of o){const t=await readUploadToolResult(e);if(null!=t)return t}const a=await readUploadToolResult("latest_beeos_upload_file");if(null!=a)return a;const i=await readLatestUploadToolResult(t);if(null!=i)return i;e+1<n&&r>0&&await new Promise(t=>setTimeout(t,r*(e+1)))}}export async function readLatestUploadToolResult(e,t=12e4){let a;try{a=await readdir(cacheDir())}catch{return}const n=Date.now();let r;for(const o of a){if(!o.endsWith(".json")||o.startsWith("enrich_"))continue;const a=join(cacheDir(),o);let i,c;try{i=await readFile(a,"utf8")}catch{continue}try{c=JSON.parse(i)}catch{continue}!c||1!==c.version||c.toolName!==e||"number"!=typeof c.createdAt||n-c.createdAt>=t||n-c.createdAt>=864e5||(!r||c.createdAt>r.createdAt)&&(r={createdAt:c.createdAt,result:c.result})}return r?.result}function enrichmentCachePath(e){return join(cacheDir(),`enrich_${safeToolCallId(e)}.json`)}export async function writeEnrichmentCache(e,t){if(0===t.length)return;await mkdir(cacheDir(),{recursive:!0,mode:448});const a={version:1,createdAt:Date.now(),toolCallId:e,resourceLinks:t},n=enrichmentCachePath(e),r=`${n}.${randomUUID()}.tmp`;await writeFile(r,JSON.stringify(a),{encoding:"utf8",mode:384}),await rename(r,n)}export async function readEnrichmentCache(e){const t=enrichmentCachePath(e);let a,n,r;try{a=await stat(t)}catch{return}if(Date.now()-a.mtimeMs>=2592e6)await safeUnlink(t);else{try{n=await readFile(t,"utf8")}catch{return}try{r=JSON.parse(n)}catch{return void await safeUnlink(t)}if(r&&1===r.version&&"number"==typeof r.createdAt&&Array.isArray(r.resourceLinks)&&!(Date.now()-r.createdAt>=2592e6))return r.resourceLinks;await safeUnlink(t)}}export async function cleanupUploadToolResultCache(){let e;try{e=await readdir(cacheDir(),{withFileTypes:!0})}catch{return 0}const t=Date.now();let a=0;for(const n of e){if(!n.isFile())continue;if(!n.name.endsWith(".json")&&!n.name.endsWith(".tmp"))continue;const e=join(cacheDir(),n.name),r=n.name.startsWith("enrich_")?2592e6:864e5;try{t-(await stat(e)).mtimeMs>=r&&(await unlink(e),a++)}catch{}}return a}
1
+ import{randomUUID}from"node:crypto";import{mkdir,readFile,rename,stat,unlink,readdir}from"node:fs/promises";import{writeFile}from"node:fs/promises";import{homedir}from"node:os";import{join}from"node:path";const CACHE_TTL_MS=864e5,ENRICHMENT_CACHE_TTL_MS=2592e6,ENRICHMENT_PREFIX="enrich_",CACHE_VERSION=1;function cacheDir(){return join(process.env.OPENCLAW_HOME||join(homedir(),".openclaw"),"beeos-claw","upload_meta")}function safeToolCallId(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_")}function cachePath(e){return join(cacheDir(),`${safeToolCallId(e)}.json`)}async function safeUnlink(e){try{await unlink(e)}catch{}}export async function writeUploadToolResult(e,t,a){await mkdir(cacheDir(),{recursive:!0,mode:448});const n={version:1,createdAt:Date.now(),toolCallId:e,toolName:t,result:a},r=async e=>{const t=`${e}.${randomUUID()}.tmp`;await writeFile(t,JSON.stringify(n),{encoding:"utf8",mode:384}),await rename(t,e)};await r(cachePath(e)),"beeos_upload_file"!==t&&"beeos_desktop_screenshot"!==t||await r(cachePath("latest_beeos_upload_file"))}export async function readUploadToolResult(e){const t=cachePath(e);let a,n,r;try{a=await stat(t)}catch{return}if(Date.now()-a.mtimeMs>=864e5)await safeUnlink(t);else{try{n=await readFile(t,"utf8")}catch{return}try{r=JSON.parse(n)}catch{return void await safeUnlink(t)}if(r&&1===r.version&&"number"==typeof r.createdAt&&!(Date.now()-r.createdAt>=864e5))return r.result;await safeUnlink(t)}}export function uploadCacheIdCandidates(e){const t=e.trim();if(!t)return[];const a=t.startsWith("tool:")?t.slice(5):t,n=[t,a,safeToolCallId(t),safeToolCallId(a)];return[...new Set(n.filter(e=>e.length>0))]}export async function resolveUploadToolResultForEnrichment(e,t="beeos_upload_file",a){const n=Math.max(1,a?.attempts??6),r=Math.max(0,a?.delayMs??40),o=uploadCacheIdCandidates(e);for(let e=0;e<n;e++){for(const e of o){const t=await readUploadToolResult(e);if(null!=t)return t}const a=await readUploadToolResult("latest_beeos_upload_file");if(null!=a)return a;const i=await readLatestUploadToolResult(t);if(null!=i)return i;e+1<n&&r>0&&await new Promise(t=>setTimeout(t,r*(e+1)))}}export async function readLatestUploadToolResult(e,t=12e4){let a;try{a=await readdir(cacheDir())}catch{return}const n=Date.now();let r;for(const o of a){if(!o.endsWith(".json")||o.startsWith("enrich_"))continue;const a=join(cacheDir(),o);let i,c;try{i=await readFile(a,"utf8")}catch{continue}try{c=JSON.parse(i)}catch{continue}!c||1!==c.version||c.toolName!==e||"number"!=typeof c.createdAt||n-c.createdAt>=t||n-c.createdAt>=864e5||(!r||c.createdAt>r.createdAt)&&(r={createdAt:c.createdAt,result:c.result})}return r?.result}function enrichmentCachePath(e){return join(cacheDir(),`enrich_${safeToolCallId(e)}.json`)}export async function writeEnrichmentCache(e,t){if(0===t.length)return;await mkdir(cacheDir(),{recursive:!0,mode:448});const a={version:1,createdAt:Date.now(),toolCallId:e,resourceLinks:t},n=enrichmentCachePath(e),r=`${n}.${randomUUID()}.tmp`;await writeFile(r,JSON.stringify(a),{encoding:"utf8",mode:384}),await rename(r,n)}export async function readEnrichmentCache(e){const t=enrichmentCachePath(e);let a,n,r;try{a=await stat(t)}catch{return}if(Date.now()-a.mtimeMs>=2592e6)await safeUnlink(t);else{try{n=await readFile(t,"utf8")}catch{return}try{r=JSON.parse(n)}catch{return void await safeUnlink(t)}if(r&&1===r.version&&"number"==typeof r.createdAt&&Array.isArray(r.resourceLinks)&&!(Date.now()-r.createdAt>=2592e6))return r.resourceLinks;await safeUnlink(t)}}export async function cleanupUploadToolResultCache(){let e;try{e=await readdir(cacheDir(),{withFileTypes:!0})}catch{return 0}const t=Date.now();let a=0;for(const n of e){if(!n.isFile())continue;if(!n.name.endsWith(".json")&&!n.name.endsWith(".tmp"))continue;const e=join(cacheDir(),n.name),r=n.name.startsWith("enrich_")?2592e6:864e5;try{t-(await stat(e)).mtimeMs>=r&&(await unlink(e),a++)}catch{}}return a}
@@ -0,0 +1 @@
1
+ import{basename}from"node:path";import{BEEOS_UPLOAD_TOOL_NAME}from"./tool.js";import{BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME}from"./desktop-screenshot-tool.js";import{extractUploadResourceLinks}from"./extract-upload-uris.js";import{resolveUploadToolResultForEnrichment,writeEnrichmentCache}from"./result-cache.js";import{tryExtractLocalFiles}from"./local-file-extractors.js";import{getUploadDeps,uploadLocalFile}from"./upload-file.js";const UPLOAD_TOOL_NAMES=new Set([BEEOS_UPLOAD_TOOL_NAME,BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME]);export function isUploadArtifactToolName(e){if(!e)return!1;if(UPLOAD_TOOL_NAMES.has(e))return!0;const t=e.toLowerCase();return t.includes("beeos_upload")||t.includes("beeos upload file")||"beeos file upload"===t||t.includes("beeos_desktop_screenshot")||t.includes("desktop screenshot")}export function isRemoteOrPlatformMediaUri(e){const t=e.trim();return!!t&&(!!t.startsWith("beeos-file://")||(!(!t.startsWith("http://")&&!t.startsWith("https://"))||!!t.startsWith("data:")))}export function isLocalMediaPath(e){const t=e.trim();return!(!t||isRemoteOrPlatformMediaUri(t))&&(!!t.startsWith("file://")||!!t.startsWith("/"))}function filePathFromMediaUri(e){const t=e.trim();if(t.startsWith("file://"))try{return decodeURIComponent(new URL(t).pathname)}catch{return t.slice(7)}return t}function linkNameFromUri(e){if(e.startsWith("beeos-file://"))return e.slice(13)||"file";try{const t=e.includes("://")?new URL(e).pathname:e;return basename(t)||"file"}catch{return"file"}}function pushUnique(e,t,o){o.uri&&!t.has(o.uri)&&(t.add(o.uri),e.push(o))}export async function resolveToolArtifactLinks(e){const t=[],o=new Set,a=getUploadDeps(),i=a?.logger;let r=!1;if(isUploadArtifactToolName(e.toolName))try{const a=await resolveUploadToolResultForEnrichment(e.toolCallId,e.toolName===BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME?BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME:BEEOS_UPLOAD_TOOL_NAME);if(null!=a)for(const e of extractUploadResourceLinks(a))pushUnique(t,o,e)}catch(t){i?.warn?.(`[enrich] resolveUploadToolResultForEnrichment failed toolCallId=${e.toolCallId}: ${t instanceof Error?t.message:String(t)}`)}if(a){const l=new Set,s=tryExtractLocalFiles({toolCallId:e.toolCallId,toolName:e.toolName,rawResult:e.rawResult,rawText:e.rawText});for(const n of s)if(!l.has(n.filePath))try{i?.debug?.(`[enrich] Uploading local file ${n.filePath} for toolCallId=${e.toolCallId}`);const s=await uploadLocalFile(n.filePath,a.gatewayUrl,a.keys,{fileNameOverride:n.suggestedName});i?.info?.(`[enrich] Uploaded: fileId=${s.fileId} toolCallId=${e.toolCallId}`),l.add(n.filePath),pushUnique(t,o,{uri:s.uri,name:s.name,...s.mimeType?{mimeType:s.mimeType}:{}}),r=!0}catch(e){i?.warn?.(`[enrich] Upload failed for ${n.filePath}: ${e instanceof Error?e.message:String(e)}, skipping`)}for(const s of e.payloadMediaUrls??[]){if(!isLocalMediaPath(s))continue;const n=filePathFromMediaUri(s);if(!l.has(n))try{i?.debug?.(`[enrich] Uploading payload media path ${n} for toolCallId=${e.toolCallId}`);const s=await uploadLocalFile(n,a.gatewayUrl,a.keys);i?.info?.(`[enrich] Uploaded payload media: fileId=${s.fileId} toolCallId=${e.toolCallId}`),l.add(n),pushUnique(t,o,{uri:s.uri,name:s.name,...s.mimeType?{mimeType:s.mimeType}:{}}),r=!0}catch(e){i?.warn?.(`[enrich] Payload media upload failed for ${n}: ${e instanceof Error?e.message:String(e)}, skipping`)}}}for(const a of e.payloadMediaUrls??[])isRemoteOrPlatformMediaUri(a)&&pushUnique(t,o,{uri:a.trim(),name:linkNameFromUri(a.trim())});if(t.length>0&&(r||t.some(e=>e.uri.startsWith("beeos-file://")))){const o=t.map(e=>({uri:e.uri,name:e.name,...e.mimeType?{mimeType:e.mimeType}:{}}));writeEnrichmentCache(e.toolCallId,o).catch(t=>{i?.warn?.(`[enrich] Cache write failed for toolCallId=${e.toolCallId}: ${t instanceof Error?t.message:String(t)}`)})}return t}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beeos-claw",
3
- "version": "0.6.44-staging.2",
3
+ "version": "0.6.44-staging.4",
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>",