Signed-off-by: 未知时光 <732857315@qq.com>

This commit is contained in:
2026-06-09 16:23:24 +08:00
parent 1bf1f08f9a
commit f7919eca40
13 changed files with 1206 additions and 1 deletions

117
plugins/hermes/src/main.rs Normal file
View File

@@ -0,0 +1,117 @@
use agentsd_plugin_sdk::{
decode_json, err_json, export, listen_addr_from_env, ok_json, plugin_endpoint_from_env,
plugin_info_with_endpoint, register,
};
use agentsd_proto::agentsd::{
plugin_bridge_server::{PluginBridge, PluginBridgeServer},
CallRequest, CallResponse, HeartbeatRequest, HeartbeatResponse, PluginInfo, RegisterResponse,
};
use anyhow::{ensure, Result};
use serde::Deserialize;
use serde_json::json;
use tokio::net::TcpListener;
use tokio_stream::wrappers::TcpListenerStream;
use tonic::{transport::Server, Request, Response, Status};
const PLUGIN_ID: &str = "hermes";
const PLUGIN_NAME: &str = "Hermes Agent Tools";
const PLUGIN_VERSION: &str = "0.16.0";
const PLUGIN_TYPE: &str = "basic";
const PLUGIN_PORT: u16 = 50052;
const SYSCALLS: &[&str] = &[
"network.request",
"fs.read",
"fs.write",
"process.spawn",
"memory.read",
"memory.write",
"display.text",
"timer.once",
];
#[derive(Default)]
struct HermesPlugin;
#[derive(Deserialize)]
struct EchoArgs {
#[serde(default)]
text: String,
}
#[tonic::async_trait]
impl PluginBridge for HermesPlugin {
async fn register(
&self,
_req: Request<PluginInfo>,
) -> std::result::Result<Response<RegisterResponse>, Status> {
Err(Status::unimplemented("hermes plugin is not an agentsd bridge"))
}
async fn call(
&self,
req: Request<CallRequest>,
) -> std::result::Result<Response<CallResponse>, Status> {
let req = req.into_inner();
let response = match req.r#fn.as_str() {
"echo" => match decode_json::<EchoArgs>(&req.args) {
Ok(args) => ok_json(&json!({ "result": format!("hermes: {}", args.text) })),
Err(err) => err_json(format!("invalid echo args: {err}")),
},
other => err_json(format!("unknown export: {other}")),
};
Ok(Response::new(response))
}
type StreamCallStream = tokio_stream::wrappers::ReceiverStream<std::result::Result<CallResponse, Status>>;
async fn stream_call(
&self,
_req: Request<CallRequest>,
) -> std::result::Result<Response<Self::StreamCallStream>, Status> {
Err(Status::unimplemented("stream_call is not implemented for hermes"))
}
async fn heartbeat(
&self,
_req: Request<HeartbeatRequest>,
) -> std::result::Result<Response<HeartbeatResponse>, Status> {
Ok(Response::new(HeartbeatResponse { ok: true }))
}
}
fn plugin_info(endpoint: &str) -> PluginInfo {
plugin_info_with_endpoint(
PLUGIN_ID,
PLUGIN_NAME,
PLUGIN_VERSION,
PLUGIN_TYPE,
SYSCALLS,
&[],
vec![export("echo", "Echo test route for Hermes plugin")],
endpoint,
)
}
#[tokio::main]
async fn main() -> Result<()> {
let endpoint = plugin_endpoint_from_env(PLUGIN_PORT);
let listen_addr: std::net::SocketAddr = listen_addr_from_env(PLUGIN_PORT).parse()?;
let listener = TcpListener::bind(listen_addr).await?;
let incoming = TcpListenerStream::new(listener);
let channel = agentsd_plugin_sdk::connect().await?;
let resp = register(channel, plugin_info(&endpoint)).await?;
ensure!(resp.ok, "register failed: {}", resp.error);
println!(
"Hermes plugin registered: id={} type={} endpoint={} session={}",
PLUGIN_ID, PLUGIN_TYPE, endpoint, resp.session_id
);
println!("Hermes PluginBridge server listening on {}", listen_addr);
Server::builder()
.add_service(PluginBridgeServer::new(HermesPlugin::default()))
.serve_with_incoming(incoming)
.await?;
Ok(())
}