Replayer: closed-loop inter-turn think-time mode
Add --inter-turn-think (env REPLAY_INTER_TURN_THINK_S): turn 1 fires on session admission, each later turn a FIXED think-time after the previous turn COMPLETES, ignoring absolute trace timestamps. Combined with --max-inflight-sessions (env REPLAY_MAX_INFLIGHT) this is a stable N-user closed loop, removing the open-loop "fire immediately because timestamp is in the past" retrigger artifact. Needed for the dispatch-coupling (wall-clock amplification) sweep. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -60,6 +60,12 @@ class ReplayConfig:
|
||||
request_limit: int | None = None
|
||||
model_name: str = "default"
|
||||
max_inflight_sessions: int | None = None # cap on concurrent sessions; None = unlimited
|
||||
# Closed-loop think-time mode: if set, ignore absolute trace timestamps for
|
||||
# subsequent turns — fire turn 1 on session admission, then each later turn a
|
||||
# FIXED think-time after the previous turn COMPLETES. Combined with
|
||||
# max_inflight_sessions=N this is a stable N-user closed-loop (no open-loop
|
||||
# runaway), so it removes the "immediate retrigger under load" artifact.
|
||||
inter_turn_think_s: float | None = None
|
||||
|
||||
|
||||
def _build_prompt_token_ids(req: TraceRequest) -> list[int]:
|
||||
@@ -279,12 +285,19 @@ async def _run_session(
|
||||
await session_sem.acquire()
|
||||
realized_context: list[int] = []
|
||||
try:
|
||||
for req in state.turns:
|
||||
# Wait until this request's trace timestamp
|
||||
target_wall = (req.timestamp_s - earliest_ts)
|
||||
elapsed = time.perf_counter() - sweep_start
|
||||
if elapsed < target_wall:
|
||||
await asyncio.sleep(target_wall - elapsed)
|
||||
for turn_idx, req in enumerate(state.turns):
|
||||
if config.inter_turn_think_s is not None:
|
||||
# Closed-loop: turn 1 fires on admission; later turns wait a fixed
|
||||
# think-time AFTER the previous turn completed (no absolute schedule,
|
||||
# so no "fire immediately because timestamp is in the past").
|
||||
if turn_idx > 0:
|
||||
await asyncio.sleep(config.inter_turn_think_s)
|
||||
else:
|
||||
# Original: dispatch at the request's absolute trace timestamp.
|
||||
target_wall = (req.timestamp_s - earliest_ts)
|
||||
elapsed = time.perf_counter() - sweep_start
|
||||
if elapsed < target_wall:
|
||||
await asyncio.sleep(target_wall - elapsed)
|
||||
|
||||
token_ids = _apply_realized_prefix(
|
||||
_build_prompt_token_ids(req),
|
||||
|
||||
Reference in New Issue
Block a user