@posthog/agent 2.3.46 → 2.3.62
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.map +1 -1
- package/dist/adapters/claude/tools.js.map +1 -1
- package/dist/agent.js +40 -7
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.d.ts +4 -0
- package/dist/server/agent-server.js +129 -10
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +129 -10
- package/dist/server/bin.cjs.map +1 -1
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/adapters/claude/claude-agent.ts +12 -2
- package/src/adapters/claude/conversion/sdk-to-acp.ts +22 -1
- package/src/adapters/claude/mcp/tool-metadata.ts +10 -0
- package/src/index.ts +5 -1
- package/src/server/agent-server.ts +119 -4
- package/src/server/question-relay.test.ts +17 -3
- package/src/session-log-writer.ts +17 -1
- package/src/types.ts +1 -0
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -55,7 +55,10 @@ import {
|
|
|
55
55
|
handleSystemMessage,
|
|
56
56
|
handleUserAssistantMessage,
|
|
57
57
|
} from "./conversion/sdk-to-acp";
|
|
58
|
-
import {
|
|
58
|
+
import {
|
|
59
|
+
fetchMcpToolMetadata,
|
|
60
|
+
getConnectedMcpServerNames,
|
|
61
|
+
} from "./mcp/tool-metadata";
|
|
59
62
|
import { canUseTool } from "./permissions/permission-handlers";
|
|
60
63
|
import { getAvailableSlashCommands } from "./session/commands";
|
|
61
64
|
import { parseMcpServers } from "./session/mcp-config";
|
|
@@ -101,6 +104,7 @@ function sanitizeTitle(text: string): string {
|
|
|
101
104
|
export interface ClaudeAcpAgentOptions {
|
|
102
105
|
onProcessSpawned?: (info: ProcessSpawnedInfo) => void;
|
|
103
106
|
onProcessExited?: (pid: number) => void;
|
|
107
|
+
onMcpServersReady?: (serverNames: string[]) => void;
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
@@ -1020,11 +1024,17 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
|
|
|
1020
1024
|
* Both populate caches used later — neither is needed to return configOptions.
|
|
1021
1025
|
*/
|
|
1022
1026
|
private deferBackgroundFetches(q: Query): void {
|
|
1027
|
+
this.logger.info("Starting background fetches (commands + MCP metadata)");
|
|
1023
1028
|
Promise.all([
|
|
1024
1029
|
new Promise<void>((resolve) => setTimeout(resolve, 10)).then(() =>
|
|
1025
1030
|
this.sendAvailableCommandsUpdate(),
|
|
1026
1031
|
),
|
|
1027
|
-
fetchMcpToolMetadata(q, this.logger)
|
|
1032
|
+
fetchMcpToolMetadata(q, this.logger).then(() => {
|
|
1033
|
+
const serverNames = getConnectedMcpServerNames();
|
|
1034
|
+
if (serverNames.length > 0) {
|
|
1035
|
+
this.options?.onMcpServersReady?.(serverNames);
|
|
1036
|
+
}
|
|
1037
|
+
}),
|
|
1028
1038
|
]).catch((err) =>
|
|
1029
1039
|
this.logger.error("Background fetch failed", { error: err }),
|
|
1030
1040
|
);
|
|
@@ -56,6 +56,8 @@ type ChunkHandlerContext = {
|
|
|
56
56
|
registerHooks?: boolean;
|
|
57
57
|
supportsTerminalOutput?: boolean;
|
|
58
58
|
cwd?: string;
|
|
59
|
+
/** Raw MCP tool result from SDKUserMessage.tool_use_result (contains content, structuredContent, _meta) */
|
|
60
|
+
mcpToolUseResult?: Record<string, unknown>;
|
|
59
61
|
};
|
|
60
62
|
|
|
61
63
|
export interface MessageHandlerContext {
|
|
@@ -348,7 +350,16 @@ function handleToolResultChunk(
|
|
|
348
350
|
toolCallId: chunk.tool_use_id,
|
|
349
351
|
sessionUpdate: "tool_call_update",
|
|
350
352
|
status: chunk.is_error ? "failed" : "completed",
|
|
351
|
-
rawOutput:
|
|
353
|
+
rawOutput: ctx.mcpToolUseResult
|
|
354
|
+
? { ...ctx.mcpToolUseResult, isError: chunk.is_error ?? false }
|
|
355
|
+
: {
|
|
356
|
+
content: Array.isArray(chunk.content)
|
|
357
|
+
? chunk.content
|
|
358
|
+
: typeof chunk.content === "string"
|
|
359
|
+
? [{ type: "text" as const, text: chunk.content }]
|
|
360
|
+
: [],
|
|
361
|
+
isError: chunk.is_error ?? false,
|
|
362
|
+
},
|
|
352
363
|
...toolUpdate,
|
|
353
364
|
});
|
|
354
365
|
|
|
@@ -435,6 +446,7 @@ function toAcpNotifications(
|
|
|
435
446
|
registerHooks?: boolean,
|
|
436
447
|
supportsTerminalOutput?: boolean,
|
|
437
448
|
cwd?: string,
|
|
449
|
+
mcpToolUseResult?: Record<string, unknown>,
|
|
438
450
|
): SessionNotification[] {
|
|
439
451
|
if (typeof content === "string") {
|
|
440
452
|
const update: SessionUpdate = {
|
|
@@ -461,6 +473,7 @@ function toAcpNotifications(
|
|
|
461
473
|
registerHooks,
|
|
462
474
|
supportsTerminalOutput,
|
|
463
475
|
cwd,
|
|
476
|
+
mcpToolUseResult,
|
|
464
477
|
};
|
|
465
478
|
const output: SessionNotification[] = [];
|
|
466
479
|
|
|
@@ -829,6 +842,13 @@ export async function handleUserAssistantMessage(
|
|
|
829
842
|
? (message.parent_tool_use_id ?? undefined)
|
|
830
843
|
: undefined;
|
|
831
844
|
|
|
845
|
+
// Pass the raw MCP tool result (contains content, structuredContent, _meta)
|
|
846
|
+
// so it can be forwarded as-is to the renderer for MCP Apps
|
|
847
|
+
const mcpToolUseResult =
|
|
848
|
+
message.type === "user" && message.tool_use_result != null
|
|
849
|
+
? (message.tool_use_result as Record<string, unknown>)
|
|
850
|
+
: undefined;
|
|
851
|
+
|
|
832
852
|
for (const notification of toAcpNotifications(
|
|
833
853
|
contentToProcess as typeof content,
|
|
834
854
|
message.message.role,
|
|
@@ -841,6 +861,7 @@ export async function handleUserAssistantMessage(
|
|
|
841
861
|
context.registerHooks,
|
|
842
862
|
context.supportsTerminalOutput,
|
|
843
863
|
session.cwd,
|
|
864
|
+
mcpToolUseResult,
|
|
844
865
|
)) {
|
|
845
866
|
await client.sessionUpdate(notification);
|
|
846
867
|
session.notificationHistory.push(notification);
|
|
@@ -48,6 +48,7 @@ export async function fetchMcpToolMetadata(
|
|
|
48
48
|
for (const tool of server.tools) {
|
|
49
49
|
const toolKey = buildToolKey(server.name, tool.name);
|
|
50
50
|
const readOnly = tool.annotations?.readOnly === true;
|
|
51
|
+
|
|
51
52
|
mcpToolMetadataCache.set(toolKey, {
|
|
52
53
|
readOnly,
|
|
53
54
|
name: tool.name,
|
|
@@ -94,6 +95,15 @@ export function isMcpToolReadOnly(toolName: string): boolean {
|
|
|
94
95
|
return metadata?.readOnly === true;
|
|
95
96
|
}
|
|
96
97
|
|
|
98
|
+
export function getConnectedMcpServerNames(): string[] {
|
|
99
|
+
const names = new Set<string>();
|
|
100
|
+
for (const key of mcpToolMetadataCache.keys()) {
|
|
101
|
+
const parts = key.split("__");
|
|
102
|
+
if (parts.length >= 3) names.add(parts[1]);
|
|
103
|
+
}
|
|
104
|
+
return [...names];
|
|
105
|
+
}
|
|
106
|
+
|
|
97
107
|
export function clearMcpToolMetadataCache(): void {
|
|
98
108
|
mcpToolMetadataCache.clear();
|
|
99
109
|
}
|
package/src/index.ts
CHANGED
|
@@ -162,6 +162,12 @@ export class AgentServer {
|
|
|
162
162
|
private questionRelayedToSlack = false;
|
|
163
163
|
private detectedPrUrl: string | null = null;
|
|
164
164
|
private resumeState: ResumeState | null = null;
|
|
165
|
+
// Guards against concurrent session initialization. autoInitializeSession() and
|
|
166
|
+
// the GET /events SSE handler can both call initializeSession() — the SSE connection
|
|
167
|
+
// often arrives while newSession() is still awaited (this.session is still null),
|
|
168
|
+
// causing a second session to be created and duplicate Slack messages to be sent.
|
|
169
|
+
private initializationPromise: Promise<void> | null = null;
|
|
170
|
+
private pendingEvents: Record<string, unknown>[] = [];
|
|
165
171
|
|
|
166
172
|
private emitConsoleLog = (
|
|
167
173
|
level: LogLevel,
|
|
@@ -264,6 +270,7 @@ export class AgentServer {
|
|
|
264
270
|
await this.initializeSession(payload, sseController);
|
|
265
271
|
} else {
|
|
266
272
|
this.session.sseController = sseController;
|
|
273
|
+
this.replayPendingEvents();
|
|
267
274
|
}
|
|
268
275
|
|
|
269
276
|
this.sendSseEvent(sseController, {
|
|
@@ -483,6 +490,8 @@ export class AgentServer {
|
|
|
483
490
|
`Processing user message (detectedPrUrl=${this.detectedPrUrl ?? "none"}): ${content.substring(0, 100)}...`,
|
|
484
491
|
);
|
|
485
492
|
|
|
493
|
+
this.session.logWriter.resetTurnMessages(this.session.payload.run_id);
|
|
494
|
+
|
|
486
495
|
const result = await this.session.clientConnection.prompt({
|
|
487
496
|
sessionId: this.session.acpSessionId,
|
|
488
497
|
prompt: [{ type: "text", text: content }],
|
|
@@ -501,7 +510,31 @@ export class AgentServer {
|
|
|
501
510
|
|
|
502
511
|
this.broadcastTurnComplete(result.stopReason);
|
|
503
512
|
|
|
504
|
-
|
|
513
|
+
if (result.stopReason === "end_turn") {
|
|
514
|
+
// Relay the response to Slack. For follow-ups this is the primary
|
|
515
|
+
// delivery path — the HTTP caller only handles reactions.
|
|
516
|
+
this.relayAgentResponse(this.session.payload).catch((err) =>
|
|
517
|
+
this.logger.warn("Failed to relay follow-up response", err),
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Flush logs and include the assistant's response text so callers
|
|
522
|
+
// (e.g. Slack follow-up forwarding) can extract it without racing
|
|
523
|
+
// against async log persistence to object storage.
|
|
524
|
+
let assistantMessage: string | undefined;
|
|
525
|
+
try {
|
|
526
|
+
await this.session.logWriter.flush(this.session.payload.run_id);
|
|
527
|
+
assistantMessage = this.session.logWriter.getFullAgentResponse(
|
|
528
|
+
this.session.payload.run_id,
|
|
529
|
+
);
|
|
530
|
+
} catch {
|
|
531
|
+
this.logger.warn("Failed to extract assistant message from logs");
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
return {
|
|
535
|
+
stopReason: result.stopReason,
|
|
536
|
+
...(assistantMessage && { assistant_message: assistantMessage }),
|
|
537
|
+
};
|
|
505
538
|
}
|
|
506
539
|
|
|
507
540
|
case POSTHOG_NOTIFICATIONS.CANCEL:
|
|
@@ -530,6 +563,40 @@ export class AgentServer {
|
|
|
530
563
|
private async initializeSession(
|
|
531
564
|
payload: JwtPayload,
|
|
532
565
|
sseController: SseController | null,
|
|
566
|
+
): Promise<void> {
|
|
567
|
+
// Race condition guard: autoInitializeSession() starts first, but while it awaits
|
|
568
|
+
// newSession() (which takes ~1-2s for MCP metadata fetch), the Temporal relay connects
|
|
569
|
+
// to GET /events. That handler sees this.session === null and calls initializeSession()
|
|
570
|
+
// again, creating a duplicate session that sends the same prompt twice — resulting in
|
|
571
|
+
// duplicate Slack messages. This lock ensures the second caller waits for the first
|
|
572
|
+
// initialization to finish and reuses the session.
|
|
573
|
+
if (this.initializationPromise) {
|
|
574
|
+
this.logger.info("Waiting for in-progress initialization", {
|
|
575
|
+
runId: payload.run_id,
|
|
576
|
+
});
|
|
577
|
+
await this.initializationPromise;
|
|
578
|
+
// After waiting, just attach the SSE controller if needed
|
|
579
|
+
if (this.session && sseController) {
|
|
580
|
+
this.session.sseController = sseController;
|
|
581
|
+
this.replayPendingEvents();
|
|
582
|
+
}
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
this.initializationPromise = this._doInitializeSession(
|
|
587
|
+
payload,
|
|
588
|
+
sseController,
|
|
589
|
+
);
|
|
590
|
+
try {
|
|
591
|
+
await this.initializationPromise;
|
|
592
|
+
} finally {
|
|
593
|
+
this.initializationPromise = null;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
private async _doInitializeSession(
|
|
598
|
+
payload: JwtPayload,
|
|
599
|
+
sseController: SseController | null,
|
|
533
600
|
): Promise<void> {
|
|
534
601
|
if (this.session) {
|
|
535
602
|
await this.cleanupSession();
|
|
@@ -770,6 +837,8 @@ export class AgentServer {
|
|
|
770
837
|
usedInitialPromptOverride: !!initialPromptOverride,
|
|
771
838
|
});
|
|
772
839
|
|
|
840
|
+
this.session.logWriter.resetTurnMessages(payload.run_id);
|
|
841
|
+
|
|
773
842
|
const result = await this.session.clientConnection.prompt({
|
|
774
843
|
sessionId: this.session.acpSessionId,
|
|
775
844
|
prompt: [{ type: "text", text: initialPrompt }],
|
|
@@ -809,8 +878,8 @@ export class AgentServer {
|
|
|
809
878
|
const pendingUserMessage = this.getPendingUserMessage(taskRun);
|
|
810
879
|
|
|
811
880
|
const sandboxContext = this.resumeState.snapshotApplied
|
|
812
|
-
? `The
|
|
813
|
-
: `The
|
|
881
|
+
? `The workspace environment (all files, packages, and code changes) has been fully restored from where you left off.`
|
|
882
|
+
: `The workspace files from the previous session were not restored (the file snapshot may have expired), so you are starting with a fresh environment. Your conversation history is fully preserved below.`;
|
|
814
883
|
|
|
815
884
|
let resumePrompt: string;
|
|
816
885
|
if (pendingUserMessage) {
|
|
@@ -842,6 +911,8 @@ export class AgentServer {
|
|
|
842
911
|
// Clear resume state so it's not reused
|
|
843
912
|
this.resumeState = null;
|
|
844
913
|
|
|
914
|
+
this.session.logWriter.resetTurnMessages(payload.run_id);
|
|
915
|
+
|
|
845
916
|
const result = await this.session.clientConnection.prompt({
|
|
846
917
|
sessionId: this.session.acpSessionId,
|
|
847
918
|
prompt: [{ type: "text", text: resumePrompt }],
|
|
@@ -852,6 +923,10 @@ export class AgentServer {
|
|
|
852
923
|
});
|
|
853
924
|
|
|
854
925
|
this.broadcastTurnComplete(result.stopReason);
|
|
926
|
+
|
|
927
|
+
if (result.stopReason === "end_turn") {
|
|
928
|
+
await this.relayAgentResponse(payload);
|
|
929
|
+
}
|
|
855
930
|
} catch (error) {
|
|
856
931
|
this.logger.error("Failed to send resume message", error);
|
|
857
932
|
if (this.session) {
|
|
@@ -992,6 +1067,27 @@ Important:
|
|
|
992
1067
|
`;
|
|
993
1068
|
}
|
|
994
1069
|
|
|
1070
|
+
if (!this.config.repositoryPath) {
|
|
1071
|
+
return `
|
|
1072
|
+
# Cloud Task Execution — No Repository Mode
|
|
1073
|
+
|
|
1074
|
+
You are a helpful assistant with access to PostHog via MCP tools. You can help with both code tasks and data/analytics questions.
|
|
1075
|
+
|
|
1076
|
+
When the user asks about analytics, data, metrics, events, funnels, dashboards, feature flags, experiments, or anything PostHog-related:
|
|
1077
|
+
- Use your PostHog MCP tools to query data, search insights, and provide real answers
|
|
1078
|
+
- Do NOT tell the user to check an external analytics platform — you ARE the analytics platform
|
|
1079
|
+
- Use tools like insight-query, query-run, event-definitions-list, and others to answer questions directly
|
|
1080
|
+
|
|
1081
|
+
When the user asks for code changes or software engineering tasks:
|
|
1082
|
+
- Let them know you can help but don't have a repository connected for this session
|
|
1083
|
+
- Offer to write code snippets, scripts, or provide guidance
|
|
1084
|
+
|
|
1085
|
+
Important:
|
|
1086
|
+
- Do NOT create branches, commits, or pull requests in this mode.
|
|
1087
|
+
- Prefer using MCP tools to answer questions with real data over giving generic advice.
|
|
1088
|
+
`;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
995
1091
|
return `
|
|
996
1092
|
# Cloud Task Execution
|
|
997
1093
|
|
|
@@ -1124,6 +1220,12 @@ Important:
|
|
|
1124
1220
|
},
|
|
1125
1221
|
};
|
|
1126
1222
|
},
|
|
1223
|
+
extNotification: async (
|
|
1224
|
+
method: string,
|
|
1225
|
+
params: Record<string, unknown>,
|
|
1226
|
+
) => {
|
|
1227
|
+
this.logger.debug("Extension notification", { method, params });
|
|
1228
|
+
},
|
|
1127
1229
|
sessionUpdate: async (params: {
|
|
1128
1230
|
sessionId: string;
|
|
1129
1231
|
update?: Record<string, unknown>;
|
|
@@ -1176,7 +1278,7 @@ Important:
|
|
|
1176
1278
|
});
|
|
1177
1279
|
}
|
|
1178
1280
|
|
|
1179
|
-
const message = this.session.logWriter.
|
|
1281
|
+
const message = this.session.logWriter.getFullAgentResponse(payload.run_id);
|
|
1180
1282
|
if (!message) {
|
|
1181
1283
|
this.logger.warn("No agent message found for Slack relay", {
|
|
1182
1284
|
taskId: payload.task_id,
|
|
@@ -1385,6 +1487,7 @@ Important:
|
|
|
1385
1487
|
this.session.sseController.close();
|
|
1386
1488
|
}
|
|
1387
1489
|
|
|
1490
|
+
this.pendingEvents = [];
|
|
1388
1491
|
this.session = null;
|
|
1389
1492
|
}
|
|
1390
1493
|
|
|
@@ -1444,6 +1547,18 @@ Important:
|
|
|
1444
1547
|
private broadcastEvent(event: Record<string, unknown>): void {
|
|
1445
1548
|
if (this.session?.sseController) {
|
|
1446
1549
|
this.sendSseEvent(this.session.sseController, event);
|
|
1550
|
+
} else if (this.session) {
|
|
1551
|
+
// Buffer events during initialization (sseController not yet attached)
|
|
1552
|
+
this.pendingEvents.push(event);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
private replayPendingEvents(): void {
|
|
1557
|
+
if (!this.session?.sseController || this.pendingEvents.length === 0) return;
|
|
1558
|
+
const events = this.pendingEvents;
|
|
1559
|
+
this.pendingEvents = [];
|
|
1560
|
+
for (const event of events) {
|
|
1561
|
+
this.sendSseEvent(this.session.sseController, event);
|
|
1447
1562
|
}
|
|
1448
1563
|
}
|
|
1449
1564
|
|
|
@@ -248,7 +248,7 @@ describe("Question relay", () => {
|
|
|
248
248
|
payload: TEST_PAYLOAD,
|
|
249
249
|
logWriter: {
|
|
250
250
|
flush: vi.fn().mockResolvedValue(undefined),
|
|
251
|
-
|
|
251
|
+
getFullAgentResponse: vi.fn().mockReturnValue("agent response"),
|
|
252
252
|
isRegistered: vi.fn().mockReturnValue(true),
|
|
253
253
|
},
|
|
254
254
|
};
|
|
@@ -269,7 +269,7 @@ describe("Question relay", () => {
|
|
|
269
269
|
payload: TEST_PAYLOAD,
|
|
270
270
|
logWriter: {
|
|
271
271
|
flush: vi.fn().mockResolvedValue(undefined),
|
|
272
|
-
|
|
272
|
+
getFullAgentResponse: vi.fn().mockReturnValue("agent response"),
|
|
273
273
|
isRegistered: vi.fn().mockReturnValue(true),
|
|
274
274
|
},
|
|
275
275
|
};
|
|
@@ -293,7 +293,7 @@ describe("Question relay", () => {
|
|
|
293
293
|
payload: TEST_PAYLOAD,
|
|
294
294
|
logWriter: {
|
|
295
295
|
flush: vi.fn().mockResolvedValue(undefined),
|
|
296
|
-
|
|
296
|
+
getFullAgentResponse: vi.fn().mockReturnValue(null),
|
|
297
297
|
isRegistered: vi.fn().mockReturnValue(true),
|
|
298
298
|
},
|
|
299
299
|
};
|
|
@@ -323,6 +323,13 @@ describe("Question relay", () => {
|
|
|
323
323
|
payload: TEST_PAYLOAD,
|
|
324
324
|
acpSessionId: "acp-session",
|
|
325
325
|
clientConnection: { prompt: promptSpy },
|
|
326
|
+
logWriter: {
|
|
327
|
+
flushAll: vi.fn().mockResolvedValue(undefined),
|
|
328
|
+
getFullAgentResponse: vi.fn().mockReturnValue(null),
|
|
329
|
+
resetTurnMessages: vi.fn(),
|
|
330
|
+
flush: vi.fn().mockResolvedValue(undefined),
|
|
331
|
+
isRegistered: vi.fn().mockReturnValue(true),
|
|
332
|
+
},
|
|
326
333
|
};
|
|
327
334
|
|
|
328
335
|
await server.sendInitialTaskMessage(TEST_PAYLOAD);
|
|
@@ -350,6 +357,13 @@ describe("Question relay", () => {
|
|
|
350
357
|
payload: TEST_PAYLOAD,
|
|
351
358
|
acpSessionId: "acp-session",
|
|
352
359
|
clientConnection: { prompt: promptSpy },
|
|
360
|
+
logWriter: {
|
|
361
|
+
flushAll: vi.fn().mockResolvedValue(undefined),
|
|
362
|
+
getFullAgentResponse: vi.fn().mockReturnValue(null),
|
|
363
|
+
resetTurnMessages: vi.fn(),
|
|
364
|
+
flush: vi.fn().mockResolvedValue(undefined),
|
|
365
|
+
isRegistered: vi.fn().mockReturnValue(true),
|
|
366
|
+
},
|
|
353
367
|
};
|
|
354
368
|
|
|
355
369
|
await server.sendInitialTaskMessage(TEST_PAYLOAD);
|
|
@@ -24,6 +24,7 @@ interface SessionState {
|
|
|
24
24
|
context: SessionContext;
|
|
25
25
|
chunkBuffer?: ChunkBuffer;
|
|
26
26
|
lastAgentMessage?: string;
|
|
27
|
+
currentTurnMessages: string[];
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
export class SessionLogWriter {
|
|
@@ -69,7 +70,7 @@ export class SessionLogWriter {
|
|
|
69
70
|
taskId: context.taskId,
|
|
70
71
|
runId: context.runId,
|
|
71
72
|
});
|
|
72
|
-
this.sessions.set(sessionId, { context });
|
|
73
|
+
this.sessions.set(sessionId, { context, currentTurnMessages: [] });
|
|
73
74
|
|
|
74
75
|
this.lastFlushAttemptTime.set(sessionId, Date.now());
|
|
75
76
|
|
|
@@ -127,6 +128,7 @@ export class SessionLogWriter {
|
|
|
127
128
|
const nonChunkAgentText = this.extractAgentMessageText(message);
|
|
128
129
|
if (nonChunkAgentText) {
|
|
129
130
|
session.lastAgentMessage = nonChunkAgentText;
|
|
131
|
+
session.currentTurnMessages.push(nonChunkAgentText);
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
const entry: StoredNotification = {
|
|
@@ -240,6 +242,7 @@ export class SessionLogWriter {
|
|
|
240
242
|
const { text, firstTimestamp } = session.chunkBuffer;
|
|
241
243
|
session.chunkBuffer = undefined;
|
|
242
244
|
session.lastAgentMessage = text;
|
|
245
|
+
session.currentTurnMessages.push(text);
|
|
243
246
|
|
|
244
247
|
const entry: StoredNotification = {
|
|
245
248
|
type: "notification",
|
|
@@ -270,6 +273,19 @@ export class SessionLogWriter {
|
|
|
270
273
|
return this.sessions.get(sessionId)?.lastAgentMessage;
|
|
271
274
|
}
|
|
272
275
|
|
|
276
|
+
getFullAgentResponse(sessionId: string): string | undefined {
|
|
277
|
+
const session = this.sessions.get(sessionId);
|
|
278
|
+
if (!session || session.currentTurnMessages.length === 0) return undefined;
|
|
279
|
+
return session.currentTurnMessages.join("\n\n");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
resetTurnMessages(sessionId: string): void {
|
|
283
|
+
const session = this.sessions.get(sessionId);
|
|
284
|
+
if (session) {
|
|
285
|
+
session.currentTurnMessages = [];
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
273
289
|
private extractAgentMessageText(
|
|
274
290
|
message: Record<string, unknown>,
|
|
275
291
|
): string | null {
|
package/src/types.ts
CHANGED