tuna-agent 0.1.180 → 0.1.181

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.
@@ -794,8 +794,6 @@ ${skillContent.slice(0, 15000)}`;
794
794
  if (result.status === 'done' && !result.followUpMessage) {
795
795
  const totalDuration = result.sessions.reduce((sum, s) => sum + (s.durationMs ?? 0), 0);
796
796
  wsClient.sendTaskDone(taskId, { result: plan.summary, durationMs: totalDuration });
797
- await new Promise(resolve => setTimeout(resolve, 150));
798
- wsClient.sendPMMessage(taskId, { sender: 'pm', content: `Task completed.` });
799
797
  }
800
798
  else if (result.followUpMessage) {
801
799
  userMessage = result.followUpMessage;
@@ -333,7 +333,7 @@ export async function executeSubtask(subtask, repoPath, contracts, callbacks, si
333
333
  const result = await runClaude({
334
334
  prompt: subtask.description,
335
335
  cwd,
336
- allowedTools: ['Read', 'Edit', 'Write', 'Bash', 'Glob', 'Grep'],
336
+ allowedTools: ['Read', 'Edit', 'Write', 'Bash', 'Glob', 'Grep', 'mcp__mem0', 'mcp__tuna-knowledge', 'mcp__tuna-idea', 'mcp__tuna-browser', 'mcp__appeeky'],
337
337
  disallowedTools: ['AskUserQuestion'],
338
338
  systemPrompt: buildSessionPrompt(subtask, contracts),
339
339
  outputFormat: 'stream-json',
@@ -370,7 +370,7 @@ export async function executeSubtask(subtask, repoPath, contracts, callbacks, si
370
370
  const resumeResult = await runClaude({
371
371
  prompt: `The answer to your question "${question.question}" is: ${answer}\n\nContinue your work with this information.`,
372
372
  cwd,
373
- allowedTools: ['Read', 'Edit', 'Write', 'Bash', 'Glob', 'Grep'],
373
+ allowedTools: ['Read', 'Edit', 'Write', 'Bash', 'Glob', 'Grep', 'mcp__mem0', 'mcp__tuna-knowledge', 'mcp__tuna-idea', 'mcp__tuna-browser', 'mcp__appeeky'],
374
374
  disallowedTools: ['AskUserQuestion'],
375
375
  resumeSessionId: info.sessionId,
376
376
  outputFormat: 'stream-json',
@@ -449,7 +449,7 @@ export async function executeSubtask(subtask, repoPath, contracts, callbacks, si
449
449
  const resumeResult = await runClaude({
450
450
  prompt: `The answer to your question "${fallbackQuestion.question}" is: ${answer}\n\nContinue your work with this information.`,
451
451
  cwd,
452
- allowedTools: ['Read', 'Edit', 'Write', 'Bash', 'Glob', 'Grep'],
452
+ allowedTools: ['Read', 'Edit', 'Write', 'Bash', 'Glob', 'Grep', 'mcp__mem0', 'mcp__tuna-knowledge', 'mcp__tuna-idea', 'mcp__tuna-browser', 'mcp__appeeky'],
453
453
  disallowedTools: ['AskUserQuestion'],
454
454
  resumeSessionId: info.sessionId,
455
455
  outputFormat: 'stream-json',
@@ -144,7 +144,7 @@ export async function planTask(task, onProgress, signal, onTextChunk, inputFiles
144
144
  const result = await runClaude({
145
145
  prompt: userPrompt,
146
146
  cwd,
147
- allowedTools: ['Read', 'Glob', 'Grep'],
147
+ allowedTools: ['Read', 'Glob', 'Grep', 'mcp__mem0', 'mcp__tuna-knowledge', 'mcp__tuna-idea'],
148
148
  systemPrompt,
149
149
  maxTurns,
150
150
  outputFormat: 'stream-json',
@@ -287,17 +287,20 @@ User message: ${userMessage}`;
287
287
  let firstDeltaMs = 0;
288
288
  let deltaCount = 0;
289
289
  const cwd = repoPath || path.join(os.homedir(), 'tuna-workspace');
290
+ let streamedText = '';
290
291
  const result = await runClaude({
291
292
  prompt: chatPrompt,
292
293
  cwd,
293
294
  resumeSessionId: pmSessionId || undefined,
294
- allowedTools: [],
295
- maxTurns: 1,
296
- lightweight: true,
295
+ // Read-only tools + knowledge/memory MCP: follow-ups like "check the skill
296
+ // list" need to actually look at files. No tools + 1 turn made the model
297
+ // attempt a tool call anyway and come back with an EMPTY result (silent task).
298
+ allowedTools: ['Read', 'Glob', 'Grep', 'mcp__mem0', 'mcp__tuna-knowledge', 'mcp__tuna-idea'],
299
+ maxTurns: 8,
297
300
  outputFormat: 'stream-json',
298
301
  includePartialMessages: true,
299
302
  inputFiles,
300
- onStreamLine: onTextChunk ? (data) => {
303
+ onStreamLine: (data) => {
301
304
  // Parse stream_event → content_block_delta for real token streaming
302
305
  if (data.type === 'stream_event') {
303
306
  const event = data.event;
@@ -305,15 +308,16 @@ User message: ${userMessage}`;
305
308
  const delta = event.delta;
306
309
  if (delta?.type === 'text_delta' && delta.text) {
307
310
  deltaCount++;
311
+ streamedText += delta.text;
308
312
  if (!firstDeltaMs) {
309
313
  firstDeltaMs = Date.now();
310
314
  console.log(`[PM] ⏱ first text delta: ${firstDeltaMs - chatStartMs}ms after chat start`);
311
315
  }
312
- onTextChunk(delta.text);
316
+ onTextChunk?.(delta.text);
313
317
  }
314
318
  }
315
319
  }
316
- } : undefined,
320
+ },
317
321
  signal,
318
322
  });
319
323
  const chatDoneMs = Date.now();
@@ -321,7 +325,11 @@ User message: ${userMessage}`;
321
325
  if (result.isError) {
322
326
  return { response: `Sorry, I encountered an error: ${result.result}`, sessionId: result.sessionId };
323
327
  }
324
- const rawResult = result.result;
328
+ // A hit turn-cap (or odd stop) can yield an empty `result` even though text was
329
+ // streamed. Never return empty — a silent agent looks dead to the user.
330
+ const rawResult = result.result?.trim()
331
+ || streamedText.trim()
332
+ || 'Xin lỗi anh, phiên xử lý tin nhắn vừa rồi bị nghẽn (không có output). Anh nhắn lại giúp nhé.';
325
333
  // Try extracting JSON plan
326
334
  let jsonStr = null;
327
335
  const codeBlockMatch = rawResult.match(/```(?:json)?\s*(\{[\s\S]*?"subtasks"[\s\S]*?\})\s*```/);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tuna-agent",
3
- "version": "0.1.180",
3
+ "version": "0.1.181",
4
4
  "description": "Tuna Agent - Run AI coding tasks on your machine",
5
5
  "bin": {
6
6
  "tuna-agent": "dist/cli/index.js"