shennian 0.2.58 → 0.2.61
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/src/agents/pi.js
CHANGED
|
@@ -471,12 +471,12 @@ export class PiAdapter extends AgentAdapter {
|
|
|
471
471
|
return;
|
|
472
472
|
this.terminalState = 'error';
|
|
473
473
|
const message = err instanceof Error ? err.message : String(err);
|
|
474
|
-
if (message.includes('429') || message.includes('daily_quota_exceeded')) {
|
|
474
|
+
if (message.includes('429') || message.includes('daily_quota_exceeded') || message.includes('nian_quota_exceeded')) {
|
|
475
475
|
this.emit('agentEvent', {
|
|
476
476
|
state: 'error',
|
|
477
477
|
runId,
|
|
478
478
|
seq: ++this.seq,
|
|
479
|
-
message: '
|
|
479
|
+
message: 'Nian 今日额度已用完,次日自动恢复。',
|
|
480
480
|
});
|
|
481
481
|
}
|
|
482
482
|
else {
|
|
@@ -257,7 +257,7 @@ export class ManagerRegistry {
|
|
|
257
257
|
function readableText(message) {
|
|
258
258
|
if (!message || isToolPayload(message.payload))
|
|
259
259
|
return null;
|
|
260
|
-
const text = extractPayloadText(message.payload).replace(/\
|
|
260
|
+
const text = extractPayloadText(message.payload).replace(/\r\n/g, '\n').trim();
|
|
261
261
|
return text || null;
|
|
262
262
|
}
|
|
263
263
|
function clip(text, max) {
|
|
@@ -29,6 +29,16 @@ function runIdFromMessageId(id) {
|
|
|
29
29
|
const match = /^agent-(.+)-\d+$/.exec(id);
|
|
30
30
|
return match?.[1] ?? null;
|
|
31
31
|
}
|
|
32
|
+
function seqFromMessageId(id) {
|
|
33
|
+
const match = /^agent-.+-(\d+)$/.exec(id);
|
|
34
|
+
if (!match)
|
|
35
|
+
return null;
|
|
36
|
+
const seq = Number(match[1]);
|
|
37
|
+
return Number.isInteger(seq) && seq >= 0 ? seq : null;
|
|
38
|
+
}
|
|
39
|
+
function normalizeMarkdownForWorkerSummary(text) {
|
|
40
|
+
return text.replace(/\r\n/g, '\n').trim();
|
|
41
|
+
}
|
|
32
42
|
function toolSummary(payload) {
|
|
33
43
|
try {
|
|
34
44
|
const parsed = JSON.parse(payload);
|
|
@@ -62,6 +72,7 @@ function compactWorkerTranscript(rawMessages, limit) {
|
|
|
62
72
|
const compacted = [];
|
|
63
73
|
let buffer = null;
|
|
64
74
|
let bufferRunId = null;
|
|
75
|
+
let bufferSeq = null;
|
|
65
76
|
let bufferText = '';
|
|
66
77
|
const flush = () => {
|
|
67
78
|
if (!buffer)
|
|
@@ -76,6 +87,7 @@ function compactWorkerTranscript(rawMessages, limit) {
|
|
|
76
87
|
}
|
|
77
88
|
buffer = null;
|
|
78
89
|
bufferRunId = null;
|
|
90
|
+
bufferSeq = null;
|
|
79
91
|
bufferText = '';
|
|
80
92
|
};
|
|
81
93
|
for (const message of chronological) {
|
|
@@ -96,14 +108,17 @@ function compactWorkerTranscript(rawMessages, limit) {
|
|
|
96
108
|
if (!text.trim())
|
|
97
109
|
continue;
|
|
98
110
|
const runId = runIdFromMessageId(message.id);
|
|
99
|
-
|
|
111
|
+
const seq = seqFromMessageId(message.id);
|
|
112
|
+
if (buffer && buffer.role === message.role && bufferRunId === runId && runId && seq !== null && bufferSeq !== null && seq === bufferSeq + 1) {
|
|
100
113
|
bufferText += text;
|
|
101
114
|
buffer.ts = message.ts;
|
|
115
|
+
bufferSeq = seq;
|
|
102
116
|
}
|
|
103
117
|
else {
|
|
104
118
|
flush();
|
|
105
119
|
buffer = message;
|
|
106
120
|
bufferRunId = runId;
|
|
121
|
+
bufferSeq = seq;
|
|
107
122
|
bufferText = text;
|
|
108
123
|
}
|
|
109
124
|
}
|
|
@@ -261,14 +276,14 @@ export class ManagerRuntimeService {
|
|
|
261
276
|
if (event.state === 'delta' && event.text && !event.thinking) {
|
|
262
277
|
const nextText = (this.workerTextAcc.get(textKey) ?? '') + event.text;
|
|
263
278
|
this.workerTextAcc.set(textKey, nextText);
|
|
264
|
-
const normalized = nextText
|
|
279
|
+
const normalized = normalizeMarkdownForWorkerSummary(nextText);
|
|
265
280
|
if (normalized) {
|
|
266
281
|
patch.summary = normalized.length > 160 ? `${normalized.slice(0, 160)}...` : normalized;
|
|
267
282
|
}
|
|
268
283
|
}
|
|
269
284
|
if (event.state === 'final' || event.state === 'error' || event.state === 'aborted') {
|
|
270
285
|
patch.status = event.state;
|
|
271
|
-
const accumulated = this.workerTextAcc.get(textKey)
|
|
286
|
+
const accumulated = normalizeMarkdownForWorkerSummary(this.workerTextAcc.get(textKey) ?? '');
|
|
272
287
|
if (accumulated) {
|
|
273
288
|
patch.summary = accumulated.length > 240 ? `${accumulated.slice(0, 240)}...` : accumulated;
|
|
274
289
|
}
|
|
@@ -350,6 +350,111 @@ function parseCodexUserMessage(payload) {
|
|
|
350
350
|
}
|
|
351
351
|
return { payload: text, titleText: text };
|
|
352
352
|
}
|
|
353
|
+
function isCodexTerminalEventType(eventType) {
|
|
354
|
+
return eventType === 'turn_completed' || eventType === 'turn_complete' || eventType === 'task_complete';
|
|
355
|
+
}
|
|
356
|
+
function codexMessageContentText(content, textType) {
|
|
357
|
+
if (!Array.isArray(content))
|
|
358
|
+
return '';
|
|
359
|
+
return normalizeText(content
|
|
360
|
+
.map((part) => {
|
|
361
|
+
if (typeof part === 'string')
|
|
362
|
+
return part;
|
|
363
|
+
if (typeof part !== 'object' || part === null)
|
|
364
|
+
return '';
|
|
365
|
+
const record = part;
|
|
366
|
+
if (record.type !== textType)
|
|
367
|
+
return '';
|
|
368
|
+
return typeof record.text === 'string' ? record.text : '';
|
|
369
|
+
})
|
|
370
|
+
.filter(Boolean)
|
|
371
|
+
.join('\n\n'));
|
|
372
|
+
}
|
|
373
|
+
function codexMessageInputImageAttachments(content) {
|
|
374
|
+
if (!Array.isArray(content))
|
|
375
|
+
return [];
|
|
376
|
+
const attachments = [];
|
|
377
|
+
for (const part of content) {
|
|
378
|
+
if (typeof part !== 'object' || part === null)
|
|
379
|
+
continue;
|
|
380
|
+
const record = part;
|
|
381
|
+
if (record.type !== 'input_image')
|
|
382
|
+
continue;
|
|
383
|
+
const imagePath = typeof record.path === 'string' ? record.path
|
|
384
|
+
: typeof record.file_path === 'string' ? record.file_path
|
|
385
|
+
: typeof record.saved_path === 'string' ? record.saved_path
|
|
386
|
+
: typeof record.image_path === 'string' ? record.image_path
|
|
387
|
+
: '';
|
|
388
|
+
if (!imagePath.trim())
|
|
389
|
+
continue;
|
|
390
|
+
attachments.push({
|
|
391
|
+
path: imagePath,
|
|
392
|
+
name: path.basename(imagePath) || 'image.png',
|
|
393
|
+
mimeType: inferMimeType(imagePath),
|
|
394
|
+
kind: 'image',
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
return attachments;
|
|
398
|
+
}
|
|
399
|
+
function parseCodexResponseMessage(payload) {
|
|
400
|
+
if (payload.type !== 'message')
|
|
401
|
+
return null;
|
|
402
|
+
const role = payload.role === 'assistant' ? 'agent' : payload.role === 'user' ? 'user' : null;
|
|
403
|
+
if (!role)
|
|
404
|
+
return null;
|
|
405
|
+
if (role === 'agent') {
|
|
406
|
+
const text = codexMessageContentText(payload.content, 'output_text');
|
|
407
|
+
return text ? { role, payload: text, titleText: text } : null;
|
|
408
|
+
}
|
|
409
|
+
const text = codexMessageContentText(payload.content, 'input_text');
|
|
410
|
+
const attachments = codexMessageInputImageAttachments(payload.content);
|
|
411
|
+
if (!text && attachments.length === 0)
|
|
412
|
+
return null;
|
|
413
|
+
return {
|
|
414
|
+
role,
|
|
415
|
+
payload: attachments.length > 0 ? buildUserMessagePayload(text, attachments) : text,
|
|
416
|
+
titleText: text,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function codexDedupeText(payload) {
|
|
420
|
+
if (!payload)
|
|
421
|
+
return '';
|
|
422
|
+
try {
|
|
423
|
+
const parsed = JSON.parse(payload);
|
|
424
|
+
if (typeof parsed === 'object' && parsed !== null) {
|
|
425
|
+
const record = parsed;
|
|
426
|
+
if (record.type === 'user' && typeof record.content === 'string')
|
|
427
|
+
return normalizeText(record.content);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
catch {
|
|
431
|
+
/* plain text payload */
|
|
432
|
+
}
|
|
433
|
+
return normalizeText(payload);
|
|
434
|
+
}
|
|
435
|
+
function isDuplicateCodexChatEvent(event, role, payload, ts) {
|
|
436
|
+
if (event.agentType !== 'codex')
|
|
437
|
+
return false;
|
|
438
|
+
if (event.role !== role)
|
|
439
|
+
return false;
|
|
440
|
+
if (isToolPayload(event.payload))
|
|
441
|
+
return false;
|
|
442
|
+
if (Math.abs(event.ts - ts) > 5 * 60 * 1000)
|
|
443
|
+
return false;
|
|
444
|
+
return codexDedupeText(event.payload) === codexDedupeText(payload);
|
|
445
|
+
}
|
|
446
|
+
function findDuplicateCodexChatEventIndex(events, role, payload, ts) {
|
|
447
|
+
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
448
|
+
const event = events[i];
|
|
449
|
+
if (!event)
|
|
450
|
+
continue;
|
|
451
|
+
if (isDuplicateCodexChatEvent(event, role, payload, ts))
|
|
452
|
+
return i;
|
|
453
|
+
if (event.agentType === 'codex' && Math.abs(event.ts - ts) > 5 * 60 * 1000)
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
return -1;
|
|
457
|
+
}
|
|
353
458
|
function pushCodexEvent(events, filePath, lineOffset, kind, sourceSessionKey, ts, payload, title, modelId, workDir, role = 'agent', terminal = false) {
|
|
354
459
|
if (!payload)
|
|
355
460
|
return;
|
|
@@ -490,6 +595,16 @@ function parseCodexResponseItem(events, filePath, lineOffset, payload, sourceSes
|
|
|
490
595
|
const itemType = typeof payload.type === 'string' ? payload.type : '';
|
|
491
596
|
if (!itemType)
|
|
492
597
|
return;
|
|
598
|
+
if (itemType === 'message') {
|
|
599
|
+
const parsedMessage = parseCodexResponseMessage(payload);
|
|
600
|
+
if (!parsedMessage)
|
|
601
|
+
return;
|
|
602
|
+
const duplicateIndex = findDuplicateCodexChatEventIndex(events, parsedMessage.role, parsedMessage.payload, ts);
|
|
603
|
+
if (duplicateIndex >= 0)
|
|
604
|
+
return;
|
|
605
|
+
pushCodexEvent(events, filePath, lineOffset, `${itemType}:${parsedMessage.role}`, sourceSessionKey, ts, parsedMessage.payload, title, modelId, workDir, parsedMessage.role);
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
493
608
|
if (itemType === 'function_call') {
|
|
494
609
|
const name = typeof payload.name === 'string' ? payload.name : 'function_call';
|
|
495
610
|
pushCodexToolEvent(events, filePath, lineOffset, itemType, sourceSessionKey, ts, name, title, modelId, workDir, parseStructuredString(payload.arguments));
|
|
@@ -803,12 +918,16 @@ export function parseCodexRolloutChunk(filePath, startOffset) {
|
|
|
803
918
|
if (!sourceSessionKey)
|
|
804
919
|
return;
|
|
805
920
|
if (type === 'response_item') {
|
|
921
|
+
const parsedMessage = parseCodexResponseMessage(payload);
|
|
922
|
+
if (parsedMessage?.role === 'user' && parsedMessage.titleText && !title) {
|
|
923
|
+
title = parsedMessage.titleText.slice(0, 80);
|
|
924
|
+
}
|
|
806
925
|
parseCodexResponseItem(events, filePath, lineOffset, payload, sourceSessionKey, ts, title, modelId, workDir);
|
|
807
926
|
return;
|
|
808
927
|
}
|
|
809
928
|
if (type === 'event_msg') {
|
|
810
929
|
const eventType = typeof payload.type === 'string' ? payload.type : '';
|
|
811
|
-
if (eventType
|
|
930
|
+
if (isCodexTerminalEventType(eventType)) {
|
|
812
931
|
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
813
932
|
const event = events[i];
|
|
814
933
|
if (event?.agentType !== 'codex')
|
|
@@ -827,6 +946,19 @@ export function parseCodexRolloutChunk(filePath, startOffset) {
|
|
|
827
946
|
const parsedUser = parseCodexUserMessage(payload);
|
|
828
947
|
if (parsedUser?.titleText && !title)
|
|
829
948
|
title = parsedUser.titleText.slice(0, 80);
|
|
949
|
+
if (parsedUser) {
|
|
950
|
+
const duplicateIndex = findDuplicateCodexChatEventIndex(events, 'user', parsedUser.payload, ts);
|
|
951
|
+
if (duplicateIndex >= 0)
|
|
952
|
+
events.splice(duplicateIndex, 1);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
else if (eventType === 'agent_message') {
|
|
956
|
+
const text = typeof payload.message === 'string' ? normalizeText(payload.message) : '';
|
|
957
|
+
if (text) {
|
|
958
|
+
const duplicateIndex = findDuplicateCodexChatEventIndex(events, 'agent', text, ts);
|
|
959
|
+
if (duplicateIndex >= 0)
|
|
960
|
+
events.splice(duplicateIndex, 1);
|
|
961
|
+
}
|
|
830
962
|
}
|
|
831
963
|
const beforeCount = events.length;
|
|
832
964
|
parseCodexEventMessage(events, filePath, lineOffset, payload, sourceSessionKey, ts, title, modelId, workDir);
|