让Direct Codex请求携带项目聊天历史
读取project.jsonl完整user assistant tool记录 新请求覆盖当前消息并保留ephemeral线程
This commit is contained in:
@@ -3149,6 +3149,23 @@ pub(crate) async fn direct_game_creator_codex_chat_at_with_optional_observer(
|
||||
.map_err(|error| error.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn build_direct_codex_history_prompt(
|
||||
root: &std::path::Path,
|
||||
client_turn_id: &str,
|
||||
current_prompt: &str,
|
||||
) -> Result<String, String> {
|
||||
let conversation = read_local_conversation_for_session_at(root, None, None)?;
|
||||
let current_message_id = format!("direct-codex:{client_turn_id}:user");
|
||||
let mut lines = conversation
|
||||
.messages
|
||||
.iter()
|
||||
.filter(|message| message.message_id.as_deref() != Some(current_message_id.as_str()))
|
||||
.map(|message| format!("{}: {}", message.role, message.content))
|
||||
.collect::<Vec<_>>();
|
||||
lines.push(format!("user: {}", current_prompt.trim()));
|
||||
Ok(lines.join("\n"))
|
||||
}
|
||||
|
||||
/// Direct home-page chat never binds Codex to a user project. It gets a
|
||||
/// fresh isolated read-only workspace and a stable in-process thread so a
|
||||
/// normal conversation can continue without creating a project, assets, a
|
||||
@@ -3234,6 +3251,41 @@ pub(in crate::agent) fn shutdown_game_creator_codex_app_servers_impl() -> Result
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn direct_history_prompt_replays_all_project_messages_in_order() {
|
||||
let root = tempfile::tempdir().expect("temp dir");
|
||||
init_local_game_project_at(root.path(), "history-project", "history").expect("init");
|
||||
for (role, content, message_id) in [
|
||||
("user", "hello", "direct-codex:old:user"),
|
||||
("assistant", "partial\nunexpected interrupt happened here", "partial-id"),
|
||||
("tool", "file-read result", "tool-id"),
|
||||
("user", "stored raw request", "direct-codex:new-turn:user"),
|
||||
] {
|
||||
append_local_conversation_message_for_session_idempotent_at(
|
||||
root.path(),
|
||||
None,
|
||||
None,
|
||||
LocalConversationMessage {
|
||||
role: role.to_string(),
|
||||
content: content.to_string(),
|
||||
agent_id: None,
|
||||
},
|
||||
message_id,
|
||||
)
|
||||
.expect("append history");
|
||||
}
|
||||
let prompt = build_direct_codex_history_prompt(
|
||||
root.path(),
|
||||
"new-turn",
|
||||
"new request",
|
||||
)
|
||||
.expect("build prompt");
|
||||
assert_eq!(
|
||||
prompt,
|
||||
"user: hello\nassistant: partial\nunexpected interrupt happened here\ntool: file-read result\nuser: new request"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_item_activities_are_closed_safe_categories() {
|
||||
let allowed = [
|
||||
|
||||
@@ -4220,9 +4220,20 @@ pub(crate) async fn chat_with_game_creator_direct_codex(
|
||||
return Err(error);
|
||||
}
|
||||
};
|
||||
let replay_prompt = match crate::agent::codex_app_server::build_direct_codex_history_prompt(
|
||||
root,
|
||||
&turn_id,
|
||||
&user_prompt,
|
||||
) {
|
||||
Ok(prompt) => prompt,
|
||||
Err(error) => {
|
||||
audit.finish(false);
|
||||
return Err(error);
|
||||
}
|
||||
};
|
||||
let reply = match run_direct_game_creator_turn_at_with_creation_type_and_emitter(
|
||||
root,
|
||||
&user_prompt,
|
||||
&replay_prompt,
|
||||
creation_type.as_deref(),
|
||||
Some(&turn_emitter),
|
||||
Some(&mut audit),
|
||||
|
||||
Reference in New Issue
Block a user