Skip to content

Replace stub text with compact turn pointers in message transform #68

Description

@durch

Goal

Reduce token waste from stubbed tool results. Currently each stubbed result costs ~18 tokens for text the LLM cannot act on. Replace with compact turn-scoped pointers (~3-5 tokens) and add a system prompt section teaching the LLM how to dereference them.

Context

The assembler's message transform (context/assembler/message-transform.ts) stubs tool results outside the hot window with:

[source: tool:read, tool:grep | Content replaced — available via re-execution]

This is ~18 tokens per stub. In a 300-turn session with ~400 stubbed tool results, that's ~7,200 tokens of dead weight — pointers the LLM cannot dereference.

The bridge already generates locator entries with structured metadata (tool name, file paths, retrieval recipe). The stub text ignores all of this except the tool name.

Current flow

  1. Bridge observes tool result, creates MemoryLocatorEntry with key, where, how
  2. Message transform stubs the result: content replaced with formatStubText(sourceTags)
  3. LLM sees dead text it can't use
  4. Original content still lives in agent.state.messages — fully recoverable

Proposed flow

  1. Bridge observes tool result, creates MemoryLocatorEntry (unchanged)
  2. Message transform stubs with compact pointer: [ref:t42:read:src/parser.ts] or similar
  3. System prompt teaches the LLM: "Stubbed results show as [ref:tN:tool:path]. To recover content, use the recall tool or re-execute the original tool."
  4. LLM can now make informed decisions about which stubs to recover

Acceptance Criteria

  • Stub text replaced with compact pointer format (target: 3-5 tokens per stub)
  • Pointer encodes: turn number, tool name, primary path/identifier
  • System prompt includes a section explaining stub pointers and how to recover content
  • formatStubText in message-transform.ts updated to accept locator metadata
  • Token savings measurable: compare before/after on a 200+ turn conversation
  • Hot window behavior unchanged (recent turns still kept verbatim)
  • Assembly summary updated to report pointer format

Technical Notes

Files to modify

  • packages/coding-agent/src/context/assembler/message-transform.tsformatStubText(), replaceToolResultContent()
  • packages/coding-agent/src/context/assembler/message-transform.tstransformMessages() needs access to bridge locator data to enrich stubs
  • System prompt template (likely prompts/system/ or assembled sections) — add stub pointer documentation
  • packages/coding-agent/src/context/bridge/bridge.ts — may need to expose locator lookup by tool_use_id

Pointer format options

Minimal: [t42] (~2 tokens) — turn number only, LLM infers tool from conversation structure
Compact: [t42:read:src/parser.ts] (~5 tokens) — turn + tool + primary path
Rich: [t42:read:src/parser.ts:L50-80] (~7 tokens) — includes line range

Recommendation: start with compact. The tool name and path give the LLM enough to decide whether to recover the content without looking at the full result.

Integration with bridge

The message transform currently operates independently of the bridge — it only knows about messages, not locator entries. To produce enriched stubs, the transform needs a lookup function: given a tool_use_id, return the locator entry's metadata. This could be:

  • A callback passed via MessageTransformOptions
  • Direct access to the bridge's locator map
  • Pre-computed metadata attached to the message during bridge observation

Edge cases

  • Tool results without locator entries (tools the bridge doesn't classify) — fall back to current stub format
  • Multiple tool results in a single turn — each gets its own pointer
  • System prompt token budget — the stub documentation section should be small (<100 tokens)

Trade-offs Accepted

  • Compact pointers lose the source provenance tags ("source: tool:read, tool:grep") — acceptable because the pointer encodes more useful info (turn + path)
  • Adds coupling between message transform and bridge locator data — acceptable because they're already part of the same assembler subsystem

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestoh-plannedCreated via oh-plan skill

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions