mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-12 04:08:53 +02:00
fix(agent): prevent Claude runtime pings from hanging after the model has already finished
Claude's stream-json flow can emit the terminal result event while the child process still waits on open stdin. Closing stdin as soon as the final result arrives lets the CLI exit cleanly instead of idling until the daemon timeout fires. Constraint: Must preserve the existing Claude stream-json protocol and child-process lifecycle Rejected: Increase ping timeout only | masks the hang without fixing process exit Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep Claude stdin handling aligned with the stream-json terminal result semantics; do not defer closure until goroutine teardown Tested: Reproduced self-hosted runtime ping timeout locally; verified ping succeeds after closing stdin on result; cd server && go test ./pkg/agent Not-tested: Full make check; Bedrock/Vertex-specific Claude auth flows
This commit is contained in:
@@ -52,14 +52,21 @@ func (b *claudeBackend) Execute(ctx context.Context, prompt string, opts ExecOpt
|
||||
cancel()
|
||||
return nil, fmt.Errorf("claude stdin pipe: %w", err)
|
||||
}
|
||||
closeStdin := func() {
|
||||
if stdin != nil {
|
||||
_ = stdin.Close()
|
||||
stdin = nil
|
||||
}
|
||||
}
|
||||
cmd.Stderr = newLogWriter(b.cfg.Logger, "[claude:stderr] ")
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
closeStdin()
|
||||
cancel()
|
||||
return nil, fmt.Errorf("start claude: %w", err)
|
||||
}
|
||||
if err := writeClaudeInput(stdin, prompt); err != nil {
|
||||
_ = stdin.Close()
|
||||
closeStdin()
|
||||
cancel()
|
||||
_ = cmd.Wait()
|
||||
return nil, fmt.Errorf("write claude input: %w", err)
|
||||
@@ -70,7 +77,7 @@ func (b *claudeBackend) Execute(ctx context.Context, prompt string, opts ExecOpt
|
||||
resCh := make(chan Result, 1)
|
||||
|
||||
go func() {
|
||||
defer stdin.Close()
|
||||
defer closeStdin()
|
||||
defer cancel()
|
||||
defer close(msgCh)
|
||||
defer close(resCh)
|
||||
@@ -107,6 +114,7 @@ func (b *claudeBackend) Execute(ctx context.Context, prompt string, opts ExecOpt
|
||||
}
|
||||
trySend(msgCh, Message{Type: MessageStatus, Status: "running"})
|
||||
case "result":
|
||||
closeStdin()
|
||||
sessionID = msg.SessionID
|
||||
if msg.ResultText != "" {
|
||||
output.Reset()
|
||||
|
||||
Reference in New Issue
Block a user