beeos-claw 0.6.44-staging.3 → 0.6.44-staging.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/acp-gateway/tool-result-payload-strategies.js +1 -1
- package/dist/browser/screenshot-upload.js +1 -1
- package/dist/runtime/im-reply-sink.js +1 -1
- package/dist/upload/index.js +1 -1
- package/dist/upload/result-cache.js +1 -1
- package/dist/upload/tool-artifact-enrichment.js +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readUploadToolResult
|
|
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
|
|
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}
|
|
@@ -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{BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME}from"../upload/desktop-screenshot-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)),_=(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},E=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")},v=e=>{if(null===e||"object"!=typeof e)return JSON.stringify(e)??String(e);if(Array.isArray(e))return`[${e.map(v).join(",")}]`;return`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${v(t)}`).join(",")}}`},b=(t,r,n)=>{const o=`${n?"1":"0"}:${v(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},S=e=>[e.mediaUrl,...e.mediaUrls??[]].filter(e=>isNonEmptyString(e)),k=(e,t=[])=>{const r=[...new Set([...S(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.":""},x=(t,r)=>{if(!(e=>{if(!e)return!1;if(e===BEEOS_UPLOAD_TOOL_NAME||e===BEEOS_DESKTOP_SCREENSHOT_TOOL_NAME)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")})(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=S(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);b(t,k(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 _(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)},O=(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=h(t);return _(e,t,o?.arguments??{},!1)},q={tool:0,block:0,final:0};let R,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)):_(o??c(),n??s.get(o??"")?.name??i.name,$(resolveRuntimeToolArguments(t))?resolveRuntimeToolArguments(t):i?.arguments??{},!1);q.tool+=1,b(l,k(t),!0===t.isError),E(l),p(l.id),x(l,t)}),!0),sendBlockReply:r=>(U("block_reply",()=>{q.block+=1,isNonEmptyString(r.text)&&(!0!==r.isError?(R=void 0,e.stream.setBody(r.text),t.text=r.text):R=r.text)}),!0),sendFinalReply:r=>(U("final_reply",()=>{q.final+=1,isNonEmptyString(r.text)&&(!0!==r.isError?(R=void 0,e.stream.setBody(r.text),t.text=r.text):R=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:()=>({...q}),getAccumulatedBody:()=>t.text,getTerminalErrorText:()=>R,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&&E(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)&&_(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=>{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&&(_(t.id,o,{},!0).itemEventObserved=!0))}const i=O(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)})}}}}
|
package/dist/upload/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
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}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&&"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
|
|
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=Math.max(0,a?.latestMaxAgeMs??5e3),i=uploadCacheIdCandidates(e);for(let e=0;e<n;e++){for(const e of i){const t=await readUploadToolResult(e);if(null!=t)return t}if(e>=Math.max(1,n-2)&&o>0){const e=await readLatestUploadToolResult(t,o);if(null!=e)return e}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.
|
|
3
|
+
"version": "0.6.44-staging.5",
|
|
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>",
|