agent-relay-runner 0.119.10 → 0.119.11
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/package.json
CHANGED
|
@@ -2,6 +2,10 @@ type EmitAgentMessage = (body: string) => void;
|
|
|
2
2
|
type ResponseEntry = { itemId?: string; body: string };
|
|
3
3
|
type CompleteItemOptions = { includeInResponse?: boolean; phase?: unknown };
|
|
4
4
|
|
|
5
|
+
const MAX_CAPTURED_RESPONSE_CHARS = 16_000;
|
|
6
|
+
const TRUNCATION_MARKER_PREFIX = "[truncated:";
|
|
7
|
+
const TERSE_FINAL_MAX_CHARS = 280;
|
|
8
|
+
|
|
5
9
|
export class CodexAgentMessageCapture {
|
|
6
10
|
private segments: ResponseEntry[][] = [];
|
|
7
11
|
private currentSegment: ResponseEntry[] = [];
|
|
@@ -44,9 +48,10 @@ export class CodexAgentMessageCapture {
|
|
|
44
48
|
|
|
45
49
|
finish(emit: EmitAgentMessage): string | undefined {
|
|
46
50
|
this.closeSegment(emit);
|
|
47
|
-
const
|
|
51
|
+
const selectedSegments = selectResponseSegments(this.segments);
|
|
48
52
|
this.segments = [];
|
|
49
|
-
|
|
53
|
+
const text = selectedSegments.length ? selectedSegments.map(segmentBody).join("\n\n").trim() : undefined;
|
|
54
|
+
return truncateCapturedResponse(text);
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
private flushPending(emit: EmitAgentMessage): void {
|
|
@@ -90,3 +95,45 @@ export class CodexAgentMessageCapture {
|
|
|
90
95
|
.filter((segment) => segment.length > 0);
|
|
91
96
|
}
|
|
92
97
|
}
|
|
98
|
+
|
|
99
|
+
function selectResponseSegments(segments: ResponseEntry[][]): ResponseEntry[][] {
|
|
100
|
+
const nonEmptySegments = segments.filter((segment) => segment.length > 0);
|
|
101
|
+
const finalSegment = nonEmptySegments.at(-1);
|
|
102
|
+
if (!finalSegment) return [];
|
|
103
|
+
const finalBody = segmentBody(finalSegment);
|
|
104
|
+
if (!isTerseTerminalStatus(finalBody)) return [finalSegment];
|
|
105
|
+
|
|
106
|
+
// Codex often posts the real wrap-up across multiple assistant segments before a
|
|
107
|
+
// final workspace-ready/status line. Keep contiguous substantive segments after
|
|
108
|
+
// the last procedural assistant segment, then append the terminal status.
|
|
109
|
+
const selectedSegments: ResponseEntry[][] = [];
|
|
110
|
+
for (let index = nonEmptySegments.length - 2; index >= 0; index -= 1) {
|
|
111
|
+
const candidate = nonEmptySegments[index];
|
|
112
|
+
if (!candidate || !isSubstantiveResponseSegment(segmentBody(candidate))) break;
|
|
113
|
+
selectedSegments.unshift(candidate);
|
|
114
|
+
}
|
|
115
|
+
return [...selectedSegments, finalSegment];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function segmentBody(segment: ResponseEntry[]): string {
|
|
119
|
+
return segment.map((entry) => entry.body).join("\n\n").trim();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function isTerseTerminalStatus(body: string): boolean {
|
|
123
|
+
if (body.length > TERSE_FINAL_MAX_CHARS) return false;
|
|
124
|
+
if (/\n\s*(?:[-*]|\d+\.)\s+/.test(body)) return false;
|
|
125
|
+
return /\b(?:landed|ready for review|handed off|no further action|done|complete|completed|committed|merged)\b/i.test(body);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function isSubstantiveResponseSegment(body: string): boolean {
|
|
129
|
+
if (body.length >= 120) return true;
|
|
130
|
+
if (/\n\s*(?:[-*]|\d+\.)\s+/.test(body)) return true;
|
|
131
|
+
if (/\*\*(?:what changed|changes?|tests?|gates?|verification|risks?|residual risk|summary)\b/i.test(body)) return true;
|
|
132
|
+
if (/^#{1,3}\s+\S/m.test(body)) return true;
|
|
133
|
+
return body.split(/\n{2,}/).length >= 2;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function truncateCapturedResponse(text: string | undefined): string | undefined {
|
|
137
|
+
if (!text || text.length <= MAX_CAPTURED_RESPONSE_CHARS) return text;
|
|
138
|
+
return `${text.slice(0, MAX_CAPTURED_RESPONSE_CHARS).trimEnd()}\n\n${TRUNCATION_MARKER_PREFIX} showing first ${MAX_CAPTURED_RESPONSE_CHARS} of ${text.length} chars]`;
|
|
139
|
+
}
|
package/src/adapters/codex.ts
CHANGED
|
@@ -533,9 +533,9 @@ export class CodexAdapter implements ProviderAdapter {
|
|
|
533
533
|
}
|
|
534
534
|
|
|
535
535
|
// Turn one completed Codex thread item into a session-mirror event. agentMessage text is
|
|
536
|
-
// mirrored as narration as it lands;
|
|
537
|
-
//
|
|
538
|
-
// as it lands.
|
|
536
|
+
// mirrored as narration as it lands; the captured turn-final response repeats the substantive
|
|
537
|
+
// assistant answer, including a substantive wrap-up segment before a terse terminal status.
|
|
538
|
+
// The rest (user prompt echo, reasoning, tool steps) is surfaced as it lands.
|
|
539
539
|
private handleCodexItem(item: Record<string, unknown> | undefined): void {
|
|
540
540
|
if (!item) return;
|
|
541
541
|
const type = stringValue(item.type);
|