@posthog/agent 2.1.115 → 2.1.120
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.js +122 -33
- package/dist/agent.js.map +1 -1
- package/dist/posthog-api.d.ts +1 -0
- package/dist/posthog-api.js +11 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.d.ts +7 -0
- package/dist/server/agent-server.js +317 -44
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +317 -44
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +3 -3
- package/src/adapters/acp-connection.ts +1 -1
- package/src/adapters/claude/claude-agent.ts +47 -29
- package/src/adapters/claude/conversion/acp-to-sdk.ts +6 -0
- package/src/adapters/claude/permissions/permission-handlers.ts +7 -1
- package/src/adapters/claude/types.ts +1 -0
- package/src/posthog-api.ts +15 -0
- package/src/server/agent-server.test.ts +109 -0
- package/src/server/agent-server.ts +261 -12
- package/src/server/question-relay.test.ts +343 -0
- package/src/session-log-writer.test.ts +19 -0
- package/src/session-log-writer.ts +72 -12
- package/src/test/mocks/msw-handlers.ts +25 -1
package/dist/agent.js
CHANGED
|
@@ -276,7 +276,7 @@ import { v7 as uuidv7 } from "uuid";
|
|
|
276
276
|
// package.json
|
|
277
277
|
var package_default = {
|
|
278
278
|
name: "@posthog/agent",
|
|
279
|
-
version: "2.1.
|
|
279
|
+
version: "2.1.120",
|
|
280
280
|
repository: "https://github.com/PostHog/twig",
|
|
281
281
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
282
282
|
exports: {
|
|
@@ -657,6 +657,10 @@ ${chunk.resource.text}
|
|
|
657
657
|
function promptToClaude(prompt) {
|
|
658
658
|
const content = [];
|
|
659
659
|
const context = [];
|
|
660
|
+
const prContext = prompt._meta?.prContext;
|
|
661
|
+
if (typeof prContext === "string") {
|
|
662
|
+
content.push(sdkText(prContext));
|
|
663
|
+
}
|
|
660
664
|
for (const chunk of prompt.prompt) {
|
|
661
665
|
processPromptChunk(chunk, content, context);
|
|
662
666
|
}
|
|
@@ -2103,9 +2107,10 @@ async function handleAskUserQuestionTool(context) {
|
|
|
2103
2107
|
}
|
|
2104
2108
|
});
|
|
2105
2109
|
if (response.outcome?.outcome !== "selected") {
|
|
2110
|
+
const customMessage = response._meta?.message;
|
|
2106
2111
|
return {
|
|
2107
2112
|
behavior: "deny",
|
|
2108
|
-
message: "User cancelled the questions",
|
|
2113
|
+
message: typeof customMessage === "string" ? customMessage : "User cancelled the questions",
|
|
2109
2114
|
interrupt: true
|
|
2110
2115
|
};
|
|
2111
2116
|
}
|
|
@@ -2490,12 +2495,10 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2490
2495
|
toolUseCache;
|
|
2491
2496
|
backgroundTerminals = {};
|
|
2492
2497
|
clientCapabilities;
|
|
2493
|
-
logWriter;
|
|
2494
2498
|
options;
|
|
2495
2499
|
lastSentConfigOptions;
|
|
2496
|
-
constructor(client,
|
|
2500
|
+
constructor(client, options) {
|
|
2497
2501
|
super(client);
|
|
2498
|
-
this.logWriter = logWriter;
|
|
2499
2502
|
this.options = options;
|
|
2500
2503
|
this.toolUseCache = {};
|
|
2501
2504
|
this.logger = new Logger({ debug: true, prefix: "[ClaudeAcpAgent]" });
|
|
@@ -2540,7 +2543,14 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2540
2543
|
async newSession(params) {
|
|
2541
2544
|
this.checkAuthStatus();
|
|
2542
2545
|
const meta = params._meta;
|
|
2546
|
+
const taskId = meta?.persistence?.taskId;
|
|
2543
2547
|
const sessionId = uuidv7();
|
|
2548
|
+
this.logger.info("Creating new session", {
|
|
2549
|
+
sessionId,
|
|
2550
|
+
taskId,
|
|
2551
|
+
taskRunId: meta?.taskRunId,
|
|
2552
|
+
cwd: params.cwd
|
|
2553
|
+
});
|
|
2544
2554
|
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
2545
2555
|
const mcpServers = parseMcpServers(params);
|
|
2546
2556
|
const options = buildSessionOptions({
|
|
@@ -2569,7 +2579,6 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2569
2579
|
options.abortController
|
|
2570
2580
|
);
|
|
2571
2581
|
session.taskRunId = meta?.taskRunId;
|
|
2572
|
-
this.registerPersistence(sessionId, meta);
|
|
2573
2582
|
if (meta?.taskRunId) {
|
|
2574
2583
|
await this.client.extNotification("_posthog/sdk_session", {
|
|
2575
2584
|
taskRunId: meta.taskRunId,
|
|
@@ -2595,6 +2604,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2595
2604
|
}
|
|
2596
2605
|
async resumeSession(params) {
|
|
2597
2606
|
const meta = params._meta;
|
|
2607
|
+
const taskId = meta?.persistence?.taskId;
|
|
2598
2608
|
const sessionId = meta?.sessionId;
|
|
2599
2609
|
if (!sessionId) {
|
|
2600
2610
|
throw new Error("Cannot resume session without sessionId");
|
|
@@ -2602,6 +2612,12 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2602
2612
|
if (this.sessionId === sessionId) {
|
|
2603
2613
|
return {};
|
|
2604
2614
|
}
|
|
2615
|
+
this.logger.info("Resuming session", {
|
|
2616
|
+
sessionId,
|
|
2617
|
+
taskId,
|
|
2618
|
+
taskRunId: meta?.taskRunId,
|
|
2619
|
+
cwd: params.cwd
|
|
2620
|
+
});
|
|
2605
2621
|
const mcpServers = parseMcpServers(params);
|
|
2606
2622
|
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
2607
2623
|
const { query: q, session } = await this.initializeQuery({
|
|
@@ -2614,15 +2630,36 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2614
2630
|
isResume: true,
|
|
2615
2631
|
additionalDirectories: meta?.claudeCode?.options?.additionalDirectories
|
|
2616
2632
|
});
|
|
2633
|
+
this.logger.info("Session query initialized, awaiting resumption", {
|
|
2634
|
+
sessionId,
|
|
2635
|
+
taskId,
|
|
2636
|
+
taskRunId: meta?.taskRunId
|
|
2637
|
+
});
|
|
2617
2638
|
session.taskRunId = meta?.taskRunId;
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2639
|
+
try {
|
|
2640
|
+
const result = await withTimeout(
|
|
2641
|
+
q.initializationResult(),
|
|
2642
|
+
SESSION_VALIDATION_TIMEOUT_MS
|
|
2643
|
+
);
|
|
2644
|
+
if (result.result === "timeout") {
|
|
2645
|
+
throw new Error(
|
|
2646
|
+
`Session resumption timed out for sessionId=${sessionId}`
|
|
2647
|
+
);
|
|
2648
|
+
}
|
|
2649
|
+
} catch (err) {
|
|
2650
|
+
this.logger.error("Session resumption failed", {
|
|
2651
|
+
sessionId,
|
|
2652
|
+
taskId,
|
|
2653
|
+
taskRunId: meta?.taskRunId,
|
|
2654
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2655
|
+
});
|
|
2656
|
+
throw err;
|
|
2625
2657
|
}
|
|
2658
|
+
this.logger.info("Session resumed successfully", {
|
|
2659
|
+
sessionId,
|
|
2660
|
+
taskId,
|
|
2661
|
+
taskRunId: meta?.taskRunId
|
|
2662
|
+
});
|
|
2626
2663
|
this.deferBackgroundFetches(q, sessionId);
|
|
2627
2664
|
const configOptions = await this.buildConfigOptions();
|
|
2628
2665
|
return { configOptions };
|
|
@@ -2821,12 +2858,6 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
2821
2858
|
this.logger.warn("Failed to fetch deferred session data", { err });
|
|
2822
2859
|
});
|
|
2823
2860
|
}
|
|
2824
|
-
registerPersistence(sessionId, meta) {
|
|
2825
|
-
const persistence = meta?.persistence;
|
|
2826
|
-
if (persistence && this.logWriter) {
|
|
2827
|
-
this.logWriter.register(sessionId, persistence);
|
|
2828
|
-
}
|
|
2829
|
-
}
|
|
2830
2861
|
sendAvailableCommandsUpdate(sessionId, availableCommands) {
|
|
2831
2862
|
setTimeout(() => {
|
|
2832
2863
|
this.client.sessionUpdate({
|
|
@@ -3114,7 +3145,7 @@ function createClaudeConnection(config) {
|
|
|
3114
3145
|
const agentStream = ndJsonStream(agentWritable, streams.agent.readable);
|
|
3115
3146
|
let agent = null;
|
|
3116
3147
|
const agentConnection = new AgentSideConnection((client) => {
|
|
3117
|
-
agent = new ClaudeAcpAgent(client,
|
|
3148
|
+
agent = new ClaudeAcpAgent(client, config.processCallbacks);
|
|
3118
3149
|
logger.info(`Created ${agent.adapterName} agent`);
|
|
3119
3150
|
return agent;
|
|
3120
3151
|
}, agentStream);
|
|
@@ -3449,6 +3480,16 @@ var PostHogAPIClient = class {
|
|
|
3449
3480
|
}
|
|
3450
3481
|
);
|
|
3451
3482
|
}
|
|
3483
|
+
async relayMessage(taskId, runId, text2) {
|
|
3484
|
+
const teamId = this.getTeamId();
|
|
3485
|
+
await this.apiRequest(
|
|
3486
|
+
`/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/relay_message/`,
|
|
3487
|
+
{
|
|
3488
|
+
method: "POST",
|
|
3489
|
+
body: JSON.stringify({ text: text2 })
|
|
3490
|
+
}
|
|
3491
|
+
);
|
|
3492
|
+
}
|
|
3452
3493
|
async uploadTaskArtifacts(taskId, runId, artifacts) {
|
|
3453
3494
|
if (!artifacts.length) {
|
|
3454
3495
|
return [];
|
|
@@ -3554,11 +3595,15 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
3554
3595
|
}
|
|
3555
3596
|
async flushAll() {
|
|
3556
3597
|
const sessionIds = [...this.sessions.keys()];
|
|
3557
|
-
const pendingCounts = sessionIds.map((id) =>
|
|
3558
|
-
id
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3598
|
+
const pendingCounts = sessionIds.map((id) => {
|
|
3599
|
+
const session = this.sessions.get(id);
|
|
3600
|
+
return {
|
|
3601
|
+
taskId: session?.context.taskId,
|
|
3602
|
+
runId: session?.context.runId,
|
|
3603
|
+
pending: this.pendingEntries.get(id)?.length ?? 0,
|
|
3604
|
+
messages: this.messageCounts.get(id) ?? 0
|
|
3605
|
+
};
|
|
3606
|
+
});
|
|
3562
3607
|
this.logger.info("flushAll called", {
|
|
3563
3608
|
sessions: sessionIds.length,
|
|
3564
3609
|
pending: pendingCounts
|
|
@@ -3574,8 +3619,8 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
3574
3619
|
return;
|
|
3575
3620
|
}
|
|
3576
3621
|
this.logger.info("Session registered", {
|
|
3577
|
-
|
|
3578
|
-
|
|
3622
|
+
taskId: context.taskId,
|
|
3623
|
+
runId: context.runId
|
|
3579
3624
|
});
|
|
3580
3625
|
this.sessions.set(sessionId, { context });
|
|
3581
3626
|
this.lastFlushAttemptTime.set(sessionId, Date.now());
|
|
@@ -3609,7 +3654,11 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
3609
3654
|
const count = (this.messageCounts.get(sessionId) ?? 0) + 1;
|
|
3610
3655
|
this.messageCounts.set(sessionId, count);
|
|
3611
3656
|
if (count % 10 === 1) {
|
|
3612
|
-
this.logger.info("Messages received", {
|
|
3657
|
+
this.logger.info("Messages received", {
|
|
3658
|
+
count,
|
|
3659
|
+
taskId: session.context.taskId,
|
|
3660
|
+
runId: session.context.runId
|
|
3661
|
+
});
|
|
3613
3662
|
}
|
|
3614
3663
|
try {
|
|
3615
3664
|
const message = JSON.parse(line);
|
|
@@ -3626,6 +3675,10 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
3626
3675
|
return;
|
|
3627
3676
|
}
|
|
3628
3677
|
this.emitCoalescedMessage(sessionId, session);
|
|
3678
|
+
const nonChunkAgentText = this.extractAgentMessageText(message);
|
|
3679
|
+
if (nonChunkAgentText) {
|
|
3680
|
+
session.lastAgentMessage = nonChunkAgentText;
|
|
3681
|
+
}
|
|
3629
3682
|
const entry = {
|
|
3630
3683
|
type: "notification",
|
|
3631
3684
|
timestamp,
|
|
@@ -3640,7 +3693,8 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
3640
3693
|
}
|
|
3641
3694
|
} catch {
|
|
3642
3695
|
this.logger.warn("Failed to parse raw line for persistence", {
|
|
3643
|
-
|
|
3696
|
+
taskId: session.context.taskId,
|
|
3697
|
+
runId: session.context.runId,
|
|
3644
3698
|
lineLength: line.length
|
|
3645
3699
|
});
|
|
3646
3700
|
}
|
|
@@ -3655,7 +3709,8 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
3655
3709
|
const pending = this.pendingEntries.get(sessionId);
|
|
3656
3710
|
if (!this.posthogAPI || !pending?.length) {
|
|
3657
3711
|
this.logger.info("flush: nothing to persist", {
|
|
3658
|
-
|
|
3712
|
+
taskId: session.context.taskId,
|
|
3713
|
+
runId: session.context.runId,
|
|
3659
3714
|
hasPosthogAPI: !!this.posthogAPI,
|
|
3660
3715
|
pendingCount: pending?.length ?? 0
|
|
3661
3716
|
});
|
|
@@ -3676,7 +3731,8 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
3676
3731
|
);
|
|
3677
3732
|
this.retryCounts.set(sessionId, 0);
|
|
3678
3733
|
this.logger.info("Flushed session logs", {
|
|
3679
|
-
|
|
3734
|
+
taskId: session.context.taskId,
|
|
3735
|
+
runId: session.context.runId,
|
|
3680
3736
|
entryCount: pending.length
|
|
3681
3737
|
});
|
|
3682
3738
|
} catch (error) {
|
|
@@ -3685,7 +3741,11 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
3685
3741
|
if (retryCount >= _SessionLogWriter.MAX_FLUSH_RETRIES) {
|
|
3686
3742
|
this.logger.error(
|
|
3687
3743
|
`Dropping ${pending.length} session log entries after ${retryCount} failed flush attempts`,
|
|
3688
|
-
{
|
|
3744
|
+
{
|
|
3745
|
+
taskId: session.context.taskId,
|
|
3746
|
+
runId: session.context.runId,
|
|
3747
|
+
error
|
|
3748
|
+
}
|
|
3689
3749
|
);
|
|
3690
3750
|
this.retryCounts.set(sessionId, 0);
|
|
3691
3751
|
} else {
|
|
@@ -3718,6 +3778,7 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
3718
3778
|
if (!session.chunkBuffer) return;
|
|
3719
3779
|
const { text: text2, firstTimestamp } = session.chunkBuffer;
|
|
3720
3780
|
session.chunkBuffer = void 0;
|
|
3781
|
+
session.lastAgentMessage = text2;
|
|
3721
3782
|
const entry = {
|
|
3722
3783
|
type: "notification",
|
|
3723
3784
|
timestamp: firstTimestamp,
|
|
@@ -3740,6 +3801,29 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
3740
3801
|
this.scheduleFlush(sessionId);
|
|
3741
3802
|
}
|
|
3742
3803
|
}
|
|
3804
|
+
getLastAgentMessage(sessionId) {
|
|
3805
|
+
return this.sessions.get(sessionId)?.lastAgentMessage;
|
|
3806
|
+
}
|
|
3807
|
+
extractAgentMessageText(message) {
|
|
3808
|
+
if (message.method !== "session/update") {
|
|
3809
|
+
return null;
|
|
3810
|
+
}
|
|
3811
|
+
const params = message.params;
|
|
3812
|
+
const update = params?.update;
|
|
3813
|
+
if (update?.sessionUpdate !== "agent_message") {
|
|
3814
|
+
return null;
|
|
3815
|
+
}
|
|
3816
|
+
const content = update.content;
|
|
3817
|
+
if (content?.type === "text" && typeof content.text === "string") {
|
|
3818
|
+
const trimmed = content.text.trim();
|
|
3819
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
3820
|
+
}
|
|
3821
|
+
if (typeof update.message === "string") {
|
|
3822
|
+
const trimmed = update.message.trim();
|
|
3823
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
3824
|
+
}
|
|
3825
|
+
return null;
|
|
3826
|
+
}
|
|
3743
3827
|
scheduleFlush(sessionId) {
|
|
3744
3828
|
const existing = this.flushTimeouts.get(sessionId);
|
|
3745
3829
|
if (existing) clearTimeout(existing);
|
|
@@ -3774,7 +3858,12 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
3774
3858
|
fs3.appendFileSync(logPath, `${JSON.stringify(entry)}
|
|
3775
3859
|
`);
|
|
3776
3860
|
} catch (error) {
|
|
3777
|
-
this.logger.warn("Failed to write to local cache", {
|
|
3861
|
+
this.logger.warn("Failed to write to local cache", {
|
|
3862
|
+
taskId: session.context.taskId,
|
|
3863
|
+
runId: session.context.runId,
|
|
3864
|
+
logPath,
|
|
3865
|
+
error
|
|
3866
|
+
});
|
|
3778
3867
|
}
|
|
3779
3868
|
}
|
|
3780
3869
|
};
|