@messenger-agent/codex-agent 0.24.0-alpha.2 → 0.24.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,172 +1 @@
1
- import path from "node:path";
2
- import { mkdir, writeFile } from "node:fs/promises";
3
- import { generateImage } from "ai";
4
- import { createOpenAI } from "@ai-sdk/openai";
5
- import { Agent, fetch as undiciFetch } from "undici";
6
- import { z } from "zod";
7
- import { executeManagedTaskTool, isManagedTaskToolName, MANAGED_TASK_TOOL_DEFINITIONS, } from "@messenger-agent/shared/managed-task-tools";
8
- import { AgentFileError, resolveAgentFilePath } from "@messenger-agent/shared/agent-files";
9
- const GENERATE_IMAGE_TIMEOUT_MS = 20 * 60 * 1000;
10
- const generateImageDispatcher = new Agent({
11
- headersTimeout: GENERATE_IMAGE_TIMEOUT_MS,
12
- bodyTimeout: GENERATE_IMAGE_TIMEOUT_MS,
13
- });
14
- const generateImageFetch = (input, init) => undiciFetch(input, {
15
- ...init,
16
- dispatcher: generateImageDispatcher,
17
- });
18
- const GenerateImageArgsSchema = z.object({
19
- prompt: z.string().describe("The text prompt describing the image to generate"),
20
- store_path: z
21
- .string()
22
- .describe("Absolute file path (including filename) to save the image. If omitted, saves to the current working directory with an auto-generated name.")
23
- .optional(),
24
- size: z
25
- .enum(["1024x1024", "1536x1024", "1024x1536"])
26
- .describe("Image size. Leave it undefined to use the auto size.")
27
- .optional(),
28
- });
29
- const SendFileArgsSchema = z.object({
30
- path: z
31
- .string()
32
- .describe("File to send. Absolute paths use the system path; relative paths resolve from the active workspace."),
33
- });
34
- const generateImageInputSchema = z.toJSONSchema(GenerateImageArgsSchema);
35
- const sendFileInputSchema = z.toJSONSchema(SendFileArgsSchema);
36
- function taskToolResponse(data) {
37
- return { contentItems: [{ type: "inputText", text: JSON.stringify(data) }], success: true };
38
- }
39
- const taskToolContexts = new Map();
40
- export function setManagedTaskToolContext(threadId, context) {
41
- const threadRef = context.threadRef?.trim();
42
- taskToolContexts.set(threadId, {
43
- workspaceRoot: context.workspaceRoot,
44
- ...(threadRef ? { threadRef } : null),
45
- ...(context.matrixEvent ? { matrixEvent: context.matrixEvent } : null),
46
- ...(context.llmProxyBinding ? { llmProxyBinding: context.llmProxyBinding } : null),
47
- });
48
- }
49
- export function inheritManagedTaskToolContext(parentThreadId, childThreadIds) {
50
- const context = taskToolContexts.get(parentThreadId);
51
- if (!context)
52
- return;
53
- for (const childThreadId of childThreadIds) {
54
- if (childThreadId && childThreadId !== parentThreadId) {
55
- setManagedTaskToolContext(childThreadId, context);
56
- }
57
- }
58
- }
59
- export function inheritManagedTaskToolContextFromNotification(method, params) {
60
- if (method !== "item/started" && method !== "item/completed")
61
- return;
62
- if (!params || typeof params !== "object")
63
- return;
64
- const record = params;
65
- const item = record.item;
66
- if (!item || typeof item !== "object")
67
- return;
68
- const itemRecord = item;
69
- if (itemRecord.type === "subAgentActivity" &&
70
- itemRecord.kind === "started" &&
71
- typeof record.threadId === "string" &&
72
- typeof itemRecord.agentThreadId === "string") {
73
- inheritManagedTaskToolContext(record.threadId, [itemRecord.agentThreadId]);
74
- return;
75
- }
76
- if (itemRecord.type === "collabAgentToolCall" &&
77
- itemRecord.tool === "spawnAgent" &&
78
- typeof itemRecord.senderThreadId === "string" &&
79
- Array.isArray(itemRecord.receiverThreadIds)) {
80
- inheritManagedTaskToolContext(itemRecord.senderThreadId, itemRecord.receiverThreadIds.filter((threadId) => typeof threadId === "string"));
81
- }
82
- }
83
- async function workspaceRootForTasks(threadId) {
84
- const context = taskToolContexts.get(threadId);
85
- if (context)
86
- return context.workspaceRoot;
87
- const { sessionManager } = await import("./codex.js");
88
- const workdir = sessionManager.workdirFor(threadId);
89
- if (!workdir) {
90
- throw new Error(`No workspace context for thread ${threadId}; the session may not exist in this process`);
91
- }
92
- return workdir;
93
- }
94
- async function loadOpenAIConfig(threadId) {
95
- const { appConfig } = await import("./config.js");
96
- if (!appConfig.openai.apiKey) {
97
- throw new Error("Missing openai.api_key in LLM config");
98
- }
99
- return {
100
- apiKey: appConfig.openai.apiKey,
101
- baseURL: appConfig.openai.baseUrl,
102
- imageModel: appConfig.openai.imageModel,
103
- llmProxyBinding: taskToolContexts.get(threadId)?.llmProxyBinding,
104
- };
105
- }
106
- export function dynamicToolSpecs() {
107
- return [
108
- {
109
- name: "generate_image",
110
- 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.",
111
- inputSchema: generateImageInputSchema,
112
- },
113
- {
114
- name: "send_file",
115
- 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.",
116
- inputSchema: sendFileInputSchema,
117
- },
118
- ...MANAGED_TASK_TOOL_DEFINITIONS.map((definition) => ({
119
- name: definition.name,
120
- description: definition.description,
121
- inputSchema: definition.inputSchema,
122
- })),
123
- ];
124
- }
125
- export async function handleDynamicToolCall(params) {
126
- try {
127
- if (params.tool === "generate_image") {
128
- const args = GenerateImageArgsSchema.parse(params.arguments);
129
- const config = await loadOpenAIConfig(params.threadId);
130
- const openai = createOpenAI({
131
- apiKey: config.apiKey,
132
- baseURL: config.baseURL,
133
- fetch: generateImageFetch,
134
- ...(config.llmProxyBinding ? { headers: { "X-Elevo-LLM-Binding": config.llmProxyBinding } } : null),
135
- });
136
- const { image } = await generateImage({
137
- model: openai.image(config.imageModel),
138
- prompt: args.prompt,
139
- size: args.size,
140
- maxRetries: 0,
141
- abortSignal: AbortSignal.timeout(GENERATE_IMAGE_TIMEOUT_MS),
142
- });
143
- const filePath = args.store_path
144
- ? path.resolve(args.store_path)
145
- : path.join(process.cwd(), `generated_${Date.now()}.png`);
146
- await mkdir(path.dirname(filePath), { recursive: true });
147
- await writeFile(filePath, Buffer.from(image.uint8Array));
148
- return { contentItems: [{ type: "inputText", text: filePath }], success: true };
149
- }
150
- if (params.tool === "send_file") {
151
- const args = SendFileArgsSchema.parse(params.arguments);
152
- const filePath = await resolveAgentFilePath(args.path, await workspaceRootForTasks(params.threadId));
153
- return {
154
- contentItems: [{ type: "inputText", text: JSON.stringify({ path: filePath }) }],
155
- success: true,
156
- };
157
- }
158
- if (isManagedTaskToolName(params.tool)) {
159
- const result = await executeManagedTaskTool(await workspaceRootForTasks(params.threadId), params.tool, params.arguments, taskToolContexts.get(params.threadId));
160
- return taskToolResponse(result);
161
- }
162
- throw new Error(`Unknown dynamic tool: ${params.tool}`);
163
- }
164
- catch (err) {
165
- const message = err instanceof AgentFileError && err.code === "INVALID_PATH"
166
- ? err.message
167
- : err instanceof Error
168
- ? err.message
169
- : String(err);
170
- return { contentItems: [{ type: "inputText", text: message }], success: false };
171
- }
172
- }
1
+ import c from"node:path";import{mkdir as h,writeFile as u}from"node:fs/promises";import{generateImage as f}from"ai";import{createOpenAI as y}from"@ai-sdk/openai";import{Agent as T,fetch as w}from"undici";import{z as r}from"zod";import{executeManagedTaskTool as x,isManagedTaskToolName as I,MANAGED_TASK_TOOL_DEFINITIONS as A}from"@messenger-agent/shared/managed-task-tools";import{AgentFileError as b,resolveAgentFilePath as k}from"@messenger-agent/shared/agent-files";const p=1200*1e3,S=new T({headersTimeout:p,bodyTimeout:p}),v=(t,e)=>w(t,{...e,dispatcher:S}),l=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.")}),M=r.toJSONSchema(l),E=r.toJSONSchema(m);function _(t){return{contentItems:[{type:"inputText",text:JSON.stringify(t)}],success:!0}}const s=new Map;function R(t,e){const o=e.threadRef?.trim();s.set(t,{workspaceRoot:e.workspaceRoot,...o?{threadRef:o}:null,...e.matrixEvent?{matrixEvent:e.matrixEvent}:null,...e.llmProxyBinding?{llmProxyBinding:e.llmProxyBinding}:null})}function d(t,e){const o=s.get(t);if(o)for(const n of e)n&&n!==t&&R(n,o)}function K(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"){d(o.threadId,[i.agentThreadId]);return}i.type==="collabAgentToolCall"&&i.tool==="spawnAgent"&&typeof i.senderThreadId=="string"&&Array.isArray(i.receiverThreadIds)&&d(i.senderThreadId,i.receiverThreadIds.filter(a=>typeof a=="string"))}async function g(t){const e=s.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 F(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:s.get(t)?.llmProxyBinding}}function U(){return[{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:M},{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:E},...A.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))]}async function j(t){try{if(t.tool==="generate_image"){const e=l.parse(t.arguments),o=await F(t.threadId),n=y({apiKey:o.apiKey,baseURL:o.baseURL,fetch:v,...o.llmProxyBinding?{headers:{"X-Elevo-LLM-Binding":o.llmProxyBinding}}:null}),{image:i}=await f({model:n.image(o.imageModel),prompt:e.prompt,size:e.size,maxRetries:0,abortSignal:AbortSignal.timeout(p)}),a=e.store_path?c.resolve(e.store_path):c.join(process.cwd(),`generated_${Date.now()}.png`);return await h(c.dirname(a),{recursive:!0}),await u(a,Buffer.from(i.uint8Array)),{contentItems:[{type:"inputText",text:a}],success:!0}}if(t.tool==="send_file"){const e=m.parse(t.arguments),o=await k(e.path,await g(t.threadId));return{contentItems:[{type:"inputText",text:JSON.stringify({path:o})}],success:!0}}if(I(t.tool)){const e=await x(await g(t.threadId),t.tool,t.arguments,s.get(t.threadId));return _(e)}throw new Error(`Unknown dynamic tool: ${t.tool}`)}catch(e){return{contentItems:[{type:"inputText",text:e instanceof b&&e.code==="INVALID_PATH"||e instanceof Error?e.message:String(e)}],success:!1}}}export{U as dynamicToolSpecs,j as handleDynamicToolCall,d as inheritManagedTaskToolContext,K as inheritManagedTaskToolContextFromNotification,R as setManagedTaskToolContext};
package/dist/git-init.js CHANGED
@@ -1 +1 @@
1
- export { initGit, initGitCoAuthorsHook, initGitLab, initGitProxy } from "@messenger-agent/shared/git-init";
1
+ import{initGit as o,initGitCoAuthorsHook as n,initGitLab as r,initGitProxy as G}from"@messenger-agent/shared/git-init";export{o as initGit,n as initGitCoAuthorsHook,r as initGitLab,G as initGitProxy};
package/dist/index.js CHANGED
@@ -1,19 +1 @@
1
- import { serve } from "@hono/node-server";
2
- import app from "./app.js";
3
- import { appConfig } from "./config.js";
4
- import { initGit } from "./git-init.js";
5
- import { startCodexTunnelClient } from "./tunnel-client.js";
6
- import { logger } from "@messenger-agent/shared/logger";
7
- const port = appConfig.port;
8
- try {
9
- await initGit(appConfig);
10
- }
11
- catch (err) {
12
- logger.warn("Git initialization failed; continuing agent startup:", err);
13
- }
14
- const tunnelClient = startCodexTunnelClient(appConfig.tunnel);
15
- if (!tunnelClient) {
16
- serve({ fetch: app.fetch, port }, () => {
17
- logger.info(`codex-agent listening on http://0.0.0.0:${port}`);
18
- });
19
- }
1
+ import{serve as r}from"@hono/node-server";import e from"./app.js";import{appConfig as t}from"./config.js";import{initGit as p}from"./git-init.js";import{startCodexTunnelClient as a}from"./tunnel-client.js";import{logger as i}from"@messenger-agent/shared/logger";const n=t.port;try{await p(t)}catch(o){i.warn("Git initialization failed; continuing agent startup:",o)}const f=a(t.tunnel);f||r({fetch:e.fetch,port:n},()=>{i.info(`codex-agent listening on http://0.0.0.0:${n}`)});
@@ -1,21 +1,3 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { fileURLToPath } from "node:url";
3
- import { logger } from "@messenger-agent/shared/logger";
4
- const DEFAULT_TEMPLATE_PATHS = [
5
- fileURLToPath(new URL("./assets/codex-home/AGENTS.md", import.meta.url)),
6
- fileURLToPath(new URL("../../../assets/codex-home/AGENTS.md", import.meta.url)),
7
- "/app/assets/codex-home/AGENTS.md",
8
- ];
9
- const CODEX_MANAGED_TASK_TOOLS = `## Codex Managed Task Tools
1
+ import{existsSync as s,readFileSync as r}from"node:fs";import{fileURLToPath as a}from"node:url";import{logger as m}from"@messenger-agent/shared/logger";const d=[a(new URL("./assets/codex-home/AGENTS.md",import.meta.url)),a(new URL("../../../assets/codex-home/AGENTS.md",import.meta.url)),"/app/assets/codex-home/AGENTS.md"],o="## Codex Managed Task Tools\n\nWhen using managed task tools in Codex, call these tool names directly: `search_managed_tasks`, `get_managed_task`, `create_managed_task`, `update_managed_task`, `apply_managed_task_patch`, and `delete_managed_task`.\n";function _(n){const e=[n??process.env.CODEX_AGENTS_TEMPLATE_PATH,...d].find(t=>!!(t&&s(t)));return e?`${r(e,"utf-8").trimEnd()}
10
2
 
11
- When using managed task tools in Codex, call these tool names directly: \`search_managed_tasks\`, \`get_managed_task\`, \`create_managed_task\`, \`update_managed_task\`, \`apply_managed_task_patch\`, and \`delete_managed_task\`.
12
- `;
13
- export function loadCodexPlatformInstructions(templatePath) {
14
- const path = [templatePath ?? process.env.CODEX_AGENTS_TEMPLATE_PATH, ...DEFAULT_TEMPLATE_PATHS].find((candidate) => Boolean(candidate && existsSync(candidate)));
15
- if (!path) {
16
- logger.warn("Codex platform instructions template not found");
17
- return CODEX_MANAGED_TASK_TOOLS;
18
- }
19
- return `${readFileSync(path, "utf-8").trimEnd()}\n\n${CODEX_MANAGED_TASK_TOOLS}`;
20
- }
21
- export const codexPlatformInstructions = loadCodexPlatformInstructions();
3
+ ${o}`:(m.warn("Codex platform instructions template not found"),o)}const p=_();export{p as codexPlatformInstructions,_ as loadCodexPlatformInstructions};