feat(agentcompany-rust): scaffold native shell and runtime bridge

This commit is contained in:
ZacharyZhang-NY committed 2026-04-19 01:02:20 -04:00
1 parent 34814b4dfd
commit 2cddf89717
40 files changed
+11300 -3

No files matched your search

@@ -0,0 +1,79 @@
use crate::{ClientRequest, RuntimeEvent};
use anyhow::{Context, Result};
use std::{
io::{BufRead, BufReader, Write},
path::PathBuf,
process::{Child, ChildStdin, ChildStdout, Command, Stdio},
};
pub struct PiBridgeClient {
child: Child,
stdin: ChildStdin,
stdout: BufReader<ChildStdout>,
}
impl PiBridgeClient {
pub fn spawn(command: PathBuf, args: &[String], working_dir: Option<PathBuf>) -> Result<Self> {
let mut process = Command::new(&command);
process
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::inherit());
if let Some(dir) = working_dir {
process.current_dir(dir);
}
let mut child = process
.spawn()
.with_context(|| format!("failed to spawn Pi Mono sidecar at {}", command.display()))?;
let stdin = child
.stdin
.take()
.context("Pi Mono sidecar stdin is unavailable")?;
let stdout = child
.stdout
.take()
.context("Pi Mono sidecar stdout is unavailable")?;
Ok(Self {
child,
stdin,
stdout: BufReader::new(stdout),
})
}
pub fn send(&mut self, message: &ClientRequest) -> Result<()> {
let payload =
serde_json::to_vec(message).context("failed to serialize Pi bridge request")?;
self.stdin
.write_all(&payload)
.context("failed to write Pi bridge request")?;
self.stdin
.write_all(b"\n")
.context("failed to terminate Pi bridge request")?;
self.stdin
.flush()
.context("failed to flush Pi bridge request")?;
Ok(())
}
pub fn read_event(&mut self) -> Result<RuntimeEvent> {
let mut line = String::new();
let bytes = self
.stdout
.read_line(&mut line)
.context("failed to read Pi bridge event")?;
if bytes == 0 {
return Err(anyhow::anyhow!("Pi Mono sidecar closed stdout"));
}
serde_json::from_str(line.trim()).context("failed to decode Pi bridge event")
}
pub fn wait(&mut self) -> Result<()> {
self.child
.wait()
.context("failed while waiting for Pi Mono sidecar")?;
Ok(())
}
}
@@ -0,0 +1,5 @@
pub mod client;
pub mod protocol;
pub use client::PiBridgeClient;
pub use protocol::*;
@@ -0,0 +1,98 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RuntimeHandshake {
pub protocol_version: u32,
pub app_name: String,
pub app_version: String,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct RunBudget {
pub thinking_level: Option<String>,
pub token_budget: Option<u64>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RunRequest {
pub run_id: String,
pub session_id: Option<String>,
pub company_id: String,
pub task_id: Option<String>,
pub agent_id: String,
pub workspace_path: Option<String>,
pub connector_id: String,
pub model: Option<String>,
pub prompt: String,
pub context_json: serde_json::Value,
pub budget: RunBudget,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ToolApprovalDecision {
pub run_id: String,
pub tool_call_id: String,
pub approved: bool,
pub note: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SteerRequest {
pub run_id: String,
pub body: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FollowUpRequest {
pub run_id: String,
pub body: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ClientRequest {
Handshake(RuntimeHandshake),
StartRun(Box<RunRequest>),
ToolApproval(ToolApprovalDecision),
Steer(SteerRequest),
FollowUp(FollowUpRequest),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum RuntimeEvent {
HandshakeAck {
protocol_version: u32,
runtime_version: String,
},
Message {
run_id: String,
role: String,
body: String,
},
ToolCall {
run_id: String,
tool_call_id: String,
tool_name: String,
input_json: serde_json::Value,
},
ToolResult {
run_id: String,
tool_call_id: String,
output_json: serde_json::Value,
},
Artifact {
run_id: String,
provider: String,
external_id: String,
title: String,
metadata_json: serde_json::Value,
},
RunFinished {
run_id: String,
status: String,
summary: String,
session_id: Option<String>,
cost_usd: Option<f64>,
},
}