@parall/codex-agent 1.30.0 → 1.32.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/config.d.ts.map +1 -1
- package/dist/config.js +34 -35
- package/dist/dispatch.d.ts +6 -5
- package/dist/dispatch.d.ts.map +1 -1
- package/dist/dispatch.js +102 -82
- package/dist/event-mapping.d.ts +1 -1
- package/dist/event-mapping.d.ts.map +1 -1
- package/dist/event-mapping.js +102 -82
- package/dist/index.js +169 -114
- package/dist/jsonrpc-client.d.ts +4 -4
- package/dist/jsonrpc-client.d.ts.map +1 -1
- package/dist/jsonrpc-client.js +15 -15
- package/dist/session-manager.d.ts +1 -1
- package/dist/session-manager.d.ts.map +1 -1
- package/dist/session-manager.js +7 -5
- package/dist/workspace.d.ts +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +40 -39
- package/package.json +4 -4
- package/src/config.ts +41 -36
- package/src/dispatch.ts +140 -110
- package/src/event-mapping.ts +135 -109
- package/src/index.ts +199 -117
- package/src/jsonrpc-client.ts +22 -20
- package/src/session-manager.ts +10 -6
- package/src/workspace.ts +50 -43
package/src/index.ts
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import * as os from
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import {
|
|
5
|
+
ParallAgentGateway,
|
|
6
|
+
createPlatformConfigManager,
|
|
7
|
+
createLogger,
|
|
8
|
+
createOtelLogger,
|
|
9
|
+
childLogger,
|
|
10
|
+
isPlatformManagedProfile,
|
|
11
|
+
isPlatformModelOverride,
|
|
12
|
+
resolveRuntimeModel,
|
|
13
|
+
parseShutdownDeadlineMs,
|
|
14
|
+
parseForkDeadlineMs,
|
|
15
|
+
parseDispatchDeadlineMs,
|
|
16
|
+
parseProviderConfig,
|
|
17
|
+
clearAllProviderCreds,
|
|
18
|
+
llmSource,
|
|
19
|
+
initAgentTelemetry,
|
|
20
|
+
} from '@parall/agent-core';
|
|
21
|
+
import { ApiError, ParallClient, ParallWs } from '@parall/sdk';
|
|
6
22
|
import {
|
|
7
23
|
buildCodexRuntimeKey,
|
|
8
24
|
contextFilePathForSession,
|
|
@@ -10,12 +26,17 @@ import {
|
|
|
10
26
|
resolveWsUrl,
|
|
11
27
|
sessionStateFilePathForRuntime,
|
|
12
28
|
stepIdFilePathForSession,
|
|
13
|
-
} from
|
|
14
|
-
import { CodexAppServerAdapter } from
|
|
15
|
-
import { CodexSessionManager } from
|
|
16
|
-
import {
|
|
29
|
+
} from './config.js';
|
|
30
|
+
import { CodexAppServerAdapter } from './dispatch.js';
|
|
31
|
+
import { CodexSessionManager } from './session-manager.js';
|
|
32
|
+
import {
|
|
33
|
+
ensureCodexWorkspace,
|
|
34
|
+
ensureParallProvider,
|
|
35
|
+
ensureWorkspaceTrusted,
|
|
36
|
+
isParallProxyMode,
|
|
37
|
+
} from './workspace.js';
|
|
17
38
|
|
|
18
|
-
const log = createLogger(
|
|
39
|
+
const log = createLogger('codex-agent');
|
|
19
40
|
let activeLog = log;
|
|
20
41
|
|
|
21
42
|
async function getAgentMeWithLegacyFallback(client: ParallClient, orgId: string) {
|
|
@@ -30,125 +51,186 @@ async function getAgentMeWithLegacyFallback(client: ParallClient, orgId: string)
|
|
|
30
51
|
}
|
|
31
52
|
}
|
|
32
53
|
|
|
54
|
+
function resolveProviderEnv(): void {
|
|
55
|
+
const pc = parseProviderConfig(process.env);
|
|
56
|
+
if (!pc) return;
|
|
57
|
+
clearAllProviderCreds(process.env);
|
|
58
|
+
const source = llmSource(pc);
|
|
59
|
+
if (source === 'parall') {
|
|
60
|
+
process.env.OPENAI_API_KEY = process.env.PRLL_API_KEY;
|
|
61
|
+
process.env.OPENAI_BASE_URL = `${process.env.PRLL_API_URL}/api/llm/v1`;
|
|
62
|
+
} else if (source === 'custom') {
|
|
63
|
+
if (pc.openai_api_key) process.env.OPENAI_API_KEY = pc.openai_api_key;
|
|
64
|
+
if (pc.openai_base_url) process.env.OPENAI_BASE_URL = pc.openai_base_url;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
33
68
|
async function main() {
|
|
34
|
-
const
|
|
69
|
+
const telemetry = await initAgentTelemetry('parall-codex-agent', 'codex');
|
|
70
|
+
activeLog = createOtelLogger('agent', 'codex-agent');
|
|
71
|
+
try {
|
|
72
|
+
resolveProviderEnv();
|
|
73
|
+
const config = resolveCodexAgentConfig(process.env);
|
|
35
74
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
75
|
+
const client = new ParallClient({
|
|
76
|
+
baseUrl: config.apiUrl,
|
|
77
|
+
token: config.apiKey,
|
|
78
|
+
swimlaneName: config.swimlaneName,
|
|
79
|
+
});
|
|
41
80
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
runtimeKey,
|
|
62
|
-
sessionStateFilePath,
|
|
63
|
-
agentLog,
|
|
64
|
-
);
|
|
81
|
+
const me = await getAgentMeWithLegacyFallback(client, config.orgId);
|
|
82
|
+
const agentUserId = me.id;
|
|
83
|
+
const agentLog = childLogger(activeLog, agentUserId);
|
|
84
|
+
activeLog = agentLog;
|
|
85
|
+
ensureWorkspaceTrusted(config.codexHome, config.workspaceDir, agentLog);
|
|
86
|
+
const useParallProvider = isParallProxyMode();
|
|
87
|
+
if (useParallProvider) {
|
|
88
|
+
ensureParallProvider(config.codexHome, config.apiUrl, agentLog);
|
|
89
|
+
agentLog.info('parall custom provider configured (Responses API HTTP/SSE mode)');
|
|
90
|
+
}
|
|
91
|
+
ensureCodexWorkspace(config.workspaceDir, agentLog, {
|
|
92
|
+
userId: agentUserId,
|
|
93
|
+
displayName: me.display_name,
|
|
94
|
+
description: me.agent_profile?.description ?? undefined,
|
|
95
|
+
});
|
|
96
|
+
const runtimeKey = config.runtimeKey || buildCodexRuntimeKey(agentUserId);
|
|
97
|
+
const mainContextFilePath = contextFilePathForSession(config.stateDir, runtimeKey);
|
|
98
|
+
const sessionStateFilePath = sessionStateFilePathForRuntime(config.stateDir, runtimeKey);
|
|
99
|
+
const sessionManager = new CodexSessionManager(runtimeKey, sessionStateFilePath, agentLog);
|
|
65
100
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
101
|
+
const resolvedWsUrl = resolveWsUrl(config.apiUrl, config.wsUrl, config.swimlaneName);
|
|
102
|
+
const ws = new ParallWs({
|
|
103
|
+
getTicket: () => client.getWsTicket(),
|
|
104
|
+
wsUrl: resolvedWsUrl,
|
|
105
|
+
});
|
|
71
106
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
107
|
+
const configMgr = createPlatformConfigManager({
|
|
108
|
+
client,
|
|
109
|
+
stateDir: config.stateDir,
|
|
110
|
+
runtimeType: 'codex',
|
|
111
|
+
log: agentLog,
|
|
112
|
+
});
|
|
113
|
+
const platformDefaults = await configMgr.fetch();
|
|
114
|
+
let platformManaged = isPlatformManagedProfile(me.agent_profile);
|
|
115
|
+
// Model precedence: operator override (platform-managed) > env > server floor.
|
|
116
|
+
// The server delivers a model floor for Parall-proxy routes even when
|
|
117
|
+
// model_management=self, so the CLI never falls back to a built-in default
|
|
118
|
+
// the catalog might reject — but that floor must lose to an explicit env
|
|
119
|
+
// override. A profile is an operator-override only when it is platform-managed
|
|
120
|
+
// AND not explicitly self-managed: this treats legacy hosted agents
|
|
121
|
+
// (model_management=null, resolved to platform server-side) as overrides,
|
|
122
|
+
// while excluding local self agents whose delivered model is a floor.
|
|
123
|
+
// reasoning_effort stays an operator override (platform).
|
|
124
|
+
let platformModelOverride = isPlatformModelOverride(me.agent_profile);
|
|
125
|
+
const resolvedModel = resolveRuntimeModel(
|
|
126
|
+
platformModelOverride,
|
|
127
|
+
platformDefaults.model,
|
|
128
|
+
config.model,
|
|
129
|
+
);
|
|
130
|
+
const resolvedEffort = platformManaged
|
|
131
|
+
? (platformDefaults.thinkingEffort ?? config.reasoningEffort)
|
|
132
|
+
: config.reasoningEffort;
|
|
133
|
+
if (platformDefaults.model)
|
|
134
|
+
agentLog.info(
|
|
135
|
+
`platform config: model=${platformDefaults.model} → resolved=${resolvedModel ?? 'cli-default'} (${platformModelOverride ? 'platform-managed' : 'floor/self'})`,
|
|
136
|
+
);
|
|
137
|
+
if (platformDefaults.thinkingEffort)
|
|
138
|
+
agentLog.info(
|
|
139
|
+
`platform config: reasoning_effort=${platformDefaults.thinkingEffort} (${platformModelOverride ? 'applied' : 'ignored, model_management=self'})`,
|
|
140
|
+
);
|
|
79
141
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
142
|
+
const adapter = new CodexAppServerAdapter({
|
|
143
|
+
codexBin: config.codexBin,
|
|
144
|
+
codexHome: config.codexHome,
|
|
145
|
+
workspaceDir: config.workspaceDir,
|
|
146
|
+
model: resolvedModel,
|
|
147
|
+
reasoningEffort: resolvedEffort,
|
|
148
|
+
sandbox: config.sandbox,
|
|
149
|
+
approvalPolicy: config.approvalPolicy,
|
|
150
|
+
sessionManager,
|
|
151
|
+
log: agentLog,
|
|
152
|
+
contextFilePath: mainContextFilePath,
|
|
153
|
+
useParallProvider,
|
|
154
|
+
});
|
|
93
155
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
156
|
+
const gateway = new ParallAgentGateway({
|
|
157
|
+
accountId: agentUserId,
|
|
158
|
+
client,
|
|
159
|
+
ws,
|
|
160
|
+
connectionLabel: resolvedWsUrl,
|
|
161
|
+
config: {
|
|
162
|
+
parall_url: config.apiUrl,
|
|
163
|
+
api_key: config.apiKey,
|
|
164
|
+
org_id: config.orgId,
|
|
165
|
+
},
|
|
166
|
+
agentUserId,
|
|
167
|
+
runtimeType: 'codex',
|
|
168
|
+
runtimeKey,
|
|
169
|
+
runtimeRef: {
|
|
170
|
+
hostname: os.hostname(),
|
|
171
|
+
pid: process.pid,
|
|
172
|
+
workspace_dir: config.workspaceDir,
|
|
173
|
+
codex_home: config.codexHome,
|
|
174
|
+
driver: 'app-server',
|
|
175
|
+
},
|
|
176
|
+
dispatchAdapter: adapter,
|
|
177
|
+
log: agentLog,
|
|
178
|
+
shutdownDeadlineMs: parseShutdownDeadlineMs(process.env.PRLL_SHUTDOWN_DEADLINE_MS),
|
|
179
|
+
forkDeadlineMs: parseForkDeadlineMs(process.env.PRLL_FORK_DEADLINE_MS),
|
|
180
|
+
dispatchDeadlineMs: parseDispatchDeadlineMs(process.env.PRLL_DISPATCH_DEADLINE_MS),
|
|
181
|
+
contextFilePathForSession: (sessionKey) =>
|
|
182
|
+
contextFilePathForSession(config.stateDir, sessionKey),
|
|
183
|
+
stepIdFilePathForSession: (sessionKey) =>
|
|
184
|
+
stepIdFilePathForSession(config.stateDir, sessionKey),
|
|
185
|
+
onConfigUpdate: async () => {
|
|
186
|
+
const refreshed = await getAgentMeWithLegacyFallback(client, config.orgId);
|
|
187
|
+
platformManaged = isPlatformManagedProfile(refreshed.agent_profile);
|
|
188
|
+
platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
|
|
189
|
+
const updated = await configMgr.fetch();
|
|
190
|
+
adapter.updateConfig({
|
|
191
|
+
model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
|
|
192
|
+
reasoningEffort: platformManaged
|
|
193
|
+
? (updated.thinkingEffort ?? config.reasoningEffort)
|
|
194
|
+
: (config.reasoningEffort ?? null),
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
onSessionReady: async () => {
|
|
198
|
+
const refreshed = await getAgentMeWithLegacyFallback(client, config.orgId);
|
|
199
|
+
platformManaged = isPlatformManagedProfile(refreshed.agent_profile);
|
|
200
|
+
platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
|
|
201
|
+
const updated = await configMgr.fetch();
|
|
202
|
+
adapter.updateConfig({
|
|
203
|
+
model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
|
|
204
|
+
reasoningEffort: platformManaged
|
|
205
|
+
? (updated.thinkingEffort ?? config.reasoningEffort)
|
|
206
|
+
: (config.reasoningEffort ?? null),
|
|
207
|
+
});
|
|
208
|
+
},
|
|
209
|
+
onNewSession: () => {
|
|
210
|
+
sessionManager.clearMainThread();
|
|
211
|
+
},
|
|
212
|
+
onSessionStale: () => {
|
|
213
|
+
sessionManager.clearMainThread();
|
|
214
|
+
},
|
|
215
|
+
});
|
|
139
216
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
217
|
+
const abortController = new AbortController();
|
|
218
|
+
const abort = () => abortController.abort();
|
|
219
|
+
process.on('SIGINT', abort);
|
|
220
|
+
process.on('SIGTERM', abort);
|
|
144
221
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
222
|
+
try {
|
|
223
|
+
agentLog.info(
|
|
224
|
+
`starting self-hosted Codex runtime (app-server driver) for ${me.display_name} (${agentUserId})`,
|
|
225
|
+
);
|
|
226
|
+
await gateway.run(abortController.signal);
|
|
227
|
+
} finally {
|
|
228
|
+
await adapter.stop();
|
|
229
|
+
process.off('SIGINT', abort);
|
|
230
|
+
process.off('SIGTERM', abort);
|
|
231
|
+
}
|
|
148
232
|
} finally {
|
|
149
|
-
await
|
|
150
|
-
process.off("SIGINT", abort);
|
|
151
|
-
process.off("SIGTERM", abort);
|
|
233
|
+
await telemetry.shutdown();
|
|
152
234
|
}
|
|
153
235
|
}
|
|
154
236
|
|
package/src/jsonrpc-client.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import type { ChildProcessWithoutNullStreams } from
|
|
1
|
+
import type { ChildProcessWithoutNullStreams } from 'node:child_process';
|
|
2
2
|
|
|
3
3
|
type JsonRpcId = number | string;
|
|
4
4
|
|
|
5
5
|
export type JsonRpcRequest = {
|
|
6
|
-
jsonrpc:
|
|
6
|
+
jsonrpc: '2.0';
|
|
7
7
|
id: JsonRpcId;
|
|
8
8
|
method: string;
|
|
9
9
|
params?: unknown;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export type JsonRpcNotification = {
|
|
13
|
-
jsonrpc:
|
|
13
|
+
jsonrpc: '2.0';
|
|
14
14
|
method: string;
|
|
15
15
|
params?: unknown;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
export type JsonRpcResponse = {
|
|
19
|
-
jsonrpc:
|
|
19
|
+
jsonrpc: '2.0';
|
|
20
20
|
id: JsonRpcId;
|
|
21
21
|
result?: unknown;
|
|
22
22
|
error?: { code: number; message: string; data?: unknown };
|
|
@@ -44,7 +44,7 @@ const DEFAULT_REQUEST_TIMEOUT_MS = 120_000;
|
|
|
44
44
|
export class JsonRpcStdioClient {
|
|
45
45
|
private nextId = 1;
|
|
46
46
|
private readonly pending = new Map<JsonRpcId, Pending>();
|
|
47
|
-
private buffer =
|
|
47
|
+
private buffer = '';
|
|
48
48
|
private onNotification: NotificationHandler | null = null;
|
|
49
49
|
private disposed = false;
|
|
50
50
|
|
|
@@ -53,11 +53,11 @@ export class JsonRpcStdioClient {
|
|
|
53
53
|
private readonly requestTimeoutMs: number = DEFAULT_REQUEST_TIMEOUT_MS,
|
|
54
54
|
private readonly killProcess?: (proc: ChildProcessWithoutNullStreams) => void,
|
|
55
55
|
) {
|
|
56
|
-
proc.stdout.setEncoding(
|
|
57
|
-
proc.stdout.on(
|
|
58
|
-
proc.once(
|
|
59
|
-
proc.once(
|
|
60
|
-
proc.stdin.on(
|
|
56
|
+
proc.stdout.setEncoding('utf8');
|
|
57
|
+
proc.stdout.on('data', (chunk: string) => this.ingest(chunk));
|
|
58
|
+
proc.once('close', () => this.dispose(new Error('app-server subprocess closed')));
|
|
59
|
+
proc.once('error', (err) => this.dispose(err));
|
|
60
|
+
proc.stdin.on('error', (err) => this.killUnhealthy(err));
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
setNotificationHandler(handler: NotificationHandler) {
|
|
@@ -66,16 +66,18 @@ export class JsonRpcStdioClient {
|
|
|
66
66
|
|
|
67
67
|
sendRequest(method: string, params?: unknown): Promise<unknown> {
|
|
68
68
|
if (this.disposed) {
|
|
69
|
-
return Promise.reject(new Error(
|
|
69
|
+
return Promise.reject(new Error('JSON-RPC client disposed'));
|
|
70
70
|
}
|
|
71
71
|
const id = this.nextId++;
|
|
72
|
-
const request: JsonRpcRequest = { jsonrpc:
|
|
72
|
+
const request: JsonRpcRequest = { jsonrpc: '2.0', id, method, params };
|
|
73
73
|
const promise = new Promise<unknown>((resolve, reject) => {
|
|
74
74
|
const timer = setTimeout(() => {
|
|
75
75
|
const pending = this.pending.get(id);
|
|
76
76
|
if (!pending) return;
|
|
77
77
|
this.pending.delete(id);
|
|
78
|
-
reject(
|
|
78
|
+
reject(
|
|
79
|
+
new Error(`JSON-RPC request "${method}" timed out after ${this.requestTimeoutMs}ms`),
|
|
80
|
+
);
|
|
79
81
|
this.killUnhealthy(new Error(`request "${method}" timed out; subprocess assumed hung`));
|
|
80
82
|
}, this.requestTimeoutMs);
|
|
81
83
|
this.pending.set(id, { resolve, reject, timer });
|
|
@@ -86,7 +88,7 @@ export class JsonRpcStdioClient {
|
|
|
86
88
|
|
|
87
89
|
sendNotification(method: string, params?: unknown) {
|
|
88
90
|
if (this.disposed) return;
|
|
89
|
-
const notification: JsonRpcNotification = { jsonrpc:
|
|
91
|
+
const notification: JsonRpcNotification = { jsonrpc: '2.0', method, params };
|
|
90
92
|
this.writeFrame(notification);
|
|
91
93
|
}
|
|
92
94
|
|
|
@@ -118,19 +120,19 @@ export class JsonRpcStdioClient {
|
|
|
118
120
|
if (this.killProcess) {
|
|
119
121
|
this.killProcess(this.proc);
|
|
120
122
|
} else {
|
|
121
|
-
this.proc.kill(
|
|
123
|
+
this.proc.kill('SIGTERM');
|
|
122
124
|
}
|
|
123
125
|
}
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
private ingest(chunk: string) {
|
|
127
129
|
this.buffer += chunk;
|
|
128
|
-
let newlineIndex = this.buffer.indexOf(
|
|
130
|
+
let newlineIndex = this.buffer.indexOf('\n');
|
|
129
131
|
while (newlineIndex >= 0) {
|
|
130
132
|
const line = this.buffer.slice(0, newlineIndex).trim();
|
|
131
133
|
this.buffer = this.buffer.slice(newlineIndex + 1);
|
|
132
134
|
if (line) this.handleLine(line);
|
|
133
|
-
newlineIndex = this.buffer.indexOf(
|
|
135
|
+
newlineIndex = this.buffer.indexOf('\n');
|
|
134
136
|
}
|
|
135
137
|
}
|
|
136
138
|
|
|
@@ -148,7 +150,7 @@ export class JsonRpcStdioClient {
|
|
|
148
150
|
this.pending.delete(message.id);
|
|
149
151
|
clearTimeout(pending.timer);
|
|
150
152
|
if (message.error) {
|
|
151
|
-
pending.reject(new Error(message.error.message ||
|
|
153
|
+
pending.reject(new Error(message.error.message || 'JSON-RPC error'));
|
|
152
154
|
} else {
|
|
153
155
|
pending.resolve(message.result);
|
|
154
156
|
}
|
|
@@ -162,9 +164,9 @@ export class JsonRpcStdioClient {
|
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
function isResponse(m: unknown): m is JsonRpcResponse {
|
|
165
|
-
return !!m && typeof m ===
|
|
167
|
+
return !!m && typeof m === 'object' && 'id' in m && ('result' in m || 'error' in m);
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
function isNotification(m: unknown): m is JsonRpcNotification {
|
|
169
|
-
return !!m && typeof m ===
|
|
171
|
+
return !!m && typeof m === 'object' && 'method' in m && !('id' in m);
|
|
170
172
|
}
|
package/src/session-manager.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as fs from
|
|
2
|
-
import * as path from
|
|
3
|
-
import type { ForkSessionHandle } from
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import type { ForkSessionHandle } from '@parall/agent-core';
|
|
4
4
|
|
|
5
5
|
type PersistedThread = {
|
|
6
6
|
runtimeKey: string;
|
|
@@ -66,13 +66,17 @@ export class CodexSessionManager {
|
|
|
66
66
|
|
|
67
67
|
private restore() {
|
|
68
68
|
try {
|
|
69
|
-
const raw = fs.readFileSync(this.stateFilePath,
|
|
69
|
+
const raw = fs.readFileSync(this.stateFilePath, 'utf8');
|
|
70
70
|
const parsed = JSON.parse(raw) as Partial<PersistedThread>;
|
|
71
|
-
if (
|
|
71
|
+
if (
|
|
72
|
+
parsed.runtimeKey === this.mainSessionKey &&
|
|
73
|
+
typeof parsed.threadId === 'string' &&
|
|
74
|
+
parsed.threadId.trim()
|
|
75
|
+
) {
|
|
72
76
|
this.threadIds.set(this.mainSessionKey, parsed.threadId.trim());
|
|
73
77
|
}
|
|
74
78
|
} catch (error) {
|
|
75
|
-
if ((error as NodeJS.ErrnoException)?.code !==
|
|
79
|
+
if ((error as NodeJS.ErrnoException)?.code !== 'ENOENT') {
|
|
76
80
|
this.logger?.warn(
|
|
77
81
|
`codex-agent: could not restore main thread state from ${this.stateFilePath}: ${String(error)}`,
|
|
78
82
|
);
|