feat(persona,LaneD): response_prompt() lazy output on PersonaTurnFrame#1400
Merged
Conversation
Lane D: adds the chat-style prompt lazy output the inference engine
consumes. Closes the chain from inbox event → turn frame → ready-to-
infer prompt, fully in Rust.
What lands
- ResponsePrompt struct: persona_id, room_id, system_prompt
(Option<String>; caller fills from IdentityState), messages
(Vec<PromptMessage>), trigger_message_id
- PromptRole enum: System / User / Assistant — chat-completion
taxonomy
- PromptMessage { role, content } — one turn in the prompt
- PersonaTurnFrame::response_prompt() — fourth lazy output
alongside consolidated_inbox + rag_seed + replay_record
Design
- Every inbox message becomes a User-role PromptMessage in
chronological order. The persona's identity (System role) is
filled in by the caller from IdentityState (not loaded into
the turn frame today; future PR may add lazily).
- Per Joel's "Rust owns behavior" + "no TS shimming Rust outputs":
the substrate owns the prompt-build path so TS PRG doesn't
wrap a raw transcript into a model-specific prompt format.
- Wire shape: camelCase fields (systemPrompt, triggerMessageId)
+ lowercase role enum (system/user/assistant). Matches the
de-facto chat-completion JSON.
- Returns None for empty frames (same contract as
consolidated_inbox + rag_seed — empty inbox = no turn to plan).
This is the lazy output PR-4 inference-llm's
InferenceRequest.prompt_text expects. A follow-up PR will add the
turn-execute command that chains drain-turn-frame → response_prompt
→ inference/llm/request, making one Rust call execute the full
persona turn end-to-end.
Tests
5 new tests:
- response_prompt_returns_none_for_empty_frame
- response_prompt_carries_one_user_message_per_inbox_message
- response_prompt_system_prompt_is_none_pr1 (pins the IdentityState
separation; flips when auto-load lands)
- response_prompt_trigger_matches_latest_message_id
- response_prompt_round_trips_through_serde (wire stability)
9/9 persona::turn_frame tests pass (5 new + 4 existing). No
regressions across other 2973 lib tests.
Stack
- Lane D PR-1/2/3 skeleton + drain_frame + rag_seed: already
shipped
- Lane D drain-turn-frame command (#1398, mine just merged)
- THIS PR — ResponsePrompt lazy output (the inference-input
lazy node the spec named)
- NEXT — turn-execute command that chains drain → response_prompt
→ inference/llm/request
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lane D advancement. Adds the chat-style prompt lazy output the inference engine consumes. Closes the chain from inbox event → turn frame → ready-to-infer prompt, fully in Rust.
Pure Rust, zero TS.
What lands
ResponsePromptstruct:persona_id,room_id,system_prompt(Option; caller fills from IdentityState),messages(Vec),trigger_message_idPromptRoleenum:System/User/Assistant— chat-completion taxonomyPromptMessage { role, content }— one turn in the promptPersonaTurnFrame::response_prompt()— fourth lazy output alongsideconsolidated_inbox+rag_seed+replay_recordDesign
User-rolePromptMessagein chronological order. The persona's identity (System role) is filled in by the caller fromIdentityState(not loaded into the turn frame today; future PR may add lazily).systemPrompt,triggerMessageId) + lowercase role enum (system/user/assistant) — matches the de-facto chat-completion JSON.Nonefor empty frames (same contract asconsolidated_inbox+rag_seed— empty inbox = no turn to plan).This is the lazy output that PR-4 inference-llm's (#1395)
InferenceRequest.prompt_textexpects. A follow-up PR will add theturn-executecommand chainingdrain-turn-frame→response_prompt→inference/llm/requestfor the full persona-turn-in-one-Rust-call.Test plan
cargo test --lib --features metal,accelerate persona::turn_frame— 9/9 pass (5 new + 4 existing):response_prompt_returns_none_for_empty_frameresponse_prompt_carries_one_user_message_per_inbox_messageresponse_prompt_system_prompt_is_none_pr1(pins the IdentityState separation)response_prompt_trigger_matches_latest_message_idresponse_prompt_round_trips_through_serde(wire stability)Stack
🤖 Generated with Claude Code