mirror of
https://github.com/openai/codex.git
synced 2026-04-29 08:56:38 +00:00
To allow the ability to have guaranteed-unique cursors, we make two important updates: * Add new updated_at_ms and created_at_ms columns that are in millisecond precision * Guarantee uniqueness -- if multiple items are inserted at the same millisecond, bump the new one by one millisecond until it becomes unique This lets us use single-number cursors for forwards and backwards paging through resultsets and guarantee that the cursor is a fixed point to do (timestamp > cursor) and get new items only. This updated implementation is backwards-compatible since multiple appservers can be running and won't handle the previous method well.
115 lines
4.0 KiB
Rust
115 lines
4.0 KiB
Rust
use anyhow::Result;
|
|
use app_test_support::McpProcess;
|
|
use app_test_support::create_fake_rollout;
|
|
use app_test_support::rollout_path;
|
|
use app_test_support::to_response;
|
|
use codex_app_server_protocol::ConversationSummary;
|
|
use codex_app_server_protocol::GetConversationSummaryParams;
|
|
use codex_app_server_protocol::GetConversationSummaryResponse;
|
|
use codex_app_server_protocol::JSONRPCResponse;
|
|
use codex_app_server_protocol::RequestId;
|
|
use codex_protocol::ThreadId;
|
|
use codex_protocol::protocol::SessionSource;
|
|
use pretty_assertions::assert_eq;
|
|
use std::path::PathBuf;
|
|
use tempfile::TempDir;
|
|
use tokio::time::timeout;
|
|
|
|
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
|
|
const FILENAME_TS: &str = "2025-01-02T12-00-00";
|
|
const META_RFC3339: &str = "2025-01-02T12:00:00Z";
|
|
const UPDATED_AT_RFC3339: &str = "2025-01-02T12:00:00.000Z";
|
|
const PREVIEW: &str = "Summarize this conversation";
|
|
const MODEL_PROVIDER: &str = "openai";
|
|
|
|
fn expected_summary(conversation_id: ThreadId, path: PathBuf) -> ConversationSummary {
|
|
ConversationSummary {
|
|
conversation_id,
|
|
path,
|
|
preview: PREVIEW.to_string(),
|
|
timestamp: Some(META_RFC3339.to_string()),
|
|
updated_at: Some(UPDATED_AT_RFC3339.to_string()),
|
|
model_provider: MODEL_PROVIDER.to_string(),
|
|
cwd: PathBuf::from("/"),
|
|
cli_version: "0.0.0".to_string(),
|
|
source: SessionSource::Cli,
|
|
git_info: None,
|
|
}
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn get_conversation_summary_by_thread_id_reads_rollout() -> Result<()> {
|
|
let codex_home = TempDir::new()?;
|
|
let conversation_id = create_fake_rollout(
|
|
codex_home.path(),
|
|
FILENAME_TS,
|
|
META_RFC3339,
|
|
PREVIEW,
|
|
Some(MODEL_PROVIDER),
|
|
/*git_info*/ None,
|
|
)?;
|
|
let thread_id = ThreadId::from_string(&conversation_id)?;
|
|
let expected = expected_summary(
|
|
thread_id,
|
|
std::fs::canonicalize(rollout_path(
|
|
codex_home.path(),
|
|
FILENAME_TS,
|
|
&conversation_id,
|
|
))?,
|
|
);
|
|
|
|
let mut mcp = McpProcess::new(codex_home.path()).await?;
|
|
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
|
|
|
|
let request_id = mcp
|
|
.send_get_conversation_summary_request(GetConversationSummaryParams::ThreadId {
|
|
conversation_id: thread_id,
|
|
})
|
|
.await?;
|
|
let response: JSONRPCResponse = timeout(
|
|
DEFAULT_READ_TIMEOUT,
|
|
mcp.read_stream_until_response_message(RequestId::Integer(request_id)),
|
|
)
|
|
.await??;
|
|
let received: GetConversationSummaryResponse = to_response(response)?;
|
|
|
|
assert_eq!(received.summary, expected);
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn get_conversation_summary_by_relative_rollout_path_resolves_from_codex_home() -> Result<()>
|
|
{
|
|
let codex_home = TempDir::new()?;
|
|
let conversation_id = create_fake_rollout(
|
|
codex_home.path(),
|
|
FILENAME_TS,
|
|
META_RFC3339,
|
|
PREVIEW,
|
|
Some(MODEL_PROVIDER),
|
|
/*git_info*/ None,
|
|
)?;
|
|
let thread_id = ThreadId::from_string(&conversation_id)?;
|
|
let rollout_path = rollout_path(codex_home.path(), FILENAME_TS, &conversation_id);
|
|
let relative_path = rollout_path.strip_prefix(codex_home.path())?.to_path_buf();
|
|
let expected = expected_summary(thread_id, std::fs::canonicalize(rollout_path)?);
|
|
|
|
let mut mcp = McpProcess::new(codex_home.path()).await?;
|
|
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
|
|
|
|
let request_id = mcp
|
|
.send_get_conversation_summary_request(GetConversationSummaryParams::RolloutPath {
|
|
rollout_path: relative_path,
|
|
})
|
|
.await?;
|
|
let response: JSONRPCResponse = timeout(
|
|
DEFAULT_READ_TIMEOUT,
|
|
mcp.read_stream_until_response_message(RequestId::Integer(request_id)),
|
|
)
|
|
.await??;
|
|
let received: GetConversationSummaryResponse = to_response(response)?;
|
|
|
|
assert_eq!(received.summary, expected);
|
|
Ok(())
|
|
}
|