1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use agent_base::ReasoningEffort;
use clap::{Parser, Subcommand};
#[derive(Parser, Debug)]
#[command(
name = "phi",
about = "phi — General-purpose AI Agent CLI tool",
version,
long_about = "phi — Drive local dev tasks via natural language.\n\n\
Supports interactive mode and one-shot mode."
)]
pub struct CliArgs {
/// One-shot query (one-shot mode). If provided, runs the query and exits.
/// If omitted, enters interactive REPL mode.
#[arg(value_name = "QUERY")]
pub query: Option<String>,
#[command(subcommand)]
pub command: Option<SubCommand>,
// ── Output control ──
#[arg(long, value_enum, default_value = "terminal")]
pub format: OutputFormatArg,
/// Hide AI thinking process
#[arg(long, default_value = "false")]
pub no_thinking: bool,
/// Thinking token budget
#[arg(long)]
pub thinking_budget: Option<u64>,
/// Thinking effort (low/medium/high/xhigh)
#[arg(long, value_enum, default_value = "medium")]
pub thinking_effort: ReasoningEffortArg,
/// Hide tool argument details
#[arg(long, default_value = "false")]
pub no_tool_args: bool,
/// Disable terminal colors
#[arg(long, default_value = "false")]
pub no_color: bool,
// ── Approval control ──
/// Auto-approve all operations (skip confirmation)
#[arg(long, short = 'y', default_value = "false")]
pub auto_approve: bool,
// ── Session control ──
/// Session ID (for session persistence)
#[arg(long, env = "PHI_SESSION_ID")]
pub session_id: Option<String>,
// ── Model config ──
/// LLM model name
#[arg(long)]
pub model: Option<String>,
/// LLM API base URL
#[arg(long)]
pub base_url: Option<String>,
// ── Logging control ──
/// Log directory
#[arg(long, default_value = "~/.phi-agent")]
pub log_dir: String,
/// Log level
#[arg(long, default_value = "info")]
pub log_level: String,
/// Disable file logging
#[arg(long, default_value = "false")]
pub no_log: bool,
// ── Safety limits ──
/// Max tool calls per turn
#[arg(long)]
pub max_tool_calls: Option<usize>,
/// Max consecutive failures for the same tool
#[arg(long)]
pub max_failures: Option<usize>,
/// Max react-loop iterations for a single run (one user input). Default: 200.
#[arg(long, env = "PHI_MAX_TURNS")]
pub max_turns: Option<u32>,
// ── Tool config ──
/// Shell command timeout (milliseconds)
#[arg(long, default_value = "30000")]
pub shell_timeout_ms: u64,
}
#[derive(Clone, Debug, clap::ValueEnum)]
pub enum OutputFormatArg {
/// Rich terminal output
Terminal,
/// One JSON object per line
Json,
/// No output
Quiet,
}
#[derive(Clone, Debug, clap::ValueEnum)]
pub enum ReasoningEffortArg {
Low,
Medium,
High,
Xhigh,
}
impl From<ReasoningEffortArg> for ReasoningEffort {
fn from(arg: ReasoningEffortArg) -> Self {
match arg {
ReasoningEffortArg::Low => ReasoningEffort::Low,
ReasoningEffortArg::Medium => ReasoningEffort::Medium,
ReasoningEffortArg::High => ReasoningEffort::High,
ReasoningEffortArg::Xhigh => ReasoningEffort::XHigh,
}
}
}
#[derive(Subcommand, Debug)]
pub enum SubCommand {
/// Manage observability data.
Metrics {
#[command(subcommand)]
cmd: MetricsCmd,
},
/// Scaffold a new phi-agent project.
Init {
/// Project name
name: String,
/// Generate a single-shot example instead of REPL
#[arg(long)]
lib: bool,
},
/// Start the bridge server for SDK consumption (stdio NDJSON protocol).
Serve,
}
#[derive(Subcommand, Debug)]
pub enum MetricsCmd {
/// List all sessions with token usage, cost, and outcome.
List,
/// Show detailed metrics for a specific session.
Show {
/// Session ID (e.g. "20260730_c52b4c91")
session_id: String,
},
/// Show the most recent session.
Last,
}