Skip to content

feat: add panic recovery with crash log & finish -> agent_exit#21

Merged
iohub merged 4 commits into
mainfrom
feat-meta-agent
May 3, 2026
Merged

feat: add panic recovery with crash log & finish -> agent_exit#21
iohub merged 4 commits into
mainfrom
feat-meta-agent

Conversation

@iohub
Copy link
Copy Markdown
Owner

@iohub iohub commented May 3, 2026

Summary by Sourcery

Introduce robust crash logging and align agent flow-control tooling and TUI history presentation with the new exit semantics and more compact task titles.

New Features:

  • Add centralized panic recovery that logs detailed crash reports to user-specific crash log files and stderr on application panic.

Enhancements:

  • Refine the TUI history panel layout and styling, including header composition, empty-state message, and per-item columns with a message count field.
  • Shorten stored task history titles to 30 characters for more concise display in the TUI.
  • Rename and repurpose the flow-control tool from finish to agent_exit across agents, executors, prompts, and tests to better represent agent termination semantics.
  • Adjust the thinking tool API to use a problem_description field instead of error_message for clearer logging semantics.

Tests:

  • Update agent conductor tests to use the new agent_exit tool name and expectations instead of finish.

iohub and others added 4 commits May 3, 2026 07:48
…tter truncation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… cognitive reflection scope

Co-Authored-By: Claude Code <noreply@anthropic.com>
…meter

Co-Authored-By: Claude Code <noreply@anthropic.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 3, 2026

Reviewer's Guide

Introduces a centralized panic recovery with crash logging, renames and re-wires the core flow-control tool from finish to agent_exit across agents, tools, and prompts, refines TUI history panel rendering, and tightens history title truncation and thinking tool parameter naming.

Sequence diagram for panic recovery crash logging

sequenceDiagram
    actor User
    participant main
    participant util_RecoverPanic as util.RecoverPanic
    participant util_buildCrashReport as buildCrashReport
    participant OS_FileSystem as OS_FileSystem

    User->>main: start_application()
    activate main
    main->>main: defer util.RecoverPanic()
    main->>main: execute_application_logic()
    main-->>main: panic(recovered_value)
    deactivate main

    activate util_RecoverPanic
    util_RecoverPanic->>util_RecoverPanic: r = recover()
    alt r is nil
        util_RecoverPanic-->>User: return (no crash)
    else r is not nil
        util_RecoverPanic->>util_buildCrashReport: buildCrashReport(r)
        activate util_buildCrashReport
        util_buildCrashReport-->>util_RecoverPanic: crash_report_string
        deactivate util_buildCrashReport

        util_RecoverPanic->>OS_FileSystem: crashLogDir() (resolve ~/.codeactor/logs/crash)
        alt dir resolution fails
            util_RecoverPanic->>User: write report to stderr
            util_RecoverPanic-->>main: re_panic(r)
        else dir ok
            OS_FileSystem-->>util_RecoverPanic: crash_dir_path
            util_RecoverPanic->>OS_FileSystem: MkdirAll(crash_dir_path)
            alt MkdirAll fails
                util_RecoverPanic->>User: write report to stderr
                util_RecoverPanic-->>main: re_panic(r)
            else MkdirAll ok
                util_RecoverPanic->>OS_FileSystem: OpenFile(crash-YYYY-MM-DD.log, append)
                alt OpenFile fails
                    util_RecoverPanic->>User: write report to stderr
                    util_RecoverPanic-->>main: re_panic(r)
                else OpenFile ok
                    OS_FileSystem-->>util_RecoverPanic: file_handle
                    util_RecoverPanic->>OS_FileSystem: WriteString(report)
                    OS_FileSystem-->>util_RecoverPanic: write_result
                    util_RecoverPanic->>User: also print report to stderr
                    util_RecoverPanic-->>main: re_panic(r)
                end
            end
        end
    end
Loading

Updated class diagram for flow control, thinking tool, and agents

classDiagram
    class FlowControlTool {
        +string WorkingDir
        +ExecuteAgentExit(ctx context.Context, params map_string_interface) (interface_type, error)
    }

    class ThinkingTool {
        +Name() string
        +Call(ctx context.Context, input string) (string, error)
        -buildCrashReport(recovered interface_type) string
    }

    class GlobalCtx {
        +FlowOps *FlowOps
        +ThinkingTool *ThinkingTool
    }

    class FlowOps {
        +ExecuteAgentExit(ctx context.Context, params map_string_interface) (interface_type, error)
        +ExecuteAskUserForHelp(ctx context.Context, params map_string_interface) (interface_type, error)
    }

    class ConductorAgent {
        +GlobalCtx *GlobalCtx
        +toolDefMap map[string]ToolDefinition
        +getToolFunc(name string) tools.ToolFunc
        +registerCustomAgent(ca *CustomAgent)
        +Run(ctx context.Context, input string, mem *memory.Conversation) (string, error)
    }

    class CodingAgent {
        +GlobalCtx *GlobalCtx
        +NewCodingAgent(globalCtx *GlobalCtx, llm llms.LLM, maxSteps int) *CodingAgent
    }

    class ExecutorConfig {
        +bool StopOnFinish
    }

    class RunAgentLoopFn {
        +RunAgentLoop(ctx context.Context, cfg ExecutorConfig) (string, error)
    }

    %% Relationships
    GlobalCtx --> FlowOps : has
    GlobalCtx --> ThinkingTool : has

    FlowOps --> FlowControlTool : uses

    ConductorAgent --> GlobalCtx : has
    CodingAgent --> GlobalCtx : has

    ConductorAgent --> FlowOps : uses ExecuteAgentExit
    CodingAgent --> FlowOps : uses ExecuteAgentExit

    ConductorAgent --> ThinkingTool : uses Call
    CodingAgent --> ThinkingTool : uses Call

    ExecutorConfig --> RunAgentLoopFn : config_for
    RunAgentLoopFn --> FlowOps : calls ExecuteAgentExit

    class ToolDefinition {
        +string Description
        +map_string_interface Parameters
    }

    ConductorAgent --> ToolDefinition : stores_in_toolDefMap
Loading

File-Level Changes

Change Details Files
Refine TUI history panel layout and styling for header, empty state, and history rows.
  • Rebuild header as a composed set of styled parts (title, filter, counter) using localized text and dynamic placeholder vs. active filter display.
  • Adjust empty-history rendering to add vertical padding and prefix a small indent before the message.
  • Rework row layout to include a right-aligned minute count column, update styles (colors, widths, padding), and ensure titles are pre-truncated and then safely re-truncated for narrow terminals.
tui.go
Rename the flow-control finish tool to agent_exit and wire it through conductor, coding agents, executor, and prompts.
  • Replace the finish adapter with agent_exit in the conductor, including updated description and schema pointing to ExecuteAgentExit.
  • Update tool dispatch in getToolFunc, custom agent registration, and Run loop completion logic to use agent_exit.
  • Adjust CodingAgent tool wiring, executor early-return condition, and meta/conductor prompt docs and tests to reference agent_exit instead of finish.
  • Ensure all tests and tool name lists expect agent_exit and align comments/docs with the new semantics (exit vs. finish).
internal/agents/conductor.go
internal/agents/conductor_test.go
internal/agents/conductor.prompt.md
internal/agents/meta.prompt.md
internal/agents/coding.go
internal/agents/executor.go
internal/agents/tools.json
Add panic recovery with crash logging and hook it into main entrypoint.
  • Introduce util.RecoverPanic, which recovers from panics, builds a detailed crash report including timestamp, Go version, OS/arch, panic value, and stack trace, and writes it to a per-day log file under ~/.codeactor/logs/crash.
  • Ensure crash directory creation and file writes are robust, with fallbacks to stderr and re-panicking to preserve original behavior.
  • Call defer util.RecoverPanic() at the start of main to enable global crash logging.
internal/util/crash.go
main.go
Tighten task history title truncation for TUI and adjust the cognitive thinking tool parameter naming.
  • Change history title truncation to keep only the first 30 runes of the first user message instead of 120, matching the TUI’s expected width.
  • Rename the ThinkingTool input field from ErrorMessage to ProblemDescription and update the log output labels accordingly while maintaining resilience when the input is just a string.
internal/datamanager/data_manager.go
internal/tools/cognitive.go

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@iohub iohub merged commit b061f79 into main May 3, 2026
1 check passed
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In FlowControlTool.ExecuteAgentExit, the error wrap context string is still "executeFinish", which is confusing now that the function and tool have been renamed; consider updating it to something like "executeAgentExit" for accurate diagnostics.
  • In ThinkingTool.Call, the JSON field was renamed from error_message to problem_description but the formatted output still labels it as Error:; consider updating the label to match the new semantics to avoid confusion in logs.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `FlowControlTool.ExecuteAgentExit`, the error wrap context string is still `"executeFinish"`, which is confusing now that the function and tool have been renamed; consider updating it to something like `"executeAgentExit"` for accurate diagnostics.
- In `ThinkingTool.Call`, the JSON field was renamed from `error_message` to `problem_description` but the formatted output still labels it as `Error:`; consider updating the label to match the new semantics to avoid confusion in logs.

## Individual Comments

### Comment 1
<location path="internal/agents/conductor.go" line_range="686" />
<code_context>
 					},
 				},
 			})
-			if tc.FunctionCall.Name == "finish" {
+			if tc.FunctionCall.Name == "agent_exit" {
 				return "Task completed successfully", nil
 			}
</code_context>
<issue_to_address>
**issue (bug_risk):** The fixed "Task completed successfully" message no longer matches the broader semantics of agent_exit.

agent_exit can represent success, failure, clarification, or forced termination, but the returned string always says “Task completed successfully”. This risks misleading callers and any UI using this value. Consider deriving a status from the tool output (e.g., including the reason) or using a neutral message that doesn’t imply success.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

},
},
})
if tc.FunctionCall.Name == "finish" {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The fixed "Task completed successfully" message no longer matches the broader semantics of agent_exit.

agent_exit can represent success, failure, clarification, or forced termination, but the returned string always says “Task completed successfully”. This risks misleading callers and any UI using this value. Consider deriving a status from the tool output (e.g., including the reason) or using a neutral message that doesn’t imply success.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant