@posthog/agent 2.1.137 → 2.1.138
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/conversion/tool-use-to-acp.js +2 -1
- package/dist/adapters/claude/conversion/tool-use-to-acp.js.map +1 -1
- package/dist/adapters/claude/session/jsonl-hydration.d.ts +45 -0
- package/dist/adapters/claude/session/jsonl-hydration.js +444 -0
- package/dist/adapters/claude/session/jsonl-hydration.js.map +1 -0
- package/dist/agent.d.ts +2 -0
- package/dist/agent.js +11 -3
- package/dist/agent.js.map +1 -1
- package/dist/posthog-api.js +5 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +8 -3
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +8 -3
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +7 -3
- package/src/adapters/claude/conversion/tool-use-to-acp.ts +2 -1
- package/src/adapters/claude/session/jsonl-hydration.test.ts +903 -0
- package/src/adapters/claude/session/jsonl-hydration.ts +581 -0
- package/src/adapters/codex/spawn.ts +1 -1
- package/src/agent.ts +4 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
// src/adapters/claude/session/jsonl-hydration.ts
|
|
2
|
+
import { randomUUID } from "crypto";
|
|
3
|
+
import * as fs from "fs/promises";
|
|
4
|
+
import * as os from "os";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
var MAX_PROJECT_KEY_LENGTH = 200;
|
|
7
|
+
function hashString(s) {
|
|
8
|
+
let hash = 0;
|
|
9
|
+
for (let i = 0; i < s.length; i++) {
|
|
10
|
+
hash = (hash << 5) - hash + s.charCodeAt(i);
|
|
11
|
+
hash |= 0;
|
|
12
|
+
}
|
|
13
|
+
return Math.abs(hash).toString(36);
|
|
14
|
+
}
|
|
15
|
+
function getSessionJsonlPath(sessionId, cwd) {
|
|
16
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
|
|
17
|
+
let projectKey = cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
18
|
+
if (projectKey.length > MAX_PROJECT_KEY_LENGTH) {
|
|
19
|
+
projectKey = `${projectKey.slice(0, MAX_PROJECT_KEY_LENGTH)}-${hashString(cwd)}`;
|
|
20
|
+
}
|
|
21
|
+
return path.join(configDir, "projects", projectKey, `${sessionId}.jsonl`);
|
|
22
|
+
}
|
|
23
|
+
function rebuildConversation(entries) {
|
|
24
|
+
const turns = [];
|
|
25
|
+
let currentAssistantContent = [];
|
|
26
|
+
let currentToolCalls = [];
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
const method = entry.notification?.method;
|
|
29
|
+
const params = entry.notification?.params;
|
|
30
|
+
if (method === "session/update" && params?.update) {
|
|
31
|
+
const update = params.update;
|
|
32
|
+
switch (update.sessionUpdate) {
|
|
33
|
+
case "user_message":
|
|
34
|
+
case "user_message_chunk": {
|
|
35
|
+
if (currentAssistantContent.length > 0 || currentToolCalls.length > 0) {
|
|
36
|
+
turns.push({
|
|
37
|
+
role: "assistant",
|
|
38
|
+
content: currentAssistantContent,
|
|
39
|
+
toolCalls: currentToolCalls.length > 0 ? currentToolCalls : void 0
|
|
40
|
+
});
|
|
41
|
+
currentAssistantContent = [];
|
|
42
|
+
currentToolCalls = [];
|
|
43
|
+
}
|
|
44
|
+
const content = update.content;
|
|
45
|
+
const contentArray = Array.isArray(content) ? content : content ? [content] : [];
|
|
46
|
+
const lastTurn = turns[turns.length - 1];
|
|
47
|
+
if (lastTurn?.role === "user") {
|
|
48
|
+
lastTurn.content.push(...contentArray);
|
|
49
|
+
} else {
|
|
50
|
+
turns.push({ role: "user", content: contentArray });
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case "agent_message":
|
|
55
|
+
case "agent_message_chunk":
|
|
56
|
+
case "agent_thought_chunk": {
|
|
57
|
+
const content = update.content;
|
|
58
|
+
if (content && !Array.isArray(content)) {
|
|
59
|
+
if (content.type === "text" && currentAssistantContent.length > 0 && currentAssistantContent[currentAssistantContent.length - 1].type === "text") {
|
|
60
|
+
const lastBlock = currentAssistantContent[currentAssistantContent.length - 1];
|
|
61
|
+
lastBlock.text += content.text;
|
|
62
|
+
} else {
|
|
63
|
+
currentAssistantContent.push(content);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
case "tool_call":
|
|
69
|
+
case "tool_call_update": {
|
|
70
|
+
const meta = update._meta?.claudeCode;
|
|
71
|
+
if (meta) {
|
|
72
|
+
const { toolCallId, toolName, toolInput, toolResponse } = meta;
|
|
73
|
+
if (toolCallId && toolName) {
|
|
74
|
+
let toolCall = currentToolCalls.find(
|
|
75
|
+
(tc) => tc.toolCallId === toolCallId
|
|
76
|
+
);
|
|
77
|
+
if (!toolCall) {
|
|
78
|
+
toolCall = { toolCallId, toolName, input: toolInput };
|
|
79
|
+
currentToolCalls.push(toolCall);
|
|
80
|
+
}
|
|
81
|
+
if (toolResponse !== void 0) {
|
|
82
|
+
toolCall.result = toolResponse;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case "tool_result": {
|
|
89
|
+
const meta = update._meta?.claudeCode;
|
|
90
|
+
if (meta) {
|
|
91
|
+
const { toolCallId, toolResponse } = meta;
|
|
92
|
+
if (toolCallId) {
|
|
93
|
+
const toolCall = currentToolCalls.find(
|
|
94
|
+
(tc) => tc.toolCallId === toolCallId
|
|
95
|
+
);
|
|
96
|
+
if (toolCall && toolResponse !== void 0) {
|
|
97
|
+
toolCall.result = toolResponse;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (currentAssistantContent.length > 0 || currentToolCalls.length > 0) {
|
|
107
|
+
turns.push({
|
|
108
|
+
role: "assistant",
|
|
109
|
+
content: currentAssistantContent,
|
|
110
|
+
toolCalls: currentToolCalls.length > 0 ? currentToolCalls : void 0
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return turns;
|
|
114
|
+
}
|
|
115
|
+
var CHARS_PER_TOKEN = 4;
|
|
116
|
+
var DEFAULT_MAX_TOKENS = 15e4;
|
|
117
|
+
function estimateTurnTokens(turn) {
|
|
118
|
+
let chars = 0;
|
|
119
|
+
for (const block of turn.content) {
|
|
120
|
+
if ("text" in block && typeof block.text === "string") {
|
|
121
|
+
chars += block.text.length;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (turn.toolCalls) {
|
|
125
|
+
for (const tc of turn.toolCalls) {
|
|
126
|
+
chars += JSON.stringify(tc.input ?? "").length;
|
|
127
|
+
if (tc.result !== void 0) {
|
|
128
|
+
chars += typeof tc.result === "string" ? tc.result.length : JSON.stringify(tc.result).length;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return Math.ceil(chars / CHARS_PER_TOKEN);
|
|
133
|
+
}
|
|
134
|
+
function selectRecentTurns(turns, maxTokens = DEFAULT_MAX_TOKENS) {
|
|
135
|
+
let budget = maxTokens;
|
|
136
|
+
let startIndex = turns.length;
|
|
137
|
+
for (let i = turns.length - 1; i >= 0; i--) {
|
|
138
|
+
const cost = estimateTurnTokens(turns[i]);
|
|
139
|
+
if (cost > budget) break;
|
|
140
|
+
budget -= cost;
|
|
141
|
+
startIndex = i;
|
|
142
|
+
}
|
|
143
|
+
while (startIndex < turns.length && turns[startIndex].role !== "user") {
|
|
144
|
+
startIndex++;
|
|
145
|
+
}
|
|
146
|
+
return turns.slice(startIndex);
|
|
147
|
+
}
|
|
148
|
+
var BASE62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
149
|
+
function generateMessageId() {
|
|
150
|
+
const bytes = new Uint8Array(24);
|
|
151
|
+
crypto.getRandomValues(bytes);
|
|
152
|
+
let id = "msg_01";
|
|
153
|
+
for (const b of bytes) {
|
|
154
|
+
id += BASE62[b % 62];
|
|
155
|
+
}
|
|
156
|
+
return id;
|
|
157
|
+
}
|
|
158
|
+
var ADJECTIVES = [
|
|
159
|
+
"bright",
|
|
160
|
+
"calm",
|
|
161
|
+
"daring",
|
|
162
|
+
"eager",
|
|
163
|
+
"fair",
|
|
164
|
+
"gentle",
|
|
165
|
+
"happy",
|
|
166
|
+
"keen",
|
|
167
|
+
"lively",
|
|
168
|
+
"merry",
|
|
169
|
+
"noble",
|
|
170
|
+
"polite",
|
|
171
|
+
"quick",
|
|
172
|
+
"sharp",
|
|
173
|
+
"warm",
|
|
174
|
+
"witty"
|
|
175
|
+
];
|
|
176
|
+
var VERBS = [
|
|
177
|
+
"blazing",
|
|
178
|
+
"crafting",
|
|
179
|
+
"dashing",
|
|
180
|
+
"flowing",
|
|
181
|
+
"gliding",
|
|
182
|
+
"humming",
|
|
183
|
+
"jumping",
|
|
184
|
+
"linking",
|
|
185
|
+
"melting",
|
|
186
|
+
"nesting",
|
|
187
|
+
"pacing",
|
|
188
|
+
"roaming",
|
|
189
|
+
"sailing",
|
|
190
|
+
"turning",
|
|
191
|
+
"waving",
|
|
192
|
+
"zoning"
|
|
193
|
+
];
|
|
194
|
+
var NOUNS = [
|
|
195
|
+
"aurora",
|
|
196
|
+
"breeze",
|
|
197
|
+
"cedar",
|
|
198
|
+
"delta",
|
|
199
|
+
"ember",
|
|
200
|
+
"frost",
|
|
201
|
+
"grove",
|
|
202
|
+
"haven",
|
|
203
|
+
"inlet",
|
|
204
|
+
"jewel",
|
|
205
|
+
"knoll",
|
|
206
|
+
"lotus",
|
|
207
|
+
"maple",
|
|
208
|
+
"nexus",
|
|
209
|
+
"oasis",
|
|
210
|
+
"prism"
|
|
211
|
+
];
|
|
212
|
+
function generateSlug() {
|
|
213
|
+
const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
|
214
|
+
return `${pick(ADJECTIVES)}-${pick(VERBS)}-${pick(NOUNS)}`;
|
|
215
|
+
}
|
|
216
|
+
function conversationTurnsToJsonlEntries(turns, config) {
|
|
217
|
+
const lines = [];
|
|
218
|
+
let parentUuid = null;
|
|
219
|
+
const model = config.model ?? "claude-opus-4-6";
|
|
220
|
+
const version = config.version ?? "2.1.63";
|
|
221
|
+
const gitBranch = config.gitBranch ?? "";
|
|
222
|
+
const slug = config.slug ?? generateSlug();
|
|
223
|
+
const permissionMode = config.permissionMode ?? "default";
|
|
224
|
+
const baseTime = Date.now() - turns.length * 3e3;
|
|
225
|
+
let turnIndex = 0;
|
|
226
|
+
for (const turn of turns) {
|
|
227
|
+
const timestamp = new Date(baseTime + turnIndex * 3e3).toISOString();
|
|
228
|
+
turnIndex++;
|
|
229
|
+
if (turn.role === "user") {
|
|
230
|
+
lines.push(
|
|
231
|
+
JSON.stringify({
|
|
232
|
+
type: "queue-operation",
|
|
233
|
+
operation: "enqueue",
|
|
234
|
+
timestamp,
|
|
235
|
+
sessionId: config.sessionId
|
|
236
|
+
})
|
|
237
|
+
);
|
|
238
|
+
lines.push(
|
|
239
|
+
JSON.stringify({
|
|
240
|
+
type: "queue-operation",
|
|
241
|
+
operation: "dequeue",
|
|
242
|
+
timestamp,
|
|
243
|
+
sessionId: config.sessionId
|
|
244
|
+
})
|
|
245
|
+
);
|
|
246
|
+
const uuid = randomUUID();
|
|
247
|
+
const textParts = turn.content.filter(
|
|
248
|
+
(block) => "text" in block && typeof block.text === "string" && block.text
|
|
249
|
+
).map((block) => block.text);
|
|
250
|
+
const userText = textParts.length > 0 ? textParts.join("") : " ";
|
|
251
|
+
lines.push(
|
|
252
|
+
JSON.stringify({
|
|
253
|
+
parentUuid,
|
|
254
|
+
isSidechain: false,
|
|
255
|
+
userType: "external",
|
|
256
|
+
cwd: config.cwd,
|
|
257
|
+
sessionId: config.sessionId,
|
|
258
|
+
version,
|
|
259
|
+
gitBranch,
|
|
260
|
+
slug,
|
|
261
|
+
type: "user",
|
|
262
|
+
message: {
|
|
263
|
+
role: "user",
|
|
264
|
+
content: [{ type: "text", text: userText }]
|
|
265
|
+
},
|
|
266
|
+
uuid,
|
|
267
|
+
timestamp,
|
|
268
|
+
permissionMode
|
|
269
|
+
})
|
|
270
|
+
);
|
|
271
|
+
parentUuid = uuid;
|
|
272
|
+
} else {
|
|
273
|
+
const allBlocks = [];
|
|
274
|
+
for (const block of turn.content) {
|
|
275
|
+
const blockType = block.type;
|
|
276
|
+
if (blockType === "thinking" || blockType === "text") {
|
|
277
|
+
allBlocks.push(block);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (turn.toolCalls) {
|
|
281
|
+
for (const tc of turn.toolCalls) {
|
|
282
|
+
allBlocks.push({
|
|
283
|
+
type: "tool_use",
|
|
284
|
+
id: tc.toolCallId,
|
|
285
|
+
name: tc.toolName,
|
|
286
|
+
input: tc.input
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const msgId = generateMessageId();
|
|
291
|
+
const hasToolUse = allBlocks.some(
|
|
292
|
+
(b) => b.type === "tool_use"
|
|
293
|
+
);
|
|
294
|
+
const lastStopReason = hasToolUse ? "tool_use" : "end_turn";
|
|
295
|
+
for (let i = 0; i < allBlocks.length; i++) {
|
|
296
|
+
const block = allBlocks[i];
|
|
297
|
+
const isLast = i === allBlocks.length - 1;
|
|
298
|
+
const uuid = randomUUID();
|
|
299
|
+
lines.push(
|
|
300
|
+
JSON.stringify({
|
|
301
|
+
parentUuid,
|
|
302
|
+
isSidechain: false,
|
|
303
|
+
userType: "external",
|
|
304
|
+
cwd: config.cwd,
|
|
305
|
+
sessionId: config.sessionId,
|
|
306
|
+
version,
|
|
307
|
+
gitBranch,
|
|
308
|
+
slug,
|
|
309
|
+
type: "assistant",
|
|
310
|
+
message: {
|
|
311
|
+
model,
|
|
312
|
+
id: msgId,
|
|
313
|
+
type: "message",
|
|
314
|
+
role: "assistant",
|
|
315
|
+
content: [block],
|
|
316
|
+
stop_reason: isLast ? lastStopReason : null,
|
|
317
|
+
stop_sequence: null,
|
|
318
|
+
usage: {
|
|
319
|
+
input_tokens: 0,
|
|
320
|
+
cache_creation_input_tokens: 0,
|
|
321
|
+
cache_read_input_tokens: 0,
|
|
322
|
+
output_tokens: 0
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
uuid,
|
|
326
|
+
timestamp
|
|
327
|
+
})
|
|
328
|
+
);
|
|
329
|
+
parentUuid = uuid;
|
|
330
|
+
}
|
|
331
|
+
if (turn.toolCalls) {
|
|
332
|
+
for (const tc of turn.toolCalls) {
|
|
333
|
+
if (tc.result === void 0) continue;
|
|
334
|
+
const uuid = randomUUID();
|
|
335
|
+
const resultText = typeof tc.result === "string" ? tc.result : JSON.stringify(tc.result);
|
|
336
|
+
lines.push(
|
|
337
|
+
JSON.stringify({
|
|
338
|
+
parentUuid,
|
|
339
|
+
isSidechain: false,
|
|
340
|
+
userType: "external",
|
|
341
|
+
cwd: config.cwd,
|
|
342
|
+
sessionId: config.sessionId,
|
|
343
|
+
version,
|
|
344
|
+
gitBranch,
|
|
345
|
+
slug,
|
|
346
|
+
type: "user",
|
|
347
|
+
message: {
|
|
348
|
+
role: "user",
|
|
349
|
+
content: [
|
|
350
|
+
{
|
|
351
|
+
type: "tool_result",
|
|
352
|
+
tool_use_id: tc.toolCallId,
|
|
353
|
+
content: resultText
|
|
354
|
+
}
|
|
355
|
+
]
|
|
356
|
+
},
|
|
357
|
+
uuid,
|
|
358
|
+
timestamp
|
|
359
|
+
})
|
|
360
|
+
);
|
|
361
|
+
parentUuid = uuid;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return lines;
|
|
367
|
+
}
|
|
368
|
+
async function hydrateSessionJsonl(params) {
|
|
369
|
+
const { posthogAPI, log } = params;
|
|
370
|
+
try {
|
|
371
|
+
const jsonlPath = getSessionJsonlPath(params.sessionId, params.cwd);
|
|
372
|
+
try {
|
|
373
|
+
await fs.access(jsonlPath);
|
|
374
|
+
log.info("Local JSONL exists, skipping S3 hydration", {
|
|
375
|
+
sessionId: params.sessionId
|
|
376
|
+
});
|
|
377
|
+
return;
|
|
378
|
+
} catch {
|
|
379
|
+
}
|
|
380
|
+
const taskRun = await posthogAPI.getTaskRun(params.taskId, params.runId);
|
|
381
|
+
if (!taskRun.log_url) {
|
|
382
|
+
log.info("No log URL, skipping JSONL hydration");
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const entries = await posthogAPI.fetchTaskRunLogs(taskRun);
|
|
386
|
+
if (entries.length === 0) {
|
|
387
|
+
log.info("No S3 log entries, skipping JSONL hydration");
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const entryCounts = {};
|
|
391
|
+
for (const entry of entries) {
|
|
392
|
+
const method = entry.notification?.method ?? "unknown";
|
|
393
|
+
const entryParams = entry.notification?.params;
|
|
394
|
+
const update = entryParams?.update;
|
|
395
|
+
const key = update?.sessionUpdate ? `${method}:${update.sessionUpdate}` : method;
|
|
396
|
+
entryCounts[key] = (entryCounts[key] ?? 0) + 1;
|
|
397
|
+
}
|
|
398
|
+
log.info("S3 log entry breakdown", {
|
|
399
|
+
totalEntries: entries.length,
|
|
400
|
+
types: entryCounts
|
|
401
|
+
});
|
|
402
|
+
const allTurns = rebuildConversation(entries);
|
|
403
|
+
if (allTurns.length === 0) {
|
|
404
|
+
log.info("No conversation in S3 logs, skipping JSONL hydration");
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const conversation = selectRecentTurns(allTurns);
|
|
408
|
+
log.info("Selected recent turns for hydration", {
|
|
409
|
+
totalTurns: allTurns.length,
|
|
410
|
+
selectedTurns: conversation.length,
|
|
411
|
+
turnRoles: conversation.map((t) => t.role)
|
|
412
|
+
});
|
|
413
|
+
const jsonlLines = conversationTurnsToJsonlEntries(conversation, {
|
|
414
|
+
sessionId: params.sessionId,
|
|
415
|
+
cwd: params.cwd,
|
|
416
|
+
model: params.model,
|
|
417
|
+
gitBranch: params.gitBranch,
|
|
418
|
+
permissionMode: params.permissionMode
|
|
419
|
+
});
|
|
420
|
+
await fs.mkdir(path.dirname(jsonlPath), { recursive: true });
|
|
421
|
+
const tmpPath = `${jsonlPath}.tmp.${Date.now()}`;
|
|
422
|
+
await fs.writeFile(tmpPath, `${jsonlLines.join("\n")}
|
|
423
|
+
`);
|
|
424
|
+
await fs.rename(tmpPath, jsonlPath);
|
|
425
|
+
log.info("Hydrated session JSONL from S3", {
|
|
426
|
+
sessionId: params.sessionId,
|
|
427
|
+
turns: conversation.length,
|
|
428
|
+
lines: jsonlLines.length
|
|
429
|
+
});
|
|
430
|
+
} catch (err) {
|
|
431
|
+
log.warn("Failed to hydrate session JSONL, continuing", {
|
|
432
|
+
sessionId: params.sessionId,
|
|
433
|
+
error: err instanceof Error ? err.message : String(err)
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
export {
|
|
438
|
+
conversationTurnsToJsonlEntries,
|
|
439
|
+
getSessionJsonlPath,
|
|
440
|
+
hydrateSessionJsonl,
|
|
441
|
+
rebuildConversation,
|
|
442
|
+
selectRecentTurns
|
|
443
|
+
};
|
|
444
|
+
//# sourceMappingURL=jsonl-hydration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/adapters/claude/session/jsonl-hydration.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ContentBlock } from \"@agentclientprotocol/sdk\";\nimport type { PostHogAPIClient } from \"../../../posthog-api.js\";\nimport type { StoredEntry } from \"../../../types.js\";\n\ninterface ConversationTurn {\n role: \"user\" | \"assistant\";\n content: ContentBlock[];\n toolCalls?: ToolCallInfo[];\n}\n\ninterface ToolCallInfo {\n toolCallId: string;\n toolName: string;\n input: unknown;\n result?: unknown;\n}\n\ninterface JsonlConfig {\n sessionId: string;\n cwd: string;\n model?: string;\n version?: string;\n gitBranch?: string;\n slug?: string;\n permissionMode?: string;\n}\n\ninterface ClaudeCodeMeta {\n toolCallId?: string;\n toolName?: string;\n toolInput?: unknown;\n toolResponse?: unknown;\n}\n\ninterface SessionUpdate {\n sessionUpdate: string;\n content?: ContentBlock | ContentBlock[];\n _meta?: { claudeCode?: ClaudeCodeMeta };\n}\n\nconst MAX_PROJECT_KEY_LENGTH = 200;\n\nfunction hashString(s: string): string {\n let hash = 0;\n for (let i = 0; i < s.length; i++) {\n hash = (hash << 5) - hash + s.charCodeAt(i);\n hash |= 0;\n }\n return Math.abs(hash).toString(36);\n}\n\nexport function getSessionJsonlPath(sessionId: string, cwd: string): string {\n const configDir =\n process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), \".claude\");\n let projectKey = cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n if (projectKey.length > MAX_PROJECT_KEY_LENGTH) {\n projectKey = `${projectKey.slice(0, MAX_PROJECT_KEY_LENGTH)}-${hashString(cwd)}`;\n }\n return path.join(configDir, \"projects\", projectKey, `${sessionId}.jsonl`);\n}\n\nexport function rebuildConversation(\n entries: StoredEntry[],\n): ConversationTurn[] {\n const turns: ConversationTurn[] = [];\n let currentAssistantContent: ContentBlock[] = [];\n let currentToolCalls: ToolCallInfo[] = [];\n\n for (const entry of entries) {\n const method = entry.notification?.method;\n const params = entry.notification?.params as Record<string, unknown>;\n\n if (method === \"session/update\" && params?.update) {\n const update = params.update as SessionUpdate;\n\n switch (update.sessionUpdate) {\n case \"user_message\":\n case \"user_message_chunk\": {\n if (\n currentAssistantContent.length > 0 ||\n currentToolCalls.length > 0\n ) {\n turns.push({\n role: \"assistant\",\n content: currentAssistantContent,\n toolCalls:\n currentToolCalls.length > 0 ? currentToolCalls : undefined,\n });\n currentAssistantContent = [];\n currentToolCalls = [];\n }\n\n const content = update.content;\n const contentArray = Array.isArray(content)\n ? content\n : content\n ? [content]\n : [];\n\n const lastTurn = turns[turns.length - 1];\n if (lastTurn?.role === \"user\") {\n lastTurn.content.push(...contentArray);\n } else {\n turns.push({ role: \"user\", content: contentArray });\n }\n break;\n }\n\n case \"agent_message\":\n case \"agent_message_chunk\":\n case \"agent_thought_chunk\": {\n const content = update.content;\n if (content && !Array.isArray(content)) {\n if (\n content.type === \"text\" &&\n currentAssistantContent.length > 0 &&\n currentAssistantContent[currentAssistantContent.length - 1]\n .type === \"text\"\n ) {\n const lastBlock = currentAssistantContent[\n currentAssistantContent.length - 1\n ] as { type: \"text\"; text: string };\n lastBlock.text += (\n content as { type: \"text\"; text: string }\n ).text;\n } else {\n currentAssistantContent.push(content);\n }\n }\n break;\n }\n\n case \"tool_call\":\n case \"tool_call_update\": {\n const meta = update._meta?.claudeCode;\n if (meta) {\n const { toolCallId, toolName, toolInput, toolResponse } = meta;\n\n if (toolCallId && toolName) {\n let toolCall = currentToolCalls.find(\n (tc) => tc.toolCallId === toolCallId,\n );\n if (!toolCall) {\n toolCall = { toolCallId, toolName, input: toolInput };\n currentToolCalls.push(toolCall);\n }\n if (toolResponse !== undefined) {\n toolCall.result = toolResponse;\n }\n }\n }\n break;\n }\n\n case \"tool_result\": {\n const meta = update._meta?.claudeCode;\n if (meta) {\n const { toolCallId, toolResponse } = meta;\n if (toolCallId) {\n const toolCall = currentToolCalls.find(\n (tc) => tc.toolCallId === toolCallId,\n );\n if (toolCall && toolResponse !== undefined) {\n toolCall.result = toolResponse;\n }\n }\n }\n break;\n }\n }\n }\n }\n\n if (currentAssistantContent.length > 0 || currentToolCalls.length > 0) {\n turns.push({\n role: \"assistant\",\n content: currentAssistantContent,\n toolCalls: currentToolCalls.length > 0 ? currentToolCalls : undefined,\n });\n }\n\n return turns;\n}\n\nconst CHARS_PER_TOKEN = 4;\nconst DEFAULT_MAX_TOKENS = 150_000;\n\nfunction estimateTurnTokens(turn: ConversationTurn): number {\n let chars = 0;\n for (const block of turn.content) {\n if (\"text\" in block && typeof block.text === \"string\") {\n chars += block.text.length;\n }\n }\n if (turn.toolCalls) {\n for (const tc of turn.toolCalls) {\n chars += JSON.stringify(tc.input ?? \"\").length;\n if (tc.result !== undefined) {\n chars +=\n typeof tc.result === \"string\"\n ? tc.result.length\n : JSON.stringify(tc.result).length;\n }\n }\n }\n return Math.ceil(chars / CHARS_PER_TOKEN);\n}\n\nexport function selectRecentTurns(\n turns: ConversationTurn[],\n maxTokens = DEFAULT_MAX_TOKENS,\n): ConversationTurn[] {\n let budget = maxTokens;\n let startIndex = turns.length;\n\n for (let i = turns.length - 1; i >= 0; i--) {\n const cost = estimateTurnTokens(turns[i]);\n if (cost > budget) break;\n budget -= cost;\n startIndex = i;\n }\n\n // Ensure we start on a user turn so the conversation is well-formed\n while (startIndex < turns.length && turns[startIndex].role !== \"user\") {\n startIndex++;\n }\n\n return turns.slice(startIndex);\n}\n\nconst BASE62 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n\nfunction generateMessageId(): string {\n const bytes = new Uint8Array(24);\n crypto.getRandomValues(bytes);\n let id = \"msg_01\";\n for (const b of bytes) {\n id += BASE62[b % 62];\n }\n return id;\n}\n\nconst ADJECTIVES = [\n \"bright\",\n \"calm\",\n \"daring\",\n \"eager\",\n \"fair\",\n \"gentle\",\n \"happy\",\n \"keen\",\n \"lively\",\n \"merry\",\n \"noble\",\n \"polite\",\n \"quick\",\n \"sharp\",\n \"warm\",\n \"witty\",\n];\nconst VERBS = [\n \"blazing\",\n \"crafting\",\n \"dashing\",\n \"flowing\",\n \"gliding\",\n \"humming\",\n \"jumping\",\n \"linking\",\n \"melting\",\n \"nesting\",\n \"pacing\",\n \"roaming\",\n \"sailing\",\n \"turning\",\n \"waving\",\n \"zoning\",\n];\nconst NOUNS = [\n \"aurora\",\n \"breeze\",\n \"cedar\",\n \"delta\",\n \"ember\",\n \"frost\",\n \"grove\",\n \"haven\",\n \"inlet\",\n \"jewel\",\n \"knoll\",\n \"lotus\",\n \"maple\",\n \"nexus\",\n \"oasis\",\n \"prism\",\n];\n\nfunction generateSlug(): string {\n const pick = (arr: string[]) => arr[Math.floor(Math.random() * arr.length)];\n return `${pick(ADJECTIVES)}-${pick(VERBS)}-${pick(NOUNS)}`;\n}\n\nexport function conversationTurnsToJsonlEntries(\n turns: ConversationTurn[],\n config: JsonlConfig,\n): string[] {\n const lines: string[] = [];\n let parentUuid: string | null = null;\n const model = config.model ?? \"claude-opus-4-6\";\n const version = config.version ?? \"2.1.63\";\n const gitBranch = config.gitBranch ?? \"\";\n const slug = config.slug ?? generateSlug();\n const permissionMode = config.permissionMode ?? \"default\";\n const baseTime = Date.now() - turns.length * 3000;\n let turnIndex = 0;\n\n for (const turn of turns) {\n const timestamp = new Date(baseTime + turnIndex * 3000).toISOString();\n turnIndex++;\n if (turn.role === \"user\") {\n lines.push(\n JSON.stringify({\n type: \"queue-operation\",\n operation: \"enqueue\",\n timestamp,\n sessionId: config.sessionId,\n }),\n );\n lines.push(\n JSON.stringify({\n type: \"queue-operation\",\n operation: \"dequeue\",\n timestamp,\n sessionId: config.sessionId,\n }),\n );\n\n const uuid = randomUUID();\n const textParts = turn.content\n .filter(\n (block) =>\n \"text\" in block && typeof block.text === \"string\" && block.text,\n )\n .map((block) => (block as { text: string }).text);\n\n const userText = textParts.length > 0 ? textParts.join(\"\") : \" \";\n\n lines.push(\n JSON.stringify({\n parentUuid,\n isSidechain: false,\n userType: \"external\",\n cwd: config.cwd,\n sessionId: config.sessionId,\n version,\n gitBranch,\n slug,\n type: \"user\",\n message: {\n role: \"user\",\n content: [{ type: \"text\", text: userText }],\n },\n uuid,\n timestamp,\n permissionMode,\n }),\n );\n parentUuid = uuid;\n } else {\n const allBlocks: unknown[] = [];\n\n for (const block of turn.content) {\n const blockType = (block as { type: string }).type;\n if (blockType === \"thinking\" || blockType === \"text\") {\n allBlocks.push(block);\n }\n }\n\n if (turn.toolCalls) {\n for (const tc of turn.toolCalls) {\n allBlocks.push({\n type: \"tool_use\",\n id: tc.toolCallId,\n name: tc.toolName,\n input: tc.input,\n });\n }\n }\n\n const msgId = generateMessageId();\n const hasToolUse = allBlocks.some(\n (b) => (b as { type: string }).type === \"tool_use\",\n );\n const lastStopReason = hasToolUse ? \"tool_use\" : \"end_turn\";\n\n for (let i = 0; i < allBlocks.length; i++) {\n const block = allBlocks[i];\n const isLast = i === allBlocks.length - 1;\n const uuid = randomUUID();\n\n lines.push(\n JSON.stringify({\n parentUuid,\n isSidechain: false,\n userType: \"external\",\n cwd: config.cwd,\n sessionId: config.sessionId,\n version,\n gitBranch,\n slug,\n type: \"assistant\",\n message: {\n model,\n id: msgId,\n type: \"message\",\n role: \"assistant\",\n content: [block],\n stop_reason: isLast ? lastStopReason : null,\n stop_sequence: null,\n usage: {\n input_tokens: 0,\n cache_creation_input_tokens: 0,\n cache_read_input_tokens: 0,\n output_tokens: 0,\n },\n },\n uuid,\n timestamp,\n }),\n );\n parentUuid = uuid;\n }\n\n if (turn.toolCalls) {\n for (const tc of turn.toolCalls) {\n if (tc.result === undefined) continue;\n\n const uuid = randomUUID();\n const resultText =\n typeof tc.result === \"string\"\n ? tc.result\n : JSON.stringify(tc.result);\n\n lines.push(\n JSON.stringify({\n parentUuid,\n isSidechain: false,\n userType: \"external\",\n cwd: config.cwd,\n sessionId: config.sessionId,\n version,\n gitBranch,\n slug,\n type: \"user\",\n message: {\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: tc.toolCallId,\n content: resultText,\n },\n ],\n },\n uuid,\n timestamp,\n }),\n );\n parentUuid = uuid;\n }\n }\n }\n }\n\n return lines;\n}\n\ninterface HydrationLog {\n info: (msg: string, data?: unknown) => void;\n warn: (msg: string, data?: unknown) => void;\n}\n\nexport async function hydrateSessionJsonl(params: {\n sessionId: string;\n cwd: string;\n taskId: string;\n runId: string;\n model?: string;\n gitBranch?: string;\n permissionMode?: string;\n posthogAPI: PostHogAPIClient;\n log: HydrationLog;\n}): Promise<void> {\n const { posthogAPI, log } = params;\n\n try {\n const jsonlPath = getSessionJsonlPath(params.sessionId, params.cwd);\n try {\n await fs.access(jsonlPath);\n log.info(\"Local JSONL exists, skipping S3 hydration\", {\n sessionId: params.sessionId,\n });\n return;\n } catch {\n // File doesn't exist, proceed with hydration\n }\n\n const taskRun = await posthogAPI.getTaskRun(params.taskId, params.runId);\n if (!taskRun.log_url) {\n log.info(\"No log URL, skipping JSONL hydration\");\n return;\n }\n\n const entries = await posthogAPI.fetchTaskRunLogs(taskRun);\n if (entries.length === 0) {\n log.info(\"No S3 log entries, skipping JSONL hydration\");\n return;\n }\n\n const entryCounts: Record<string, number> = {};\n for (const entry of entries) {\n const method = entry.notification?.method ?? \"unknown\";\n const entryParams = entry.notification?.params as\n | Record<string, unknown>\n | undefined;\n const update = entryParams?.update as\n | { sessionUpdate?: string }\n | undefined;\n const key = update?.sessionUpdate\n ? `${method}:${update.sessionUpdate}`\n : method;\n entryCounts[key] = (entryCounts[key] ?? 0) + 1;\n }\n log.info(\"S3 log entry breakdown\", {\n totalEntries: entries.length,\n types: entryCounts,\n });\n\n const allTurns = rebuildConversation(entries);\n if (allTurns.length === 0) {\n log.info(\"No conversation in S3 logs, skipping JSONL hydration\");\n return;\n }\n\n const conversation = selectRecentTurns(allTurns);\n log.info(\"Selected recent turns for hydration\", {\n totalTurns: allTurns.length,\n selectedTurns: conversation.length,\n turnRoles: conversation.map((t) => t.role),\n });\n\n const jsonlLines = conversationTurnsToJsonlEntries(conversation, {\n sessionId: params.sessionId,\n cwd: params.cwd,\n model: params.model,\n gitBranch: params.gitBranch,\n permissionMode: params.permissionMode,\n });\n\n await fs.mkdir(path.dirname(jsonlPath), { recursive: true });\n\n const tmpPath = `${jsonlPath}.tmp.${Date.now()}`;\n await fs.writeFile(tmpPath, `${jsonlLines.join(\"\\n\")}\\n`);\n await fs.rename(tmpPath, jsonlPath);\n\n log.info(\"Hydrated session JSONL from S3\", {\n sessionId: params.sessionId,\n turns: conversation.length,\n lines: jsonlLines.length,\n });\n } catch (err) {\n log.warn(\"Failed to hydrate session JSONL, continuing\", {\n sessionId: params.sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/agent.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AgentSideConnection } from '@agentclientprotocol/sdk';
|
|
2
|
+
import { PostHogAPIClient } from './posthog-api.js';
|
|
2
3
|
import { AgentConfig, TaskExecutionOptions } from './types.js';
|
|
3
4
|
|
|
4
5
|
type StreamPair = {
|
|
@@ -23,6 +24,7 @@ declare class Agent {
|
|
|
23
24
|
private _configureLlmGateway;
|
|
24
25
|
run(taskId: string, taskRunId: string, options?: TaskExecutionOptions): Promise<InProcessAcpConnection>;
|
|
25
26
|
attachPullRequestToTask(taskId: string, prUrl: string, branchName?: string): Promise<void>;
|
|
27
|
+
getPosthogAPI(): PostHogAPIClient | undefined;
|
|
26
28
|
flushAllLogs(): Promise<void>;
|
|
27
29
|
cleanup(): Promise<void>;
|
|
28
30
|
}
|
package/dist/agent.js
CHANGED
|
@@ -279,7 +279,7 @@ import { v7 as uuidv7 } from "uuid";
|
|
|
279
279
|
// package.json
|
|
280
280
|
var package_default = {
|
|
281
281
|
name: "@posthog/agent",
|
|
282
|
-
version: "2.1.
|
|
282
|
+
version: "2.1.138",
|
|
283
283
|
repository: "https://github.com/PostHog/twig",
|
|
284
284
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
285
285
|
exports: {
|
|
@@ -319,6 +319,10 @@ var package_default = {
|
|
|
319
319
|
types: "./dist/adapters/claude/conversion/tool-use-to-acp.d.ts",
|
|
320
320
|
import: "./dist/adapters/claude/conversion/tool-use-to-acp.js"
|
|
321
321
|
},
|
|
322
|
+
"./adapters/claude/session/jsonl-hydration": {
|
|
323
|
+
types: "./dist/adapters/claude/session/jsonl-hydration.d.ts",
|
|
324
|
+
import: "./dist/adapters/claude/session/jsonl-hydration.js"
|
|
325
|
+
},
|
|
322
326
|
"./server": {
|
|
323
327
|
types: "./dist/server/agent-server.d.ts",
|
|
324
328
|
import: "./dist/server/agent-server.js"
|
|
@@ -870,8 +874,9 @@ function toolInfoFromToolUse(toolUse, options) {
|
|
|
870
874
|
const input = toolUse.input;
|
|
871
875
|
switch (name) {
|
|
872
876
|
case "Task":
|
|
877
|
+
case "Agent":
|
|
873
878
|
return {
|
|
874
|
-
title: input?.description ? String(input.description) :
|
|
879
|
+
title: input?.description ? String(input.description) : name,
|
|
875
880
|
kind: "think",
|
|
876
881
|
content: input?.prompt ? toolContent().text(String(input.prompt)).build() : []
|
|
877
882
|
};
|
|
@@ -3658,7 +3663,7 @@ function spawnCodexProcess(options) {
|
|
|
3658
3663
|
detached: process.platform !== "win32"
|
|
3659
3664
|
});
|
|
3660
3665
|
child.stderr?.on("data", (data) => {
|
|
3661
|
-
logger.
|
|
3666
|
+
logger.debug("codex-acp stderr:", data.toString());
|
|
3662
3667
|
});
|
|
3663
3668
|
child.on("error", (err) => {
|
|
3664
3669
|
logger.error("codex-acp process error:", err);
|
|
@@ -4591,6 +4596,9 @@ var Agent = class {
|
|
|
4591
4596
|
prUrl
|
|
4592
4597
|
});
|
|
4593
4598
|
}
|
|
4599
|
+
getPosthogAPI() {
|
|
4600
|
+
return this.posthogAPI;
|
|
4601
|
+
}
|
|
4594
4602
|
async flushAllLogs() {
|
|
4595
4603
|
await this.sessionLogWriter?.flushAll();
|
|
4596
4604
|
}
|