mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 06:04:43 +00:00
fix: show agent mode list or fallback label in gigacode
This commit is contained in:
parent
07a05fe1a7
commit
0f325c87dc
4 changed files with 132 additions and 45 deletions
|
|
@ -1020,12 +1020,28 @@ fn extract_result_text(agent: AgentId, events: &[Value]) -> Option<String> {
|
|||
}
|
||||
}
|
||||
|
||||
fn amp_mode_from_agent_mode(agent_mode: Option<&str>) -> Option<String> {
|
||||
let mode = agent_mode
|
||||
.map(|value| value.trim())
|
||||
.filter(|value| !value.is_empty())?;
|
||||
let normalized = match mode {
|
||||
"build" | "default" => "smart",
|
||||
other => other,
|
||||
};
|
||||
Some(normalized.to_string())
|
||||
}
|
||||
|
||||
fn spawn_amp(
|
||||
path: &Path,
|
||||
working_dir: &Path,
|
||||
options: &SpawnOptions,
|
||||
) -> Result<std::process::Output, AgentError> {
|
||||
let flags = detect_amp_flags(path, working_dir).unwrap_or_default();
|
||||
let mode = if flags.mode {
|
||||
amp_mode_from_agent_mode(options.agent_mode.as_deref())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut args: Vec<&str> = Vec::new();
|
||||
if flags.execute {
|
||||
args.push("--execute");
|
||||
|
|
@ -1042,8 +1058,8 @@ fn spawn_amp(
|
|||
|
||||
let mut command = Command::new(path);
|
||||
command.current_dir(working_dir);
|
||||
if let Some(model) = options.model.as_deref() {
|
||||
command.arg("--model").arg(model);
|
||||
if let Some(mode) = mode.as_deref() {
|
||||
command.arg("--mode").arg(mode);
|
||||
}
|
||||
if let Some(session_id) = options.session_id.as_deref() {
|
||||
command.arg("--continue").arg(session_id);
|
||||
|
|
@ -1070,10 +1086,15 @@ fn spawn_amp(
|
|||
|
||||
fn build_amp_command(path: &Path, working_dir: &Path, options: &SpawnOptions) -> Command {
|
||||
let flags = detect_amp_flags(path, working_dir).unwrap_or_default();
|
||||
let mode = if flags.mode {
|
||||
amp_mode_from_agent_mode(options.agent_mode.as_deref())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut command = Command::new(path);
|
||||
command.current_dir(working_dir);
|
||||
if let Some(model) = options.model.as_deref() {
|
||||
command.arg("--model").arg(model);
|
||||
if let Some(mode) = mode.as_deref() {
|
||||
command.arg("--mode").arg(mode);
|
||||
}
|
||||
if let Some(session_id) = options.session_id.as_deref() {
|
||||
command.arg("--continue").arg(session_id);
|
||||
|
|
@ -1102,6 +1123,7 @@ struct AmpFlags {
|
|||
print: bool,
|
||||
output_format: bool,
|
||||
dangerously_skip_permissions: bool,
|
||||
mode: bool,
|
||||
}
|
||||
|
||||
fn detect_amp_flags(path: &Path, working_dir: &Path) -> Option<AmpFlags> {
|
||||
|
|
@ -1120,6 +1142,7 @@ fn detect_amp_flags(path: &Path, working_dir: &Path) -> Option<AmpFlags> {
|
|||
print: text.contains("--print"),
|
||||
output_format: text.contains("--output-format"),
|
||||
dangerously_skip_permissions: text.contains("--dangerously-skip-permissions"),
|
||||
mode: text.contains("--mode"),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1128,6 +1151,12 @@ fn spawn_amp_fallback(
|
|||
working_dir: &Path,
|
||||
options: &SpawnOptions,
|
||||
) -> Result<std::process::Output, AgentError> {
|
||||
let flags = detect_amp_flags(path, working_dir).unwrap_or_default();
|
||||
let mode = if flags.mode {
|
||||
amp_mode_from_agent_mode(options.agent_mode.as_deref())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut attempts = vec![
|
||||
vec!["--execute"],
|
||||
vec!["--print", "--output-format", "stream-json"],
|
||||
|
|
@ -1142,8 +1171,8 @@ fn spawn_amp_fallback(
|
|||
for args in attempts {
|
||||
let mut command = Command::new(path);
|
||||
command.current_dir(working_dir);
|
||||
if let Some(model) = options.model.as_deref() {
|
||||
command.arg("--model").arg(model);
|
||||
if let Some(mode) = mode.as_deref() {
|
||||
command.arg("--mode").arg(mode);
|
||||
}
|
||||
if let Some(session_id) = options.session_id.as_deref() {
|
||||
command.arg("--continue").arg(session_id);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ use tracing::{info, warn};
|
|||
use utoipa::{IntoParams, OpenApi, ToSchema};
|
||||
|
||||
use crate::router::{
|
||||
is_question_tool_action, AgentModelInfo, AppState, CreateSessionRequest, PermissionReply,
|
||||
is_question_tool_action, AgentModeInfo, AgentModelInfo, AppState, CreateSessionRequest,
|
||||
PermissionReply,
|
||||
};
|
||||
use sandbox_agent_agent_management::agents::AgentId;
|
||||
use sandbox_agent_agent_management::credentials::{
|
||||
|
|
@ -2834,16 +2835,64 @@ pub fn build_opencode_router(state: Arc<OpenCodeAppState>) -> Router {
|
|||
)]
|
||||
async fn oc_agent_list(State(state): State<Arc<OpenCodeAppState>>) -> impl IntoResponse {
|
||||
let name = state.inner.branding.product_name();
|
||||
let agent = json!({
|
||||
"name": name,
|
||||
"description": format!("{name} compatibility layer"),
|
||||
"mode": "all",
|
||||
"native": false,
|
||||
"hidden": false,
|
||||
"permission": [],
|
||||
"options": {},
|
||||
});
|
||||
(StatusCode::OK, Json(json!([agent])))
|
||||
let mut modes = match state
|
||||
.inner
|
||||
.session_manager()
|
||||
.agent_modes(AgentId::Opencode)
|
||||
.await
|
||||
{
|
||||
Ok(modes) if !modes.is_empty() => modes,
|
||||
_ => fallback_opencode_modes(),
|
||||
};
|
||||
if modes.is_empty() {
|
||||
let agent = json!({
|
||||
"name": name,
|
||||
"description": format!("{name} compatibility layer"),
|
||||
"mode": "all",
|
||||
"native": false,
|
||||
"hidden": false,
|
||||
"permission": [],
|
||||
"options": {},
|
||||
});
|
||||
return (StatusCode::OK, Json(json!([agent])));
|
||||
}
|
||||
modes.sort_by(|a, b| a.id.cmp(&b.id));
|
||||
let agents: Vec<Value> = modes
|
||||
.into_iter()
|
||||
.map(|mode| {
|
||||
json!({
|
||||
"id": mode.id,
|
||||
"name": mode.id,
|
||||
"description": mode.description,
|
||||
"mode": "all",
|
||||
"native": false,
|
||||
"hidden": false,
|
||||
"permission": [],
|
||||
"options": {},
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
(StatusCode::OK, Json(json!(agents)))
|
||||
}
|
||||
|
||||
fn fallback_opencode_modes() -> Vec<AgentModeInfo> {
|
||||
vec![
|
||||
AgentModeInfo {
|
||||
id: "build".to_string(),
|
||||
name: "Build".to_string(),
|
||||
description: "Default build mode".to_string(),
|
||||
},
|
||||
AgentModeInfo {
|
||||
id: "plan".to_string(),
|
||||
name: "Plan".to_string(),
|
||||
description: "Planning mode".to_string(),
|
||||
},
|
||||
AgentModeInfo {
|
||||
id: "custom".to_string(),
|
||||
name: "Custom".to_string(),
|
||||
description: "Any user-defined OpenCode agent name".to_string(),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
|
|
|||
|
|
@ -1823,7 +1823,10 @@ impl SessionManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn agent_modes(&self, agent: AgentId) -> Result<Vec<AgentModeInfo>, SandboxError> {
|
||||
pub(crate) async fn agent_modes(
|
||||
&self,
|
||||
agent: AgentId,
|
||||
) -> Result<Vec<AgentModeInfo>, SandboxError> {
|
||||
if agent != AgentId::Opencode {
|
||||
return Ok(agent_modes_for(agent));
|
||||
}
|
||||
|
|
@ -4986,11 +4989,28 @@ fn agent_modes_for(agent: AgentId) -> Vec<AgentModeInfo> {
|
|||
description: "Plan mode (prompt-only)".to_string(),
|
||||
},
|
||||
],
|
||||
AgentId::Amp => vec![AgentModeInfo {
|
||||
id: "build".to_string(),
|
||||
name: "Build".to_string(),
|
||||
description: "Default build mode".to_string(),
|
||||
}],
|
||||
AgentId::Amp => vec![
|
||||
AgentModeInfo {
|
||||
id: "smart".to_string(),
|
||||
name: "Smart".to_string(),
|
||||
description: "Default Amp mode".to_string(),
|
||||
},
|
||||
AgentModeInfo {
|
||||
id: "rush".to_string(),
|
||||
name: "Rush".to_string(),
|
||||
description: "Fast mode with smaller context".to_string(),
|
||||
},
|
||||
AgentModeInfo {
|
||||
id: "deep".to_string(),
|
||||
name: "Deep".to_string(),
|
||||
description: "Deep reasoning mode".to_string(),
|
||||
},
|
||||
AgentModeInfo {
|
||||
id: "free".to_string(),
|
||||
name: "Free".to_string(),
|
||||
description: "Free/experimental mode".to_string(),
|
||||
},
|
||||
],
|
||||
AgentId::Mock => vec![
|
||||
AgentModeInfo {
|
||||
id: "build".to_string(),
|
||||
|
|
@ -5007,23 +5027,14 @@ fn agent_modes_for(agent: AgentId) -> Vec<AgentModeInfo> {
|
|||
}
|
||||
|
||||
fn amp_models_response() -> AgentModelsResponse {
|
||||
// NOTE: Amp models are hardcoded based on ampcode.com manual:
|
||||
// - smart
|
||||
// - rush
|
||||
// - deep
|
||||
// - free
|
||||
let models = ["smart", "rush", "deep", "free"]
|
||||
.into_iter()
|
||||
.map(|id| AgentModelInfo {
|
||||
id: id.to_string(),
|
||||
name: None,
|
||||
AgentModelsResponse {
|
||||
models: vec![AgentModelInfo {
|
||||
id: "default".to_string(),
|
||||
name: Some("Default".to_string()),
|
||||
variants: Some(amp_variants()),
|
||||
default_variant: Some("medium".to_string()),
|
||||
})
|
||||
.collect();
|
||||
AgentModelsResponse {
|
||||
models,
|
||||
default_model: Some("smart".to_string()),
|
||||
}],
|
||||
default_model: Some("default".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5159,7 +5170,8 @@ fn normalize_agent_mode(agent: AgentId, agent_mode: Option<&str>) -> Result<Stri
|
|||
.into()),
|
||||
},
|
||||
AgentId::Amp => match mode {
|
||||
"build" => Ok("build".to_string()),
|
||||
"build" => Ok("smart".to_string()),
|
||||
"smart" | "rush" | "deep" | "free" => Ok(mode.to_string()),
|
||||
value => Err(SandboxError::ModeNotSupported {
|
||||
agent: agent.as_str().to_string(),
|
||||
mode: value.to_string(),
|
||||
|
|
|
|||
|
|
@ -6,13 +6,10 @@ nonEmpty: true
|
|||
hasDefault: true
|
||||
defaultInList: true
|
||||
hasVariants: true
|
||||
modelCount: 4
|
||||
modelCount: 1
|
||||
ids:
|
||||
- deep
|
||||
- free
|
||||
- rush
|
||||
- smart
|
||||
defaultModel: smart
|
||||
- default
|
||||
defaultModel: default
|
||||
variants:
|
||||
- high
|
||||
- medium
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue