@posthog/agent 2.3.43 → 2.3.53

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.
@@ -904,7 +904,7 @@ var import_hono = require("hono");
904
904
  // package.json
905
905
  var package_default = {
906
906
  name: "@posthog/agent",
907
- version: "2.3.43",
907
+ version: "2.3.53",
908
908
  repository: "https://github.com/PostHog/code",
909
909
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
910
910
  exports: {
@@ -4159,6 +4159,10 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
4159
4159
  (m) => m.contextWindow
4160
4160
  );
4161
4161
  const contextWindowSize = contextWindows.length > 0 ? Math.min(...contextWindows) : getDefaultContextWindow(this.session.modelId ?? "");
4162
+ this.session.contextSize = contextWindowSize;
4163
+ if (lastAssistantTotalUsage !== null) {
4164
+ this.session.contextUsed = lastAssistantTotalUsage;
4165
+ }
4162
4166
  if (lastAssistantTotalUsage !== null) {
4163
4167
  await this.client.sessionUpdate({
4164
4168
  sessionId: params.sessionId,
@@ -11104,7 +11108,7 @@ var SessionLogWriter = class _SessionLogWriter {
11104
11108
  taskId: context.taskId,
11105
11109
  runId: context.runId
11106
11110
  });
11107
- this.sessions.set(sessionId, { context });
11111
+ this.sessions.set(sessionId, { context, currentTurnMessages: [] });
11108
11112
  this.lastFlushAttemptTime.set(sessionId, Date.now());
11109
11113
  if (this.localCachePath) {
11110
11114
  const sessionDir = import_node_path7.default.join(
@@ -11151,6 +11155,7 @@ var SessionLogWriter = class _SessionLogWriter {
11151
11155
  const nonChunkAgentText = this.extractAgentMessageText(message);
11152
11156
  if (nonChunkAgentText) {
11153
11157
  session.lastAgentMessage = nonChunkAgentText;
11158
+ session.currentTurnMessages.push(nonChunkAgentText);
11154
11159
  }
11155
11160
  const entry = {
11156
11161
  type: "notification",
@@ -11247,6 +11252,7 @@ var SessionLogWriter = class _SessionLogWriter {
11247
11252
  const { text: text2, firstTimestamp } = session.chunkBuffer;
11248
11253
  session.chunkBuffer = void 0;
11249
11254
  session.lastAgentMessage = text2;
11255
+ session.currentTurnMessages.push(text2);
11250
11256
  const entry = {
11251
11257
  type: "notification",
11252
11258
  timestamp: firstTimestamp,
@@ -11272,6 +11278,17 @@ var SessionLogWriter = class _SessionLogWriter {
11272
11278
  getLastAgentMessage(sessionId) {
11273
11279
  return this.sessions.get(sessionId)?.lastAgentMessage;
11274
11280
  }
11281
+ getFullAgentResponse(sessionId) {
11282
+ const session = this.sessions.get(sessionId);
11283
+ if (!session || session.currentTurnMessages.length === 0) return void 0;
11284
+ return session.currentTurnMessages.join("\n\n");
11285
+ }
11286
+ resetTurnMessages(sessionId) {
11287
+ const session = this.sessions.get(sessionId);
11288
+ if (session) {
11289
+ session.currentTurnMessages = [];
11290
+ }
11291
+ }
11275
11292
  extractAgentMessageText(message) {
11276
11293
  if (message.method !== "session/update") {
11277
11294
  return null;
@@ -11587,6 +11604,12 @@ var AgentServer = class _AgentServer {
11587
11604
  questionRelayedToSlack = false;
11588
11605
  detectedPrUrl = null;
11589
11606
  resumeState = null;
11607
+ // Guards against concurrent session initialization. autoInitializeSession() and
11608
+ // the GET /events SSE handler can both call initializeSession() — the SSE connection
11609
+ // often arrives while newSession() is still awaited (this.session is still null),
11610
+ // causing a second session to be created and duplicate Slack messages to be sent.
11611
+ initializationPromise = null;
11612
+ pendingEvents = [];
11590
11613
  emitConsoleLog = (level, _scope, message, data) => {
11591
11614
  if (!this.session) return;
11592
11615
  const formatted = data !== void 0 ? `${message} ${JSON.stringify(data)}` : message;
@@ -11666,6 +11689,7 @@ var AgentServer = class _AgentServer {
11666
11689
  await this.initializeSession(payload, sseController);
11667
11690
  } else {
11668
11691
  this.session.sseController = sseController;
11692
+ this.replayPendingEvents();
11669
11693
  }
11670
11694
  this.sendSseEvent(sseController, {
11671
11695
  type: "connected",
@@ -11845,6 +11869,7 @@ var AgentServer = class _AgentServer {
11845
11869
  this.logger.info(
11846
11870
  `Processing user message (detectedPrUrl=${this.detectedPrUrl ?? "none"}): ${content.substring(0, 100)}...`
11847
11871
  );
11872
+ this.session.logWriter.resetTurnMessages(this.session.payload.run_id);
11848
11873
  const result = await this.session.clientConnection.prompt({
11849
11874
  sessionId: this.session.acpSessionId,
11850
11875
  prompt: [{ type: "text", text: content }],
@@ -11860,7 +11885,24 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
11860
11885
  }
11861
11886
  });
11862
11887
  this.broadcastTurnComplete(result.stopReason);
11863
- return { stopReason: result.stopReason };
11888
+ if (result.stopReason === "end_turn") {
11889
+ this.relayAgentResponse(this.session.payload).catch(
11890
+ (err) => this.logger.warn("Failed to relay follow-up response", err)
11891
+ );
11892
+ }
11893
+ let assistantMessage;
11894
+ try {
11895
+ await this.session.logWriter.flush(this.session.payload.run_id);
11896
+ assistantMessage = this.session.logWriter.getFullAgentResponse(
11897
+ this.session.payload.run_id
11898
+ );
11899
+ } catch {
11900
+ this.logger.warn("Failed to extract assistant message from logs");
11901
+ }
11902
+ return {
11903
+ stopReason: result.stopReason,
11904
+ ...assistantMessage && { assistant_message: assistantMessage }
11905
+ };
11864
11906
  }
11865
11907
  case POSTHOG_NOTIFICATIONS.CANCEL:
11866
11908
  case "cancel": {
@@ -11883,6 +11925,28 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
11883
11925
  }
11884
11926
  }
11885
11927
  async initializeSession(payload, sseController) {
11928
+ if (this.initializationPromise) {
11929
+ this.logger.info("Waiting for in-progress initialization", {
11930
+ runId: payload.run_id
11931
+ });
11932
+ await this.initializationPromise;
11933
+ if (this.session && sseController) {
11934
+ this.session.sseController = sseController;
11935
+ this.replayPendingEvents();
11936
+ }
11937
+ return;
11938
+ }
11939
+ this.initializationPromise = this._doInitializeSession(
11940
+ payload,
11941
+ sseController
11942
+ );
11943
+ try {
11944
+ await this.initializationPromise;
11945
+ } finally {
11946
+ this.initializationPromise = null;
11947
+ }
11948
+ }
11949
+ async _doInitializeSession(payload, sseController) {
11886
11950
  if (this.session) {
11887
11951
  await this.cleanupSession();
11888
11952
  }
@@ -12069,6 +12133,7 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
12069
12133
  descriptionLength: initialPrompt.length,
12070
12134
  usedInitialPromptOverride: !!initialPromptOverride
12071
12135
  });
12136
+ this.session.logWriter.resetTurnMessages(payload.run_id);
12072
12137
  const result = await this.session.clientConnection.prompt({
12073
12138
  sessionId: this.session.acpSessionId,
12074
12139
  prompt: [{ type: "text", text: initialPrompt }]
@@ -12095,7 +12160,7 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
12095
12160
  this.resumeState.conversation
12096
12161
  );
12097
12162
  const pendingUserMessage = this.getPendingUserMessage(taskRun);
12098
- const sandboxContext = this.resumeState.snapshotApplied ? `The sandbox environment (all files, packages, and code changes) has been fully restored from a snapshot.` : `The sandbox could not be restored from a snapshot (it may have expired). You are starting with a fresh environment but have the full conversation history below.`;
12163
+ const sandboxContext = this.resumeState.snapshotApplied ? `The workspace environment (all files, packages, and code changes) has been fully restored from where you left off.` : `The workspace files from the previous session were not restored (the file snapshot may have expired), so you are starting with a fresh environment. Your conversation history is fully preserved below.`;
12099
12164
  let resumePrompt;
12100
12165
  if (pendingUserMessage) {
12101
12166
  resumePrompt = `You are resuming a previous conversation. ${sandboxContext}
@@ -12126,6 +12191,7 @@ Continue from where you left off. The user is waiting for your response.`;
12126
12191
  snapshotApplied: this.resumeState.snapshotApplied
12127
12192
  });
12128
12193
  this.resumeState = null;
12194
+ this.session.logWriter.resetTurnMessages(payload.run_id);
12129
12195
  const result = await this.session.clientConnection.prompt({
12130
12196
  sessionId: this.session.acpSessionId,
12131
12197
  prompt: [{ type: "text", text: resumePrompt }]
@@ -12134,6 +12200,9 @@ Continue from where you left off. The user is waiting for your response.`;
12134
12200
  stopReason: result.stopReason
12135
12201
  });
12136
12202
  this.broadcastTurnComplete(result.stopReason);
12203
+ if (result.stopReason === "end_turn") {
12204
+ await this.relayAgentResponse(payload);
12205
+ }
12137
12206
  } catch (error) {
12138
12207
  this.logger.error("Failed to send resume message", error);
12139
12208
  if (this.session) {
@@ -12232,6 +12301,26 @@ Important:
12232
12301
  - Do NOT create a new branch or a new pull request.
12233
12302
  - Do NOT add "Co-Authored-By" trailers to commit messages.
12234
12303
  - Do NOT add "Generated with [Claude Code]" or similar attribution lines to PR descriptions.
12304
+ `;
12305
+ }
12306
+ if (!this.config.repositoryPath) {
12307
+ return `
12308
+ # Cloud Task Execution \u2014 No Repository Mode
12309
+
12310
+ You are a helpful assistant with access to PostHog via MCP tools. You can help with both code tasks and data/analytics questions.
12311
+
12312
+ When the user asks about analytics, data, metrics, events, funnels, dashboards, feature flags, experiments, or anything PostHog-related:
12313
+ - Use your PostHog MCP tools to query data, search insights, and provide real answers
12314
+ - Do NOT tell the user to check an external analytics platform \u2014 you ARE the analytics platform
12315
+ - Use tools like insight-query, query-run, event-definitions-list, and others to answer questions directly
12316
+
12317
+ When the user asks for code changes or software engineering tasks:
12318
+ - Let them know you can help but don't have a repository connected for this session
12319
+ - Offer to write code snippets, scripts, or provide guidance
12320
+
12321
+ Important:
12322
+ - Do NOT create branches, commits, or pull requests in this mode.
12323
+ - Prefer using MCP tools to answer questions with real data over giving generic advice.
12235
12324
  `;
12236
12325
  }
12237
12326
  return `
@@ -12334,6 +12423,9 @@ Important:
12334
12423
  }
12335
12424
  };
12336
12425
  },
12426
+ extNotification: async (method, params) => {
12427
+ this.logger.debug("Extension notification", { method, params });
12428
+ },
12337
12429
  sessionUpdate: async (params) => {
12338
12430
  if (params.update?.sessionUpdate === "tool_call_update") {
12339
12431
  const meta = params.update?._meta?.claudeCode;
@@ -12366,7 +12458,7 @@ Important:
12366
12458
  error
12367
12459
  });
12368
12460
  }
12369
- const message = this.session.logWriter.getLastAgentMessage(payload.run_id);
12461
+ const message = this.session.logWriter.getFullAgentResponse(payload.run_id);
12370
12462
  if (!message) {
12371
12463
  this.logger.warn("No agent message found for Slack relay", {
12372
12464
  taskId: payload.task_id,
@@ -12519,6 +12611,7 @@ Important:
12519
12611
  if (this.session.sseController) {
12520
12612
  this.session.sseController.close();
12521
12613
  }
12614
+ this.pendingEvents = [];
12522
12615
  this.session = null;
12523
12616
  }
12524
12617
  async captureTreeState() {
@@ -12567,6 +12660,16 @@ Important:
12567
12660
  broadcastEvent(event) {
12568
12661
  if (this.session?.sseController) {
12569
12662
  this.sendSseEvent(this.session.sseController, event);
12663
+ } else if (this.session) {
12664
+ this.pendingEvents.push(event);
12665
+ }
12666
+ }
12667
+ replayPendingEvents() {
12668
+ if (!this.session?.sseController || this.pendingEvents.length === 0) return;
12669
+ const events = this.pendingEvents;
12670
+ this.pendingEvents = [];
12671
+ for (const event of events) {
12672
+ this.sendSseEvent(this.session.sseController, event);
12570
12673
  }
12571
12674
  }
12572
12675
  sendSseEvent(controller, data) {