@parall/claude-agent 1.23.0 → 1.25.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.d.ts +1 -1
- package/dist/dispatch.d.ts.map +1 -1
- package/dist/dispatch.js +76 -57
- package/dist/index.js +19 -3
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +2 -0
- package/package.json +4 -4
- package/src/dispatch.ts +86 -63
- package/src/index.ts +19 -3
- package/src/workspace.ts +2 -0
package/dist/dispatch.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export declare function buildSpawnEnv(parentEnv: NodeJS.ProcessEnv, claudeHome:
|
|
|
10
10
|
export declare class ClaudeCodeAdapter implements DispatchAdapter {
|
|
11
11
|
private readonly opts;
|
|
12
12
|
constructor(opts: ClaudeCodeAdapterOptions);
|
|
13
|
-
dispatch({ bodyForAgent, sessionKey, context }: DispatchOpts): AsyncIterable<RuntimeEvent>;
|
|
13
|
+
dispatch({ event, bodyForAgent, sessionKey, context }: DispatchOpts): AsyncIterable<RuntimeEvent>;
|
|
14
14
|
forkSession({ sessionKey }: ForkOpts): import("@parall/agent-core").ForkSessionHandle | null;
|
|
15
15
|
cleanupFork({ fork }: CleanupForkOpts): void;
|
|
16
16
|
private buildArgs;
|
package/dist/dispatch.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,KAAK,wBAAwB,GAAG,IAAI,CAClC,iBAAiB,EACf,gBAAgB,GAChB,aAAa,GACb,cAAc,GACd,oBAAoB,GACpB,WAAW,GACX,YAAY,GACZ,iBAAiB,GACjB,OAAO,GACP,gBAAgB,GAChB,cAAc,CACjB,GAAG;IACF,cAAc,EAAE,oBAAoB,CAAC;CACtC,CAAC;AAEF,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,CAAC,UAAU,EAC5B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC,EAChC,IAAI,EAAE;IAAE,WAAW,EAAE,OAAO,CAAA;CAAE,GAC7B,MAAM,CAAC,UAAU,CAuBnB;AAED,qBAAa,iBAAkB,YAAW,eAAe;IAC3C,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,wBAAwB;IAEpD,QAAQ,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC;IAkGxG,WAAW,CAAC,EAAE,UAAU,EAAE,EAAE,QAAQ;IAIpC,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,eAAe;IAIrC,OAAO,CAAC,SAAS;CAkClB"}
|
package/dist/dispatch.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
|
+
import { appendPreparedLocalAttachmentRefs, pinLocalAttachmentPaths, } from "@parall/agent-core/internal/attachment-input";
|
|
3
4
|
import { parseClaudeStreamJson } from "./output-parser.js";
|
|
4
5
|
export function buildSpawnEnv(parentEnv, claudeHome, context, opts) {
|
|
5
6
|
const env = { ...parentEnv };
|
|
@@ -30,73 +31,91 @@ export class ClaudeCodeAdapter {
|
|
|
30
31
|
constructor(opts) {
|
|
31
32
|
this.opts = opts;
|
|
32
33
|
}
|
|
33
|
-
async *dispatch({ bodyForAgent, sessionKey, context }) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
async *dispatch({ event, bodyForAgent, sessionKey, context }) {
|
|
35
|
+
let promptBody = bodyForAgent;
|
|
36
|
+
let releasePreparedAttachments = () => { };
|
|
37
|
+
try {
|
|
38
|
+
const prepared = await appendPreparedLocalAttachmentRefs(bodyForAgent, event, context, {
|
|
39
|
+
workspaceDir: this.opts.workspaceDir,
|
|
40
|
+
log: context.log,
|
|
41
|
+
});
|
|
42
|
+
promptBody = prepared.body;
|
|
43
|
+
releasePreparedAttachments = pinLocalAttachmentPaths(prepared.attachments.images);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
context.log?.warn?.(`claude-agent[${context.accountId}]: failed to prepare local attachments: ${String(err)}`);
|
|
46
47
|
}
|
|
47
|
-
const stderr = [];
|
|
48
|
-
proc.stderr.on("data", (chunk) => {
|
|
49
|
-
stderr.push(chunk.toString());
|
|
50
|
-
});
|
|
51
|
-
const exitPromise = new Promise((resolve, reject) => {
|
|
52
|
-
proc.once("error", reject);
|
|
53
|
-
proc.once("close", (code, signal) => resolve({ code, signal }));
|
|
54
|
-
});
|
|
55
|
-
const groupKey = randomUUID();
|
|
56
|
-
let sawError = false;
|
|
57
|
-
let completed = false;
|
|
58
48
|
try {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
49
|
+
const args = this.buildArgs(sessionKey, promptBody);
|
|
50
|
+
const env = buildSpawnEnv(process.env, this.opts.claudeHome, context, {
|
|
51
|
+
allowApiKey: this.opts.allowApiKey,
|
|
52
|
+
});
|
|
53
|
+
context.log?.info(`claude-agent[${context.accountId}]: spawn ${this.opts.claudeBin} ${args.slice(0, -1).join(" ")}`);
|
|
54
|
+
const proc = spawn(this.opts.claudeBin, args, {
|
|
55
|
+
cwd: this.opts.workspaceDir,
|
|
56
|
+
env,
|
|
57
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
58
|
+
});
|
|
59
|
+
if (!proc.stdout || !proc.stderr) {
|
|
60
|
+
throw new Error("Claude subprocess did not provide stdio pipes");
|
|
61
|
+
}
|
|
62
|
+
const stderr = [];
|
|
63
|
+
proc.stderr.on("data", (chunk) => {
|
|
64
|
+
stderr.push(chunk.toString());
|
|
65
|
+
});
|
|
66
|
+
const exitPromise = new Promise((resolve, reject) => {
|
|
67
|
+
proc.once("error", reject);
|
|
68
|
+
proc.once("close", (code, signal) => resolve({ code, signal }));
|
|
69
|
+
});
|
|
70
|
+
const groupKey = randomUUID();
|
|
71
|
+
let sawError = false;
|
|
72
|
+
let completed = false;
|
|
73
|
+
try {
|
|
74
|
+
for await (const streamEvent of parseClaudeStreamJson(proc.stdout)) {
|
|
75
|
+
if (streamEvent.type === "session_id") {
|
|
76
|
+
this.opts.sessionManager.recordSessionId(sessionKey, streamEvent.sessionId);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (streamEvent.type === "error") {
|
|
80
|
+
sawError = true;
|
|
81
|
+
yield streamEvent;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (streamEvent.type === "text") {
|
|
85
|
+
// Runtime output contract (symmetric with OpenClaw channel): Claude's
|
|
86
|
+
// plain text is never projected as a chat message. To reply, the agent
|
|
87
|
+
// must explicitly run `parall messages send` / `dm` via Bash. Text
|
|
88
|
+
// events are still recorded as suppressed session steps for audit.
|
|
89
|
+
yield {
|
|
90
|
+
...streamEvent,
|
|
91
|
+
project: false,
|
|
92
|
+
groupKey,
|
|
93
|
+
};
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
yield {
|
|
97
|
+
...streamEvent,
|
|
98
|
+
groupKey,
|
|
99
|
+
};
|
|
63
100
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
101
|
+
completed = true;
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
if (!completed && proc.exitCode === null && proc.signalCode === null) {
|
|
105
|
+
proc.kill("SIGTERM");
|
|
68
106
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// must explicitly run `parall messages send` / `dm` via Bash. Text
|
|
73
|
-
// events are still recorded as suppressed session steps for audit.
|
|
107
|
+
const { code, signal } = await exitPromise;
|
|
108
|
+
if ((code ?? 0) !== 0 && !sawError) {
|
|
109
|
+
const detail = stderr.join("").trim();
|
|
74
110
|
yield {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
groupKey,
|
|
111
|
+
type: "error",
|
|
112
|
+
message: detail || `Claude exited with code ${code ?? "unknown"}${signal ? ` (${signal})` : ""}`,
|
|
78
113
|
};
|
|
79
|
-
continue;
|
|
80
114
|
}
|
|
81
|
-
yield {
|
|
82
|
-
...event,
|
|
83
|
-
groupKey,
|
|
84
|
-
};
|
|
85
115
|
}
|
|
86
|
-
completed = true;
|
|
87
116
|
}
|
|
88
117
|
finally {
|
|
89
|
-
|
|
90
|
-
proc.kill("SIGTERM");
|
|
91
|
-
}
|
|
92
|
-
const { code, signal } = await exitPromise;
|
|
93
|
-
if ((code ?? 0) !== 0 && !sawError) {
|
|
94
|
-
const detail = stderr.join("").trim();
|
|
95
|
-
yield {
|
|
96
|
-
type: "error",
|
|
97
|
-
message: detail || `Claude exited with code ${code ?? "unknown"}${signal ? ` (${signal})` : ""}`,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
118
|
+
releasePreparedAttachments();
|
|
100
119
|
}
|
|
101
120
|
}
|
|
102
121
|
forkSession({ sessionKey }) {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import { ParallAgentGateway, parseShutdownDeadlineMs } from "@parall/agent-core";
|
|
4
|
-
import { ParallClient, ParallWs } from "@parall/sdk";
|
|
4
|
+
import { ApiError, ParallClient, ParallWs } from "@parall/sdk";
|
|
5
5
|
import { buildClaudeRuntimeKey, resolveClaudeAgentConfig, resolveWsUrl, sessionStateFilePathForRuntime, stepIdFilePathForSession, } from "./config.js";
|
|
6
6
|
import { ClaudeCodeAdapter } from "./dispatch.js";
|
|
7
7
|
import { ClaudeSessionManager } from "./session-manager.js";
|
|
@@ -13,6 +13,18 @@ function createLogger(prefix) {
|
|
|
13
13
|
error: (msg) => console.error(`[${prefix}] ${msg}`),
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
+
async function getAgentMeWithLegacyFallback(client, orgId) {
|
|
17
|
+
try {
|
|
18
|
+
return await client.getAgentMe(orgId);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
if (!(err instanceof ApiError && err.status === 404)) {
|
|
22
|
+
throw err;
|
|
23
|
+
}
|
|
24
|
+
const user = await client.getMe();
|
|
25
|
+
return { ...user, agent_profile: null };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
16
28
|
async function main() {
|
|
17
29
|
const config = resolveClaudeAgentConfig(process.env);
|
|
18
30
|
const log = createLogger("claude-agent");
|
|
@@ -28,9 +40,13 @@ async function main() {
|
|
|
28
40
|
token: config.apiKey,
|
|
29
41
|
swimlaneName: config.swimlaneName,
|
|
30
42
|
});
|
|
31
|
-
const me = await client.
|
|
43
|
+
const me = await getAgentMeWithLegacyFallback(client, config.orgId);
|
|
32
44
|
const agentUserId = me.id;
|
|
33
|
-
ensureClaudeWorkspace(config.workspaceDir, log, {
|
|
45
|
+
ensureClaudeWorkspace(config.workspaceDir, log, {
|
|
46
|
+
userId: agentUserId,
|
|
47
|
+
displayName: me.display_name,
|
|
48
|
+
description: me.agent_profile?.description ?? undefined,
|
|
49
|
+
});
|
|
34
50
|
const runtimeKey = config.runtimeKey || buildClaudeRuntimeKey(agentUserId);
|
|
35
51
|
const sessionStateFilePath = sessionStateFilePathForRuntime(config.stateDir, runtimeKey);
|
|
36
52
|
const sessionManager = new ClaudeSessionManager(runtimeKey, sessionStateFilePath, log);
|
package/dist/workspace.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,EACrC,aAAa,CAAC,EAAE,aAAa,QAiC9B"}
|
package/dist/workspace.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { BRIDGE_WORKSPACE_INSTRUCTIONS, PRLL_BEHAVIOR, PRLL_REFERENCE_GUIDE, buildIdentity, } from "@parall/agent-core";
|
|
4
|
+
import { ensureLocalAttachmentGitExclude } from "@parall/agent-core/internal/attachment-input";
|
|
4
5
|
export function ensureClaudeWorkspace(workspaceDir, log, agentIdentity) {
|
|
5
6
|
const CLAUDE_MD = [
|
|
6
7
|
buildIdentity(agentIdentity),
|
|
@@ -30,4 +31,5 @@ export function ensureClaudeWorkspace(workspaceDir, log, agentIdentity) {
|
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
fs.writeFileSync(claudeMdPath, CLAUDE_MD, "utf8");
|
|
34
|
+
ensureLocalAttachmentGitExclude(workspaceDir);
|
|
33
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/claude-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.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.25.0",
|
|
29
|
+
"@parall/cli": "1.25.0",
|
|
30
|
+
"@parall/sdk": "1.25.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^22.0.0",
|
package/src/dispatch.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
|
+
import {
|
|
4
|
+
appendPreparedLocalAttachmentRefs,
|
|
5
|
+
pinLocalAttachmentPaths,
|
|
6
|
+
} from "@parall/agent-core/internal/attachment-input";
|
|
3
7
|
import type {
|
|
4
8
|
CleanupForkOpts,
|
|
5
9
|
DispatchAdapter,
|
|
@@ -60,82 +64,101 @@ export function buildSpawnEnv(
|
|
|
60
64
|
export class ClaudeCodeAdapter implements DispatchAdapter {
|
|
61
65
|
constructor(private readonly opts: ClaudeCodeAdapterOptions) {}
|
|
62
66
|
|
|
63
|
-
async *dispatch({ bodyForAgent, sessionKey, context }: DispatchOpts): AsyncIterable<RuntimeEvent> {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (!proc.stdout || !proc.stderr) {
|
|
78
|
-
throw new Error("Claude subprocess did not provide stdio pipes");
|
|
67
|
+
async *dispatch({ event, bodyForAgent, sessionKey, context }: DispatchOpts): AsyncIterable<RuntimeEvent> {
|
|
68
|
+
let promptBody = bodyForAgent;
|
|
69
|
+
let releasePreparedAttachments = () => {};
|
|
70
|
+
try {
|
|
71
|
+
const prepared = await appendPreparedLocalAttachmentRefs(bodyForAgent, event, context, {
|
|
72
|
+
workspaceDir: this.opts.workspaceDir,
|
|
73
|
+
log: context.log,
|
|
74
|
+
});
|
|
75
|
+
promptBody = prepared.body;
|
|
76
|
+
releasePreparedAttachments = pinLocalAttachmentPaths(prepared.attachments.images);
|
|
77
|
+
} catch (err) {
|
|
78
|
+
context.log?.warn?.(
|
|
79
|
+
`claude-agent[${context.accountId}]: failed to prepare local attachments: ${String(err)}`,
|
|
80
|
+
);
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
try {
|
|
84
|
+
const args = this.buildArgs(sessionKey, promptBody);
|
|
85
|
+
const env = buildSpawnEnv(process.env, this.opts.claudeHome, context, {
|
|
86
|
+
allowApiKey: this.opts.allowApiKey,
|
|
87
|
+
});
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
proc.once("error", reject);
|
|
88
|
-
proc.once("close", (code, signal) => resolve({ code, signal }));
|
|
89
|
-
});
|
|
89
|
+
context.log?.info(`claude-agent[${context.accountId}]: spawn ${this.opts.claudeBin} ${args.slice(0, -1).join(" ")}`);
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
const proc = spawn(this.opts.claudeBin, args, {
|
|
92
|
+
cwd: this.opts.workspaceDir,
|
|
93
|
+
env,
|
|
94
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
95
|
+
});
|
|
94
96
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
this.opts.sessionManager.recordSessionId(sessionKey, event.sessionId);
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
97
|
+
if (!proc.stdout || !proc.stderr) {
|
|
98
|
+
throw new Error("Claude subprocess did not provide stdio pipes");
|
|
99
|
+
}
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
const stderr: string[] = [];
|
|
102
|
+
proc.stderr.on("data", (chunk) => {
|
|
103
|
+
stderr.push(chunk.toString());
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const exitPromise = new Promise<{ code: number | null; signal: NodeJS.Signals | null }>((resolve, reject) => {
|
|
107
|
+
proc.once("error", reject);
|
|
108
|
+
proc.once("close", (code, signal) => resolve({ code, signal }));
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const groupKey = randomUUID();
|
|
112
|
+
let sawError = false;
|
|
113
|
+
let completed = false;
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
for await (const streamEvent of parseClaudeStreamJson(proc.stdout)) {
|
|
117
|
+
if (streamEvent.type === "session_id") {
|
|
118
|
+
this.opts.sessionManager.recordSessionId(sessionKey, streamEvent.sessionId);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (streamEvent.type === "error") {
|
|
123
|
+
sawError = true;
|
|
124
|
+
yield streamEvent;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (streamEvent.type === "text") {
|
|
129
|
+
// Runtime output contract (symmetric with OpenClaw channel): Claude's
|
|
130
|
+
// plain text is never projected as a chat message. To reply, the agent
|
|
131
|
+
// must explicitly run `parall messages send` / `dm` via Bash. Text
|
|
132
|
+
// events are still recorded as suppressed session steps for audit.
|
|
133
|
+
yield {
|
|
134
|
+
...streamEvent,
|
|
135
|
+
project: false,
|
|
136
|
+
groupKey,
|
|
137
|
+
};
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
107
140
|
|
|
108
|
-
if (event.type === "text") {
|
|
109
|
-
// Runtime output contract (symmetric with OpenClaw channel): Claude's
|
|
110
|
-
// plain text is never projected as a chat message. To reply, the agent
|
|
111
|
-
// must explicitly run `parall messages send` / `dm` via Bash. Text
|
|
112
|
-
// events are still recorded as suppressed session steps for audit.
|
|
113
141
|
yield {
|
|
114
|
-
...
|
|
115
|
-
project: false,
|
|
142
|
+
...streamEvent,
|
|
116
143
|
groupKey,
|
|
117
144
|
};
|
|
118
|
-
continue;
|
|
119
145
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
146
|
+
completed = true;
|
|
147
|
+
} finally {
|
|
148
|
+
if (!completed && proc.exitCode === null && proc.signalCode === null) {
|
|
149
|
+
proc.kill("SIGTERM");
|
|
150
|
+
}
|
|
151
|
+
const { code, signal } = await exitPromise;
|
|
152
|
+
if ((code ?? 0) !== 0 && !sawError) {
|
|
153
|
+
const detail = stderr.join("").trim();
|
|
154
|
+
yield {
|
|
155
|
+
type: "error",
|
|
156
|
+
message: detail || `Claude exited with code ${code ?? "unknown"}${signal ? ` (${signal})` : ""}`,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
125
159
|
}
|
|
126
|
-
completed = true;
|
|
127
160
|
} finally {
|
|
128
|
-
|
|
129
|
-
proc.kill("SIGTERM");
|
|
130
|
-
}
|
|
131
|
-
const { code, signal } = await exitPromise;
|
|
132
|
-
if ((code ?? 0) !== 0 && !sawError) {
|
|
133
|
-
const detail = stderr.join("").trim();
|
|
134
|
-
yield {
|
|
135
|
-
type: "error",
|
|
136
|
-
message: detail || `Claude exited with code ${code ?? "unknown"}${signal ? ` (${signal})` : ""}`,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
161
|
+
releasePreparedAttachments();
|
|
139
162
|
}
|
|
140
163
|
}
|
|
141
164
|
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import { ParallAgentGateway, parseShutdownDeadlineMs } from "@parall/agent-core";
|
|
5
|
-
import { ParallClient, ParallWs } from "@parall/sdk";
|
|
5
|
+
import { ApiError, ParallClient, ParallWs } from "@parall/sdk";
|
|
6
6
|
import {
|
|
7
7
|
buildClaudeRuntimeKey,
|
|
8
8
|
resolveClaudeAgentConfig,
|
|
@@ -22,6 +22,18 @@ function createLogger(prefix: string) {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
async function getAgentMeWithLegacyFallback(client: ParallClient, orgId: string) {
|
|
26
|
+
try {
|
|
27
|
+
return await client.getAgentMe(orgId);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
if (!(err instanceof ApiError && err.status === 404)) {
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
const user = await client.getMe();
|
|
33
|
+
return { ...user, agent_profile: null };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
25
37
|
async function main() {
|
|
26
38
|
const config = resolveClaudeAgentConfig(process.env);
|
|
27
39
|
const log = createLogger("claude-agent");
|
|
@@ -44,9 +56,13 @@ async function main() {
|
|
|
44
56
|
swimlaneName: config.swimlaneName,
|
|
45
57
|
});
|
|
46
58
|
|
|
47
|
-
const me = await client.
|
|
59
|
+
const me = await getAgentMeWithLegacyFallback(client, config.orgId);
|
|
48
60
|
const agentUserId = me.id;
|
|
49
|
-
ensureClaudeWorkspace(config.workspaceDir, log, {
|
|
61
|
+
ensureClaudeWorkspace(config.workspaceDir, log, {
|
|
62
|
+
userId: agentUserId,
|
|
63
|
+
displayName: me.display_name,
|
|
64
|
+
description: me.agent_profile?.description ?? undefined,
|
|
65
|
+
});
|
|
50
66
|
const runtimeKey = config.runtimeKey || buildClaudeRuntimeKey(agentUserId);
|
|
51
67
|
const sessionStateFilePath = sessionStateFilePathForRuntime(config.stateDir, runtimeKey);
|
|
52
68
|
const sessionManager = new ClaudeSessionManager(
|
package/src/workspace.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
buildIdentity,
|
|
8
8
|
} from "@parall/agent-core";
|
|
9
9
|
import type { AgentIdentity } from "@parall/agent-core";
|
|
10
|
+
import { ensureLocalAttachmentGitExclude } from "@parall/agent-core/internal/attachment-input";
|
|
10
11
|
|
|
11
12
|
export function ensureClaudeWorkspace(
|
|
12
13
|
workspaceDir: string,
|
|
@@ -43,4 +44,5 @@ export function ensureClaudeWorkspace(
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
fs.writeFileSync(claudeMdPath, CLAUDE_MD, "utf8");
|
|
47
|
+
ensureLocalAttachmentGitExclude(workspaceDir);
|
|
46
48
|
}
|