fix: dedup intermediate/final, filter long descriptions, update SDKs

- Track lastIntermediateText to prevent duplicate Discord delivery
  when same text arrives as both intermediate and final
- Filter task_progress descriptions >80 chars (AI summaries)
- Mark completed subagents with  instead of removing
- Update claude-agent-sdk 0.2.76→0.2.81, codex 0.115→0.116
This commit is contained in:
Eyejoker
2026-03-23 20:16:54 +09:00
parent 21a6be84b4
commit 2161b555ec
6 changed files with 62 additions and 52 deletions

View File

@@ -9,7 +9,7 @@
"start": "node dist/index.js"
},
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.2.76",
"@anthropic-ai/claude-agent-sdk": "^0.2.81",
"@modelcontextprotocol/sdk": "^1.12.1",
"cron-parser": "^5.0.0",
"zod": "^4.0.0"

View File

@@ -9,8 +9,8 @@ importers:
.:
dependencies:
'@anthropic-ai/claude-agent-sdk':
specifier: ^0.2.76
version: 0.2.76(zod@4.3.6)
specifier: ^0.2.81
version: 0.2.81(zod@4.3.6)
'@modelcontextprotocol/sdk':
specifier: ^1.12.1
version: 1.27.1(zod@4.3.6)
@@ -30,8 +30,8 @@ importers:
packages:
'@anthropic-ai/claude-agent-sdk@0.2.76':
resolution: {integrity: sha512-HZxvnT8ZWkzCnQygaYCA0dl8RSUzuVbxE1YG4ecy6vh4nQbTT36CxUxBy+QVdR12pPQluncC0mCOLhI2918Eaw==}
'@anthropic-ai/claude-agent-sdk@0.2.81':
resolution: {integrity: sha512-CBeebgibBEN/DWOQGZN67vhuTG55RbI1hlsFSSoZ4uA/Io3lw04eHTE2ISCmdbqyJaefYTt6GKZei1nP0TQMNw==}
engines: {node: '>=18.0.0'}
peerDependencies:
zod: ^4.0.0
@@ -512,7 +512,7 @@ packages:
snapshots:
'@anthropic-ai/claude-agent-sdk@0.2.76(zod@4.3.6)':
'@anthropic-ai/claude-agent-sdk@0.2.81(zod@4.3.6)':
dependencies:
zod: 4.3.6
optionalDependencies:

View File

@@ -581,7 +581,8 @@ async function runQuery(
const taskId = typeof tp.task_id === 'string' ? tp.task_id : undefined;
const summary = typeof tp.summary === 'string' ? tp.summary : '';
const description = typeof tp.description === 'string' ? tp.description : '';
if (description) {
if (description && description.length <= 80) {
// Short tool description → show as sub-line in progress
writeOutput({
status: 'success',
phase: 'tool-activity',
@@ -589,6 +590,9 @@ async function runQuery(
agentId: taskId,
newSessionId,
});
} else if (description) {
// Long AI summary → skip (too long for progress sub-line)
log(`Skipping long task_progress description (${description.length} chars)`);
}
}

View File

@@ -9,7 +9,7 @@
"start": "node dist/index.js"
},
"dependencies": {
"@openai/codex": "^0.115.0"
"@openai/codex": "^0.116.0"
},
"devDependencies": {
"@types/node": "^22.10.7",

View File

@@ -8,9 +8,9 @@ importers:
.:
dependencies:
'@openai/codex-sdk':
specifier: ^0.115.0
version: 0.115.0
'@openai/codex':
specifier: ^0.116.0
version: 0.116.0
devDependencies:
'@types/node':
specifier: ^22.10.7
@@ -21,47 +21,43 @@ importers:
packages:
'@openai/codex-sdk@0.115.0':
resolution: {integrity: sha512-BPoPhim0uUm3rzugY7JFaFJ+rPG/wMRhvKNFii//Dp3kTb+gFy3jrip7ijXqhswsnqXM3nwTiv7kYHt1+TMUPg==}
engines: {node: '>=18'}
'@openai/codex@0.115.0':
resolution: {integrity: sha512-uu689DHUzvuPcb39hJ+7fqy++TAvY32w9VggDpcz3HS0Sx0WadWoAPPcMK547P2T6AqfMsAtA8kspkR3tqErOg==}
'@openai/codex@0.116.0':
resolution: {integrity: sha512-K6q9P2ZmpnzGmpS6Ybjvsdtvu8AbJx3f/Z4KmjH1u85StSS9TWMSQB8z0PPObKMejbtiIkHwhGyEIHi4iBYjig==}
engines: {node: '>=16'}
hasBin: true
'@openai/codex@0.115.0-darwin-arm64':
resolution: {integrity: sha512-wTWV+YlDTL0y0mL+FMmbzhilm+dPkbIZTe/lH3LwBzcEMhgSGLsPdZLfAiMND4wFE21HS7H0pjMogNQEMLQmqg==}
'@openai/codex@0.116.0-darwin-arm64':
resolution: {integrity: sha512-WkdL083p8uMeASpg8bwV0DPGgzkm48LjN3MyU2m/YukujbiLnknAmG29O2q2rFCLm0oLSDIGUK8EnXA4ZcAF9Q==}
engines: {node: '>=16'}
cpu: [arm64]
os: [darwin]
'@openai/codex@0.115.0-darwin-x64':
resolution: {integrity: sha512-EPzgymU4CFp83qjv29wXFwhWib3zC8g6SLTJGh2OpcJiOYyLY0bO53FB+QchL1jC9gm1uLyD5j5F3ddI0AbjIg==}
'@openai/codex@0.116.0-darwin-x64':
resolution: {integrity: sha512-Ax8uTwYSNIwGrzcNRcn0jJQhZzNcKGDbbn00Emde7gGOemjSLhRALjUaKjckAaW5xWnNqHTGdtzzPB4phNlDYg==}
engines: {node: '>=16'}
cpu: [x64]
os: [darwin]
'@openai/codex@0.115.0-linux-arm64':
resolution: {integrity: sha512-40+SCyI+LvVx/iX30qH7dTQzWt9MZxDaK2E6YRB4hoYej5UALrhkFNzweHa5uvqvhmqGZCuagZOYB8285eGCgw==}
'@openai/codex@0.116.0-linux-arm64':
resolution: {integrity: sha512-X7cL8rBSGDB+RSZc2FoKiqcMVeLPMmo06bkss/en4lLQsV1XG2DZI56WuXg92IOX3SjYl6Av/eOWgsb1t3UeLQ==}
engines: {node: '>=16'}
cpu: [arm64]
os: [linux]
'@openai/codex@0.115.0-linux-x64':
resolution: {integrity: sha512-+6eRd2p4KMrhQvuF7XpjYIdCA2Ok2LbhOq+ywZdLpHbmwQ/Yynd0gJ/Q90xCeo2vloCwl9WsbsiVVSahG5FyWg==}
'@openai/codex@0.116.0-linux-x64':
resolution: {integrity: sha512-S9InOgJT3tj6uQp55NqrCA1k5tklwFaH00JdC2ElbRmxchm7ard4WxHSJZX9TiY8enj4cQoLIC04NFTUCO+/PQ==}
engines: {node: '>=16'}
cpu: [x64]
os: [linux]
'@openai/codex@0.115.0-win32-arm64':
resolution: {integrity: sha512-yaYhQ0kPL9Kithmrr1vh5A4c+gqAMhMZeA/htTtkpWW8RQkmwgcYYpX/Ky2cEzu0w51pvxQQy63LgHftc+pg1Q==}
'@openai/codex@0.116.0-win32-arm64':
resolution: {integrity: sha512-kX2oAUzkgZX9OsYpd4omv9IGf+9VWj4Vy3UtIAnQKBu1DTSzmTJmXDuDn87mkyUciSZadm2QbeqQQzm2NC0NYw==}
engines: {node: '>=16'}
cpu: [arm64]
os: [win32]
'@openai/codex@0.115.0-win32-x64':
resolution: {integrity: sha512-wtYf2HJCB+p+Uj7o1W08fRgZMzKCVGRQ4YdSfLRNfF4wwPqX5XsK9blsv7brukn5J9lclYxagiR6qGvbfHbD7w==}
'@openai/codex@0.116.0-win32-x64':
resolution: {integrity: sha512-6sBIMOoA9FNuxQvCCnK0P548Wqrlk3I9SMdtOCUg2zYzYU7jOF2mWS1VpRQ6R+Jvo2x50dxeJZ+W37dBmXfprw==}
engines: {node: '>=16'}
cpu: [x64]
os: [win32]
@@ -79,35 +75,31 @@ packages:
snapshots:
'@openai/codex-sdk@0.115.0':
dependencies:
'@openai/codex': 0.115.0
'@openai/codex@0.115.0':
'@openai/codex@0.116.0':
optionalDependencies:
'@openai/codex-darwin-arm64': '@openai/codex@0.115.0-darwin-arm64'
'@openai/codex-darwin-x64': '@openai/codex@0.115.0-darwin-x64'
'@openai/codex-linux-arm64': '@openai/codex@0.115.0-linux-arm64'
'@openai/codex-linux-x64': '@openai/codex@0.115.0-linux-x64'
'@openai/codex-win32-arm64': '@openai/codex@0.115.0-win32-arm64'
'@openai/codex-win32-x64': '@openai/codex@0.115.0-win32-x64'
'@openai/codex-darwin-arm64': '@openai/codex@0.116.0-darwin-arm64'
'@openai/codex-darwin-x64': '@openai/codex@0.116.0-darwin-x64'
'@openai/codex-linux-arm64': '@openai/codex@0.116.0-linux-arm64'
'@openai/codex-linux-x64': '@openai/codex@0.116.0-linux-x64'
'@openai/codex-win32-arm64': '@openai/codex@0.116.0-win32-arm64'
'@openai/codex-win32-x64': '@openai/codex@0.116.0-win32-x64'
'@openai/codex@0.115.0-darwin-arm64':
'@openai/codex@0.116.0-darwin-arm64':
optional: true
'@openai/codex@0.115.0-darwin-x64':
'@openai/codex@0.116.0-darwin-x64':
optional: true
'@openai/codex@0.115.0-linux-arm64':
'@openai/codex@0.116.0-linux-arm64':
optional: true
'@openai/codex@0.115.0-linux-x64':
'@openai/codex@0.116.0-linux-x64':
optional: true
'@openai/codex@0.115.0-win32-arm64':
'@openai/codex@0.116.0-win32-arm64':
optional: true
'@openai/codex@0.115.0-win32-x64':
'@openai/codex@0.116.0-win32-x64':
optional: true
'@types/node@22.19.15':

View File

@@ -42,6 +42,7 @@ export class MessageTurnController {
private progressEditFailCount = 0;
private latestProgressTextForFinal: string | null = null;
private subagents = new Map<string, SubagentTrack>();
private lastIntermediateText: string | null = null;
private poisonedSessionDetected = false;
private closeRequested = false;
@@ -114,6 +115,7 @@ export class MessageTurnController {
if (result.phase === 'intermediate') {
// Send as standalone message without touching progress state
if (text) {
this.lastIntermediateText = text;
await this.options.channel.sendMessage(this.options.chatJid, text);
}
if (!this.poisonedSessionDetected) {
@@ -158,7 +160,11 @@ export class MessageTurnController {
if (result.phase === 'progress') {
if (result.agentId) {
if (result.agentDone) {
this.subagents.delete(result.agentId);
const done = this.subagents.get(result.agentId);
if (done) {
done.label = done.label.replace('🔄', '✅');
done.activities = [];
}
} else {
const label =
text ||
@@ -212,9 +218,18 @@ export class MessageTurnController {
// Final arrived — flush any buffered progress that isn't the same text,
// then discard the pending buffer so it never shows up.
if (text) {
if (this.lastIntermediateText && text === this.lastIntermediateText) {
// Already sent as intermediate — skip duplicate, just finalize
this.lastIntermediateText = null;
await this.finalizeProgressMessage();
this.visiblePhase = 'final';
this.latestProgressTextForFinal = null;
} else {
this.lastIntermediateText = null;
await this.flushPendingProgress(text);
await this.finalizeProgressMessage();
await this.deliverFinalText(text);
}
} else if (raw) {
logger.info(
{
@@ -347,8 +362,7 @@ export class MessageTurnController {
body = text + activityLines;
}
const maxBody =
2000 - TASK_STATUS_MESSAGE_PREFIX.length - suffix.length;
const maxBody = 2000 - TASK_STATUS_MESSAGE_PREFIX.length - suffix.length;
const truncated =
body.length > maxBody ? body.slice(0, maxBody - 1) + '…' : body;
return `${TASK_STATUS_MESSAGE_PREFIX}${truncated}${suffix}`;