Skip to content

Handle the full variety of Workflow invocation shapes (#174 follow-up)#258

Merged
cboos merged 6 commits into
mainfrom
dev/workflow-shape-variety
Jul 2, 2026
Merged

Handle the full variety of Workflow invocation shapes (#174 follow-up)#258
cboos merged 6 commits into
mainfrom
dev/workflow-shape-variety

Conversation

@cboos

@cboos cboos commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

The #174 dynamic-workflow rendering assumed the inline-script invocation shape. Real sessions use others — a reference session's 6 Workflow tool_uses were all scriptPath invocations (one with args), which produced bare headers (no source, no description, invisible args) and a spurious meta format may have drifted warning per run per field. One run there also failed before launching any agent, leaving a snapshot but no journal — journal-led discovery skipped it entirely, so its failed status and error appeared nowhere.

  • Parse (workflow.py): surface the terminal snapshot's full enrichment on WorkflowRunscript (the source that actually ran: the recovery route for non-inline shapes), scriptPath, args, summary, error, defaultModel, durationMs, totalToolCalls. The header resolves from the effective script (input, else snapshot copy), falls back to the snapshot summary for a missing description, and warns only when a non-empty script fails a parse the snapshot can answer — absent source is not drift.
  • Meta string parse: accept any JS quote style ('/"/backtick) with backslash-escape support — real meta descriptions contain \', which truncated the old parse mid-string.
  • Model (models.py): WorkflowToolInput declares the invocation union — script, scriptPath, name, args, resumeFromRunId — instead of dropping the non-inline fields into extra="allow".
  • Render (HTML + Markdown): script body falls back to the snapshot copy; a workflow-invocation line shows saved-workflow name / scriptPath reference / resumed run id; args renders via the hybrid params table (HTML) / fenced JSON (Markdown).
  • Failure surfacing: discovery also yields snapshot-only runs (no run dir/journal); a non-completed status renders as a chip next to the workflow name and the snapshot error as a collapsed fold — in both output formats.

Verification

  • New fixture test/test_data/workflow_scriptpath/ (checked-in generator, same convention as workflow_basic): a scriptPath+args run whose snapshot carries the script (meta description with an escaped quote) + a snapshot-only failed run.
  • 24 new tests in test/test_workflow_rendering.py; just ci green on every commit; snapshot .ambr churn is the new CSS only.
  • End-to-end against the real reference session: all 6 invocations now render their orchestrator + invocation line, the failed run shows its status chip + stack trace, and the drift warnings are gone.
  • dev-docs/workflows.md updated in-PR.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Workflow runs now show richer details, including invocation info, optional arguments, and clearer error output.
    • Support was added for multiple workflow invocation styles, including saved workflows and script-path based runs.
  • Bug Fixes

    • Improved handling of failed workflow runs, including cases where only a snapshot is available.
    • Workflow header details are now more accurate when scripts contain quotes or special characters.
  • Documentation

    • Updated workflow docs to reflect the expanded run lifecycle and new display behavior.

cboos and others added 6 commits July 2, 2026 18:48
…ve script

Real Workflow invocations come in more shapes than the inline-`script`
one (#174 assumed): `scriptPath` / `name` / `resumeFromRunId` inputs
carry no source at all, so the JS-meta parse came up empty and the
snapshot-first header fired spurious "meta format may have drifted"
warnings on every such run (observed on all 5 runs of the SAM
reference session).

The terminal <runId>.json snapshot stores the script that actually ran,
plus scriptPath, args, summary, error, defaultModel, durationMs and
totalToolCalls — surface them all on WorkflowRun. The header now
parses the *effective* script (input, else snapshot copy; new
resolve_workflow_script helper), falls back to the snapshot `summary`
for a missing description, and warns only when a NON-empty script
fails a parse the snapshot can answer — absent source is not drift.

Also fix the meta string regexes: real meta blocks contain
backslash-escaped quotes ('SAM\'s ...'), which truncated the parsed
description; strings now match any JS quote style (' / " / backtick)
with escape support and are unescaped on extraction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
scriptPath, name, args and resumeFromRunId are all legal Workflow
inputs (the SAM reference session uses scriptPath exclusively), but the
model declared only `script` — the other shapes fell into
extra="allow" and were invisible to the formatters. Declare them with
their camelCase aliases so the renderer can surface them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
For the scriptPath / name / resumeFromRunId invocation shapes the
tool_use card showed a bare header pill row: no source, no description,
no hint of how the workflow was launched. Now, in HTML and Markdown:

- the script body falls back to the snapshot-stored copy of the source
  that actually ran (resolve_workflow_script), so scriptPath runs show
  their orchestrator just like inline ones;
- a workflow-invocation line surfaces the saved-workflow name, the
  script file reference, and the resumed run id;
- `args` renders through the hybrid params table (HTML) / a fenced
  JSON block (Markdown), wrapped under an explicit "args" key.

New workflow_scriptpath fixture: a scriptPath+args invocation whose
snapshot carries the script (with an escaped quote in the meta
description, exercising the commit-1 string parse). Snapshot .ambr
churn is the new CSS block only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A workflow that dies before launching any agent (e.g. a script error on
an early line — observed as wf_700cd51d in the SAM reference session)
leaves a <runId>.json snapshot but NO run dir/journal. Journal-led
discovery skipped it entirely: no run link, no header, and the error
nowhere on the page.

- discover_workflow_runs also yields snapshot-only runs (snapshots with
  no matching run dir); parse_workflow_run accepts a missing journal
  when the snapshot loads, producing a run with an empty agents list.
- The tool_use header now shows a status chip for any non-completed
  terminal status next to the workflow name, and the snapshot `error`
  (typically a JS stack trace) as a collapsed fold — in HTML and
  Markdown. WorkflowRun.status was previously parsed but never
  rendered; error wasn't even parsed.

Fixture: wf_fail01 snapshot-only failed run added to the
workflow_scriptpath session. Snapshot .ambr churn is the new CSS only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same convention as gen_workflow_fixture.py: the fixture is checked in
but regenerable. Regenerated output (cosmetic JSON key-order change in
the trunk only).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Document the invocation shapes (script / scriptPath / name / args /
resumeFromRunId), the snapshot enrichment fields and script recovery
route, snapshot-only failed-run discovery, the effective-script header
resolution with its narrowed drift warning, the failure chrome, and the
workflow_scriptpath fixture.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9655d01b-398e-4f9a-84f5-38fd2779c4cc

📥 Commits

Reviewing files that changed from the base of the PR and between fc80008 and 1620b3f.

📒 Files selected for processing (15)
  • claude_code_log/html/templates/components/message_styles.css
  • claude_code_log/html/tool_formatters.py
  • claude_code_log/markdown/renderer.py
  • claude_code_log/models.py
  • claude_code_log/workflow.py
  • dev-docs/workflows.md
  • scripts/gen_workflow_scriptpath_fixture.py
  • test/__snapshots__/test_snapshot_html.ambr
  • test/test_data/workflow_scriptpath/22220000-0000-4000-8000-000000000002.jsonl
  • test/test_data/workflow_scriptpath/22220000-0000-4000-8000-000000000002/subagents/workflows/wf_sp01/agent-agsp0001.jsonl
  • test/test_data/workflow_scriptpath/22220000-0000-4000-8000-000000000002/subagents/workflows/wf_sp01/agent-agsp0001.meta.json
  • test/test_data/workflow_scriptpath/22220000-0000-4000-8000-000000000002/subagents/workflows/wf_sp01/journal.jsonl
  • test/test_data/workflow_scriptpath/22220000-0000-4000-8000-000000000002/workflows/wf_fail01.json
  • test/test_data/workflow_scriptpath/22220000-0000-4000-8000-000000000002/workflows/wf_sp01.json
  • test/test_workflow_rendering.py

📝 Walkthrough

Walkthrough

This PR extends the dynamic Workflow tool to support multiple invocation shapes (inline script, scriptPath, saved name, resumeFromRunId), enriches WorkflowRun with snapshot-derived fields, resolves an "effective script" for header/meta parsing, adds snapshot-only failed run handling, and renders status/invocation/args/error UI in HTML and Markdown outputs, plus fixtures and tests.

Changes

Workflow invocation shapes and snapshot-driven rendering

Layer / File(s) Summary
Tool input schema
claude_code_log/models.py
WorkflowToolInput gains script_path, name, args, and resume_from_run_id alongside inline script.
Meta parsing and snapshot enrichment
claude_code_log/workflow.py
Adds JS string-literal parsing, resolve_workflow_script, updated resolve_workflow_header, expanded WorkflowRun fields, _as_str coercion, and snapshot-only run discovery/parsing.
HTML rendering
claude_code_log/html/tool_formatters.py, claude_code_log/html/templates/components/message_styles.css
Renders workflow status chip, invocation line, args table, and collapsible error block; adds corresponding CSS.
Markdown rendering
claude_code_log/markdown/renderer.py
Adds status token, invocation bits, args JSON block, and error block to workflow tool-input formatting.
Fixture generator and data
scripts/gen_workflow_scriptpath_fixture.py, test/test_data/workflow_scriptpath/...
New script and generated fixtures for scriptPath-invoked and snapshot-only failed workflow runs.
Tests and docs/snapshots
test/test_workflow_rendering.py, dev-docs/workflows.md, test/__snapshots__/test_snapshot_html.ambr
New/extended tests for meta parsing, invocation shapes, and rendering; documentation and snapshot CSS updates.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: broader support for Workflow invocation shapes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev/workflow-shape-variety

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cboos

cboos commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator Author

If I may add a little note of self-satisfaction, our dynamic workflow rendering really nails it.
I rendered a relatively complex session with several dynamic workflows, and the HTML report clearly exposed all the details of what happened during those workflows.

@daaain, maybe it's time to cut a new release?

@cboos cboos merged commit 6496622 into main Jul 2, 2026
17 checks passed
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