mcp-codex-worker 0.1.35 → 0.1.37
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.
|
@@ -37,6 +37,7 @@ export class CodexAdapter extends BaseProviderAdapter {
|
|
|
37
37
|
let detachPauseFlow;
|
|
38
38
|
let detachEventCapture;
|
|
39
39
|
let removeExitListener;
|
|
40
|
+
let heartbeatTimer;
|
|
40
41
|
// Clean up listeners only once, regardless of which path triggers it.
|
|
41
42
|
const cleanup = () => {
|
|
42
43
|
detachPauseFlow?.();
|
|
@@ -45,6 +46,10 @@ export class CodexAdapter extends BaseProviderAdapter {
|
|
|
45
46
|
detachEventCapture = undefined;
|
|
46
47
|
removeExitListener?.();
|
|
47
48
|
removeExitListener = undefined;
|
|
49
|
+
if (heartbeatTimer) {
|
|
50
|
+
clearInterval(heartbeatTimer);
|
|
51
|
+
heartbeatTimer = undefined;
|
|
52
|
+
}
|
|
48
53
|
};
|
|
49
54
|
try {
|
|
50
55
|
// 1. Create a new thread
|
|
@@ -67,17 +72,65 @@ export class CodexAdapter extends BaseProviderAdapter {
|
|
|
67
72
|
.getCurrentClient();
|
|
68
73
|
detachPauseFlow = attachPauseFlow(client, handle, threadId);
|
|
69
74
|
detachEventCapture = attachEventCapture(client, handle, threadId, this.options.fileWriter);
|
|
70
|
-
// 3b.
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
const
|
|
75
|
+
// 3b. Capture stderr for diagnostics — logs to verbose + events.jsonl.
|
|
76
|
+
// Also accumulate recent stderr to detect auth token expiry on exit.
|
|
77
|
+
let recentStderr = '';
|
|
78
|
+
const onStderr = (chunk) => {
|
|
79
|
+
handle.writeOutputFileOnly(`[stderr] ${chunk.trimEnd()}`);
|
|
80
|
+
recentStderr += chunk;
|
|
81
|
+
// Cap at 10KB to avoid unbounded growth on verbose processes
|
|
82
|
+
if (recentStderr.length > 10_000) {
|
|
83
|
+
recentStderr = recentStderr.slice(-10_000);
|
|
84
|
+
}
|
|
85
|
+
if (this.options.fileWriter) {
|
|
86
|
+
this.options.fileWriter.appendEvent(handle.taskId, {
|
|
87
|
+
method: '_stderr',
|
|
88
|
+
data: chunk.trimEnd(),
|
|
89
|
+
}).catch(() => { });
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
client.on('stderr', onStderr);
|
|
93
|
+
// 3c. Listen for app-server exits. Detect the root cause from stderr
|
|
94
|
+
// and produce an actionable error message.
|
|
95
|
+
const onExit = (info) => {
|
|
74
96
|
if (handle.isAlive()) {
|
|
75
|
-
|
|
97
|
+
const stderrLower = recentStderr.toLowerCase();
|
|
98
|
+
let errorMessage;
|
|
99
|
+
if (stderrLower.includes('refresh token') && stderrLower.includes('already used')) {
|
|
100
|
+
errorMessage = 'AUTH_TOKEN_EXPIRED: Codex refresh token was already consumed. Run `codex auth login` to re-authenticate, then retry.';
|
|
101
|
+
}
|
|
102
|
+
else if (stderrLower.includes('unauthorized') || stderrLower.includes('requires auth') || stderrLower.includes('log out and sign in')) {
|
|
103
|
+
errorMessage = 'AUTH_ERROR: Codex authentication failed. Run `codex auth login` to re-authenticate, then retry.';
|
|
104
|
+
}
|
|
105
|
+
else if (stderrLower.includes('rate limit') || stderrLower.includes('usage limit')) {
|
|
106
|
+
errorMessage = `RATE_LIMITED: Codex hit a rate or usage limit. Details in events.jsonl. Exit code=${String(info.code)}`;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
errorMessage = `Codex app-server exited (code=${String(info.code)}, signal=${String(info.signal)})`;
|
|
110
|
+
}
|
|
111
|
+
handle.markFailed(errorMessage);
|
|
112
|
+
}
|
|
113
|
+
if (this.options.fileWriter) {
|
|
114
|
+
this.options.fileWriter.appendEvent(handle.taskId, {
|
|
115
|
+
method: '_process_exit',
|
|
116
|
+
code: info.code,
|
|
117
|
+
signal: info.signal,
|
|
118
|
+
stderr_tail: recentStderr.slice(-2000),
|
|
119
|
+
}).catch(() => { });
|
|
76
120
|
}
|
|
77
121
|
cleanup();
|
|
78
122
|
};
|
|
79
123
|
client.on('exit', onExit);
|
|
80
|
-
removeExitListener = () =>
|
|
124
|
+
removeExitListener = () => {
|
|
125
|
+
client.off('exit', onExit);
|
|
126
|
+
client.off('stderr', onStderr);
|
|
127
|
+
};
|
|
128
|
+
// 3d. Heartbeat — prevent Codex idle timeout during approval waits.
|
|
129
|
+
// Sends a lightweight request every 30s to keep the connection alive.
|
|
130
|
+
heartbeatTimer = setInterval(() => {
|
|
131
|
+
runtime.request('account/rateLimits/read', {}).catch(() => { });
|
|
132
|
+
}, 30_000);
|
|
133
|
+
heartbeatTimer.unref();
|
|
81
134
|
// 4. Build turn params and start the turn via bridged request
|
|
82
135
|
const { params: turnParams } = await runtime.buildTurnStartParams({
|
|
83
136
|
threadId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-adapter.js","sourceRoot":"","sources":["../../../src/execution/codex-adapter.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,uBAAuB;AACvB,8EAA8E;AAK9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EACL,mBAAmB,GAGpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAa3D,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,OAAO,YAAa,SAAQ,mBAAmB;IAC1C,EAAE,GAAa,OAAO,CAAC;IACvB,WAAW,GAAG,OAAO,CAAC;IAEd,OAAO,CAAsB;IACtC,OAAO,CAAgB;IAE/B,YAAY,OAA4B;QACtC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,iBAAiB;QACf,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED,eAAe;QACb,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IAED,QAAQ;QACN,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,4EAA4E;IAC5E,yBAAyB;IACzB,4EAA4E;IAElE,KAAK,CAAC,cAAc,CAC5B,MAAkB,EAClB,MAAc,EACd,OAAoB,EACpB,OAA6B;QAE7B,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAClC,IAAI,eAAyC,CAAC;QAC9C,IAAI,kBAA4C,CAAC;QACjD,IAAI,kBAA4C,CAAC;
|
|
1
|
+
{"version":3,"file":"codex-adapter.js","sourceRoot":"","sources":["../../../src/execution/codex-adapter.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -72,6 +72,7 @@ export class CodexAdapter extends BaseProviderAdapter {
|
|
|
72
72
|
let detachPauseFlow: (() => void) | undefined;
|
|
73
73
|
let detachEventCapture: (() => void) | undefined;
|
|
74
74
|
let removeExitListener: (() => void) | undefined;
|
|
75
|
+
let heartbeatTimer: ReturnType<typeof setInterval> | undefined;
|
|
75
76
|
|
|
76
77
|
// Clean up listeners only once, regardless of which path triggers it.
|
|
77
78
|
const cleanup = () => {
|
|
@@ -81,6 +82,10 @@ export class CodexAdapter extends BaseProviderAdapter {
|
|
|
81
82
|
detachEventCapture = undefined;
|
|
82
83
|
removeExitListener?.();
|
|
83
84
|
removeExitListener = undefined;
|
|
85
|
+
if (heartbeatTimer) {
|
|
86
|
+
clearInterval(heartbeatTimer);
|
|
87
|
+
heartbeatTimer = undefined;
|
|
88
|
+
}
|
|
84
89
|
};
|
|
85
90
|
|
|
86
91
|
try {
|
|
@@ -109,17 +114,66 @@ export class CodexAdapter extends BaseProviderAdapter {
|
|
|
109
114
|
detachPauseFlow = attachPauseFlow(client, handle, threadId);
|
|
110
115
|
detachEventCapture = attachEventCapture(client, handle, threadId, this.options.fileWriter);
|
|
111
116
|
|
|
112
|
-
// 3b.
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
const
|
|
117
|
+
// 3b. Capture stderr for diagnostics — logs to verbose + events.jsonl.
|
|
118
|
+
// Also accumulate recent stderr to detect auth token expiry on exit.
|
|
119
|
+
let recentStderr = '';
|
|
120
|
+
const onStderr = (chunk: string) => {
|
|
121
|
+
handle.writeOutputFileOnly(`[stderr] ${chunk.trimEnd()}`);
|
|
122
|
+
recentStderr += chunk;
|
|
123
|
+
// Cap at 10KB to avoid unbounded growth on verbose processes
|
|
124
|
+
if (recentStderr.length > 10_000) {
|
|
125
|
+
recentStderr = recentStderr.slice(-10_000);
|
|
126
|
+
}
|
|
127
|
+
if (this.options.fileWriter) {
|
|
128
|
+
this.options.fileWriter.appendEvent(handle.taskId, {
|
|
129
|
+
method: '_stderr',
|
|
130
|
+
data: chunk.trimEnd(),
|
|
131
|
+
}).catch(() => {});
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
client.on('stderr', onStderr);
|
|
135
|
+
|
|
136
|
+
// 3c. Listen for app-server exits. Detect the root cause from stderr
|
|
137
|
+
// and produce an actionable error message.
|
|
138
|
+
const onExit = (info: { code: number | null; signal: string | null }) => {
|
|
116
139
|
if (handle.isAlive()) {
|
|
117
|
-
|
|
140
|
+
const stderrLower = recentStderr.toLowerCase();
|
|
141
|
+
let errorMessage: string;
|
|
142
|
+
|
|
143
|
+
if (stderrLower.includes('refresh token') && stderrLower.includes('already used')) {
|
|
144
|
+
errorMessage = 'AUTH_TOKEN_EXPIRED: Codex refresh token was already consumed. Run `codex auth login` to re-authenticate, then retry.';
|
|
145
|
+
} else if (stderrLower.includes('unauthorized') || stderrLower.includes('requires auth') || stderrLower.includes('log out and sign in')) {
|
|
146
|
+
errorMessage = 'AUTH_ERROR: Codex authentication failed. Run `codex auth login` to re-authenticate, then retry.';
|
|
147
|
+
} else if (stderrLower.includes('rate limit') || stderrLower.includes('usage limit')) {
|
|
148
|
+
errorMessage = `RATE_LIMITED: Codex hit a rate or usage limit. Details in events.jsonl. Exit code=${String(info.code)}`;
|
|
149
|
+
} else {
|
|
150
|
+
errorMessage = `Codex app-server exited (code=${String(info.code)}, signal=${String(info.signal)})`;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
handle.markFailed(errorMessage);
|
|
154
|
+
}
|
|
155
|
+
if (this.options.fileWriter) {
|
|
156
|
+
this.options.fileWriter.appendEvent(handle.taskId, {
|
|
157
|
+
method: '_process_exit',
|
|
158
|
+
code: info.code,
|
|
159
|
+
signal: info.signal,
|
|
160
|
+
stderr_tail: recentStderr.slice(-2000),
|
|
161
|
+
}).catch(() => {});
|
|
118
162
|
}
|
|
119
163
|
cleanup();
|
|
120
164
|
};
|
|
121
165
|
client.on('exit', onExit);
|
|
122
|
-
removeExitListener = () =>
|
|
166
|
+
removeExitListener = () => {
|
|
167
|
+
client.off('exit', onExit);
|
|
168
|
+
client.off('stderr', onStderr);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// 3d. Heartbeat — prevent Codex idle timeout during approval waits.
|
|
172
|
+
// Sends a lightweight request every 30s to keep the connection alive.
|
|
173
|
+
heartbeatTimer = setInterval(() => {
|
|
174
|
+
runtime.request('account/rateLimits/read', {}).catch(() => {});
|
|
175
|
+
}, 30_000);
|
|
176
|
+
heartbeatTimer.unref();
|
|
123
177
|
|
|
124
178
|
// 4. Build turn params and start the turn via bridged request
|
|
125
179
|
const { params: turnParams } = await runtime.buildTurnStartParams({
|