Skip to content

Count sub-runs' and foreach bodies' model usage toward their step - #3332

Merged
yohamta0 merged 2 commits into
mainfrom
feat/model-usage-subruns
Oct 26, 2026
Merged

yohamta0 merged 2 commits into
mainfrom
feat/model-usage-subruns

Conversation

@yohamta0

@yohamta0 yohamta0 commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Summary

Last engine step toward showing a run's model usage. Stacked on #3331.

A step that runs other work showed nothing of what that work spent on models:

  • Sub-DAG runs (call, parallel, chat tools): the child's total now reaches the calling step as its latest report, which replaces the one before. A retried or reused child keeps its run ID, and its total already covers its earlier attempts, so replacing never counts it twice. A repeated step starts new children, which get their own entries.
    • Distributed children report on every status poll, so the step shows the child's usage while it runs.
    • In-process children report when they finish. They run with the parent's meter hidden, so their steps count only toward their own nodes, never also toward the parent step.
  • Foreach: an item's body steps run in a nested runner that is not saved with the run. Each item's body usage now adds to the foreach step when the item ends.

Changes

  • ir.RunStatus.ModelUsage (json:"-", so not part of the step's output) is filled by statusToRunStatus from the child's ModelUsageTotal(). Both the in-process and distributed runners build results through it.
  • SubDAGExecutor.Execute, Reuse and Retry pass their result through reportSubRunUsage, which calls SetReported("run:<id>", total). That one funnel serves dag, parallel and chat-tool steps.
  • subflow.Runner.waitCompletion reports each polled status.
  • subflow.Local.runAgent runs the child with modelusage.WithMeter(ctx, nil).
  • foreach.runItem adds bodyModelUsage(plan) with the new Meter.Add once the body finishes.
  • Meter.SetReported ignores an empty report for a source it doesn't have yet, so a child that used no model adds no entry.

Test plan

  • TestSubDAGExecutor_ReportsChildModelUsage: a run and then a retry of the same child replace the entry (3 calls, not 5).
  • TestRunnerReportsChildModelUsage: a distributed child's running poll is reported, then replaced by the finished total, which also reaches the result.
  • TestForeachCountsBodyModelUsage: three items' body calls add up on the foreach step.
  • TestMeterAdd: additions merge, and an empty report adds no entry.
  • golangci-lint v2.13.2 is clean for darwin, linux and windows.

Summary by CodeRabbit

  • New Features

    • Model usage reporting now includes usage from nested runs and repeated workflow steps.
    • Usage totals are associated with child runs and included in parent run results.
  • Bug Fixes

    • Corrected usage totals for retried runs so earlier attempts are replaced rather than counted twice.
    • Improved token and model-call accounting across iterative workflows and subflows.
  • Tests

    • Added coverage for nested execution, retries, and aggregated model usage reporting.

@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 1e070a8b-2054-41ea-9ee0-aff0cc7d6330
Commits

Reviewing files that changed from the base of the PR and between 5ed107c and 49c266a.

Files selected for processing: 10
  • internal/ir/run_result.go
  • internal/runtime/builtin/foreach/foreach.go
  • internal/runtime/builtin/foreach/usage_test.go
  • internal/runtime/executor/dag_runner.go
  • internal/runtime/executor/dag_runner_test.go
  • internal/runtime/modelusage/modelusage.go
  • internal/runtime/modelusage/modelusage_test.go
  • internal/service/coordinator/subflow/local.go
  • internal/service/coordinator/subflow/runner.go
  • internal/service/coordinator/subflow/runner_test.go

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.

Walkthrough

This change adds model usage to run status and reports usage from foreach bodies, sub-DAG results, and polled subflow runs to parent meters.

Changes: Nested model usage reporting

Layer / File(s) Summary
Run usage and meter support
internal/ir/run_result.go, internal/runtime/modelusage/*
RunStatus gains a non-serialized ModelUsage field. The meter adds usage, skips empty reports for new sources, and provides child-run source names.
Foreach body usage aggregation
internal/runtime/builtin/foreach/foreach.go, internal/runtime/builtin/foreach/usage_test.go
Foreach body node usage is merged and added to the parent step context after each body run. The test checks totals across three items.
Sub-DAG result usage reporting
internal/runtime/executor/dag_runner.go, internal/runtime/executor/dag_runner_test.go
Execute, Reuse, and Retry report child result usage under the child run ID. The test checks that retry usage replaces the earlier report.
Subflow status usage reporting
internal/service/coordinator/subflow/local.go, internal/service/coordinator/subflow/runner.go, internal/service/coordinator/subflow/runner_test.go
Status polling reports child usage to the parent meter, and returned run status includes the child’s aggregated usage. Local child agents run with a context that has no model-usage meter.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ParentSubflowRunner
  participant ChildRunStatus
  participant ModelUsageMeter
  ParentSubflowRunner->>ChildRunStatus: Poll child run status
  ChildRunStatus-->>ParentSubflowRunner: Return status with model usage
  ParentSubflowRunner->>ModelUsageMeter: Report usage under child run ID
Loading

Possibly related PRs

  • dagucloud/dagu#3331: Adds model-usage reporting for decision steps and coding-agent sources using the same meter flow.
  • dagucloud/dagu#3330: Adds per-step model-usage storage and a meter that records calls across attempts.
  • dagucloud/dagu#3329: Expands llm.Usage with data that feeds ir.ModelUsage.
Merge Risk: Minimal · up to 49c26

The reviewed usage-accounting paths show no identified issue that needs correction before merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 10 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: counting model usage from sub-runs and foreach bodies toward their parent step.
Description check Passed The description provides a detailed summary, lists the implementation changes, and documents the test plan. It does not include the required Related Issues and Checklist sections, but the main change …
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.
Full details: Description check

Explanation

The description provides a detailed summary, lists the implementation changes, and documents the test plan. It does not include the required Related Issues and Checklist sections, but the main change and validation details are complete.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@yohamta0
yohamta0 force-pushed the feat/model-usage-producers branch from af41f8f to ff360d5 Compare October 26, 2026 05:05
@yohamta0
yohamta0 force-pushed the feat/model-usage-subruns branch 2 times, most recently from 893e01e to 9a6a537 Compare October 26, 2026 05:44
@yohamta0
yohamta0 force-pushed the feat/model-usage-producers branch 2 times, most recently from 05444bf to 96dc039 Compare October 26, 2026 06:44
@yohamta0
yohamta0 force-pushed the feat/model-usage-subruns branch from 9a6a537 to 282746a Compare October 26, 2026 06:45
@yohamta0
yohamta0 changed the base branch from feat/model-usage-producers to main October 26, 2026 07:08
A step that runs a sub-DAG showed nothing of what the child spent on
models. The child's total now reaches the step as its latest report,
replacing the one before, so a retried or reused child, whose total
already covers its earlier attempts, is not counted twice. A
distributed child reports on every poll, so the step shows its usage
while it runs. An in-process child runs with the parent's meter
hidden, so its steps count only toward their own nodes.
A foreach item's body steps run in a nested runner that is not saved
with the run, so what they spent on models was lost. Each item's body
usage now adds to the foreach step's when the item ends.
@yohamta0
yohamta0 force-pushed the feat/model-usage-subruns branch from 282746a to 49c266a Compare October 26, 2026 07:09
@yohamta0
yohamta0 merged commit 967e9bd into main Oct 26, 2026
19 checks passed
@yohamta0
yohamta0 deleted the feat/model-usage-subruns branch October 26, 2026 07:40
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