From 2161b555ecb1cefbcd229157c19e5579d2211de9 Mon Sep 17 00:00:00 2001 From: Eyejoker Date: Mon, 23 Mar 2026 20:16:54 +0900 Subject: [PATCH] fix: dedup intermediate/final, filter long descriptions, update SDKs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- runners/agent-runner/package.json | 2 +- runners/agent-runner/pnpm-lock.yaml | 10 ++--- runners/agent-runner/src/index.ts | 6 ++- runners/codex-runner/package.json | 2 +- runners/codex-runner/pnpm-lock.yaml | 68 +++++++++++++---------------- src/message-turn-controller.ts | 26 ++++++++--- 6 files changed, 62 insertions(+), 52 deletions(-) diff --git a/runners/agent-runner/package.json b/runners/agent-runner/package.json index 1154b6e..14b3084 100644 --- a/runners/agent-runner/package.json +++ b/runners/agent-runner/package.json @@ -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" diff --git a/runners/agent-runner/pnpm-lock.yaml b/runners/agent-runner/pnpm-lock.yaml index a5dcc26..a0ac373 100644 --- a/runners/agent-runner/pnpm-lock.yaml +++ b/runners/agent-runner/pnpm-lock.yaml @@ -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: diff --git a/runners/agent-runner/src/index.ts b/runners/agent-runner/src/index.ts index d10a8b9..6b810f6 100644 --- a/runners/agent-runner/src/index.ts +++ b/runners/agent-runner/src/index.ts @@ -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)`); } } diff --git a/runners/codex-runner/package.json b/runners/codex-runner/package.json index a5bd352..01aaca7 100644 --- a/runners/codex-runner/package.json +++ b/runners/codex-runner/package.json @@ -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", diff --git a/runners/codex-runner/pnpm-lock.yaml b/runners/codex-runner/pnpm-lock.yaml index e397a43..a59b118 100644 --- a/runners/codex-runner/pnpm-lock.yaml +++ b/runners/codex-runner/pnpm-lock.yaml @@ -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': diff --git a/src/message-turn-controller.ts b/src/message-turn-controller.ts index 32c0b4d..72623af 100644 --- a/src/message-turn-controller.ts +++ b/src/message-turn-controller.ts @@ -42,6 +42,7 @@ export class MessageTurnController { private progressEditFailCount = 0; private latestProgressTextForFinal: string | null = null; private subagents = new Map(); + 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) { - await this.flushPendingProgress(text); - await this.finalizeProgressMessage(); - await this.deliverFinalText(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}`;