doer-agent 0.5.4 → 0.5.6
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-session-rpc.js +43 -31
- package/package.json +1 -1
|
@@ -13,7 +13,6 @@ const SESSION_RPC_BLOB_KEYS = new Set([
|
|
|
13
13
|
"bytes",
|
|
14
14
|
"data",
|
|
15
15
|
]);
|
|
16
|
-
const SESSION_RPC_MAX_STRING_CHARS = 512;
|
|
17
16
|
function getSessionsRootPath(workspaceRoot) {
|
|
18
17
|
return path.join(workspaceRoot, ".codex", "sessions");
|
|
19
18
|
}
|
|
@@ -90,19 +89,27 @@ function buildInlineBlobMarker(value) {
|
|
|
90
89
|
}
|
|
91
90
|
return "[inline blob omitted]";
|
|
92
91
|
}
|
|
93
|
-
function
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
function getSessionRpcPayloadByteLength(value) {
|
|
93
|
+
try {
|
|
94
|
+
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
95
|
+
return typeof serialized === "string" ? Buffer.byteLength(serialized, "utf8") : null;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
96
99
|
}
|
|
97
|
-
const omittedChars = value.length - SESSION_RPC_MAX_STRING_CHARS;
|
|
98
|
-
return `${value.slice(0, SESSION_RPC_MAX_STRING_CHARS)}\n[truncated ${omittedChars} chars for session RPC]`;
|
|
99
100
|
}
|
|
100
|
-
function
|
|
101
|
+
function buildSessionRpcTruncatedMarker(label, value) {
|
|
102
|
+
const byteLength = getSessionRpcPayloadByteLength(value);
|
|
103
|
+
return byteLength === null
|
|
104
|
+
? `[${label} truncated for session RPC pagination]`
|
|
105
|
+
: `[${label} truncated for session RPC pagination: ${byteLength} bytes omitted]`;
|
|
106
|
+
}
|
|
107
|
+
function sanitizeSessionRpcPayload(value) {
|
|
101
108
|
if (typeof value === "string") {
|
|
102
|
-
return
|
|
109
|
+
return value;
|
|
103
110
|
}
|
|
104
111
|
if (Array.isArray(value)) {
|
|
105
|
-
return value.map((entry) => sanitizeSessionRpcPayload(entry
|
|
112
|
+
return value.map((entry) => sanitizeSessionRpcPayload(entry));
|
|
106
113
|
}
|
|
107
114
|
if (!isObjectRecord(value)) {
|
|
108
115
|
return value;
|
|
@@ -113,7 +120,7 @@ function sanitizeSessionRpcPayload(value, options = {}) {
|
|
|
113
120
|
sanitized[key] = buildInlineBlobMarker(entry);
|
|
114
121
|
continue;
|
|
115
122
|
}
|
|
116
|
-
sanitized[key] = sanitizeSessionRpcPayload(entry
|
|
123
|
+
sanitized[key] = sanitizeSessionRpcPayload(entry);
|
|
117
124
|
}
|
|
118
125
|
return sanitized;
|
|
119
126
|
}
|
|
@@ -130,7 +137,7 @@ function sanitizeSessionRpcRawLine(line) {
|
|
|
130
137
|
if (parsed.type === "compacted" || parsed.type === "turn_context" || parsed.type === "session_meta") {
|
|
131
138
|
return JSON.stringify({
|
|
132
139
|
...parsed,
|
|
133
|
-
payload:
|
|
140
|
+
payload: buildSessionRpcTruncatedMarker("payload", parsed.payload),
|
|
134
141
|
});
|
|
135
142
|
}
|
|
136
143
|
if (!isObjectRecord(parsed.payload)) {
|
|
@@ -146,7 +153,7 @@ function sanitizeSessionRpcRawLine(line) {
|
|
|
146
153
|
payload: {
|
|
147
154
|
type: payloadType,
|
|
148
155
|
status: typeof parsed.payload.status === "string" ? parsed.payload.status : "completed",
|
|
149
|
-
message:
|
|
156
|
+
message: buildSessionRpcTruncatedMarker(`${payloadType} payload`, parsed.payload),
|
|
150
157
|
},
|
|
151
158
|
});
|
|
152
159
|
}
|
|
@@ -175,6 +182,10 @@ function pickSessionString(...values) {
|
|
|
175
182
|
}
|
|
176
183
|
return null;
|
|
177
184
|
}
|
|
185
|
+
function toSortableTimestampMs(value) {
|
|
186
|
+
const parsed = Date.parse(value);
|
|
187
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
188
|
+
}
|
|
178
189
|
export async function collectSessionJsonlFiles(workspaceRoot) {
|
|
179
190
|
const out = [];
|
|
180
191
|
const stack = [getSessionsRootPath(workspaceRoot)];
|
|
@@ -233,8 +244,14 @@ async function readFirstLine(fileHandle, fileSize) {
|
|
|
233
244
|
}
|
|
234
245
|
return raw.trim();
|
|
235
246
|
}
|
|
236
|
-
function
|
|
237
|
-
|
|
247
|
+
function normalizeSessionSummaryMessage(value) {
|
|
248
|
+
const message = toTrimmedStringOrNull(value);
|
|
249
|
+
if (!message || message.toLowerCase() === "empty") {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
return message;
|
|
253
|
+
}
|
|
254
|
+
function extractLastSessionMessage(candidateLines) {
|
|
238
255
|
for (const line of candidateLines) {
|
|
239
256
|
const trimmed = line.trim();
|
|
240
257
|
if (!trimmed) {
|
|
@@ -245,18 +262,13 @@ function extractLastAgentMessage(candidateLines) {
|
|
|
245
262
|
if (parsed.type !== "event_msg" || !isObjectRecord(parsed.payload)) {
|
|
246
263
|
continue;
|
|
247
264
|
}
|
|
248
|
-
if (parsed.payload.type
|
|
249
|
-
|
|
250
|
-
message: parsed.payload.message.trim(),
|
|
251
|
-
updatedAt: toTrimmedStringOrNull(parsed.timestamp),
|
|
252
|
-
};
|
|
265
|
+
if (parsed.payload.type !== "agent_message" && parsed.payload.type !== "user_message") {
|
|
266
|
+
continue;
|
|
253
267
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
fallback = {
|
|
259
|
-
message: parsed.payload.last_agent_message.trim(),
|
|
268
|
+
const message = normalizeSessionSummaryMessage(parsed.payload.message);
|
|
269
|
+
if (message) {
|
|
270
|
+
return {
|
|
271
|
+
message,
|
|
260
272
|
updatedAt: toTrimmedStringOrNull(parsed.timestamp),
|
|
261
273
|
};
|
|
262
274
|
}
|
|
@@ -265,9 +277,9 @@ function extractLastAgentMessage(candidateLines) {
|
|
|
265
277
|
// ignore malformed lines
|
|
266
278
|
}
|
|
267
279
|
}
|
|
268
|
-
return
|
|
280
|
+
return null;
|
|
269
281
|
}
|
|
270
|
-
async function
|
|
282
|
+
async function readLastSessionMessage(fileHandle, fileSize) {
|
|
271
283
|
const chunkBytes = 16_384;
|
|
272
284
|
const maxScanBytes = 131_072;
|
|
273
285
|
if (fileSize <= 0) {
|
|
@@ -288,12 +300,12 @@ async function readLastAgentMessage(fileHandle, fileSize) {
|
|
|
288
300
|
const merged = buffer.toString("utf8", 0, bytesRead) + carry;
|
|
289
301
|
const lines = merged.split(/\r?\n/);
|
|
290
302
|
carry = lines.shift() || "";
|
|
291
|
-
const found =
|
|
303
|
+
const found = extractLastSessionMessage(lines.reverse());
|
|
292
304
|
if (found) {
|
|
293
305
|
return found;
|
|
294
306
|
}
|
|
295
307
|
}
|
|
296
|
-
return
|
|
308
|
+
return extractLastSessionMessage([carry]);
|
|
297
309
|
}
|
|
298
310
|
function normalizeSessionMeta(rawMeta, filePath, mtimeMs) {
|
|
299
311
|
const baseName = path.basename(filePath, path.extname(filePath));
|
|
@@ -315,7 +327,7 @@ async function readSessionSummary(filePath, mtimeMs) {
|
|
|
315
327
|
fileHandle = await open(filePath, "r");
|
|
316
328
|
const entryStat = await fileHandle.stat();
|
|
317
329
|
const firstLine = await readFirstLine(fileHandle, entryStat.size);
|
|
318
|
-
const tailSummary = await
|
|
330
|
+
const tailSummary = await readLastSessionMessage(fileHandle, entryStat.size);
|
|
319
331
|
let normalized = normalizeSessionMeta({}, filePath, mtimeMs);
|
|
320
332
|
if (firstLine) {
|
|
321
333
|
try {
|
|
@@ -365,7 +377,7 @@ async function listAgentSessions(workspaceRoot) {
|
|
|
365
377
|
const files = await collectSessionJsonlFiles(workspaceRoot);
|
|
366
378
|
files.sort((a, b) => b.mtimeMs - a.mtimeMs || a.filePath.localeCompare(b.filePath));
|
|
367
379
|
const sessions = await Promise.all(files.slice(0, 10).map((file) => readSessionSummary(file.filePath, file.mtimeMs)));
|
|
368
|
-
return sessions.sort((a, b) =>
|
|
380
|
+
return sessions.sort((a, b) => toSortableTimestampMs(b.updatedAt) - toSortableTimestampMs(a.updatedAt) || b.filePath.localeCompare(a.filePath));
|
|
369
381
|
}
|
|
370
382
|
async function readSessionLineIndex(workspaceRoot, filePath) {
|
|
371
383
|
const resolvedFile = resolveSessionFilePath(workspaceRoot, filePath);
|