tuna-agent 0.1.104 → 0.1.106

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.
@@ -350,12 +350,13 @@ export class ClaudeCodeAdapter {
350
350
  // Send finalized message for the last turn's remaining text (skip if duplicate)
351
351
  // Fallback: if no streaming deltas were captured (e.g. agent_team mode may emit
352
352
  // complete assistant messages instead of stream_event deltas), use result.result
353
+ // Always send pm_message for DB persistence — pm_stream is fire-and-forget
354
+ // (not saved to DB), so this is the only way to persist the response.
355
+ // Still skip if duplicate of last SENT message (multi-turn dedup).
353
356
  const finalText = turnAccumulatedText.trim() || result.result;
354
357
  if (finalText) {
355
358
  const simplified = simplifyMarkdown(finalText);
356
- const simplifiedResult = simplifyMarkdown(result.result);
357
- // Skip if similar to last sent content OR to task result (avoid duplicate in chat + session)
358
- if (!isSimilar(simplified, lastSentContent) && !isSimilar(simplified, simplifiedResult)) {
359
+ if (!isSimilar(simplified, lastSentContent)) {
359
360
  ws.sendPMMessage(task.id, {
360
361
  sender: 'pm',
361
362
  content: simplified,
@@ -364,7 +365,7 @@ export class ClaudeCodeAdapter {
364
365
  lastSentContent = simplified;
365
366
  }
366
367
  else {
367
- console.log(`[ClaudeCode] ⏭️ Skipping final message (duplicate of ${isSimilar(simplified, simplifiedResult) ? 'task result' : 'last sent'}, ${simplified.length} chars)`);
368
+ console.log(`[ClaudeCode] ⏭️ Skipping final message (duplicate of last sent, ${simplified.length} chars)`);
368
369
  }
369
370
  }
370
371
  // Last round → close
@@ -267,6 +267,22 @@ export async function startDaemon(config) {
267
267
  }
268
268
  break;
269
269
  }
270
+ case 'task_interrupted': {
271
+ const taskId = msg.taskId;
272
+ console.log(`[Daemon] Task interrupted: ${taskId}`);
273
+ // Kill the running process but preserve PM state so next message can resume the session
274
+ const interruptAbort = taskAbortControllers.get(taskId);
275
+ if (interruptAbort) {
276
+ interruptAbort.abort();
277
+ console.log(`[Daemon] Aborted running task ${taskId} (state preserved for resume)`);
278
+ }
279
+ const interruptResolver = pendingInputResolvers.get(taskId);
280
+ if (interruptResolver) {
281
+ interruptResolver({ text: '__TASK_CANCELLED__' });
282
+ pendingInputResolvers.delete(taskId);
283
+ }
284
+ break;
285
+ }
270
286
  case 'command': {
271
287
  const command = msg.command;
272
288
  if (command === 'rescan_agent_skills') {
@@ -906,31 +922,22 @@ ${skillContent.slice(0, 15000)}`;
906
922
  return true;
907
923
  return false;
908
924
  };
925
+ // Always send pm_message for DB persistence — pm_stream is fire-and-forget
926
+ // (not saved to DB), so this is the only way to persist the response.
909
927
  if (turnAccumulatedText.trim()) {
910
928
  const simplified = simplifyMarkdown(turnAccumulatedText);
911
- if (!isSameAsResult(simplified)) {
912
- wsClient.sendPMMessage(taskId, {
913
- sender: 'pm',
914
- content: simplified,
915
- startedAt: firstChunkIso || undefined,
916
- });
917
- }
918
- else {
919
- console.log(`[Daemon] ⏭️ Skipping resume final message (duplicate of task result, ${simplified.length} chars)`);
920
- }
929
+ wsClient.sendPMMessage(taskId, {
930
+ sender: 'pm',
931
+ content: simplified,
932
+ startedAt: firstChunkIso || undefined,
933
+ });
921
934
  }
922
- else if (resultText.length > 0 && messageCount === 0) {
923
- // No stream events but CLI returned a result — skip if same as task result
924
- if (!isSameAsResult(resultText)) {
925
- console.log(`[Daemon] No stream events but got result (${resultText.length} chars) — sending as message`);
926
- wsClient.sendPMMessage(taskId, {
927
- sender: 'pm',
928
- content: simplifyMarkdown(resultText),
929
- });
930
- }
931
- else {
932
- console.log(`[Daemon] ⏭️ Skipping no-stream result message (duplicate of task result, ${resultText.length} chars)`);
933
- }
935
+ else if (resultText.length > 0) {
936
+ // No stream events but CLI returned a result
937
+ wsClient.sendPMMessage(taskId, {
938
+ sender: 'pm',
939
+ content: simplifyMarkdown(resultText),
940
+ });
934
941
  }
935
942
  lastResumeOutput = turnAccumulatedText.trim() || resultText || lastResumeOutput;
936
943
  if (result.isError) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tuna-agent",
3
- "version": "0.1.104",
3
+ "version": "0.1.106",
4
4
  "description": "Tuna Agent - Run AI coding tasks on your machine",
5
5
  "bin": {
6
6
  "tuna-agent": "dist/cli/index.js"