tuna-agent 0.1.81 → 0.1.83

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.
@@ -185,6 +185,22 @@ export class ClaudeCodeAdapter {
185
185
  let firstChunkIso = '';
186
186
  let turnAccumulatedText = '';
187
187
  let messageCount = 0; // Track message_start events to detect new turns
188
+ let lastSentContent = ''; // Dedup: skip sending same/similar message twice
189
+ // Normalize text for similarity comparison (strip markdown, collapse whitespace)
190
+ const normalize = (s) => s.replace(/[#*_`~\-|>]/g, '').replace(/\s+/g, ' ').trim().toLowerCase();
191
+ const isSimilar = (a, b) => {
192
+ if (!a || !b)
193
+ return false;
194
+ const na = normalize(a), nb = normalize(b);
195
+ if (na === nb)
196
+ return true;
197
+ // Check if one contains the other (common with slight variations)
198
+ if (na.length > 20 && nb.length > 20) {
199
+ if (na.includes(nb) || nb.includes(na))
200
+ return true;
201
+ }
202
+ return false;
203
+ };
188
204
  console.log(`[ClaudeCode] Agent Team round ${round + 1}: ${userMessage.substring(0, 80)}${currentInputFiles?.length ? ` (+${currentInputFiles.length} images)` : ''}`);
189
205
  const defaultWorkspace = path.join(os.homedir(), 'tuna-workspace');
190
206
  const cwd = task.repoPath || defaultWorkspace;
@@ -231,11 +247,18 @@ export class ClaudeCodeAdapter {
231
247
  if (messageCount > 1 && turnAccumulatedText.trim()) {
232
248
  console.log(`[ClaudeCode] ✂️ Splitting bubble — finalizing ${turnAccumulatedText.length} chars from previous turn`);
233
249
  ws.sendPMStreamEnd(task.id, streamMsgId);
234
- ws.sendPMMessage(task.id, {
235
- sender: 'pm',
236
- content: simplifyMarkdown(turnAccumulatedText),
237
- startedAt: firstChunkIso || undefined,
238
- });
250
+ const simplified = simplifyMarkdown(turnAccumulatedText);
251
+ if (!isSimilar(simplified, lastSentContent)) {
252
+ ws.sendPMMessage(task.id, {
253
+ sender: 'pm',
254
+ content: simplified,
255
+ startedAt: firstChunkIso || undefined,
256
+ });
257
+ lastSentContent = simplified;
258
+ }
259
+ else {
260
+ console.log(`[ClaudeCode] ⏭️ Skipping duplicate message (${simplified.length} chars)`);
261
+ }
239
262
  turnAccumulatedText = '';
240
263
  firstChunkIso = '';
241
264
  streamMsgId = `team-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
@@ -327,13 +350,20 @@ export class ClaudeCodeAdapter {
327
350
  if (lastTaskOutput) {
328
351
  console.log(`[Reflection] Captured ${lastTaskOutput.length} chars of task output for reflection`);
329
352
  }
330
- // Send finalized message for the last turn's remaining text
353
+ // Send finalized message for the last turn's remaining text (skip if duplicate)
331
354
  if (turnAccumulatedText.trim()) {
332
- ws.sendPMMessage(task.id, {
333
- sender: 'pm',
334
- content: simplifyMarkdown(turnAccumulatedText),
335
- startedAt: firstChunkIso || undefined,
336
- });
355
+ const simplified = simplifyMarkdown(turnAccumulatedText);
356
+ if (!isSimilar(simplified, lastSentContent)) {
357
+ ws.sendPMMessage(task.id, {
358
+ sender: 'pm',
359
+ content: simplified,
360
+ startedAt: firstChunkIso || undefined,
361
+ });
362
+ lastSentContent = simplified;
363
+ }
364
+ else {
365
+ console.log(`[ClaudeCode] ⏭️ Skipping similar final message (${simplified.length} chars)`);
366
+ }
337
367
  }
338
368
  // Last round → close
339
369
  if (round === MAX_ROUNDS - 1)
package/dist/cli/index.js CHANGED
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tuna-agent",
3
- "version": "0.1.81",
3
+ "version": "0.1.83",
4
4
  "description": "Tuna Agent - Run AI coding tasks on your machine",
5
5
  "bin": {
6
6
  "tuna-agent": "dist/cli/index.js"