@posthog/agent 2.1.148 → 2.1.150
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/agent.js +53 -9
- package/dist/agent.js.map +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +51 -11
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +63 -23
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +3 -3
- package/src/adapters/claude/session/options.ts +9 -0
- package/src/adapters/codex/spawn.ts +1 -1
- package/src/agent.ts +9 -1
- package/src/sagas/apply-snapshot-saga.ts +2 -0
- package/src/sagas/capture-tree-saga.ts +2 -0
- package/src/sagas/resume-saga.ts +2 -0
- package/src/session-log-writer.ts +39 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/agent",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.150",
|
|
4
4
|
"repository": "https://github.com/PostHog/twig",
|
|
5
5
|
"description": "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
6
6
|
"exports": {
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
"tsx": "^4.20.6",
|
|
75
75
|
"typescript": "^5.5.0",
|
|
76
76
|
"vitest": "^2.1.8",
|
|
77
|
-
"@
|
|
78
|
-
"@
|
|
77
|
+
"@twig/git": "1.0.0",
|
|
78
|
+
"@posthog/shared": "1.0.0"
|
|
79
79
|
},
|
|
80
80
|
"dependencies": {
|
|
81
81
|
"@agentclientprotocol/sdk": "^0.14.0",
|
|
@@ -140,6 +140,7 @@ function buildSpawnWrapper(
|
|
|
140
140
|
sessionId: string,
|
|
141
141
|
onProcessSpawned: (info: ProcessSpawnedInfo) => void,
|
|
142
142
|
onProcessExited?: (pid: number) => void,
|
|
143
|
+
logger?: Logger,
|
|
143
144
|
): (options: SpawnOptions) => SpawnedProcess {
|
|
144
145
|
return (spawnOpts: SpawnOptions): SpawnedProcess => {
|
|
145
146
|
const child = spawn(spawnOpts.command, spawnOpts.args, {
|
|
@@ -156,6 +157,13 @@ function buildSpawnWrapper(
|
|
|
156
157
|
});
|
|
157
158
|
}
|
|
158
159
|
|
|
160
|
+
child.stderr?.on("data", (data: Buffer) => {
|
|
161
|
+
const msg = data.toString().trim();
|
|
162
|
+
if (msg && logger) {
|
|
163
|
+
logger.debug(`[claude-code:${child.pid}] stderr: ${msg}`);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
159
167
|
if (onProcessExited) {
|
|
160
168
|
child.on("exit", () => {
|
|
161
169
|
if (child.pid) {
|
|
@@ -256,6 +264,7 @@ export function buildSessionOptions(params: BuildOptionsParams): Options {
|
|
|
256
264
|
params.sessionId,
|
|
257
265
|
params.onProcessSpawned,
|
|
258
266
|
params.onProcessExited,
|
|
267
|
+
params.logger,
|
|
259
268
|
),
|
|
260
269
|
}),
|
|
261
270
|
};
|
|
@@ -101,7 +101,7 @@ export function spawnCodexProcess(options: CodexProcessOptions): CodexProcess {
|
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
child.stderr?.on("data", (data: Buffer) => {
|
|
104
|
-
logger.
|
|
104
|
+
logger.warn("codex-acp stderr:", data.toString());
|
|
105
105
|
});
|
|
106
106
|
|
|
107
107
|
child.on("error", (err) => {
|
package/src/agent.ts
CHANGED
|
@@ -36,6 +36,12 @@ export class Agent {
|
|
|
36
36
|
logger: this.logger.child("SessionLogWriter"),
|
|
37
37
|
localCachePath: config.localCachePath,
|
|
38
38
|
});
|
|
39
|
+
|
|
40
|
+
if (config.localCachePath) {
|
|
41
|
+
SessionLogWriter.cleanupOldSessions(config.localCachePath).catch(
|
|
42
|
+
() => {},
|
|
43
|
+
);
|
|
44
|
+
}
|
|
39
45
|
}
|
|
40
46
|
}
|
|
41
47
|
|
|
@@ -69,7 +75,9 @@ export class Agent {
|
|
|
69
75
|
options: TaskExecutionOptions = {},
|
|
70
76
|
): Promise<InProcessAcpConnection> {
|
|
71
77
|
const gatewayConfig = this._configureLlmGateway(options.adapter);
|
|
72
|
-
this.logger.info("Configured LLM gateway",
|
|
78
|
+
this.logger.info("Configured LLM gateway", {
|
|
79
|
+
adapter: options.adapter,
|
|
80
|
+
});
|
|
73
81
|
this.taskRunId = taskRunId;
|
|
74
82
|
|
|
75
83
|
let allowedModelIds: Set<string> | undefined;
|
|
@@ -21,6 +21,8 @@ export interface CaptureTreeOutput {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export class CaptureTreeSaga extends Saga<CaptureTreeInput, CaptureTreeOutput> {
|
|
24
|
+
readonly sagaName = "CaptureTreeSaga";
|
|
25
|
+
|
|
24
26
|
protected async execute(input: CaptureTreeInput): Promise<CaptureTreeOutput> {
|
|
25
27
|
const {
|
|
26
28
|
repositoryPath,
|
package/src/sagas/resume-saga.ts
CHANGED
|
@@ -41,6 +41,8 @@ export interface ResumeOutput {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export class ResumeSaga extends Saga<ResumeInput, ResumeOutput> {
|
|
44
|
+
readonly sagaName = "ResumeSaga";
|
|
45
|
+
|
|
44
46
|
protected async execute(input: ResumeInput): Promise<ResumeOutput> {
|
|
45
47
|
const { taskId, runId, repositoryPath, apiClient } = input;
|
|
46
48
|
const logger =
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import fsp from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import type { SessionContext } from "./otel-log-writer.js";
|
|
4
5
|
import type { PostHogAPIClient } from "./posthog-api.js";
|
|
@@ -30,6 +31,7 @@ export class SessionLogWriter {
|
|
|
30
31
|
private static readonly FLUSH_MAX_INTERVAL_MS = 5000;
|
|
31
32
|
private static readonly MAX_FLUSH_RETRIES = 10;
|
|
32
33
|
private static readonly MAX_RETRY_DELAY_MS = 30_000;
|
|
34
|
+
private static readonly SESSIONS_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;
|
|
33
35
|
|
|
34
36
|
private posthogAPI?: PostHogAPIClient;
|
|
35
37
|
private pendingEntries: Map<string, StoredNotification[]> = new Map();
|
|
@@ -196,10 +198,16 @@ export class SessionLogWriter {
|
|
|
196
198
|
);
|
|
197
199
|
this.retryCounts.set(sessionId, 0);
|
|
198
200
|
} else {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
201
|
+
if (retryCount === 1) {
|
|
202
|
+
this.logger.warn(
|
|
203
|
+
`Failed to persist session logs, will retry (up to ${SessionLogWriter.MAX_FLUSH_RETRIES} attempts)`,
|
|
204
|
+
{
|
|
205
|
+
taskId: session.context.taskId,
|
|
206
|
+
runId: session.context.runId,
|
|
207
|
+
error: error instanceof Error ? error.message : String(error),
|
|
208
|
+
},
|
|
209
|
+
);
|
|
210
|
+
}
|
|
203
211
|
const currentPending = this.pendingEntries.get(sessionId) ?? [];
|
|
204
212
|
this.pendingEntries.set(sessionId, [...pending, ...currentPending]);
|
|
205
213
|
this.scheduleFlush(sessionId);
|
|
@@ -344,4 +352,31 @@ export class SessionLogWriter {
|
|
|
344
352
|
});
|
|
345
353
|
}
|
|
346
354
|
}
|
|
355
|
+
|
|
356
|
+
static async cleanupOldSessions(localCachePath: string): Promise<number> {
|
|
357
|
+
const sessionsDir = path.join(localCachePath, "sessions");
|
|
358
|
+
let deleted = 0;
|
|
359
|
+
try {
|
|
360
|
+
const entries = await fsp.readdir(sessionsDir);
|
|
361
|
+
const now = Date.now();
|
|
362
|
+
for (const entry of entries) {
|
|
363
|
+
const entryPath = path.join(sessionsDir, entry);
|
|
364
|
+
try {
|
|
365
|
+
const stats = await fsp.stat(entryPath);
|
|
366
|
+
if (
|
|
367
|
+
stats.isDirectory() &&
|
|
368
|
+
now - stats.birthtimeMs > SessionLogWriter.SESSIONS_MAX_AGE_MS
|
|
369
|
+
) {
|
|
370
|
+
await fsp.rm(entryPath, { recursive: true, force: true });
|
|
371
|
+
deleted++;
|
|
372
|
+
}
|
|
373
|
+
} catch {
|
|
374
|
+
// Skip entries we can't stat
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
} catch {
|
|
378
|
+
// Sessions dir may not exist yet
|
|
379
|
+
}
|
|
380
|
+
return deleted;
|
|
381
|
+
}
|
|
347
382
|
}
|