Files
codex/prs/bolinfest/study/PR-1643-study.md
2025-09-02 15:17:45 -07:00

118 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
**DOs**
- Return a struct instead of a long tuple for multi-value results.
```rust
// Before
pub async fn spawn(config: Config, ctrl_c: Arc<Notify>) -> CodexResult<(Codex, String, Uuid)> { ... }
// After
pub struct SpawnResult {
pub codex: Codex,
pub init_event_id: String,
pub session_id: Uuid,
}
pub async fn spawn(config: Config, ctrl_c: Arc<Notify>) -> CodexResult<SpawnResult> {
// ...
Ok(SpawnResult { codex, init_event_id: init_id, session_id })
}
// Call site
let SpawnResult { codex, init_event_id, session_id } = Codex::spawn(config, ctrl_c).await?;
```
- Keep parameters immutable; only create a mutable local when truly necessary.
```rust
// Prefer immutable params
async fn submission_loop(session_id: Uuid, /* ... */) {
// If you must mutate, make a local copy
let mut current_session = session_id;
// ...
}
```
- Use camelCase for MCP tool schemas with serdes rename_all.
```rust
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
struct CodexToolCallReplyParam {
/// The *session id* for this conversation.
session_id: String,
/// The *next user prompt* to continue the Codex conversation.
prompt: String,
}
```
- Release Mutex guards promptly in async code; dont hold them across long operations.
```rust
let mut map = session_map.lock().await;
map.insert(session_id, codex.clone());
drop(map); // release before streaming loop
// Now do long-running work without the lock held
run_codex_tool_session_inner(codex, outgoing, request_id).await;
```
- Always send an error response to the client on failures; use the same request_id you received.
```rust
let result = CallToolResult {
content: vec![ContentBlock::TextContent(TextContent {
r#type: "text".into(),
text: format!("Unknown tool '{name}'"),
annotations: None,
})],
is_error: Some(true),
structured_content: None,
};
outgoing
.send_response::<mcp_types::CallToolRequest>(request_id.clone(), result)
.await;
```
- Convert RequestId to a String only when needed (e.g., for submission IDs); keep using RequestId for responses.
```rust
let sub_id = match &request_id {
RequestId::String(s) => s.clone(),
RequestId::Integer(n) => n.to_string(),
};
// Use `sub_id` internally, but reply with `request_id`
outgoing.send_response::<mcp_types::CallToolRequest>(request_id.clone(), result).await;
```
**DON'Ts**
- Dont grow tuples of return values; avoid unnamed return values that cause churn.
```rust
// Avoid
pub async fn spawn(/* ... */) -> CodexResult<(Codex, String, Uuid)> { /* ... */ }
```
- Dont mark parameters mut unless you reassign them; prefer local mutable copies if needed.
```rust
// Avoid
async fn submission_loop(mut session_id: Uuid, /* ... */) { /* ... */ }
```
- Dont hold a MutexGuard across awaits or long-running loops; it risks contention or deadlocks.
```rust
// Avoid: guard held while streaming events
let guard = session_map.lock().await;
run_codex_tool_session_inner(codex, outgoing, request_id).await; // guard not dropped
```
- Dont use kebab-case (or snake_case) in MCP JSON schemas.
```rust
// Avoid
#[serde(rename_all = "kebab-case")]
struct CodexToolCallReplyParam { /* ... */ }
```
- Dont just log errors and return; always respond so the client/LLM can react.
```rust
// Avoid
tracing::error!("Failed to parse params: {e}");
return; // no response sent
```
- Dont send responses with a stale or unrelated id; always reply with the original request_id.
```rust
// Avoid
outgoing.send_response(id.clone(), result.into()).await; // `id` is not the current request_id
```