Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
d4ab0ad
[TRTLLM-16460][feat] staircase: staircase-onboard workflow: plan, ass…
Wanli-Jiang Oct 12, 2026
0d97289
[TRTLLM-16460][feat] staircase: serving envelope, feature matrix and …
Wanli-Jiang Oct 12, 2026
5fba5c4
[TRTLLM-16460][feat] staircase: adopt upstream agent-flow routing and…
Wanli-Jiang Oct 12, 2026
11f29ac
[TRTLLM-16460][feat] staircase: commit helper, pre-merge pack, source…
Wanli-Jiang Oct 12, 2026
1cdd017
[TRTLLM-16460][feat] staircase: evidence ledger, stale-verdict invali…
Wanli-Jiang Oct 12, 2026
b822ba6
[TRTLLM-16460][feat] staircase: gates that catch the escaped defects:…
Wanli-Jiang Oct 12, 2026
b21a6d7
[TRTLLM-16460][feat] staircase: execution substrate: spool scheduler,…
Wanli-Jiang Oct 12, 2026
90be7b0
[TRTLLM-16460][feat] staircase: follow the #19977 modeling_v2 layout:…
Wanli-Jiang Oct 12, 2026
c658abb
[TRTLLM-16460][feat] staircase: FlashInfer's public API is a sourcing…
Wanli-Jiang Oct 12, 2026
b39f6fc
[TRTLLM-16460][doc] staircase: README, LESSONS.md, TROUBLESHOOTING an…
Wanli-Jiang Oct 12, 2026
001c312
[TRTLLM-16460][fix] staircase: reap job processes that escaped the jo…
Wanli-Jiang Oct 13, 2026
8020277
[TRTLLM-16460][feat] staircase: the tune stage -- config ladder and t…
Wanli-Jiang Oct 13, 2026
80a9121
[TRTLLM-16460][fix] staircase: select the modeling_v2 target through …
Wanli-Jiang Oct 13, 2026
879219a
[TRTLLM-16460][feat] staircase: tune stage -- same-host judging, stac…
Wanli-Jiang Oct 13, 2026
de0d1f3
[TRTLLM-16460][fix] staircase tune: controls keyed by tree, config an…
Wanli-Jiang Oct 13, 2026
aa1dcf0
[TRTLLM-16460][feat] staircase: accept the perf block in task.yaml; -…
Wanli-Jiang Oct 13, 2026
23b09cd
[TRTLLM-16460][feat] staircase tune: rebase a candidate that conflict…
Wanli-Jiang Oct 13, 2026
785a8d8
[TRTLLM-16460][feat] staircase tune: cancel measurements on the old b…
Wanli-Jiang Oct 13, 2026
379dc64
[TRTLLM-16460][fix] staircase tune: nsys_summary places CUDA-graph re…
Wanli-Jiang Oct 13, 2026
57fa9ff
[TRTLLM-16460][feat] staircase tune: a keep's own measurement is its …
Wanli-Jiang Oct 13, 2026
9f8f9da
[TRTLLM-16460][fix] staircase tune: key accuracy gates by the tree ga…
Wanli-Jiang Oct 13, 2026
8c58665
[TRTLLM-16460][feat] staircase tune: stack the winners on one best tr…
Wanli-Jiang Oct 13, 2026
8a23dae
[TRTLLM-16460][feat] staircase tune: batch the compatible winners wit…
Wanli-Jiang Oct 13, 2026
03e3e32
[TRTLLM-16460][perf] staircase tune: reuse a finished candidate's eva…
Wanli-Jiang Oct 13, 2026
dccf24e
[TRTLLM-16460][feat] staircase tune: refresh a spent roadmap by re-pr…
Wanli-Jiang Oct 13, 2026
b238188
[TRTLLM-16460][perf] staircase tune: queue one control per waiting me…
Wanli-Jiang Oct 13, 2026
5d1ee30
[TRTLLM-16460][feat] staircase tune: the keep gate runs the target's …
Wanli-Jiang Oct 13, 2026
7ce93f5
[TRTLLM-16460][fix] staircase: a full filesystem no longer ends sessi…
Wanli-Jiang Oct 13, 2026
895243a
[TRTLLM-16460][fix] staircase tune: a measurement on a session that d…
Wanli-Jiang Oct 13, 2026
baddf37
[TRTLLM-16460][fix] staircase tune: re-point eval checkouts with a fo…
Wanli-Jiang Oct 13, 2026
bd1ffbb
[TRTLLM-16460][doc] staircase tune: document batches, rebases onto a …
Wanli-Jiang Oct 13, 2026
6957149
[TRTLLM-16460][fix] staircase tune: resolve the stage's paths before …
Wanli-Jiang Oct 13, 2026
260452d
[TRTLLM-16460][fix] staircase tune: run-scoped job names and retried …
Wanli-Jiang Oct 13, 2026
93559fb
[TRTLLM-16460][perf] staircase tune: re-probe only near-miss neutral …
Wanli-Jiang Oct 13, 2026
8229ebb
[TRTLLM-16460][fix] staircase tune: a ladder resumed after its probes…
Wanli-Jiang Oct 13, 2026
0bae96b
[TRTLLM-16460][fix] staircase tune: a preempted session neither gets …
Wanli-Jiang Oct 13, 2026
4a607aa
[TRTLLM-16460][fix] staircase tune: branch names scoped to the run
Wanli-Jiang Oct 13, 2026
16bf1c8
[TRTLLM-16460][perf] staircase tune: the campaign starts on the ladde…
Wanli-Jiang Oct 13, 2026
7343733
[TRTLLM-16460][fix] file dispatch: the orchestrator heartbeat survive…
Wanli-Jiang Oct 13, 2026
6e28f11
[TRTLLM-16460][fix] staircase tune: a turn that finished during a res…
Wanli-Jiang Oct 13, 2026
af48a1b
[TRTLLM-16460][perf] staircase tune: winners that conflict with a lon…
Wanli-Jiang Oct 13, 2026
5b38767
[TRTLLM-16460][perf] staircase tune: stop a gate whose stacked tree a…
Wanli-Jiang Oct 13, 2026
5c04c5f
[TRTLLM-16460][doc] staircase tune: lone-winner rebases and moved-tre…
Wanli-Jiang Oct 13, 2026
6b1b0ee
[TRTLLM-16460][fix] staircase tune: a restarted campaign adopts its g…
Wanli-Jiang Oct 13, 2026
4da78fc
[TRTLLM-16460][fix] staircase tune: a gate whose suite cannot run is …
Wanli-Jiang Oct 13, 2026
d286fac
[TRTLLM-16460][feat] staircase tune: tuner requests and the perf skil…
Wanli-Jiang Oct 13, 2026
dd82886
[TRTLLM-16460][doc] staircase perf skill: FlashInfer-backed entries g…
Wanli-Jiang Oct 13, 2026
6a83cfa
[TRTLLM-16460][fix] staircase tune: the campaign CLI takes a branch p…
Wanli-Jiang Oct 14, 2026
c9d16a2
[TRTLLM-16460][feat] staircase tune: per-model accuracy-gate eval arg…
Wanli-Jiang Oct 14, 2026
ef9091a
[TRTLLM-16460][feat] staircase tune: roadmap turns see the sources; d…
Wanli-Jiang Oct 14, 2026
01254b1
[TRTLLM-16460][test] staircase tune: nsys_summary on a synthetic capture
Wanli-Jiang Oct 14, 2026
5a3a942
[TRTLLM-16460][feat] staircase tune: without a ladder, the ground bas…
Wanli-Jiang Oct 14, 2026
485dbab
[TRTLLM-16460][feat] staircase tune: the roadmap request carries path…
Wanli-Jiang Oct 14, 2026
53bbe4b
[TRTLLM-16460][fix] staircase tune: noise repeats run on the baseline…
Wanli-Jiang Oct 14, 2026
6cddcbe
[TRTLLM-16460][feat] staircase tune: roadmaps owe perf_optimize's ker…
Wanli-Jiang Oct 14, 2026
469452f
[TRTLLM-16460][feat] staircase-onboard: --wait-for-spool lets the run…
Wanli-Jiang Oct 14, 2026
cbb5239
[TRTLLM-16460][fix] staircase tune: bench warms up at the largest con…
Wanli-Jiang Oct 14, 2026
fc18e13
[TRTLLM-16460][fix] staircase-onboard: a resumed run keeps a current …
Wanli-Jiang Oct 14, 2026
7ca5f19
[TRTLLM-16460][fix] staircase tune: a finished measurement without it…
Wanli-Jiang Oct 14, 2026
962e5d2
[TRTLLM-16460][perf] staircase tune: candidate worktrees check out si…
Wanli-Jiang Oct 14, 2026
68b157f
[TRTLLM-16460][fix] staircase tune: a half-created candidate worktree…
Wanli-Jiang Oct 14, 2026
51771eb
[TRTLLM-16460][feat] staircase tune: near misses are stacked and judg…
Wanli-Jiang Oct 14, 2026
52ea14a
[TRTLLM-16460][doc] staircase-onboard: README flags table lists --wai…
Wanli-Jiang Oct 14, 2026
c096716
[TRTLLM-16460][feat] staircase tune: warn on a thin noise floor; over…
Wanli-Jiang Oct 14, 2026
031594b
[TRTLLM-16460][fix] staircase: delivery checks follow modeling_v2 as …
Wanli-Jiang Oct 15, 2026
d27607a
[TRTLLM-16460][fix] staircase: the catalog is its entry files; no index
Wanli-Jiang Oct 15, 2026
ced5879
[TRTLLM-16460][doc] staircase: role prompts describe modeling_v2 as m…
Wanli-Jiang Oct 15, 2026
5b7aba5
[TRTLLM-16460][doc] staircase: skills and guides describe modeling_v2…
Wanli-Jiang Oct 15, 2026
2c4d773
[TRTLLM-16460][chore] staircase tune: pass the repo's pre-commit
Wanli-Jiang Oct 15, 2026
6490d8b
[TRTLLM-16460][chore] agent-flow: rename staircase-onboard to trtllm_…
Wanli-Jiang Oct 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,21 @@ For a full list of up-to-date bot commands, post `/bot help` as a PR comment and

- Use `TLLM_LOG_LEVEL_BY_MODULE` to enable per-module log filtering (e.g., `"debug:_torch,runtime;info:serve"`); see [Module-Level Logging](docs/source/developer-guide/overview.md#module-level-logging) for details.

**Environment failures that read as model failures.** Each of these presents as a broken
model or a broken build, and none of them is. Check them before debugging modeling code:

| symptom | cause | fix |
|---|---|---|
| `MPI_ERR_SPAWN: could not spawn` | the container runtime forbids `MPI_Comm_spawn`, which the default LLM API path uses to start workers (normal under pyxis/enroot) | `TLLM_WORKER_USE_SINGLE_PROCESS=1` |
| `Impossible to fit in any sequence in kvCache` | the engine inherited the checkpoint's `max_position_embeddings` (262144 is common) and sized the cache for it | pass `--max_seq_len` / `--max_batch_size` / `--kv_cache_fraction` explicitly |
| `NVRTC ... could not open source file "cuda.h"` | usually the venv's `bin` missing from `PATH`; separately, the generation FMHA kernel takes the NVRTC path unless the KV dtype is `E2m1` (grep `options.mDtypeKv != tg::Dtype::E2m1`) | check `PATH` first; `--kv_cache_dtype fp8` takes the non-NVRTC branch |
| the engine hangs at startup and never returns | a wrong launch substrate hangs rather than raises — typically an MPI connect-back on an interface that does not carry it | probe with a deadline rather than waiting |
| the import resolves to a different checkout | `/root/.local` is shared across container runs on some clusters | `PYTHONNOUSERSITE=1` at runtime — but **not** during the native build, which needs the user site for `cutlass_library` |

A longer list, with the wrong diagnoses recorded alongside the right ones, is in
[`agent-flow/agent_flow/workflows/trtllm_modeling_v2/TROUBLESHOOTING.md`](agent-flow/agent_flow/workflows/trtllm_modeling_v2/TROUBLESHOOTING.md).
It is keyed on verbatim error text, so search it for the string you saw.

## Key Documentation

| Topic | Path |
Expand Down
3 changes: 2 additions & 1 deletion agent-flow/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,4 +297,5 @@ block, before `run`: it writes each role's composed system prompt verbatim to
handed in, since that is what the agents are built from (`AgentTeamWorkflow`
appends its MCP-tool protocol to the bundle it is given). The `perf-analyze`
and `perf-optimize` CLIs use it to snapshot `<workspace>/prompts/` at every
launch.
launch; `trtllm-modeling-v2` does the same from preflight, once the launch
environment its prompts carry is resolved.
70 changes: 70 additions & 0 deletions agent-flow/agent_flow/runtime/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Execution substrate shared by every workflow.

Two questions live here, and neither of them is a workflow's business:

* **how does one agent turn get delivered and answered** — in this process
through an ``AgentLayer``, or through a filesystem mailbox a separate
authenticated session drains;
* **where and how does one command run** — a local subprocess, an ``srun``
step, or a file dropped into a spool a long-lived allocation watches.

A workflow states *what* it needs run and *what* it needs proven. It should
not carry a branch per cluster protocol, and it should not have to change
when a credential store turns read-only. Everything in this package is
therefore free of workflow vocabulary: nothing here knows what a catalog
entry, a smith or a gate is.

A third concern, older than the other two, already lived at this import
path: running async work on a background loop for a synchronous caller. It
is the same kind of thing — substrate a workflow uses without describing —
so it stayed, as :mod:`~agent_flow.runtime.portal`, and
``from agent_flow.runtime import PortalRunner`` still resolves.
"""

from .commands import (
CommandExecutor,
CommandSpec,
DelegatedCommandExecutor,
ExecutionCapabilities,
ExecutionRecord,
LocalCommandExecutor,
SlurmStepExecutor,
SpoolCommandExecutor,
SubmissionRenderer,
)
from .portal import PortalRunner, build_request
from .turns import (
DEFAULT_TURN_TIMEOUT_S,
FileDispatchTurnExecutor,
InProcessTurnExecutor,
TurnExecutionError,
TurnExecutor,
TurnOutcome,
TurnRequest,
TurnTimeout,
)

__all__ = [
"CommandExecutor",
"CommandSpec",
"DEFAULT_TURN_TIMEOUT_S",
"DelegatedCommandExecutor",
"SubmissionRenderer",
"ExecutionCapabilities",
"ExecutionRecord",
"FileDispatchTurnExecutor",
"InProcessTurnExecutor",
"LocalCommandExecutor",
"PortalRunner",
"SlurmStepExecutor",
"SpoolCommandExecutor",
"TurnExecutionError",
"TurnExecutor",
"TurnOutcome",
"TurnRequest",
"TurnTimeout",
"build_request",
]
24 changes: 24 additions & 0 deletions agent-flow/agent_flow/runtime/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Command execution: one interface, one per place a command can land."""

from .base import CommandExecutor, CommandSpec, ExecutionCapabilities, ExecutionRecord
from .delegated import DelegatedCommandExecutor, SubmissionRenderer
from .local import NOT_FOUND_RETURNCODE, TIMEOUT_RETURNCODE, LocalCommandExecutor
from .slurm import SlurmStepExecutor
from .spool import SpoolCommandExecutor

__all__ = [
"CommandExecutor",
"CommandSpec",
"DelegatedCommandExecutor",
"ExecutionCapabilities",
"ExecutionRecord",
"LocalCommandExecutor",
"NOT_FOUND_RETURNCODE",
"SlurmStepExecutor",
"SubmissionRenderer",
"SpoolCommandExecutor",
"TIMEOUT_RETURNCODE",
]
140 changes: 140 additions & 0 deletions agent-flow/agent_flow/runtime/commands/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""One command, and where it ran.

A workflow that measures something needs to say *what to run* and *how long
it may take*. Where that lands — this host, an ``srun`` step, a file in a
spool a long-lived allocation drains — is a property of the deployment, and
every time it leaked into the workflow it arrived as a new branch beside a
stage transition.

So: the caller builds a :class:`CommandSpec`, an executor returns an
:class:`ExecutionRecord`, and the record carries enough provenance that the
verdict drawn from it can be defended later without knowing which executor
produced it.

**A timeout is not an error here.** ``timed_out`` is a separate field from
the exit code because the two need different handling — a gate that timed out
has said nothing about the thing it was gating, while a gate that exited
non-zero has.
"""

from __future__ import annotations

import abc
import shlex
from dataclasses import dataclass, field
from typing import ClassVar, Mapping, Sequence


@dataclass(frozen=True)
class ExecutionCapabilities:
"""What an executor can actually run, in machine-readable form.

Stated rather than inferred, so a caller can refuse an impossible
request before paying for it instead of discovering the limit from a
failure three hours in.
"""

gpu: bool = False
distributed: bool = False
#: True when the executor runs inside an allocation acquired once and
#: reused, rather than queueing per command. That is the difference
#: between paying a scheduler wait (and a container import) per gate and
#: paying it once for the run.
persistent_allocation: bool = False
max_world_size: int | None = None
architectures: tuple[str, ...] = ()


@dataclass(frozen=True)
class CommandSpec:
"""What to run, and the bounds it runs under.

``argv`` is either a **string**, which is a shell line and is run as
one, or a **sequence**, which is executed directly with no shell between.
Both forms are real and neither is a convenience: a resolved launch
prefix (environment assignments, or an ``srun`` line) *is* shell syntax
and re-parsing it into an argv would mean reimplementing the shell, while
a probe like ``nvidia-smi --query-gpu=...`` has no reason to be exposed
to word splitting at all.
"""

argv: str | Sequence[str]
env: Mapping[str, str] | None = None
timeout_s: int = 600
#: A short name for this command in logs and artifacts. Not an id.
label: str = ""
#: How many ranks the command expects. Carried so an executor can refuse
#: a request its allocation cannot satisfy; never used to rewrite the
#: command, which is the caller's business.
world_size: int = 1
gpu_arch: str | None = None
#: Where to run it, when the executor supports a working directory.
cwd: str | None = None

@property
def rendered(self) -> str:
"""``argv`` as a single line, for logs and for shell execution."""
if isinstance(self.argv, str):
return self.argv
return " ".join(shlex.quote(str(part)) for part in self.argv)

@property
def is_shell_line(self) -> bool:
return isinstance(self.argv, str)


@dataclass(frozen=True)
class ExecutionRecord:
"""What happened, with the provenance a verdict rests on."""

command: str
returncode: int
stdout: str = ""
stderr: str = ""
timed_out: bool = False
duration_s: float = 0.0
#: Which executor ran it — ``local``, ``slurm``, ``spool``.
executor: str = ""
label: str = ""
#: Where the full output lives, when the executor wrote one. The tail a
#: record carries is for reading; this is for auditing.
log_path: str | None = None
started_at: float = 0.0
artifacts: tuple[str, ...] = field(default_factory=tuple)

@property
def ok(self) -> bool:
return self.returncode == 0 and not self.timed_out

@property
def combined(self) -> str:
return self.stdout + self.stderr

def tail(self, lines: int = 40) -> str:
return "\n".join(self.combined.splitlines()[-lines:])


class CommandExecutor(abc.ABC):
"""Run one command somewhere and report what happened."""

#: Recorded in :attr:`ExecutionRecord.executor`.
name: ClassVar[str] = "command-executor"

#: Overridden per executor. A class attribute rather than a property so
#: a caller can ask without constructing one.
capabilities: ExecutionCapabilities = ExecutionCapabilities()

@abc.abstractmethod
def execute(self, spec: CommandSpec) -> ExecutionRecord:
"""Run ``spec`` to completion or to its deadline."""


__all__ = [
"CommandExecutor",
"CommandSpec",
"ExecutionCapabilities",
"ExecutionRecord",
]
Loading
Loading