tuna-agent 0.1.87 → 0.1.89
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.
- package/dist/daemon/index.js +84 -57
- package/package.json +1 -1
package/dist/daemon/index.js
CHANGED
|
@@ -777,72 +777,99 @@ ${skillContent.slice(0, 15000)}`;
|
|
|
777
777
|
let turnAccumulatedText = '';
|
|
778
778
|
let messageCount = 0;
|
|
779
779
|
console.log(`[Daemon] Resumed agent_team round ${round + 1}: ${userMessage.substring(0, 80)}${currentInputFiles?.length ? ` (+${currentInputFiles.length} images)` : ''}`);
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
if (
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
780
|
+
let result;
|
|
781
|
+
try {
|
|
782
|
+
result = await runClaude({
|
|
783
|
+
prompt: userMessage,
|
|
784
|
+
cwd,
|
|
785
|
+
allowedTools: ['Read', 'Edit', 'Write', 'Bash', 'Glob', 'Grep'],
|
|
786
|
+
outputFormat: 'stream-json',
|
|
787
|
+
includePartialMessages: false,
|
|
788
|
+
agentTeam: true,
|
|
789
|
+
maxTurns: 200,
|
|
790
|
+
resumeSessionId: sessionId,
|
|
791
|
+
signal: abort.signal,
|
|
792
|
+
inputFiles: currentInputFiles,
|
|
793
|
+
onStreamLine: (data) => {
|
|
794
|
+
if (data.type === 'stream_event') {
|
|
795
|
+
const event = data.event;
|
|
796
|
+
// message_start → new turn; finalize previous turn's text as separate bubble
|
|
797
|
+
if (event?.type === 'message_start') {
|
|
798
|
+
messageCount++;
|
|
799
|
+
if (messageCount > 1 && turnAccumulatedText.trim()) {
|
|
800
|
+
wsClient.sendPMStreamEnd(taskId, streamMsgId);
|
|
801
|
+
wsClient.sendPMMessage(taskId, {
|
|
802
|
+
sender: 'pm',
|
|
803
|
+
content: simplifyMarkdown(turnAccumulatedText),
|
|
804
|
+
startedAt: firstChunkIso || undefined,
|
|
805
|
+
});
|
|
806
|
+
turnAccumulatedText = '';
|
|
807
|
+
firstChunkIso = '';
|
|
808
|
+
streamMsgId = `team-resume-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
809
|
+
}
|
|
807
810
|
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
811
|
+
if (event?.type === 'content_block_delta') {
|
|
812
|
+
const delta = event.delta;
|
|
813
|
+
if (delta?.type === 'text_delta' && delta.text) {
|
|
814
|
+
if (!firstChunkIso)
|
|
815
|
+
firstChunkIso = new Date().toISOString();
|
|
816
|
+
turnAccumulatedText += delta.text;
|
|
817
|
+
wsClient.sendPMStream(taskId, delta.text);
|
|
818
|
+
}
|
|
816
819
|
}
|
|
817
820
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
}
|
|
821
|
+
if (data.type === 'system' && data.subtype === 'init') {
|
|
822
|
+
sessionId = data.session_id;
|
|
823
|
+
}
|
|
824
|
+
// Extract tool usage from assistant messages (no text patching —
|
|
825
|
+
// content_block_delta is the sole source of streaming text)
|
|
826
|
+
if (data.type === 'assistant' && data.message) {
|
|
827
|
+
const msg = data.message;
|
|
828
|
+
const content = msg.content;
|
|
829
|
+
if (content) {
|
|
830
|
+
for (const block of content) {
|
|
831
|
+
if (block.type === 'tool_use') {
|
|
832
|
+
const toolName = block.name;
|
|
833
|
+
const toolInput = block.input;
|
|
834
|
+
const detail = toolInput?.file_path || toolInput?.command || toolInput?.pattern || '';
|
|
835
|
+
wsClient.sendProgress(taskId, 'subtask_log', {
|
|
836
|
+
subtaskId: 'agent-team',
|
|
837
|
+
log: { type: 'action', message: `${toolName}: ${String(detail).substring(0, 80)}` },
|
|
838
|
+
});
|
|
839
|
+
}
|
|
837
840
|
}
|
|
838
841
|
}
|
|
839
842
|
}
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
+
},
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
catch (cliError) {
|
|
847
|
+
// Stale session: Claude CLI fails when resuming a dead session
|
|
848
|
+
if (sessionId && round === 0 && messageCount === 0) {
|
|
849
|
+
console.log(`[Daemon] ⚠️ Stale session detected (CLI error: ${cliError.message?.substring(0, 80)}) — retrying without resume`);
|
|
850
|
+
sessionId = undefined;
|
|
851
|
+
wsClient.sendPMMessage(taskId, {
|
|
852
|
+
sender: 'pm',
|
|
853
|
+
content: 'Session expired after restart. Starting fresh...',
|
|
854
|
+
});
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
throw cliError;
|
|
858
|
+
}
|
|
843
859
|
wsClient.sendPMStreamEnd(taskId, streamMsgId);
|
|
844
860
|
sessionId = result.sessionId || sessionId;
|
|
845
861
|
totalDurationMs += result.durationMs || 0;
|
|
862
|
+
// Detect stale/dead session: no stream events + empty or very short result
|
|
863
|
+
const resultText = (result.result || '').trim();
|
|
864
|
+
if (messageCount === 0 && resultText.length < 10 && round === 0 && sessionId) {
|
|
865
|
+
console.log(`[Daemon] ⚠️ Stale session detected (no stream events, result=${resultText.length} chars) — retrying without resume`);
|
|
866
|
+
sessionId = undefined;
|
|
867
|
+
wsClient.sendPMMessage(taskId, {
|
|
868
|
+
sender: 'pm',
|
|
869
|
+
content: 'Session expired after restart. Starting fresh...',
|
|
870
|
+
});
|
|
871
|
+
continue; // retry this round without --resume
|
|
872
|
+
}
|
|
846
873
|
// Send finalized message for the last turn's remaining text
|
|
847
874
|
if (turnAccumulatedText.trim()) {
|
|
848
875
|
wsClient.sendPMMessage(taskId, {
|