mcp-codex-worker 0.1.0 → 0.1.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/src/app.js +155 -83
- package/dist/src/app.js.map +1 -1
- package/dist/src/mcp/task-markdown.d.ts +4 -0
- package/dist/src/mcp/task-markdown.js +107 -0
- package/dist/src/mcp/task-markdown.js.map +1 -0
- package/dist/src/mcp/tool-banners.d.ts +3 -0
- package/dist/src/mcp/tool-banners.js +44 -0
- package/dist/src/mcp/tool-banners.js.map +1 -0
- package/dist/src/mcp/tool-definitions.d.ts +6 -9
- package/dist/src/mcp/tool-definitions.js +80 -78
- package/dist/src/mcp/tool-definitions.js.map +1 -1
- package/dist/src/services/app-server-client.d.ts +1 -0
- package/dist/src/services/app-server-client.js +5 -0
- package/dist/src/services/app-server-client.js.map +1 -1
- package/dist/src/services/codex-runtime.d.ts +5 -3
- package/dist/src/services/codex-runtime.js +18 -0
- package/dist/src/services/codex-runtime.js.map +1 -1
- package/dist/src/services/model-catalog.js +1 -1
- package/dist/src/services/model-catalog.js.map +1 -1
- package/package.json +1 -2
- package/src/app.ts +187 -85
- package/src/mcp/task-markdown.ts +136 -0
- package/src/mcp/tool-banners.ts +53 -0
- package/src/mcp/tool-definitions.ts +86 -81
- package/src/services/app-server-client.ts +6 -0
- package/src/services/codex-runtime.ts +19 -1
- package/src/services/model-catalog.ts +1 -1
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
|
-
const jsonSchema = { type: 'object' as const };
|
|
4
|
-
|
|
5
3
|
const threadStartSchema = z.object({
|
|
6
4
|
model: z.string().optional(),
|
|
7
5
|
cwd: z.string().optional(),
|
|
@@ -46,10 +44,6 @@ const requestListSchema = z.object({
|
|
|
46
44
|
include_resolved: z.boolean().optional(),
|
|
47
45
|
});
|
|
48
46
|
|
|
49
|
-
const requestReadSchema = z.object({
|
|
50
|
-
request_id: z.union([z.string(), z.number()]),
|
|
51
|
-
});
|
|
52
|
-
|
|
53
47
|
const requestRespondSchema = z.object({
|
|
54
48
|
request_id: z.union([z.string(), z.number()]),
|
|
55
49
|
payload: z.record(z.string(), z.unknown()).optional(),
|
|
@@ -91,20 +85,32 @@ function objectSchema(
|
|
|
91
85
|
};
|
|
92
86
|
}
|
|
93
87
|
|
|
94
|
-
export
|
|
88
|
+
export interface CreateToolDefinitionsInput {
|
|
89
|
+
modelIds: string[];
|
|
90
|
+
threadBanner: string;
|
|
91
|
+
requestBanner: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function createToolDefinitions(input: CreateToolDefinitionsInput): ToolDefinition[] {
|
|
95
|
+
const { modelIds, threadBanner, requestBanner } = input;
|
|
95
96
|
return [
|
|
96
97
|
{
|
|
97
|
-
name: 'thread-start',
|
|
98
|
+
name: 'codex-thread-start',
|
|
98
99
|
description: [
|
|
99
|
-
'
|
|
100
|
-
'
|
|
101
|
-
'
|
|
102
|
-
|
|
100
|
+
'Launch a new Codex agent as a background thread.',
|
|
101
|
+
'',
|
|
102
|
+
'PARALLEL EXECUTION: Launch multiple threads simultaneously — each thread is an independent agent workspace with its own context and conversation history.',
|
|
103
|
+
'This is the primary way to dispatch coding and testing work to Codex.',
|
|
104
|
+
'',
|
|
105
|
+
'After creating a thread, use codex-turn-start to send the task prompt.',
|
|
106
|
+
'Use codex-wait to block until the agent finishes or asks for permission.',
|
|
107
|
+
'Check codex-request-list after starting turns — agents often need approval for commands or file changes.',
|
|
108
|
+
].join('\n'),
|
|
103
109
|
inputSchema: objectSchema({
|
|
104
110
|
model: {
|
|
105
111
|
type: 'string',
|
|
106
112
|
...(modelIds.length > 0 ? { enum: modelIds } : {}),
|
|
107
|
-
description: 'Model to use
|
|
113
|
+
description: 'Model to use. Defaults to gpt-5.4. Available models are listed in the enum.',
|
|
108
114
|
},
|
|
109
115
|
cwd: {
|
|
110
116
|
type: 'string',
|
|
@@ -112,14 +118,14 @@ export function createToolDefinitions(modelIds: string[]): ToolDefinition[] {
|
|
|
112
118
|
},
|
|
113
119
|
developer_instructions: {
|
|
114
120
|
type: 'string',
|
|
115
|
-
description: 'System-level instructions injected before user messages. Use for constraints, coding style, or scope boundaries.',
|
|
121
|
+
description: 'System-level instructions injected before user messages. Use for constraints, coding style, acceptance criteria, or scope boundaries. Be specific — include file paths, function names, and expected behavior.',
|
|
116
122
|
},
|
|
117
123
|
}),
|
|
118
124
|
validate: (value) => threadStartSchema.parse(value),
|
|
119
125
|
},
|
|
120
126
|
{
|
|
121
|
-
name: 'thread-resume',
|
|
122
|
-
description: 'Resume
|
|
127
|
+
name: 'codex-thread-resume',
|
|
128
|
+
description: 'Resume a previously started Codex thread. Reloads context and reconnects the agent. Use to continue work on an existing thread after a pause, or to send follow-up instructions to a completed thread.',
|
|
123
129
|
inputSchema: objectSchema({
|
|
124
130
|
thread_id: { type: 'string', minLength: 1, description: 'ID of the thread to resume.' },
|
|
125
131
|
model: {
|
|
@@ -133,17 +139,20 @@ export function createToolDefinitions(modelIds: string[]): ToolDefinition[] {
|
|
|
133
139
|
validate: (value) => threadResumeSchema.parse(value),
|
|
134
140
|
},
|
|
135
141
|
{
|
|
136
|
-
name: 'thread-read',
|
|
137
|
-
description:
|
|
142
|
+
name: 'codex-thread-read',
|
|
143
|
+
description: [
|
|
144
|
+
'Read thread status and conversation history. Use to check what an agent has done, inspect its output, or verify task completion. Set include_turns=true for full turn details including tool calls and file changes.',
|
|
145
|
+
threadBanner,
|
|
146
|
+
].filter(Boolean).join('\n\n'),
|
|
138
147
|
inputSchema: objectSchema({
|
|
139
148
|
thread_id: { type: 'string', minLength: 1, description: 'Thread to read.' },
|
|
140
|
-
include_turns: { type: 'boolean', description: 'Include full turn history. Defaults to true.' },
|
|
149
|
+
include_turns: { type: 'boolean', description: 'Include full turn history with tool calls and outputs. Defaults to true.' },
|
|
141
150
|
}, ['thread_id']),
|
|
142
151
|
validate: (value) => threadReadSchema.parse(value),
|
|
143
152
|
},
|
|
144
153
|
{
|
|
145
|
-
name: 'thread-list',
|
|
146
|
-
description: 'List recent Codex threads. Use to discover existing
|
|
154
|
+
name: 'codex-thread-list',
|
|
155
|
+
description: 'List recent Codex threads across all sessions. Use to discover existing threads before starting new ones, or to find a thread ID you need to resume.',
|
|
147
156
|
inputSchema: objectSchema({
|
|
148
157
|
limit: { type: 'integer', minimum: 1, maximum: 100, description: 'Max threads to return. Default 50.' },
|
|
149
158
|
cursor: { type: 'string', description: 'Pagination cursor from a previous response.' },
|
|
@@ -151,15 +160,23 @@ export function createToolDefinitions(modelIds: string[]): ToolDefinition[] {
|
|
|
151
160
|
validate: (value) => threadListSchema.parse(value),
|
|
152
161
|
},
|
|
153
162
|
{
|
|
154
|
-
name: 'turn-start',
|
|
163
|
+
name: 'codex-turn-start',
|
|
155
164
|
description: [
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
165
|
+
[
|
|
166
|
+
'Send a task to an active Codex thread, starting an autonomous agent turn.',
|
|
167
|
+
'',
|
|
168
|
+
'The agent executes independently — it reads files, writes code, runs commands, and commits changes.',
|
|
169
|
+
'Use codex-wait to block until the turn completes or a pending request appears.',
|
|
170
|
+
'Use codex-turn-steer to redirect the agent mid-execution if it goes off track.',
|
|
171
|
+
'',
|
|
172
|
+
'IMPORTANT: After starting a turn, check codex-request-list — the agent frequently needs approval for shell commands or file changes before it can proceed.',
|
|
173
|
+
'For parallel work, start turns on multiple threads simultaneously.',
|
|
174
|
+
].join('\n'),
|
|
175
|
+
threadBanner,
|
|
176
|
+
].filter(Boolean).join('\n\n'),
|
|
160
177
|
inputSchema: objectSchema({
|
|
161
|
-
thread_id: { type: 'string', minLength: 1, description: 'Thread to send the
|
|
162
|
-
user_input: { type: 'string', minLength: 1, description: 'The
|
|
178
|
+
thread_id: { type: 'string', minLength: 1, description: 'Thread to send the task to.' },
|
|
179
|
+
user_input: { type: 'string', minLength: 1, description: 'The task instruction. Be specific: include file paths, function names, acceptance criteria, and constraints.' },
|
|
163
180
|
model: {
|
|
164
181
|
type: 'string',
|
|
165
182
|
...(modelIds.length > 0 ? { enum: modelIds } : {}),
|
|
@@ -169,8 +186,11 @@ export function createToolDefinitions(modelIds: string[]): ToolDefinition[] {
|
|
|
169
186
|
validate: (value) => turnStartSchema.parse(value),
|
|
170
187
|
},
|
|
171
188
|
{
|
|
172
|
-
name: 'turn-steer',
|
|
173
|
-
description:
|
|
189
|
+
name: 'codex-turn-steer',
|
|
190
|
+
description: [
|
|
191
|
+
'Redirect an in-progress turn with new instructions. The agent adjusts course without losing prior context. Use when you see the agent heading in the wrong direction via codex-thread-read or codex-request-list.',
|
|
192
|
+
threadBanner,
|
|
193
|
+
].filter(Boolean).join('\n\n'),
|
|
174
194
|
inputSchema: objectSchema({
|
|
175
195
|
thread_id: { type: 'string', minLength: 1, description: 'Thread containing the active turn.' },
|
|
176
196
|
expected_turn_id: { type: 'string', minLength: 1, description: 'Turn ID to steer. Must be the currently active turn.' },
|
|
@@ -179,8 +199,8 @@ export function createToolDefinitions(modelIds: string[]): ToolDefinition[] {
|
|
|
179
199
|
validate: (value) => turnSteerSchema.parse(value),
|
|
180
200
|
},
|
|
181
201
|
{
|
|
182
|
-
name: 'turn-interrupt',
|
|
183
|
-
description: 'Stop an active turn immediately. Use when the agent is heading in the wrong direction or
|
|
202
|
+
name: 'codex-turn-interrupt',
|
|
203
|
+
description: 'Stop an active turn immediately. Use when the agent is heading in the wrong direction and steering is not enough, or when you need to cancel work in progress.',
|
|
184
204
|
inputSchema: objectSchema({
|
|
185
205
|
thread_id: { type: 'string', minLength: 1, description: 'Thread containing the turn.' },
|
|
186
206
|
turn_id: { type: 'string', minLength: 1, description: 'Turn ID to interrupt.' },
|
|
@@ -188,58 +208,38 @@ export function createToolDefinitions(modelIds: string[]): ToolDefinition[] {
|
|
|
188
208
|
validate: (value) => turnInterruptSchema.parse(value),
|
|
189
209
|
},
|
|
190
210
|
{
|
|
191
|
-
name: '
|
|
192
|
-
description:
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
{
|
|
203
|
-
name: 'account-rate-limits-read',
|
|
204
|
-
description: 'Read current rate limit status for the Codex account. Check before launching many parallel threads.',
|
|
205
|
-
inputSchema: jsonSchema,
|
|
206
|
-
validate: (value) => value ?? {},
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
name: 'skills-list',
|
|
210
|
-
description: 'List registered Codex skills available in this session.',
|
|
211
|
-
inputSchema: jsonSchema,
|
|
212
|
-
validate: (value) => value ?? {},
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
name: 'app-list',
|
|
216
|
-
description: 'List Codex apps available in this session.',
|
|
217
|
-
inputSchema: jsonSchema,
|
|
218
|
-
validate: (value) => value ?? {},
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
name: 'request-list',
|
|
222
|
-
description: 'List pending Codex server requests awaiting approval (command execution, file changes, permissions). Check this after starting turns — agents often need permission to proceed.',
|
|
211
|
+
name: 'codex-request-list',
|
|
212
|
+
description: [
|
|
213
|
+
[
|
|
214
|
+
'List pending approval requests from Codex agents (command execution, file changes, permissions).',
|
|
215
|
+
'',
|
|
216
|
+
'CRITICAL: Check this after every codex-turn-start — agents frequently pause and wait for approval before executing shell commands or writing files.',
|
|
217
|
+
'If an agent appears stuck, it is almost certainly waiting for a request to be approved.',
|
|
218
|
+
'Use codex-request-respond to approve or decline each request.',
|
|
219
|
+
].join('\n'),
|
|
220
|
+
requestBanner,
|
|
221
|
+
].filter(Boolean).join('\n\n'),
|
|
223
222
|
inputSchema: objectSchema({
|
|
224
223
|
include_resolved: { type: 'boolean', description: 'Include already-resolved requests. Default false.' },
|
|
225
224
|
}),
|
|
226
225
|
validate: (value) => requestListSchema.parse(value),
|
|
227
226
|
},
|
|
228
227
|
{
|
|
229
|
-
name: 'request-
|
|
230
|
-
description: 'Read details of a specific pending server request. Use to understand what the agent is asking before responding.',
|
|
231
|
-
inputSchema: objectSchema({
|
|
232
|
-
request_id: { type: ['string', 'number'], description: 'ID of the pending request.' },
|
|
233
|
-
}, ['request_id']),
|
|
234
|
-
validate: (value) => requestReadSchema.parse(value),
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
name: 'request-respond',
|
|
228
|
+
name: 'codex-request-respond',
|
|
238
229
|
description: [
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
230
|
+
[
|
|
231
|
+
'Approve or decline a pending Codex agent request (command execution, file changes, permissions, user input).',
|
|
232
|
+
'',
|
|
233
|
+
'Common patterns:',
|
|
234
|
+
'- Approve command/file change: decision="accept"',
|
|
235
|
+
'- Decline: decision="decline"',
|
|
236
|
+
'- Grant permissions: scope="session", permissions={...}',
|
|
237
|
+
'- Answer agent question: answers={ "key": { "answers": ["value"] } }',
|
|
238
|
+
'',
|
|
239
|
+
'The tool auto-builds the correct payload shape based on the request method.',
|
|
240
|
+
].join('\n'),
|
|
241
|
+
requestBanner,
|
|
242
|
+
].filter(Boolean).join('\n\n'),
|
|
243
243
|
inputSchema: objectSchema({
|
|
244
244
|
request_id: { type: ['string', 'number'], description: 'ID of the request to respond to.' },
|
|
245
245
|
payload: { type: 'object', description: 'Raw response payload. Overrides all other fields if provided.' },
|
|
@@ -254,10 +254,16 @@ export function createToolDefinitions(modelIds: string[]): ToolDefinition[] {
|
|
|
254
254
|
validate: (value) => requestRespondSchema.parse(value),
|
|
255
255
|
},
|
|
256
256
|
{
|
|
257
|
-
name: 'wait',
|
|
258
|
-
description:
|
|
257
|
+
name: 'codex-wait',
|
|
258
|
+
description: [
|
|
259
|
+
'Block until a Codex turn completes or a pending approval request appears.',
|
|
260
|
+
'',
|
|
261
|
+
'Use after codex-turn-start to wait for the agent to finish or ask for permission.',
|
|
262
|
+
'Provide operation_id (from turn-start response) for precise tracking, or thread_id to poll thread status.',
|
|
263
|
+
'When it returns with a pending request, use codex-request-list + codex-request-respond to unblock the agent.',
|
|
264
|
+
].join('\n'),
|
|
259
265
|
inputSchema: objectSchema({
|
|
260
|
-
operation_id: { type: 'string', description: 'Operation ID to wait on (from a turn-start response).' },
|
|
266
|
+
operation_id: { type: 'string', description: 'Operation ID to wait on (from a codex-turn-start response).' },
|
|
261
267
|
thread_id: { type: 'string', description: 'Thread ID to wait on — polls until thread status is no longer active.' },
|
|
262
268
|
timeout_ms: { type: 'integer', minimum: 1, maximum: 300000, description: 'Max wait time in ms. Default 120,000 (2 minutes).' },
|
|
263
269
|
poll_interval_ms: { type: 'integer', minimum: 1, maximum: 5000, description: 'Poll interval in ms. Default 250.' },
|
|
@@ -275,6 +281,5 @@ export type TurnStartInput = z.infer<typeof turnStartSchema>;
|
|
|
275
281
|
export type TurnSteerInput = z.infer<typeof turnSteerSchema>;
|
|
276
282
|
export type TurnInterruptInput = z.infer<typeof turnInterruptSchema>;
|
|
277
283
|
export type RequestListInput = z.infer<typeof requestListSchema>;
|
|
278
|
-
export type RequestReadInput = z.infer<typeof requestReadSchema>;
|
|
279
284
|
export type RequestRespondInput = z.infer<typeof requestRespondSchema>;
|
|
280
285
|
export type WaitInput = z.infer<typeof waitSchema>;
|
|
@@ -352,6 +352,12 @@ export class AppServerClient extends EventEmitter {
|
|
|
352
352
|
}));
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
+
listOperationsForThread(threadId: string): RuntimeOperation[] {
|
|
356
|
+
return [...this.operations.values()]
|
|
357
|
+
.filter((op) => op.threadId === threadId)
|
|
358
|
+
.map((op) => ({ ...op, pendingRequestIds: [...op.pendingRequestIds] }));
|
|
359
|
+
}
|
|
360
|
+
|
|
355
361
|
listServerRequests(includeResolved = false): PendingServerRequest[] {
|
|
356
362
|
return [...this.serverRequests.values()]
|
|
357
363
|
.filter((request) => includeResolved || request.status === 'pending')
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
CODEX_APP_SERVER_COMMAND_ENV,
|
|
9
9
|
REQUEST_TIMEOUT_MS,
|
|
10
10
|
} from '../config/defaults.js';
|
|
11
|
-
import type { PendingServerRequest } from '../types/codex.js';
|
|
11
|
+
import type { PendingServerRequest, RuntimeOperation } from '../types/codex.js';
|
|
12
12
|
import { AppServerClient, type BridgedOperationResult } from './app-server-client.js';
|
|
13
13
|
import { appendFleetDeveloperInstructions } from './fleet-mode.js';
|
|
14
14
|
import {
|
|
@@ -294,6 +294,7 @@ export class CodexRuntime {
|
|
|
294
294
|
cwd: input.cwd ?? process.cwd(),
|
|
295
295
|
approvalPolicy: 'on-request',
|
|
296
296
|
sandbox: 'workspace-write',
|
|
297
|
+
reasoningEffort: 'high',
|
|
297
298
|
developerInstructions: appendFleetDeveloperInstructions(input.developerInstructions),
|
|
298
299
|
experimentalRawEvents: false,
|
|
299
300
|
persistExtendedHistory: false,
|
|
@@ -319,6 +320,7 @@ export class CodexRuntime {
|
|
|
319
320
|
cwd: input.cwd ?? process.cwd(),
|
|
320
321
|
approvalPolicy: 'on-request',
|
|
321
322
|
sandbox: 'workspace-write',
|
|
323
|
+
reasoningEffort: 'high',
|
|
322
324
|
developerInstructions: appendFleetDeveloperInstructions(input.developerInstructions),
|
|
323
325
|
persistExtendedHistory: false,
|
|
324
326
|
};
|
|
@@ -364,6 +366,22 @@ export class CodexRuntime {
|
|
|
364
366
|
};
|
|
365
367
|
}
|
|
366
368
|
|
|
369
|
+
getOperationsForThread(threadId: string): RuntimeOperation[] {
|
|
370
|
+
try {
|
|
371
|
+
return this.getCurrentClient().listOperationsForThread(threadId);
|
|
372
|
+
} catch {
|
|
373
|
+
return [];
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
getAllOperations(): RuntimeOperation[] {
|
|
378
|
+
try {
|
|
379
|
+
return this.getCurrentClient().listOperations();
|
|
380
|
+
} catch {
|
|
381
|
+
return [];
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
367
385
|
async getThreadEvents(threadId: string): Promise<unknown[]> {
|
|
368
386
|
return this.getCurrentClient().getThreadEvents(threadId);
|
|
369
387
|
}
|
|
@@ -52,7 +52,7 @@ export function resolveModel(
|
|
|
52
52
|
catalog: ModelCatalog,
|
|
53
53
|
requestedModel?: string | undefined,
|
|
54
54
|
): ModelResolution {
|
|
55
|
-
const requested = requestedModel ?? catalog.defaultModelId;
|
|
55
|
+
const requested = requestedModel ?? catalog.defaultModelId ?? 'gpt-5.4';
|
|
56
56
|
if (!requested) {
|
|
57
57
|
throw new Error('No models available from model/list.');
|
|
58
58
|
}
|