You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by wy...@apache.org on 2026/09/23 13:07:10 UTC

(maka) branch feat/runtime-host-rust updated: feat(tui): preserve complete pending message inputs

This is an automated email from the ASF dual-hosted git repository.

M4n5ter pushed a commit to branch feat/runtime-host-rust
in repository https://gitbox.apache.org/repos/asf/maka.git


The following commit(s) were added to refs/heads/feat/runtime-host-rust by this push:
     new 0bc19fb2d8 feat(tui): preserve complete pending message inputs
0bc19fb2d8 is described below

commit 0bc19fb2d8606ffda4879cda11bf7c10d0768945
Author: M4n5ter <m4...@gmail.com>
AuthorDate: Wed Sep 23 21:06:44 2026 +0800

    feat(tui): preserve complete pending message inputs
    
    Persist native content, references and input intent through checkpoint and explicit retry. Migrate text-only checkpoints without changing request identity, and reject mismatched completion payloads.
    
    Generated-by: Codex
---
 crates/cli/tests/integration/tui/reading.rs  |   2 +-
 crates/cli/tests/integration/tui/recovery.rs |  25 ++++-
 crates/tui/locales/en.ftl                    |   2 +-
 crates/tui/locales/zh-CN.ftl                 |   2 +-
 crates/tui/locales/zh-TW.ftl                 |   2 +-
 crates/tui/src/pages/sending.rs              |  43 ++++-----
 crates/tui/src/state.rs                      |   1 +
 crates/tui/src/state/snapshot.rs             | 136 +++++++++++++++++++++++++--
 crates/tui/src/state/submission.rs           |  68 ++++++++++++++
 9 files changed, 243 insertions(+), 38 deletions(-)

diff --git a/crates/cli/tests/integration/tui/reading.rs b/crates/cli/tests/integration/tui/reading.rs
index 8516afc8ed..1ab4ad3ee7 100644
--- a/crates/cli/tests/integration/tui/reading.rs
+++ b/crates/cli/tests/integration/tui/reading.rs
@@ -151,7 +151,7 @@ fn old_window_selection_and_search_resume_across_pages_and_disk_restart() {
         .unwrap(),
     )
     .unwrap();
-    assert_eq!(saved["version"], 6);
+    assert_eq!(saved["version"], 7);
     let encoded = serde_json::to_string(&saved).unwrap();
     assert!(
         !encoded.contains("History context line"),
diff --git a/crates/cli/tests/integration/tui/recovery.rs b/crates/cli/tests/integration/tui/recovery.rs
index 7ae7f3a12d..2cc5a22c82 100644
--- a/crates/cli/tests/integration/tui/recovery.rs
+++ b/crates/cli/tests/integration/tui/recovery.rs
@@ -76,9 +76,9 @@ fn recover(after_acceptance: bool) {
             tui.wait_for("storage offline edit");
             std::fs::remove_dir(&checkpoint).unwrap();
             tui.send(b"\x10");
-            tui.wait_for("Retry original message (same ID and text)");
+            tui.wait_for("Retry original message");
             assert!(proxy.requests.lock().unwrap().is_empty(), "storage recovery must not automatically resend");
-            tui.click_text("Retry original message (same ID and text)");
+            tui.click_text("Retry original message");
         }
         tui.wait_for("Delivery uncertain");
         tui.wait_for("connection failed"); // The request failure can precede the connection-close observation.
@@ -99,6 +99,18 @@ fn recover(after_acceptance: bool) {
             // SIGKILL cannot run the normal quit flush; only the prior checkpoint survives.
             tui.child.kill().unwrap();
             assert!(!tui.child.wait().unwrap().success());
+            // Reopen an actual v6 text-only checkpoint, not a synthetic Host
+            // response. The migration must retain the same unknown identity.
+            let mut legacy: serde_json::Value = serde_json::from_slice(&std::fs::read(&checkpoint).unwrap()).unwrap();
+            legacy["version"] = json!(6);
+            for request in legacy["unresolved"].as_array_mut().unwrap() {
+                let fields = request.as_object_mut().unwrap();
+                let content = fields.remove("content").unwrap();
+                fields.insert("text".into(), content["text"].clone());
+                fields.remove("input_selections");
+                fields.remove("turn_orchestration");
+            }
+            std::fs::write(&checkpoint, serde_json::to_vec(&legacy).unwrap()).unwrap();
         }
         let mut tui = Pty::spawn(&["--root", host.root.to_str().unwrap()]);
         tui.wait_for(if after_acceptance { "Delivered once." } else { "No messages yet." });
@@ -106,10 +118,10 @@ fn recover(after_acceptance: bool) {
         tui.wait_for("Delivery uncertain");
         assert_eq!(proxy.requests.lock().unwrap().len(), 1, "reopening must not automatically replay");
         tui.send(b"\x10");
-        tui.wait_for("Retry original message (same ID and text)");
+        tui.wait_for("Retry original message");
         // wait_for already waits for a complete synchronized frame. An unrelated
         // last command may be below the viewport when a live turn adds actions.
-        tui.click_text("Retry original message (same ID and text)");
+        tui.click_text("Retry original message");
         // Closing the palette can temporarily cover/erase the old feedback before
         // the checkpoint releases the explicit retry. Observe the real relay too.
         tui.wait_until(|screen| proxy.requests.lock().unwrap().len() == 2 && !screen.contains("Delivery uncertain") && !screen.contains("Sending…") && !screen.contains("Commands · Esc") && screen.contains("plus new edits"));
@@ -248,8 +260,11 @@ impl LostReply {
                                 assert_eq!(original["origin_epoch"], value["input"]["originHostEpoch"]);
                                 assert_eq!(original["session"], value["input"]["sessionId"]);
                                 assert_eq!(original["id"], value["input"]["messageId"]);
-                                assert_eq!(original["text"], value["input"]["content"]["text"]);
+                                assert_eq!(saved["version"], 7);
+                                assert_eq!(original["content"], value["input"]["content"]);
                                 assert_eq!(original["placement"], value["input"]["placement"]);
+                                assert_eq!(original["input_selections"], value["input"].get("inputSelections").cloned().unwrap_or_else(|| json!({})));
+                                assert_eq!(original["turn_orchestration"], value["input"]["turnOrchestration"]);
                                 captured.lock().unwrap().push(value["input"].clone());
                                 if lose && !after_acceptance {
                                     lose = false;
diff --git a/crates/tui/locales/en.ftl b/crates/tui/locales/en.ftl
index 874102a104..78d8c8ab5b 100644
--- a/crates/tui/locales/en.ftl
+++ b/crates/tui/locales/en.ftl
@@ -248,7 +248,7 @@ chat-stop-failed = Could not stop · { $error }
 chat-send-failed = Not accepted · Draft kept · { $error }
 chat-send-unknown = Outcome unknown · Ctrl+R to check · { $id } · { $error }
 chat-reconcile = Check delivery without resending · Ctrl+R
-chat-retry-original = Retry original message (same ID and text)
+chat-retry-original = Retry original message
 chat-send-unknown-retry = Outcome unknown · Ctrl+R checks without resending. Commands can retry the original message, not your newer edits. { $id } · { $error }
 chat-checking = Checking delivery…
 chat-send-unconfirmed = Not yet confirmed · Draft kept; Ctrl+R to check again · { $id }
diff --git a/crates/tui/locales/zh-CN.ftl b/crates/tui/locales/zh-CN.ftl
index 6b987aa862..9b005a05cb 100644
--- a/crates/tui/locales/zh-CN.ftl
+++ b/crates/tui/locales/zh-CN.ftl
@@ -248,7 +248,7 @@ chat-stop-failed = 未能中止 · { $error }
 chat-send-failed = 未被接收 · 草稿已保留 · { $error }
 chat-send-unknown = 结果未知 · Ctrl+R 核对 · { $id } · { $error }
 chat-reconcile = 核对发送结果,不重发 · Ctrl+R
-chat-retry-original = 重试原消息(原 ID 和内容)
+chat-retry-original = 重试原消息
 chat-send-unknown-retry = 结果未知 · Ctrl+R 只核对;可从命令面板重试原消息,不会发送之后的新编辑。{ $id } · { $error }
 chat-checking = 正在核对发送结果…
 chat-send-unconfirmed = 尚未确认 · 草稿已保留;Ctrl+R 再次核对 · { $id }
diff --git a/crates/tui/locales/zh-TW.ftl b/crates/tui/locales/zh-TW.ftl
index 95e98aa249..521289477d 100644
--- a/crates/tui/locales/zh-TW.ftl
+++ b/crates/tui/locales/zh-TW.ftl
@@ -248,7 +248,7 @@ chat-stop-failed = 未能中止 · { $error }
 chat-send-failed = 未被接受 · 草稿已保留 · { $error }
 chat-send-unknown = 結果未知 · Ctrl+R 核對 · { $id } · { $error }
 chat-reconcile = 核對傳送結果,不重送 · Ctrl+R
-chat-retry-original = 重試原訊息(原 ID 與內容)
+chat-retry-original = 重試原訊息
 chat-send-unknown-retry = 結果未知 · Ctrl+R 僅核對;可從命令面板重試原訊息,不會傳送之後的新編輯。{ $id } · { $error }
 chat-checking = 正在核對傳送結果…
 chat-send-unconfirmed = 尚未確認 · 草稿已保留;Ctrl+R 再次核對 · { $id }
diff --git a/crates/tui/src/pages/sending.rs b/crates/tui/src/pages/sending.rs
index 61d9a5f2ea..1207023220 100644
--- a/crates/tui/src/pages/sending.rs
+++ b/crates/tui/src/pages/sending.rs
@@ -23,18 +23,20 @@ use maka_client::{ClientError, RequestFailure};
 use maka_protocol::{
     OperationErrorCode,
     message::{ExecutionResolution, Placement, SubmitInput, SubmitResult},
-    turn::MessageContent,
+    turn::{MessageContent, TurnOrchestration},
 };
 
-#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
+#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
 #[serde(deny_unknown_fields)]
 pub struct Submission {
     pub root_id: String,
     pub origin_epoch: String,
     pub session: String,
     pub id: String,
-    pub text: String,
+    pub content: MessageContent,
     pub placement: Placement,
+    pub input_selections: std::collections::BTreeMap<String, Vec<String>>,
+    pub turn_orchestration: Option<TurnOrchestration>,
 }
 pub enum Delivery {
     Pending,
@@ -64,17 +66,10 @@ impl Submission {
             origin_host_epoch: self.origin_epoch.clone(),
             session_id: self.session.clone(),
             message_id: self.id.clone(),
-            content: MessageContent {
-                text: self.text.clone(),
-                display_text: None,
-                attachments: None,
-                directory_references: None,
-                quotes: None,
-                inline_references: None,
-            },
+            content: self.content.clone(),
             placement: self.placement,
-            input_selections: Default::default(),
-            turn_orchestration: None,
+            input_selections: self.input_selections.clone(),
+            turn_orchestration: self.turn_orchestration.clone(),
         }
     }
 }
@@ -143,8 +138,17 @@ impl App {
             origin_epoch: epoch.clone(),
             session: session.clone(),
             id: uuid::Uuid::new_v4().to_string(),
-            text,
+            content: MessageContent {
+                text,
+                display_text: None,
+                attachments: None,
+                directory_references: None,
+                quotes: None,
+                inline_references: None,
+            },
             placement,
+            input_selections: Default::default(),
+            turn_orchestration: None,
         };
         self.sending.insert(
             session,
@@ -167,7 +171,7 @@ impl App {
         let Some(sent) = self.sending.get_mut(&request.session) else {
             return;
         };
-        if sent.request.id != request.id || sent.request.root_id != request.root_id {
+        if sent.request != request {
             return;
         }
         let retrying = matches!(sent.delivery, Delivery::Retrying);
@@ -181,7 +185,7 @@ impl App {
             Ok(SubmitResult::Blocked { message, .. }) => Delivery::Failed(message),
             Ok(_) => {
                 if let Some(editor) = self.drafts.get_mut(&request.session) {
-                    editor.clear_if_unchanged(&request.text);
+                    editor.clear_if_unchanged(&request.content.text);
                 }
                 Delivery::Accepted
             }
@@ -227,16 +231,13 @@ impl App {
         let Some(sent) = self.sending.get_mut(&request.session) else {
             return;
         };
-        if sent.request.id != request.id
-            || sent.request.root_id != request.root_id
-            || !matches!(sent.delivery, Delivery::Checking)
-        {
+        if sent.request != request || !matches!(sent.delivery, Delivery::Checking) {
             return;
         }
         sent.delivery = match result {
             Ok(Some(ExecutionResolution::Pending { .. } | ExecutionResolution::Owned { .. })) => {
                 if let Some(editor) = self.drafts.get_mut(&request.session) {
-                    editor.clear_if_unchanged(&request.text);
+                    editor.clear_if_unchanged(&request.content.text);
                 }
                 Delivery::Accepted
             }
diff --git a/crates/tui/src/state.rs b/crates/tui/src/state.rs
index 4344827b68..4a45e4229f 100644
--- a/crates/tui/src/state.rs
+++ b/crates/tui/src/state.rs
@@ -19,6 +19,7 @@
 
 mod snapshot;
 mod store;
+mod submission;
 
 use crate::{
     app::App,
diff --git a/crates/tui/src/state/snapshot.rs b/crates/tui/src/state/snapshot.rs
index c9476b1627..1cdafabc0e 100644
--- a/crates/tui/src/state/snapshot.rs
+++ b/crates/tui/src/state/snapshot.rs
@@ -22,7 +22,7 @@ use crate::{
     editor::{Editor, saved::Saved},
     i18n::LocalePreference,
     navigation::{Route, tabs::LIMIT},
-    pages::sending::{Delivery, Sending, Submission},
+    pages::sending::{Delivery, Sending},
 };
 use serde::{Deserialize, Serialize};
 use std::collections::{BTreeMap, HashSet};
@@ -35,7 +35,7 @@ pub struct Snapshot {
     route: Route,
     tabs: Vec<String>,
     drafts: BTreeMap<String, Saved>,
-    unresolved: Vec<Submission>,
+    unresolved: Vec<super::submission::Saved>,
     locale: LocalePreference,
     terminal_colors: bool,
     #[serde(default)]
@@ -66,7 +66,7 @@ impl Snapshot {
             .collect();
         unresolved.sort_by(|left, right| left.session.cmp(&right.session));
         Self {
-            version: 6,
+            version: 7,
             root: root.into(),
             route: app.navigation.current(),
             tabs: app.tabs.entries.iter().map(|tab| tab.id.clone()).collect(),
@@ -75,7 +75,10 @@ impl Snapshot {
                 .iter()
                 .map(|(id, editor)| (id.clone(), editor.save()))
                 .collect(),
-            unresolved,
+            unresolved: unresolved
+                .into_iter()
+                .map(|request| super::submission::Saved::Current(Box::new(request)))
+                .collect(),
             locale: app.i18n.preference,
             terminal_colors: app.theme.choice == crate::theme::Choice::Terminal,
             theme: Some(app.theme.choice),
@@ -95,7 +98,7 @@ impl Snapshot {
         let id = |id: &str| {
             !id.is_empty() && id.encode_utf16().count() <= 256 && !id.chars().any(char::is_control)
         };
-        if !matches!(self.version, 1..=6)
+        if !matches!(self.version, 1..=7)
             || self.root != root
             || self.tabs.len() > LIMIT
             || self.drafts.len() > LIMIT
@@ -158,10 +161,10 @@ impl Snapshot {
         }
         let mut seen = HashSet::new();
         for request in &self.unresolved {
+            let request = request.clone().request(self.version)?;
             if request.root_id != root
                 || !self.drafts.contains_key(&request.session)
-                || !seen.insert(&request.session)
-                || request.text.len() > 256 * 1024
+                || !seen.insert(request.session.clone())
             {
                 return Err("Invalid saved submission identity".into());
             }
@@ -191,6 +194,7 @@ impl Snapshot {
             app.drafts.insert(id, Editor::restore(saved)?);
         }
         for request in self.unresolved {
+            let request = request.request(self.version)?;
             app.sending.insert(
                 request.session.clone(),
                 Sending {
@@ -247,6 +251,15 @@ mod tests {
         };
         app
     }
+    fn text_only_requests(value: &mut serde_json::Value) {
+        for request in value["unresolved"].as_array_mut().unwrap() {
+            let fields = request.as_object_mut().unwrap();
+            let content = fields.remove("content").unwrap();
+            fields.insert("text".into(), content["text"].clone());
+            fields.remove("input_selections");
+            fields.remove("turn_orchestration");
+        }
+    }
     #[test]
     fn checkpoint_restores_drafts_preferences_and_original_unknown_identity_without_dispatching() {
         let mut original = app();
@@ -300,7 +313,7 @@ mod tests {
         assert!(restored.retry_submission().is_none());
         assert!(restored.reconciliation().is_some());
         let mut invalid: serde_json::Value = serde_json::from_slice(&bytes).unwrap();
-        invalid["version"] = serde_json::json!(7);
+        invalid["version"] = serde_json::json!(8);
         assert!(
             serde_json::from_value::<Snapshot>(invalid)
                 .unwrap()
@@ -308,6 +321,7 @@ mod tests {
                 .is_err()
         );
         let mut legacy: serde_json::Value = serde_json::from_slice(&bytes).unwrap();
+        text_only_requests(&mut legacy);
         legacy.as_object_mut().unwrap().remove("theme");
         legacy["version"] = serde_json::json!(1);
         legacy.as_object_mut().unwrap().remove("readings");
@@ -316,6 +330,13 @@ mod tests {
         let legacy: Snapshot = serde_json::from_value(legacy).unwrap();
         legacy.validate("root").unwrap();
         assert!(legacy.readings.is_empty());
+        let mut migrated = app();
+        legacy.restore(&mut migrated, false).unwrap();
+        assert_eq!(migrated.sending["a"].request, request);
+        assert!(matches!(
+            migrated.sending["a"].delivery,
+            Delivery::Unknown(None)
+        ));
 
         // v4 adds only the original OAuth query basis. A v3 reader must not
         // silently discard it; current readers still accept v1-v3 without it.
@@ -334,6 +355,7 @@ mod tests {
             oauth["oauth"]
         );
         oauth.as_object_mut().unwrap().remove("theme");
+        text_only_requests(&mut oauth);
         oauth["version"] = serde_json::json!(3);
         assert!(
             serde_json::from_value::<Snapshot>(oauth.clone())
@@ -348,6 +370,104 @@ mod tests {
             .unwrap();
     }
 
+    #[test]
+    fn structured_unknown_requests_keep_all_content_and_intent_across_restore_and_retry() {
+        use maka_protocol::message::{Placement, SubmitResult};
+        use serde_json::json;
+
+        let mut original = app();
+        original.apply(Action::Visit(Route::Session("a".into())));
+        original
+            .drafts
+            .get_mut("a")
+            .unwrap()
+            .insert("Original prompt");
+        let mut request = original.submission_for(Placement::CurrentTurn).unwrap();
+        request.content = serde_json::from_value(json!({
+            "text":"Original prompt", "displayText":"🦀 @src/main.rs",
+            "attachments":[{"kind":"image","name":"image.png","mimeType":"image/png","bytes":42,
+                "ref":{"kind":"session_file","sessionId":"source","relativePath":"image.png"}}],
+            "quotes":[{"text":"Original quotation","label":"Source","sourceTurnId":"source-turn"}],
+            "directoryReferences":[{"hostId":"origin-host","path":"/original/workspace"}],
+            "inlineReferences":[{"kind":"workspace_file","value":"@src/main.rs","label":"main.rs","start":3}]
+        })).unwrap();
+        request
+            .input_selections
+            .insert("skills".into(), vec!["review".into()]);
+        request.turn_orchestration =
+            Some(serde_json::from_value(json!({"mode":"code","source":"slash_command"})).unwrap());
+        request.input().validate().unwrap();
+        original.sending.get_mut("a").unwrap().request = request.clone();
+        let saved = serde_json::to_value(Snapshot::capture(&original, "root")).unwrap();
+        assert_eq!(saved["version"], 7);
+        let mut restored = app();
+        serde_json::from_value::<Snapshot>(saved.clone())
+            .unwrap()
+            .restore(&mut restored, false)
+            .unwrap();
+        assert_eq!(restored.sending["a"].request.input(), request.input());
+        assert!(matches!(
+            restored.sending["a"].delivery,
+            Delivery::Unknown(None)
+        ));
+        let retry = restored.retry_submission().unwrap();
+        assert_eq!(retry, request);
+
+        // Same message ID is not enough: an altered attachment, display or
+        // preparation intent must not release the saved request or its draft.
+        let mut changed = retry.clone();
+        changed.content.attachments.as_mut().unwrap()[0].name = "other.png".into();
+        assert!(!restored.after_checkpoint(&changed, &Ok(())));
+        restored.submitted(
+            changed.clone(),
+            Ok(SubmitResult::Blocked {
+                message: "foreign reply".into(),
+                preparation: vec![],
+            }),
+        );
+        assert!(matches!(restored.sending["a"].delivery, Delivery::Retrying));
+        assert!(restored.after_checkpoint(&retry, &Ok(())));
+        restored.abandon_pending_submissions();
+        let checking = restored.reconciliation().unwrap();
+        let accepted = maka_protocol::message::ExecutionResolution::Pending {
+            message_id: retry.id.clone(),
+        };
+        restored.reconciled(changed, Ok(Some(accepted.clone())));
+        assert!(matches!(restored.sending["a"].delivery, Delivery::Checking));
+        assert_eq!(restored.drafts["a"].text(), "Original prompt");
+        restored.reconciled(checking, Ok(Some(accepted)));
+        assert!(restored.drafts["a"].text().is_empty());
+
+        for (pointer, value) in [
+            ("/version", json!(6)),
+            ("/unresolved/0/placement", json!("next_turn")),
+            ("/unresolved/0/content/inlineReferences/0/start", json!(2)),
+            (
+                "/unresolved/0/content/attachments/0/ref",
+                json!({"kind":"session_context","sessionId":"source","refId":"owned"}),
+            ),
+        ] {
+            let mut invalid = saved.clone();
+            *invalid.pointer_mut(pointer).unwrap() = value;
+            assert!(
+                serde_json::from_value::<Snapshot>(invalid)
+                    .unwrap()
+                    .validate("root")
+                    .is_err(),
+                "{pointer}"
+            );
+        }
+        let mut incomplete = saved;
+        incomplete["unresolved"][0]
+            .as_object_mut()
+            .unwrap()
+            .remove("input_selections");
+        assert!(
+            serde_json::from_value::<Snapshot>(incomplete).is_err(),
+            "never downgrade an incomplete structured request to text-only"
+        );
+    }
+
     #[test]
     fn navigation_checkpoint_restores_both_branches_and_safe_focus_but_not_live_controls() {
         let mut original = app();
diff --git a/crates/tui/src/state/submission.rs b/crates/tui/src/state/submission.rs
new file mode 100644
index 0000000000..1d89473f8f
--- /dev/null
+++ b/crates/tui/src/state/submission.rs
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use crate::pages::sending::Submission;
+use maka_protocol::{message::Placement, turn::MessageContent};
+use serde::{Deserialize, Serialize};
+
+/// v1-v6 saved text-only requests. Never reinterpret an incomplete v7 request
+/// as legacy: losing metadata would change an unknown request's identity.
+#[derive(Clone, Serialize, Deserialize)]
+#[serde(untagged)]
+pub(super) enum Saved {
+    Current(Box<Submission>),
+    Legacy(Legacy),
+}
+
+#[derive(Clone, Serialize, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub(super) struct Legacy {
+    root_id: String,
+    origin_epoch: String,
+    session: String,
+    id: String,
+    text: String,
+    placement: Placement,
+}
+
+impl Saved {
+    pub fn request(self, version: u32) -> Result<Submission, String> {
+        match self {
+            Self::Current(request) if version == 7 => Ok(*request),
+            Self::Legacy(request) if (1..=6).contains(&version) => Ok(Submission {
+                root_id: request.root_id,
+                origin_epoch: request.origin_epoch,
+                session: request.session,
+                id: request.id,
+                content: MessageContent {
+                    text: request.text,
+                    display_text: None,
+                    attachments: None,
+                    directory_references: None,
+                    quotes: None,
+                    inline_references: None,
+                },
+                placement: request.placement,
+                input_selections: Default::default(),
+                turn_orchestration: None,
+            }),
+            _ => Err("Submission does not match checkpoint version".into()),
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org