refactor(worker): simplify ClaudeProcess to accept pre-built args and use StreamAnalyzer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
8825351526
commit
1cdaaf9fd2
@@ -16,17 +16,16 @@ public sealed class ClaudeProcess : IClaudeProcess
|
||||
}
|
||||
|
||||
public async Task<RunResult> RunAsync(
|
||||
string arguments,
|
||||
string prompt,
|
||||
string workingDirectory,
|
||||
string logPath,
|
||||
string taskId,
|
||||
Func<string, Task> onStdoutLine,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = _cfg.ClaudeBin,
|
||||
Arguments = "-p --output-format stream-json --verbose --dangerously-skip-permissions",
|
||||
Arguments = arguments,
|
||||
WorkingDirectory = workingDirectory,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
@@ -40,30 +39,25 @@ public sealed class ClaudeProcess : IClaudeProcess
|
||||
using var process = new Process { StartInfo = psi };
|
||||
process.Start();
|
||||
|
||||
// Write prompt to stdin, then close.
|
||||
await process.StandardInput.WriteAsync(prompt);
|
||||
process.StandardInput.Close();
|
||||
|
||||
string? resultMarkdown = null;
|
||||
var analyzer = new StreamAnalyzer();
|
||||
var lastStderr = new StringBuilder();
|
||||
|
||||
// Register cancellation to kill the process tree.
|
||||
await using var ctr = ct.Register(() =>
|
||||
{
|
||||
try { process.Kill(entireProcessTree: true); }
|
||||
catch { /* already exited */ }
|
||||
});
|
||||
|
||||
// Read stdout and stderr concurrently.
|
||||
var stdoutTask = Task.Run(async () =>
|
||||
{
|
||||
while (await process.StandardOutput.ReadLineAsync(ct) is { } line)
|
||||
{
|
||||
if (string.IsNullOrEmpty(line)) continue;
|
||||
await onStdoutLine(line);
|
||||
|
||||
if (MessageParser.TryExtractResult(line, out var res))
|
||||
resultMarkdown = res;
|
||||
analyzer.ProcessLine(line);
|
||||
}
|
||||
}, ct);
|
||||
|
||||
@@ -81,16 +75,34 @@ public sealed class ClaudeProcess : IClaudeProcess
|
||||
await process.WaitForExitAsync(ct);
|
||||
|
||||
var exitCode = process.ExitCode;
|
||||
var streamResult = analyzer.GetResult();
|
||||
|
||||
if (exitCode == 0 && resultMarkdown is not null)
|
||||
if (exitCode == 0 && streamResult.ResultMarkdown is not null)
|
||||
{
|
||||
return new RunResult { ExitCode = exitCode, ResultMarkdown = resultMarkdown };
|
||||
return new RunResult
|
||||
{
|
||||
ExitCode = exitCode,
|
||||
ResultMarkdown = streamResult.ResultMarkdown,
|
||||
StructuredOutputJson = streamResult.StructuredOutputJson,
|
||||
SessionId = streamResult.SessionId,
|
||||
TurnCount = streamResult.TurnCount,
|
||||
TokensIn = streamResult.TokensIn,
|
||||
TokensOut = streamResult.TokensOut,
|
||||
};
|
||||
}
|
||||
|
||||
var error = lastStderr.Length > 0
|
||||
? lastStderr.ToString().Trim()
|
||||
: $"Claude exited with code {exitCode} and no result.";
|
||||
|
||||
return new RunResult { ExitCode = exitCode, ErrorMarkdown = error };
|
||||
return new RunResult
|
||||
{
|
||||
ExitCode = exitCode,
|
||||
ErrorMarkdown = error,
|
||||
SessionId = streamResult.SessionId,
|
||||
TurnCount = streamResult.TurnCount,
|
||||
TokensIn = streamResult.TokensIn,
|
||||
TokensOut = streamResult.TokensOut,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user