@posthog/agent 2.1.107 → 2.1.112
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/permissions/permission-options.js +0 -4
- package/dist/adapters/claude/permissions/permission-options.js.map +1 -1
- package/dist/adapters/claude/tools.js +0 -2
- package/dist/adapters/claude/tools.js.map +1 -1
- package/dist/agent.js +57 -65
- package/dist/agent.js.map +1 -1
- package/dist/claude-cli/cli.js +1764 -1746
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/posthog-api.js +2 -3
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +60 -69
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +60 -69
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +2 -3
- package/src/adapters/claude/claude-agent.ts +8 -12
- package/src/adapters/claude/mcp/tool-metadata.ts +54 -72
- package/src/adapters/claude/session/options.ts +2 -1
- package/src/agent.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/agent",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.112",
|
|
4
4
|
"repository": "https://github.com/PostHog/twig",
|
|
5
5
|
"description": "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
6
6
|
"exports": {
|
|
@@ -76,10 +76,9 @@
|
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
78
|
"@agentclientprotocol/sdk": "^0.14.0",
|
|
79
|
-
"@anthropic-ai/claude-agent-sdk": "0.2.
|
|
79
|
+
"@anthropic-ai/claude-agent-sdk": "0.2.59",
|
|
80
80
|
"@anthropic-ai/sdk": "^0.71.0",
|
|
81
81
|
"@hono/node-server": "^1.19.9",
|
|
82
|
-
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
83
82
|
"@opentelemetry/api-logs": "^0.208.0",
|
|
84
83
|
"@opentelemetry/exporter-logs-otlp-http": "^0.208.0",
|
|
85
84
|
"@opentelemetry/resources": "^2.0.0",
|
|
@@ -33,7 +33,7 @@ import { v7 as uuidv7 } from "uuid";
|
|
|
33
33
|
import packageJson from "../../../package.json" with { type: "json" };
|
|
34
34
|
import type { SessionContext } from "../../otel-log-writer.js";
|
|
35
35
|
import type { SessionLogWriter } from "../../session-log-writer.js";
|
|
36
|
-
import { withTimeout } from "../../utils/common.js";
|
|
36
|
+
import { unreachable, withTimeout } from "../../utils/common.js";
|
|
37
37
|
import { Logger } from "../../utils/logger.js";
|
|
38
38
|
import { Pushable } from "../../utils/streams.js";
|
|
39
39
|
import { BaseAcpAgent } from "../base-acp-agent.js";
|
|
@@ -192,7 +192,7 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
192
192
|
const modelOptions = await this.getModelConfigOptions();
|
|
193
193
|
|
|
194
194
|
// Deferred: slash commands + MCP metadata (not needed to return configOptions)
|
|
195
|
-
this.deferBackgroundFetches(q, sessionId
|
|
195
|
+
this.deferBackgroundFetches(q, sessionId);
|
|
196
196
|
|
|
197
197
|
session.modelId = modelOptions.currentModelId;
|
|
198
198
|
// Only call setModel if the resolved model differs from the default we
|
|
@@ -260,7 +260,7 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
// Deferred: slash commands + MCP metadata (not needed to return configOptions)
|
|
263
|
-
this.deferBackgroundFetches(q, sessionId
|
|
263
|
+
this.deferBackgroundFetches(q, sessionId);
|
|
264
264
|
|
|
265
265
|
const configOptions = await this.buildConfigOptions();
|
|
266
266
|
|
|
@@ -514,14 +514,10 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
514
514
|
* Fire-and-forget: fetch slash commands and MCP tool metadata in parallel.
|
|
515
515
|
* Both populate caches used later — neither is needed to return configOptions.
|
|
516
516
|
*/
|
|
517
|
-
private deferBackgroundFetches(
|
|
518
|
-
q: Query,
|
|
519
|
-
sessionId: string,
|
|
520
|
-
mcpServers: ReturnType<typeof parseMcpServers>,
|
|
521
|
-
): void {
|
|
517
|
+
private deferBackgroundFetches(q: Query, sessionId: string): void {
|
|
522
518
|
Promise.all([
|
|
523
519
|
getAvailableSlashCommands(q),
|
|
524
|
-
fetchMcpToolMetadata(
|
|
520
|
+
fetchMcpToolMetadata(q, this.logger),
|
|
525
521
|
])
|
|
526
522
|
.then(([slashCommands]) => {
|
|
527
523
|
this.sendAvailableCommandsUpdate(sessionId, slashCommands);
|
|
@@ -646,9 +642,9 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
646
642
|
return null;
|
|
647
643
|
|
|
648
644
|
default:
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
645
|
+
// SDKMessage union includes undefined types (SDKRateLimitEvent, SDKPromptSuggestionMessage)
|
|
646
|
+
// that resolve to `any`, preventing exhaustive narrowing
|
|
647
|
+
unreachable(message as never, this.logger);
|
|
652
648
|
return null;
|
|
653
649
|
}
|
|
654
650
|
}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
McpHttpServerConfig,
|
|
3
|
-
McpServerConfig,
|
|
4
|
-
} from "@anthropic-ai/claude-agent-sdk";
|
|
5
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
6
|
-
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
7
|
-
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
1
|
+
import type { McpServerStatus, Query } from "@anthropic-ai/claude-agent-sdk";
|
|
8
2
|
import { Logger } from "../../../utils/logger.js";
|
|
9
3
|
|
|
10
4
|
export interface McpToolMetadata {
|
|
@@ -13,86 +7,74 @@ export interface McpToolMetadata {
|
|
|
13
7
|
|
|
14
8
|
const mcpToolMetadataCache: Map<string, McpToolMetadata> = new Map();
|
|
15
9
|
|
|
10
|
+
const PENDING_RETRY_INTERVAL_MS = 1_000;
|
|
11
|
+
const PENDING_MAX_RETRIES = 10;
|
|
12
|
+
|
|
16
13
|
function buildToolKey(serverName: string, toolName: string): string {
|
|
17
14
|
return `mcp__${serverName}__${toolName}`;
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
): config is McpHttpServerConfig {
|
|
23
|
-
return config.type === "http" && typeof config.url === "string";
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async function fetchToolsFromHttpServer(
|
|
27
|
-
_serverName: string,
|
|
28
|
-
config: McpHttpServerConfig,
|
|
29
|
-
): Promise<Tool[]> {
|
|
30
|
-
const transport = new StreamableHTTPClientTransport(new URL(config.url), {
|
|
31
|
-
requestInit: {
|
|
32
|
-
headers: config.headers ?? {},
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const client = new Client({
|
|
37
|
-
name: "twig-metadata-fetcher",
|
|
38
|
-
version: "1.0.0",
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
await client.connect(transport);
|
|
43
|
-
const result = await client.listTools();
|
|
44
|
-
return result.tools;
|
|
45
|
-
} finally {
|
|
46
|
-
await client.close().catch(() => {});
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function extractToolMetadata(tool: Tool): McpToolMetadata {
|
|
51
|
-
return {
|
|
52
|
-
readOnly: tool.annotations?.readOnlyHint === true,
|
|
53
|
-
};
|
|
17
|
+
function delay(ms: number): Promise<void> {
|
|
18
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
54
19
|
}
|
|
55
20
|
|
|
56
21
|
export async function fetchMcpToolMetadata(
|
|
57
|
-
|
|
22
|
+
q: Query,
|
|
58
23
|
logger: Logger = new Logger({ debug: false, prefix: "[McpToolMetadata]" }),
|
|
59
24
|
): Promise<void> {
|
|
60
|
-
|
|
25
|
+
let retries = 0;
|
|
26
|
+
|
|
27
|
+
while (retries <= PENDING_MAX_RETRIES) {
|
|
28
|
+
let statuses: McpServerStatus[];
|
|
29
|
+
try {
|
|
30
|
+
statuses = await q.mcpServerStatus();
|
|
31
|
+
} catch (error) {
|
|
32
|
+
logger.error("Failed to fetch MCP server status", {
|
|
33
|
+
error: error instanceof Error ? error.message : String(error),
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const pendingServers = statuses.filter((s) => s.status === "pending");
|
|
39
|
+
|
|
40
|
+
for (const server of statuses) {
|
|
41
|
+
if (server.status !== "connected" || !server.tools) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let readOnlyCount = 0;
|
|
46
|
+
for (const tool of server.tools) {
|
|
47
|
+
const toolKey = buildToolKey(server.name, tool.name);
|
|
48
|
+
const readOnly = tool.annotations?.readOnly === true;
|
|
49
|
+
mcpToolMetadataCache.set(toolKey, { readOnly });
|
|
50
|
+
if (readOnly) readOnlyCount++;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
logger.info("Fetched MCP tool metadata", {
|
|
54
|
+
serverName: server.name,
|
|
55
|
+
toolCount: server.tools.length,
|
|
56
|
+
readOnlyCount,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
continue;
|
|
60
|
+
if (pendingServers.length === 0) {
|
|
61
|
+
return;
|
|
65
62
|
}
|
|
66
63
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
(t) => t.annotations?.readOnlyHint === true,
|
|
72
|
-
).length;
|
|
73
|
-
|
|
74
|
-
for (const tool of tools) {
|
|
75
|
-
const toolKey = buildToolKey(serverName, tool.name);
|
|
76
|
-
mcpToolMetadataCache.set(toolKey, extractToolMetadata(tool));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
logger.info("Fetched MCP tool metadata", {
|
|
80
|
-
serverName,
|
|
81
|
-
toolCount,
|
|
82
|
-
readOnlyCount,
|
|
83
|
-
});
|
|
84
|
-
})
|
|
85
|
-
.catch((error) => {
|
|
86
|
-
logger.error("Failed to fetch MCP tool metadata", {
|
|
87
|
-
serverName,
|
|
88
|
-
error: error instanceof Error ? error.message : String(error),
|
|
89
|
-
});
|
|
64
|
+
retries++;
|
|
65
|
+
if (retries > PENDING_MAX_RETRIES) {
|
|
66
|
+
logger.warn("Gave up waiting for pending MCP servers", {
|
|
67
|
+
pendingServers: pendingServers.map((s) => s.name),
|
|
90
68
|
});
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
91
71
|
|
|
92
|
-
|
|
72
|
+
logger.info("Waiting for pending MCP servers", {
|
|
73
|
+
pendingServers: pendingServers.map((s) => s.name),
|
|
74
|
+
retry: retries,
|
|
75
|
+
});
|
|
76
|
+
await delay(PENDING_RETRY_INTERVAL_MS);
|
|
93
77
|
}
|
|
94
|
-
|
|
95
|
-
await Promise.all(fetchPromises);
|
|
96
78
|
}
|
|
97
79
|
|
|
98
80
|
export function isMcpToolReadOnly(toolName: string): boolean {
|
|
@@ -88,7 +88,8 @@ function buildEnvironment(): Record<string, string> {
|
|
|
88
88
|
...process.env,
|
|
89
89
|
ELECTRON_RUN_AS_NODE: "1",
|
|
90
90
|
CLAUDE_CODE_ENABLE_ASK_USER_QUESTION_TOOL: "true",
|
|
91
|
-
|
|
91
|
+
// Offload all MCP tools by default
|
|
92
|
+
ENABLE_TOOL_SEARCH: "auto:0",
|
|
92
93
|
};
|
|
93
94
|
}
|
|
94
95
|
|
package/src/agent.ts
CHANGED
|
@@ -69,7 +69,7 @@ export class Agent {
|
|
|
69
69
|
options: TaskExecutionOptions = {},
|
|
70
70
|
): Promise<InProcessAcpConnection> {
|
|
71
71
|
const gatewayConfig = this._configureLlmGateway(options.adapter);
|
|
72
|
-
|
|
72
|
+
this.logger.info("Configured LLM gateway", options);
|
|
73
73
|
this.taskRunId = taskRunId;
|
|
74
74
|
|
|
75
75
|
let allowedModelIds: Set<string> | undefined;
|