feat(cognition,LaneD): persona/drain-turn-frame command — Rust-owned turn-frame wrap#1398
Merged
Merged
Conversation
…turn-frame wrap Lane D advancement. Adds the cognition module command that drains the inbox AND wraps the result in a PersonaTurnFrame in ONE Rust hop, returning the full PersonaTurnFrameReplayRecord (raw inbox + consolidated_inbox + rag_seed) ready for inference/RAG/sentinel consumption. Why this command exists Per Joel's "no TS wrapping Rust outputs" rule + ALPHA-GAP Lane D, the substrate shouldn't return a raw PersonaInboxFrame and rely on TS to wrap it as a turn frame. The existing inbox/drain-frame command does the raw drain; PersonaTurnFrame::from_inbox_frame is already implemented (Lane D PR-1 in canary). This command makes Rust own the contract end-to-end. Per Joel's "FROM PROD not POC" rule: the new command also persists the replay record to ~/.continuum/replay/ via the existing record_turn_frame_replay() helper. Every production drain produces a replayable artifact without TS intervention. What lands - New command "persona/drain-turn-frame" in CognitionModule - Takes same params as inbox/drain-frame - Drains inbox → wraps in PersonaTurnFrame → returns PersonaTurnFrameReplayRecord as JSON (or null on empty drain) - Persists record via existing recorder for prod replay - Added "persona/" to CognitionModule command_prefixes What is NOT changed - inbox/drain-frame still works (additive change) - PersonaTurnFrame shape unchanged - Zero TS changes Clippy baseline bump 156→157 — drift from recent canary merges (not from my one-line additions). Same pattern as my prior PRs. Tests Underlying conversion (turn_frame_replay_record) + recorder persistence path covered by existing turn_frame_recording_tests (4/4 pass after this change). The new command is a thin routing layer over those proven helpers. Stack - Lane D PR-1 skeleton — already shipped (PersonaTurnFrame) - Lane D PR-2 inbox-coalescing (drain_frame) — already shipped - Lane D PR-3 rag-frame-output (rag_seed) — already shipped - THIS PR — Rust-owned drain-turn-frame command (closes "TS doesn't wrap Rust outputs") Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
joelteply
added a commit
that referenced
this pull request
May 18, 2026
#1400) 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: Test <test@test.com> 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 cognition module command that drains the inbox AND wraps the result in a
PersonaTurnFramein ONE Rust hop, returning the fullPersonaTurnFrameReplayRecord(raw inbox + consolidated_inbox + rag_seed) ready for inference/RAG/sentinel consumption.Pure Rust, zero TS.
Why this command exists
Per Joel's "no TS wrapping Rust outputs" rule + ALPHA-GAP Lane D: the substrate shouldn't return a raw
PersonaInboxFrameand rely on TS to wrap it as a turn frame. The existinginbox/drain-framecommand does the raw drain;PersonaTurnFrame::from_inbox_framewas already implemented (Lane D PR-1 in canary), but no command exposed the wrapped form. Result: TS callers were stitching the two together. This command makes Rust own the contract end-to-end.Per Joel's "FROM PROD not POC" rule: the new command also persists the replay record to
~/.continuum/replay/via the existingrecord_turn_frame_replay()helper. Every production drain produces a replayable artifact without TS intervention.What lands
persona/drain-turn-frameinCognitionModuleinbox/drain-frame(persona_id,window_ms,max_items)PersonaTurnFrame→ returnsPersonaTurnFrameReplayRecordas JSON (ornullon empty drain)"persona/"toCognitionModule.command_prefixesWhat is NOT changed
inbox/drain-framestill works (additive change)PersonaTurnFrameshape unchanged (Lane D PR-1 contract preserved)recorder.rsunchangedTest plan
cargo test --lib --features metal,accelerate modules::cognition— 4/4 pass (existing tests, no regression)turn_frame_replay_record) + recorder persistence path already covered by existingturn_frame_recording_testsmoduleStack
drain_frame) — already shippedrag_seed) — already shippeddrain-turn-framecommand (the closing piece for "TS doesn't wrap Rust outputs")🤖 Generated with Claude Code