Skip to content

refactor: extract finalize_run helper to deduplicate Runner exit paths#56

Merged
scmmishra merged 1 commit intochatwoot:mainfrom
sergiobayona:refactor/extract-finalize-run-in-runner
Mar 13, 2026
Merged

refactor: extract finalize_run helper to deduplicate Runner exit paths#56
scmmishra merged 1 commit intochatwoot:mainfrom
sergiobayona:refactor/extract-finalize-run-in-runner

Conversation

@sergiobayona
Copy link
Copy Markdown
Contributor

The Runner#run method had five near-identical blocks that each built a RunResult, emitted agent_complete and run_complete callbacks, and returned. This copy-paste pattern existed across:

  • Handoff validation error (AgentNotFoundError)
  • Non-handoff halt response
  • Normal completion (no tool calls)
  • MaxTurnsExceeded rescue
  • StandardError rescue

Extract a single finalize_run private method that centralises the save-state → build-result → emit-callbacks → return sequence.

Also remove the unnecessary resultresponse variable alias introduced by the intermediate assignment (result = if ...; response = result), assigning directly to response instead.

The Runner#run method had five near-identical blocks that each built a
RunResult, emitted agent_complete and run_complete callbacks, and
returned. This copy-paste pattern existed across:

- Handoff validation error (AgentNotFoundError)
- Non-handoff halt response
- Normal completion (no tool calls)
- MaxTurnsExceeded rescue
- StandardError rescue

Extract a single `finalize_run` private method that centralises the
save-state → build-result → emit-callbacks → return sequence.

Also remove the unnecessary `result` → `response` variable alias
introduced by the intermediate assignment (`result = if ...; response = result`),
assigning directly to `response` instead.
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 13, 2026

Deploy Preview for ruby-ai-agents canceled.

Name Link
🔨 Latest commit 46059f5
🔍 Latest deploy log https://app.netlify.com/projects/ruby-ai-agents/deploys/69b36349e187fd00085b9214

@scmmishra
Copy link
Copy Markdown
Member

@codex please review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@scmmishra scmmishra merged commit 33fab56 into chatwoot:main Mar 13, 2026
7 checks passed
sergiobayona added a commit to sergiobayona/ai-agents that referenced this pull request Mar 17, 2026
…run refactor

Main branch introduced a `finalize_run` helper (chatwoot#56) that centralised
the exit path. Our guardrails branch had inline output guards + manual
finalization. This commit resolves the conflict and re-applies all
three guard fixes on top of the new architecture.

Changes re-applied:

1. GuardRunner.run now tracks `any_rewrite` across the chain and
   returns `action: :rewrite` when any guard rewrote content.
   Previously always returned `:pass`, making caller `.rewrite?`
   checks dead code.

2. `last_message_matches?` moved below the input guard block so
   dedup compares against post-guard (potentially rewritten) input.
   Prevents stale dedup from silently discarding guard rewrites.

3. Output guards serialize Hash/Array content (from response_schema)
   to JSON before the guard chain and deserialize after rewrite,
   so guards always operate on Strings.

Conflict resolution: output guards run before `finalize_run`, passing
the guarded `final_output` to the helper. Tripwire rescue remains
separate (needs `guardrail_tripwire` field not supported by
`finalize_run`).

Tests: 10 new examples covering input guard rewrites, output guard
rewrites, structured output guards (redact/tripwire/pass-through),
and dedup regression.

432 examples, 0 failures, 98.24% line coverage.
sergiobayona added a commit to sergiobayona/ai-agents that referenced this pull request Mar 18, 2026
…run refactor

Main branch introduced a `finalize_run` helper (chatwoot#56) that centralised
the exit path. Our guardrails branch had inline output guards + manual
finalization. This commit resolves the conflict and re-applies all
three guard fixes on top of the new architecture.

Changes re-applied:

1. GuardRunner.run now tracks `any_rewrite` across the chain and
   returns `action: :rewrite` when any guard rewrote content.
   Previously always returned `:pass`, making caller `.rewrite?`
   checks dead code.

2. `last_message_matches?` moved below the input guard block so
   dedup compares against post-guard (potentially rewritten) input.
   Prevents stale dedup from silently discarding guard rewrites.

3. Output guards serialize Hash/Array content (from response_schema)
   to JSON before the guard chain and deserialize after rewrite,
   so guards always operate on Strings.

Conflict resolution: output guards run before `finalize_run`, passing
the guarded `final_output` to the helper. Tripwire rescue remains
separate (needs `guardrail_tripwire` field not supported by
`finalize_run`).

Tests: 10 new examples covering input guard rewrites, output guard
rewrites, structured output guards (redact/tripwire/pass-through),
and dedup regression.

432 examples, 0 failures, 98.24% line coverage.

refactor: consolidate tripwire rescue into finalize_run for rescue ordering safety

The Tripwire rescue had 15 lines of inline finalization duplicating
what finalize_run already does. If anyone reordered the rescue clauses,
Guard::Tripwire (a StandardError subclass) would fall into the generic
StandardError rescue, silently losing guardrail_tripwire metadata.

Changes:
- Add `guardrail_tripwire:` kwarg to finalize_run so it can build
  tripwire-aware RunResults
- Collapse Tripwire rescue to a single finalize_run call
- Add `raise if e.is_a?(Guard::Tripwire)` safety net in the
  StandardError rescue to prevent silent metadata loss

Tests: 2 new examples verifying tripwire RunResult metadata and
callback emission through the finalize_run path.

434 examples, 0 failures, 98.24% line coverage.
sergiobayona added a commit to sergiobayona/ai-agents that referenced this pull request Mar 18, 2026
…run refactor

Main branch introduced a `finalize_run` helper (chatwoot#56) that centralised
the exit path. Our guardrails branch had inline output guards + manual
finalization. This commit resolves the conflict and re-applies all
three guard fixes on top of the new architecture.

Changes re-applied:

1. GuardRunner.run now tracks `any_rewrite` across the chain and
   returns `action: :rewrite` when any guard rewrote content.
   Previously always returned `:pass`, making caller `.rewrite?`
   checks dead code.

2. `last_message_matches?` moved below the input guard block so
   dedup compares against post-guard (potentially rewritten) input.
   Prevents stale dedup from silently discarding guard rewrites.

3. Output guards serialize Hash/Array content (from response_schema)
   to JSON before the guard chain and deserialize after rewrite,
   so guards always operate on Strings.

Conflict resolution: output guards run before `finalize_run`, passing
the guarded `final_output` to the helper. Tripwire rescue remains
separate (needs `guardrail_tripwire` field not supported by
`finalize_run`).

Tests: 10 new examples covering input guard rewrites, output guard
rewrites, structured output guards (redact/tripwire/pass-through),
and dedup regression.

432 examples, 0 failures, 98.24% line coverage.

refactor: consolidate tripwire rescue into finalize_run for rescue ordering safety

The Tripwire rescue had 15 lines of inline finalization duplicating
what finalize_run already does. If anyone reordered the rescue clauses,
Guard::Tripwire (a StandardError subclass) would fall into the generic
StandardError rescue, silently losing guardrail_tripwire metadata.

Changes:
- Add `guardrail_tripwire:` kwarg to finalize_run so it can build
  tripwire-aware RunResults
- Collapse Tripwire rescue to a single finalize_run call
- Add `raise if e.is_a?(Guard::Tripwire)` safety net in the
  StandardError rescue to prevent silent metadata loss

Tests: 2 new examples verifying tripwire RunResult metadata and
callback emission through the finalize_run path.

434 examples, 0 failures, 98.24% line coverage.
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.

2 participants