Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions crates/altius-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,7 @@ pub struct GitHubMcpArgs {

/// Name of the environment variable containing the GitHub bearer token.
/// The token value is never accepted as a CLI argument or sent to the LLM.
#[arg(
long,
env = "ALTIUS_GITHUB_TOKEN_ENV",
default_value = "GITHUB_TOKEN"
)]
#[arg(long, env = "ALTIUS_GITHUB_TOKEN_ENV", default_value = "GITHUB_TOKEN")]
pub github_token_env: String,

/// GitHub MCP capability exposed to the specialist.
Expand Down
1 change: 0 additions & 1 deletion crates/altius-cli/src/github_connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,3 @@ pub async fn attach(
dispatcher: Arc::new(tools),
}))
}

24 changes: 19 additions & 5 deletions crates/altius-cli/src/serve_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use altius_protocol::anp::{
AgentDescription, AgentRegistry, AnpState, InMemoryRegistry, InterfaceDescription,
};
use altius_protocol::beeacp::{
require_bearer, BearerAuth, BeeAcpState, Message, MessagePart, Run, RunApproval, RunExecutor,
RunOutcome, SqliteRunStore, openapi_router,
openapi_router, require_bearer, BearerAuth, BeeAcpState, Message, MessagePart, Run,
RunApproval, RunExecutor, RunOutcome, SqliteRunStore,
};
use altius_protocol::Result as ProtocolResult;
use async_trait::async_trait;
Expand Down Expand Up @@ -294,9 +294,11 @@ impl FleetRunExecutor {
.await
{
Ok(ExecutionOutcome::Finished { state, .. }) => Ok(Some(completed_outcome(state))),
Ok(ExecutionOutcome::Interrupted { reason, node, .. }) => Ok(Some(RunOutcome::Awaiting {
approval: RunApproval::generic(reason, Some(node)),
})),
Ok(ExecutionOutcome::Interrupted { reason, node, .. }) => {
Ok(Some(RunOutcome::Awaiting {
approval: RunApproval::generic(reason, Some(node)),
}))
}
Err(error) => Ok(Some(RunOutcome::Failed(error.to_string()))),
}
}
Expand Down Expand Up @@ -384,6 +386,7 @@ fn options_for_run(template: &SupervisorOptions, agent_name: &str) -> Supervisor
SupervisorOptions {
agent_name: Some(agent_name.to_owned()),
browser: template.browser.clone(),
github: template.github.clone(),
hooks: template.hooks.clone(),
}
}
Expand Down Expand Up @@ -554,10 +557,20 @@ async fn build_supervisor_options(
}
}
let browser_enabled = browser_tooling.is_some();

let github_tooling = match crate::github_connector::attach(&args.github, &attachments).await {
Ok(tooling) => tooling,
Err(error) => {
eprintln!("altius: warning: GitHub MCP attach failed: {error}");
None
}
};

Ok((
SupervisorOptions {
agent_name: None,
browser: browser_tooling,
github: github_tooling,
hooks: Vec::new(),
},
browser_enabled,
Expand Down Expand Up @@ -612,6 +625,7 @@ fn serve_protocols(args: &FleetServeArgs, include_beeacp: bool) -> Result<(), Cl
token: args.token.clone(),
run_db: args.run_db.clone(),
plugin: args.plugin.clone(),
github: args.github.clone(),
};

rt.block_on(async move {
Expand Down
3 changes: 3 additions & 0 deletions crates/altius-mcp/src/agent_lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ fn map_error(error: McpClientError) -> AgentLspError {
McpClientError::Request(_, message) => AgentLspError::Request(message),
McpClientError::NotFound(name) => AgentLspError::Request(format!("not found: {name}")),
McpClientError::Shutdown(_, message) => AgentLspError::Shutdown(message),
McpClientError::MissingCredential(env_var) => AgentLspError::InvalidConfig(format!(
"missing credential environment variable `{env_var}`"
)),
}
}

Expand Down
10 changes: 2 additions & 8 deletions crates/altius-mcp/src/mcp_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,7 @@ pub async fn attach_mcp(config: McpAttachConfig) -> Result<AttachedMcp, McpClien
}

/// Attach directly to a remote streamable-HTTP MCP endpoint.
pub async fn attach_remote_mcp(
config: McpRemoteConfig,
) -> Result<AttachedMcp, McpClientError> {
pub async fn attach_remote_mcp(config: McpRemoteConfig) -> Result<AttachedMcp, McpClientError> {
validate_remote_config(&config)?;
spawn_remote(config).await
}
Expand Down Expand Up @@ -398,11 +396,7 @@ fn validate_config(config: &McpAttachConfig) -> Result<(), McpClientError> {
"too many env_extras entries".into(),
));
}
if config
.env_extras
.iter()
.any(|key| !valid_env_key(key))
{
if config.env_extras.iter().any(|key| !valid_env_key(key)) {
return Err(McpClientError::InvalidConfig(
"env_extras keys must be ASCII environment names and bounded".into(),
));
Expand Down
2 changes: 1 addition & 1 deletion crates/altius-protocol/src/beeacp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

mod auth;
mod model;
mod routes;
mod openapi;
mod routes;
mod sqlite_store;
mod store;

Expand Down
26 changes: 13 additions & 13 deletions crates/altius-protocol/src/beeacp/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ pub enum RunOutcome {
/// The run finished with the given output messages.
Completed(Vec<Message>),
/// The run is paused waiting for external input (`POST /runs/{id}`).
Awaiting {
approval: RunApproval,
},
Awaiting { approval: RunApproval },
/// The run failed with a human-readable reason.
Failed(String),
}
Expand Down Expand Up @@ -156,13 +154,7 @@ async fn apply_outcome(state: &BeeAcpState, run_id: RunId, outcome: RunOutcome)
RunOutcome::Awaiting { approval } => {
state
.store
.transition(
run_id,
RunStatus::Awaiting,
None,
None,
Some(approval),
)
.transition(run_id, RunStatus::Awaiting, None, None, Some(approval))
.await
}
RunOutcome::Failed(reason) => {
Expand Down Expand Up @@ -257,7 +249,10 @@ pub(crate) async fn list_runs(State(state): State<BeeAcpState>) -> Result<Json<V
),
security(("bearer_auth" = []))
)]
pub(crate) async fn get_run(State(state): State<BeeAcpState>, Path(id): Path<String>) -> Result<Json<Run>> {
pub(crate) async fn get_run(
State(state): State<BeeAcpState>,
Path(id): Path<String>,
) -> Result<Json<Run>> {
let run = state.store.get(parse_run_id(&id)?).await?;
Ok(Json(run))
}
Expand All @@ -274,7 +269,10 @@ pub(crate) async fn get_run(State(state): State<BeeAcpState>, Path(id): Path<Str
),
security(("bearer_auth" = []))
)]
pub(crate) async fn cancel_run(State(state): State<BeeAcpState>, Path(id): Path<String>) -> Result<Json<Run>> {
pub(crate) async fn cancel_run(
State(state): State<BeeAcpState>,
Path(id): Path<String>,
) -> Result<Json<Run>> {
let run = state
.store
.transition(parse_run_id(&id)?, RunStatus::Cancelled, None, None, None)
Expand Down Expand Up @@ -663,7 +661,9 @@ mod tests {
// so keep-alive pings keep the stream open indefinitely.
let (_, run) = send(
&app,
Request::get(format!("/runs/{id}")).body(Body::empty()).unwrap(),
Request::get(format!("/runs/{id}"))
.body(Body::empty())
.unwrap(),
)
.await;
assert_eq!(run["status"], "awaiting");
Expand Down
13 changes: 7 additions & 6 deletions crates/altius-protocol/src/beeacp/sqlite_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,13 @@ fn decode_run(
finished_at,
): StoredRunRow,
) -> Result<Run> {
let approval = match approval_json {
Some(raw) => Some(serde_json::from_str(&raw).map_err(|e| {
ProtocolError::Internal(format!("corrupt approval json in db: {e}"))
})?),
None => None,
};
let approval =
match approval_json {
Some(raw) => Some(serde_json::from_str(&raw).map_err(|e| {
ProtocolError::Internal(format!("corrupt approval json in db: {e}"))
})?),
None => None,
};
Ok(Run {
run_id: run_id
.parse()
Expand Down
Loading