mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 08:03:46 +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(
|
fn spawn_amp(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
working_dir: &Path,
|
working_dir: &Path,
|
||||||
options: &SpawnOptions,
|
options: &SpawnOptions,
|
||||||
) -> Result<std::process::Output, AgentError> {
|
) -> Result<std::process::Output, AgentError> {
|
||||||
let flags = detect_amp_flags(path, working_dir).unwrap_or_default();
|
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();
|
let mut args: Vec<&str> = Vec::new();
|
||||||
if flags.execute {
|
if flags.execute {
|
||||||
args.push("--execute");
|
args.push("--execute");
|
||||||
|
|
@ -1042,8 +1058,8 @@ fn spawn_amp(
|
||||||
|
|
||||||
let mut command = Command::new(path);
|
let mut command = Command::new(path);
|
||||||
command.current_dir(working_dir);
|
command.current_dir(working_dir);
|
||||||
if let Some(model) = options.model.as_deref() {
|
if let Some(mode) = mode.as_deref() {
|
||||||
command.arg("--model").arg(model);
|
command.arg("--mode").arg(mode);
|
||||||
}
|
}
|
||||||
if let Some(session_id) = options.session_id.as_deref() {
|
if let Some(session_id) = options.session_id.as_deref() {
|
||||||
command.arg("--continue").arg(session_id);
|
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 {
|
fn build_amp_command(path: &Path, working_dir: &Path, options: &SpawnOptions) -> Command {
|
||||||
let flags = detect_amp_flags(path, working_dir).unwrap_or_default();
|
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);
|
let mut command = Command::new(path);
|
||||||
command.current_dir(working_dir);
|
command.current_dir(working_dir);
|
||||||
if let Some(model) = options.model.as_deref() {
|
if let Some(mode) = mode.as_deref() {
|
||||||
command.arg("--model").arg(model);
|
command.arg("--mode").arg(mode);
|
||||||
}
|
}
|
||||||
if let Some(session_id) = options.session_id.as_deref() {
|
if let Some(session_id) = options.session_id.as_deref() {
|
||||||
command.arg("--continue").arg(session_id);
|
command.arg("--continue").arg(session_id);
|
||||||
|
|
@ -1102,6 +1123,7 @@ struct AmpFlags {
|
||||||
print: bool,
|
print: bool,
|
||||||
output_format: bool,
|
output_format: bool,
|
||||||
dangerously_skip_permissions: bool,
|
dangerously_skip_permissions: bool,
|
||||||
|
mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_amp_flags(path: &Path, working_dir: &Path) -> Option<AmpFlags> {
|
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"),
|
print: text.contains("--print"),
|
||||||
output_format: text.contains("--output-format"),
|
output_format: text.contains("--output-format"),
|
||||||
dangerously_skip_permissions: text.contains("--dangerously-skip-permissions"),
|
dangerously_skip_permissions: text.contains("--dangerously-skip-permissions"),
|
||||||
|
mode: text.contains("--mode"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1128,6 +1151,12 @@ fn spawn_amp_fallback(
|
||||||
working_dir: &Path,
|
working_dir: &Path,
|
||||||
options: &SpawnOptions,
|
options: &SpawnOptions,
|
||||||
) -> Result<std::process::Output, AgentError> {
|
) -> 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![
|
let mut attempts = vec![
|
||||||
vec!["--execute"],
|
vec!["--execute"],
|
||||||
vec!["--print", "--output-format", "stream-json"],
|
vec!["--print", "--output-format", "stream-json"],
|
||||||
|
|
@ -1142,8 +1171,8 @@ fn spawn_amp_fallback(
|
||||||
for args in attempts {
|
for args in attempts {
|
||||||
let mut command = Command::new(path);
|
let mut command = Command::new(path);
|
||||||
command.current_dir(working_dir);
|
command.current_dir(working_dir);
|
||||||
if let Some(model) = options.model.as_deref() {
|
if let Some(mode) = mode.as_deref() {
|
||||||
command.arg("--model").arg(model);
|
command.arg("--mode").arg(mode);
|
||||||
}
|
}
|
||||||
if let Some(session_id) = options.session_id.as_deref() {
|
if let Some(session_id) = options.session_id.as_deref() {
|
||||||
command.arg("--continue").arg(session_id);
|
command.arg("--continue").arg(session_id);
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,8 @@ use tracing::{info, warn};
|
||||||
use utoipa::{IntoParams, OpenApi, ToSchema};
|
use utoipa::{IntoParams, OpenApi, ToSchema};
|
||||||
|
|
||||||
use crate::router::{
|
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::agents::AgentId;
|
||||||
use sandbox_agent_agent_management::credentials::{
|
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 {
|
async fn oc_agent_list(State(state): State<Arc<OpenCodeAppState>>) -> impl IntoResponse {
|
||||||
let name = state.inner.branding.product_name();
|
let name = state.inner.branding.product_name();
|
||||||
let agent = json!({
|
let mut modes = match state
|
||||||
"name": name,
|
.inner
|
||||||
"description": format!("{name} compatibility layer"),
|
.session_manager()
|
||||||
"mode": "all",
|
.agent_modes(AgentId::Opencode)
|
||||||
"native": false,
|
.await
|
||||||
"hidden": false,
|
{
|
||||||
"permission": [],
|
Ok(modes) if !modes.is_empty() => modes,
|
||||||
"options": {},
|
_ => fallback_opencode_modes(),
|
||||||
});
|
};
|
||||||
(StatusCode::OK, Json(json!([agent])))
|
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(
|
#[utoipa::path(
|
||||||
|
|
|
||||||
|
|
@ -1823,7 +1823,10 @@ impl SessionManager {
|
||||||
Ok(())
|
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 {
|
if agent != AgentId::Opencode {
|
||||||
return Ok(agent_modes_for(agent));
|
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(),
|
description: "Plan mode (prompt-only)".to_string(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
AgentId::Amp => vec![AgentModeInfo {
|
AgentId::Amp => vec![
|
||||||
id: "build".to_string(),
|
AgentModeInfo {
|
||||||
name: "Build".to_string(),
|
id: "smart".to_string(),
|
||||||
description: "Default build mode".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![
|
AgentId::Mock => vec![
|
||||||
AgentModeInfo {
|
AgentModeInfo {
|
||||||
id: "build".to_string(),
|
id: "build".to_string(),
|
||||||
|
|
@ -5007,23 +5027,14 @@ fn agent_modes_for(agent: AgentId) -> Vec<AgentModeInfo> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn amp_models_response() -> AgentModelsResponse {
|
fn amp_models_response() -> AgentModelsResponse {
|
||||||
// NOTE: Amp models are hardcoded based on ampcode.com manual:
|
AgentModelsResponse {
|
||||||
// - smart
|
models: vec![AgentModelInfo {
|
||||||
// - rush
|
id: "default".to_string(),
|
||||||
// - deep
|
name: Some("Default".to_string()),
|
||||||
// - free
|
|
||||||
let models = ["smart", "rush", "deep", "free"]
|
|
||||||
.into_iter()
|
|
||||||
.map(|id| AgentModelInfo {
|
|
||||||
id: id.to_string(),
|
|
||||||
name: None,
|
|
||||||
variants: Some(amp_variants()),
|
variants: Some(amp_variants()),
|
||||||
default_variant: Some("medium".to_string()),
|
default_variant: Some("medium".to_string()),
|
||||||
})
|
}],
|
||||||
.collect();
|
default_model: Some("default".to_string()),
|
||||||
AgentModelsResponse {
|
|
||||||
models,
|
|
||||||
default_model: Some("smart".to_string()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5159,7 +5170,8 @@ fn normalize_agent_mode(agent: AgentId, agent_mode: Option<&str>) -> Result<Stri
|
||||||
.into()),
|
.into()),
|
||||||
},
|
},
|
||||||
AgentId::Amp => match mode {
|
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 {
|
value => Err(SandboxError::ModeNotSupported {
|
||||||
agent: agent.as_str().to_string(),
|
agent: agent.as_str().to_string(),
|
||||||
mode: value.to_string(),
|
mode: value.to_string(),
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,10 @@ nonEmpty: true
|
||||||
hasDefault: true
|
hasDefault: true
|
||||||
defaultInList: true
|
defaultInList: true
|
||||||
hasVariants: true
|
hasVariants: true
|
||||||
modelCount: 4
|
modelCount: 1
|
||||||
ids:
|
ids:
|
||||||
- deep
|
- default
|
||||||
- free
|
defaultModel: default
|
||||||
- rush
|
|
||||||
- smart
|
|
||||||
defaultModel: smart
|
|
||||||
variants:
|
variants:
|
||||||
- high
|
- high
|
||||||
- medium
|
- medium
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue