@posthog/agent 2.3.46 → 2.3.62
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/adapters/claude/conversion/tool-use-to-acp.js.map +1 -1
- package/dist/adapters/claude/tools.js.map +1 -1
- package/dist/agent.js +40 -7
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.d.ts +4 -0
- package/dist/server/agent-server.js +129 -10
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +129 -10
- package/dist/server/bin.cjs.map +1 -1
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/adapters/claude/claude-agent.ts +12 -2
- package/src/adapters/claude/conversion/sdk-to-acp.ts +22 -1
- package/src/adapters/claude/mcp/tool-metadata.ts +10 -0
- package/src/index.ts +5 -1
- package/src/server/agent-server.ts +119 -4
- package/src/server/question-relay.test.ts +17 -3
- package/src/session-log-writer.ts +17 -1
- package/src/types.ts +1 -0
package/dist/server/bin.cjs
CHANGED
|
@@ -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.
|
|
907
|
+
version: "2.3.62",
|
|
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: {
|
|
@@ -1729,6 +1729,14 @@ function isMcpToolReadOnly(toolName) {
|
|
|
1729
1729
|
const metadata = mcpToolMetadataCache.get(toolName);
|
|
1730
1730
|
return metadata?.readOnly === true;
|
|
1731
1731
|
}
|
|
1732
|
+
function getConnectedMcpServerNames() {
|
|
1733
|
+
const names = /* @__PURE__ */ new Set();
|
|
1734
|
+
for (const key of mcpToolMetadataCache.keys()) {
|
|
1735
|
+
const parts = key.split("__");
|
|
1736
|
+
if (parts.length >= 3) names.add(parts[1]);
|
|
1737
|
+
}
|
|
1738
|
+
return [...names];
|
|
1739
|
+
}
|
|
1732
1740
|
|
|
1733
1741
|
// src/adapters/claude/conversion/tool-use-to-acp.ts
|
|
1734
1742
|
var SYSTEM_REMINDER_REGEX = /\s*<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
@@ -2485,7 +2493,10 @@ function handleToolResultChunk(chunk, ctx) {
|
|
|
2485
2493
|
toolCallId: chunk.tool_use_id,
|
|
2486
2494
|
sessionUpdate: "tool_call_update",
|
|
2487
2495
|
status: chunk.is_error ? "failed" : "completed",
|
|
2488
|
-
rawOutput: chunk.
|
|
2496
|
+
rawOutput: ctx.mcpToolUseResult ? { ...ctx.mcpToolUseResult, isError: chunk.is_error ?? false } : {
|
|
2497
|
+
content: Array.isArray(chunk.content) ? chunk.content : typeof chunk.content === "string" ? [{ type: "text", text: chunk.content }] : [],
|
|
2498
|
+
isError: chunk.is_error ?? false
|
|
2499
|
+
},
|
|
2489
2500
|
...toolUpdate
|
|
2490
2501
|
});
|
|
2491
2502
|
return updates;
|
|
@@ -2539,7 +2550,7 @@ function processContentChunk(chunk, role, ctx) {
|
|
|
2539
2550
|
return [];
|
|
2540
2551
|
}
|
|
2541
2552
|
}
|
|
2542
|
-
function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentCache, client, logger, parentToolCallId, registerHooks, supportsTerminalOutput, cwd) {
|
|
2553
|
+
function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentCache, client, logger, parentToolCallId, registerHooks, supportsTerminalOutput, cwd, mcpToolUseResult) {
|
|
2543
2554
|
if (typeof content === "string") {
|
|
2544
2555
|
const update = {
|
|
2545
2556
|
sessionUpdate: messageUpdateType(role),
|
|
@@ -2563,7 +2574,8 @@ function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentC
|
|
|
2563
2574
|
parentToolCallId,
|
|
2564
2575
|
registerHooks,
|
|
2565
2576
|
supportsTerminalOutput,
|
|
2566
|
-
cwd
|
|
2577
|
+
cwd,
|
|
2578
|
+
mcpToolUseResult
|
|
2567
2579
|
};
|
|
2568
2580
|
const output = [];
|
|
2569
2581
|
for (const chunk of content) {
|
|
@@ -2822,6 +2834,7 @@ async function handleUserAssistantMessage(message, context) {
|
|
|
2822
2834
|
const content = message.message.content;
|
|
2823
2835
|
const contentToProcess = message.type === "assistant" ? filterMessageContent(content) : content;
|
|
2824
2836
|
const parentToolCallId = "parent_tool_use_id" in message ? message.parent_tool_use_id ?? void 0 : void 0;
|
|
2837
|
+
const mcpToolUseResult = message.type === "user" && message.tool_use_result != null ? message.tool_use_result : void 0;
|
|
2825
2838
|
for (const notification of toAcpNotifications(
|
|
2826
2839
|
contentToProcess,
|
|
2827
2840
|
message.message.role,
|
|
@@ -2833,7 +2846,8 @@ async function handleUserAssistantMessage(message, context) {
|
|
|
2833
2846
|
parentToolCallId,
|
|
2834
2847
|
context.registerHooks,
|
|
2835
2848
|
context.supportsTerminalOutput,
|
|
2836
|
-
session.cwd
|
|
2849
|
+
session.cwd,
|
|
2850
|
+
mcpToolUseResult
|
|
2837
2851
|
)) {
|
|
2838
2852
|
await client.sessionUpdate(notification);
|
|
2839
2853
|
session.notificationHistory.push(notification);
|
|
@@ -4673,11 +4687,17 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
4673
4687
|
* Both populate caches used later — neither is needed to return configOptions.
|
|
4674
4688
|
*/
|
|
4675
4689
|
deferBackgroundFetches(q) {
|
|
4690
|
+
this.logger.info("Starting background fetches (commands + MCP metadata)");
|
|
4676
4691
|
Promise.all([
|
|
4677
4692
|
new Promise((resolve4) => setTimeout(resolve4, 10)).then(
|
|
4678
4693
|
() => this.sendAvailableCommandsUpdate()
|
|
4679
4694
|
),
|
|
4680
|
-
fetchMcpToolMetadata(q, this.logger)
|
|
4695
|
+
fetchMcpToolMetadata(q, this.logger).then(() => {
|
|
4696
|
+
const serverNames = getConnectedMcpServerNames();
|
|
4697
|
+
if (serverNames.length > 0) {
|
|
4698
|
+
this.options?.onMcpServersReady?.(serverNames);
|
|
4699
|
+
}
|
|
4700
|
+
})
|
|
4681
4701
|
]).catch(
|
|
4682
4702
|
(err) => this.logger.error("Background fetch failed", { error: err })
|
|
4683
4703
|
);
|
|
@@ -11108,7 +11128,7 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
11108
11128
|
taskId: context.taskId,
|
|
11109
11129
|
runId: context.runId
|
|
11110
11130
|
});
|
|
11111
|
-
this.sessions.set(sessionId, { context });
|
|
11131
|
+
this.sessions.set(sessionId, { context, currentTurnMessages: [] });
|
|
11112
11132
|
this.lastFlushAttemptTime.set(sessionId, Date.now());
|
|
11113
11133
|
if (this.localCachePath) {
|
|
11114
11134
|
const sessionDir = import_node_path7.default.join(
|
|
@@ -11155,6 +11175,7 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
11155
11175
|
const nonChunkAgentText = this.extractAgentMessageText(message);
|
|
11156
11176
|
if (nonChunkAgentText) {
|
|
11157
11177
|
session.lastAgentMessage = nonChunkAgentText;
|
|
11178
|
+
session.currentTurnMessages.push(nonChunkAgentText);
|
|
11158
11179
|
}
|
|
11159
11180
|
const entry = {
|
|
11160
11181
|
type: "notification",
|
|
@@ -11251,6 +11272,7 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
11251
11272
|
const { text: text2, firstTimestamp } = session.chunkBuffer;
|
|
11252
11273
|
session.chunkBuffer = void 0;
|
|
11253
11274
|
session.lastAgentMessage = text2;
|
|
11275
|
+
session.currentTurnMessages.push(text2);
|
|
11254
11276
|
const entry = {
|
|
11255
11277
|
type: "notification",
|
|
11256
11278
|
timestamp: firstTimestamp,
|
|
@@ -11276,6 +11298,17 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
11276
11298
|
getLastAgentMessage(sessionId) {
|
|
11277
11299
|
return this.sessions.get(sessionId)?.lastAgentMessage;
|
|
11278
11300
|
}
|
|
11301
|
+
getFullAgentResponse(sessionId) {
|
|
11302
|
+
const session = this.sessions.get(sessionId);
|
|
11303
|
+
if (!session || session.currentTurnMessages.length === 0) return void 0;
|
|
11304
|
+
return session.currentTurnMessages.join("\n\n");
|
|
11305
|
+
}
|
|
11306
|
+
resetTurnMessages(sessionId) {
|
|
11307
|
+
const session = this.sessions.get(sessionId);
|
|
11308
|
+
if (session) {
|
|
11309
|
+
session.currentTurnMessages = [];
|
|
11310
|
+
}
|
|
11311
|
+
}
|
|
11279
11312
|
extractAgentMessageText(message) {
|
|
11280
11313
|
if (message.method !== "session/update") {
|
|
11281
11314
|
return null;
|
|
@@ -11591,6 +11624,12 @@ var AgentServer = class _AgentServer {
|
|
|
11591
11624
|
questionRelayedToSlack = false;
|
|
11592
11625
|
detectedPrUrl = null;
|
|
11593
11626
|
resumeState = null;
|
|
11627
|
+
// Guards against concurrent session initialization. autoInitializeSession() and
|
|
11628
|
+
// the GET /events SSE handler can both call initializeSession() — the SSE connection
|
|
11629
|
+
// often arrives while newSession() is still awaited (this.session is still null),
|
|
11630
|
+
// causing a second session to be created and duplicate Slack messages to be sent.
|
|
11631
|
+
initializationPromise = null;
|
|
11632
|
+
pendingEvents = [];
|
|
11594
11633
|
emitConsoleLog = (level, _scope, message, data) => {
|
|
11595
11634
|
if (!this.session) return;
|
|
11596
11635
|
const formatted = data !== void 0 ? `${message} ${JSON.stringify(data)}` : message;
|
|
@@ -11670,6 +11709,7 @@ var AgentServer = class _AgentServer {
|
|
|
11670
11709
|
await this.initializeSession(payload, sseController);
|
|
11671
11710
|
} else {
|
|
11672
11711
|
this.session.sseController = sseController;
|
|
11712
|
+
this.replayPendingEvents();
|
|
11673
11713
|
}
|
|
11674
11714
|
this.sendSseEvent(sseController, {
|
|
11675
11715
|
type: "connected",
|
|
@@ -11849,6 +11889,7 @@ var AgentServer = class _AgentServer {
|
|
|
11849
11889
|
this.logger.info(
|
|
11850
11890
|
`Processing user message (detectedPrUrl=${this.detectedPrUrl ?? "none"}): ${content.substring(0, 100)}...`
|
|
11851
11891
|
);
|
|
11892
|
+
this.session.logWriter.resetTurnMessages(this.session.payload.run_id);
|
|
11852
11893
|
const result = await this.session.clientConnection.prompt({
|
|
11853
11894
|
sessionId: this.session.acpSessionId,
|
|
11854
11895
|
prompt: [{ type: "text", text: content }],
|
|
@@ -11864,7 +11905,24 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
|
11864
11905
|
}
|
|
11865
11906
|
});
|
|
11866
11907
|
this.broadcastTurnComplete(result.stopReason);
|
|
11867
|
-
|
|
11908
|
+
if (result.stopReason === "end_turn") {
|
|
11909
|
+
this.relayAgentResponse(this.session.payload).catch(
|
|
11910
|
+
(err) => this.logger.warn("Failed to relay follow-up response", err)
|
|
11911
|
+
);
|
|
11912
|
+
}
|
|
11913
|
+
let assistantMessage;
|
|
11914
|
+
try {
|
|
11915
|
+
await this.session.logWriter.flush(this.session.payload.run_id);
|
|
11916
|
+
assistantMessage = this.session.logWriter.getFullAgentResponse(
|
|
11917
|
+
this.session.payload.run_id
|
|
11918
|
+
);
|
|
11919
|
+
} catch {
|
|
11920
|
+
this.logger.warn("Failed to extract assistant message from logs");
|
|
11921
|
+
}
|
|
11922
|
+
return {
|
|
11923
|
+
stopReason: result.stopReason,
|
|
11924
|
+
...assistantMessage && { assistant_message: assistantMessage }
|
|
11925
|
+
};
|
|
11868
11926
|
}
|
|
11869
11927
|
case POSTHOG_NOTIFICATIONS.CANCEL:
|
|
11870
11928
|
case "cancel": {
|
|
@@ -11887,6 +11945,28 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
|
11887
11945
|
}
|
|
11888
11946
|
}
|
|
11889
11947
|
async initializeSession(payload, sseController) {
|
|
11948
|
+
if (this.initializationPromise) {
|
|
11949
|
+
this.logger.info("Waiting for in-progress initialization", {
|
|
11950
|
+
runId: payload.run_id
|
|
11951
|
+
});
|
|
11952
|
+
await this.initializationPromise;
|
|
11953
|
+
if (this.session && sseController) {
|
|
11954
|
+
this.session.sseController = sseController;
|
|
11955
|
+
this.replayPendingEvents();
|
|
11956
|
+
}
|
|
11957
|
+
return;
|
|
11958
|
+
}
|
|
11959
|
+
this.initializationPromise = this._doInitializeSession(
|
|
11960
|
+
payload,
|
|
11961
|
+
sseController
|
|
11962
|
+
);
|
|
11963
|
+
try {
|
|
11964
|
+
await this.initializationPromise;
|
|
11965
|
+
} finally {
|
|
11966
|
+
this.initializationPromise = null;
|
|
11967
|
+
}
|
|
11968
|
+
}
|
|
11969
|
+
async _doInitializeSession(payload, sseController) {
|
|
11890
11970
|
if (this.session) {
|
|
11891
11971
|
await this.cleanupSession();
|
|
11892
11972
|
}
|
|
@@ -12073,6 +12153,7 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
|
12073
12153
|
descriptionLength: initialPrompt.length,
|
|
12074
12154
|
usedInitialPromptOverride: !!initialPromptOverride
|
|
12075
12155
|
});
|
|
12156
|
+
this.session.logWriter.resetTurnMessages(payload.run_id);
|
|
12076
12157
|
const result = await this.session.clientConnection.prompt({
|
|
12077
12158
|
sessionId: this.session.acpSessionId,
|
|
12078
12159
|
prompt: [{ type: "text", text: initialPrompt }]
|
|
@@ -12099,7 +12180,7 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
|
12099
12180
|
this.resumeState.conversation
|
|
12100
12181
|
);
|
|
12101
12182
|
const pendingUserMessage = this.getPendingUserMessage(taskRun);
|
|
12102
|
-
const sandboxContext = this.resumeState.snapshotApplied ? `The
|
|
12183
|
+
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.`;
|
|
12103
12184
|
let resumePrompt;
|
|
12104
12185
|
if (pendingUserMessage) {
|
|
12105
12186
|
resumePrompt = `You are resuming a previous conversation. ${sandboxContext}
|
|
@@ -12130,6 +12211,7 @@ Continue from where you left off. The user is waiting for your response.`;
|
|
|
12130
12211
|
snapshotApplied: this.resumeState.snapshotApplied
|
|
12131
12212
|
});
|
|
12132
12213
|
this.resumeState = null;
|
|
12214
|
+
this.session.logWriter.resetTurnMessages(payload.run_id);
|
|
12133
12215
|
const result = await this.session.clientConnection.prompt({
|
|
12134
12216
|
sessionId: this.session.acpSessionId,
|
|
12135
12217
|
prompt: [{ type: "text", text: resumePrompt }]
|
|
@@ -12138,6 +12220,9 @@ Continue from where you left off. The user is waiting for your response.`;
|
|
|
12138
12220
|
stopReason: result.stopReason
|
|
12139
12221
|
});
|
|
12140
12222
|
this.broadcastTurnComplete(result.stopReason);
|
|
12223
|
+
if (result.stopReason === "end_turn") {
|
|
12224
|
+
await this.relayAgentResponse(payload);
|
|
12225
|
+
}
|
|
12141
12226
|
} catch (error) {
|
|
12142
12227
|
this.logger.error("Failed to send resume message", error);
|
|
12143
12228
|
if (this.session) {
|
|
@@ -12236,6 +12321,26 @@ Important:
|
|
|
12236
12321
|
- Do NOT create a new branch or a new pull request.
|
|
12237
12322
|
- Do NOT add "Co-Authored-By" trailers to commit messages.
|
|
12238
12323
|
- Do NOT add "Generated with [Claude Code]" or similar attribution lines to PR descriptions.
|
|
12324
|
+
`;
|
|
12325
|
+
}
|
|
12326
|
+
if (!this.config.repositoryPath) {
|
|
12327
|
+
return `
|
|
12328
|
+
# Cloud Task Execution \u2014 No Repository Mode
|
|
12329
|
+
|
|
12330
|
+
You are a helpful assistant with access to PostHog via MCP tools. You can help with both code tasks and data/analytics questions.
|
|
12331
|
+
|
|
12332
|
+
When the user asks about analytics, data, metrics, events, funnels, dashboards, feature flags, experiments, or anything PostHog-related:
|
|
12333
|
+
- Use your PostHog MCP tools to query data, search insights, and provide real answers
|
|
12334
|
+
- Do NOT tell the user to check an external analytics platform \u2014 you ARE the analytics platform
|
|
12335
|
+
- Use tools like insight-query, query-run, event-definitions-list, and others to answer questions directly
|
|
12336
|
+
|
|
12337
|
+
When the user asks for code changes or software engineering tasks:
|
|
12338
|
+
- Let them know you can help but don't have a repository connected for this session
|
|
12339
|
+
- Offer to write code snippets, scripts, or provide guidance
|
|
12340
|
+
|
|
12341
|
+
Important:
|
|
12342
|
+
- Do NOT create branches, commits, or pull requests in this mode.
|
|
12343
|
+
- Prefer using MCP tools to answer questions with real data over giving generic advice.
|
|
12239
12344
|
`;
|
|
12240
12345
|
}
|
|
12241
12346
|
return `
|
|
@@ -12338,6 +12443,9 @@ Important:
|
|
|
12338
12443
|
}
|
|
12339
12444
|
};
|
|
12340
12445
|
},
|
|
12446
|
+
extNotification: async (method, params) => {
|
|
12447
|
+
this.logger.debug("Extension notification", { method, params });
|
|
12448
|
+
},
|
|
12341
12449
|
sessionUpdate: async (params) => {
|
|
12342
12450
|
if (params.update?.sessionUpdate === "tool_call_update") {
|
|
12343
12451
|
const meta = params.update?._meta?.claudeCode;
|
|
@@ -12370,7 +12478,7 @@ Important:
|
|
|
12370
12478
|
error
|
|
12371
12479
|
});
|
|
12372
12480
|
}
|
|
12373
|
-
const message = this.session.logWriter.
|
|
12481
|
+
const message = this.session.logWriter.getFullAgentResponse(payload.run_id);
|
|
12374
12482
|
if (!message) {
|
|
12375
12483
|
this.logger.warn("No agent message found for Slack relay", {
|
|
12376
12484
|
taskId: payload.task_id,
|
|
@@ -12523,6 +12631,7 @@ Important:
|
|
|
12523
12631
|
if (this.session.sseController) {
|
|
12524
12632
|
this.session.sseController.close();
|
|
12525
12633
|
}
|
|
12634
|
+
this.pendingEvents = [];
|
|
12526
12635
|
this.session = null;
|
|
12527
12636
|
}
|
|
12528
12637
|
async captureTreeState() {
|
|
@@ -12571,6 +12680,16 @@ Important:
|
|
|
12571
12680
|
broadcastEvent(event) {
|
|
12572
12681
|
if (this.session?.sseController) {
|
|
12573
12682
|
this.sendSseEvent(this.session.sseController, event);
|
|
12683
|
+
} else if (this.session) {
|
|
12684
|
+
this.pendingEvents.push(event);
|
|
12685
|
+
}
|
|
12686
|
+
}
|
|
12687
|
+
replayPendingEvents() {
|
|
12688
|
+
if (!this.session?.sseController || this.pendingEvents.length === 0) return;
|
|
12689
|
+
const events = this.pendingEvents;
|
|
12690
|
+
this.pendingEvents = [];
|
|
12691
|
+
for (const event of events) {
|
|
12692
|
+
this.sendSseEvent(this.session.sseController, event);
|
|
12574
12693
|
}
|
|
12575
12694
|
}
|
|
12576
12695
|
sendSseEvent(controller, data) {
|