@posthog/agent 2.3.353 → 2.3.356
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 +19 -2
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -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 +2 -0
- package/dist/server/agent-server.js +98 -54
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +98 -54
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +3 -3
- package/src/acp-extensions.ts +3 -0
- package/src/adapters/claude/conversion/sdk-to-acp.ts +31 -1
- package/src/server/agent-server.ts +103 -53
- package/src/server/question-relay.test.ts +124 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/agent",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.356",
|
|
4
4
|
"repository": "https://github.com/PostHog/code",
|
|
5
5
|
"description": "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
6
6
|
"exports": {
|
|
@@ -86,9 +86,9 @@
|
|
|
86
86
|
"tsx": "^4.20.6",
|
|
87
87
|
"typescript": "^5.5.0",
|
|
88
88
|
"vitest": "^2.1.8",
|
|
89
|
-
"@posthog/shared": "1.0.0",
|
|
90
89
|
"@posthog/enricher": "1.0.0",
|
|
91
|
-
"@posthog/git": "1.0.0"
|
|
90
|
+
"@posthog/git": "1.0.0",
|
|
91
|
+
"@posthog/shared": "1.0.0"
|
|
92
92
|
},
|
|
93
93
|
"dependencies": {
|
|
94
94
|
"@agentclientprotocol/sdk": "0.19.0",
|
package/src/acp-extensions.ts
CHANGED
|
@@ -55,6 +55,9 @@ export const POSTHOG_NOTIFICATIONS = {
|
|
|
55
55
|
/** Agent status update (thinking, working, etc.) */
|
|
56
56
|
STATUS: "_posthog/status",
|
|
57
57
|
|
|
58
|
+
/** Structured backend progress notification; events in the same turn group into one card on the client */
|
|
59
|
+
PROGRESS: "_posthog/progress",
|
|
60
|
+
|
|
58
61
|
/** Task-level notification (progress, milestones) */
|
|
59
62
|
TASK_NOTIFICATION: "_posthog/task_notification",
|
|
60
63
|
|
|
@@ -618,6 +618,32 @@ export type ResultMessageHandlerResult = {
|
|
|
618
618
|
};
|
|
619
619
|
};
|
|
620
620
|
|
|
621
|
+
export type AgentErrorClassification =
|
|
622
|
+
| "upstream_stream_terminated"
|
|
623
|
+
| "upstream_connection_error"
|
|
624
|
+
| "agent_error";
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Classify an error string surfaced by the Claude CLI via `is_error: true`
|
|
628
|
+
* result messages. Transient upstream-stream terminations (e.g. the fetch body
|
|
629
|
+
* from the LLM gateway is torn down mid-stream) are retriable; most other
|
|
630
|
+
* errors are not.
|
|
631
|
+
*/
|
|
632
|
+
export function classifyAgentError(
|
|
633
|
+
result: string | undefined,
|
|
634
|
+
): AgentErrorClassification {
|
|
635
|
+
if (!result) return "agent_error";
|
|
636
|
+
const text = result.trim();
|
|
637
|
+
// Anthropic SDK surfaces an undici fetch abort as "API Error: terminated".
|
|
638
|
+
if (/API Error:\s*terminated\b/i.test(text)) {
|
|
639
|
+
return "upstream_stream_terminated";
|
|
640
|
+
}
|
|
641
|
+
if (/API Error:\s*Connection error\b/i.test(text)) {
|
|
642
|
+
return "upstream_connection_error";
|
|
643
|
+
}
|
|
644
|
+
return "agent_error";
|
|
645
|
+
}
|
|
646
|
+
|
|
621
647
|
export function handleResultMessage(
|
|
622
648
|
message: SDKResultMessage,
|
|
623
649
|
): ResultMessageHandlerResult {
|
|
@@ -636,9 +662,13 @@ export function handleResultMessage(
|
|
|
636
662
|
return { shouldStop: true, stopReason: "max_tokens", usage };
|
|
637
663
|
}
|
|
638
664
|
if (message.is_error) {
|
|
665
|
+
const classification = classifyAgentError(message.result);
|
|
639
666
|
return {
|
|
640
667
|
shouldStop: true,
|
|
641
|
-
error: RequestError.internalError(
|
|
668
|
+
error: RequestError.internalError(
|
|
669
|
+
{ classification, result: message.result },
|
|
670
|
+
message.result,
|
|
671
|
+
),
|
|
642
672
|
usage,
|
|
643
673
|
};
|
|
644
674
|
}
|
|
@@ -14,12 +14,17 @@ import {
|
|
|
14
14
|
import { type ServerType, serve } from "@hono/node-server";
|
|
15
15
|
import { getCurrentBranch } from "@posthog/git/queries";
|
|
16
16
|
import { Hono } from "hono";
|
|
17
|
+
import { z } from "zod";
|
|
17
18
|
import packageJson from "../../package.json" with { type: "json" };
|
|
18
19
|
import { POSTHOG_METHODS, POSTHOG_NOTIFICATIONS } from "../acp-extensions";
|
|
19
20
|
import {
|
|
20
21
|
createAcpConnection,
|
|
21
22
|
type InProcessAcpConnection,
|
|
22
23
|
} from "../adapters/acp-connection";
|
|
24
|
+
import {
|
|
25
|
+
type AgentErrorClassification,
|
|
26
|
+
classifyAgentError,
|
|
27
|
+
} from "../adapters/claude/conversion/sdk-to-acp";
|
|
23
28
|
import { selectRecentTurns } from "../adapters/claude/session/jsonl-hydration";
|
|
24
29
|
import type { PermissionMode } from "../execution-mode";
|
|
25
30
|
import { DEFAULT_CODEX_MODEL } from "../gateway-models";
|
|
@@ -51,6 +56,16 @@ import { type JwtPayload, JwtValidationError, validateJwt } from "./jwt";
|
|
|
51
56
|
import { jsonRpcRequestSchema, validateCommandParams } from "./schemas";
|
|
52
57
|
import type { AgentServerConfig } from "./types";
|
|
53
58
|
|
|
59
|
+
const agentErrorClassificationSchema = z.enum([
|
|
60
|
+
"upstream_stream_terminated",
|
|
61
|
+
"upstream_connection_error",
|
|
62
|
+
"agent_error",
|
|
63
|
+
]) satisfies z.ZodType<AgentErrorClassification>;
|
|
64
|
+
|
|
65
|
+
const errorWithClassificationSchema = z.object({
|
|
66
|
+
data: z.object({ classification: agentErrorClassificationSchema }),
|
|
67
|
+
});
|
|
68
|
+
|
|
54
69
|
type MessageCallback = (message: unknown) => void;
|
|
55
70
|
|
|
56
71
|
class NdJsonTap {
|
|
@@ -445,7 +460,9 @@ export class AgentServer {
|
|
|
445
460
|
port: this.config.port,
|
|
446
461
|
},
|
|
447
462
|
() => {
|
|
448
|
-
this.logger.
|
|
463
|
+
this.logger.debug(
|
|
464
|
+
`HTTP server listening on port ${this.config.port}`,
|
|
465
|
+
);
|
|
449
466
|
resolve();
|
|
450
467
|
},
|
|
451
468
|
);
|
|
@@ -457,12 +474,12 @@ export class AgentServer {
|
|
|
457
474
|
private async autoInitializeSession(): Promise<void> {
|
|
458
475
|
const { taskId, runId, mode, projectId } = this.config;
|
|
459
476
|
|
|
460
|
-
this.logger.
|
|
477
|
+
this.logger.debug("Auto-initializing session", { taskId, runId, mode });
|
|
461
478
|
|
|
462
479
|
// Check if this is a resume from a previous run
|
|
463
480
|
const resumeRunId = process.env.POSTHOG_RESUME_RUN_ID;
|
|
464
481
|
if (resumeRunId) {
|
|
465
|
-
this.logger.
|
|
482
|
+
this.logger.debug("Resuming from previous run", {
|
|
466
483
|
resumeRunId,
|
|
467
484
|
currentRunId: runId,
|
|
468
485
|
});
|
|
@@ -474,13 +491,13 @@ export class AgentServer {
|
|
|
474
491
|
apiClient: this.posthogAPI,
|
|
475
492
|
logger: new Logger({ debug: true, prefix: "[Resume]" }),
|
|
476
493
|
});
|
|
477
|
-
this.logger.
|
|
494
|
+
this.logger.debug("Resume state loaded", {
|
|
478
495
|
conversationTurns: this.resumeState.conversation.length,
|
|
479
496
|
snapshotApplied: this.resumeState.snapshotApplied,
|
|
480
497
|
logEntries: this.resumeState.logEntryCount,
|
|
481
498
|
});
|
|
482
499
|
} catch (error) {
|
|
483
|
-
this.logger.
|
|
500
|
+
this.logger.debug("Failed to load resume state, starting fresh", {
|
|
484
501
|
error,
|
|
485
502
|
});
|
|
486
503
|
this.resumeState = null;
|
|
@@ -501,7 +518,7 @@ export class AgentServer {
|
|
|
501
518
|
}
|
|
502
519
|
|
|
503
520
|
async stop(): Promise<void> {
|
|
504
|
-
this.logger.
|
|
521
|
+
this.logger.debug("Stopping agent server...");
|
|
505
522
|
|
|
506
523
|
if (this.session) {
|
|
507
524
|
await this.cleanupSession();
|
|
@@ -512,7 +529,7 @@ export class AgentServer {
|
|
|
512
529
|
this.server = null;
|
|
513
530
|
}
|
|
514
531
|
|
|
515
|
-
this.logger.
|
|
532
|
+
this.logger.debug("Agent server stopped");
|
|
516
533
|
}
|
|
517
534
|
|
|
518
535
|
private authenticateRequest(
|
|
@@ -574,7 +591,7 @@ export class AgentServer {
|
|
|
574
591
|
});
|
|
575
592
|
const promptPreview = promptBlocksToText(prompt);
|
|
576
593
|
|
|
577
|
-
this.logger.
|
|
594
|
+
this.logger.debug(
|
|
578
595
|
`Processing user message (detectedPrUrl=${this.detectedPrUrl ?? "none"}): ${promptPreview.substring(0, 100)}...`,
|
|
579
596
|
);
|
|
580
597
|
|
|
@@ -592,7 +609,7 @@ export class AgentServer {
|
|
|
592
609
|
}),
|
|
593
610
|
});
|
|
594
611
|
|
|
595
|
-
this.logger.
|
|
612
|
+
this.logger.debug("User message completed", {
|
|
596
613
|
stopReason: result.stopReason,
|
|
597
614
|
});
|
|
598
615
|
|
|
@@ -606,7 +623,7 @@ export class AgentServer {
|
|
|
606
623
|
// Relay the response to Slack. For follow-ups this is the primary
|
|
607
624
|
// delivery path — the HTTP caller only handles reactions.
|
|
608
625
|
this.relayAgentResponse(this.session.payload).catch((err) =>
|
|
609
|
-
this.logger.
|
|
626
|
+
this.logger.debug("Failed to relay follow-up response", err),
|
|
610
627
|
);
|
|
611
628
|
}
|
|
612
629
|
|
|
@@ -622,7 +639,7 @@ export class AgentServer {
|
|
|
622
639
|
this.session.payload.run_id,
|
|
623
640
|
);
|
|
624
641
|
} catch {
|
|
625
|
-
this.logger.
|
|
642
|
+
this.logger.debug("Failed to extract assistant message from logs");
|
|
626
643
|
}
|
|
627
644
|
|
|
628
645
|
return {
|
|
@@ -633,7 +650,7 @@ export class AgentServer {
|
|
|
633
650
|
|
|
634
651
|
case POSTHOG_NOTIFICATIONS.CANCEL:
|
|
635
652
|
case "cancel": {
|
|
636
|
-
this.logger.
|
|
653
|
+
this.logger.debug("Cancel requested", {
|
|
637
654
|
acpSessionId: this.session.acpSessionId,
|
|
638
655
|
});
|
|
639
656
|
await this.session.clientConnection.cancel({
|
|
@@ -644,7 +661,7 @@ export class AgentServer {
|
|
|
644
661
|
|
|
645
662
|
case POSTHOG_NOTIFICATIONS.CLOSE:
|
|
646
663
|
case "close": {
|
|
647
|
-
this.logger.
|
|
664
|
+
this.logger.debug("Close requested");
|
|
648
665
|
await this.cleanupSession();
|
|
649
666
|
return { closed: true };
|
|
650
667
|
}
|
|
@@ -654,7 +671,7 @@ export class AgentServer {
|
|
|
654
671
|
const configId = params.configId as string;
|
|
655
672
|
const value = params.value as string;
|
|
656
673
|
|
|
657
|
-
this.logger.
|
|
674
|
+
this.logger.debug("Set config option requested", { configId, value });
|
|
658
675
|
|
|
659
676
|
const result =
|
|
660
677
|
await this.session.clientConnection.setSessionConfigOption({
|
|
@@ -692,7 +709,7 @@ export class AgentServer {
|
|
|
692
709
|
const customInput = params.customInput as string | undefined;
|
|
693
710
|
const answers = params.answers as Record<string, string> | undefined;
|
|
694
711
|
|
|
695
|
-
this.logger.
|
|
712
|
+
this.logger.debug("Permission response received", {
|
|
696
713
|
requestId,
|
|
697
714
|
optionId,
|
|
698
715
|
});
|
|
@@ -727,7 +744,7 @@ export class AgentServer {
|
|
|
727
744
|
// duplicate Slack messages. This lock ensures the second caller waits for the first
|
|
728
745
|
// initialization to finish and reuses the session.
|
|
729
746
|
if (this.initializationPromise) {
|
|
730
|
-
this.logger.
|
|
747
|
+
this.logger.debug("Waiting for in-progress initialization", {
|
|
731
748
|
runId: payload.run_id,
|
|
732
749
|
});
|
|
733
750
|
await this.initializationPromise;
|
|
@@ -759,7 +776,7 @@ export class AgentServer {
|
|
|
759
776
|
await this.cleanupSession();
|
|
760
777
|
}
|
|
761
778
|
|
|
762
|
-
this.logger.
|
|
779
|
+
this.logger.debug("Initializing session", {
|
|
763
780
|
runId: payload.run_id,
|
|
764
781
|
taskId: payload.task_id,
|
|
765
782
|
});
|
|
@@ -775,7 +792,7 @@ export class AgentServer {
|
|
|
775
792
|
this.posthogAPI
|
|
776
793
|
.getTaskRun(payload.task_id, payload.run_id)
|
|
777
794
|
.catch((err) => {
|
|
778
|
-
this.logger.
|
|
795
|
+
this.logger.debug("Failed to fetch task run for session context", {
|
|
779
796
|
taskId: payload.task_id,
|
|
780
797
|
runId: payload.run_id,
|
|
781
798
|
error: err,
|
|
@@ -783,7 +800,7 @@ export class AgentServer {
|
|
|
783
800
|
return null;
|
|
784
801
|
}),
|
|
785
802
|
this.posthogAPI.getTask(payload.task_id).catch((err) => {
|
|
786
|
-
this.logger.
|
|
803
|
+
this.logger.debug("Failed to fetch task for session context", {
|
|
787
804
|
taskId: payload.task_id,
|
|
788
805
|
error: err,
|
|
789
806
|
});
|
|
@@ -926,7 +943,7 @@ export class AgentServer {
|
|
|
926
943
|
});
|
|
927
944
|
|
|
928
945
|
const acpSessionId = sessionResponse.sessionId;
|
|
929
|
-
this.logger.
|
|
946
|
+
this.logger.debug("ACP session created", {
|
|
930
947
|
acpSessionId,
|
|
931
948
|
runId: payload.run_id,
|
|
932
949
|
});
|
|
@@ -948,18 +965,15 @@ export class AgentServer {
|
|
|
948
965
|
debug: true,
|
|
949
966
|
prefix: "[AgentServer]",
|
|
950
967
|
onLog: (level, scope, message, data) => {
|
|
951
|
-
// Preserve console output (onLog suppresses default console.*)
|
|
952
|
-
const _formatted =
|
|
953
|
-
data !== undefined ? `${message} ${JSON.stringify(data)}` : message;
|
|
954
968
|
this.emitConsoleLog(level, scope, message, data);
|
|
955
969
|
},
|
|
956
970
|
});
|
|
957
971
|
|
|
958
|
-
this.logger.
|
|
959
|
-
this.logger.
|
|
972
|
+
this.logger.debug("Session initialized successfully");
|
|
973
|
+
this.logger.debug(
|
|
960
974
|
`Agent version: ${this.config.version ?? packageJson.version}`,
|
|
961
975
|
);
|
|
962
|
-
this.logger.
|
|
976
|
+
this.logger.debug(`Initial permission mode: ${initialPermissionMode}`);
|
|
963
977
|
|
|
964
978
|
// Signal in_progress so the UI can start polling for updates
|
|
965
979
|
this.posthogAPI
|
|
@@ -967,12 +981,47 @@ export class AgentServer {
|
|
|
967
981
|
status: "in_progress",
|
|
968
982
|
})
|
|
969
983
|
.catch((err) =>
|
|
970
|
-
this.logger.
|
|
984
|
+
this.logger.debug("Failed to set task run to in_progress", err),
|
|
971
985
|
);
|
|
972
986
|
|
|
973
987
|
await this.sendInitialTaskMessage(payload, preTaskRun);
|
|
974
988
|
}
|
|
975
989
|
|
|
990
|
+
private extractErrorClassification(error: unknown): {
|
|
991
|
+
classification: AgentErrorClassification;
|
|
992
|
+
message: string;
|
|
993
|
+
} {
|
|
994
|
+
const message =
|
|
995
|
+
error instanceof Error ? error.message : String(error ?? "");
|
|
996
|
+
|
|
997
|
+
// Prefer the structured `data` carried on RequestError if present.
|
|
998
|
+
const parsed = errorWithClassificationSchema.safeParse(error);
|
|
999
|
+
if (parsed.success) {
|
|
1000
|
+
return { classification: parsed.data.data.classification, message };
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
return { classification: classifyAgentError(message), message };
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
private classifyAndSignalFailure(
|
|
1007
|
+
payload: JwtPayload,
|
|
1008
|
+
phase: "initial" | "resume",
|
|
1009
|
+
error: unknown,
|
|
1010
|
+
): Promise<void> {
|
|
1011
|
+
const { classification, message } = this.extractErrorClassification(error);
|
|
1012
|
+
const errorMessage =
|
|
1013
|
+
classification === "upstream_stream_terminated"
|
|
1014
|
+
? "Upstream LLM stream terminated"
|
|
1015
|
+
: classification === "upstream_connection_error"
|
|
1016
|
+
? "Upstream LLM connection error"
|
|
1017
|
+
: message || "Agent error";
|
|
1018
|
+
this.logger.error(`send_${phase}_task_message_failed`, {
|
|
1019
|
+
classification,
|
|
1020
|
+
message,
|
|
1021
|
+
});
|
|
1022
|
+
return this.signalTaskComplete(payload, "error", errorMessage);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
976
1025
|
private async sendInitialTaskMessage(
|
|
977
1026
|
payload: JwtPayload,
|
|
978
1027
|
prefetchedRun?: TaskRun | null,
|
|
@@ -988,7 +1037,7 @@ export class AgentServer {
|
|
|
988
1037
|
payload.run_id,
|
|
989
1038
|
);
|
|
990
1039
|
} catch (error) {
|
|
991
|
-
this.logger.
|
|
1040
|
+
this.logger.debug("Failed to fetch task run", {
|
|
992
1041
|
taskId: payload.task_id,
|
|
993
1042
|
runId: payload.run_id,
|
|
994
1043
|
error,
|
|
@@ -1000,7 +1049,7 @@ export class AgentServer {
|
|
|
1000
1049
|
if (!this.resumeState) {
|
|
1001
1050
|
const resumeRunId = this.getResumeRunId(taskRun);
|
|
1002
1051
|
if (resumeRunId) {
|
|
1003
|
-
this.logger.
|
|
1052
|
+
this.logger.debug("Resuming from previous run (via TaskRun state)", {
|
|
1004
1053
|
resumeRunId,
|
|
1005
1054
|
currentRunId: payload.run_id,
|
|
1006
1055
|
});
|
|
@@ -1012,13 +1061,13 @@ export class AgentServer {
|
|
|
1012
1061
|
apiClient: this.posthogAPI,
|
|
1013
1062
|
logger: new Logger({ debug: true, prefix: "[Resume]" }),
|
|
1014
1063
|
});
|
|
1015
|
-
this.logger.
|
|
1064
|
+
this.logger.debug("Resume state loaded (via TaskRun state)", {
|
|
1016
1065
|
conversationTurns: this.resumeState.conversation.length,
|
|
1017
1066
|
snapshotApplied: this.resumeState.snapshotApplied,
|
|
1018
1067
|
logEntries: this.resumeState.logEntryCount,
|
|
1019
1068
|
});
|
|
1020
1069
|
} catch (error) {
|
|
1021
|
-
this.logger.
|
|
1070
|
+
this.logger.debug("Failed to load resume state, starting fresh", {
|
|
1022
1071
|
error,
|
|
1023
1072
|
});
|
|
1024
1073
|
this.resumeState = null;
|
|
@@ -1049,11 +1098,11 @@ export class AgentServer {
|
|
|
1049
1098
|
}
|
|
1050
1099
|
|
|
1051
1100
|
if (initialPrompt.length === 0) {
|
|
1052
|
-
this.logger.
|
|
1101
|
+
this.logger.debug("Task has no description, skipping initial message");
|
|
1053
1102
|
return;
|
|
1054
1103
|
}
|
|
1055
1104
|
|
|
1056
|
-
this.logger.
|
|
1105
|
+
this.logger.debug("Sending initial task message", {
|
|
1057
1106
|
taskId: payload.task_id,
|
|
1058
1107
|
descriptionLength: promptBlocksToText(initialPrompt).length,
|
|
1059
1108
|
usedInitialPromptOverride: !!initialPromptOverride,
|
|
@@ -1067,7 +1116,7 @@ export class AgentServer {
|
|
|
1067
1116
|
prompt: initialPrompt,
|
|
1068
1117
|
});
|
|
1069
1118
|
|
|
1070
|
-
this.logger.
|
|
1119
|
+
this.logger.debug("Initial task message completed", {
|
|
1071
1120
|
stopReason: result.stopReason,
|
|
1072
1121
|
});
|
|
1073
1122
|
|
|
@@ -1087,7 +1136,7 @@ export class AgentServer {
|
|
|
1087
1136
|
if (this.session) {
|
|
1088
1137
|
await this.session.logWriter.flushAll();
|
|
1089
1138
|
}
|
|
1090
|
-
await this.
|
|
1139
|
+
await this.classifyAndSignalFailure(payload, "initial", error);
|
|
1091
1140
|
}
|
|
1092
1141
|
}
|
|
1093
1142
|
|
|
@@ -1140,7 +1189,7 @@ export class AgentServer {
|
|
|
1140
1189
|
];
|
|
1141
1190
|
}
|
|
1142
1191
|
|
|
1143
|
-
this.logger.
|
|
1192
|
+
this.logger.debug("Sending resume message", {
|
|
1144
1193
|
taskId: payload.task_id,
|
|
1145
1194
|
conversationTurns: this.resumeState.conversation.length,
|
|
1146
1195
|
promptLength: promptBlocksToText(resumePromptBlocks).length,
|
|
@@ -1158,7 +1207,7 @@ export class AgentServer {
|
|
|
1158
1207
|
prompt: resumePromptBlocks,
|
|
1159
1208
|
});
|
|
1160
1209
|
|
|
1161
|
-
this.logger.
|
|
1210
|
+
this.logger.debug("Resume message completed", {
|
|
1162
1211
|
stopReason: result.stopReason,
|
|
1163
1212
|
});
|
|
1164
1213
|
|
|
@@ -1176,7 +1225,7 @@ export class AgentServer {
|
|
|
1176
1225
|
if (this.session) {
|
|
1177
1226
|
await this.session.logWriter.flushAll();
|
|
1178
1227
|
}
|
|
1179
|
-
await this.
|
|
1228
|
+
await this.classifyAndSignalFailure(payload, "resume", error);
|
|
1180
1229
|
}
|
|
1181
1230
|
}
|
|
1182
1231
|
|
|
@@ -1624,7 +1673,7 @@ ${attributionInstructions}
|
|
|
1624
1673
|
try {
|
|
1625
1674
|
return await getCurrentBranch(this.config.repositoryPath);
|
|
1626
1675
|
} catch (error) {
|
|
1627
|
-
this.logger.
|
|
1676
|
+
this.logger.debug("Failed to determine current git branch", {
|
|
1628
1677
|
repositoryPath: this.config.repositoryPath,
|
|
1629
1678
|
error,
|
|
1630
1679
|
});
|
|
@@ -1645,7 +1694,7 @@ ${attributionInstructions}
|
|
|
1645
1694
|
});
|
|
1646
1695
|
this.lastReportedBranch = branchName;
|
|
1647
1696
|
} catch (error) {
|
|
1648
|
-
this.logger.
|
|
1697
|
+
this.logger.debug("Failed to attach current branch to task run", {
|
|
1649
1698
|
taskId: payload.task_id,
|
|
1650
1699
|
runId: payload.run_id,
|
|
1651
1700
|
branchName,
|
|
@@ -1657,6 +1706,7 @@ ${attributionInstructions}
|
|
|
1657
1706
|
private async signalTaskComplete(
|
|
1658
1707
|
payload: JwtPayload,
|
|
1659
1708
|
stopReason: string,
|
|
1709
|
+
errorMessage?: string,
|
|
1660
1710
|
): Promise<void> {
|
|
1661
1711
|
if (this.session?.payload.run_id === payload.run_id) {
|
|
1662
1712
|
try {
|
|
@@ -1664,7 +1714,7 @@ ${attributionInstructions}
|
|
|
1664
1714
|
coalesce: true,
|
|
1665
1715
|
});
|
|
1666
1716
|
} catch (error) {
|
|
1667
|
-
this.logger.
|
|
1717
|
+
this.logger.debug("Failed to flush session logs before completion", {
|
|
1668
1718
|
taskId: payload.task_id,
|
|
1669
1719
|
runId: payload.run_id,
|
|
1670
1720
|
error,
|
|
@@ -1673,7 +1723,7 @@ ${attributionInstructions}
|
|
|
1673
1723
|
}
|
|
1674
1724
|
|
|
1675
1725
|
if (stopReason !== "error") {
|
|
1676
|
-
this.logger.
|
|
1726
|
+
this.logger.debug("Skipping status update for non-error stop reason", {
|
|
1677
1727
|
stopReason,
|
|
1678
1728
|
});
|
|
1679
1729
|
return;
|
|
@@ -1684,9 +1734,9 @@ ${attributionInstructions}
|
|
|
1684
1734
|
try {
|
|
1685
1735
|
await this.posthogAPI.updateTaskRun(payload.task_id, payload.run_id, {
|
|
1686
1736
|
status,
|
|
1687
|
-
error_message:
|
|
1737
|
+
error_message: errorMessage ?? "Agent error",
|
|
1688
1738
|
});
|
|
1689
|
-
this.logger.
|
|
1739
|
+
this.logger.debug("Task completion signaled", { status, stopReason });
|
|
1690
1740
|
} catch (error) {
|
|
1691
1741
|
this.logger.error("Failed to signal task completion", error);
|
|
1692
1742
|
}
|
|
@@ -1823,7 +1873,7 @@ ${attributionInstructions}
|
|
|
1823
1873
|
isPlanApproval ||
|
|
1824
1874
|
(needsDesktopApproval && this.session?.hasDesktopConnected)
|
|
1825
1875
|
) {
|
|
1826
|
-
this.logger.
|
|
1876
|
+
this.logger.debug("Relaying permission request", {
|
|
1827
1877
|
kind: params.toolCall?.kind,
|
|
1828
1878
|
isQuestion,
|
|
1829
1879
|
hasDesktopConnected: this.session?.hasDesktopConnected ?? false,
|
|
@@ -1868,7 +1918,7 @@ ${attributionInstructions}
|
|
|
1868
1918
|
) {
|
|
1869
1919
|
this.session.permissionMode = params.update
|
|
1870
1920
|
.currentModeId as PermissionMode;
|
|
1871
|
-
this.logger.
|
|
1921
|
+
this.logger.debug("Permission mode updated", {
|
|
1872
1922
|
mode: params.update.currentModeId,
|
|
1873
1923
|
});
|
|
1874
1924
|
}
|
|
@@ -1914,7 +1964,7 @@ ${attributionInstructions}
|
|
|
1914
1964
|
try {
|
|
1915
1965
|
await this.session.logWriter.flush(payload.run_id, { coalesce: true });
|
|
1916
1966
|
} catch (error) {
|
|
1917
|
-
this.logger.
|
|
1967
|
+
this.logger.debug("Failed to flush logs before Slack relay", {
|
|
1918
1968
|
taskId: payload.task_id,
|
|
1919
1969
|
runId: payload.run_id,
|
|
1920
1970
|
error,
|
|
@@ -1923,7 +1973,7 @@ ${attributionInstructions}
|
|
|
1923
1973
|
|
|
1924
1974
|
const message = this.session.logWriter.getFullAgentResponse(payload.run_id);
|
|
1925
1975
|
if (!message) {
|
|
1926
|
-
this.logger.
|
|
1976
|
+
this.logger.debug("No agent message found for Slack relay", {
|
|
1927
1977
|
taskId: payload.task_id,
|
|
1928
1978
|
runId: payload.run_id,
|
|
1929
1979
|
sessionRegistered: this.session.logWriter.isRegistered(payload.run_id),
|
|
@@ -1938,7 +1988,7 @@ ${attributionInstructions}
|
|
|
1938
1988
|
message,
|
|
1939
1989
|
);
|
|
1940
1990
|
} catch (error) {
|
|
1941
|
-
this.logger.
|
|
1991
|
+
this.logger.debug("Failed to relay initial agent response to Slack", {
|
|
1942
1992
|
taskId: payload.task_id,
|
|
1943
1993
|
runId: payload.run_id,
|
|
1944
1994
|
error,
|
|
@@ -1971,7 +2021,7 @@ ${attributionInstructions}
|
|
|
1971
2021
|
this.posthogAPI
|
|
1972
2022
|
.relayMessage(payload.task_id, payload.run_id, message)
|
|
1973
2023
|
.catch((err) =>
|
|
1974
|
-
this.logger.
|
|
2024
|
+
this.logger.debug("Failed to relay question to Slack", { err }),
|
|
1975
2025
|
);
|
|
1976
2026
|
}
|
|
1977
2027
|
|
|
@@ -2069,7 +2119,7 @@ ${attributionInstructions}
|
|
|
2069
2119
|
|
|
2070
2120
|
const prUrl = prUrlMatch[0];
|
|
2071
2121
|
this.detectedPrUrl = prUrl;
|
|
2072
|
-
this.logger.
|
|
2122
|
+
this.logger.debug("Detected PR URL in bash output", {
|
|
2073
2123
|
runId: payload.run_id,
|
|
2074
2124
|
prUrl,
|
|
2075
2125
|
});
|
|
@@ -2080,7 +2130,7 @@ ${attributionInstructions}
|
|
|
2080
2130
|
output: { pr_url: prUrl },
|
|
2081
2131
|
})
|
|
2082
2132
|
.then(() => {
|
|
2083
|
-
this.logger.
|
|
2133
|
+
this.logger.debug("PR URL attached to task run", {
|
|
2084
2134
|
taskId: payload.task_id,
|
|
2085
2135
|
runId: payload.run_id,
|
|
2086
2136
|
prUrl,
|
|
@@ -2106,7 +2156,7 @@ ${attributionInstructions}
|
|
|
2106
2156
|
private async cleanupSession(): Promise<void> {
|
|
2107
2157
|
if (!this.session) return;
|
|
2108
2158
|
|
|
2109
|
-
this.logger.
|
|
2159
|
+
this.logger.debug("Cleaning up session");
|
|
2110
2160
|
|
|
2111
2161
|
try {
|
|
2112
2162
|
await this.captureTreeState();
|