Skip to content

fix(gateway): add parentId to non-agent-run transcript messages#11033

Closed
openperf wants to merge 1 commit intoopenclaw:mainfrom
openperf:fix-status-command-transcript-tree
Closed

fix(gateway): add parentId to non-agent-run transcript messages#11033
openperf wants to merge 1 commit intoopenclaw:mainfrom
openperf:fix-status-command-transcript-tree

Conversation

@openperf
Copy link
Copy Markdown
Contributor

@openperf openperf commented Feb 7, 2026

Summary

This fixes an issue where commands that don't trigger an agent run (like /status) would append a reply to the transcript without a parentId. This created an orphaned root node in the transcript tree, causing subsequent messages to lose the conversation history.

This addresses the same category of transcript tree breakage described in #10821. A related but separate issue (missing parentId after gateway restart) is tracked in #10018 / PR #10060.

Fixes #10821

Repro Steps

  1. Start a chat session.
  2. Send a message (e.g., "hello").
  3. Send a command that doesn't trigger an agent run (e.g., /status).
  4. Send another message (e.g., "world").
  5. Observe that the agent's response to "world" does not have the context of "hello" or the /status command.

Root Cause

The appendAssistantTranscriptMessage function in src/gateway/server-methods/chat.ts was called for non-agent-run replies. This function created a new transcript entry with a new messageId but without a parentId, effectively starting a new branch in the transcript tree.

The original issue suggested two possible fixes: either not writing these replies to the transcript, or adding a parentId. We chose to add the parentId because it is a more localized and safer change that preserves the metadata of the command reply in the transcript, which could be useful for debugging, without altering the broader logic of what gets written to the transcript.

Behavior Changes

  • A new helper function readTranscriptLeafId has been added to chat.ts to read the last message ID from a transcript file.
  • appendAssistantTranscriptMessage now uses this helper to get the parentId of the last message and includes it in the new transcript entry.
  • This ensures that replies from commands like /status are correctly appended to the existing conversation branch, preserving context.

Codebase and GitHub Search

  • Searched for appendAssistantTranscriptMessage to identify call sites.
  • Confirmed this function is used for replies that don't start an agent run.
  • Verified that no other logic was appending transcript messages without a parentId in a similar context.

Tests

  • Added a new test file src/gateway/server-methods/chat.append-transcript-parentId.test.ts.
  • This file includes unit tests for the new readTranscriptLeafId helper function, covering cases like non-existent files, empty files, and files with various entry types.
  • All new tests pass.
  • Existing related tests were run to ensure no regressions were introduced.

Validation

npx vitest run src/gateway/server-methods/chat.append-transcript-parentId.test.ts

npx vitest run src/gateway/chat-sanitize.test.ts src/gateway/chat-attachments.test.ts

npx tsc --noEmit

Greptile Overview

Greptile Summary

  • Adds readTranscriptLeafId() to find the last message id in a session transcript JSONL.
  • Updates appendAssistantTranscriptMessage() so non-agent-run command replies are appended with a parentId instead of creating a new root.
  • Adds a new unit test file intended to cover leaf-id reading behavior.
  • Overall aim is to prevent transcript tree breakage / lost context after commands like /status.

Confidence Score: 2/5

  • This PR reduces one transcript-orphan path but still leaves another reachable code path that can create orphaned transcript roots.
  • Main fix in appendAssistantTranscriptMessage looks correct, but chat.inject still appends transcript messages without parentId, reintroducing the same class of breakage. Additionally, the new test reimplements the helper rather than asserting behavior of the production code, so it won’t reliably prevent regressions.
  • src/gateway/server-methods/chat.ts, src/gateway/server-methods/chat.append-transcript-parentId.test.ts

Context used:

  • Context from dashboard - CLAUDE.md (source)
  • Context from dashboard - AGENTS.md (source)

@openclaw-barnacle openclaw-barnacle bot added app: web-ui App: web-ui gateway Gateway runtime labels Feb 7, 2026
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 7, 2026

Additional Comments (1)

src/gateway/server-methods/chat.ts
Still writes orphan

chat.inject still appends a type: "message" transcript entry without a parentId, which recreates the same transcript-tree breakage described in this PR (any inject that isn’t part of an agent run will start a new root). This should use the same readTranscriptLeafId()/parentId logic as appendAssistantTranscriptMessage (or call that helper) so injected messages remain on the existing branch.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/gateway/server-methods/chat.ts
Line: 639:641

Comment:
**Still writes orphan**

`chat.inject` still appends a `type: "message"` transcript entry without a `parentId`, which recreates the same transcript-tree breakage described in this PR (any inject that isn’t part of an agent run will start a new root). This should use the same `readTranscriptLeafId()`/parentId logic as `appendAssistantTranscriptMessage` (or call that helper) so injected messages remain on the existing branch.

How can I resolve this? If you propose a fix, please make it concise.

@openperf
Copy link
Copy Markdown
Contributor Author

openperf commented Feb 7, 2026

Hi! This PR is ready for review.

@leszekszpunar
Copy link
Copy Markdown
Contributor

Heads up: the lint failure (preserve-caught-error in extensions/memory-lancedb/index.ts) is a pre-existing issue on main, not caused by your changes. The fix is in #11061. Once it lands, rebase on main and re-push to get a clean CI run.

git fetch origin main && git rebase origin/main && git push --force-with-lease

@leszekszpunar
Copy link
Copy Markdown
Contributor

Update: the lint failure has been resolved by #11093 (merged), which excluded extensions/ from oxlint scope. A rebase on main should give you a clean CI run.

git fetch origin main && git rebase origin/main && git push --force-with-lease

@openperf openperf force-pushed the fix-status-command-transcript-tree branch from 0317e98 to 2179c9f Compare February 14, 2026 14:23
@openperf
Copy link
Copy Markdown
Contributor Author

Closing this PR — the underlying bug has been fixed in #12283, which introduced SessionManager.appendMessage() to automatically maintain the parentId chain. My manual readTranscriptLeafId approach is no longer needed.

@openperf openperf closed this Feb 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui gateway Gateway runtime size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: /status reply breaks transcript tree structure, causing apparent context loss

2 participants