@posthog/agent 2.1.111 → 2.1.113

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.1.111",
907
+ version: "2.1.113",
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: {
@@ -992,7 +992,6 @@ var package_default = {
992
992
  "@anthropic-ai/claude-agent-sdk": "0.2.59",
993
993
  "@anthropic-ai/sdk": "^0.71.0",
994
994
  "@hono/node-server": "^1.19.9",
995
- "@modelcontextprotocol/sdk": "^1.25.3",
996
995
  "@opentelemetry/api-logs": "^0.208.0",
997
996
  "@opentelemetry/exporter-logs-otlp-http": "^0.208.0",
998
997
  "@opentelemetry/resources": "^2.0.0",
@@ -1603,6 +1602,75 @@ var createPostToolUseHook = ({ onModeChange }) => async (input, toolUseID) => {
1603
1602
  return { continue: true };
1604
1603
  };
1605
1604
 
1605
+ // src/adapters/claude/mcp/tool-metadata.ts
1606
+ var mcpToolMetadataCache = /* @__PURE__ */ new Map();
1607
+ var PENDING_RETRY_INTERVAL_MS = 1e3;
1608
+ var PENDING_MAX_RETRIES = 10;
1609
+ function buildToolKey(serverName, toolName) {
1610
+ return `mcp__${serverName}__${toolName}`;
1611
+ }
1612
+ function delay(ms) {
1613
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
1614
+ }
1615
+ async function fetchMcpToolMetadata(q, logger = new Logger({ debug: false, prefix: "[McpToolMetadata]" })) {
1616
+ let retries = 0;
1617
+ while (retries <= PENDING_MAX_RETRIES) {
1618
+ let statuses;
1619
+ try {
1620
+ statuses = await q.mcpServerStatus();
1621
+ } catch (error) {
1622
+ logger.error("Failed to fetch MCP server status", {
1623
+ error: error instanceof Error ? error.message : String(error)
1624
+ });
1625
+ return;
1626
+ }
1627
+ const pendingServers = statuses.filter((s) => s.status === "pending");
1628
+ for (const server of statuses) {
1629
+ if (server.status !== "connected" || !server.tools) {
1630
+ continue;
1631
+ }
1632
+ let readOnlyCount = 0;
1633
+ for (const tool of server.tools) {
1634
+ const toolKey = buildToolKey(server.name, tool.name);
1635
+ const readOnly = tool.annotations?.readOnly === true;
1636
+ mcpToolMetadataCache.set(toolKey, {
1637
+ readOnly,
1638
+ name: tool.name,
1639
+ description: tool.description
1640
+ });
1641
+ if (readOnly) readOnlyCount++;
1642
+ }
1643
+ logger.info("Fetched MCP tool metadata", {
1644
+ serverName: server.name,
1645
+ toolCount: server.tools.length,
1646
+ readOnlyCount
1647
+ });
1648
+ }
1649
+ if (pendingServers.length === 0) {
1650
+ return;
1651
+ }
1652
+ retries++;
1653
+ if (retries > PENDING_MAX_RETRIES) {
1654
+ logger.warn("Gave up waiting for pending MCP servers", {
1655
+ pendingServers: pendingServers.map((s) => s.name)
1656
+ });
1657
+ return;
1658
+ }
1659
+ logger.info("Waiting for pending MCP servers", {
1660
+ pendingServers: pendingServers.map((s) => s.name),
1661
+ retry: retries
1662
+ });
1663
+ await delay(PENDING_RETRY_INTERVAL_MS);
1664
+ }
1665
+ }
1666
+ function getMcpToolMetadata(toolName) {
1667
+ return mcpToolMetadataCache.get(toolName);
1668
+ }
1669
+ function isMcpToolReadOnly(toolName) {
1670
+ const metadata = mcpToolMetadataCache.get(toolName);
1671
+ return metadata?.readOnly === true;
1672
+ }
1673
+
1606
1674
  // src/adapters/claude/conversion/tool-use-to-acp.ts
1607
1675
  var SYSTEM_REMINDER = `
1608
1676
 
@@ -1933,14 +2001,27 @@ function toolInfoFromToolUse(toolUse, cachedFileContent, logger = new Logger({ d
1933
2001
  ${output}\`\`\``).build()
1934
2002
  };
1935
2003
  }
1936
- default:
2004
+ default: {
2005
+ if (name?.startsWith("mcp__")) {
2006
+ return mcpToolInfo(name, input);
2007
+ }
1937
2008
  return {
1938
2009
  title: name || "Unknown Tool",
1939
2010
  kind: "other",
1940
2011
  content: []
1941
2012
  };
2013
+ }
1942
2014
  }
1943
2015
  }
2016
+ function mcpToolInfo(name, _input) {
2017
+ const metadata = getMcpToolMetadata(name);
2018
+ const title = metadata?.name ?? (name.split("__").slice(2).join("__") || name);
2019
+ return {
2020
+ title,
2021
+ kind: "other",
2022
+ content: []
2023
+ };
2024
+ }
1944
2025
  function toolUpdateFromToolResult(toolResult, toolUse) {
1945
2026
  switch (toolUse?.name) {
1946
2027
  case "Read":
@@ -2476,75 +2557,6 @@ async function handleUserAssistantMessage(message, context) {
2476
2557
  return {};
2477
2558
  }
2478
2559
 
2479
- // src/adapters/claude/mcp/tool-metadata.ts
2480
- var import_client = require("@modelcontextprotocol/sdk/client/index.js");
2481
- var import_streamableHttp = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
2482
- var mcpToolMetadataCache = /* @__PURE__ */ new Map();
2483
- function buildToolKey(serverName, toolName) {
2484
- return `mcp__${serverName}__${toolName}`;
2485
- }
2486
- function isHttpMcpServer(config) {
2487
- return config.type === "http" && typeof config.url === "string";
2488
- }
2489
- async function fetchToolsFromHttpServer(_serverName, config) {
2490
- const transport = new import_streamableHttp.StreamableHTTPClientTransport(new URL(config.url), {
2491
- requestInit: {
2492
- headers: config.headers ?? {}
2493
- }
2494
- });
2495
- const client = new import_client.Client({
2496
- name: "twig-metadata-fetcher",
2497
- version: "1.0.0"
2498
- });
2499
- try {
2500
- await client.connect(transport);
2501
- const result = await client.listTools();
2502
- return result.tools;
2503
- } finally {
2504
- await client.close().catch(() => {
2505
- });
2506
- }
2507
- }
2508
- function extractToolMetadata(tool) {
2509
- return {
2510
- readOnly: tool.annotations?.readOnlyHint === true
2511
- };
2512
- }
2513
- async function fetchMcpToolMetadata(mcpServers, logger = new Logger({ debug: false, prefix: "[McpToolMetadata]" })) {
2514
- const fetchPromises = [];
2515
- for (const [serverName, config] of Object.entries(mcpServers)) {
2516
- if (!isHttpMcpServer(config)) {
2517
- continue;
2518
- }
2519
- const fetchPromise = fetchToolsFromHttpServer(serverName, config).then((tools) => {
2520
- const toolCount = tools.length;
2521
- const readOnlyCount = tools.filter(
2522
- (t) => t.annotations?.readOnlyHint === true
2523
- ).length;
2524
- for (const tool of tools) {
2525
- const toolKey = buildToolKey(serverName, tool.name);
2526
- mcpToolMetadataCache.set(toolKey, extractToolMetadata(tool));
2527
- }
2528
- logger.info("Fetched MCP tool metadata", {
2529
- serverName,
2530
- toolCount,
2531
- readOnlyCount
2532
- });
2533
- }).catch((error) => {
2534
- logger.error("Failed to fetch MCP tool metadata", {
2535
- serverName,
2536
- error: error instanceof Error ? error.message : String(error)
2537
- });
2538
- });
2539
- fetchPromises.push(fetchPromise);
2540
- }
2541
- await Promise.all(fetchPromises);
2542
- }
2543
- function isMcpToolReadOnly(toolName) {
2544
- const metadata = mcpToolMetadataCache.get(toolName);
2545
- return metadata?.readOnly === true;
2546
- }
2547
-
2548
2560
  // src/adapters/claude/plan/utils.ts
2549
2561
  var os = __toESM(require("os"), 1);
2550
2562
  var path = __toESM(require("path"), 1);
@@ -3411,7 +3423,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3411
3423
  });
3412
3424
  }
3413
3425
  const modelOptions = await this.getModelConfigOptions();
3414
- this.deferBackgroundFetches(q, sessionId, mcpServers);
3426
+ this.deferBackgroundFetches(q, sessionId);
3415
3427
  session.modelId = modelOptions.currentModelId;
3416
3428
  const resolvedSdkModel = toSdkModelId(modelOptions.currentModelId);
3417
3429
  if (resolvedSdkModel !== DEFAULT_MODEL) {
@@ -3456,7 +3468,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3456
3468
  if (validation.result === "timeout") {
3457
3469
  throw new Error("Session validation timed out");
3458
3470
  }
3459
- this.deferBackgroundFetches(q, sessionId, mcpServers);
3471
+ this.deferBackgroundFetches(q, sessionId);
3460
3472
  const configOptions = await this.buildConfigOptions();
3461
3473
  return { configOptions };
3462
3474
  }
@@ -3644,10 +3656,10 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3644
3656
  * Fire-and-forget: fetch slash commands and MCP tool metadata in parallel.
3645
3657
  * Both populate caches used later — neither is needed to return configOptions.
3646
3658
  */
3647
- deferBackgroundFetches(q, sessionId, mcpServers) {
3659
+ deferBackgroundFetches(q, sessionId) {
3648
3660
  Promise.all([
3649
3661
  getAvailableSlashCommands(q),
3650
- fetchMcpToolMetadata(mcpServers, this.logger)
3662
+ fetchMcpToolMetadata(q, this.logger)
3651
3663
  ]).then(([slashCommands]) => {
3652
3664
  this.sendAvailableCommandsUpdate(sessionId, slashCommands);
3653
3665
  }).catch((err) => {
@@ -4579,18 +4591,18 @@ var SessionLogWriter = class _SessionLogWriter {
4579
4591
  const retryCount = this.retryCounts.get(sessionId) ?? 0;
4580
4592
  const lastAttempt = this.lastFlushAttemptTime.get(sessionId) ?? 0;
4581
4593
  const elapsed = Date.now() - lastAttempt;
4582
- let delay2;
4594
+ let delay3;
4583
4595
  if (retryCount > 0) {
4584
- delay2 = Math.min(
4596
+ delay3 = Math.min(
4585
4597
  _SessionLogWriter.FLUSH_DEBOUNCE_MS * 2 ** retryCount,
4586
4598
  _SessionLogWriter.MAX_RETRY_DELAY_MS
4587
4599
  );
4588
4600
  } else if (elapsed >= _SessionLogWriter.FLUSH_MAX_INTERVAL_MS) {
4589
- delay2 = 0;
4601
+ delay3 = 0;
4590
4602
  } else {
4591
- delay2 = _SessionLogWriter.FLUSH_DEBOUNCE_MS;
4603
+ delay3 = _SessionLogWriter.FLUSH_DEBOUNCE_MS;
4592
4604
  }
4593
- const timeout = setTimeout(() => this.flush(sessionId), delay2);
4605
+ const timeout = setTimeout(() => this.flush(sessionId), delay3);
4594
4606
  this.flushTimeouts.set(sessionId, timeout);
4595
4607
  }
4596
4608
  writeToLocalCache(sessionId, entry) {
@@ -4812,7 +4824,7 @@ function pick(source, properties) {
4812
4824
  });
4813
4825
  return out;
4814
4826
  }
4815
- function delay(duration = 0) {
4827
+ function delay2(duration = 0) {
4816
4828
  return new Promise((done) => setTimeout(done, duration));
4817
4829
  }
4818
4830
  function orVoid(input) {
@@ -5079,7 +5091,7 @@ __export(utils_exports, {
5079
5091
  bufferToString: () => bufferToString,
5080
5092
  callTaskParser: () => callTaskParser,
5081
5093
  createInstanceConfig: () => createInstanceConfig,
5082
- delay: () => delay,
5094
+ delay: () => delay2,
5083
5095
  filterArray: () => filterArray,
5084
5096
  filterFunction: () => filterFunction,
5085
5097
  filterHasLength: () => filterHasLength,
@@ -8892,7 +8904,7 @@ function completionDetectionPlugin({
8892
8904
  if (flag === false) {
8893
8905
  return;
8894
8906
  }
8895
- (flag === true ? event.promise : event.promise.then(() => delay(flag))).then(timeout.done);
8907
+ (flag === true ? event.promise : event.promise.then(() => delay2(flag))).then(timeout.done);
8896
8908
  }
8897
8909
  return {
8898
8910
  type: "spawn.after",
@@ -8908,7 +8920,7 @@ function completionDetectionPlugin({
8908
8920
  try {
8909
8921
  await events.result;
8910
8922
  if (deferClose) {
8911
- await delay(50);
8923
+ await delay2(50);
8912
8924
  }
8913
8925
  close(events.exitCode);
8914
8926
  } catch (err) {