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

158 lines
4.9 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**
- Boldly pass overrides end-to-end: thread `base_instructions` through config → session → prompt.
```rust
// During ConfigureSession:
Op::ConfigureSession {
// ...
user_instructions,
base_instructions: config.base_instructions.clone(),
// ...
};
// When building the Prompt:
let prompt = Prompt {
// ...
user_instructions: sess.user_instructions.clone(),
base_instructions_override: sess.base_instructions.clone(),
// ...
};
```
- Prefer helper utilities in tests to reduce flakiness and boilerplate.
```rust
// Good: wait for a specific event, then for TaskComplete.
let EventMsg::SessionConfigured(SessionConfiguredEvent { session_id, .. }) =
test_support::wait_for_event(&codex, |ev| matches!(ev, EventMsg::SessionConfigured(_))).await
else { unreachable!() };
test_support::wait_for_event(&codex, |ev| matches!(ev, EventMsg::TaskComplete(_))).await;
```
- Capture full return values from functions that now return more items; ignore what you dont need.
```rust
// Accept signature evolution safely:
let (codex, ..) = Codex::spawn(config, ctrl_c.clone()).await?;
// or explicitly:
let (codex, _init_id, _extra) = Codex::spawn(config, ctrl_c.clone()).await?;
```
- Keep imports tidy after refactors; remove unused imports and the stray blank line they leave behind.
```rust
// Good: no unused imports and no extra blank lines.
use tempfile::TempDir;
use wiremock::{Mock, MockServer, ResponseTemplate};
```
- Treat `CodexToolCallParam.base_instructions` as literal text (not a file path).
```rust
use codex_mcp_server::CodexToolCallParam;
let params = CodexToolCallParam {
prompt: "How are you?".to_string(),
base_instructions: Some("You are a helpful assistant.".to_string()),
..Default::default()
};
```
- Support file-based overrides via config for local workflows.
```toml
# config.toml
experimental-instructions-file = "/abs/path/to/instructions.md"
```
```rust
fn get_base_instructions(path: Option<&PathBuf>) -> Option<String> {
let path = path.as_ref()?;
std::fs::read_to_string(path).ok()
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
}
```
- Compose final instructions with the correct precedence: base first, then user.
```rust
let base = self.base_instructions_override.as_deref().unwrap_or(BASE_INSTRUCTIONS);
let mut sections = vec![base];
if let Some(ref user) = self.user_instructions {
sections.push(user);
}
let full = sections.join("\n\n");
```
- Write assertions that dont move `Option` values unnecessarily.
```rust
let maybe_id = Some(session_id.to_string());
assert!(maybe_id.is_some());
assert_eq!(request_body.to_str().unwrap(), maybe_id.as_ref().unwrap());
```
- Verify overrides actually reach the wire in both APIs under test.
```rust
// responses API: body has top-level "instructions"
let body = request.body_json::<serde_json::Value>().unwrap();
assert!(body["instructions"].as_str().unwrap().contains("test instructions"));
// chat.completions API: first system message content
let body = request.body_json::<serde_json::Value>().unwrap();
let sys = body["messages"][0]["content"].as_str().unwrap();
assert!(sys.starts_with("You are a helpful assistant."));
```
- Derive `Default` for test-friendly params.
```rust
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
pub struct CodexToolCallParam { /* ... */ }
```
**DONTs**
- Dont leave stale imports or extra blank lines after removing an import.
```rust
// Bad:
use tokio::time::timeout;
// <- orphaned blank line after removing usage
```
- Dont assume `Codex::spawn` still returns exactly two values.
```rust
// Bad: breaks if a third value was added.
let (codex, init_id) = Codex::spawn(config, ctrl_c).await?;
```
- Dont pass file paths via `base_instructions` in the MCP tool call.
```rust
// Bad: this field expects literal instructions text, not a path.
base_instructions: Some("/tmp/instructions.md".to_string())
```
- Dont move `Option` values you still need later.
```rust
// Bad:
assert_eq!(header, maybe_id.unwrap()); // moved, cannot use maybe_id again
```
- Dont duplicate ad-hoc event polling loops in tests; use the shared helper.
```rust
// Bad: open-coded loop with timeouts and pattern matching everywhere.
loop {
// ...
if matches!(ev.msg, EventMsg::TaskComplete(_)) { break; }
}
```
- Dont ignore the intended precedence: base instructions (built-in or override) must come before user instructions.
```rust
// Bad: user first, base second (reverses meaning).
let mut sections = vec![user, base];
```
- Dont treat `base_instructions` and `user_instructions` as interchangeable; they serve different purposes.
```rust
// Bad: stuffing user content into base overrides changes global behavior.
config.base_instructions = config.user_instructions.clone();
```
- Dont forget to trim and validate file-based overrides.
```rust
// Bad: accepts empty files and trailing whitespace verbatim.
std::fs::read_to_string(path).ok()
```