Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
e6bae72
[WIP] feat: scaffolding serve
Boreas618 Feb 24, 2026
c4352f5
refactor: structure of coder agent
Boreas618 Mar 10, 2026
966a293
feat: scaffolding tracer
Boreas618 Mar 10, 2026
a141e58
feat: scaffolding replay
Boreas618 Mar 13, 2026
cfb1943
[feat][None]: draft for IterResearch
WeiHaocheng Mar 17, 2026
10b2639
[feat][None]: refator mcp server code
WeiHaocheng Mar 17, 2026
e943b33
feat (WIP): coder with sandbox
Boreas618 Mar 18, 2026
94d5984
refactor: format of execution trace
Boreas618 Mar 19, 2026
1c7d014
[feat][None]: Add a api for openai server to get token count and modi…
WeiHaocheng Mar 19, 2026
a9f628e
fix bug of tracing tokenize
WeiHaocheng Mar 20, 2026
601d2f8
fix: swebench integration
Boreas618 Mar 20, 2026
3e346d9
refactor: swebench integration
Boreas618 Apr 20, 2026
566b0fa
[None][feat] Add apiary python interpreter for iter_research
KleinBlueC Apr 21, 2026
bff7b70
[None][feat] Enable trace replay with parallel strategies
KleinBlueC Apr 9, 2026
0ca6628
[None][feat] Update search agent mcp tools
KleinBlueC Apr 22, 2026
f70bc56
[None][feat] Enable search agent tracing and replaying
KleinBlueC Apr 22, 2026
41a3cdd
refactor: openai server for pareto
Boreas618 Apr 23, 2026
1552dbd
[None][feat] Add tree_of_thought_research and enhance search mcp tool…
KleinBlueC Apr 27, 2026
c7fc184
[None][feat] Enable coder and swebench tracing
KleinBlueC Apr 30, 2026
0aed7ff
[None][fix] Revise agent message format and system message caching fo…
KleinBlueC May 12, 2026
f882da8
[None][feat] Calculate kv cache hit rate upper bound for scaffolding …
KleinBlueC May 12, 2026
02385f2
feat: as-eval artifacts
KleinBlueC May 16, 2026
02b2e39
[None][feat] Add steady-state replay performance measurements and exp…
KleinBlueC May 18, 2026
d807165
[None][fix] Revise the optimal kv cache calculation module for scaffo…
KleinBlueC May 21, 2026
b8a582b
[None][refactor] Delete redundant config files and update trace example
KleinBlueC May 21, 2026
e0ceb20
[None][refactor] Delete experimental scripts and revise improper edit…
KleinBlueC May 25, 2026
70f47a4
[None][refactor] Remove trtllm server modifications for pareto experi…
KleinBlueC May 25, 2026
0c62498
[None][refactor] Add descriptions for TokenizeRequest and TokenizeRes…
KleinBlueC May 25, 2026
ed53748
Merge branch 'main' into feat/scaffolding-trace-replay
KleinBlueC May 25, 2026
3215fb6
[None][refactor] Remove trtllm scheduler logging modification
KleinBlueC May 25, 2026
988e9d1
[None][refactor] Separate trace-replay related codes and refactor SWE…
KleinBlueC Jun 9, 2026
9c4d2b8
[None][feat] Record parallel region timestamps during replaying
KleinBlueC Jun 9, 2026
0cd21c3
Merge remote-tracking branch 'upstream/main' into temp/split-part1
KleinBlueC Jun 9, 2026
e56b166
[None][fix] Fix pre-commit lint violations
KleinBlueC Jun 10, 2026
cecf63a
Merge branch 'main' into feat/scaffolding-trace-replay
KleinBlueC Jun 16, 2026
681ffc3
Merge branch 'main' into feat/scaffolding-trace-replay
KleinBlueC Jun 25, 2026
7e1bfca
Merge branch 'main' into temp/split-part1
KleinBlueC Jul 1, 2026
6818a49
[None][chore] Remove large full trace example file
KleinBlueC Jul 1, 2026
8775612
[None][docs] Update trace_replay README for example layout
KleinBlueC Jul 1, 2026
fe33ce8
[None][docs] Consolidate research-agent example configs into one shar…
KleinBlueC Jul 1, 2026
0a9a697
[None][chore] Drop copyright headers from scaffolding example files
KleinBlueC Jul 1, 2026
73b3c45
Merge branch 'main' into feat/scaffolding-trace-replay
KleinBlueC Jul 2, 2026
e043736
[None][fix] Fix duplicate imports in openai_server.py via isort
KleinBlueC Jul 5, 2026
86b5f94
Merge branch 'main' into feat/scaffolding-trace-replay
KleinBlueC Jul 6, 2026
c25e0ba
[None][chore] Move tokenize endpoint from /v1/tokenize to /_internal/…
KleinBlueC Jul 9, 2026
4d3d630
[None][test] Relocate tokenize endpoint tests into llmapi/apps
KleinBlueC Jul 10, 2026
c6c8938
[None][fix] Drop always-null KV cache pool-state fields from perf met…
KleinBlueC Jul 10, 2026
1a206bb
[None][chore] Restrict tokenize endpoint to plain-text prompt
KleinBlueC Jul 10, 2026
ed2e13a
[None][fix] Expect 400 from tokenize endpoint on empty body
KleinBlueC Jul 11, 2026
e18ea37
Merge branch 'main' into feat/scaffolding-trace-replay
KleinBlueC Jul 11, 2026
1586d38
[None][fix] Add id to dummy ToolCall in scaffolding MCP worker test
KleinBlueC Jul 12, 2026
328a4fd
Merge branch 'main' into feat/scaffolding-trace-replay
KleinBlueC Jul 13, 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
69 changes: 67 additions & 2 deletions examples/scaffolding/benchmarks/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
"""

import argparse
import os
import sys

from tensorrt_llm.scaffolding import TaskMetricsCollector

from .agent_benchmark import async_agent_benchmark, async_burst_agent_benchmark
from .benchmark_utils import run_benchmark_in_thread
from .chat_benchmark import async_chat_benchmark
from .coder_benchmark import async_coder_benchmark
from .multiround_chat_benchmark import async_multiround_chat_benchmark


Expand Down Expand Up @@ -129,6 +131,68 @@ def parse_arguments():
help="[Agent only] Enable query collector for debugging",
)

# Coder agent parameters
parser.add_argument(
"--enable_coder",
action="store_true",
help="Enable Coder agent benchmark (uses Apiary sandboxes via ApiaryMCPWorker)",
)
parser.add_argument(
"--coder_concurrency",
type=int,
default=32,
help="Concurrency for Coder agent benchmark (default: 32)",
)
parser.add_argument(
"--coder_prompt_num",
type=int,
default=8,
help="Number of prompts for Coder benchmark (default: 8)",
)
parser.add_argument(
"--coder_max_iterations",
type=int,
default=50,
help="Max tool-calling iterations per Coder request (default: 50)",
)
parser.add_argument(
"--coder_max_connections",
type=int,
default=200,
help="Max concurrent Apiary sandbox connections for Coder (default: 200)",
)
parser.add_argument(
"--mcp_url",
type=str,
default="http://0.0.0.0:8083/sse",
help="Coder Apiary MCP server URL (default: http://0.0.0.0:8083/sse)",
)
parser.add_argument(
"--coder_image",
type=str,
default="ubuntu:22.04",
help="Docker image name used for Coder benchmark sandboxes (default: ubuntu:22.04)",
)
parser.add_argument(
"--apiary_url",
type=str,
default=os.getenv("APIARY_URL", "http://127.0.0.1:8080"),
help="[Coder only] Apiary daemon URL used to register the sandbox image "
"(default: $APIARY_URL or http://127.0.0.1:8080)",
)
parser.add_argument(
"--apiary_token",
type=str,
default=os.getenv("APIARY_API_TOKEN"),
help="[Coder only] Bearer token for the Apiary daemon (default: $APIARY_API_TOKEN)",
)
parser.add_argument(
"--coder_rate",
type=float,
default=1.0,
help="[Rate mode] Poisson arrival rate (req/s) for Coder benchmark. Default: 1.0.",
)

# Burst agent parameters
parser.add_argument(
"--enable_burst_agent",
Expand Down Expand Up @@ -456,6 +520,7 @@ def parse_arguments():
# Benchmark registry: (async_func, display_name, flag_name)
BENCHMARK_REGISTRY = [
(async_agent_benchmark, "Agent-Benchmark", "enable_normal_agent"),
(async_coder_benchmark, "Coder-Benchmark", "enable_coder"),
(async_burst_agent_benchmark, "Burst-Agent-Benchmark", "enable_burst_agent"),
(async_chat_benchmark, "Chat-Benchmark", "enable_chat"),
(async_multiround_chat_benchmark, "Multiround-Chat-Benchmark", "enable_multiround_chat"),
Expand Down Expand Up @@ -497,8 +562,8 @@ def main():

if not enabled_benchmarks:
print(
"No benchmark enabled. Use --enable_normal_agent, --enable_burst_agent, "
"--enable_chat, or --enable_multiround_chat"
"No benchmark enabled. Use --enable_normal_agent, --enable_coder, "
"--enable_burst_agent, --enable_chat, or --enable_multiround_chat"
)
sys.exit(1)

Expand Down
203 changes: 203 additions & 0 deletions examples/scaffolding/benchmarks/coder_benchmark.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
"""Coder agent benchmark for scaffolding benchmarks.

Runs the Coder agent against Apiary sandboxes with configurable concurrency.
Each concurrent request gets its own isolated sandbox via ApiaryMCPWorker.
"""

import sys

from apiary_client import AsyncApiary
from openai import AsyncOpenAI

from tensorrt_llm.scaffolding import ApiaryMCPWorker, QueryCollector, TRTOpenaiWorker
from tensorrt_llm.scaffolding.benchmark import ScaffoldingBenchRequest, async_scaffolding_benchmark
from tensorrt_llm.scaffolding.contrib.Coder import create_coder_scaffolding_llm
from tensorrt_llm.scaffolding.load_generation_strategy import (
ConcurrentStrategy,
PoissonRateStrategy,
UniformWarmupStrategy,
)

from .benchmark_utils import print_benchmark_results, print_lock, shutdown_llm

DEFAULT_CODER_PROMPTS = [
"Add comprehensive error handling to all public functions in the project.",
"Implement a thread-safe LRU cache with configurable capacity.",
"Write a CLI tool that converts CSV files to JSON with streaming support.",
"Create a retry decorator with exponential backoff and jitter.",
"Implement a simple key-value store with TTL-based expiration.",
"Add input validation and type checking to the API endpoint handlers.",
"Write a log aggregation utility that merges and deduplicates log entries.",
"Create a configuration loader that supports YAML, JSON, and environment variables.",
]


def load_coder_prompts(num_prompts: int) -> list[str]:
"""Load prompts for the Coder benchmark from built-in coding tasks."""
prompts = DEFAULT_CODER_PROMPTS.copy()
if len(prompts) < num_prompts:
original = prompts.copy()
repeat = (num_prompts + len(original) - 1) // len(original)
prompts = []
for i in range(repeat):
for p in original:
tag = f"[{i}]." if i > 0 else ""
prompts.append(f"{tag}{p}")
return prompts[:num_prompts]


async def register_coder_image(args) -> None:
"""Register the Coder benchmark image with the Apiary daemon.

The image used by every benchmark request must be registered before the
MCP server creates sandboxes against it (otherwise Apiary returns 404).
Failures are surfaced as a hard error so the benchmark doesn't silently
produce 502s for every iteration.
"""
image = getattr(args, "coder_image", "ubuntu:22.04")
apiary_url = getattr(args, "apiary_url", "http://127.0.0.1:8080")
apiary_token = getattr(args, "apiary_token", None)

apiary = AsyncApiary(
apiary_url=apiary_url,
apiary_token=apiary_token,
images=[image],
)
try:
if not await apiary.health_check(retries=10, interval=1.0):
raise RuntimeError(
f"Apiary daemon at {apiary_url} is not reachable. "
"Start it with `apiary init && apiary daemon --bind ...`."
)
status = await apiary.load()
if status is not None and image in status.failed:
reason = next(
(
entry.get("reason")
for entry in status.failed_images
if entry.get("name") == image
),
"unknown",
)
raise RuntimeError(f"Failed to register image {image!r} with Apiary: {reason}")
finally:
await apiary.close()


async def create_coder_resources(args):
"""Create isolated resources for a Coder benchmark run.

Returns:
Tuple of (llm, mcp_worker, generation_worker) for cleanup.
"""
client = AsyncOpenAI(api_key=args.openai_api_key, base_url=args.base_url)
generation_worker = TRTOpenaiWorker(
client, args.model, getattr(args, "kv_cache_hint_agent", False)
)

mcp_url = getattr(args, "mcp_url", "http://0.0.0.0:8083/sse")
max_conns = getattr(args, "coder_max_connections", 200)
mcp_worker = ApiaryMCPWorker(mcp_url, max_connections=max_conns)

llm = create_coder_scaffolding_llm(
generation_worker,
mcp_worker,
max_tokens=getattr(args, "max_tokens_agent", 65536),
max_iterations=getattr(args, "coder_max_iterations", 50),
max_parallel_requests=getattr(args, "max_parallel_requests", 1024),
enable_statistics=getattr(args, "enable_statistics", False),
)

return llm, mcp_worker, generation_worker


async def cleanup_coder_resources(llm, mcp_worker):
"""Cleanup Coder benchmark resources."""
await mcp_worker.async_shutdown()
await shutdown_llm(llm)


async def run_coder_benchmark_core(
llm, prompts, concurrency, benchmark_name, args, use_poisson_arrival=True
):
"""Core Coder benchmark logic.

Args:
llm: The ScaffoldingLlm instance.
prompts: List of prompts to benchmark.
concurrency: Number of concurrent requests.
benchmark_name: Name for the benchmark (used in output).
args: Command line arguments.

Returns:
Tuple of (results, requests_start_time, requests_execution_time, total_time).
"""
task_collection_types = {}
requests = [
ScaffoldingBenchRequest(
prompt=prompt,
scope_params={"image": getattr(args, "coder_image", "ubuntu:22.04")},
)
for prompt in prompts
]

if use_poisson_arrival and getattr(args, "load_mode", "concurrent") == "rate":
strategy = PoissonRateStrategy(
rate=getattr(args, "coder_rate", 1.0),
random_seed=getattr(args, "rate_seed", 42),
)
elif getattr(args, "warmup_window", None) is not None:
strategy = UniformWarmupStrategy(
num_requests=len(requests),
warmup_window=args.warmup_window,
max_concurrency=concurrency,
)
else:
strategy = ConcurrentStrategy(concurrency=concurrency)
print(f" Strategy: {strategy}")

(
results,
requests_start_time,
requests_execution_time,
total_time,
) = await async_scaffolding_benchmark(llm, task_collection_types, requests, strategy=strategy)

print_benchmark_results(
benchmark_name,
results,
requests_start_time,
requests_execution_time,
total_time,
)

if getattr(args, "enable_query_collector", False):
QueryCollector.get_global_info()
with print_lock:
print(f"Query info dumped to query_result.json! ({benchmark_name})")

return results, requests_start_time, requests_execution_time, total_time


async def async_coder_benchmark(args):
"""Run the Coder agent benchmark.

Returns:
Tuple of (results, requests_start_time, requests_execution_time, total_time).
"""
concurrency = getattr(args, "coder_concurrency", 32)
num_prompts = getattr(args, "coder_prompt_num", 8)

await register_coder_image(args)

llm, mcp_worker, _ = await create_coder_resources(args)
prompts = load_coder_prompts(num_prompts)

with print_lock:
print(f"\n[Coder] Starting benchmark with {num_prompts} prompts, concurrency={concurrency}")
sys.stdout.flush()

try:
return await run_coder_benchmark_core(llm, prompts, concurrency, "Coder", args)
finally:
await cleanup_coder_resources(llm, mcp_worker)
Loading
Loading