diff --git a/src/ClaudeDo.Worker/Runner/StreamAnalyzer.cs b/src/ClaudeDo.Worker/Runner/StreamAnalyzer.cs index 89060b6..6b683d0 100644 --- a/src/ClaudeDo.Worker/Runner/StreamAnalyzer.cs +++ b/src/ClaudeDo.Worker/Runner/StreamAnalyzer.cs @@ -86,7 +86,7 @@ public sealed class StreamAnalyzer TokensIn = _tokensIn, TokensOut = _tokensOut, ApiRetryCount = _apiRetryCount, - Blocks = _blocks, + Blocks = _blocks.Distinct().ToList(), }; private string? FallbackResult() diff --git a/src/ClaudeDo.Worker/Runner/TaskRunner.cs b/src/ClaudeDo.Worker/Runner/TaskRunner.cs index 102a54b..1c12b5b 100644 --- a/src/ClaudeDo.Worker/Runner/TaskRunner.cs +++ b/src/ClaudeDo.Worker/Runner/TaskRunner.cs @@ -380,7 +380,7 @@ public sealed class TaskRunner global = await settingsRepo.GetAsync(ct); } - var systemFile = PromptFiles.ReadOrNull(PromptKind.System); + var systemFile = PromptFiles.ReadOrDefault(PromptKind.System); var instructions = MergeInstructions( systemFile, global.DefaultClaudeInstructions, listConfig?.SystemPrompt, task.SystemPrompt); diff --git a/tests/ClaudeDo.Worker.Tests/Runner/StreamAnalyzerTests.cs b/tests/ClaudeDo.Worker.Tests/Runner/StreamAnalyzerTests.cs index 371f952..27c8406 100644 --- a/tests/ClaudeDo.Worker.Tests/Runner/StreamAnalyzerTests.cs +++ b/tests/ClaudeDo.Worker.Tests/Runner/StreamAnalyzerTests.cs @@ -152,4 +152,15 @@ public sealed class StreamAnalyzerTests analyzer.ProcessLine("""{"type":"result","result":"done","session_id":"s1"}"""); Assert.Empty(analyzer.GetResult().Blocks); } + + [Fact] + public void Duplicate_Marker_In_Assistant_And_Result_Is_Collected_Once() + { + var analyzer = new StreamAnalyzer(); + analyzer.ProcessLine("""{"type":"assistant","message":{"content":[{"type":"text","text":"CLAUDEDO_BLOCKED: no creds"}]}}"""); + analyzer.ProcessLine("""{"type":"result","result":"summary\nCLAUDEDO_BLOCKED: no creds","session_id":"s1"}"""); + var result = analyzer.GetResult(); + Assert.Single(result.Blocks); + Assert.Equal("no creds", result.Blocks[0]); + } }