1use std::path::PathBuf;
8
9use crate::error::{Error, Result};
10
11#[derive(Debug, Clone)]
12pub struct Config {
13 pub workspace: PathBuf,
14 pub api_base: String,
15 pub api_key: Option<String>,
16 pub model: String,
17 pub max_steps: usize,
18 pub temperature: f64,
19 pub system_prompt: String,
20}
21
22impl Config {
23 pub fn from_env() -> Result<Self> {
26 let workspace = std::env::var("RECURSIVE_WORKSPACE")
27 .map(PathBuf::from)
28 .unwrap_or_else(|_| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")));
29
30 let api_base = std::env::var("RECURSIVE_API_BASE")
31 .or_else(|_| std::env::var("OPENAI_API_BASE"))
32 .unwrap_or_else(|_| "https://api.openai.com/v1".into());
33
34 let api_key = std::env::var("RECURSIVE_API_KEY")
35 .or_else(|_| std::env::var("OPENAI_API_KEY"))
36 .ok();
37
38 let model = std::env::var("RECURSIVE_MODEL")
39 .or_else(|_| std::env::var("OPENAI_MODEL"))
40 .unwrap_or_else(|_| "gpt-4o-mini".into());
41
42 let max_steps = std::env::var("RECURSIVE_MAX_STEPS")
43 .ok()
44 .and_then(|s| s.parse().ok())
45 .unwrap_or(32);
46
47 let temperature = std::env::var("RECURSIVE_TEMPERATURE")
48 .ok()
49 .and_then(|s| s.parse().ok())
50 .unwrap_or(0.2);
51
52 let system_prompt = match std::env::var("RECURSIVE_SYSTEM_PROMPT_FILE") {
53 Ok(path) => std::fs::read_to_string(&path)
54 .map_err(|e| Error::Config(format!("read system prompt {path}: {e}")))?,
55 Err(_) => default_system_prompt(),
56 };
57
58 Ok(Self {
59 workspace,
60 api_base,
61 api_key,
62 model,
63 max_steps,
64 temperature,
65 system_prompt,
66 })
67 }
68
69 pub fn require_api_key(&self) -> Result<&str> {
71 self.api_key
72 .as_deref()
73 .ok_or_else(|| Error::Config("set RECURSIVE_API_KEY (or OPENAI_API_KEY)".into()))
74 }
75}
76
77pub fn default_system_prompt() -> String {
78 "You are Recursive, a minimal but capable coding agent. \
79 You have these tools: read_file, write_file, list_dir, run_shell. \
80 Work inside the workspace; never reach outside. \
81 Plan briefly, then act with tool calls. \
82 Before writing code, read the relevant existing files. \
83 After changes, run the project's tests via run_shell to verify. \
84 Stop calling tools and write a final summary once the task is done."
85 .to_string()
86}