@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
package/dist/server/bin.cjs
CHANGED
|
@@ -1175,7 +1175,7 @@ var import_uuid = require("uuid");
|
|
|
1175
1175
|
// package.json
|
|
1176
1176
|
var package_default = {
|
|
1177
1177
|
name: "@posthog/agent",
|
|
1178
|
-
version: "2.1.
|
|
1178
|
+
version: "2.1.29",
|
|
1179
1179
|
repository: "https://github.com/PostHog/twig",
|
|
1180
1180
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
1181
1181
|
exports: {
|
|
@@ -4258,19 +4258,36 @@ var PostHogAPIClient = class {
|
|
|
4258
4258
|
};
|
|
4259
4259
|
|
|
4260
4260
|
// src/session-log-writer.ts
|
|
4261
|
-
var SessionLogWriter = class {
|
|
4261
|
+
var SessionLogWriter = class _SessionLogWriter {
|
|
4262
|
+
static FLUSH_DEBOUNCE_MS = 500;
|
|
4263
|
+
static FLUSH_MAX_INTERVAL_MS = 5e3;
|
|
4264
|
+
static MAX_FLUSH_RETRIES = 10;
|
|
4265
|
+
static MAX_RETRY_DELAY_MS = 3e4;
|
|
4262
4266
|
posthogAPI;
|
|
4263
4267
|
pendingEntries = /* @__PURE__ */ new Map();
|
|
4264
4268
|
flushTimeouts = /* @__PURE__ */ new Map();
|
|
4269
|
+
lastFlushAttemptTime = /* @__PURE__ */ new Map();
|
|
4270
|
+
retryCounts = /* @__PURE__ */ new Map();
|
|
4265
4271
|
sessions = /* @__PURE__ */ new Map();
|
|
4272
|
+
messageCounts = /* @__PURE__ */ new Map();
|
|
4266
4273
|
logger;
|
|
4267
4274
|
constructor(options = {}) {
|
|
4268
4275
|
this.posthogAPI = options.posthogAPI;
|
|
4269
4276
|
this.logger = options.logger ?? new Logger({ debug: false, prefix: "[SessionLogWriter]" });
|
|
4270
4277
|
}
|
|
4271
4278
|
async flushAll() {
|
|
4279
|
+
const sessionIds = [...this.sessions.keys()];
|
|
4280
|
+
const pendingCounts = sessionIds.map((id) => ({
|
|
4281
|
+
id,
|
|
4282
|
+
pending: this.pendingEntries.get(id)?.length ?? 0,
|
|
4283
|
+
messages: this.messageCounts.get(id) ?? 0
|
|
4284
|
+
}));
|
|
4285
|
+
this.logger.info("flushAll called", {
|
|
4286
|
+
sessions: sessionIds.length,
|
|
4287
|
+
pending: pendingCounts
|
|
4288
|
+
});
|
|
4272
4289
|
const flushPromises = [];
|
|
4273
|
-
for (const sessionId of
|
|
4290
|
+
for (const sessionId of sessionIds) {
|
|
4274
4291
|
flushPromises.push(this.flush(sessionId));
|
|
4275
4292
|
}
|
|
4276
4293
|
await Promise.all(flushPromises);
|
|
@@ -4279,7 +4296,12 @@ var SessionLogWriter = class {
|
|
|
4279
4296
|
if (this.sessions.has(sessionId)) {
|
|
4280
4297
|
return;
|
|
4281
4298
|
}
|
|
4299
|
+
this.logger.info("Session registered", {
|
|
4300
|
+
sessionId,
|
|
4301
|
+
taskId: context.taskId
|
|
4302
|
+
});
|
|
4282
4303
|
this.sessions.set(sessionId, { context });
|
|
4304
|
+
this.lastFlushAttemptTime.set(sessionId, Date.now());
|
|
4283
4305
|
}
|
|
4284
4306
|
isRegistered(sessionId) {
|
|
4285
4307
|
return this.sessions.has(sessionId);
|
|
@@ -4287,8 +4309,16 @@ var SessionLogWriter = class {
|
|
|
4287
4309
|
appendRawLine(sessionId, line) {
|
|
4288
4310
|
const session = this.sessions.get(sessionId);
|
|
4289
4311
|
if (!session) {
|
|
4312
|
+
this.logger.warn("appendRawLine called for unregistered session", {
|
|
4313
|
+
sessionId
|
|
4314
|
+
});
|
|
4290
4315
|
return;
|
|
4291
4316
|
}
|
|
4317
|
+
const count = (this.messageCounts.get(sessionId) ?? 0) + 1;
|
|
4318
|
+
this.messageCounts.set(sessionId, count);
|
|
4319
|
+
if (count % 10 === 1) {
|
|
4320
|
+
this.logger.info("Messages received", { count, sessionId });
|
|
4321
|
+
}
|
|
4292
4322
|
try {
|
|
4293
4323
|
const message = JSON.parse(line);
|
|
4294
4324
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -4324,24 +4354,56 @@ var SessionLogWriter = class {
|
|
|
4324
4354
|
}
|
|
4325
4355
|
async flush(sessionId) {
|
|
4326
4356
|
const session = this.sessions.get(sessionId);
|
|
4327
|
-
if (!session)
|
|
4357
|
+
if (!session) {
|
|
4358
|
+
this.logger.warn("flush: no session found", { sessionId });
|
|
4359
|
+
return;
|
|
4360
|
+
}
|
|
4328
4361
|
this.emitCoalescedMessage(sessionId, session);
|
|
4329
4362
|
const pending = this.pendingEntries.get(sessionId);
|
|
4330
|
-
if (!this.posthogAPI || !pending?.length)
|
|
4363
|
+
if (!this.posthogAPI || !pending?.length) {
|
|
4364
|
+
this.logger.info("flush: nothing to persist", {
|
|
4365
|
+
sessionId,
|
|
4366
|
+
hasPosthogAPI: !!this.posthogAPI,
|
|
4367
|
+
pendingCount: pending?.length ?? 0
|
|
4368
|
+
});
|
|
4369
|
+
return;
|
|
4370
|
+
}
|
|
4331
4371
|
this.pendingEntries.delete(sessionId);
|
|
4332
4372
|
const timeout = this.flushTimeouts.get(sessionId);
|
|
4333
4373
|
if (timeout) {
|
|
4334
4374
|
clearTimeout(timeout);
|
|
4335
4375
|
this.flushTimeouts.delete(sessionId);
|
|
4336
4376
|
}
|
|
4377
|
+
this.lastFlushAttemptTime.set(sessionId, Date.now());
|
|
4337
4378
|
try {
|
|
4338
4379
|
await this.posthogAPI.appendTaskRunLog(
|
|
4339
4380
|
session.context.taskId,
|
|
4340
4381
|
session.context.runId,
|
|
4341
4382
|
pending
|
|
4342
4383
|
);
|
|
4384
|
+
this.retryCounts.set(sessionId, 0);
|
|
4385
|
+
this.logger.info("Flushed session logs", {
|
|
4386
|
+
sessionId,
|
|
4387
|
+
entryCount: pending.length
|
|
4388
|
+
});
|
|
4343
4389
|
} catch (error) {
|
|
4344
|
-
this.
|
|
4390
|
+
const retryCount = (this.retryCounts.get(sessionId) ?? 0) + 1;
|
|
4391
|
+
this.retryCounts.set(sessionId, retryCount);
|
|
4392
|
+
if (retryCount >= _SessionLogWriter.MAX_FLUSH_RETRIES) {
|
|
4393
|
+
this.logger.error(
|
|
4394
|
+
`Dropping ${pending.length} session log entries after ${retryCount} failed flush attempts`,
|
|
4395
|
+
{ sessionId, error }
|
|
4396
|
+
);
|
|
4397
|
+
this.retryCounts.set(sessionId, 0);
|
|
4398
|
+
} else {
|
|
4399
|
+
this.logger.error(
|
|
4400
|
+
`Failed to persist session logs (attempt ${retryCount}/${_SessionLogWriter.MAX_FLUSH_RETRIES}):`,
|
|
4401
|
+
error
|
|
4402
|
+
);
|
|
4403
|
+
const currentPending = this.pendingEntries.get(sessionId) ?? [];
|
|
4404
|
+
this.pendingEntries.set(sessionId, [...pending, ...currentPending]);
|
|
4405
|
+
this.scheduleFlush(sessionId);
|
|
4406
|
+
}
|
|
4345
4407
|
}
|
|
4346
4408
|
}
|
|
4347
4409
|
isAgentMessageChunk(message) {
|
|
@@ -4387,7 +4449,21 @@ var SessionLogWriter = class {
|
|
|
4387
4449
|
scheduleFlush(sessionId) {
|
|
4388
4450
|
const existing = this.flushTimeouts.get(sessionId);
|
|
4389
4451
|
if (existing) clearTimeout(existing);
|
|
4390
|
-
const
|
|
4452
|
+
const retryCount = this.retryCounts.get(sessionId) ?? 0;
|
|
4453
|
+
const lastAttempt = this.lastFlushAttemptTime.get(sessionId) ?? 0;
|
|
4454
|
+
const elapsed = Date.now() - lastAttempt;
|
|
4455
|
+
let delay2;
|
|
4456
|
+
if (retryCount > 0) {
|
|
4457
|
+
delay2 = Math.min(
|
|
4458
|
+
_SessionLogWriter.FLUSH_DEBOUNCE_MS * 2 ** retryCount,
|
|
4459
|
+
_SessionLogWriter.MAX_RETRY_DELAY_MS
|
|
4460
|
+
);
|
|
4461
|
+
} else if (elapsed >= _SessionLogWriter.FLUSH_MAX_INTERVAL_MS) {
|
|
4462
|
+
delay2 = 0;
|
|
4463
|
+
} else {
|
|
4464
|
+
delay2 = _SessionLogWriter.FLUSH_DEBOUNCE_MS;
|
|
4465
|
+
}
|
|
4466
|
+
const timeout = setTimeout(() => this.flush(sessionId), delay2);
|
|
4391
4467
|
this.flushTimeouts.set(sessionId, timeout);
|
|
4392
4468
|
}
|
|
4393
4469
|
};
|
|
@@ -10361,6 +10437,7 @@ var AgentServer = class {
|
|
|
10361
10437
|
});
|
|
10362
10438
|
const mode = this.getEffectiveMode(payload);
|
|
10363
10439
|
if (mode === "background") {
|
|
10440
|
+
await this.session.logWriter.flushAll();
|
|
10364
10441
|
await this.signalTaskComplete(payload, result.stopReason);
|
|
10365
10442
|
} else {
|
|
10366
10443
|
this.logger.info("Interactive mode - staying open for conversation");
|
|
@@ -10369,6 +10446,9 @@ var AgentServer = class {
|
|
|
10369
10446
|
this.logger.error("Failed to send initial task message", error);
|
|
10370
10447
|
const mode = this.getEffectiveMode(payload);
|
|
10371
10448
|
if (mode === "background") {
|
|
10449
|
+
if (this.session) {
|
|
10450
|
+
await this.session.logWriter.flushAll();
|
|
10451
|
+
}
|
|
10372
10452
|
await this.signalTaskComplete(payload, "error");
|
|
10373
10453
|
}
|
|
10374
10454
|
}
|
|
@@ -10383,10 +10463,24 @@ After completing the requested changes:
|
|
|
10383
10463
|
3. Push the branch to origin
|
|
10384
10464
|
4. Create a pull request using \`gh pr create\` with a descriptive title and body
|
|
10385
10465
|
|
|
10386
|
-
Important:
|
|
10466
|
+
Important:
|
|
10467
|
+
- Always create the PR. Do not ask for confirmation.
|
|
10468
|
+
- Do NOT add "Co-Authored-By" trailers to commit messages.
|
|
10469
|
+
- Do NOT add "Generated with [Claude Code]" or similar attribution lines to PR descriptions.
|
|
10387
10470
|
`;
|
|
10388
10471
|
}
|
|
10389
10472
|
async signalTaskComplete(payload, stopReason) {
|
|
10473
|
+
if (this.session?.payload.run_id === payload.run_id) {
|
|
10474
|
+
try {
|
|
10475
|
+
await this.session.logWriter.flush(payload.run_id);
|
|
10476
|
+
} catch (error) {
|
|
10477
|
+
this.logger.warn("Failed to flush session logs before completion", {
|
|
10478
|
+
taskId: payload.task_id,
|
|
10479
|
+
runId: payload.run_id,
|
|
10480
|
+
error
|
|
10481
|
+
});
|
|
10482
|
+
}
|
|
10483
|
+
}
|
|
10390
10484
|
const status = stopReason === "cancelled" ? "cancelled" : stopReason === "error" ? "failed" : "completed";
|
|
10391
10485
|
try {
|
|
10392
10486
|
await this.posthogAPI.updateTaskRun(payload.task_id, payload.run_id, {
|