mirror of
https://github.com/openai/codex.git
synced 2026-11-13 21:30:47 +00:00
feat(executor): add executor protocol and runtime crates
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "codex-executor-protocol"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "codex_executor_protocol"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = { workspace = true }
|
||||
@@ -0,0 +1,189 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExecutorToolSpec {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub input_schema: JsonValue,
|
||||
}
|
||||
|
||||
impl ExecutorToolSpec {
|
||||
pub fn new(
|
||||
name: impl Into<String>,
|
||||
description: impl Into<String>,
|
||||
input_schema: JsonValue,
|
||||
) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
description: description.into(),
|
||||
input_schema,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ListToolsRequest {
|
||||
pub request_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallToolRequest {
|
||||
pub request_id: String,
|
||||
pub tool_name: String,
|
||||
pub arguments: JsonValue,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ShutdownRequest {
|
||||
pub request_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum OrchestratorToExecutorMessage {
|
||||
ListTools(ListToolsRequest),
|
||||
CallTool(CallToolRequest),
|
||||
Shutdown(ShutdownRequest),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ListToolsResponse {
|
||||
pub request_id: String,
|
||||
pub tools: Vec<ExecutorToolSpec>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum ToolCallContent {
|
||||
InputText { text: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(tag = "status", rename_all = "snake_case")]
|
||||
pub enum ToolCallOutcome {
|
||||
Success { content: Vec<ToolCallContent> },
|
||||
Error { message: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallToolResponse {
|
||||
pub request_id: String,
|
||||
pub tool_name: String,
|
||||
pub outcome: ToolCallOutcome,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ShutdownResponse {
|
||||
pub request_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ErrorResponse {
|
||||
pub request_id: Option<String>,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum ExecutorToOrchestratorMessage {
|
||||
ListToolsResponse(ListToolsResponse),
|
||||
CallToolResponse(CallToolResponse),
|
||||
ShutdownResponse(ShutdownResponse),
|
||||
Error(ErrorResponse),
|
||||
}
|
||||
|
||||
impl ExecutorToOrchestratorMessage {
|
||||
pub fn error(request_id: Option<String>, message: impl Into<String>) -> Self {
|
||||
Self::Error(ErrorResponse {
|
||||
request_id,
|
||||
message: message.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::CallToolRequest;
|
||||
use super::ExecutorToOrchestratorMessage;
|
||||
use super::ExecutorToolSpec;
|
||||
use super::ListToolsResponse;
|
||||
use super::OrchestratorToExecutorMessage;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn list_tools_response_round_trips_with_camel_case_fields() {
|
||||
let message = ExecutorToOrchestratorMessage::ListToolsResponse(ListToolsResponse {
|
||||
request_id: "req-1".to_string(),
|
||||
tools: vec![ExecutorToolSpec::new(
|
||||
"exec_command",
|
||||
"Run a command",
|
||||
json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cmd": {"type": "string"},
|
||||
},
|
||||
"required": ["cmd"],
|
||||
}),
|
||||
)],
|
||||
});
|
||||
|
||||
let value = serde_json::to_value(&message).expect("serialize");
|
||||
assert_eq!(
|
||||
value,
|
||||
json!({
|
||||
"type": "list_tools_response",
|
||||
"requestId": "req-1",
|
||||
"tools": [{
|
||||
"name": "exec_command",
|
||||
"description": "Run a command",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cmd": {"type": "string"},
|
||||
},
|
||||
"required": ["cmd"],
|
||||
},
|
||||
}],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_tool_request_round_trips() {
|
||||
let value = json!({
|
||||
"type": "call_tool",
|
||||
"requestId": "req-2",
|
||||
"toolName": "exec_command",
|
||||
"arguments": {
|
||||
"cmd": "pwd",
|
||||
},
|
||||
});
|
||||
|
||||
let actual: OrchestratorToExecutorMessage =
|
||||
serde_json::from_value(value.clone()).expect("deserialize");
|
||||
|
||||
assert_eq!(
|
||||
actual,
|
||||
OrchestratorToExecutorMessage::CallTool(CallToolRequest {
|
||||
request_id: "req-2".to_string(),
|
||||
tool_name: "exec_command".to_string(),
|
||||
arguments: json!({
|
||||
"cmd": "pwd",
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
assert_eq!(serde_json::to_value(actual).expect("serialize"), value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user