Skip to content

[pull] main from danny-avila:main - #169

Merged
pull[bot] merged 2 commits into
innFactory:mainfrom
danny-avila:main
Aug 12, 2026
Merged

[pull] main from danny-avila:main#169
pull[bot] merged 2 commits into
innFactory:mainfrom
danny-avila:main

Conversation

@pull

@pull pull Bot commented Aug 12, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

danny-avila and others added 2 commits August 12, 2026 14:02
* fix: improve activity label Langfuse traces

* fix: scope activity trace correlation
* feat: add run step lifecycle timestamps and on_run_step_closed event

Stamps every run step with created_at + status ('in_progress') at dispatch
and closes each step exactly once with a terminal status and timestamp:

- New GraphEvents.ON_RUN_STEP_CLOSED custom event carrying
  { id, index, type, status, created_at, closed_at, runId?, agentId?,
  groupId?, stepIndex? }, dual-dispatched (handler registry + custom
  event) with the standard echo dedup. Purely additive: hosts that
  register nothing observe identical behavior.
- RunStep gains optional created_at / completed_at / cancelled_at /
  failed_at / status fields (the previously commented-out
  OpenAI-Assistants shape); ToolCompleteEvent gains completed_at so tool
  durations also ride the existing ON_RUN_STEP_COMPLETED event.
- StandardGraph.closeRunStep is the idempotent close funnel
  (first-close-wins; a narrow completed->completed restamp lets a
  completed TOOL_CALLS step refresh its timestamp when a late-registered
  parallel call finishes). recordStepCompletion counts pending tool
  calls per step (N-of-M) so multi-call steps close on their last
  completion.
- Close triggers: tool completions are observed centrally in run.ts's
  custom-event callback (ToolNode holds no graph reference), directly at
  the registry-only summarization/tool-error sites, on CHAT_MODEL_END
  for the lane's open message step, and when a successor step opens in
  the same agent lane.
- End-of-run sweep in processStream's finally closes anything still
  open: completed on natural finish, cancelled on caller abort or hook
  halt, failed on unexpected stream errors. Skipped while paused on a
  HITL interrupt so resumed steps keep their original created_at.
- Subagent forwarding: run_step_closed phase + sanitizer allowlists for
  the new fields; manual session compaction emits the closed event for
  its synthetic steps; session streams gain a 'step.finished' event.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vLhxCFMYkCaTsoFTiAjJ5

* refactor: tighten run-step accounting hot paths

- untrackRunStep: replace the per-close scan of openMessageStepByAgent
  with an O(1) keyed delete — the lane key is recomputable as
  runStep.agentId ?? '', exactly how both funnels insert it.
- dispatchRunStep: hoist the pending-set get-or-create out of the
  existing per-tool-call loop (one lookup per step instead of per call).
- Deduplicate the successor-close + content-map + open-step accounting
  shared by dispatchRunStep and the summarization adapter into
  trackDispatchedRunStep.
- Replace linear contentData.find with O(1) contentIndexMap lookups in
  the summarization adapter's completion dispatch and manual
  compaction's synthetic graph.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vLhxCFMYkCaTsoFTiAjJ5

* refactor: options-bag close API, typed completion narrowing, invariant docs

- closeRunStep(stepId, status, options): fold the positional `at` timestamp
  into RunStepCloseOptions, removing undefined-hole call sites.
- run.ts: narrow ON_RUN_STEP_COMPLETED payloads through getToolCompletionIds
  instead of an inline structural cast.
- Document the RunStep terminal-status/timestamp invariant on the type,
  noting it is runtime-enforced to stay wire-compatible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vLhxCFMYkCaTsoFTiAjJ5

* perf: short-circuit message-step closure on the model-end path

closeOpenMessageStep runs on every CHAT_MODEL_END. Return early when no
message step is tracked, and gate getStepAgentKey's context lookup behind
the constant-time multi-agent check — getAgentContext signals a miss by
throwing, so single-agent graphs were constructing and discarding an Error
per model call to derive a lane key that is always ''.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vLhxCFMYkCaTsoFTiAjJ5

* fix: address Codex review findings on step closure

- Keep ON_RUN_STEP_CLOSED single-shot: a restamp for a late parallel tool
  completion now updates the stored completed_at without re-emitting, so
  consumers cannot double-count a step (duplicate session step.finished).
- Isolate sweep dispatch per step so one throwing host handler no longer
  strands every later step in_progress with no terminal event.
- Dual-dispatch swept closures instead of registry-only, so callback-only
  subscribers receive cancelled/failed terminals when the channel is alive.
- Stop tracking summarization steps as the lane's open message step: their
  model call emits CHAT_MODEL_END long before the summary is assembled, so
  model-end was publishing an authoritative completed closure early. They
  close through their own completion instead.
- Sweep open steps in manual compaction, which runs outside processStream
  and had no failure path to close a published summary step.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vLhxCFMYkCaTsoFTiAjJ5

* fix: preserve producer completion time and corroborate abort status

- Carry the producer's `completed_at` from ON_RUN_STEP_COMPLETED through to
  the close, so a slow host completion handler no longer inflates the
  recorded step duration. recordStepCompletion takes an options bag rather
  than growing a fourth positional parameter.
- Classify the terminal sweep from an actually-aborted caller/construction
  signal instead of the error name: a provider or host rejection that merely
  borrows the AbortError name is an unexpected failure, and reporting it as
  `cancelled` corrupts abort forensics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vLhxCFMYkCaTsoFTiAjJ5

* fix: reserve step indexes synchronously and stamp closes at their source

- Register a dispatched step in contentData/contentIndexMap synchronously
  before awaiting the predecessor's closure. Parallel agent lanes both
  dispatching successors could otherwise push with the same index, letting
  contentIndexMap resolve one step id to the other lane's entry so later
  deltas and completions mutated the wrong agent's step. The predecessor's
  CLOSED event still precedes the successor's ON_RUN_STEP.
- Capture the model-end timestamp before host CHAT_MODEL_END handlers run
  and pass it into the message-step close, so a slow usage sink cannot
  inflate the step duration.
- Close manual compaction steps as failed rather than inferring cancellation
  from an error name; compaction has no caller abort signal to corroborate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vLhxCFMYkCaTsoFTiAjJ5

* fix: drop the restamp path and close summary steps that never complete

- Remove the completed->completed restamp. Its only two registration sites
  cannot reach a terminal step (dispatchRunStep registers at creation; the
  reuse path in tools/handlers requires an empty step, so no completion can
  reference it yet), so it guarded an unreachable race. Worse, if it had
  fired it would leave RunStep.completed_at disagreeing with the closed_at
  already delivered. First close now wins outright.
- Isolate the predecessor close in trackDispatchedRunStep: the successor is
  already registered in contentData, so a throwing predecessor handler would
  abort the caller before it published the successor's ON_RUN_STEP, leaving
  the sweep to emit a terminal event for a step that never started.
- Close the summary step as failed when summarization produces empty output.
  That branch returns without a completion, so the step previously stayed
  in_progress until the run-end sweep reported an inflated duration and a
  successful status for an explicitly failed summary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vLhxCFMYkCaTsoFTiAjJ5

* fix: stamp step lifecycle times at their true boundaries

- Run the terminal sweep before the callback teardown so callback-only
  subscribers still receive abort/failure/halt closures instead of being
  left with unmatched starts.
- Capture the stream's terminal time when it ends, throws, or halts, and
  pass it through the sweep, so Stop/StopFailure hooks and Langfuse
  disposal no longer inflate swept terminal stamps.
- Stamp created_at after the predecessor closure is delivered and just
  before the start event publishes, so a slow predecessor handler is not
  charged to the successor's duration.
- Track the latest producer completion time per step and close multi-call
  steps with it; parallel calls can settle out of producer order, so the
  call that drains the pending set is not necessarily the last to finish.
- Implement closeRunStep on the manual compaction adapter so an empty
  summary closes as failed there too, instead of no-opping into the
  success path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vLhxCFMYkCaTsoFTiAjJ5

---------

Co-authored-by: Claude <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators Aug 12, 2026
@pull pull Bot added the ⤵️ pull label Aug 12, 2026
@pull
pull Bot merged commit 9551546 into innFactory:main Aug 12, 2026
2 checks passed
@pull
pull Bot deployed to publish August 12, 2026 22:44 Active
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant