Skip to content

feat(routes): let a route declare its render budget with config.render.maxElapsedMs (#454) - #526

Merged
ScriptedAlchemy merged 4 commits into
mainfrom
fix/runtime-install-gaps
Sep 4, 2026
Merged

feat(routes): let a route declare its render budget with config.render.maxElapsedMs (#454)#526
ScriptedAlchemy merged 4 commits into
mainfrom
fix/runtime-install-gaps

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Fixes #454.

Why

Every rendered route runs inside one render session bounded by DEFAULT_AGENT_RENDER_LIMITS.maxElapsedMs (60 s). The CLI runtime and the MCP projector construct the dispatcher with no overrides and no config field could raise it, so a long-poll route (cargo-hauler's hauler_await) had to clamp its own waits to 55 s and ask the agent to call again.

Design

  • Config surfaceconfig.render: { maxElapsedMs } on ToolConfig, ResourceConfig, PromptConfig, and CliRouteConfig (RouteRenderConfig). Read statically with the rest of config, so inspect --routes shows it and the generated servers never evaluate the module's config.
  • Compile-time validation — new AB4835 (routes/render-budget.ts): render must be an object whose only key is maxElapsedMs, a positive safe integer of milliseconds ≤ MAX_ROUTE_RENDER_ELAPSED_MS (24 h, exported from agent-bundle). A plain .ts CLI command declaring one is also AB4835 — it has no render session. Reported once per route: MCP routes with their server, CLI routes in the command compiler; a projected MCP command inherits its tool's value without re-reporting.
  • RuntimeAgentRenderDispatch.limits layers per-dispatch limits over the dispatcher's own, so the one long-lived dispatcher a generated MCP server or CLI executable owns serves routes with different budgets. renderGeneratedRoute passes the compiled config.render; the generated CLI shell passes command.render (CompiledCliCommand.render, absent key when undeclared so pre-existing graph digests are unchanged); the route-unit and mcp-in-memory harnesses layer the compiled budget over the limits a test passes as the dispatcher base (openInMemoryMcpServer({ limits }) is new).
  • Progress keep-alive — unchanged mechanism, now proven for a raised budget: every progress.report() and streamed Agent.Progress fallback is forwarded as notifications/progress for the whole call.
  • Ceiling evidence — none of adapters/capabilities/*.json records an MCP tool-call deadline. From the host docs (cited in the guide): Claude Code's default per-call wall clock is ~28 h (MCP_TOOL_TIMEOUT; per-server timeout), with a stdio idle timer of 30 min that progress notifications reset; Codex bounds a call at tool_timeout_sec (60 s default). The 24 h ceiling sits under Claude's default; Codex must be raised by the operator regardless. Default (60 s) unchanged.

Event routes keep their existing timeoutMs; rendered scripts have no config surface and are out of scope.

Tests

  • rsc-runtime/tests/dispatcher.test.ts — per-dispatch limits layer over the dispatcher base (real-time EOF past the base, completes under the dispatch budget; other keys untouched).
  • tests/cli-routes.test.ts — valid budgets on compiled commands + inheritance by projected MCP commands; every AB4835 shape, message order, and that a rejected route compiles no command.
  • tests/route-unit/render-route.test.tswait (fixture now declares render: { maxElapsedMs: 120_000 }) renders past a 100 ms base for a manifest route, the same module rendered directly does not, progress keeps flowing.
  • tests/projection/mcp-in-memory.test.ts — real SDK client over the generated server with a 100 ms base: wait completes and three notifications/progress arrive; catalog (no budget) is still bound by the base.
  • tests/test-harness-manifest.test.ts — projected command carries the budget.

Docs

docs/diagnostics.md (AB4835), docs/entry-conventions.md, website/docs/{en,zh}/guide/authoring/mcp.mdx (new "Render budget" section), website/docs/{en,zh}/guide/authoring/package-entries.mdx. pnpm docs:site:build green.

Verification

pnpm typecheck (the framework-plugin-registration.test.ts errors are pre-existing on main, fixed by #523), pnpm lint, pnpm test:unit (only framework-plugin-registration.test.ts fails, same pre-existing cause; 24 timeouts under concurrent docs build all pass when re-run), pnpm test:route-unit, pnpm test:projection, pnpm docs:site:build.

Review status

@changeset-bot

changeset-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6ff411b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@agent-bundle/runtime Patch
agent-bundle Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T05:37:15.935973Z 40675e0 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

ScriptedAlchemy added a commit that referenced this pull request Sep 4, 2026
@pkg-pr-new

pkg-pr-new Bot commented Sep 4, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@526
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@526
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@526

commit: 6ff411b

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 40675e0434

ℹ️ 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".

// directly and has none, so declaring one there is a mistake to surface.
const render = validateRouteRenderConfig(route, 'CLI route');
diagnostics.push(...render.diagnostics);
if (render.render !== undefined && !isRenderedCliRoute(route)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject empty render configs on plain commands

When a plain .ts command declares the type-valid config.render: {}, validateRouteRenderConfig() returns neither a budget nor a diagnostic, so this condition is false and the unsupported key compiles silently. This contradicts the new documentation and changeset promise that plain commands reject any config.render declaration with AB4835; check whether route.config['render'] was declared rather than whether validation produced a budget.

AGENTS.md reference: AGENTS.md:L78-L81

Useful? React with 👍 / 👎.

ScriptedAlchemy added a commit that referenced this pull request Sep 4, 2026
@ScriptedAlchemy
ScriptedAlchemy force-pushed the fix/runtime-install-gaps branch from 76e2f2c to 72dd531 Compare September 4, 2026 05:57
ScriptedAlchemy added a commit that referenced this pull request Sep 4, 2026
@ScriptedAlchemy
ScriptedAlchemy force-pushed the fix/runtime-install-gaps branch from 72dd531 to 3dae9ec Compare September 4, 2026 06:44
@ScriptedAlchemy
ScriptedAlchemy enabled auto-merge (squash) September 4, 2026 06:44
ScriptedAlchemy added a commit that referenced this pull request Sep 4, 2026
@ScriptedAlchemy
ScriptedAlchemy force-pushed the fix/runtime-install-gaps branch from 3dae9ec to 8e646ed Compare September 4, 2026 07:07
ScriptedAlchemy added a commit that referenced this pull request Sep 4, 2026
@ScriptedAlchemy
ScriptedAlchemy force-pushed the fix/runtime-install-gaps branch from 8e646ed to bcde3ff Compare September 4, 2026 07:32
ScriptedAlchemy added a commit that referenced this pull request Sep 4, 2026
@ScriptedAlchemy
ScriptedAlchemy force-pushed the fix/runtime-install-gaps branch from bcde3ff to 5f57f0f Compare September 4, 2026 08:23
@ScriptedAlchemy
ScriptedAlchemy force-pushed the fix/runtime-install-gaps branch from 0d92015 to 8813bdf Compare September 4, 2026 15:07
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.

Routes cannot raise the 60 s render session limit (maxElapsedMs); long-polling tools must clamp their own waits

1 participant