@posthog/agent 2.1.150 → 2.1.156
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.d.ts +2 -0
- package/dist/adapters/claude/conversion/tool-use-to-acp.js +10 -3
- package/dist/adapters/claude/conversion/tool-use-to-acp.js.map +1 -1
- package/dist/agent.js +59 -6
- 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.d.ts +36 -0
- package/dist/server/agent-server.js +112 -12
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +138 -14
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +3 -3
- package/src/adapters/claude/conversion/sdk-to-acp.ts +66 -0
- package/src/adapters/claude/conversion/tool-use-to-acp.ts +33 -5
- package/src/server/agent-server.ts +61 -6
- package/src/server/bin.ts +29 -0
- package/src/server/schemas.test.ts +117 -0
- package/src/server/schemas.ts +16 -0
- package/src/server/types.ts +2 -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.1.
|
|
907
|
+
version: "2.1.156",
|
|
908
908
|
repository: "https://github.com/PostHog/twig",
|
|
909
909
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
910
910
|
exports: {
|
|
@@ -1810,8 +1810,14 @@ function toolInfoFromToolUse(toolUse, options) {
|
|
|
1810
1810
|
};
|
|
1811
1811
|
case "Edit": {
|
|
1812
1812
|
const path9 = input?.file_path ? String(input.file_path) : void 0;
|
|
1813
|
-
|
|
1814
|
-
|
|
1813
|
+
let oldText = input?.old_string ? String(input.old_string) : null;
|
|
1814
|
+
let newText = input?.new_string ? String(input.new_string) : "";
|
|
1815
|
+
if (path9 && options?.cachedFileContent && path9 in options.cachedFileContent) {
|
|
1816
|
+
const oldContent = options.cachedFileContent[path9];
|
|
1817
|
+
const newContent = input?.replace_all ? oldContent.replaceAll(oldText ?? "", newText) : oldContent.replace(oldText ?? "", newText);
|
|
1818
|
+
oldText = oldContent;
|
|
1819
|
+
newText = newContent;
|
|
1820
|
+
}
|
|
1815
1821
|
return {
|
|
1816
1822
|
title: path9 ? `Edit \`${path9}\`` : "Edit",
|
|
1817
1823
|
kind: "edit",
|
|
@@ -1831,7 +1837,8 @@ function toolInfoFromToolUse(toolUse, options) {
|
|
|
1831
1837
|
const filePath = input?.file_path ? String(input.file_path) : void 0;
|
|
1832
1838
|
const contentStr = input?.content ? String(input.content) : void 0;
|
|
1833
1839
|
if (filePath) {
|
|
1834
|
-
|
|
1840
|
+
const oldContent = options?.cachedFileContent && filePath in options.cachedFileContent ? options.cachedFileContent[filePath] : null;
|
|
1841
|
+
contentResult = toolContent().diff(filePath, oldContent, contentStr ?? "").build();
|
|
1835
1842
|
} else if (contentStr) {
|
|
1836
1843
|
contentResult = toolContent().text(contentStr).build();
|
|
1837
1844
|
}
|
|
@@ -2325,7 +2332,8 @@ function handleToolUseChunk(chunk, ctx) {
|
|
|
2325
2332
|
}
|
|
2326
2333
|
const toolInfo = toolInfoFromToolUse(chunk, {
|
|
2327
2334
|
supportsTerminalOutput: ctx.supportsTerminalOutput,
|
|
2328
|
-
toolUseId: chunk.id
|
|
2335
|
+
toolUseId: chunk.id,
|
|
2336
|
+
cachedFileContent: ctx.fileContentCache
|
|
2329
2337
|
});
|
|
2330
2338
|
const meta = {
|
|
2331
2339
|
...toolMeta(chunk.name, void 0, ctx.parentToolCallId)
|
|
@@ -2351,6 +2359,47 @@ function handleToolUseChunk(chunk, ctx) {
|
|
|
2351
2359
|
...toolInfo
|
|
2352
2360
|
};
|
|
2353
2361
|
}
|
|
2362
|
+
function extractTextFromContent(content) {
|
|
2363
|
+
if (Array.isArray(content)) {
|
|
2364
|
+
const parts = [];
|
|
2365
|
+
for (const item of content) {
|
|
2366
|
+
if (typeof item === "object" && item !== null && "text" in item && typeof item.text === "string") {
|
|
2367
|
+
parts.push(item.text);
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
return parts.length > 0 ? parts.join("") : null;
|
|
2371
|
+
}
|
|
2372
|
+
if (typeof content === "string") {
|
|
2373
|
+
return content;
|
|
2374
|
+
}
|
|
2375
|
+
return null;
|
|
2376
|
+
}
|
|
2377
|
+
function stripCatLineNumbers(text2) {
|
|
2378
|
+
return text2.replace(/^ *\d+[\t→]/gm, "");
|
|
2379
|
+
}
|
|
2380
|
+
function updateFileContentCache(toolUse, chunk, ctx) {
|
|
2381
|
+
const input = toolUse.input;
|
|
2382
|
+
const filePath = input?.file_path ? String(input.file_path) : void 0;
|
|
2383
|
+
if (!filePath) return;
|
|
2384
|
+
if (toolUse.name === "Read" && !input?.limit && !input?.offset) {
|
|
2385
|
+
const fileText = extractTextFromContent(chunk.content);
|
|
2386
|
+
if (fileText !== null) {
|
|
2387
|
+
ctx.fileContentCache[filePath] = stripCatLineNumbers(fileText);
|
|
2388
|
+
}
|
|
2389
|
+
} else if (toolUse.name === "Write") {
|
|
2390
|
+
const content = input?.content;
|
|
2391
|
+
if (typeof content === "string") {
|
|
2392
|
+
ctx.fileContentCache[filePath] = content;
|
|
2393
|
+
}
|
|
2394
|
+
} else if (toolUse.name === "Edit") {
|
|
2395
|
+
const oldString = input?.old_string;
|
|
2396
|
+
const newString = input?.new_string;
|
|
2397
|
+
if (typeof oldString === "string" && typeof newString === "string" && filePath in ctx.fileContentCache) {
|
|
2398
|
+
const current = ctx.fileContentCache[filePath];
|
|
2399
|
+
ctx.fileContentCache[filePath] = input?.replace_all ? current.replaceAll(oldString, newString) : current.replace(oldString, newString);
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2354
2403
|
function handleToolResultChunk(chunk, ctx) {
|
|
2355
2404
|
const toolUse = ctx.toolUseCache[chunk.tool_use_id];
|
|
2356
2405
|
if (!toolUse) {
|
|
@@ -2362,12 +2411,16 @@ function handleToolResultChunk(chunk, ctx) {
|
|
|
2362
2411
|
if (toolUse.name === "TodoWrite") {
|
|
2363
2412
|
return [];
|
|
2364
2413
|
}
|
|
2414
|
+
if (!chunk.is_error) {
|
|
2415
|
+
updateFileContentCache(toolUse, chunk, ctx);
|
|
2416
|
+
}
|
|
2365
2417
|
const { _meta: resultMeta, ...toolUpdate } = toolUpdateFromToolResult(
|
|
2366
2418
|
chunk,
|
|
2367
2419
|
toolUse,
|
|
2368
2420
|
{
|
|
2369
2421
|
supportsTerminalOutput: ctx.supportsTerminalOutput,
|
|
2370
|
-
toolUseId: chunk.tool_use_id
|
|
2422
|
+
toolUseId: chunk.tool_use_id,
|
|
2423
|
+
cachedFileContent: ctx.fileContentCache
|
|
2371
2424
|
}
|
|
2372
2425
|
);
|
|
2373
2426
|
const updates = [];
|
|
@@ -10894,6 +10947,17 @@ function validateJwt(token, publicKey) {
|
|
|
10894
10947
|
|
|
10895
10948
|
// src/server/schemas.ts
|
|
10896
10949
|
var import_zod3 = require("zod");
|
|
10950
|
+
var httpHeaderSchema = import_zod3.z.object({
|
|
10951
|
+
name: import_zod3.z.string(),
|
|
10952
|
+
value: import_zod3.z.string()
|
|
10953
|
+
});
|
|
10954
|
+
var remoteMcpServerSchema = import_zod3.z.object({
|
|
10955
|
+
type: import_zod3.z.enum(["http", "sse"]),
|
|
10956
|
+
name: import_zod3.z.string().min(1, "MCP server name is required"),
|
|
10957
|
+
url: import_zod3.z.string().url("MCP server url must be a valid URL"),
|
|
10958
|
+
headers: import_zod3.z.array(httpHeaderSchema).default([])
|
|
10959
|
+
});
|
|
10960
|
+
var mcpServersSchema = import_zod3.z.array(remoteMcpServerSchema);
|
|
10897
10961
|
var jsonRpcRequestSchema = import_zod3.z.object({
|
|
10898
10962
|
jsonrpc: import_zod3.z.literal("2.0"),
|
|
10899
10963
|
method: import_zod3.z.string(),
|
|
@@ -11018,6 +11082,24 @@ var AgentServer = class {
|
|
|
11018
11082
|
posthogAPI;
|
|
11019
11083
|
questionRelayedToSlack = false;
|
|
11020
11084
|
detectedPrUrl = null;
|
|
11085
|
+
emitConsoleLog = (level, _scope, message, data) => {
|
|
11086
|
+
if (!this.session) return;
|
|
11087
|
+
const formatted = data !== void 0 ? `${message} ${JSON.stringify(data)}` : message;
|
|
11088
|
+
const notification = {
|
|
11089
|
+
jsonrpc: "2.0",
|
|
11090
|
+
method: POSTHOG_NOTIFICATIONS.CONSOLE,
|
|
11091
|
+
params: { level, message: formatted }
|
|
11092
|
+
};
|
|
11093
|
+
this.broadcastEvent({
|
|
11094
|
+
type: "notification",
|
|
11095
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11096
|
+
notification
|
|
11097
|
+
});
|
|
11098
|
+
this.session.logWriter.appendRawLine(
|
|
11099
|
+
this.session.payload.run_id,
|
|
11100
|
+
JSON.stringify(notification)
|
|
11101
|
+
);
|
|
11102
|
+
};
|
|
11021
11103
|
constructor(config) {
|
|
11022
11104
|
this.config = config;
|
|
11023
11105
|
this.logger = new Logger({ debug: true, prefix: "[AgentServer]" });
|
|
@@ -11347,7 +11429,7 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
|
11347
11429
|
}
|
|
11348
11430
|
const sessionResponse = await clientConnection.newSession({
|
|
11349
11431
|
cwd: this.config.repositoryPath,
|
|
11350
|
-
mcpServers: [],
|
|
11432
|
+
mcpServers: this.config.mcpServers ?? [],
|
|
11351
11433
|
_meta: {
|
|
11352
11434
|
sessionId: payload.run_id,
|
|
11353
11435
|
taskRunId: payload.run_id,
|
|
@@ -11369,6 +11451,14 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
|
11369
11451
|
deviceInfo,
|
|
11370
11452
|
logWriter
|
|
11371
11453
|
};
|
|
11454
|
+
this.logger = new Logger({
|
|
11455
|
+
debug: true,
|
|
11456
|
+
prefix: "[AgentServer]",
|
|
11457
|
+
onLog: (level, scope, message, data) => {
|
|
11458
|
+
const _formatted = data !== void 0 ? `${message} ${JSON.stringify(data)}` : message;
|
|
11459
|
+
this.emitConsoleLog(level, scope, message, data);
|
|
11460
|
+
}
|
|
11461
|
+
});
|
|
11372
11462
|
this.logger.info("Session initialized successfully");
|
|
11373
11463
|
this.posthogAPI.updateTaskRun(payload.task_id, payload.run_id, {
|
|
11374
11464
|
status: "in_progress"
|
|
@@ -11751,15 +11841,25 @@ Important:
|
|
|
11751
11841
|
...snapshot,
|
|
11752
11842
|
device: this.session.deviceInfo
|
|
11753
11843
|
};
|
|
11844
|
+
const notification = {
|
|
11845
|
+
jsonrpc: "2.0",
|
|
11846
|
+
method: POSTHOG_NOTIFICATIONS.TREE_SNAPSHOT,
|
|
11847
|
+
params: snapshotWithDevice
|
|
11848
|
+
};
|
|
11754
11849
|
this.broadcastEvent({
|
|
11755
11850
|
type: "notification",
|
|
11756
11851
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11757
|
-
notification
|
|
11758
|
-
jsonrpc: "2.0",
|
|
11759
|
-
method: POSTHOG_NOTIFICATIONS.TREE_SNAPSHOT,
|
|
11760
|
-
params: snapshotWithDevice
|
|
11761
|
-
}
|
|
11852
|
+
notification
|
|
11762
11853
|
});
|
|
11854
|
+
const { archiveUrl: _, ...paramsWithoutArchive } = snapshotWithDevice;
|
|
11855
|
+
const logNotification = {
|
|
11856
|
+
...notification,
|
|
11857
|
+
params: paramsWithoutArchive
|
|
11858
|
+
};
|
|
11859
|
+
this.session.logWriter.appendRawLine(
|
|
11860
|
+
this.session.payload.run_id,
|
|
11861
|
+
JSON.stringify(logNotification)
|
|
11862
|
+
);
|
|
11763
11863
|
}
|
|
11764
11864
|
} catch (error) {
|
|
11765
11865
|
this.logger.error("Failed to capture tree state", error);
|
|
@@ -11795,7 +11895,10 @@ program.name("agent-server").description("PostHog cloud agent server - runs in s
|
|
|
11795
11895
|
"--mode <mode>",
|
|
11796
11896
|
"Execution mode: interactive or background",
|
|
11797
11897
|
"interactive"
|
|
11798
|
-
).requiredOption("--repositoryPath <path>", "Path to the repository").requiredOption("--taskId <id>", "Task ID").requiredOption("--runId <id>", "Task run ID").
|
|
11898
|
+
).requiredOption("--repositoryPath <path>", "Path to the repository").requiredOption("--taskId <id>", "Task ID").requiredOption("--runId <id>", "Task run ID").option(
|
|
11899
|
+
"--mcpServers <json>",
|
|
11900
|
+
"MCP servers config as JSON array (ACP McpServer[] format)"
|
|
11901
|
+
).action(async (options) => {
|
|
11799
11902
|
const envResult = envSchema.safeParse(process.env);
|
|
11800
11903
|
if (!envResult.success) {
|
|
11801
11904
|
const errors = envResult.error.issues.map((issue) => ` - ${issue.message}`).join("\n");
|
|
@@ -11805,6 +11908,26 @@ ${errors}`);
|
|
|
11805
11908
|
}
|
|
11806
11909
|
const env = envResult.data;
|
|
11807
11910
|
const mode = options.mode === "background" ? "background" : "interactive";
|
|
11911
|
+
let mcpServers;
|
|
11912
|
+
if (options.mcpServers) {
|
|
11913
|
+
let parsed;
|
|
11914
|
+
try {
|
|
11915
|
+
parsed = JSON.parse(options.mcpServers);
|
|
11916
|
+
} catch {
|
|
11917
|
+
program.error("--mcpServers must be valid JSON");
|
|
11918
|
+
return;
|
|
11919
|
+
}
|
|
11920
|
+
const result = mcpServersSchema.safeParse(parsed);
|
|
11921
|
+
if (!result.success) {
|
|
11922
|
+
const errors = result.error.issues.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`).join("\n");
|
|
11923
|
+
program.error(
|
|
11924
|
+
`--mcpServers validation failed (only remote http/sse servers are supported):
|
|
11925
|
+
${errors}`
|
|
11926
|
+
);
|
|
11927
|
+
return;
|
|
11928
|
+
}
|
|
11929
|
+
mcpServers = result.data;
|
|
11930
|
+
}
|
|
11808
11931
|
const server = new AgentServer({
|
|
11809
11932
|
port: parseInt(options.port, 10),
|
|
11810
11933
|
jwtPublicKey: env.JWT_PUBLIC_KEY,
|
|
@@ -11814,7 +11937,8 @@ ${errors}`);
|
|
|
11814
11937
|
projectId: env.POSTHOG_PROJECT_ID,
|
|
11815
11938
|
mode,
|
|
11816
11939
|
taskId: options.taskId,
|
|
11817
|
-
runId: options.runId
|
|
11940
|
+
runId: options.runId,
|
|
11941
|
+
mcpServers
|
|
11818
11942
|
});
|
|
11819
11943
|
process.on("SIGINT", async () => {
|
|
11820
11944
|
await server.stop();
|