Monorepo management for opam overlays
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

doctor: stream Claude activity to console during analysis

Remove max_turns=1 restriction and plan mode to allow Claude to use
tools for deeper analysis. Add a custom handler that streams tool
usage to the console so users can see what Claude is doing:

- Bash commands (truncated to 60 chars)
- Read file paths
- Grep/Glob patterns
- Other tool names

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+39 -16
+39 -16
lib/doctor.ml
··· 548 548 let options = 549 549 Claude.Options.default 550 550 |> Claude.Options.with_output_format output_format 551 - |> Claude.Options.with_max_turns 1 552 551 in 553 552 554 553 let client = Claude.Client.create ~sw ~process_mgr ~clock ~options () in 555 554 Claude.Client.query client (Buffer.contents prompt); 556 555 557 - let responses = Claude.Client.receive_all client in 556 + (* Stream Claude's activity to console *) 557 + let result = ref None in 558 + let handler = object 559 + inherit Claude.Handler.default 560 + 561 + method! on_text t = 562 + let content = Claude.Response.Text.content t in 563 + if String.length content > 0 then 564 + Log.app (fun m -> m "Claude: %s" content) 565 + 566 + method! on_tool_use t = 567 + let name = Claude.Response.Tool_use.name t in 568 + let input = Claude.Response.Tool_use.input t in 569 + (* Show tool being used with key parameters *) 570 + (match name with 571 + | "Bash" -> 572 + let cmd = Claude.Tool_input.get_string input "command" |> Option.value ~default:"" in 573 + let short_cmd = if String.length cmd > 60 then String.sub cmd 0 57 ^ "..." else cmd in 574 + Log.app (fun m -> m " [Bash] %s" short_cmd) 575 + | "Read" -> 576 + let path = Claude.Tool_input.get_string input "file_path" |> Option.value ~default:"" in 577 + Log.app (fun m -> m " [Read] %s" path) 578 + | "Grep" -> 579 + let pattern = Claude.Tool_input.get_string input "pattern" |> Option.value ~default:"" in 580 + Log.app (fun m -> m " [Grep] %s" pattern) 581 + | "Glob" -> 582 + let pattern = Claude.Tool_input.get_string input "pattern" |> Option.value ~default:"" in 583 + Log.app (fun m -> m " [Glob] %s" pattern) 584 + | _ -> 585 + Log.app (fun m -> m " [%s]" name)) 558 586 559 - (* Parse response into our types *) 560 - let result = ref None in 561 - List.iter (function 562 - | Claude.Response.Complete c -> ( 563 - match Claude.Response.Complete.structured_output c with 564 - | Some json -> 565 - (* Parse the JSON manually since we have a complex nested structure *) 566 - result := Some json 567 - | None -> 568 - Log.warn (fun m -> m "No structured output from Claude")) 569 - | Claude.Response.Error e -> 570 - Log.warn (fun m -> m "Claude error: %s" (Claude.Response.Error.message e)) 571 - | _ -> ()) 572 - responses; 587 + method! on_complete c = 588 + match Claude.Response.Complete.structured_output c with 589 + | Some json -> result := Some json 590 + | None -> Log.warn (fun m -> m "No structured output from Claude") 591 + 592 + method! on_error e = 593 + Log.warn (fun m -> m "Claude error: %s" (Claude.Response.Error.message e)) 594 + end in 573 595 596 + Claude.Client.run client ~handler; 574 597 !result 575 598 576 599 (** Parse Claude's JSON response into our types *)