@messenger-agent/codex-agent 0.24.0-alpha.2
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/app-server-client.d.ts +32 -0
- package/dist/app-server-client.js +316 -0
- package/dist/app-server-protocol.d.ts +325 -0
- package/dist/app-server-protocol.js +1 -0
- package/dist/app.d.ts +3 -0
- package/dist/app.js +15 -0
- package/dist/assets/codex-home/AGENTS.md +50 -0
- package/dist/codex.d.ts +63 -0
- package/dist/codex.js +461 -0
- package/dist/config.d.ts +32 -0
- package/dist/config.js +154 -0
- package/dist/db.d.ts +10 -0
- package/dist/db.js +32 -0
- package/dist/dynamic-tools.d.ts +14 -0
- package/dist/dynamic-tools.js +172 -0
- package/dist/git-init.d.ts +1 -0
- package/dist/git-init.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +19 -0
- package/dist/platform-instructions.d.ts +2 -0
- package/dist/platform-instructions.js +21 -0
- package/dist/prompts/plan-mode-system-reminder.txt +26 -0
- package/dist/prompts/question-tool-description.txt +12 -0
- package/dist/routes/chat.d.ts +27 -0
- package/dist/routes/chat.js +909 -0
- package/dist/routes/shared.d.ts +37 -0
- package/dist/routes/shared.js +218 -0
- package/dist/schemas.d.ts +112 -0
- package/dist/schemas.js +72 -0
- package/dist/tunnel-client.d.ts +15 -0
- package/dist/tunnel-client.js +232 -0
- package/package.json +36 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { handleDynamicToolCall } from "./dynamic-tools.js";
|
|
3
|
+
import type { ToolRequestUserInputResponse } from "./app-server-protocol.js";
|
|
4
|
+
type DynamicToolHandler = typeof handleDynamicToolCall;
|
|
5
|
+
export declare function findCodexPath(): string;
|
|
6
|
+
export declare class AppServerClient extends EventEmitter {
|
|
7
|
+
private toolHandler;
|
|
8
|
+
private child;
|
|
9
|
+
private nextId;
|
|
10
|
+
private pending;
|
|
11
|
+
private pendingUserInputRequests;
|
|
12
|
+
private notifiedUserInputRequests;
|
|
13
|
+
private answeredUserInputRequests;
|
|
14
|
+
private started;
|
|
15
|
+
private buffer;
|
|
16
|
+
constructor(toolHandler?: DynamicToolHandler);
|
|
17
|
+
request<T = unknown>(method: string, params: unknown): Promise<T>;
|
|
18
|
+
private writeRequest;
|
|
19
|
+
notify(method: string, params: unknown): Promise<void>;
|
|
20
|
+
respondToUserInput(threadId: string, itemId: string, response: ToolRequestUserInputResponse): Promise<boolean>;
|
|
21
|
+
pendingUserInputTurnId(threadId: string, itemId: string): string | undefined;
|
|
22
|
+
discardPendingUserInput(threadId: string, itemId: string): void;
|
|
23
|
+
private ensureStarted;
|
|
24
|
+
private start;
|
|
25
|
+
private handleStdout;
|
|
26
|
+
private handleMessage;
|
|
27
|
+
private handleServerRequest;
|
|
28
|
+
private handleExit;
|
|
29
|
+
private handleProcessError;
|
|
30
|
+
}
|
|
31
|
+
export declare const appServerClient: AppServerClient;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
3
|
+
import { statSync } from "node:fs";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { handleDynamicToolCall, inheritManagedTaskToolContextFromNotification } from "./dynamic-tools.js";
|
|
7
|
+
import { logger } from "@messenger-agent/shared/logger";
|
|
8
|
+
const CODEX_NPM_NAME = "@openai/codex";
|
|
9
|
+
const PLATFORM_PACKAGE_BY_TARGET = {
|
|
10
|
+
"x86_64-unknown-linux-musl": "@openai/codex-linux-x64",
|
|
11
|
+
"aarch64-unknown-linux-musl": "@openai/codex-linux-arm64",
|
|
12
|
+
"x86_64-apple-darwin": "@openai/codex-darwin-x64",
|
|
13
|
+
"aarch64-apple-darwin": "@openai/codex-darwin-arm64",
|
|
14
|
+
"x86_64-pc-windows-msvc": "@openai/codex-win32-x64",
|
|
15
|
+
"aarch64-pc-windows-msvc": "@openai/codex-win32-arm64",
|
|
16
|
+
};
|
|
17
|
+
const moduleRequire = createRequire(import.meta.url);
|
|
18
|
+
export function findCodexPath() {
|
|
19
|
+
const { platform, arch } = process;
|
|
20
|
+
let targetTriple = null;
|
|
21
|
+
switch (platform) {
|
|
22
|
+
case "linux":
|
|
23
|
+
case "android":
|
|
24
|
+
if (arch === "x64")
|
|
25
|
+
targetTriple = "x86_64-unknown-linux-musl";
|
|
26
|
+
if (arch === "arm64")
|
|
27
|
+
targetTriple = "aarch64-unknown-linux-musl";
|
|
28
|
+
break;
|
|
29
|
+
case "darwin":
|
|
30
|
+
if (arch === "x64")
|
|
31
|
+
targetTriple = "x86_64-apple-darwin";
|
|
32
|
+
if (arch === "arm64")
|
|
33
|
+
targetTriple = "aarch64-apple-darwin";
|
|
34
|
+
break;
|
|
35
|
+
case "win32":
|
|
36
|
+
if (arch === "x64")
|
|
37
|
+
targetTriple = "x86_64-pc-windows-msvc";
|
|
38
|
+
if (arch === "arm64")
|
|
39
|
+
targetTriple = "aarch64-pc-windows-msvc";
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
if (!targetTriple) {
|
|
45
|
+
throw new Error(`Unsupported platform: ${platform} (${arch})`);
|
|
46
|
+
}
|
|
47
|
+
const platformPackage = PLATFORM_PACKAGE_BY_TARGET[targetTriple];
|
|
48
|
+
if (!platformPackage) {
|
|
49
|
+
throw new Error(`Unsupported target triple: ${targetTriple}`);
|
|
50
|
+
}
|
|
51
|
+
let vendorRoot;
|
|
52
|
+
try {
|
|
53
|
+
const codexPackageJsonPath = moduleRequire.resolve(`${CODEX_NPM_NAME}/package.json`);
|
|
54
|
+
const codexRequire = createRequire(codexPackageJsonPath);
|
|
55
|
+
const platformPackageJsonPath = codexRequire.resolve(`${platformPackage}/package.json`);
|
|
56
|
+
vendorRoot = path.join(path.dirname(platformPackageJsonPath), "vendor");
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
throw new Error(`Unable to locate Codex CLI binaries. Ensure ${CODEX_NPM_NAME} is installed with optional dependencies.`);
|
|
60
|
+
}
|
|
61
|
+
const codexBinaryName = process.platform === "win32" ? "codex.exe" : "codex";
|
|
62
|
+
const nativePackage = resolveNativePackage(vendorRoot, targetTriple, codexBinaryName);
|
|
63
|
+
if (!nativePackage) {
|
|
64
|
+
throw new Error(`Unable to locate Codex CLI binaries for ${targetTriple}. Ensure ${CODEX_NPM_NAME} is installed with optional dependencies.`);
|
|
65
|
+
}
|
|
66
|
+
return nativePackage.executablePath;
|
|
67
|
+
}
|
|
68
|
+
function resolveNativePackage(vendorRoot, targetTriple, codexBinaryName) {
|
|
69
|
+
const packageRoot = path.join(vendorRoot, targetTriple);
|
|
70
|
+
const packageBinaryPath = path.join(packageRoot, "bin", codexBinaryName);
|
|
71
|
+
if (isFile(packageBinaryPath) && isFile(path.join(packageRoot, "codex-package.json"))) {
|
|
72
|
+
return {
|
|
73
|
+
executablePath: packageBinaryPath,
|
|
74
|
+
pathDirs: existingDirs(path.join(packageRoot, "codex-path")),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const legacyBinaryPath = path.join(packageRoot, "codex", codexBinaryName);
|
|
78
|
+
if (isFile(legacyBinaryPath)) {
|
|
79
|
+
return {
|
|
80
|
+
executablePath: legacyBinaryPath,
|
|
81
|
+
pathDirs: existingDirs(path.join(packageRoot, "path")),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
function existingDirs(...dirs) {
|
|
87
|
+
return dirs.filter(isDirectory);
|
|
88
|
+
}
|
|
89
|
+
function isFile(filePath) {
|
|
90
|
+
try {
|
|
91
|
+
return statSync(filePath).isFile();
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function isDirectory(filePath) {
|
|
98
|
+
try {
|
|
99
|
+
return statSync(filePath).isDirectory();
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function parseCommand(command) {
|
|
106
|
+
const trimmed = command.trim();
|
|
107
|
+
if (!trimmed)
|
|
108
|
+
return { command: "codex", args: ["app-server", "--listen", "stdio://"] };
|
|
109
|
+
const parts = trimmed.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) ?? [];
|
|
110
|
+
const [cmd, ...args] = parts.map((part) => {
|
|
111
|
+
if ((part.startsWith('"') && part.endsWith('"')) || (part.startsWith("'") && part.endsWith("'"))) {
|
|
112
|
+
return part.slice(1, -1);
|
|
113
|
+
}
|
|
114
|
+
return part;
|
|
115
|
+
});
|
|
116
|
+
return { command: cmd ?? "codex", args };
|
|
117
|
+
}
|
|
118
|
+
export class AppServerClient extends EventEmitter {
|
|
119
|
+
toolHandler;
|
|
120
|
+
child;
|
|
121
|
+
nextId = 1;
|
|
122
|
+
pending = new Map();
|
|
123
|
+
pendingUserInputRequests = new Map();
|
|
124
|
+
notifiedUserInputRequests = new Set();
|
|
125
|
+
answeredUserInputRequests = new Set();
|
|
126
|
+
started;
|
|
127
|
+
buffer = "";
|
|
128
|
+
constructor(toolHandler = handleDynamicToolCall) {
|
|
129
|
+
super();
|
|
130
|
+
this.toolHandler = toolHandler;
|
|
131
|
+
}
|
|
132
|
+
async request(method, params) {
|
|
133
|
+
await this.ensureStarted();
|
|
134
|
+
return this.writeRequest(method, params);
|
|
135
|
+
}
|
|
136
|
+
async writeRequest(method, params) {
|
|
137
|
+
if (!this.child)
|
|
138
|
+
throw new Error("Codex app-server is not running");
|
|
139
|
+
const id = this.nextId++;
|
|
140
|
+
const payload = JSON.stringify({ jsonrpc: "2.0", id, method, params });
|
|
141
|
+
return new Promise((resolve, reject) => {
|
|
142
|
+
this.pending.set(id, { resolve: (value) => resolve(value), reject });
|
|
143
|
+
this.child?.stdin.write(`${payload}\n`, (err) => {
|
|
144
|
+
if (err) {
|
|
145
|
+
this.pending.delete(id);
|
|
146
|
+
reject(err);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
async notify(method, params) {
|
|
152
|
+
await this.ensureStarted();
|
|
153
|
+
if (!this.child)
|
|
154
|
+
throw new Error("Codex app-server is not running");
|
|
155
|
+
this.child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", method, params })}\n`);
|
|
156
|
+
}
|
|
157
|
+
async respondToUserInput(threadId, itemId, response) {
|
|
158
|
+
await this.ensureStarted();
|
|
159
|
+
if (!this.child)
|
|
160
|
+
throw new Error("Codex app-server is not running");
|
|
161
|
+
const key = userInputRequestKey(threadId, itemId);
|
|
162
|
+
if (this.answeredUserInputRequests.has(key)) {
|
|
163
|
+
throw new Error(`User input request already answered for item: ${itemId}`);
|
|
164
|
+
}
|
|
165
|
+
const pending = this.pendingUserInputRequests.get(key);
|
|
166
|
+
if (!pending)
|
|
167
|
+
return false;
|
|
168
|
+
this.pendingUserInputRequests.delete(key);
|
|
169
|
+
this.answeredUserInputRequests.add(key);
|
|
170
|
+
this.child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id: pending.requestId, result: response })}\n`);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
pendingUserInputTurnId(threadId, itemId) {
|
|
174
|
+
return this.pendingUserInputRequests.get(userInputRequestKey(threadId, itemId))?.turnId;
|
|
175
|
+
}
|
|
176
|
+
discardPendingUserInput(threadId, itemId) {
|
|
177
|
+
const key = userInputRequestKey(threadId, itemId);
|
|
178
|
+
this.pendingUserInputRequests.delete(key);
|
|
179
|
+
this.notifiedUserInputRequests.delete(key);
|
|
180
|
+
this.answeredUserInputRequests.delete(key);
|
|
181
|
+
}
|
|
182
|
+
async ensureStarted() {
|
|
183
|
+
if (!this.started) {
|
|
184
|
+
this.started = this.start();
|
|
185
|
+
}
|
|
186
|
+
return this.started;
|
|
187
|
+
}
|
|
188
|
+
async start() {
|
|
189
|
+
const configured = process.env.CODEX_APP_SERVER_COMMAND;
|
|
190
|
+
const { command, args } = configured
|
|
191
|
+
? parseCommand(configured)
|
|
192
|
+
: { command: findCodexPath(), args: ["app-server", "--listen", "stdio://"] };
|
|
193
|
+
const env = { ...process.env };
|
|
194
|
+
this.child = spawn(command, args, { env, stdio: ["pipe", "pipe", "pipe"] });
|
|
195
|
+
this.child.stdout.setEncoding("utf-8");
|
|
196
|
+
this.child.stderr.setEncoding("utf-8");
|
|
197
|
+
this.child.stdout.on("data", (chunk) => this.handleStdout(chunk));
|
|
198
|
+
this.child.stderr.on("data", (chunk) => logger.debug(`codex app-server stderr: ${chunk.trimEnd()}`));
|
|
199
|
+
this.child.on("exit", (code, signal) => this.handleExit(code, signal));
|
|
200
|
+
this.child.on("error", (err) => this.handleProcessError(err));
|
|
201
|
+
await this.writeRequest("initialize", {
|
|
202
|
+
clientInfo: { name: "codex-agent", title: "codex-agent", version: "0.1.0" },
|
|
203
|
+
capabilities: { experimentalApi: true, requestAttestation: false },
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
handleStdout(chunk) {
|
|
207
|
+
this.buffer += chunk;
|
|
208
|
+
while (true) {
|
|
209
|
+
const newline = this.buffer.indexOf("\n");
|
|
210
|
+
if (newline === -1)
|
|
211
|
+
break;
|
|
212
|
+
const line = this.buffer.slice(0, newline).trim();
|
|
213
|
+
this.buffer = this.buffer.slice(newline + 1);
|
|
214
|
+
if (!line)
|
|
215
|
+
continue;
|
|
216
|
+
try {
|
|
217
|
+
this.handleMessage(JSON.parse(line));
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
logger.error("Failed to parse codex app-server JSON-RPC message:", err);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
handleMessage(message) {
|
|
225
|
+
if (!message.method ||
|
|
226
|
+
!(message.method.endsWith("/delta") ||
|
|
227
|
+
message.method.endsWith("/outputDelta") ||
|
|
228
|
+
message.method === "turn/diff/updated")) {
|
|
229
|
+
logger.debug(`Received message:`, message);
|
|
230
|
+
}
|
|
231
|
+
if (message.id !== undefined && message.method) {
|
|
232
|
+
this.handleServerRequest(message).catch((err) => logger.error("Failed to handle app-server request:", err));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (message.id !== undefined) {
|
|
236
|
+
const pending = this.pending.get(message.id);
|
|
237
|
+
if (!pending)
|
|
238
|
+
return;
|
|
239
|
+
this.pending.delete(message.id);
|
|
240
|
+
if (message.error) {
|
|
241
|
+
pending.reject(new Error(message.error.message ?? `Codex app-server request failed: ${message.error.code}`));
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
pending.resolve(message.result);
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (message.method) {
|
|
249
|
+
inheritManagedTaskToolContextFromNotification(message.method, message.params);
|
|
250
|
+
this.emit("notification", { method: message.method, params: message.params });
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async handleServerRequest(message) {
|
|
254
|
+
if (!this.child || message.id === undefined || !message.method)
|
|
255
|
+
return;
|
|
256
|
+
try {
|
|
257
|
+
if (message.method === "item/tool/call") {
|
|
258
|
+
const result = await this.toolHandler(message.params);
|
|
259
|
+
this.child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id: message.id, result })}\n`);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (message.method === "item/tool/requestUserInput") {
|
|
263
|
+
const requestParams = message.params;
|
|
264
|
+
const requestKey = userInputRequestKey(requestParams.threadId, requestParams.itemId);
|
|
265
|
+
this.pendingUserInputRequests.set(requestKey, {
|
|
266
|
+
threadId: requestParams.threadId,
|
|
267
|
+
turnId: requestParams.turnId,
|
|
268
|
+
itemId: requestParams.itemId,
|
|
269
|
+
requestId: message.id,
|
|
270
|
+
});
|
|
271
|
+
if (this.notifiedUserInputRequests.has(requestKey))
|
|
272
|
+
return;
|
|
273
|
+
this.notifiedUserInputRequests.add(requestKey);
|
|
274
|
+
this.emit("notification", { method: message.method, params: requestParams });
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
this.child.stdin.write(`${JSON.stringify({
|
|
278
|
+
jsonrpc: "2.0",
|
|
279
|
+
id: message.id,
|
|
280
|
+
error: { code: -32601, message: `Unsupported server request: ${message.method}` },
|
|
281
|
+
})}\n`);
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
const messageText = err instanceof Error ? err.message : String(err);
|
|
285
|
+
this.child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id: message.id, error: { code: -32000, message: messageText } })}\n`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
handleExit(code, signal) {
|
|
289
|
+
const err = new Error(`Codex app-server exited${signal ? ` with signal ${signal}` : ` with code ${code}`}`);
|
|
290
|
+
for (const pending of this.pending.values()) {
|
|
291
|
+
pending.reject(err);
|
|
292
|
+
}
|
|
293
|
+
this.pending.clear();
|
|
294
|
+
this.pendingUserInputRequests.clear();
|
|
295
|
+
this.notifiedUserInputRequests.clear();
|
|
296
|
+
this.answeredUserInputRequests.clear();
|
|
297
|
+
this.child = undefined;
|
|
298
|
+
this.started = undefined;
|
|
299
|
+
this.emit("exit", err);
|
|
300
|
+
}
|
|
301
|
+
handleProcessError(err) {
|
|
302
|
+
for (const pending of this.pending.values()) {
|
|
303
|
+
pending.reject(err);
|
|
304
|
+
}
|
|
305
|
+
this.pending.clear();
|
|
306
|
+
this.pendingUserInputRequests.clear();
|
|
307
|
+
this.notifiedUserInputRequests.clear();
|
|
308
|
+
this.answeredUserInputRequests.clear();
|
|
309
|
+
this.emit("exit", err);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function userInputRequestKey(threadId, itemId) {
|
|
313
|
+
return `${threadId}:${itemId}`;
|
|
314
|
+
}
|
|
315
|
+
export const appServerClient = new AppServerClient();
|
|
316
|
+
appServerClient.setMaxListeners(20);
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
export type SandboxMode = "read-only" | "workspace-write" | "danger-full-access";
|
|
2
|
+
export type UsageBreakdown = {
|
|
3
|
+
input_tokens?: number;
|
|
4
|
+
output_tokens?: number;
|
|
5
|
+
total_tokens?: number;
|
|
6
|
+
};
|
|
7
|
+
export type Usage = {
|
|
8
|
+
total?: UsageBreakdown;
|
|
9
|
+
last?: UsageBreakdown;
|
|
10
|
+
model_context_window?: number;
|
|
11
|
+
};
|
|
12
|
+
export type UserInput = {
|
|
13
|
+
type: "text";
|
|
14
|
+
text: string;
|
|
15
|
+
text_elements?: [];
|
|
16
|
+
};
|
|
17
|
+
export type DynamicToolSpec = {
|
|
18
|
+
name: string;
|
|
19
|
+
description: string;
|
|
20
|
+
inputSchema: unknown;
|
|
21
|
+
namespace?: string;
|
|
22
|
+
deferLoading?: boolean;
|
|
23
|
+
};
|
|
24
|
+
export type ThreadStartParams = {
|
|
25
|
+
model?: string | null;
|
|
26
|
+
modelProvider?: string | null;
|
|
27
|
+
cwd?: string | null;
|
|
28
|
+
approvalPolicy?: "never" | "on-request" | "on-failure" | "untrusted" | null;
|
|
29
|
+
sandbox?: SandboxMode | null;
|
|
30
|
+
config?: Record<string, unknown> | null;
|
|
31
|
+
baseInstructions?: string | null;
|
|
32
|
+
developerInstructions?: string | null;
|
|
33
|
+
dynamicTools?: DynamicToolSpec[] | null;
|
|
34
|
+
experimentalRawEvents: boolean;
|
|
35
|
+
persistExtendedHistory: boolean;
|
|
36
|
+
};
|
|
37
|
+
export type ThreadResumeParams = {
|
|
38
|
+
threadId: string;
|
|
39
|
+
model?: string | null;
|
|
40
|
+
modelProvider?: string | null;
|
|
41
|
+
cwd?: string | null;
|
|
42
|
+
approvalPolicy?: "never" | "on-request" | "on-failure" | "untrusted" | null;
|
|
43
|
+
sandbox?: SandboxMode | null;
|
|
44
|
+
config?: Record<string, unknown> | null;
|
|
45
|
+
baseInstructions?: string | null;
|
|
46
|
+
developerInstructions?: string | null;
|
|
47
|
+
excludeTurns?: boolean;
|
|
48
|
+
persistExtendedHistory: boolean;
|
|
49
|
+
};
|
|
50
|
+
export type ThreadForkParams = {
|
|
51
|
+
threadId: string;
|
|
52
|
+
lastTurnId?: string | null;
|
|
53
|
+
model?: string | null;
|
|
54
|
+
modelProvider?: string | null;
|
|
55
|
+
cwd?: string | null;
|
|
56
|
+
approvalPolicy?: "never" | "on-request" | "on-failure" | "untrusted" | null;
|
|
57
|
+
sandbox?: SandboxMode | null;
|
|
58
|
+
config?: Record<string, unknown> | null;
|
|
59
|
+
baseInstructions?: string | null;
|
|
60
|
+
developerInstructions?: string | null;
|
|
61
|
+
ephemeral?: boolean;
|
|
62
|
+
excludeTurns?: boolean;
|
|
63
|
+
};
|
|
64
|
+
export type ThreadReadParams = {
|
|
65
|
+
threadId: string;
|
|
66
|
+
includeTurns?: boolean;
|
|
67
|
+
};
|
|
68
|
+
export type ThreadRollbackParams = {
|
|
69
|
+
threadId: string;
|
|
70
|
+
numTurns: number;
|
|
71
|
+
};
|
|
72
|
+
export type TurnStartParams = {
|
|
73
|
+
threadId: string;
|
|
74
|
+
input: UserInput[];
|
|
75
|
+
cwd?: string | null;
|
|
76
|
+
approvalPolicy?: "never" | "on-request" | "on-failure" | "untrusted" | null;
|
|
77
|
+
model?: string | null;
|
|
78
|
+
collaborationMode?: {
|
|
79
|
+
mode: "plan" | "default";
|
|
80
|
+
settings: {
|
|
81
|
+
model?: string | null;
|
|
82
|
+
reasoning_effort?: string | null;
|
|
83
|
+
developer_instructions: null;
|
|
84
|
+
};
|
|
85
|
+
} | null;
|
|
86
|
+
};
|
|
87
|
+
export type TurnInterruptParams = {
|
|
88
|
+
threadId: string;
|
|
89
|
+
turnId: string;
|
|
90
|
+
};
|
|
91
|
+
export type TurnSteerParams = {
|
|
92
|
+
threadId: string;
|
|
93
|
+
input: UserInput[];
|
|
94
|
+
expectedTurnId: string;
|
|
95
|
+
};
|
|
96
|
+
export type Thread = {
|
|
97
|
+
id: string;
|
|
98
|
+
turns?: Turn[];
|
|
99
|
+
};
|
|
100
|
+
export type Turn = {
|
|
101
|
+
id: string;
|
|
102
|
+
items: ThreadItem[];
|
|
103
|
+
status: "completed" | "interrupted" | "failed" | "inProgress";
|
|
104
|
+
error: {
|
|
105
|
+
message: string;
|
|
106
|
+
} | null;
|
|
107
|
+
};
|
|
108
|
+
export type CommandExecutionItem = {
|
|
109
|
+
type: "commandExecution";
|
|
110
|
+
id: string;
|
|
111
|
+
command: string;
|
|
112
|
+
status: "inProgress" | "completed" | "failed" | "declined";
|
|
113
|
+
aggregatedOutput: string | null;
|
|
114
|
+
};
|
|
115
|
+
export type FileChangeItem = {
|
|
116
|
+
type: "fileChange";
|
|
117
|
+
id: string;
|
|
118
|
+
changes: Array<{
|
|
119
|
+
path: string;
|
|
120
|
+
kind: {
|
|
121
|
+
type: "add" | "update" | "delete";
|
|
122
|
+
move_path: string | null;
|
|
123
|
+
};
|
|
124
|
+
diff?: string;
|
|
125
|
+
}>;
|
|
126
|
+
status: "inProgress" | "completed" | "failed" | "declined";
|
|
127
|
+
};
|
|
128
|
+
export type PlanItem = {
|
|
129
|
+
type: "plan";
|
|
130
|
+
id: string;
|
|
131
|
+
text: string;
|
|
132
|
+
};
|
|
133
|
+
export type McpToolCallItem = {
|
|
134
|
+
type: "mcpToolCall";
|
|
135
|
+
id: string;
|
|
136
|
+
server: string;
|
|
137
|
+
tool: string;
|
|
138
|
+
arguments: unknown;
|
|
139
|
+
status: "inProgress" | "completed" | "failed";
|
|
140
|
+
result: {
|
|
141
|
+
content?: unknown[];
|
|
142
|
+
structuredContent?: unknown;
|
|
143
|
+
} | null;
|
|
144
|
+
error: {
|
|
145
|
+
message: string;
|
|
146
|
+
} | null;
|
|
147
|
+
};
|
|
148
|
+
export type DynamicToolCallItem = {
|
|
149
|
+
type: "dynamicToolCall";
|
|
150
|
+
id: string;
|
|
151
|
+
namespace: string | null;
|
|
152
|
+
tool: string;
|
|
153
|
+
arguments: unknown;
|
|
154
|
+
status: "inProgress" | "completed" | "failed";
|
|
155
|
+
contentItems: Array<{
|
|
156
|
+
type: "inputText";
|
|
157
|
+
text: string;
|
|
158
|
+
} | {
|
|
159
|
+
type: "inputImage";
|
|
160
|
+
imageUrl: string;
|
|
161
|
+
}> | null;
|
|
162
|
+
success: boolean | null;
|
|
163
|
+
};
|
|
164
|
+
export type WebSearchAction = {
|
|
165
|
+
type: "search";
|
|
166
|
+
query?: string;
|
|
167
|
+
queries?: string[];
|
|
168
|
+
} | {
|
|
169
|
+
type: "openPage";
|
|
170
|
+
url?: string;
|
|
171
|
+
} | {
|
|
172
|
+
type: "findInPage";
|
|
173
|
+
url?: string;
|
|
174
|
+
pattern?: string;
|
|
175
|
+
} | {
|
|
176
|
+
type: "other";
|
|
177
|
+
};
|
|
178
|
+
export type WebSearchItem = {
|
|
179
|
+
type: "webSearch";
|
|
180
|
+
id: string;
|
|
181
|
+
query: string;
|
|
182
|
+
action?: WebSearchAction;
|
|
183
|
+
};
|
|
184
|
+
export type ContextCompactionItem = {
|
|
185
|
+
type: "contextCompaction";
|
|
186
|
+
id: string;
|
|
187
|
+
};
|
|
188
|
+
export type SubAgentActivityItem = {
|
|
189
|
+
type: "subAgentActivity";
|
|
190
|
+
id: string;
|
|
191
|
+
kind: "started" | "interacted" | "interrupted";
|
|
192
|
+
agentThreadId: string;
|
|
193
|
+
agentPath: string;
|
|
194
|
+
};
|
|
195
|
+
export type CollabAgentStatus = "pendingInit" | "running" | "interrupted" | "completed" | "errored" | "shutdown" | "notFound";
|
|
196
|
+
export type CollabAgentToolCallItem = {
|
|
197
|
+
type: "collabAgentToolCall";
|
|
198
|
+
id: string;
|
|
199
|
+
tool: string;
|
|
200
|
+
status: "inProgress" | "completed" | "failed";
|
|
201
|
+
senderThreadId: string;
|
|
202
|
+
receiverThreadIds: string[];
|
|
203
|
+
prompt: string | null;
|
|
204
|
+
model: string | null;
|
|
205
|
+
reasoningEffort: string | null;
|
|
206
|
+
agentsStates: Record<string, {
|
|
207
|
+
status: CollabAgentStatus;
|
|
208
|
+
message: string | null;
|
|
209
|
+
} | undefined>;
|
|
210
|
+
};
|
|
211
|
+
export type ThreadItem = {
|
|
212
|
+
type: "agentMessage";
|
|
213
|
+
id: string;
|
|
214
|
+
text: string;
|
|
215
|
+
} | {
|
|
216
|
+
type: "reasoning";
|
|
217
|
+
id: string;
|
|
218
|
+
summary: string[];
|
|
219
|
+
content: string[];
|
|
220
|
+
} | CommandExecutionItem | FileChangeItem | PlanItem | McpToolCallItem | DynamicToolCallItem | WebSearchItem | ContextCompactionItem | SubAgentActivityItem | CollabAgentToolCallItem;
|
|
221
|
+
export type ItemDeltaEvent = {
|
|
222
|
+
type: "item.delta";
|
|
223
|
+
item_id: string;
|
|
224
|
+
item_type: "agentMessage" | "reasoning" | "plan";
|
|
225
|
+
delta: string;
|
|
226
|
+
};
|
|
227
|
+
export type AppServerEvent = {
|
|
228
|
+
type: "thread.started";
|
|
229
|
+
thread_id: string;
|
|
230
|
+
} | {
|
|
231
|
+
type: "turn.started";
|
|
232
|
+
turn_id: string;
|
|
233
|
+
} | {
|
|
234
|
+
type: "turn.diff.updated";
|
|
235
|
+
diff: string;
|
|
236
|
+
} | {
|
|
237
|
+
type: "thread.tokenUsage.updated";
|
|
238
|
+
usage: Usage | null;
|
|
239
|
+
} | {
|
|
240
|
+
type: "item.started";
|
|
241
|
+
item: ThreadItem;
|
|
242
|
+
} | {
|
|
243
|
+
type: "item.updated";
|
|
244
|
+
item: ThreadItem;
|
|
245
|
+
} | {
|
|
246
|
+
type: "item.delta";
|
|
247
|
+
item_id: string;
|
|
248
|
+
item_type: "agentMessage" | "reasoning" | "plan";
|
|
249
|
+
delta: string;
|
|
250
|
+
} | {
|
|
251
|
+
type: "item.completed";
|
|
252
|
+
item: ThreadItem;
|
|
253
|
+
} | {
|
|
254
|
+
type: "item.tool.requestUserInput";
|
|
255
|
+
params: ToolRequestUserInputParams;
|
|
256
|
+
} | {
|
|
257
|
+
type: "turn.completed";
|
|
258
|
+
} | {
|
|
259
|
+
type: "turn.failed";
|
|
260
|
+
error: {
|
|
261
|
+
message: string;
|
|
262
|
+
};
|
|
263
|
+
} | {
|
|
264
|
+
type: "error";
|
|
265
|
+
message: string;
|
|
266
|
+
};
|
|
267
|
+
export type DynamicToolCallParams = {
|
|
268
|
+
threadId: string;
|
|
269
|
+
turnId: string;
|
|
270
|
+
callId: string;
|
|
271
|
+
namespace: string | null;
|
|
272
|
+
tool: string;
|
|
273
|
+
arguments: unknown;
|
|
274
|
+
};
|
|
275
|
+
export type DynamicToolCallResponse = {
|
|
276
|
+
contentItems: Array<{
|
|
277
|
+
type: "inputText";
|
|
278
|
+
text: string;
|
|
279
|
+
} | {
|
|
280
|
+
type: "inputImage";
|
|
281
|
+
imageUrl: string;
|
|
282
|
+
}>;
|
|
283
|
+
success: boolean;
|
|
284
|
+
};
|
|
285
|
+
/**
|
|
286
|
+
* EXPERIMENTAL. Params sent with a request_user_input event.
|
|
287
|
+
*/
|
|
288
|
+
export type ToolRequestUserInputParams = {
|
|
289
|
+
threadId: string;
|
|
290
|
+
turnId: string;
|
|
291
|
+
itemId: string;
|
|
292
|
+
questions: Array<ToolRequestUserInputQuestion>;
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* EXPERIMENTAL. Params sent with a request_user_input event.
|
|
296
|
+
*/
|
|
297
|
+
export type ToolRequestUserInputQuestion = {
|
|
298
|
+
id: string;
|
|
299
|
+
header: string;
|
|
300
|
+
question: string;
|
|
301
|
+
isOther: boolean;
|
|
302
|
+
isSecret: boolean;
|
|
303
|
+
options: Array<ToolRequestUserInputOption> | null;
|
|
304
|
+
};
|
|
305
|
+
/**
|
|
306
|
+
* EXPERIMENTAL. Defines a single selectable option for request_user_input.
|
|
307
|
+
*/
|
|
308
|
+
export type ToolRequestUserInputOption = {
|
|
309
|
+
label: string;
|
|
310
|
+
description: string;
|
|
311
|
+
};
|
|
312
|
+
/**
|
|
313
|
+
* EXPERIMENTAL. Response payload mapping question ids to answers.
|
|
314
|
+
*/
|
|
315
|
+
export type ToolRequestUserInputResponse = {
|
|
316
|
+
answers: {
|
|
317
|
+
[key in string]?: ToolRequestUserInputAnswer;
|
|
318
|
+
};
|
|
319
|
+
};
|
|
320
|
+
/**
|
|
321
|
+
* EXPERIMENTAL. Captures a user's answer to a request_user_input question.
|
|
322
|
+
*/
|
|
323
|
+
export type ToolRequestUserInputAnswer = {
|
|
324
|
+
answers: Array<string>;
|
|
325
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/app.d.ts
ADDED
package/dist/app.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { logger as honoLogger } from "hono/logger";
|
|
3
|
+
import chat from "./routes/chat.js";
|
|
4
|
+
import { logger } from "@messenger-agent/shared/logger";
|
|
5
|
+
import { agentAuthMiddleware } from "@messenger-agent/shared/agent-auth";
|
|
6
|
+
import { appConfig } from "./config.js";
|
|
7
|
+
import { installAgentActivityResponder } from "@messenger-agent/shared/agent-activity";
|
|
8
|
+
import { codexActivitySnapshot } from "./routes/chat.js";
|
|
9
|
+
const app = new Hono();
|
|
10
|
+
installAgentActivityResponder("codex", codexActivitySnapshot);
|
|
11
|
+
app.use(honoLogger((str, ...rest) => logger.info(str, ...rest)));
|
|
12
|
+
app.get("/health", (c) => c.json({ status: "ok" }));
|
|
13
|
+
app.use("/*", agentAuthMiddleware(appConfig.authTokens));
|
|
14
|
+
app.route("/", chat);
|
|
15
|
+
export default app;
|