Skip to content

RLM v1 (draft — base API decision needed)#86

Draft
darinkishore wants to merge 44 commits into
mainfrom
feature/rlm-v1
Draft

RLM v1 (draft — base API decision needed)#86
darinkishore wants to merge 44 commits into
mainfrom
feature/rlm-v1

Conversation

@darinkishore
Copy link
Copy Markdown
Collaborator

Draft PR for the RLM v1 stack. Not ready to land yet — there's an unresolved base-API decision documented below.

Summary

  • 44 commits implementing the RLM (Reasoning Language Module) architecture: PyO3 runtime, perception loop, REPL/passthrough adapters, Phase 1–5 work, and downstream tightening (schema dedup, sub-LM batching, prompt redesign, etc.).
  • Branch tip: nqzvplvs 94685374 "RLM schema rendering overhaul: type dedup, nested methods, clean unions".

⚠️ Base-API ambiguity (blocker)

The branch is built on top of an orphaned multi-turn-predict refactor that never made it to main, and main has since taken a different shape. Specifically:

Surface This branch's base (ynqyxtnl) Main (3c850e60 + 5bb65ca5)
Forward signature forward(input, history: Option<Chat>) -> Predicted forward(input) -> Predicted
Continue conversation Same forward with Some(history) Separate forward_continue(chat) -> (Predicted, Chat)
Internal split compose_chat + execute_chat (private) build_chat + call_and_parse (public)
LM call signature lm.call(chat, tools, ToolLoopMode::Auto) lm.call(chat, tools) (no ToolLoopMode)
Per-instance LM override not present Predict.lm: Option<Arc<LM>> + .lm() builder

How it ended up like this

  1. 2026-02-19 — initial multi-turn-predict commits (zqytoppy, kqyktwmv) with the split API (forward(input) + forward_continue(chat)) + ToolLoopMode::CallerManaged.
  2. 2026-02-21 23:08 — local refactor 1e9d503a "collapse call API" (= ynqyxtnl on this branch): collapses split API back to unified forward(input, history), switches to ToolLoopMode::Auto, uses Role enum.
  3. 2026-02-22 00:21:20 — PR squash-merged to main as 3c850e60 containing only the first two commits. The "collapse call API" refactor was not included.
  4. 2026-02-22 00:21:27 — 7 seconds after the squash-merge, the local multi-turn-predict branch got the orphaned refactor as 659c3938 ynqyxtnl. RLM v1 was then built on top.
  5. 2026-04-08 — main got 5bb65ca5 feat(predict): add per-instance LM override on top of the older split API.

So the local stack uses the newer/collapsed API; main uses the older/split API plus an LM-override addition.

Two paths forward

(A) Keep main's split API. Port the RLM stack to use forward(input) + forward_continue(chat) + drop ToolLoopMode::Auto for the equivalent main-side construct. The ynqyxtnl "collapse call API" refactor is effectively discarded.

(B) Restore the unified API. Land ynqyxtnl (the orphaned refactor) into main first as its own PR, re-apply 5bb65ca5 (per-instance LM override) on top, then rebase RLM. Preserves the local API design.

Both involve a non-trivial API migration in the rebase; the "update with main" delta itself is only one small commit (5bb65ca5, 143 lines).

Test plan

  • Decide A vs B
  • Resolve the API mismatch (port RLM call sites or re-land the orphaned refactor)
  • Rebase onto current main
  • Full cargo test across dspy-rs + RLM-derive + integration suites
  • Re-verify RLM live demos (OpenAI Responses, Anthropic prompt caching) still pass

darin and others added 30 commits February 19, 2026 18:46
- Refactor Message from flat enum to Role + Vec<ContentBlock>

- Reasoning continuity preserved through rig round-trips

- From<RigMessage> trivial (no data loss), RigChatMessage removed

- Predict API split: forward(input) + forward_continue(chat)

- ToolLoopMode::CallerManaged for caller-controlled tool loops

- Full conversation history in LMResponse.chat

- temp_env replaces unsafe set_var in all tests

- 14 new tests: round-trip, CallerManaged conversation, reasoning preservation
Two trybuild tests (render_invalid_jinja, render_non_literal) failed on CI
because syn::Error::new(span, msg) with .span() produces different underline
widths on stable (CI) vs nightly (local). Switch to
syn::Error::new_spanned(tokens, msg) which reliably spans from first to last
token regardless of compiler version.
…, collapse call API

* refactor: unify Predict history API and chat contracts

- collapse Predict to forward(input, history) with call() wrapper
- preserve full provider content in CallerManaged LMResponse.output
- remove inaccurate lossless conversion claim
- remove legacy Chat JSON parsing; enforce canonical grouped format
- update conversation and chat roundtrip tests

* refactor: harden LM transcript fidelity, unify Predicted return shape, collapse call API
… perception-based user messages, custom repr support
- Type dedup: persistent visited set, types expand once then reference by name
- Nested method visibility: collect methods by type (schema-driven resolution),
  render on all class blocks, not just top-level vars
- Data enum de-wrapper: single-payload variants render as direct payload types
  instead of Entry_X { type, data } wrappers
- Doc comment normalization: multi-line docs collapse to single line
- Union indentation fix: preserve nested indentation in continuation lines
- Docstring gating removed: methods without docs still appear in schema
- Defensive synthetic variant guard: prevent method contamination on
  BAML-generated variant classes

Schema output: 409 → 222 lines (46% reduction), 0 → 11 nested methods visible.
All changes are general infrastructure — any program using the RLM benefits.
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