@posthog/agent 2.1.45 → 2.1.47

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.
@@ -94,6 +94,8 @@ type AcpConnectionConfig = {
94
94
  /** Deployment environment - "local" for desktop, "cloud" for cloud sandbox */
95
95
  deviceType?: "local" | "cloud";
96
96
  logger?: Logger;
97
+ /** Enable dev-only instrumentation (timing, verbose logging) */
98
+ debug?: boolean;
97
99
  processCallbacks?: ProcessSpawnedCallback;
98
100
  codexOptions?: CodexProcessOptions;
99
101
  allowedModelIds?: Set<string>;
package/dist/agent.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { b as Agent } from './agent-DcBmoTR4.js';
1
+ export { b as Agent } from './agent-BJ7Uacyp.js';
2
2
  import './types.js';
3
3
  import '@agentclientprotocol/sdk';
4
4
  import './logger-DDBiMOOD.js';
package/dist/agent.js CHANGED
@@ -271,12 +271,49 @@ import {
271
271
  import {
272
272
  query
273
273
  } from "@anthropic-ai/claude-agent-sdk";
274
+
275
+ // ../shared/dist/index.js
276
+ var NOOP_COLLECTOR = {
277
+ time: (_label, fn) => fn(),
278
+ timeSync: (_label, fn) => fn(),
279
+ record: () => {
280
+ },
281
+ summarize: () => {
282
+ }
283
+ };
284
+ function createTimingCollector(enabled, log) {
285
+ if (!enabled) return NOOP_COLLECTOR;
286
+ const steps = {};
287
+ return {
288
+ async time(label, fn) {
289
+ const start = Date.now();
290
+ const result = await fn();
291
+ steps[label] = Date.now() - start;
292
+ return result;
293
+ },
294
+ timeSync(label, fn) {
295
+ const start = Date.now();
296
+ const result = fn();
297
+ steps[label] = Date.now() - start;
298
+ return result;
299
+ },
300
+ record(label, ms) {
301
+ steps[label] = ms;
302
+ },
303
+ summarize(label) {
304
+ const total = Object.values(steps).reduce((a, b) => a + b, 0);
305
+ log(`[timing] ${label}: ${total}ms`, steps);
306
+ }
307
+ };
308
+ }
309
+
310
+ // src/adapters/claude/claude-agent.ts
274
311
  import { v7 as uuidv7 } from "uuid";
275
312
 
276
313
  // package.json
277
314
  var package_default = {
278
315
  name: "@posthog/agent",
279
- version: "2.1.45",
316
+ version: "2.1.47",
280
317
  repository: "https://github.com/PostHog/twig",
281
318
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
282
319
  exports: {
@@ -2385,12 +2422,14 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
2385
2422
  backgroundTerminals = {};
2386
2423
  clientCapabilities;
2387
2424
  logWriter;
2388
- processCallbacks;
2425
+ options;
2389
2426
  lastSentConfigOptions;
2390
- constructor(client, logWriter, processCallbacks) {
2427
+ debug;
2428
+ constructor(client, logWriter, options) {
2391
2429
  super(client);
2392
2430
  this.logWriter = logWriter;
2393
- this.processCallbacks = processCallbacks;
2431
+ this.options = options;
2432
+ this.debug = options?.debug ?? false;
2394
2433
  this.toolUseCache = {};
2395
2434
  this.logger = new Logger({ debug: true, prefix: "[ClaudeAcpAgent]" });
2396
2435
  }
@@ -2433,27 +2472,36 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
2433
2472
  }
2434
2473
  async newSession(params) {
2435
2474
  this.checkAuthStatus();
2475
+ const tc = createTimingCollector(
2476
+ this.debug,
2477
+ (msg, data) => this.logger.info(msg, data)
2478
+ );
2436
2479
  const meta = params._meta;
2437
2480
  const sessionId = uuidv7();
2438
2481
  const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
2439
- const mcpServers = parseMcpServers(params);
2440
- const mcpMetadataPromise = fetchMcpToolMetadata(mcpServers, this.logger);
2441
- const options = buildSessionOptions({
2442
- cwd: params.cwd,
2443
- mcpServers,
2444
- permissionMode,
2445
- canUseTool: this.createCanUseTool(sessionId),
2446
- logger: this.logger,
2447
- systemPrompt: buildSystemPrompt(meta?.systemPrompt),
2448
- userProvidedOptions: meta?.claudeCode?.options,
2449
- sessionId,
2450
- isResume: false,
2451
- onModeChange: this.createOnModeChange(sessionId),
2452
- onProcessSpawned: this.processCallbacks?.onProcessSpawned,
2453
- onProcessExited: this.processCallbacks?.onProcessExited
2454
- });
2482
+ const mcpServers = tc.timeSync(
2483
+ "parseMcpServers",
2484
+ () => parseMcpServers(params)
2485
+ );
2486
+ const options = tc.timeSync(
2487
+ "buildSessionOptions",
2488
+ () => buildSessionOptions({
2489
+ cwd: params.cwd,
2490
+ mcpServers,
2491
+ permissionMode,
2492
+ canUseTool: this.createCanUseTool(sessionId),
2493
+ logger: this.logger,
2494
+ systemPrompt: buildSystemPrompt(meta?.systemPrompt),
2495
+ userProvidedOptions: meta?.claudeCode?.options,
2496
+ sessionId,
2497
+ isResume: false,
2498
+ onModeChange: this.createOnModeChange(sessionId),
2499
+ onProcessSpawned: this.options?.onProcessSpawned,
2500
+ onProcessExited: this.options?.onProcessExited
2501
+ })
2502
+ );
2455
2503
  const input = new Pushable();
2456
- const q = query({ prompt: input, options });
2504
+ const q = tc.timeSync("sdkQuery", () => query({ prompt: input, options }));
2457
2505
  const session = this.createSession(
2458
2506
  sessionId,
2459
2507
  q,
@@ -2465,29 +2513,40 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
2465
2513
  session.taskRunId = meta?.taskRunId;
2466
2514
  this.registerPersistence(sessionId, meta);
2467
2515
  if (meta?.taskRunId) {
2468
- await this.client.extNotification("_posthog/sdk_session", {
2469
- taskRunId: meta.taskRunId,
2470
- sessionId,
2471
- adapter: "claude"
2472
- });
2516
+ await tc.time(
2517
+ "extNotification",
2518
+ () => this.client.extNotification("_posthog/sdk_session", {
2519
+ taskRunId: meta.taskRunId,
2520
+ sessionId,
2521
+ adapter: "claude"
2522
+ })
2523
+ );
2473
2524
  }
2474
- const [modelOptions, slashCommands] = await Promise.all([
2475
- this.getModelConfigOptions(),
2476
- getAvailableSlashCommands(q),
2477
- mcpMetadataPromise
2478
- ]);
2525
+ const modelOptions = await tc.time(
2526
+ "fetchModels",
2527
+ () => this.getModelConfigOptions()
2528
+ );
2529
+ this.deferBackgroundFetches(tc, q, sessionId, mcpServers);
2479
2530
  session.modelId = modelOptions.currentModelId;
2480
2531
  await this.trySetModel(q, modelOptions.currentModelId);
2481
- this.sendAvailableCommandsUpdate(sessionId, slashCommands);
2532
+ const configOptions = await tc.time(
2533
+ "buildConfigOptions",
2534
+ () => this.buildConfigOptions(modelOptions)
2535
+ );
2536
+ tc.summarize("newSession");
2482
2537
  return {
2483
2538
  sessionId,
2484
- configOptions: await this.buildConfigOptions(modelOptions)
2539
+ configOptions
2485
2540
  };
2486
2541
  }
2487
2542
  async loadSession(params) {
2488
2543
  return this.resumeSession(params);
2489
2544
  }
2490
2545
  async resumeSession(params) {
2546
+ const tc = createTimingCollector(
2547
+ this.debug,
2548
+ (msg, data) => this.logger.info(msg, data)
2549
+ );
2491
2550
  const meta = params._meta;
2492
2551
  const sessionId = meta?.sessionId;
2493
2552
  if (!sessionId) {
@@ -2496,29 +2555,33 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
2496
2555
  if (this.sessionId === sessionId) {
2497
2556
  return {};
2498
2557
  }
2499
- const mcpServers = parseMcpServers(params);
2500
- const mcpMetadataPromise = fetchMcpToolMetadata(mcpServers, this.logger);
2558
+ const mcpServers = tc.timeSync(
2559
+ "parseMcpServers",
2560
+ () => parseMcpServers(params)
2561
+ );
2501
2562
  const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
2502
- const { query: q, session } = await this.initializeQuery({
2503
- cwd: params.cwd,
2504
- permissionMode,
2505
- mcpServers,
2506
- systemPrompt: buildSystemPrompt(meta?.systemPrompt),
2507
- userProvidedOptions: meta?.claudeCode?.options,
2508
- sessionId,
2509
- isResume: true,
2510
- additionalDirectories: meta?.claudeCode?.options?.additionalDirectories
2511
- });
2563
+ const { query: q, session } = await tc.time(
2564
+ "initializeQuery",
2565
+ () => this.initializeQuery({
2566
+ cwd: params.cwd,
2567
+ permissionMode,
2568
+ mcpServers,
2569
+ systemPrompt: buildSystemPrompt(meta?.systemPrompt),
2570
+ userProvidedOptions: meta?.claudeCode?.options,
2571
+ sessionId,
2572
+ isResume: true,
2573
+ additionalDirectories: meta?.claudeCode?.options?.additionalDirectories
2574
+ })
2575
+ );
2512
2576
  session.taskRunId = meta?.taskRunId;
2513
2577
  this.registerPersistence(sessionId, meta);
2514
- const [slashCommands] = await Promise.all([
2515
- getAvailableSlashCommands(q),
2516
- mcpMetadataPromise
2517
- ]);
2518
- this.sendAvailableCommandsUpdate(sessionId, slashCommands);
2519
- return {
2520
- configOptions: await this.buildConfigOptions()
2521
- };
2578
+ this.deferBackgroundFetches(tc, q, sessionId, mcpServers);
2579
+ const configOptions = await tc.time(
2580
+ "buildConfigOptions",
2581
+ () => this.buildConfigOptions()
2582
+ );
2583
+ tc.summarize("resumeSession");
2584
+ return { configOptions };
2522
2585
  }
2523
2586
  async prompt(params) {
2524
2587
  this.session.cancelled = false;
@@ -2590,8 +2653,8 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
2590
2653
  isResume: config.isResume,
2591
2654
  additionalDirectories: config.additionalDirectories,
2592
2655
  onModeChange: this.createOnModeChange(config.sessionId),
2593
- onProcessSpawned: this.processCallbacks?.onProcessSpawned,
2594
- onProcessExited: this.processCallbacks?.onProcessExited
2656
+ onProcessSpawned: this.options?.onProcessSpawned,
2657
+ onProcessExited: this.options?.onProcessExited
2595
2658
  });
2596
2659
  const q = query({ prompt: input, options });
2597
2660
  const abortController = options.abortController;
@@ -2701,6 +2764,23 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
2701
2764
  await q.setModel(fallback);
2702
2765
  }
2703
2766
  }
2767
+ /**
2768
+ * Fire-and-forget: fetch slash commands and MCP tool metadata in parallel.
2769
+ * Both populate caches used later — neither is needed to return configOptions.
2770
+ */
2771
+ deferBackgroundFetches(tc, q, sessionId, mcpServers) {
2772
+ Promise.all([
2773
+ tc.time("slashCommands", () => getAvailableSlashCommands(q)),
2774
+ tc.time(
2775
+ "mcpMetadata",
2776
+ () => fetchMcpToolMetadata(mcpServers, this.logger)
2777
+ )
2778
+ ]).then(([slashCommands]) => {
2779
+ this.sendAvailableCommandsUpdate(sessionId, slashCommands);
2780
+ }).catch((err) => {
2781
+ this.logger.warn("Failed to fetch deferred session data", { err });
2782
+ });
2783
+ }
2704
2784
  registerPersistence(sessionId, meta) {
2705
2785
  const persistence = meta?.persistence;
2706
2786
  if (persistence && this.logWriter) {
@@ -2988,7 +3068,10 @@ function createClaudeConnection(config) {
2988
3068
  const agentStream = ndJsonStream(agentWritable, streams.agent.readable);
2989
3069
  let agent = null;
2990
3070
  const agentConnection = new AgentSideConnection((client) => {
2991
- agent = new ClaudeAcpAgent(client, logWriter, config.processCallbacks);
3071
+ agent = new ClaudeAcpAgent(client, logWriter, {
3072
+ ...config.processCallbacks,
3073
+ debug: config.debug
3074
+ });
2992
3075
  logger.info(`Created ${agent.adapterName} agent`);
2993
3076
  return agent;
2994
3077
  }, agentStream);
@@ -3688,6 +3771,7 @@ var Agent = class {
3688
3771
  taskId,
3689
3772
  deviceType: "local",
3690
3773
  logger: this.logger,
3774
+ debug: this.debug,
3691
3775
  processCallbacks: options.processCallbacks,
3692
3776
  allowedModelIds,
3693
3777
  codexOptions: options.adapter === "codex" && gatewayConfig ? {