Skip to content

Collect no LangChain run whose conversation cannot be told - #70

Merged
wu-sheng merged 1 commit into
mainfrom
langsmith-lost-records
Oct 16, 2026
Merged

wu-sheng merged 1 commit into
mainfrom
langsmith-lost-records

Conversation

@wu-sheng

Copy link
Copy Markdown
Member

A LangChain run's conversation can depend on something the receiver no longer has. An update that names no conversation of its own is completed from its run's start. A run that names no thread takes the conversation of a run above it. The receiver remembers both for a day, and at most 50,000 runs. When what would say the conversation was forgotten, or never came, the run landed under a name saying its identity was not supplied. That put one conversation's evidence in another.

What changes

  • Such a run waits, then is not collected. It waits as a run waits for its ancestry, sharing the same counter of three passes. Once its request has waited as long as it may, these are dropped:
    • an update with no complete identity whose start was not seen;
    • a run whose own thread is not whole yet, with the rest of its key still to come;
    • a run that names no thread under a run above it that is not known: one that never came, was forgotten, or is known only from updates that named no conversation of their own.
  • The receiver's memory records whether a run's start was seen. An update no longer proves a start, even with a start time.
  • A dropped run leaves no conversation behind. Its start, if it comes later, decides for itself instead of taking the dropped run's fallback.
  • Inheritance stops at the first run above that does not decide, and a farther run's thread is never taken past it.
  • What still lands as today:
    • An update that carries its conversation's whole key lands with no start seen. All 11 captured updates from the Python client carry the project and the thread.
    • A trace whose runs are all known and name no thread lands unassigned.
    • A run whose conversation is known lands with whatever ancestry arrived.
  • A complete identity is checked against every configured dimension. On an update, a metadata key in scope that is missing makes the identity incomplete. A start carries its whole metadata, so a key it leaves out is supplied empty.
  • The memory moves to version 2, so what it held is forgotten once.
  • The pass line says runs_not_collected=N for each pass that drops an arrival.

Tests

  • Four existing inheritance tests change to the dropped outcome. They now assert the exact drop count and an empty inbox. The partial-identity test gains a case with no run below the call, so the partial guard alone holds the call back.
  • lost_test.go covers:
    • a start forgotten by age and by count;
    • a run kept alive past a day by its updates;
    • a complete update with no start, alone and beside other runs;
    • an update before its start in one request, and in an earlier request;
    • a later start naming another conversation, with and without a restart;
    • a run under an ancestor known only from a dropped update;
    • an unassigned run whose root is forgotten later;
    • the scope dimensions, a start time that is not a start, a partial start, and a version-1 memory.
  • cmd/asz asserts the pass line for a pass that only drops.

Each new guard was proven by reverting it. make test, the JSON v1 step (GOEXPERIMENT=nojsonv2), make scenarios, lint and the Windows build pass.

A run's conversation can depend on something the receiver no longer
has. An update that names no conversation of its own is completed from
its run's start, and a run that names no thread takes the conversation
of a run above it. The receiver remembers both for a day, and at most
50,000 runs. When what would say the conversation was forgotten, or
never came, the run landed under a name saying its identity was not
supplied. That put one conversation's evidence in another.

Such a run now waits, as a run waits for its ancestry, and is not
collected once its request has waited as long as it may:

- an update with no complete identity whose start was not seen;
- a run whose own thread is not whole yet, with the rest of its key
  still to come;
- a run that names no thread under a run above it that is not known,
  one that never came, was forgotten, or is known only from updates
  that named no conversation of their own.

The receiver's memory records whether a run's start was seen, so an
update no longer proves one, and a dropped run leaves no conversation
behind for its start to take later. Inheritance stops at the first run
above that does not decide. An update that carries its conversation's
whole key still lands with no start seen, as every captured update
from the Python client does. A trace whose runs are all known and name
no thread still lands unassigned. A run whose conversation is known
still lands with whatever ancestry arrived.

The memory moves to version 2, so what it held is forgotten once. Each
pass that drops an arrival says how many, as runs_not_collected.
@wu-sheng wu-sheng added this to the 0.6.0 milestone Oct 16, 2026
@wu-sheng
wu-sheng merged commit 01539f4 into main Oct 16, 2026
24 checks passed
@wu-sheng
wu-sheng deleted the langsmith-lost-records branch October 16, 2026 23:37
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.

1 participant