@posthog/agent 2.1.35 → 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.
- package/dist/{agent-DcBmoTR4.d.ts → agent-BJ7Uacyp.d.ts} +2 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +161 -60
- package/dist/agent.js.map +1 -1
- package/dist/gateway-models.js +21 -2
- package/dist/gateway-models.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +292 -193
- package/dist/index.js.map +1 -1
- package/dist/server/agent-server.js +282 -193
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +276 -187
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/acp-connection.ts +6 -1
- package/src/adapters/claude/claude-agent.ts +107 -50
- package/src/adapters/claude/session/options.ts +3 -7
- package/src/agent.ts +1 -0
- package/src/gateway-models.ts +42 -2
|
@@ -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
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.
|
|
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: {
|
|
@@ -407,11 +444,16 @@ function unreachable(value, logger) {
|
|
|
407
444
|
// src/gateway-models.ts
|
|
408
445
|
var DEFAULT_GATEWAY_MODEL = "claude-opus-4-6";
|
|
409
446
|
var BLOCKED_MODELS = /* @__PURE__ */ new Set(["gpt-5-mini", "openai/gpt-5-mini"]);
|
|
447
|
+
var CACHE_TTL = 10 * 60 * 1e3;
|
|
448
|
+
var gatewayModelsCache = null;
|
|
410
449
|
async function fetchGatewayModels(options) {
|
|
411
450
|
const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
|
|
412
451
|
if (!gatewayUrl) {
|
|
413
452
|
return [];
|
|
414
453
|
}
|
|
454
|
+
if (gatewayModelsCache && gatewayModelsCache.url === gatewayUrl && Date.now() < gatewayModelsCache.expiry) {
|
|
455
|
+
return gatewayModelsCache.models;
|
|
456
|
+
}
|
|
415
457
|
const modelsUrl = `${gatewayUrl}/v1/models`;
|
|
416
458
|
try {
|
|
417
459
|
const response = await fetch(modelsUrl);
|
|
@@ -419,8 +461,13 @@ async function fetchGatewayModels(options) {
|
|
|
419
461
|
return [];
|
|
420
462
|
}
|
|
421
463
|
const data = await response.json();
|
|
422
|
-
const models = data.data ?? [];
|
|
423
|
-
|
|
464
|
+
const models = (data.data ?? []).filter((m) => !BLOCKED_MODELS.has(m.id));
|
|
465
|
+
gatewayModelsCache = {
|
|
466
|
+
models,
|
|
467
|
+
expiry: Date.now() + CACHE_TTL,
|
|
468
|
+
url: gatewayUrl
|
|
469
|
+
};
|
|
470
|
+
return models;
|
|
424
471
|
} catch {
|
|
425
472
|
return [];
|
|
426
473
|
}
|
|
@@ -431,11 +478,15 @@ function isAnthropicModel(model) {
|
|
|
431
478
|
}
|
|
432
479
|
return model.id.startsWith("claude-") || model.id.startsWith("anthropic/");
|
|
433
480
|
}
|
|
481
|
+
var arrayModelsCache = null;
|
|
434
482
|
async function fetchArrayModels(options) {
|
|
435
483
|
const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
|
|
436
484
|
if (!gatewayUrl) {
|
|
437
485
|
return [];
|
|
438
486
|
}
|
|
487
|
+
if (arrayModelsCache && arrayModelsCache.url === gatewayUrl && Date.now() < arrayModelsCache.expiry) {
|
|
488
|
+
return arrayModelsCache.models;
|
|
489
|
+
}
|
|
439
490
|
try {
|
|
440
491
|
const base = new URL(gatewayUrl);
|
|
441
492
|
base.pathname = "/array/v1/models";
|
|
@@ -453,6 +504,11 @@ async function fetchArrayModels(options) {
|
|
|
453
504
|
if (!id) continue;
|
|
454
505
|
results.push({ id, owned_by: model?.owned_by });
|
|
455
506
|
}
|
|
507
|
+
arrayModelsCache = {
|
|
508
|
+
models: results,
|
|
509
|
+
expiry: Date.now() + CACHE_TTL,
|
|
510
|
+
url: gatewayUrl
|
|
511
|
+
};
|
|
456
512
|
return results;
|
|
457
513
|
} catch {
|
|
458
514
|
return [];
|
|
@@ -2355,12 +2411,8 @@ function clearStatsigCache() {
|
|
|
2355
2411
|
process.env.CLAUDE_CONFIG_DIR || path2.join(os2.homedir(), ".claude"),
|
|
2356
2412
|
"statsig"
|
|
2357
2413
|
);
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
fs.rmSync(statsigPath, { recursive: true, force: true });
|
|
2361
|
-
}
|
|
2362
|
-
} catch {
|
|
2363
|
-
}
|
|
2414
|
+
fs.rm(statsigPath, { recursive: true, force: true }, () => {
|
|
2415
|
+
});
|
|
2364
2416
|
}
|
|
2365
2417
|
|
|
2366
2418
|
// src/adapters/claude/claude-agent.ts
|
|
@@ -2370,12 +2422,14 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2370
2422
|
backgroundTerminals = {};
|
|
2371
2423
|
clientCapabilities;
|
|
2372
2424
|
logWriter;
|
|
2373
|
-
|
|
2425
|
+
options;
|
|
2374
2426
|
lastSentConfigOptions;
|
|
2375
|
-
|
|
2427
|
+
debug;
|
|
2428
|
+
constructor(client, logWriter, options) {
|
|
2376
2429
|
super(client);
|
|
2377
2430
|
this.logWriter = logWriter;
|
|
2378
|
-
this.
|
|
2431
|
+
this.options = options;
|
|
2432
|
+
this.debug = options?.debug ?? false;
|
|
2379
2433
|
this.toolUseCache = {};
|
|
2380
2434
|
this.logger = new Logger({ debug: true, prefix: "[ClaudeAcpAgent]" });
|
|
2381
2435
|
}
|
|
@@ -2418,27 +2472,36 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2418
2472
|
}
|
|
2419
2473
|
async newSession(params) {
|
|
2420
2474
|
this.checkAuthStatus();
|
|
2475
|
+
const tc = createTimingCollector(
|
|
2476
|
+
this.debug,
|
|
2477
|
+
(msg, data) => this.logger.info(msg, data)
|
|
2478
|
+
);
|
|
2421
2479
|
const meta = params._meta;
|
|
2422
2480
|
const sessionId = uuidv7();
|
|
2423
2481
|
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
2424
|
-
const mcpServers =
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
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
|
+
);
|
|
2440
2503
|
const input = new Pushable();
|
|
2441
|
-
const q = query({ prompt: input, options });
|
|
2504
|
+
const q = tc.timeSync("sdkQuery", () => query({ prompt: input, options }));
|
|
2442
2505
|
const session = this.createSession(
|
|
2443
2506
|
sessionId,
|
|
2444
2507
|
q,
|
|
@@ -2450,28 +2513,40 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2450
2513
|
session.taskRunId = meta?.taskRunId;
|
|
2451
2514
|
this.registerPersistence(sessionId, meta);
|
|
2452
2515
|
if (meta?.taskRunId) {
|
|
2453
|
-
await
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2516
|
+
await tc.time(
|
|
2517
|
+
"extNotification",
|
|
2518
|
+
() => this.client.extNotification("_posthog/sdk_session", {
|
|
2519
|
+
taskRunId: meta.taskRunId,
|
|
2520
|
+
sessionId,
|
|
2521
|
+
adapter: "claude"
|
|
2522
|
+
})
|
|
2523
|
+
);
|
|
2458
2524
|
}
|
|
2459
|
-
const modelOptions = await
|
|
2525
|
+
const modelOptions = await tc.time(
|
|
2526
|
+
"fetchModels",
|
|
2527
|
+
() => this.getModelConfigOptions()
|
|
2528
|
+
);
|
|
2529
|
+
this.deferBackgroundFetches(tc, q, sessionId, mcpServers);
|
|
2460
2530
|
session.modelId = modelOptions.currentModelId;
|
|
2461
2531
|
await this.trySetModel(q, modelOptions.currentModelId);
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2532
|
+
const configOptions = await tc.time(
|
|
2533
|
+
"buildConfigOptions",
|
|
2534
|
+
() => this.buildConfigOptions(modelOptions)
|
|
2465
2535
|
);
|
|
2536
|
+
tc.summarize("newSession");
|
|
2466
2537
|
return {
|
|
2467
2538
|
sessionId,
|
|
2468
|
-
configOptions
|
|
2539
|
+
configOptions
|
|
2469
2540
|
};
|
|
2470
2541
|
}
|
|
2471
2542
|
async loadSession(params) {
|
|
2472
2543
|
return this.resumeSession(params);
|
|
2473
2544
|
}
|
|
2474
2545
|
async resumeSession(params) {
|
|
2546
|
+
const tc = createTimingCollector(
|
|
2547
|
+
this.debug,
|
|
2548
|
+
(msg, data) => this.logger.info(msg, data)
|
|
2549
|
+
);
|
|
2475
2550
|
const meta = params._meta;
|
|
2476
2551
|
const sessionId = meta?.sessionId;
|
|
2477
2552
|
if (!sessionId) {
|
|
@@ -2480,28 +2555,33 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2480
2555
|
if (this.sessionId === sessionId) {
|
|
2481
2556
|
return {};
|
|
2482
2557
|
}
|
|
2483
|
-
const mcpServers =
|
|
2484
|
-
|
|
2558
|
+
const mcpServers = tc.timeSync(
|
|
2559
|
+
"parseMcpServers",
|
|
2560
|
+
() => parseMcpServers(params)
|
|
2561
|
+
);
|
|
2485
2562
|
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
2486
|
-
const { query: q, session } = await
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
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
|
+
);
|
|
2496
2576
|
session.taskRunId = meta?.taskRunId;
|
|
2497
2577
|
this.registerPersistence(sessionId, meta);
|
|
2498
|
-
this.
|
|
2499
|
-
|
|
2500
|
-
|
|
2578
|
+
this.deferBackgroundFetches(tc, q, sessionId, mcpServers);
|
|
2579
|
+
const configOptions = await tc.time(
|
|
2580
|
+
"buildConfigOptions",
|
|
2581
|
+
() => this.buildConfigOptions()
|
|
2501
2582
|
);
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
};
|
|
2583
|
+
tc.summarize("resumeSession");
|
|
2584
|
+
return { configOptions };
|
|
2505
2585
|
}
|
|
2506
2586
|
async prompt(params) {
|
|
2507
2587
|
this.session.cancelled = false;
|
|
@@ -2573,8 +2653,8 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2573
2653
|
isResume: config.isResume,
|
|
2574
2654
|
additionalDirectories: config.additionalDirectories,
|
|
2575
2655
|
onModeChange: this.createOnModeChange(config.sessionId),
|
|
2576
|
-
onProcessSpawned: this.
|
|
2577
|
-
onProcessExited: this.
|
|
2656
|
+
onProcessSpawned: this.options?.onProcessSpawned,
|
|
2657
|
+
onProcessExited: this.options?.onProcessExited
|
|
2578
2658
|
});
|
|
2579
2659
|
const q = query({ prompt: input, options });
|
|
2580
2660
|
const abortController = options.abortController;
|
|
@@ -2684,6 +2764,23 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2684
2764
|
await q.setModel(fallback);
|
|
2685
2765
|
}
|
|
2686
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
|
+
}
|
|
2687
2784
|
registerPersistence(sessionId, meta) {
|
|
2688
2785
|
const persistence = meta?.persistence;
|
|
2689
2786
|
if (persistence && this.logWriter) {
|
|
@@ -2971,7 +3068,10 @@ function createClaudeConnection(config) {
|
|
|
2971
3068
|
const agentStream = ndJsonStream(agentWritable, streams.agent.readable);
|
|
2972
3069
|
let agent = null;
|
|
2973
3070
|
const agentConnection = new AgentSideConnection((client) => {
|
|
2974
|
-
agent = new ClaudeAcpAgent(client, logWriter,
|
|
3071
|
+
agent = new ClaudeAcpAgent(client, logWriter, {
|
|
3072
|
+
...config.processCallbacks,
|
|
3073
|
+
debug: config.debug
|
|
3074
|
+
});
|
|
2975
3075
|
logger.info(`Created ${agent.adapterName} agent`);
|
|
2976
3076
|
return agent;
|
|
2977
3077
|
}, agentStream);
|
|
@@ -3671,6 +3771,7 @@ var Agent = class {
|
|
|
3671
3771
|
taskId,
|
|
3672
3772
|
deviceType: "local",
|
|
3673
3773
|
logger: this.logger,
|
|
3774
|
+
debug: this.debug,
|
|
3674
3775
|
processCallbacks: options.processCallbacks,
|
|
3675
3776
|
allowedModelIds,
|
|
3676
3777
|
codexOptions: options.adapter === "codex" && gatewayConfig ? {
|