@messenger-agent/codex-agent 0.37.1 → 0.37.3-alpha.0

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/codex.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import{mkdirSync as k,existsSync as P}from"node:fs";import{appServerClient as l}from"./app-server-client.js";import{dynamicToolSpecs as E}from"./dynamic-tools.js";import{loadAllSessions as U,persistSession as _}from"./db.js";import{appConfig as p}from"./config.js";import{logger as I}from"@messenger-agent/shared/logger";import{resolveAgentWorkdir as N}from"@messenger-agent/shared/agent-workspaces";import{loadCodexPlatformInstructions as C}from"./platform-instructions.js";const v=C(void 0,p.schedule?.enabled===!0);class T extends Error{path;constructor(e){super(`Workdir not found: ${e}`),this.path=e}}class x{id;model;workingDirectory;constructor(e,t,n){this.id=e,this.model=t,this.workingDirectory=n}async run(e,t){const n=await this.runStreamed(e,t),r=new Map,o=new Set;let a=null;for await(const u of n.events)if(u.type==="item.started")o.has(u.item.id)||r.set(u.item.id,u.item);else if(u.type==="item.completed")o.add(u.item.id),r.set(u.item.id,u.item);else if(u.type==="thread.tokenUsage.updated")a=u.usage;else if(u.type==="turn.failed")throw new Error(u.error.message);const d=Array.from(r.values()),i=d.filter(u=>u.type==="agentMessage").map(u=>u.text).join(`
2
2
  `);return{items:d,finalResponse:i||void 0,usage:a}}async runStreamed(e,t){const n=l.request("turn/start",this.turnStartParams(e,t)),r=await this.waitForTurnStart(n,t?.signal),o=r.turn.id;return{turnId:o,events:this.eventsForTurn(o,r.turn,t?.signal)}}async waitForTurnStart(e,t){if(!t)return e;let n,r;const o=new Promise((d,i)=>{r=i}),a=()=>{n=t.reason??new DOMException("The operation was aborted","AbortError"),r(n)};t.addEventListener("abort",a,{once:!0}),t.aborted&&a();try{return await Promise.race([e,o])}catch(d){throw d===n&&e.then(i=>this.interrupt(i.turn.id)).catch(i=>I.error("Failed to clean up aborted Codex turn start:",i)),d}finally{t.removeEventListener("abort",a)}}async steerStreamed(e,t,n){const r={threadId:this.id,input:[{type:"text",text:e}],expectedTurnId:t},o=await l.request("turn/steer",r);return{turnId:o.turnId,events:this.eventsForTurn(o.turnId,void 0,n?.signal,void 0,!0)}}async continueWithUserInput(e,t,n){const r=l.pendingUserInputTurnId(this.id,e);return r?{turnId:r,events:this.eventsForTurn(r,void 0,n?.signal,async()=>{if(!await l.respondToUserInput(this.id,e,t))throw new Error(`No pending user input request found for item: ${e}`)})}:(await this.interruptStaleTurn(n?.sourceTurnId),this.runStreamed(A(e,t),n))}async submitPendingUserInput(e,t){const n=l.pendingUserInputTurnId(this.id,e);if(!(!n||!await l.respondToUserInput(this.id,e,t)))return n}async interrupt(e){await l.request("turn/interrupt",{threadId:this.id,turnId:e})}async interruptPendingUserInput(e,t){await this.interrupt(e),l.discardPendingUserInput(this.id,t)}async interruptStaleTurn(e){if(!e)return;(await l.request("thread/read",{threadId:this.id,includeTurns:!0})).thread.turns?.find(r=>r.id===e)?.status==="inProgress"&&await this.interrupt(e)}turnStartParams(e,t){return{threadId:this.id,input:[{type:"text",text:e,text_elements:[]}],cwd:this.workingDirectory,approvalPolicy:"never",model:this.model,...t?.collaborationMode?{collaborationMode:t.collaborationMode}:null}}async*eventsForTurn(e,t,n,r,o=!1){const a=[...t||o?[{type:"thread.started",thread_id:this.id},{type:"turn.started",turn_id:e}]:[],...t?M(t):[]];let d=t?.status==="completed"||t?.status==="failed"||t?.status==="interrupted",i,u=!1,c=()=>{};const f=({method:h,params:w})=>{if(u)return;const g=R(h,w,this.id,e);g&&(a.push(g),(g.type==="turn.completed"||g.type==="turn.failed")&&(d=!0),c())},y=h=>{i=h,d=!0,c()},m=()=>{u=!0,a.length=0,d=!0,c()};l.on("notification",f),l.on("exit",y),n?.addEventListener("abort",m,{once:!0}),n?.aborted&&m();try{for(await r?.();!d||a.length>0;){for(;a.length>0;)yield a.shift();if(d)break;await new Promise(h=>{const w=setTimeout(()=>{c=()=>{},h()},50);c=()=>{clearTimeout(w),c=()=>{},h()}})}i&&(yield{type:"error",message:i.message})}finally{l.off("notification",f),l.off("exit",y),n?.removeEventListener("abort",m)}}}function A(s,e){return[`The user answered a previous request_user_input prompt (${s}), but the original pending tool request is no longer active.`,"Continue the task using this answer:",JSON.stringify(e,null,2)].join(`
3
- `)}class F{sessions=new Map;constructor(){for(const e of U())this.sessions.set(e.sessionId,{workdir:e.workdir,botName:e.botName??"main",llmProxyBinding:e.llmProxyBinding});I.info(`SessionManager: loaded ${this.sessions.size} persisted sessions`)}async getOrCreate(e,t,n,r,o,a,d){const i=this.resolveWorkdir(n,r);if(e){const c=this.sessions.get(e);if(c&&c.workdir===i){const f=c.llmProxyBinding??d,y=await l.request("thread/resume",this.threadResumeParams(e,o,i,a,f));if(!c.llmProxyBinding&&f){const m={...c,llmProxyBinding:f};this.sessions.set(e,m),_({sessionId:e,botName:m.botName,workdir:m.workdir,createdAt:Date.now(),llmProxyBinding:f})}return{thread:new x(y.thread.id,o,i),sessionId:e,isNewSession:!1}}}if(n&&!P(i))throw new T(i);k(i,{recursive:!0});const u=await l.request("thread/start",this.threadStartParams(o,i,a,d));return{thread:new x(u.thread.id,o,i),sessionId:void 0,isNewSession:!0}}async fork(e,t,n,r,o,a,d){const i=this.resolveWorkdir(n,r);if(n&&!P(i))throw new T(i);k(i,{recursive:!0});const c=(await l.request("thread/fork",this.threadForkParams(e.threadId,e.turnId,o,i,a,d))).thread.id;return this.persist(c,t,n,r,d),{thread:new x(c,o,i),sessionId:c,isNewSession:!1}}persist(e,t,n,r,o){const a=t??"main",d=this.resolveWorkdir(n,r);this.sessions.set(e,{botName:a,workdir:d,llmProxyBinding:o}),_({sessionId:e,botName:a,workdir:d,createdAt:Date.now(),llmProxyBinding:o})}bindingFor(e){return e?this.sessions.get(e)?.llmProxyBinding:void 0}workdirFor(e){return e?this.sessions.get(e)?.workdir:void 0}hasSession(e){return!!e&&this.sessions.has(e)}resolveWorkdir(e,t){return N(p,t,e)}threadStartParams(e,t,n,r){return{model:e,modelProvider:p.codex.baseUrl?"custom":null,cwd:t,approvalPolicy:"never",sandbox:n,config:this.codexConfig(r),developerInstructions:v,dynamicTools:E(p.schedule?.enabled===!0),experimentalRawEvents:!1,persistExtendedHistory:!1}}threadResumeParams(e,t,n,r,o){return{threadId:e,model:t,modelProvider:p.codex.baseUrl?"custom":null,cwd:n,approvalPolicy:"never",sandbox:r,config:this.codexConfig(o),developerInstructions:v,excludeTurns:!0,persistExtendedHistory:!1}}threadForkParams(e,t,n,r,o,a){return{threadId:e,lastTurnId:t,model:n,modelProvider:p.codex.baseUrl?"custom":null,cwd:r,approvalPolicy:"never",sandbox:o,config:this.codexConfig(a),developerInstructions:v,ephemeral:!1,excludeTurns:!0}}codexConfig(e){return{approval_policy:"never",...p.codex.baseUrl?{model_provider:"custom",model_reasoning_effort:"medium",disable_response_storage:!0,model_providers:{custom:{name:"custom",base_url:p.codex.baseUrl,wire_api:"responses",...p.codex.apiKey?{env_key:"OPENAI_API_KEY"}:null,...e?{http_headers:{"X-Elevo-LLM-Binding":e}}:null}},"features.default_mode_request_user_input":!1}:null}}}p.codex.apiKey&&!process.env.OPENAI_API_KEY&&(process.env.OPENAI_API_KEY=p.codex.apiKey);function M(s){const e=[];for(const t of s.items??[])e.push({type:"item.completed",item:t});return s.status==="completed"?e.push({type:"turn.completed"}):s.status==="failed"&&e.push({type:"turn.failed",error:{message:s.error?.message??"Codex turn failed"}}),e}function R(s,e,t,n){const r=e;if(!r)return;const o=r.threadId,a=r.turnId;if(!(typeof o=="string"&&o!==t)&&!(typeof a=="string"&&a!==n)){if(s==="item/started"&&S(r.item))return{type:"item.started",item:r.item};if(s==="item/completed"&&S(r.item))return{type:"item.completed",item:r.item};if(s==="item/agentMessage/delta")return b(r,"agentMessage");if(s==="item/reasoning/summaryTextDelta"||s==="item/reasoning/textDelta")return b(r,"reasoning");if(s==="item/plan/delta")return b(r,"plan");if(s==="item/tool/requestUserInput")return{type:"item.tool.requestUserInput",params:r};if(s==="turn/diff/updated"&&typeof r.diff=="string")return{type:"turn.diff.updated",diff:r.diff};if(s==="thread/tokenUsage/updated")return{type:"thread.tokenUsage.updated",usage:D(r)};if(s==="turn/completed"){const d=r.turn;return d?.status==="failed"?{type:"turn.failed",error:{message:d.error?.message??"Codex turn failed"}}:{type:"turn.completed"}}if(s==="error")return console.error("Received error notification from app-server:",r),{type:"error",message:q(r)}}}function q(s){const e=s.error,t=e&&typeof e=="object"&&"message"in e?e.message:void 0,n=s.additionalDetails,r=typeof t=="string"&&t.trim()?t:"Codex app-server error";return typeof n=="string"&&n.trim()?`${r}: ${n}`:r}function b(s,e){if(!(typeof s.itemId!="string"||typeof s.delta!="string"))return{type:"item.delta",item_id:s.itemId,item_type:e,delta:s.delta}}function D(s){const e=s.tokenUsage;if(!e||typeof e!="object")return null;const t=e,n=t.total,r=t.last;if(!n||typeof n!="object"||!r||typeof r!="object")return null;const o=d=>{const i=d;return{input_tokens:typeof i.inputTokens=="number"?i.inputTokens:void 0,output_tokens:typeof i.outputTokens=="number"?i.outputTokens:void 0,total_tokens:typeof i.totalTokens=="number"?i.totalTokens:void 0}},a=t.modelContextWindow;return{total:o(n),last:o(r),model_context_window:typeof a=="number"?a:void 0}}function S(s){return!!(s&&typeof s=="object"&&"type"in s&&"id"in s)}const H=new F;export{x as CodexThread,T as WorkdirNotFoundError,H as sessionManager};
3
+ `)}class F{sessions=new Map;constructor(){for(const e of U())this.sessions.set(e.sessionId,{workdir:e.workdir,botName:e.botName??"main",llmProxyBinding:e.llmProxyBinding});I.info(`SessionManager: loaded ${this.sessions.size} persisted sessions`)}async getOrCreate(e,t,n,r,o,a,d){const i=this.resolveWorkdir(n,r);if(e){const c=this.sessions.get(e);if(c&&c.workdir===i){const f=c.llmProxyBinding??d,y=await l.request("thread/resume",this.threadResumeParams(e,o,i,a,f));if(!c.llmProxyBinding&&f){const m={...c,llmProxyBinding:f};this.sessions.set(e,m),_({sessionId:e,botName:m.botName,workdir:m.workdir,createdAt:Date.now(),llmProxyBinding:f})}return{thread:new x(y.thread.id,o,i),sessionId:e,isNewSession:!1}}}if(n&&!P(i))throw new T(i);k(i,{recursive:!0});const u=await l.request("thread/start",this.threadStartParams(o,i,a,d));return{thread:new x(u.thread.id,o,i),sessionId:void 0,isNewSession:!0}}async fork(e,t,n,r,o,a,d){const i=this.resolveWorkdir(n,r);if(n&&!P(i))throw new T(i);k(i,{recursive:!0});const c=(await l.request("thread/fork",this.threadForkParams(e.threadId,e.turnId,o,i,a,d))).thread.id;return this.persist(c,t,n,r,d),{thread:new x(c,o,i),sessionId:c,isNewSession:!1}}persist(e,t,n,r,o){const a=t??"main",d=this.resolveWorkdir(n,r);this.sessions.set(e,{botName:a,workdir:d,llmProxyBinding:o}),_({sessionId:e,botName:a,workdir:d,createdAt:Date.now(),llmProxyBinding:o})}bindingFor(e){return e?this.sessions.get(e)?.llmProxyBinding:void 0}workdirFor(e){return e?this.sessions.get(e)?.workdir:void 0}hasSession(e){return!!e&&this.sessions.has(e)}resolveWorkdir(e,t){return N(p,t,e)}threadStartParams(e,t,n,r){return{model:e,modelProvider:p.codex.baseUrl?"custom":null,cwd:t,approvalPolicy:"never",sandbox:n,config:this.codexConfig(r),developerInstructions:v,dynamicTools:E(p.schedule?.enabled===!0),experimentalRawEvents:!1,persistExtendedHistory:!1}}threadResumeParams(e,t,n,r,o){return{threadId:e,model:t,modelProvider:p.codex.baseUrl?"custom":null,cwd:n,approvalPolicy:"never",sandbox:r,config:this.codexConfig(o),developerInstructions:v,excludeTurns:!0,persistExtendedHistory:!1}}threadForkParams(e,t,n,r,o,a){return{threadId:e,lastTurnId:t,model:n,modelProvider:p.codex.baseUrl?"custom":null,cwd:r,approvalPolicy:"never",sandbox:o,config:this.codexConfig(a),developerInstructions:v,ephemeral:!1,excludeTurns:!0}}codexConfig(e){return{approval_policy:"never",...p.codex.baseUrl?{model_provider:"custom",model_reasoning_effort:"medium",disable_response_storage:!0,model_providers:{custom:{name:"custom",base_url:p.codex.baseUrl,wire_api:"responses",...p.codex.apiKey?{env_key:"OPENAI_API_KEY"}:null,...e?{http_headers:{"X-Elevo-LLM-Binding":e}}:null}},"features.default_mode_request_user_input":!1}:null}}}p.codex.apiKey&&!process.env.OPENAI_API_KEY&&(process.env.OPENAI_API_KEY=p.codex.apiKey);function M(s){const e=[];for(const t of s.items??[])e.push({type:"item.completed",item:t});return s.status==="completed"?e.push({type:"turn.completed"}):s.status==="failed"&&e.push({type:"turn.failed",error:{message:s.error?.message??"Codex turn failed"}}),e}function R(s,e,t,n){const r=e;if(!r)return;const o=r.threadId,a=r.turnId;if(!(typeof o=="string"&&o!==t)&&!(typeof a=="string"&&a!==n)){if(s==="item/started"&&S(r.item))return{type:"item.started",item:r.item};if(s==="item/completed"&&S(r.item))return{type:"item.completed",item:r.item};if(s==="item/agentMessage/delta")return b(r,"agentMessage");if(s==="item/reasoning/summaryTextDelta"||s==="item/reasoning/textDelta")return b(r,"reasoning");if(s==="item/plan/delta")return b(r,"plan");if(s==="item/tool/requestUserInput")return{type:"item.tool.requestUserInput",params:r};if(s==="turn/diff/updated"&&typeof r.diff=="string")return{type:"turn.diff.updated",diff:r.diff};if(s==="thread/tokenUsage/updated")return{type:"thread.tokenUsage.updated",usage:D(r)};if(s==="turn/completed"){const d=r.turn;return d?.status==="failed"?{type:"turn.failed",error:{message:d.error?.message??"Codex turn failed"}}:{type:"turn.completed"}}if(s==="error")return console.error("Received error notification from app-server:"),console.dir(r,{depth:5}),{type:"error",message:q(r)}}}function q(s){const e=s.error,t=e&&typeof e=="object"&&"message"in e?e.message:void 0,n=s.additionalDetails,r=typeof t=="string"&&t.trim()?t:"Codex app-server error";return typeof n=="string"&&n.trim()?`${r}: ${n}`:r}function b(s,e){if(!(typeof s.itemId!="string"||typeof s.delta!="string"))return{type:"item.delta",item_id:s.itemId,item_type:e,delta:s.delta}}function D(s){const e=s.tokenUsage;if(!e||typeof e!="object")return null;const t=e,n=t.total,r=t.last;if(!n||typeof n!="object"||!r||typeof r!="object")return null;const o=d=>{const i=d;return{input_tokens:typeof i.inputTokens=="number"?i.inputTokens:void 0,output_tokens:typeof i.outputTokens=="number"?i.outputTokens:void 0,total_tokens:typeof i.totalTokens=="number"?i.totalTokens:void 0}},a=t.modelContextWindow;return{total:o(n),last:o(r),model_context_window:typeof a=="number"?a:void 0}}function S(s){return!!(s&&typeof s=="object"&&"type"in s&&"id"in s)}const H=new F;export{x as CodexThread,T as WorkdirNotFoundError,H as sessionManager};
@@ -1,5 +1,6 @@
1
1
  import type { MatrixTaskEvent } from "@messenger-agent/shared/workspace-tasks";
2
2
  import type { DynamicToolCallParams, DynamicToolCallResponse, DynamicToolSpec } from "./app-server-protocol.js";
3
+ export declare function resolveImageFilePath(storePath: string | undefined, workingDirectory: string): Promise<string>;
3
4
  type ManagedTaskToolContext = {
4
5
  workspaceRoot: string;
5
6
  threadRef?: string;
@@ -1 +1 @@
1
- import l from"node:path";import{mkdir as f,writeFile as y}from"node:fs/promises";import{generateImage as T}from"ai";import{createOpenAI as w}from"@ai-sdk/openai";import{Agent as I,fetch as x}from"undici";import{z as r}from"zod";import{executeManagedTaskTool as S,isManagedTaskToolName as b,MANAGED_TASK_TOOL_DEFINITIONS as A}from"@messenger-agent/shared/managed-task-tools";import{AgentFileError as k,resolveAgentFilePath as v}from"@messenger-agent/shared/agent-files";import{executeScheduleTool as E,SCHEDULE_TOOL_DEFINITION as c,ScheduleToolError as _}from"@messenger-agent/shared/schedule-tools";const d=1200*1e3,M=new I({headersTimeout:d,bodyTimeout:d}),R=(t,e)=>x(t,{...e,dispatcher:M}),p=r.object({prompt:r.string().describe("The text prompt describing the image to generate"),store_path:r.string().describe("Absolute file path (including filename) to save the image. If omitted, saves to the current working directory with an auto-generated name.").optional(),size:r.enum(["1024x1024","1536x1024","1024x1536"]).describe("Image size. Leave it undefined to use the auto size.").optional()}),m=r.object({path:r.string().describe("File to send. Absolute paths use the system path; relative paths resolve from the active workspace.")}),N=r.toJSONSchema(p),O=r.toJSONSchema(m);function g(t){return{contentItems:[{type:"inputText",text:JSON.stringify(t)}],success:!0}}const a=new Map;function F(t,e){const o=e.threadRef?.trim();a.set(t,{workspaceRoot:e.workspaceRoot,...o?{threadRef:o}:null,...e.matrixEvent?{matrixEvent:e.matrixEvent}:null,...e.llmProxyBinding?{llmProxyBinding:e.llmProxyBinding}:null})}function u(t,e){const o=a.get(t);if(o)for(const n of e)n&&n!==t&&F(n,o)}function $(t,e){if(t!=="item/started"&&t!=="item/completed"||!e||typeof e!="object")return;const o=e,n=o.item;if(!n||typeof n!="object")return;const i=n;if(i.type==="subAgentActivity"&&i.kind==="started"&&typeof o.threadId=="string"&&typeof i.agentThreadId=="string"){u(o.threadId,[i.agentThreadId]);return}i.type==="collabAgentToolCall"&&i.tool==="spawnAgent"&&typeof i.senderThreadId=="string"&&Array.isArray(i.receiverThreadIds)&&u(i.senderThreadId,i.receiverThreadIds.filter(s=>typeof s=="string"))}async function h(t){const e=a.get(t);if(e)return e.workspaceRoot;const{sessionManager:o}=await import("./codex.js"),n=o.workdirFor(t);if(!n)throw new Error(`No workspace context for thread ${t}; the session may not exist in this process`);return n}async function L(t){const{appConfig:e}=await import("./config.js");if(!e.openai.apiKey)throw new Error("Missing openai.api_key in LLM config");return{apiKey:e.openai.apiKey,baseURL:e.openai.baseUrl,imageModel:e.openai.imageModel,llmProxyBinding:a.get(t)?.llmProxyBinding}}async function C(){const{appConfig:t}=await import("./config.js");return t.schedule}function H(t=!1){const e=[{name:"generate_image",description:"Generate an image from a text prompt. The image is saved to the specified path (absolute path including filename) or the current working directory if not specified. Returns the saved file path.",inputSchema:N},{name:"send_file",description:"Send any readable file to the client. Absolute paths use the system path; relative paths resolve from the active workspace. The agent runtime captures this tool call and performs the actual send.",inputSchema:O},...A.map(o=>({name:o.name,description:o.description,inputSchema:o.inputSchema}))];return t&&e.push({name:c.name,description:c.description,inputSchema:c.inputSchema}),e}async function V(t){try{if(t.tool==="generate_image"){const e=p.parse(t.arguments),o=await L(t.threadId),n=w({apiKey:o.apiKey,baseURL:o.baseURL,fetch:R,...o.llmProxyBinding?{headers:{"X-Elevo-LLM-Binding":o.llmProxyBinding}}:null}),{image:i}=await T({model:n.image(o.imageModel),prompt:e.prompt,size:e.size,maxRetries:0,abortSignal:AbortSignal.timeout(d)}),s=e.store_path?l.resolve(e.store_path):l.join(process.cwd(),`generated_${Date.now()}.png`);return await f(l.dirname(s),{recursive:!0}),await y(s,Buffer.from(i.uint8Array)),{contentItems:[{type:"inputText",text:s}],success:!0}}if(t.tool==="send_file"){const e=m.parse(t.arguments),o=await v(e.path,await h(t.threadId));return{contentItems:[{type:"inputText",text:JSON.stringify({path:o})}],success:!0}}if(b(t.tool)){const e=await S(await h(t.threadId),t.tool,t.arguments,a.get(t.threadId));return g(e)}if(t.tool===c.name)return g(await E(await C(),a.get(t.threadId),t.arguments,fetch,t.callId));throw new Error(`Unknown dynamic tool: ${t.tool}`)}catch(e){const o=e instanceof k&&e.code==="INVALID_PATH"||e instanceof Error?e.message:String(e),n=e instanceof _?{error:{code:e.code,message:e.message,retryable:e.retryable,currentRevision:e.currentRevision}}:o;return{contentItems:[{type:"inputText",text:typeof n=="string"?n:JSON.stringify(n)}],success:!1}}}export{H as dynamicToolSpecs,V as handleDynamicToolCall,u as inheritManagedTaskToolContext,$ as inheritManagedTaskToolContextFromNotification,F as setManagedTaskToolContext};
1
+ import s from"node:path";import{mkdir as f,stat as y,writeFile as T}from"node:fs/promises";import{generateImage as w}from"ai";import{createOpenAI as I}from"@ai-sdk/openai";import{Agent as x,fetch as S}from"undici";import{z as a}from"zod";import{executeManagedTaskTool as v,isManagedTaskToolName as A,MANAGED_TASK_TOOL_DEFINITIONS as b}from"@messenger-agent/shared/managed-task-tools";import{AgentFileError as k,resolveAgentFilePath as E}from"@messenger-agent/shared/agent-files";import{executeScheduleTool as N,SCHEDULE_TOOL_DEFINITION as d,ScheduleToolError as M}from"@messenger-agent/shared/schedule-tools";const l=1200*1e3,_=new x({headersTimeout:l,bodyTimeout:l}),R=(t,e)=>S(t,{...e,dispatcher:_}),p=a.object({prompt:a.string().describe("The text prompt describing the image to generate"),store_path:a.string().describe("File path or directory to save the image. Directory paths (including paths ending with a slash) use an auto-generated filename. If omitted, saves to the current working directory with an auto-generated name.").optional(),size:a.enum(["1024x1024","1536x1024","1024x1536"]).describe("Image size. Leave it undefined to use the auto size.").optional()}),m=a.object({path:a.string().describe("File to send. Absolute paths use the system path; relative paths resolve from the active workspace.")}),F=a.toJSONSchema(p),O=a.toJSONSchema(m);function L(t){return t.endsWith(s.posix.sep)||t.endsWith(s.win32.sep)}async function C(t,e){const o=`generated_${Date.now()}.png`;if(!t)return s.join(e,o);const n=s.resolve(t);let r=L(t);if(!r)try{r=(await y(n)).isDirectory()}catch(i){if(i.code!=="ENOENT")throw i}return r?s.join(n,o):n}function g(t){return{contentItems:[{type:"inputText",text:JSON.stringify(t)}],success:!0}}const c=new Map;function D(t,e){const o=e.threadRef?.trim();c.set(t,{workspaceRoot:e.workspaceRoot,...o?{threadRef:o}:null,...e.matrixEvent?{matrixEvent:e.matrixEvent}:null,...e.llmProxyBinding?{llmProxyBinding:e.llmProxyBinding}:null})}function h(t,e){const o=c.get(t);if(o)for(const n of e)n&&n!==t&&D(n,o)}function V(t,e){if(t!=="item/started"&&t!=="item/completed"||!e||typeof e!="object")return;const o=e,n=o.item;if(!n||typeof n!="object")return;const r=n;if(r.type==="subAgentActivity"&&r.kind==="started"&&typeof o.threadId=="string"&&typeof r.agentThreadId=="string"){h(o.threadId,[r.agentThreadId]);return}r.type==="collabAgentToolCall"&&r.tool==="spawnAgent"&&typeof r.senderThreadId=="string"&&Array.isArray(r.receiverThreadIds)&&h(r.senderThreadId,r.receiverThreadIds.filter(i=>typeof i=="string"))}async function u(t){const e=c.get(t);if(e)return e.workspaceRoot;const{sessionManager:o}=await import("./codex.js"),n=o.workdirFor(t);if(!n)throw new Error(`No workspace context for thread ${t}; the session may not exist in this process`);return n}async function P(t){const{appConfig:e}=await import("./config.js");if(!e.openai.apiKey)throw new Error("Missing openai.api_key in LLM config");return{apiKey:e.openai.apiKey,baseURL:e.openai.baseUrl,imageModel:e.openai.imageModel,llmProxyBinding:c.get(t)?.llmProxyBinding}}async function B(){const{appConfig:t}=await import("./config.js");return t.schedule}function X(t=!1){const e=[{name:"generate_image",description:"Generate an image from a text prompt. The image is saved to the specified file path or directory, or the current working directory if not specified. Returns the saved file path.",inputSchema:F},{name:"send_file",description:"Send any readable file to the client. Absolute paths use the system path; relative paths resolve from the active workspace. The agent runtime captures this tool call and performs the actual send.",inputSchema:O},...b.map(o=>({name:o.name,description:o.description,inputSchema:o.inputSchema}))];return t&&e.push({name:d.name,description:d.description,inputSchema:d.inputSchema}),e}async function q(t){try{if(t.tool==="generate_image"){const e=p.parse(t.arguments),o=await P(t.threadId),n=I({apiKey:o.apiKey,baseURL:o.baseURL,fetch:R,...o.llmProxyBinding?{headers:{"X-Elevo-LLM-Binding":o.llmProxyBinding}}:null}),{image:r}=await w({model:n.image(o.imageModel),prompt:e.prompt,size:e.size,maxRetries:0,abortSignal:AbortSignal.timeout(l)}),i=await C(e.store_path,process.cwd());return await f(s.dirname(i),{recursive:!0}),await T(i,Buffer.from(r.uint8Array)),{contentItems:[{type:"inputText",text:i}],success:!0}}if(t.tool==="send_file"){const e=m.parse(t.arguments),o=await E(e.path,await u(t.threadId));return{contentItems:[{type:"inputText",text:JSON.stringify({path:o})}],success:!0}}if(A(t.tool)){const e=await v(await u(t.threadId),t.tool,t.arguments,c.get(t.threadId));return g(e)}if(t.tool===d.name)return g(await N(await B(),c.get(t.threadId),t.arguments,fetch,t.callId));throw new Error(`Unknown dynamic tool: ${t.tool}`)}catch(e){const o=e instanceof k&&e.code==="INVALID_PATH"||e instanceof Error?e.message:String(e),n=e instanceof M?{error:{code:e.code,message:e.message,retryable:e.retryable,currentRevision:e.currentRevision}}:o;return{contentItems:[{type:"inputText",text:typeof n=="string"?n:JSON.stringify(n)}],success:!1}}}export{X as dynamicToolSpecs,q as handleDynamicToolCall,h as inheritManagedTaskToolContext,V as inheritManagedTaskToolContextFromNotification,C as resolveImageFilePath,D as setManagedTaskToolContext};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@messenger-agent/codex-agent",
3
- "version": "0.37.1",
3
+ "version": "0.37.3-alpha.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "ws": "^8.21.0",
23
23
  "yaml": "^2.9.0",
24
24
  "zod": "^4.4.3",
25
- "@messenger-agent/shared": "0.37.1"
25
+ "@messenger-agent/shared": "0.37.3-alpha.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/ws": "^8.18.1"