Skip to content

LLP 0265: the OpenClaw sweep reads the run trajectory for system_text and tools - #869

Draft
bgmcmullen wants to merge 1 commit into
masterfrom
llp-0265-openclaw-trajectory-enrichment
Draft

LLP 0265: the OpenClaw sweep reads the run trajectory for system_text and tools#869
bgmcmullen wants to merge 1 commit into
masterfrom
llp-0265-openclaw-trajectory-enrichment

Conversation

@bgmcmullen

Copy link
Copy Markdown
Contributor

OpenClaw rows were the thinnest in ai_gateway_messages. On the machine this was developed against: 73 rows, cwd on all of them, model on half, and system_text / tools null on every one. The session transcript records the conversation and nothing about the run that produced it; the run trajectory OpenClaw already writes beside every session does.

What changed

  • New reader openclaw/src/trajectory_file.js, the one reader of <sessionId>.trajectory.jsonl (resolved through OpenClaw's .trajectory-path.json pointer when present). It takes exactly two facts from context.compiled, the compiled system prompt and the tool definitions, and leaves the rest of the stream on disk.
  • Per-message stamping. AiGatewayProjectedMessage gains system_text and tools, and the row builder prefers them over the exchange-level pair, the precedence model (LLP 0026) and provider (LLP 0194) already had. An OpenClaw session recompiles per run: one observed session ran with 23, then 21, then 26 tools under three different system prompts, so an exchange-level value would present one turn's answer as every turn's. No live projector sets either field, so live rows are unchanged.
  • Run windows. A run's window opens at its context.compiled and closes at its session.ended; a message outside every window is stamped with nothing, because a run that failed before compiling (or one an embedded CLI harness owned) is not described by whatever the previous run compiled.
  • Recording time, not message time. OpenclawSessionMessage now surfaces recordedAtMs (the record line's timestamp) alongside timestampMs (the envelope's, still what message_created_at uses). A webchat prompt carries the moment the user sent it, seconds before its own run compiled.

The truncation problem

OpenClaw truncates a recorded system prompt at two caps and announces only one:

  • past 32768 characters (TRAJECTORY_RUNTIME_DATA_STRING_MAX_CHARS, hard-coded) the value is replaced by a { truncated: true, originalChars, limitChars } stub;
  • below that, a long prompt is still clipped to 20000 characters plus an ellipsis and written as an ordinary string, with no marker.

Truncation is therefore detected rather than assumed absent: the stub, a recorded string shorter than the chars the run's own trace.metadata reports, or the trailing ellipsis. Clipped text is kept (a 20000-char prefix is useful) and flagged; attributes.openclaw.system_prompt carries chars, hash, recorded_chars, and truncated.

Across the 33 verified runs, no real agent run recorded a complete system prompt (24 stubbed at 36k-41k, 9 clipped at exactly 20001 chars, 2 complete two-line probes). Complete prompt text still depends on the wire, so LLP 0175 remains the path to it.

Effect on real data (73 rows)

before after
tools 0 71
system_text, complete 0 1
system_text, clipped and flagged 0 20
digest only (prompt over 32k) 0 50

Enrichment applies from the next import onward: backfill dedupe skips rows already committed under the same part_id, the same boundary LLP 0194 accepted.

Docs

LLP 0265 is new. LLP 0171 gains an Extended-by and a narrowed non-goal: the trajectory-file half is lifted for these two columns only; the probe-session stream and the live tail stay out.

Testing

  • test/plugins/openclaw-trajectory.test.js (new, 12 cases): pointer resolution and its refusals, per-run contexts, both truncation caps, the report cross-check, window matching.
  • test/plugins/openclaw-backfill.test.js (+8 cases): end-to-end stamping through the real materializer, two runs in one session, the recording-time rule, both truncation states, untraced sessions, and the run's log counters.
  • npm run smoke -- backfill_openclaw_session_shape now stages a trajectory and asserts both columns through the query path. Its existing two-level timestamp disagreement doubles as the recording-time proof: the assistant envelope's 10:00:09 falls outside the run window, its record line's 10:00:02 falls inside.
  • npm test at the 28 pre-existing failures (unchanged), npm run typecheck at its 3 pre-existing errors, backfill_openclaw_fixture green.

🤖 Generated with Claude Code

… and tools

OpenClaw rows were the thinnest in ai_gateway_messages: system_text and
tools null on every one, because the session transcript records the
conversation and nothing about the run that produced it. The run
trajectory OpenClaw already writes beside every session does, so the
sweep now reads it.

A new one-reader module takes exactly two facts from context.compiled,
the compiled system prompt and the tool definitions, and the backfill
stamps them onto the messages of the run whose window covers them. The
match is on the session file's recording time, not the message's own
timestamp: a webchat prompt carries the moment the user sent it, which
can predate its own run's compile, so the reader now surfaces
recordedAtMs alongside timestampMs.

Stamping is per message, so AiGatewayProjectedMessage gains system_text
and tools and the row builder prefers them over the exchange pair, the
precedence model (LLP 0026) and provider (LLP 0194) already had. An
OpenClaw session recompiles per run: one observed session ran with 23,
then 21, then 26 tools under three different prompts.

OpenClaw truncates a recorded prompt at two caps and announces only one:
past 32768 characters the value is replaced by a stub, and below that a
long prompt is clipped to 20000 characters plus an ellipsis and written
as an ordinary string. Truncation is therefore detected (stub, a
recorded string shorter than the run's own reported size, or the
trailing ellipsis) rather than assumed absent, and
attributes.openclaw.system_prompt carries chars, hash, recorded_chars,
and truncated. On the corpus this was verified against, no real agent
run recorded a complete system prompt, so complete prompt text still
depends on the live lane and LLP 0175.

LLP 0171's trajectory-file non-goal is lifted for these two columns
only; the probe-session stream and live tail stay out.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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