beeos-claw 0.6.63-cloud.5 → 0.6.63-cloud.7
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/a2a/tools.js +1 -1
- package/dist/acp-gateway/beeos-file-resolver.js +1 -1
- package/dist/acp-gateway/bridge-core.js +1 -1
- package/dist/acp-gateway/gateway-events.js +1 -1
- package/dist/acp-server.js +1 -1
- package/dist/agent-sync.js +1 -1
- package/dist/automation/tools.js +1 -0
- package/dist/automation/turn-policy.js +1 -0
- package/dist/automation/wake.js +1 -0
- package/dist/canvas/relay-client.js +1 -1
- package/dist/canvas/ws-provider.js +1 -1
- package/dist/connectors/managed-connector-tools.js +1 -0
- package/dist/files/fetch-tool.js +1 -1
- package/dist/files/list-tool.js +1 -1
- package/dist/im-inbound-handler.js +1 -1
- package/dist/im-runtime-dispatch.js +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp-connector-proxy.js +1 -1
- package/dist/runtime/agent-projection-production.js +1 -1
- package/dist/runtime/ms-runtime-message-channel-adapter.js +1 -1
- package/dist/runtime/ms-runtime-message-channel-consumer-factory.js +1 -1
- package/dist/runtime/ms-runtime-rpc-adapter.js +1 -1
- package/dist/runtime/native-cloud-chat-composition.js +1 -1
- package/dist/runtime/native-cloud-prompt-bridge.js +1 -1
- package/dist/runtime/native-prompt-preflight.js +1 -1
- package/dist/runtime/runtime-operation-resource-resolver.js +1 -1
- package/dist/runtime/runtime-production-authority.js +1 -1
- package/dist/runtime/runtime-registration-identity-store.js +1 -1
- package/dist/runtime/runtime-service-production-candidate.js +1 -1
- package/dist/runtime/service-runtime-attempt-ports-resolver.js +1 -1
- package/dist/terminal/runtime-terminal-outbound-registration.js +1 -1
- package/dist/terminal/terminal-lease-bound-bridge-client.js +1 -1
- package/dist/upload/desktop-screenshot-tool.js +1 -1
- package/dist/upload/finalize-hook.js +1 -1
- package/dist/upload/tool-artifact-enrichment.js +1 -1
- package/dist/upload/tool.js +1 -1
- package/dist/upload/upload-file.js +1 -1
- package/openclaw.plugin.json +15 -1
- package/package.json +4 -4
- package/dist/agent-auth.js +0 -1
- package/dist/bridge-discovery.js +0 -1
- package/dist/runtime/agent-gateway-runtime-attempt-authorization.js +0 -1
- package/dist/runtime/message-service-runtime-invocation-authority.js +0 -1
- package/dist/runtime/runtime-jwks-verifier.js +0 -1
- package/dist/runtime/runtime-registration.js +0 -1
- package/dist/runtime/runtime-transport-failure-policy.js +0 -1
- package/dist/runtime/split-runtime-authorization-verifier.js +0 -1
package/dist/a2a/tools.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{agentFetch}from"../agent-auth.js";import{resolveAgentIdFromMentions}from"../delegation/mention-resolver.js";async function a2aFetch(t,e,a){const n=`${t.agentGatewayUrl}${e}`;return t.agentKeys?agentFetch(n,t.agentKeys,a):fetch(n,a)}export{a2aFetch};export async function completeA2ATask(t,e,a,n){const s=await a2aFetch(t,`/api/v1/a2a/tasks/${encodeURIComponent(e)}/complete`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({result:n?"":a,error:n})});if(!s.ok)throw new Error(`A2A CompleteTask failed: ${s.status}`)}function normalizeState(t){if(!t)return"";const e=t.toLowerCase();return{task_state_submitted:"submitted",task_state_delivered:"submitted",task_state_working:"working",task_state_completed:"completed",task_state_failed:"failed",task_state_timeout:"timeout",task_state_canceled:"canceled",task_state_rejected:"rejected",task_state_input_required:"input-required",task_state_auth_required:"auth-required"}[e]??e}function unwrapTask(t){if(!t||"object"!=typeof t)return;const e=t,a=e.task;return a&&"object"==typeof a?a:e}function extractArtifactText(t){const e=t?.artifacts;if(!e)return;return e.flatMap(t=>t.parts??[]).filter(t=>"string"==typeof t.text&&(void 0===t.kind||"text"===t.kind)).map(t=>t.text).join("\n")||void 0}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function stringValue(t){return"string"==typeof t&&""!==t?t:void 0}function normalizeArtifactFilePart(t){const e=stringValue(t.kind),a=isRecord(t.file)?t.file:void 0;let n=stringValue(t.url),s=stringValue(t.filename),r=stringValue(t.mediaType);if(a&&(n=stringValue(a.uri)??stringValue(a.url)??n,s=stringValue(a.name)??stringValue(a.filename)??s,r=stringValue(a.mimeType)??stringValue(a.mediaType)??r),n&&(!e||"file"===e))return{uri:n,...s?{name:s}:{},...r?{mimeType:r}:{}}}function extractArtifactFiles(t){const e=t?.artifacts;if(!e)return;const a=[];for(const t of e){const e=t.parts;if(Array.isArray(e))for(const t of e){if(!isRecord(t))continue;const e=normalizeArtifactFilePart(t);e&&a.push(e)}}return a.length>0?a:void 0}function extractStatusText(t){const e=t?.status,a=e?.message?.parts,n=a?.[0]?.text;return"string"==typeof n?n:void 0}function taskState(t){return normalizeState(t?.status?.state)}const TERMINAL_FAILURE_STATES=new Set(["failed","timeout","canceled","rejected"]);function taskContextId(t){const e=t?.contextId;return"string"==typeof e&&""!==e?e:void 0}function buildTaskPayload(t,e,a){const n=taskState(t),s=extractArtifactText(t),r=extractArtifactFiles(t),i=extractStatusText(t),o=taskContextId(t),c={status:n,is_terminal:"completed"===n||TERMINAL_FAILURE_STATES.has(n)};return e&&(c.task_id=e),a&&(c.agent_id=a),o&&(c.context_id=o),s?c.result=s:i&&(c.error=i),r&&(c.files=r),c}export{unwrapTask,extractArtifactText,extractArtifactFiles,extractStatusText,taskState,taskContextId,normalizeState,buildTaskPayload};export class TaskHandleRegistry{seq=0;handles=new Map;taskIdToHandle=new Map;create(t,e,a,n){const s="bth_"+ ++this.seq;return this.handles.set(s,{taskId:t,agentId:e,contextId:a,sessionKey:n}),this.taskIdToHandle.set(t,s),s}resolveTaskId(t){const e=this.handles.get(t);return e?e.taskId:t}resolveAgentId(t){const e=this.handles.get(t);if(e)return e.agentId;const a=this.taskIdToHandle.get(t);return a?this.handles.get(a)?.agentId:void 0}}const defaultRegistry=new TaskHandleRegistry;export function registerA2ATools(t,e,a=defaultRegistry,n,s,r,i){t.registerTool({name:"beeos_discover_agents",description:"List agents available for A2A collaboration. When called without a query, returns all visible agents (your own agents + public agents). When called with a query, filters by name, description, or skill. Results include an `isSelf` flag marking the agent that represents the current instance (do not call yourself). Each result includes `instanceName` (human-readable device/instance label) when available.",parameters:{type:"object",properties:{query:{type:"string",description:"Optional keyword to filter agents by name, description, or skill. Omit to list all agents."}},required:[]},async execute(t,a,n){const{query:s}=a??{};try{const t=new URLSearchParams({limit:"50"});s&&t.set("query",s);const a=await a2aFetch(e,`/api/v1/a2a/discover?${t}`,{signal:n});if(!a.ok)return{content:JSON.stringify({error:`discover failed: ${a.status}`})};const r=await a.json(),o=i?.();if(o&&Array.isArray(r?.data))for(const t of r.data)t.isSelf=t.instance_id===o;return{content:JSON.stringify(r,null,2)}}catch(t){if(n?.aborted)throw t;return{content:JSON.stringify({error:t instanceof Error?t.message:String(t)})}}}}),t.registerTool({name:"beeos_call_agent",description:"Ask another agent to perform a task. This creates the task ASYNCHRONOUSLY and returns immediately with a handle ({ task_id, agent_id, context_id, status }) — it does NOT wait for the result. To fetch the agent's reply, call beeos_get_task with the returned task_id (and agent_id). Do NOT call beeos_call_agent again to poll an existing task — that creates a brand-new task.",parameters:{type:"object",properties:{agentId:{type:"string",description:"The target agent UUID (e.g. d04080d1-...) or display name. Prefer the UUID from discover results or @mention metadata when available."},message:{type:"string",description:"The task description or message to send to the agent"},taskId:{type:"string",description:"Optional existing task ID to continue a multi-turn conversation. When provided, the message is appended to the existing task instead of creating a new one."},files:{type:"array",items:{type:"string"},description:"Optional file URLs to include with the request"},contextId:{type:"string",description:"Optional context ID for multi-turn conversations with the same agent"},timeoutMs:{type:"number",description:"Server-side task timeout in milliseconds (how long the target agent may run before the task is timed out). Omit it for no task deadline. This is NOT a client wait time — beeos_call_agent returns immediately regardless."}},required:["agentId","message"]},async execute(t,i,o){let{agentId:c,message:d,files:l,contextId:u,timeoutMs:g,taskId:f}=i;const p=n?.(t),h=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;if(!h.test(c)){const a=s?.(t);if(a?.length){const t=resolveAgentIdFromMentions(a,c);t&&(e.logger.info?.(`beeos_call_agent: resolved "${c}" → ${t} via mention context`),c=t)}if(!h.test(c))try{const t=await a2aFetch(e,`/api/v1/a2a/discover?query=${encodeURIComponent(c)}&limit=10`,{signal:o});if(t.ok){const a=await t.json(),n=a?.data??[],s=c.toLowerCase(),r=n.find(t=>t.name.toLowerCase()===s)??n.find(t=>t.name.toLowerCase().includes(s));if(!r)return{content:JSON.stringify({error:`Could not resolve agent name "${c}". Available agents: ${n.map(t=>`${t.name} (${t.id})`).join(", ")||"none"}`})};e.logger.info?.(`beeos_call_agent: resolved "${c}" → ${r.id} (${r.name}) via discover`),c=r.id}}catch{}}const m=u||(p?`session:${p}`:"");try{const t={message:{role:"user",parts:[{text:d}],...m?{contextId:m}:{},...f?{taskId:f}:{}},...void 0!==g?{configuration:{timeoutMs:g}}:{}},n={jsonrpc:"2.0",id:`claw-${Date.now()}`,method:"SendMessage",params:t},s=`/api/v1/a2a/${encodeURIComponent(c)}`,i=AbortSignal.timeout(3e4),l=o?AbortSignal.any([o,i]):i,h=await a2aFetch(e,s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),signal:l}),y=await h.text();let k;try{k=JSON.parse(y)}catch{k={}}if(!h.ok||k.error){if(401===h.status||403===h.status){const t=k.error??{};-32600===t.code&&r&&r("_beeos/auth_required",{type:"auth_required",target_agent_id:c,target_agent_name:c,title:"Authentication Required",content:`Agent **${c}** requires authentication.`})}const t=k.error?JSON.stringify(k.error):y;return{content:JSON.stringify({error:`send task failed: ${h.status} ${t}`,agent_id:c})}}const _=unwrapTask(k.result),w=_?.id;return w?(a.create(w,c,u,p),{content:JSON.stringify({status:taskState(_)||"working",task_id:w,agent_id:c,context_id:taskContextId(_)??m??void 0,message:`Task created. Call beeos_get_task with task_id "${w}" (and agent_id "${c}") to fetch status and result.`})}):{content:JSON.stringify({error:"task created but server returned no task_id",agent_id:c})}}catch(t){if(o?.aborted)throw t;return t instanceof DOMException&&"TimeoutError"===t.name?{content:JSON.stringify({error:"create task request timed out after 30000ms",agent_id:c})}:{content:JSON.stringify({error:t instanceof Error?t.message:String(t),agent_id:c})}}}}),t.registerTool({name:"beeos_get_task",description:'Fetch the current state AND data of an existing A2A task by its task_id. Use this to check on a task that beeos_call_agent created (it returns status "working" with a task_id), or to re-read a finished task. Always returns a JSON object { status, task_id, agent_id, context_id, is_terminal, result?, files?, error? }: `result` holds the produced output (present whenever the device produced output, EVEN for timeout/canceled/failed tasks that still produced content); `files` contains structured file artifacts ({uri,name,mimeType}). Do not output MEDIA:, and do not upload/fetch/browser/shell files[].uri for display. Use beeos_fetch_file only for local byte analysis. `error` holds the failure reason when there is no produced output; `is_terminal` indicates whether the task has reached a final state. Do NOT call beeos_call_agent again to re-query an existing task — that creates a brand-new task.',parameters:{type:"object",properties:{taskId:{type:"string",description:"The task ID returned by a previous beeos_call_agent call."},agentId:{type:"string",description:"The target agent UUID that owns the task (the same agentId passed to beeos_call_agent). Optional when the task was created earlier in this session — it is resolved automatically."}},required:["taskId"]},async execute(t,n,s){const{taskId:r,agentId:i}=n??{};if(!r)return{content:JSON.stringify({error:"taskId is required"})};const o=i||a.resolveAgentId(r);if(!o)return{content:JSON.stringify({error:`agentId is required to query task "${r}" (it was not created in this session, so the target agent is unknown). Pass the agentId you originally called.`,task_id:r})};try{const t=`/api/v1/a2a/${encodeURIComponent(o)}`,a=await a2aFetch(e,t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:`claw-get-${Date.now()}`,method:"GetTask",params:{id:r}}),signal:s}),n=await a.text();let i;try{i=JSON.parse(n)}catch{i={}}if(!a.ok||i.error){const t=i.error?JSON.stringify(i.error):n;return{content:JSON.stringify({error:`get task failed: ${a.status} ${t}`,task_id:r,agent_id:o})}}const c=unwrapTask(i.result);return{content:JSON.stringify(buildTaskPayload(c,r,o))}}catch(t){if(s?.aborted)throw t;return{content:JSON.stringify({error:t instanceof Error?t.message:String(t),task_id:r,agent_id:o})}}}})}
|
|
1
|
+
import{CloudHttpError}from"@beeos-ai/cloud-harness-sdk";import{resolveAgentIdFromMentions}from"../delegation/mention-resolver.js";export async function completeA2ATask(t,e,a,r){try{await t.gateway.a2a.completeTask(e,{result:r?"":a,error:r})}catch(t){if(t instanceof CloudHttpError)throw new Error(`A2A CompleteTask failed: ${t.status}`);throw t}}function normalizeState(t){if(!t)return"";const e=t.toLowerCase();return{task_state_submitted:"submitted",task_state_delivered:"submitted",task_state_working:"working",task_state_completed:"completed",task_state_failed:"failed",task_state_timeout:"timeout",task_state_canceled:"canceled",task_state_rejected:"rejected",task_state_input_required:"input-required",task_state_auth_required:"auth-required"}[e]??e}function unwrapTask(t){if(!t||"object"!=typeof t)return;const e=t,a=e.task;return a&&"object"==typeof a?a:e}function extractArtifactText(t){const e=t?.artifacts;if(!e)return;return e.flatMap(t=>t.parts??[]).filter(t=>"string"==typeof t.text&&(void 0===t.kind||"text"===t.kind)).map(t=>t.text).join("\n")||void 0}function isRecord(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function stringValue(t){return"string"==typeof t&&""!==t?t:void 0}function normalizeArtifactFilePart(t){const e=stringValue(t.kind),a=isRecord(t.file)?t.file:void 0;let r=stringValue(t.url),s=stringValue(t.filename),n=stringValue(t.mediaType);if(a&&(r=stringValue(a.uri)??stringValue(a.url)??r,s=stringValue(a.name)??stringValue(a.filename)??s,n=stringValue(a.mimeType)??stringValue(a.mediaType)??n),r&&(!e||"file"===e))return{uri:r,...s?{name:s}:{},...n?{mimeType:n}:{}}}function extractArtifactFiles(t){const e=t?.artifacts;if(!e)return;const a=[];for(const t of e){const e=t.parts;if(Array.isArray(e))for(const t of e){if(!isRecord(t))continue;const e=normalizeArtifactFilePart(t);e&&a.push(e)}}return a.length>0?a:void 0}function extractStatusText(t){const e=t?.status,a=e?.message?.parts,r=a?.[0]?.text;return"string"==typeof r?r:void 0}function taskState(t){return normalizeState(t?.status?.state)}const TERMINAL_FAILURE_STATES=new Set(["failed","timeout","canceled","rejected"]);function taskContextId(t){const e=t?.contextId;return"string"==typeof e&&""!==e?e:void 0}function buildTaskPayload(t,e,a){const r=taskState(t),s=extractArtifactText(t),n=extractArtifactFiles(t),i=extractStatusText(t),o=taskContextId(t),d={status:r,is_terminal:"completed"===r||TERMINAL_FAILURE_STATES.has(r)};return e&&(d.task_id=e),a&&(d.agent_id=a),o&&(d.context_id=o),s?d.result=s:i&&(d.error=i),n&&(d.files=n),d}export{unwrapTask,extractArtifactText,extractArtifactFiles,extractStatusText,taskState,taskContextId,normalizeState,buildTaskPayload};export class TaskHandleRegistry{seq=0;handles=new Map;taskIdToHandle=new Map;create(t,e,a,r){const s="bth_"+ ++this.seq;return this.handles.set(s,{taskId:t,agentId:e,contextId:a,sessionKey:r}),this.taskIdToHandle.set(t,s),s}resolveTaskId(t){const e=this.handles.get(t);return e?e.taskId:t}resolveAgentId(t){const e=this.handles.get(t);if(e)return e.agentId;const a=this.taskIdToHandle.get(t);return a?this.handles.get(a)?.agentId:void 0}}const defaultRegistry=new TaskHandleRegistry;export function registerA2ATools(t,e,a=defaultRegistry,r,s,n,i){t.registerTool({name:"beeos_discover_agents",description:"List agents available for A2A collaboration. When called without a query, returns all visible agents (your own agents + public agents). When called with a query, filters by name, description, or skill. Results include an `isSelf` flag marking the agent that represents the current instance (do not call yourself). Each result includes `instanceName` (human-readable device/instance label) when available.",parameters:{type:"object",properties:{query:{type:"string",description:"Optional keyword to filter agents by name, description, or skill. Omit to list all agents."}},required:[]},async execute(t,a,r){const{query:s}=a??{};try{let t;try{t=await e.gateway.a2a.discover({query:s,limit:50},{signal:r})}catch(t){if(t instanceof CloudHttpError)return{content:JSON.stringify({error:`discover failed: ${t.status}`})};throw t}const a=i?.();if(a&&Array.isArray(t?.data))for(const e of t.data)e.isSelf=e.instance_id===a;return{content:JSON.stringify(t,null,2)}}catch(t){if(r?.aborted)throw t;return{content:JSON.stringify({error:t instanceof Error?t.message:String(t)})}}}}),t.registerTool({name:"beeos_call_agent",description:"Ask another agent to perform a task. This creates the task ASYNCHRONOUSLY and returns immediately with a handle ({ task_id, agent_id, context_id, status }) — it does NOT wait for the result. To fetch the agent's reply, call beeos_get_task with the returned task_id (and agent_id). Do NOT call beeos_call_agent again to poll an existing task — that creates a brand-new task.",parameters:{type:"object",properties:{agentId:{type:"string",description:"The target agent UUID (e.g. d04080d1-...) or display name. Prefer the UUID from discover results or @mention metadata when available."},message:{type:"string",description:"The task description or message to send to the agent"},taskId:{type:"string",description:"Optional existing task ID to continue a multi-turn conversation. When provided, the message is appended to the existing task instead of creating a new one."},files:{type:"array",items:{type:"string"},description:"Optional file URLs to include with the request"},contextId:{type:"string",description:"Optional context ID for multi-turn conversations with the same agent"},timeoutMs:{type:"number",description:"Server-side task timeout in milliseconds (how long the target agent may run before the task is timed out). Omit it for no task deadline. This is NOT a client wait time — beeos_call_agent returns immediately regardless."}},required:["agentId","message"]},async execute(t,i,o){let{agentId:d,message:c,files:l,contextId:u,timeoutMs:g,taskId:f}=i;const p=r?.(t),h=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;if(!h.test(d)){const a=s?.(t);if(a?.length){const t=resolveAgentIdFromMentions(a,d);t&&(e.logger.info?.(`beeos_call_agent: resolved "${d}" → ${t} via mention context`),d=t)}if(!h.test(d))try{const t=await e.gateway.a2a.discover({query:d,limit:10},{signal:o}),a=t?.data??[],r=d.toLowerCase(),s=a.find(t=>t.name.toLowerCase()===r)??a.find(t=>t.name.toLowerCase().includes(r));if(!s)return{content:JSON.stringify({error:`Could not resolve agent name "${d}". Available agents: ${a.map(t=>`${t.name} (${t.id})`).join(", ")||"none"}`})};e.logger.info?.(`beeos_call_agent: resolved "${d}" → ${s.id} (${s.name}) via discover`),d=s.id}catch{}}const m=u||(p?`session:${p}`:"");try{const t={message:{role:"user",parts:[{text:c}],...m?{contextId:m}:{},...f?{taskId:f}:{}},...void 0!==g?{configuration:{timeoutMs:g}}:{}},r=AbortSignal.timeout(3e4),s=o?AbortSignal.any([o,r]):r,{ok:i,status:l,body:h,rpc:k}=await e.gateway.a2a.rpc(d,"SendMessage",t,{signal:s,requestId:`claw-${Date.now()}`});if(!i){if(401===l||403===l){const t=k.error??{};-32600===t.code&&n&&n("_beeos/auth_required",{type:"auth_required",target_agent_id:d,target_agent_name:d,title:"Authentication Required",content:`Agent **${d}** requires authentication.`})}const t=k.error?JSON.stringify(k.error):h;return{content:JSON.stringify({error:`send task failed: ${l} ${t}`,agent_id:d})}}const y=unwrapTask(k.result),_=y?.id;return _?(a.create(_,d,u,p),{content:JSON.stringify({status:taskState(y)||"working",task_id:_,agent_id:d,context_id:taskContextId(y)??m??void 0,message:`Task created. Call beeos_get_task with task_id "${_}" (and agent_id "${d}") to fetch status and result.`})}):{content:JSON.stringify({error:"task created but server returned no task_id",agent_id:d})}}catch(t){if(o?.aborted)throw t;return t instanceof DOMException&&"TimeoutError"===t.name?{content:JSON.stringify({error:"create task request timed out after 30000ms",agent_id:d})}:{content:JSON.stringify({error:t instanceof Error?t.message:String(t),agent_id:d})}}}}),t.registerTool({name:"beeos_get_task",description:'Fetch the current state AND data of an existing A2A task by its task_id. Use this to check on a task that beeos_call_agent created (it returns status "working" with a task_id), or to re-read a finished task. Always returns a JSON object { status, task_id, agent_id, context_id, is_terminal, result?, files?, error? }: `result` holds the produced output (present whenever the device produced output, EVEN for timeout/canceled/failed tasks that still produced content); `files` contains structured file artifacts ({uri,name,mimeType}). Do not output MEDIA:, and do not upload/fetch/browser/shell files[].uri for display. Use beeos_fetch_file only for local byte analysis. `error` holds the failure reason when there is no produced output; `is_terminal` indicates whether the task has reached a final state. Do NOT call beeos_call_agent again to re-query an existing task — that creates a brand-new task.',parameters:{type:"object",properties:{taskId:{type:"string",description:"The task ID returned by a previous beeos_call_agent call."},agentId:{type:"string",description:"The target agent UUID that owns the task (the same agentId passed to beeos_call_agent). Optional when the task was created earlier in this session — it is resolved automatically."}},required:["taskId"]},async execute(t,r,s){const{taskId:n,agentId:i}=r??{};if(!n)return{content:JSON.stringify({error:"taskId is required"})};const o=i||a.resolveAgentId(n);if(!o)return{content:JSON.stringify({error:`agentId is required to query task "${n}" (it was not created in this session, so the target agent is unknown). Pass the agentId you originally called.`,task_id:n})};try{const{ok:t,status:a,body:r,rpc:i}=await e.gateway.a2a.rpc(o,"GetTask",{id:n},{signal:s,requestId:`claw-get-${Date.now()}`});if(!t){const t=i.error?JSON.stringify(i.error):r;return{content:JSON.stringify({error:`get task failed: ${a} ${t}`,task_id:n,agent_id:o})}}const d=unwrapTask(i.result);return{content:JSON.stringify(buildTaskPayload(d,n,o))}}catch(t){if(s?.aborted)throw t;return{content:JSON.stringify({error:t instanceof Error?t.message:String(t),task_id:n,agent_id:o})}}}})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync,mkdirSync,readdirSync,statSync,writeFileSync}from"node:fs";import{join,basename}from"node:path";import{parseBeeosFileUri}from"../files/beeos-file-uri.js";const MAX_FILE_NAME_LENGTH=120,DOWNLOAD_TIMEOUT_MS=12e4,MAX_CONCURRENT_RESOLVES=3,OPENCLAW_HOME=process.env.OPENCLAW_HOME||join(process.env.HOME||"/home/node",".openclaw"),UPLOAD_DIR=join(OPENCLAW_HOME,"workspace","uploads"),RESOURCE_CACHE_DIR=join(OPENCLAW_HOME,"workspace","resource_cache");export{parseBeeosFileUri}from"../files/beeos-file-uri.js";export class BeeosFileResolver{
|
|
1
|
+
import{existsSync,mkdirSync,readdirSync,statSync,writeFileSync}from"node:fs";import{join,basename}from"node:path";import{CloudHttpError}from"@beeos-ai/cloud-harness-sdk";import{parseBeeosFileUri}from"../files/beeos-file-uri.js";const MAX_FILE_NAME_LENGTH=120,DOWNLOAD_TIMEOUT_MS=12e4,MAX_CONCURRENT_RESOLVES=3,OPENCLAW_HOME=process.env.OPENCLAW_HOME||join(process.env.HOME||"/home/node",".openclaw"),UPLOAD_DIR=join(OPENCLAW_HOME,"workspace","uploads"),RESOURCE_CACHE_DIR=join(OPENCLAW_HOME,"workspace","resource_cache");export{parseBeeosFileUri}from"../files/beeos-file-uri.js";export class BeeosFileResolver{cloud;writeObs;constructor(e){this.cloud=e.cloud,this.writeObs=e.writeObs}buildResolutionPlan(e){const t=[],i=new Map;for(let a=0;a<e.length;a++){const o=e[a];if("resource_link"!==o.type||!o.uri)continue;const l=parseBeeosFileUri(o.uri);l.fileId&&(t.push({blockIndex:a,uri:o.uri,fileId:l.fileId,name:o.title??o.name}),i.set(o.uri,l.fileId))}return{refs:t,fileIds:[...new Set(i.values())],fileIdByUri:i}}async resolveMetadataForPrompt(e){if(0===e.fileIds.length)return new Map;const t=new Map,i=e.fileIds.map(e=>async()=>{const i=await this.resolveOneFile(e);t.set(e,i)});await runWithConcurrency(i,3);const a=new Map;for(const[i,o]of e.fileIdByUri.entries()){const e=t.get(o);e&&a.set(i,e)}return a}async resolveOneFile(e){const t=Date.now(),i=this.findCachedFile(e);if(i)return this.writeObs?.({component:"beeos-file-resolver",domain:"file",name:"cache_hit",severity:"debug",payload:{fileId:e,localPath:i.localPath}}),{status:"resolved",fileId:e,name:i.localFileName,mimeType:"application/octet-stream",localPath:i.localPath,localFileName:i.localFileName,localSizeBytes:i.localSizeBytes,localCacheHit:!0,downloadUrl:""};this.writeObs?.({component:"beeos-file-resolver",domain:"file",name:"metadata_request",severity:"info",payload:{fileId:e}});const a=new AbortController,o=setTimeout(()=>a.abort(),12e4);"object"==typeof o&&"unref"in o&&o.unref();try{let i;try{i=await this.cloud.files.resolve(e,{signal:a.signal})}catch(i){if(!(i instanceof CloudHttpError))throw i;const a=i.status>=500?"http_5xx":"http_4xx",o=i.status>=500||429===i.status;return this.writeObs?.({component:"beeos-file-resolver",domain:"file",name:"metadata_failed",severity:"warn",payload:{fileId:e,httpStatus:i.status,code:a,durationMs:Date.now()-t}}),{status:"resolve_failed",fileId:e,code:a,message:`resolve request failed with status ${i.status}`,retriable:o,httpStatus:i.status}}const o=asString(i.fileName),l=asString(i.mimeType),r=asString(i.downloadUrl),s="number"==typeof i.size?i.size:void 0;if(!r)return this.makeFailure(e,"missing_download_url","resolve response missing downloadUrl",!1,o);this.writeObs?.({component:"beeos-file-resolver",domain:"file",name:"metadata_ok",severity:"debug",payload:{fileId:e,fileName:o,mimeType:l,size:s,durationMs:Date.now()-t}});const n=await this.ensureFileDownloaded({fileId:e,name:o||e,downloadUrl:r});return"resolve_failed"===n.status?n:{status:"resolved",fileId:e,name:o||n.localFileName,mimeType:l||"application/octet-stream",size:s,downloadUrl:r,localPath:n.localPath,localFileName:n.localFileName,localSizeBytes:n.localSizeBytes,localCacheHit:!1}}catch(t){const i=t instanceof Error&&"AbortError"===t.name,a=i?"timeout":"network_error",o=i?"resolve request timed out after 120000ms":`resolve request failed: ${t instanceof Error?t.message:String(t)}`;return this.makeFailure(e,a,o,!0)}finally{clearTimeout(o)}}findCachedFile(e){for(const t of[UPLOAD_DIR,RESOURCE_CACHE_DIR]){const i=this.findFileByPrefix(t,e);if(i)return i}}findFileByPrefix(e,t){if(!existsSync(e))return;const i=`${t}_`;let a;try{a=readdirSync(e).sort()}catch{return}for(const t of a){if(!t.startsWith(i))continue;const a=join(e,t);try{const e=statSync(a);if(e.isFile()&&e.size>0)return{localPath:a,localFileName:t,localSizeBytes:e.size}}catch{continue}}}async ensureFileDownloaded(e){const t=sanitizeFileName(e.name),i=`${e.fileId}_${t}`,a=join(RESOURCE_CACHE_DIR,i);try{mkdirSync(RESOURCE_CACHE_DIR,{recursive:!0})}catch(t){return this.makeFailure(e.fileId,"fs_error",`failed to create cache dir: ${String(t)}`,!1,e.name)}const o=this.findFileByPrefix(RESOURCE_CACHE_DIR,e.fileId);if(o)return{status:"resolved",fileId:e.fileId,name:e.name,mimeType:"application/octet-stream",downloadUrl:e.downloadUrl,localPath:o.localPath,localFileName:o.localFileName,localSizeBytes:o.localSizeBytes,localCacheHit:!0};const l=new AbortController,r=setTimeout(()=>l.abort(),12e4);"object"==typeof r&&"unref"in r&&r.unref();try{let t;try{t=Buffer.from(await this.cloud.files.download(e.downloadUrl,l.signal))}catch(t){if(!(t instanceof CloudHttpError))throw t;const i=t.status>=500?"http_5xx":"http_4xx";return this.makeFailure(e.fileId,i,`file download failed with status ${t.status}`,t.status>=500||429===t.status,e.name,t.status)}if(0===t.byteLength)return this.makeFailure(e.fileId,"invalid_response","downloaded file is empty",!1,e.name);try{writeFileSync(a,t)}catch(t){return this.makeFailure(e.fileId,"fs_error",`failed to write file: ${String(t)}`,!1,e.name)}let o=t.byteLength;try{const e=statSync(a);e.isFile()&&e.size>0&&(o=e.size)}catch{}return this.writeObs?.({component:"beeos-file-resolver",domain:"file",name:"download_ok",severity:"info",payload:{fileId:e.fileId,localPath:a,localSizeBytes:o}}),{status:"resolved",fileId:e.fileId,name:e.name,mimeType:"application/octet-stream",downloadUrl:e.downloadUrl,localPath:a,localFileName:i,localSizeBytes:o,localCacheHit:!1}}catch(t){const i=t instanceof Error&&"AbortError"===t.name,a=i?"timeout":"network_error",o=i?"file download timed out after 120000ms":`file download failed: ${t instanceof Error?t.message:String(t)}`;return this.makeFailure(e.fileId,a,o,!0,e.name)}finally{clearTimeout(r)}}makeFailure(e,t,i,a,o,l){return this.writeObs?.({component:"beeos-file-resolver",domain:"file",name:"resolve_failed",severity:"warn",payload:{fileId:e,code:t,message:i,retriable:a,...void 0!==l?{httpStatus:l}:{}}}),{status:"resolve_failed",fileId:e,...o?{name:o}:{},code:t,message:i,retriable:a,...void 0!==l?{httpStatus:l}:{}}}}function sanitizeFileName(e){return basename(e).trim().replace(/[\u0000-\u001f\u007f]/g,"").replace(/[\\/]+/g,"_").replace(/[^\p{L}\p{N}._-]+/gu,"_").replace(/_+/g,"_").replace(/^\.+/,"").replace(/^_+|_+$/g,"").slice(0,120)||"file"}function asString(e){if("string"==typeof e&&e.trim())return e.trim()}async function runWithConcurrency(e,t){let i=0;async function a(){for(;i<e.length;){const t=i++;await e[t]()}}const o=[];for(let i=0;i<Math.min(t,e.length);i++)o.push(a());await Promise.all(o)}
|