Skip to content

feat: enforce workflow token budgets#724

Open
kjgbot wants to merge 1 commit intomainfrom
relay-issue-4
Open

feat: enforce workflow token budgets#724
kjgbot wants to merge 1 commit intomainfrom
relay-issue-4

Conversation

@kjgbot
Copy link
Copy Markdown
Contributor

@kjgbot kjgbot commented Apr 13, 2026

Summary

Implements runtime token budget enforcement for workflow steps in the SDK.

This adds a shared BudgetTracker and wires it into the workflow runner so token usage is no longer just collected post-hoc. The runner now:

  • records token usage after each attempt, including failed attempts
  • enforces workflow-level budget exhaustion before spawning later steps
  • carries retry token usage forward so retries consume the same shared budget
  • surfaces per-step budget usage in the run summary with [OVER] markers

Changes

  • added packages/sdk/src/workflows/budget-tracker.ts
  • added swarm.tokenBudget support in workflow types
  • integrated budget tracking/enforcement into packages/sdk/src/workflows/runner.ts
  • extended run-summary-table.ts with budget reporting
  • exported the new budget tracker from the workflows index
  • added tests for tracker behavior, workflow budget enforcement, and budget rendering in the run summary

Validation

  • npm run build:sdk
  • npx vitest run --config vitest.config.ts src/workflows/tests/budget-tracker.test.ts src/workflows/tests/budget-enforcement.test.ts src/workflows/tests/run-summary-table.test.ts

Notes

  • cache read tokens remain informational only and are not counted toward enforced totals
  • if no tokenBudget or maxTokens values are configured, existing workflow behavior is unchanged

Open with Devin

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 7 additional findings in Devin Review.

Open in Devin Review

// Only show the Cost column when at least one report has reliable cost data
// (currently only OpenCode populates cost; Claude and Codex return null)
const hasCost = Array.from(reports.values()).some((r) => typeof r.cost === 'number' && r.cost > 0);
const hasBudget = workflowBudget?.limit !== undefined || stepBudgets.size > 0;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 hasBudget check incorrectly treats null limit as a defined budget due to !== undefined

At packages/sdk/src/workflows/run-summary-table.ts:75, the condition workflowBudget?.limit !== undefined evaluates to true when limit is null, because null !== undefined is true in JavaScript. The buildWorkflowBudgetSummary method in packages/sdk/src/workflows/runner.ts:1541-1544 produces { used, limit: null, over: false } when per-agent constraints exist but no workflow tokenBudget is set. This causes the Budget column to appear in the summary table even when there is no meaningful budget data to display — all cells render as --.

Suggested change
const hasBudget = workflowBudget?.limit !== undefined || stepBudgets.size > 0;
const hasBudget = (workflowBudget?.limit != null) || stepBudgets.size > 0;
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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