@posthog/agent 2.1.22 → 2.1.29
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-LrKyX9KN.d.ts → agent-DcBmoTR4.d.ts} +7 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +83 -7
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +83 -7
- package/dist/index.js.map +1 -1
- package/dist/server/agent-server.js +102 -8
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +102 -8
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +1 -1
- package/src/server/agent-server.ts +21 -1
- package/src/session-log-writer.test.ts +41 -0
- package/src/session-log-writer.ts +91 -5
|
@@ -1183,7 +1183,7 @@ import { v7 as uuidv7 } from "uuid";
|
|
|
1183
1183
|
// package.json
|
|
1184
1184
|
var package_default = {
|
|
1185
1185
|
name: "@posthog/agent",
|
|
1186
|
-
version: "2.1.
|
|
1186
|
+
version: "2.1.29",
|
|
1187
1187
|
repository: "https://github.com/PostHog/twig",
|
|
1188
1188
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
1189
1189
|
exports: {
|
|
@@ -4266,19 +4266,36 @@ var PostHogAPIClient = class {
|
|
|
4266
4266
|
};
|
|
4267
4267
|
|
|
4268
4268
|
// src/session-log-writer.ts
|
|
4269
|
-
var SessionLogWriter = class {
|
|
4269
|
+
var SessionLogWriter = class _SessionLogWriter {
|
|
4270
|
+
static FLUSH_DEBOUNCE_MS = 500;
|
|
4271
|
+
static FLUSH_MAX_INTERVAL_MS = 5e3;
|
|
4272
|
+
static MAX_FLUSH_RETRIES = 10;
|
|
4273
|
+
static MAX_RETRY_DELAY_MS = 3e4;
|
|
4270
4274
|
posthogAPI;
|
|
4271
4275
|
pendingEntries = /* @__PURE__ */ new Map();
|
|
4272
4276
|
flushTimeouts = /* @__PURE__ */ new Map();
|
|
4277
|
+
lastFlushAttemptTime = /* @__PURE__ */ new Map();
|
|
4278
|
+
retryCounts = /* @__PURE__ */ new Map();
|
|
4273
4279
|
sessions = /* @__PURE__ */ new Map();
|
|
4280
|
+
messageCounts = /* @__PURE__ */ new Map();
|
|
4274
4281
|
logger;
|
|
4275
4282
|
constructor(options = {}) {
|
|
4276
4283
|
this.posthogAPI = options.posthogAPI;
|
|
4277
4284
|
this.logger = options.logger ?? new Logger({ debug: false, prefix: "[SessionLogWriter]" });
|
|
4278
4285
|
}
|
|
4279
4286
|
async flushAll() {
|
|
4287
|
+
const sessionIds = [...this.sessions.keys()];
|
|
4288
|
+
const pendingCounts = sessionIds.map((id) => ({
|
|
4289
|
+
id,
|
|
4290
|
+
pending: this.pendingEntries.get(id)?.length ?? 0,
|
|
4291
|
+
messages: this.messageCounts.get(id) ?? 0
|
|
4292
|
+
}));
|
|
4293
|
+
this.logger.info("flushAll called", {
|
|
4294
|
+
sessions: sessionIds.length,
|
|
4295
|
+
pending: pendingCounts
|
|
4296
|
+
});
|
|
4280
4297
|
const flushPromises = [];
|
|
4281
|
-
for (const sessionId of
|
|
4298
|
+
for (const sessionId of sessionIds) {
|
|
4282
4299
|
flushPromises.push(this.flush(sessionId));
|
|
4283
4300
|
}
|
|
4284
4301
|
await Promise.all(flushPromises);
|
|
@@ -4287,7 +4304,12 @@ var SessionLogWriter = class {
|
|
|
4287
4304
|
if (this.sessions.has(sessionId)) {
|
|
4288
4305
|
return;
|
|
4289
4306
|
}
|
|
4307
|
+
this.logger.info("Session registered", {
|
|
4308
|
+
sessionId,
|
|
4309
|
+
taskId: context.taskId
|
|
4310
|
+
});
|
|
4290
4311
|
this.sessions.set(sessionId, { context });
|
|
4312
|
+
this.lastFlushAttemptTime.set(sessionId, Date.now());
|
|
4291
4313
|
}
|
|
4292
4314
|
isRegistered(sessionId) {
|
|
4293
4315
|
return this.sessions.has(sessionId);
|
|
@@ -4295,8 +4317,16 @@ var SessionLogWriter = class {
|
|
|
4295
4317
|
appendRawLine(sessionId, line) {
|
|
4296
4318
|
const session = this.sessions.get(sessionId);
|
|
4297
4319
|
if (!session) {
|
|
4320
|
+
this.logger.warn("appendRawLine called for unregistered session", {
|
|
4321
|
+
sessionId
|
|
4322
|
+
});
|
|
4298
4323
|
return;
|
|
4299
4324
|
}
|
|
4325
|
+
const count = (this.messageCounts.get(sessionId) ?? 0) + 1;
|
|
4326
|
+
this.messageCounts.set(sessionId, count);
|
|
4327
|
+
if (count % 10 === 1) {
|
|
4328
|
+
this.logger.info("Messages received", { count, sessionId });
|
|
4329
|
+
}
|
|
4300
4330
|
try {
|
|
4301
4331
|
const message = JSON.parse(line);
|
|
4302
4332
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -4332,24 +4362,56 @@ var SessionLogWriter = class {
|
|
|
4332
4362
|
}
|
|
4333
4363
|
async flush(sessionId) {
|
|
4334
4364
|
const session = this.sessions.get(sessionId);
|
|
4335
|
-
if (!session)
|
|
4365
|
+
if (!session) {
|
|
4366
|
+
this.logger.warn("flush: no session found", { sessionId });
|
|
4367
|
+
return;
|
|
4368
|
+
}
|
|
4336
4369
|
this.emitCoalescedMessage(sessionId, session);
|
|
4337
4370
|
const pending = this.pendingEntries.get(sessionId);
|
|
4338
|
-
if (!this.posthogAPI || !pending?.length)
|
|
4371
|
+
if (!this.posthogAPI || !pending?.length) {
|
|
4372
|
+
this.logger.info("flush: nothing to persist", {
|
|
4373
|
+
sessionId,
|
|
4374
|
+
hasPosthogAPI: !!this.posthogAPI,
|
|
4375
|
+
pendingCount: pending?.length ?? 0
|
|
4376
|
+
});
|
|
4377
|
+
return;
|
|
4378
|
+
}
|
|
4339
4379
|
this.pendingEntries.delete(sessionId);
|
|
4340
4380
|
const timeout = this.flushTimeouts.get(sessionId);
|
|
4341
4381
|
if (timeout) {
|
|
4342
4382
|
clearTimeout(timeout);
|
|
4343
4383
|
this.flushTimeouts.delete(sessionId);
|
|
4344
4384
|
}
|
|
4385
|
+
this.lastFlushAttemptTime.set(sessionId, Date.now());
|
|
4345
4386
|
try {
|
|
4346
4387
|
await this.posthogAPI.appendTaskRunLog(
|
|
4347
4388
|
session.context.taskId,
|
|
4348
4389
|
session.context.runId,
|
|
4349
4390
|
pending
|
|
4350
4391
|
);
|
|
4392
|
+
this.retryCounts.set(sessionId, 0);
|
|
4393
|
+
this.logger.info("Flushed session logs", {
|
|
4394
|
+
sessionId,
|
|
4395
|
+
entryCount: pending.length
|
|
4396
|
+
});
|
|
4351
4397
|
} catch (error) {
|
|
4352
|
-
this.
|
|
4398
|
+
const retryCount = (this.retryCounts.get(sessionId) ?? 0) + 1;
|
|
4399
|
+
this.retryCounts.set(sessionId, retryCount);
|
|
4400
|
+
if (retryCount >= _SessionLogWriter.MAX_FLUSH_RETRIES) {
|
|
4401
|
+
this.logger.error(
|
|
4402
|
+
`Dropping ${pending.length} session log entries after ${retryCount} failed flush attempts`,
|
|
4403
|
+
{ sessionId, error }
|
|
4404
|
+
);
|
|
4405
|
+
this.retryCounts.set(sessionId, 0);
|
|
4406
|
+
} else {
|
|
4407
|
+
this.logger.error(
|
|
4408
|
+
`Failed to persist session logs (attempt ${retryCount}/${_SessionLogWriter.MAX_FLUSH_RETRIES}):`,
|
|
4409
|
+
error
|
|
4410
|
+
);
|
|
4411
|
+
const currentPending = this.pendingEntries.get(sessionId) ?? [];
|
|
4412
|
+
this.pendingEntries.set(sessionId, [...pending, ...currentPending]);
|
|
4413
|
+
this.scheduleFlush(sessionId);
|
|
4414
|
+
}
|
|
4353
4415
|
}
|
|
4354
4416
|
}
|
|
4355
4417
|
isAgentMessageChunk(message) {
|
|
@@ -4395,7 +4457,21 @@ var SessionLogWriter = class {
|
|
|
4395
4457
|
scheduleFlush(sessionId) {
|
|
4396
4458
|
const existing = this.flushTimeouts.get(sessionId);
|
|
4397
4459
|
if (existing) clearTimeout(existing);
|
|
4398
|
-
const
|
|
4460
|
+
const retryCount = this.retryCounts.get(sessionId) ?? 0;
|
|
4461
|
+
const lastAttempt = this.lastFlushAttemptTime.get(sessionId) ?? 0;
|
|
4462
|
+
const elapsed = Date.now() - lastAttempt;
|
|
4463
|
+
let delay2;
|
|
4464
|
+
if (retryCount > 0) {
|
|
4465
|
+
delay2 = Math.min(
|
|
4466
|
+
_SessionLogWriter.FLUSH_DEBOUNCE_MS * 2 ** retryCount,
|
|
4467
|
+
_SessionLogWriter.MAX_RETRY_DELAY_MS
|
|
4468
|
+
);
|
|
4469
|
+
} else if (elapsed >= _SessionLogWriter.FLUSH_MAX_INTERVAL_MS) {
|
|
4470
|
+
delay2 = 0;
|
|
4471
|
+
} else {
|
|
4472
|
+
delay2 = _SessionLogWriter.FLUSH_DEBOUNCE_MS;
|
|
4473
|
+
}
|
|
4474
|
+
const timeout = setTimeout(() => this.flush(sessionId), delay2);
|
|
4399
4475
|
this.flushTimeouts.set(sessionId, timeout);
|
|
4400
4476
|
}
|
|
4401
4477
|
};
|
|
@@ -10369,6 +10445,7 @@ var AgentServer = class {
|
|
|
10369
10445
|
});
|
|
10370
10446
|
const mode = this.getEffectiveMode(payload);
|
|
10371
10447
|
if (mode === "background") {
|
|
10448
|
+
await this.session.logWriter.flushAll();
|
|
10372
10449
|
await this.signalTaskComplete(payload, result.stopReason);
|
|
10373
10450
|
} else {
|
|
10374
10451
|
this.logger.info("Interactive mode - staying open for conversation");
|
|
@@ -10377,6 +10454,9 @@ var AgentServer = class {
|
|
|
10377
10454
|
this.logger.error("Failed to send initial task message", error);
|
|
10378
10455
|
const mode = this.getEffectiveMode(payload);
|
|
10379
10456
|
if (mode === "background") {
|
|
10457
|
+
if (this.session) {
|
|
10458
|
+
await this.session.logWriter.flushAll();
|
|
10459
|
+
}
|
|
10380
10460
|
await this.signalTaskComplete(payload, "error");
|
|
10381
10461
|
}
|
|
10382
10462
|
}
|
|
@@ -10391,10 +10471,24 @@ After completing the requested changes:
|
|
|
10391
10471
|
3. Push the branch to origin
|
|
10392
10472
|
4. Create a pull request using \`gh pr create\` with a descriptive title and body
|
|
10393
10473
|
|
|
10394
|
-
Important:
|
|
10474
|
+
Important:
|
|
10475
|
+
- Always create the PR. Do not ask for confirmation.
|
|
10476
|
+
- Do NOT add "Co-Authored-By" trailers to commit messages.
|
|
10477
|
+
- Do NOT add "Generated with [Claude Code]" or similar attribution lines to PR descriptions.
|
|
10395
10478
|
`;
|
|
10396
10479
|
}
|
|
10397
10480
|
async signalTaskComplete(payload, stopReason) {
|
|
10481
|
+
if (this.session?.payload.run_id === payload.run_id) {
|
|
10482
|
+
try {
|
|
10483
|
+
await this.session.logWriter.flush(payload.run_id);
|
|
10484
|
+
} catch (error) {
|
|
10485
|
+
this.logger.warn("Failed to flush session logs before completion", {
|
|
10486
|
+
taskId: payload.task_id,
|
|
10487
|
+
runId: payload.run_id,
|
|
10488
|
+
error
|
|
10489
|
+
});
|
|
10490
|
+
}
|
|
10491
|
+
}
|
|
10398
10492
|
const status = stopReason === "cancelled" ? "cancelled" : stopReason === "error" ? "failed" : "completed";
|
|
10399
10493
|
try {
|
|
10400
10494
|
await this.posthogAPI.updateTaskRun(payload.task_id, payload.run_id, {
|