@parall/claude-agent 1.29.3 → 1.30.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/dispatch.js +8 -8
- package/dist/index.js +16 -9
- package/dist/session-manager.d.ts +1 -0
- package/dist/session-manager.d.ts.map +1 -1
- package/dist/session-manager.js +9 -0
- package/package.json +4 -4
- package/src/dispatch.ts +8 -8
- package/src/index.ts +16 -9
- package/src/session-manager.ts +9 -0
package/dist/dispatch.js
CHANGED
|
@@ -92,7 +92,7 @@ export class ClaudeCodeAdapter {
|
|
|
92
92
|
const pending = this.pendingInjections.get(sessionKey) ?? 0;
|
|
93
93
|
if (pending > 0) {
|
|
94
94
|
this.pendingInjections.delete(sessionKey);
|
|
95
|
-
context.log?.info?.(`
|
|
95
|
+
context.log?.info?.(`consuming ${pending} steer turn(s)`);
|
|
96
96
|
for (let i = 0; i < pending; i++) {
|
|
97
97
|
yield* this.consumeSteerTurn(sessionKey, context.log);
|
|
98
98
|
}
|
|
@@ -109,7 +109,7 @@ export class ClaudeCodeAdapter {
|
|
|
109
109
|
releasePreparedAttachments = pinLocalAttachmentPaths(prepared.attachments.images);
|
|
110
110
|
}
|
|
111
111
|
catch (err) {
|
|
112
|
-
context.log?.warn?.(`
|
|
112
|
+
context.log?.warn?.(`failed to prepare local attachments: ${String(err)}`);
|
|
113
113
|
}
|
|
114
114
|
try {
|
|
115
115
|
yield* this.runTurn(sessionKey, promptBody, context.log);
|
|
@@ -161,7 +161,7 @@ export class ClaudeCodeAdapter {
|
|
|
161
161
|
async *consumeSteerTurn(sessionKey, log) {
|
|
162
162
|
const state = this.processes.get(sessionKey);
|
|
163
163
|
if (!state || state.done) {
|
|
164
|
-
throw new Error("
|
|
164
|
+
throw new Error("process dead during steer consumption");
|
|
165
165
|
}
|
|
166
166
|
const groupKey = randomUUID();
|
|
167
167
|
const parserNext = state.parser.next();
|
|
@@ -171,7 +171,7 @@ export class ClaudeCodeAdapter {
|
|
|
171
171
|
]);
|
|
172
172
|
if (firstRead.kind === "timeout") {
|
|
173
173
|
state.steerReadPending = parserNext;
|
|
174
|
-
log?.info?.(`
|
|
174
|
+
log?.info?.(`steer turn timeout — steer was incorporated into previous turn`);
|
|
175
175
|
return;
|
|
176
176
|
}
|
|
177
177
|
let next = firstRead.result;
|
|
@@ -180,7 +180,7 @@ export class ClaudeCodeAdapter {
|
|
|
180
180
|
if (next.done) {
|
|
181
181
|
state.done = true;
|
|
182
182
|
this.processes.delete(sessionKey);
|
|
183
|
-
throw new Error("
|
|
183
|
+
throw new Error("process exited while consuming steer turn");
|
|
184
184
|
}
|
|
185
185
|
const parsed = next.value;
|
|
186
186
|
if (parsed.type === "session_id") {
|
|
@@ -263,7 +263,7 @@ export class ClaudeCodeAdapter {
|
|
|
263
263
|
const detail = state.handle.stderrChunks.join("").trim();
|
|
264
264
|
const exit = await state.handle.exitPromise.catch(() => ({ code: null, signal: null }));
|
|
265
265
|
if (detail) {
|
|
266
|
-
log?.warn?.(`
|
|
266
|
+
log?.warn?.(`subprocess stderr: ${detail}`);
|
|
267
267
|
}
|
|
268
268
|
if (!sawError) {
|
|
269
269
|
yield {
|
|
@@ -308,7 +308,7 @@ export class ClaudeCodeAdapter {
|
|
|
308
308
|
}
|
|
309
309
|
ensureProcess(sessionKey, log) {
|
|
310
310
|
if (this.shuttingDown) {
|
|
311
|
-
throw new Error("
|
|
311
|
+
throw new Error("adapter shutting down, refusing new process");
|
|
312
312
|
}
|
|
313
313
|
const existing = this.processes.get(sessionKey);
|
|
314
314
|
if (existing && !existing.done) {
|
|
@@ -333,7 +333,7 @@ export class ClaudeCodeAdapter {
|
|
|
333
333
|
spawnProcess(sessionKey, log) {
|
|
334
334
|
const args = this.buildArgs(sessionKey);
|
|
335
335
|
const env = buildSpawnEnv(process.env, this.opts.claudeHome, this.buildPlaceholderContext(sessionKey), { allowApiKey: this.opts.allowApiKey, effortLevel: this._effortLevel });
|
|
336
|
-
log?.info(`
|
|
336
|
+
log?.info(`spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || "default"}, effort=${this._effortLevel || "default"}, mode=${this.opts.permissionMode})`);
|
|
337
337
|
const proc = spawn(IS_WIN32 ? quoteWin32Arg(this.opts.claudeBin) : this.opts.claudeBin, IS_WIN32 ? args.map(quoteWin32Arg) : args, {
|
|
338
338
|
cwd: this.opts.workspaceDir,
|
|
339
339
|
env,
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as os from "node:os";
|
|
3
|
-
import { ParallAgentGateway, createPlatformConfigManager, createLogger, isPlatformManagedProfile, parseShutdownDeadlineMs } from "@parall/agent-core";
|
|
3
|
+
import { ParallAgentGateway, createPlatformConfigManager, createLogger, childLogger, isPlatformManagedProfile, parseShutdownDeadlineMs } from "@parall/agent-core";
|
|
4
4
|
import { ApiError, ParallClient, ParallWs } from "@parall/sdk";
|
|
5
5
|
import { buildClaudeRuntimeKey, contextFilePathForSession, resolveClaudeAgentConfig, resolveWsUrl, sessionStateFilePathForRuntime, stepIdFilePathForSession, } from "./config.js";
|
|
6
6
|
import { ClaudeCodeAdapter } from "./dispatch.js";
|
|
7
7
|
import { ClaudeSessionManager } from "./session-manager.js";
|
|
8
8
|
import { ensureClaudeWorkspace } from "./workspace.js";
|
|
9
9
|
const log = createLogger("claude-agent");
|
|
10
|
+
let activeLog = log;
|
|
10
11
|
async function getAgentMeWithLegacyFallback(client, orgId) {
|
|
11
12
|
try {
|
|
12
13
|
return await client.getAgentMe(orgId);
|
|
@@ -35,20 +36,22 @@ async function main() {
|
|
|
35
36
|
});
|
|
36
37
|
const me = await getAgentMeWithLegacyFallback(client, config.orgId);
|
|
37
38
|
const agentUserId = me.id;
|
|
38
|
-
|
|
39
|
+
const agentLog = childLogger(log, agentUserId);
|
|
40
|
+
activeLog = agentLog;
|
|
41
|
+
ensureClaudeWorkspace(config.workspaceDir, agentLog, {
|
|
39
42
|
userId: agentUserId,
|
|
40
43
|
displayName: me.display_name,
|
|
41
44
|
description: me.agent_profile?.description ?? undefined,
|
|
42
45
|
});
|
|
43
46
|
const runtimeKey = config.runtimeKey || buildClaudeRuntimeKey(agentUserId);
|
|
44
47
|
const sessionStateFilePath = sessionStateFilePathForRuntime(config.stateDir, runtimeKey);
|
|
45
|
-
const sessionManager = new ClaudeSessionManager(runtimeKey, sessionStateFilePath,
|
|
48
|
+
const sessionManager = new ClaudeSessionManager(runtimeKey, sessionStateFilePath, agentLog);
|
|
46
49
|
const resolvedWsUrl = resolveWsUrl(config.apiUrl, config.wsUrl, config.swimlaneName);
|
|
47
50
|
const ws = new ParallWs({
|
|
48
51
|
getTicket: () => client.getWsTicket(),
|
|
49
52
|
wsUrl: resolvedWsUrl,
|
|
50
53
|
});
|
|
51
|
-
const configMgr = createPlatformConfigManager({ client, stateDir: config.stateDir, runtimeType: "claude-code", log });
|
|
54
|
+
const configMgr = createPlatformConfigManager({ client, stateDir: config.stateDir, runtimeType: "claude-code", log: agentLog });
|
|
52
55
|
const platformDefaults = await configMgr.fetch();
|
|
53
56
|
let platformManaged = isPlatformManagedProfile(me.agent_profile);
|
|
54
57
|
const resolvedModel = platformManaged ? (platformDefaults.model ?? config.model) : config.model;
|
|
@@ -56,9 +59,9 @@ async function main() {
|
|
|
56
59
|
? (platformDefaults.thinkingEffort ?? (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined))
|
|
57
60
|
: (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined);
|
|
58
61
|
if (platformDefaults.model)
|
|
59
|
-
|
|
62
|
+
agentLog.info(`platform config: model=${platformDefaults.model} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
|
|
60
63
|
if (platformDefaults.thinkingEffort)
|
|
61
|
-
|
|
64
|
+
agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
|
|
62
65
|
const adapter = new ClaudeCodeAdapter({
|
|
63
66
|
claudeBin: config.claudeBin,
|
|
64
67
|
claudeHome: config.claudeHome,
|
|
@@ -103,7 +106,7 @@ async function main() {
|
|
|
103
106
|
claude_home: config.claudeHome,
|
|
104
107
|
},
|
|
105
108
|
dispatchAdapter: adapter,
|
|
106
|
-
log,
|
|
109
|
+
log: agentLog,
|
|
107
110
|
shutdownDeadlineMs: parseShutdownDeadlineMs(process.env.PRLL_SHUTDOWN_DEADLINE_MS),
|
|
108
111
|
contextFilePathForSession: (sessionKey) => contextFilePathForSession(config.stateDir, sessionKey),
|
|
109
112
|
stepIdFilePathForSession: (sessionKey) => stepIdFilePathForSession(config.stateDir, sessionKey),
|
|
@@ -132,13 +135,17 @@ async function main() {
|
|
|
132
135
|
// onBeforeDisconnect to close stdin and SIGTERM any survivors after
|
|
133
136
|
// in-flight drains finish.
|
|
134
137
|
onBeforeDisconnect: () => adapter.shutdown(),
|
|
138
|
+
onNewSession: async () => {
|
|
139
|
+
sessionManager.clearMainSession();
|
|
140
|
+
await adapter.shutdown();
|
|
141
|
+
},
|
|
135
142
|
});
|
|
136
143
|
const abortController = new AbortController();
|
|
137
144
|
const abort = () => abortController.abort();
|
|
138
145
|
process.on("SIGINT", abort);
|
|
139
146
|
process.on("SIGTERM", abort);
|
|
140
147
|
try {
|
|
141
|
-
|
|
148
|
+
agentLog.info(`starting self-hosted Claude runtime for ${me.display_name} (${agentUserId})`);
|
|
142
149
|
await gateway.run(abortController.signal);
|
|
143
150
|
}
|
|
144
151
|
finally {
|
|
@@ -147,6 +154,6 @@ async function main() {
|
|
|
147
154
|
}
|
|
148
155
|
}
|
|
149
156
|
main().catch((err) => {
|
|
150
|
-
|
|
157
|
+
activeLog.error(`fatal: ${String(err)}`);
|
|
151
158
|
process.exitCode = 1;
|
|
152
159
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../src/session-manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAO5D,KAAK,0BAA0B,GAAG;IAChC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,8BAA8B,CAAC;IACrC,WAAW,EAAE,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAC7E,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,qBAAa,oBAAoB;IAM7B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAP1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IACxD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA6B;IAChE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;gBAGjD,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,0BAA0B,YAAA;IAKtD,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE;IAU3C,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAQrD,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAYrE,WAAW,CAAC,UAAU,EAAE,MAAM;IAU9B,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAI/D,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB;IAsB/D,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,mBAAmB;IAO7D,qEAAqE;IACrE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAE5C,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;YAQpB,WAAW;IAuCzB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,OAAO;CAahB"}
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../src/session-manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAO5D,KAAK,0BAA0B,GAAG;IAChC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,8BAA8B,CAAC;IACrC,WAAW,EAAE,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAC7E,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,qBAAa,oBAAoB;IAM7B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAP1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IACxD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA6B;IAChE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;gBAGjD,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,0BAA0B,YAAA;IAKtD,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE;IAU3C,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAQrD,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAYrE,WAAW,CAAC,UAAU,EAAE,MAAM;IAU9B,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAI/D,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB;IAsB/D,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,mBAAmB;IAO7D,qEAAqE;IACrE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAE5C,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;YAQpB,WAAW;IAuCzB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,WAAW;IAqBnB,gBAAgB;IAShB,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,OAAO;CAahB"}
|
package/dist/session-manager.js
CHANGED
|
@@ -164,6 +164,15 @@ export class ClaudeSessionManager {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
|
+
clearMainSession() {
|
|
168
|
+
this.sessionIds.delete(this.mainSessionKey);
|
|
169
|
+
try {
|
|
170
|
+
fs.unlinkSync(this.stateFilePath);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// File may not exist.
|
|
174
|
+
}
|
|
175
|
+
}
|
|
167
176
|
restore() {
|
|
168
177
|
try {
|
|
169
178
|
const raw = fs.readFileSync(this.stateFilePath, "utf8");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/claude-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.0",
|
|
4
4
|
"description": "Claude Code bridge runtime for self-hosted Parall agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"src"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@parall/agent-core": "1.
|
|
29
|
-
"@parall/cli": "1.
|
|
30
|
-
"@parall/sdk": "1.
|
|
28
|
+
"@parall/agent-core": "1.30.0",
|
|
29
|
+
"@parall/cli": "1.30.0",
|
|
30
|
+
"@parall/sdk": "1.30.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^22.0.0",
|
package/src/dispatch.ts
CHANGED
|
@@ -150,7 +150,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
150
150
|
const pending = this.pendingInjections.get(sessionKey) ?? 0;
|
|
151
151
|
if (pending > 0) {
|
|
152
152
|
this.pendingInjections.delete(sessionKey);
|
|
153
|
-
context.log?.info?.(`
|
|
153
|
+
context.log?.info?.(`consuming ${pending} steer turn(s)`);
|
|
154
154
|
for (let i = 0; i < pending; i++) {
|
|
155
155
|
yield* this.consumeSteerTurn(sessionKey, context.log);
|
|
156
156
|
}
|
|
@@ -168,7 +168,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
168
168
|
releasePreparedAttachments = pinLocalAttachmentPaths(prepared.attachments.images);
|
|
169
169
|
} catch (err) {
|
|
170
170
|
context.log?.warn?.(
|
|
171
|
-
`
|
|
171
|
+
`failed to prepare local attachments: ${String(err)}`,
|
|
172
172
|
);
|
|
173
173
|
}
|
|
174
174
|
|
|
@@ -230,7 +230,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
230
230
|
): AsyncGenerator<RuntimeEvent> {
|
|
231
231
|
const state = this.processes.get(sessionKey);
|
|
232
232
|
if (!state || state.done) {
|
|
233
|
-
throw new Error("
|
|
233
|
+
throw new Error("process dead during steer consumption");
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
const groupKey = randomUUID();
|
|
@@ -245,7 +245,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
245
245
|
|
|
246
246
|
if (firstRead.kind === "timeout") {
|
|
247
247
|
state.steerReadPending = parserNext;
|
|
248
|
-
log?.info?.(`
|
|
248
|
+
log?.info?.(`steer turn timeout — steer was incorporated into previous turn`);
|
|
249
249
|
return;
|
|
250
250
|
}
|
|
251
251
|
|
|
@@ -255,7 +255,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
255
255
|
if (next.done) {
|
|
256
256
|
state.done = true;
|
|
257
257
|
this.processes.delete(sessionKey);
|
|
258
|
-
throw new Error("
|
|
258
|
+
throw new Error("process exited while consuming steer turn");
|
|
259
259
|
}
|
|
260
260
|
const parsed = next.value;
|
|
261
261
|
|
|
@@ -334,7 +334,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
334
334
|
const detail = state.handle.stderrChunks.join("").trim();
|
|
335
335
|
const exit = await state.handle.exitPromise.catch(() => ({ code: null, signal: null } as const));
|
|
336
336
|
if (detail) {
|
|
337
|
-
log?.warn?.(`
|
|
337
|
+
log?.warn?.(`subprocess stderr: ${detail}`);
|
|
338
338
|
}
|
|
339
339
|
if (!sawError) {
|
|
340
340
|
yield {
|
|
@@ -387,7 +387,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
387
387
|
|
|
388
388
|
private ensureProcess(sessionKey: string, log: GatewayLogger | undefined): ProcessState {
|
|
389
389
|
if (this.shuttingDown) {
|
|
390
|
-
throw new Error("
|
|
390
|
+
throw new Error("adapter shutting down, refusing new process");
|
|
391
391
|
}
|
|
392
392
|
|
|
393
393
|
const existing = this.processes.get(sessionKey);
|
|
@@ -420,7 +420,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
|
420
420
|
);
|
|
421
421
|
|
|
422
422
|
log?.info(
|
|
423
|
-
`
|
|
423
|
+
`spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || "default"}, effort=${this._effortLevel || "default"}, mode=${this.opts.permissionMode})`,
|
|
424
424
|
);
|
|
425
425
|
|
|
426
426
|
const proc = spawn(
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import * as os from "node:os";
|
|
4
|
-
import { ParallAgentGateway, createPlatformConfigManager, createLogger, isPlatformManagedProfile, parseShutdownDeadlineMs } from "@parall/agent-core";
|
|
4
|
+
import { ParallAgentGateway, createPlatformConfigManager, createLogger, childLogger, isPlatformManagedProfile, parseShutdownDeadlineMs } from "@parall/agent-core";
|
|
5
5
|
import { ApiError, ParallClient, ParallWs } from "@parall/sdk";
|
|
6
6
|
import {
|
|
7
7
|
buildClaudeRuntimeKey,
|
|
@@ -16,6 +16,7 @@ import { ClaudeSessionManager } from "./session-manager.js";
|
|
|
16
16
|
import { ensureClaudeWorkspace } from "./workspace.js";
|
|
17
17
|
|
|
18
18
|
const log = createLogger("claude-agent");
|
|
19
|
+
let activeLog = log;
|
|
19
20
|
|
|
20
21
|
async function getAgentMeWithLegacyFallback(client: ParallClient, orgId: string) {
|
|
21
22
|
try {
|
|
@@ -52,7 +53,9 @@ async function main() {
|
|
|
52
53
|
|
|
53
54
|
const me = await getAgentMeWithLegacyFallback(client, config.orgId);
|
|
54
55
|
const agentUserId = me.id;
|
|
55
|
-
|
|
56
|
+
const agentLog = childLogger(log, agentUserId);
|
|
57
|
+
activeLog = agentLog;
|
|
58
|
+
ensureClaudeWorkspace(config.workspaceDir, agentLog, {
|
|
56
59
|
userId: agentUserId,
|
|
57
60
|
displayName: me.display_name,
|
|
58
61
|
description: me.agent_profile?.description ?? undefined,
|
|
@@ -62,7 +65,7 @@ async function main() {
|
|
|
62
65
|
const sessionManager = new ClaudeSessionManager(
|
|
63
66
|
runtimeKey,
|
|
64
67
|
sessionStateFilePath,
|
|
65
|
-
|
|
68
|
+
agentLog,
|
|
66
69
|
);
|
|
67
70
|
|
|
68
71
|
const resolvedWsUrl = resolveWsUrl(config.apiUrl, config.wsUrl, config.swimlaneName);
|
|
@@ -71,15 +74,15 @@ async function main() {
|
|
|
71
74
|
wsUrl: resolvedWsUrl,
|
|
72
75
|
});
|
|
73
76
|
|
|
74
|
-
const configMgr = createPlatformConfigManager({ client, stateDir: config.stateDir, runtimeType: "claude-code", log });
|
|
77
|
+
const configMgr = createPlatformConfigManager({ client, stateDir: config.stateDir, runtimeType: "claude-code", log: agentLog });
|
|
75
78
|
const platformDefaults = await configMgr.fetch();
|
|
76
79
|
let platformManaged = isPlatformManagedProfile(me.agent_profile);
|
|
77
80
|
const resolvedModel = platformManaged ? (platformDefaults.model ?? config.model) : config.model;
|
|
78
81
|
const resolvedEffort = platformManaged
|
|
79
82
|
? (platformDefaults.thinkingEffort ?? (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined))
|
|
80
83
|
: (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined);
|
|
81
|
-
if (platformDefaults.model)
|
|
82
|
-
if (platformDefaults.thinkingEffort)
|
|
84
|
+
if (platformDefaults.model) agentLog.info(`platform config: model=${platformDefaults.model} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
|
|
85
|
+
if (platformDefaults.thinkingEffort) agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
|
|
83
86
|
|
|
84
87
|
const adapter = new ClaudeCodeAdapter({
|
|
85
88
|
claudeBin: config.claudeBin,
|
|
@@ -126,7 +129,7 @@ async function main() {
|
|
|
126
129
|
claude_home: config.claudeHome,
|
|
127
130
|
},
|
|
128
131
|
dispatchAdapter: adapter,
|
|
129
|
-
log,
|
|
132
|
+
log: agentLog,
|
|
130
133
|
shutdownDeadlineMs: parseShutdownDeadlineMs(process.env.PRLL_SHUTDOWN_DEADLINE_MS),
|
|
131
134
|
contextFilePathForSession: (sessionKey) => contextFilePathForSession(config.stateDir, sessionKey),
|
|
132
135
|
stepIdFilePathForSession: (sessionKey) => stepIdFilePathForSession(config.stateDir, sessionKey),
|
|
@@ -155,6 +158,10 @@ async function main() {
|
|
|
155
158
|
// onBeforeDisconnect to close stdin and SIGTERM any survivors after
|
|
156
159
|
// in-flight drains finish.
|
|
157
160
|
onBeforeDisconnect: () => adapter.shutdown(),
|
|
161
|
+
onNewSession: async () => {
|
|
162
|
+
sessionManager.clearMainSession();
|
|
163
|
+
await adapter.shutdown();
|
|
164
|
+
},
|
|
158
165
|
});
|
|
159
166
|
|
|
160
167
|
const abortController = new AbortController();
|
|
@@ -163,7 +170,7 @@ async function main() {
|
|
|
163
170
|
process.on("SIGTERM", abort);
|
|
164
171
|
|
|
165
172
|
try {
|
|
166
|
-
|
|
173
|
+
agentLog.info(`starting self-hosted Claude runtime for ${me.display_name} (${agentUserId})`);
|
|
167
174
|
await gateway.run(abortController.signal);
|
|
168
175
|
} finally {
|
|
169
176
|
process.off("SIGINT", abort);
|
|
@@ -172,6 +179,6 @@ async function main() {
|
|
|
172
179
|
}
|
|
173
180
|
|
|
174
181
|
main().catch((err) => {
|
|
175
|
-
|
|
182
|
+
activeLog.error(`fatal: ${String(err)}`);
|
|
176
183
|
process.exitCode = 1;
|
|
177
184
|
});
|
package/src/session-manager.ts
CHANGED
|
@@ -207,6 +207,15 @@ export class ClaudeSessionManager {
|
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
clearMainSession() {
|
|
211
|
+
this.sessionIds.delete(this.mainSessionKey);
|
|
212
|
+
try {
|
|
213
|
+
fs.unlinkSync(this.stateFilePath);
|
|
214
|
+
} catch {
|
|
215
|
+
// File may not exist.
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
210
219
|
private restore() {
|
|
211
220
|
try {
|
|
212
221
|
const raw = fs.readFileSync(this.stateFilePath, "utf8");
|