mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-16 01:03:52 +00:00
fix: correct inspector package name in Dockerfiles and add .dockerignore (#50)
* chore: remove inspect.sandboxagent.dev in favor of /ui/ * chore: add 404 page * fix: correct inspector package name in Dockerfiles and add .dockerignore - Change @anthropic-ai/sdk-inspector to @sandbox-agent/inspector in all Dockerfiles - Add .dockerignore to exclude target/, node_modules/, etc from Docker context The wrong package name caused pnpm install --filter to match nothing, so the inspector frontend was never built, resulting in binaries without the /ui/ endpoint. * chore: cargo fmt * chore(release): update version to 0.1.4-rc.7
This commit is contained in:
parent
cacb63ef17
commit
e3c030f66d
57 changed files with 927 additions and 771 deletions
|
|
@ -4,20 +4,9 @@ use serde_json::Value;
|
|||
|
||||
use crate::amp as schema;
|
||||
use crate::{
|
||||
ContentPart,
|
||||
ErrorData,
|
||||
EventConversion,
|
||||
ItemDeltaData,
|
||||
ItemEventData,
|
||||
ItemKind,
|
||||
ItemRole,
|
||||
ItemStatus,
|
||||
SessionEndedData,
|
||||
SessionEndReason,
|
||||
TerminatedBy,
|
||||
UniversalEventData,
|
||||
UniversalEventType,
|
||||
UniversalItem,
|
||||
ContentPart, ErrorData, EventConversion, ItemDeltaData, ItemEventData, ItemKind, ItemRole,
|
||||
ItemStatus, SessionEndReason, SessionEndedData, TerminatedBy, UniversalEventData,
|
||||
UniversalEventType, UniversalItem,
|
||||
};
|
||||
|
||||
static TEMP_ID: AtomicU64 = AtomicU64::new(1);
|
||||
|
|
@ -27,7 +16,9 @@ fn next_temp_id(prefix: &str) -> String {
|
|||
format!("{prefix}_{id}")
|
||||
}
|
||||
|
||||
pub fn event_to_universal(event: &schema::StreamJsonMessage) -> Result<Vec<EventConversion>, String> {
|
||||
pub fn event_to_universal(
|
||||
event: &schema::StreamJsonMessage,
|
||||
) -> Result<Vec<EventConversion>, String> {
|
||||
let mut events = Vec::new();
|
||||
match event.type_ {
|
||||
schema::StreamJsonMessageType::Message => {
|
||||
|
|
@ -49,12 +40,17 @@ pub fn event_to_universal(event: &schema::StreamJsonMessage) -> Result<Vec<Event
|
|||
let arguments = match call.arguments {
|
||||
schema::ToolCallArguments::Variant0(text) => text,
|
||||
schema::ToolCallArguments::Variant1(map) => {
|
||||
serde_json::to_string(&Value::Object(map)).unwrap_or_else(|_| "{}".to_string())
|
||||
serde_json::to_string(&Value::Object(map))
|
||||
.unwrap_or_else(|_| "{}".to_string())
|
||||
}
|
||||
};
|
||||
(call.name, arguments, call.id)
|
||||
} else {
|
||||
("unknown".to_string(), "{}".to_string(), next_temp_id("tmp_amp_tool"))
|
||||
(
|
||||
"unknown".to_string(),
|
||||
"{}".to_string(),
|
||||
next_temp_id("tmp_amp_tool"),
|
||||
)
|
||||
};
|
||||
let item = UniversalItem {
|
||||
item_id: next_temp_id("tmp_amp_tool_call"),
|
||||
|
|
@ -83,16 +79,16 @@ pub fn event_to_universal(event: &schema::StreamJsonMessage) -> Result<Vec<Event
|
|||
parent_id: None,
|
||||
kind: ItemKind::ToolResult,
|
||||
role: Some(ItemRole::Tool),
|
||||
content: vec![ContentPart::ToolResult {
|
||||
call_id,
|
||||
output,
|
||||
}],
|
||||
content: vec![ContentPart::ToolResult { call_id, output }],
|
||||
status: ItemStatus::Completed,
|
||||
};
|
||||
events.extend(item_events(item));
|
||||
}
|
||||
schema::StreamJsonMessageType::Error => {
|
||||
let message = event.error.clone().unwrap_or_else(|| "amp error".to_string());
|
||||
let message = event
|
||||
.error
|
||||
.clone()
|
||||
.unwrap_or_else(|| "amp error".to_string());
|
||||
events.push(EventConversion::new(
|
||||
UniversalEventType::Error,
|
||||
UniversalEventData::Error(ErrorData {
|
||||
|
|
|
|||
|
|
@ -3,21 +3,9 @@ use std::sync::atomic::{AtomicU64, Ordering};
|
|||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
ContentPart,
|
||||
EventConversion,
|
||||
ItemEventData,
|
||||
ItemDeltaData,
|
||||
ItemKind,
|
||||
ItemRole,
|
||||
ItemStatus,
|
||||
PermissionEventData,
|
||||
PermissionStatus,
|
||||
QuestionEventData,
|
||||
QuestionStatus,
|
||||
SessionStartedData,
|
||||
UniversalEventData,
|
||||
UniversalEventType,
|
||||
UniversalItem,
|
||||
ContentPart, EventConversion, ItemDeltaData, ItemEventData, ItemKind, ItemRole, ItemStatus,
|
||||
PermissionEventData, PermissionStatus, QuestionEventData, QuestionStatus, SessionStartedData,
|
||||
UniversalEventData, UniversalEventType, UniversalItem,
|
||||
};
|
||||
|
||||
static TEMP_ID: AtomicU64 = AtomicU64::new(1);
|
||||
|
|
@ -56,8 +44,11 @@ fn system_event_to_universal(event: &Value) -> EventConversion {
|
|||
let data = SessionStartedData {
|
||||
metadata: Some(event.clone()),
|
||||
};
|
||||
EventConversion::new(UniversalEventType::SessionStarted, UniversalEventData::SessionStarted(data))
|
||||
.with_raw(Some(event.clone()))
|
||||
EventConversion::new(
|
||||
UniversalEventType::SessionStarted,
|
||||
UniversalEventData::SessionStarted(data),
|
||||
)
|
||||
.with_raw(Some(event.clone()))
|
||||
}
|
||||
|
||||
fn assistant_event_to_universal(event: &Value, session_id: &str) -> Vec<EventConversion> {
|
||||
|
|
@ -97,12 +88,15 @@ fn assistant_event_to_universal(event: &Value, session_id: &str) -> Vec<EventCon
|
|||
);
|
||||
let is_question_tool = matches!(
|
||||
name,
|
||||
"AskUserQuestion" | "ask_user_question" | "askUserQuestion"
|
||||
"AskUserQuestion"
|
||||
| "ask_user_question"
|
||||
| "askUserQuestion"
|
||||
| "ask-user-question"
|
||||
) || is_exit_plan_mode;
|
||||
let has_question_payload = input.get("questions").is_some();
|
||||
if is_question_tool || has_question_payload {
|
||||
if let Some(question) = question_from_claude_input(&input, call_id.clone()) {
|
||||
if let Some(question) = question_from_claude_input(&input, call_id.clone())
|
||||
{
|
||||
conversions.push(
|
||||
EventConversion::new(
|
||||
UniversalEventType::QuestionRequested,
|
||||
|
|
@ -117,10 +111,7 @@ fn assistant_event_to_universal(event: &Value, session_id: &str) -> Vec<EventCon
|
|||
UniversalEventData::Question(QuestionEventData {
|
||||
question_id: call_id.clone(),
|
||||
prompt: "Approve plan execution?".to_string(),
|
||||
options: vec![
|
||||
"approve".to_string(),
|
||||
"reject".to_string(),
|
||||
],
|
||||
options: vec!["approve".to_string(), "reject".to_string()],
|
||||
response: None,
|
||||
status: QuestionStatus::Requested,
|
||||
}),
|
||||
|
|
@ -129,7 +120,8 @@ fn assistant_event_to_universal(event: &Value, session_id: &str) -> Vec<EventCon
|
|||
);
|
||||
}
|
||||
}
|
||||
let arguments = serde_json::to_string(&input).unwrap_or_else(|_| "{}".to_string());
|
||||
let arguments =
|
||||
serde_json::to_string(&input).unwrap_or_else(|_| "{}".to_string());
|
||||
let tool_item = UniversalItem {
|
||||
item_id: String::new(),
|
||||
native_item_id: Some(call_id.clone()),
|
||||
|
|
@ -369,13 +361,12 @@ fn control_request_to_universal(event: &Value) -> Result<Vec<EventConversion>, S
|
|||
.get("request")
|
||||
.and_then(Value::as_object)
|
||||
.ok_or_else(|| "missing request".to_string())?;
|
||||
let subtype = request
|
||||
.get("subtype")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("");
|
||||
let subtype = request.get("subtype").and_then(Value::as_str).unwrap_or("");
|
||||
|
||||
if subtype != "can_use_tool" {
|
||||
return Err(format!("unsupported Claude control_request subtype: {subtype}"));
|
||||
return Err(format!(
|
||||
"unsupported Claude control_request subtype: {subtype}"
|
||||
));
|
||||
}
|
||||
|
||||
let tool_name = request
|
||||
|
|
@ -387,10 +378,7 @@ fn control_request_to_universal(event: &Value) -> Result<Vec<EventConversion>, S
|
|||
.get("permission_suggestions")
|
||||
.cloned()
|
||||
.unwrap_or(Value::Null);
|
||||
let blocked_path = request
|
||||
.get("blocked_path")
|
||||
.cloned()
|
||||
.unwrap_or(Value::Null);
|
||||
let blocked_path = request.get("blocked_path").cloned().unwrap_or(Value::Null);
|
||||
|
||||
let metadata = serde_json::json!({
|
||||
"toolName": tool_name,
|
||||
|
|
|
|||
|
|
@ -2,22 +2,9 @@ use serde_json::Value;
|
|||
|
||||
use crate::codex as schema;
|
||||
use crate::{
|
||||
ContentPart,
|
||||
ErrorData,
|
||||
EventConversion,
|
||||
ItemDeltaData,
|
||||
ItemEventData,
|
||||
ItemKind,
|
||||
ItemRole,
|
||||
ItemStatus,
|
||||
ReasoningVisibility,
|
||||
SessionEndedData,
|
||||
SessionEndReason,
|
||||
SessionStartedData,
|
||||
TerminatedBy,
|
||||
UniversalEventData,
|
||||
UniversalEventType,
|
||||
UniversalItem,
|
||||
ContentPart, ErrorData, EventConversion, ItemDeltaData, ItemEventData, ItemKind, ItemRole,
|
||||
ItemStatus, ReasoningVisibility, SessionEndReason, SessionEndedData, SessionStartedData,
|
||||
TerminatedBy, UniversalEventData, UniversalEventType, UniversalItem,
|
||||
};
|
||||
|
||||
/// Convert a Codex ServerNotification to universal events.
|
||||
|
|
@ -30,14 +17,12 @@ pub fn notification_to_universal(
|
|||
let data = SessionStartedData {
|
||||
metadata: serde_json::to_value(¶ms.thread).ok(),
|
||||
};
|
||||
Ok(vec![
|
||||
EventConversion::new(
|
||||
UniversalEventType::SessionStarted,
|
||||
UniversalEventData::SessionStarted(data),
|
||||
)
|
||||
.with_native_session(Some(params.thread.id.clone()))
|
||||
.with_raw(raw),
|
||||
])
|
||||
Ok(vec![EventConversion::new(
|
||||
UniversalEventType::SessionStarted,
|
||||
UniversalEventData::SessionStarted(data),
|
||||
)
|
||||
.with_native_session(Some(params.thread.id.clone()))
|
||||
.with_raw(raw)])
|
||||
}
|
||||
schema::ServerNotification::ThreadCompacted(params) => Ok(vec![status_event(
|
||||
"thread.compacted",
|
||||
|
|
@ -77,28 +62,24 @@ pub fn notification_to_universal(
|
|||
)]),
|
||||
schema::ServerNotification::ItemStarted(params) => {
|
||||
let item = thread_item_to_item(¶ms.item, ItemStatus::InProgress);
|
||||
Ok(vec![
|
||||
EventConversion::new(
|
||||
UniversalEventType::ItemStarted,
|
||||
UniversalEventData::Item(ItemEventData { item }),
|
||||
)
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw),
|
||||
])
|
||||
Ok(vec![EventConversion::new(
|
||||
UniversalEventType::ItemStarted,
|
||||
UniversalEventData::Item(ItemEventData { item }),
|
||||
)
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw)])
|
||||
}
|
||||
schema::ServerNotification::ItemCompleted(params) => {
|
||||
let item = thread_item_to_item(¶ms.item, ItemStatus::Completed);
|
||||
Ok(vec![
|
||||
EventConversion::new(
|
||||
UniversalEventType::ItemCompleted,
|
||||
UniversalEventData::Item(ItemEventData { item }),
|
||||
)
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw),
|
||||
])
|
||||
Ok(vec![EventConversion::new(
|
||||
UniversalEventType::ItemCompleted,
|
||||
UniversalEventData::Item(ItemEventData { item }),
|
||||
)
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw)])
|
||||
}
|
||||
schema::ServerNotification::ItemAgentMessageDelta(params) => Ok(vec![
|
||||
EventConversion::new(
|
||||
schema::ServerNotification::ItemAgentMessageDelta(params) => {
|
||||
Ok(vec![EventConversion::new(
|
||||
UniversalEventType::ItemDelta,
|
||||
UniversalEventData::ItemDelta(ItemDeltaData {
|
||||
item_id: String::new(),
|
||||
|
|
@ -107,10 +88,10 @@ pub fn notification_to_universal(
|
|||
}),
|
||||
)
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw),
|
||||
]),
|
||||
schema::ServerNotification::ItemReasoningTextDelta(params) => Ok(vec![
|
||||
EventConversion::new(
|
||||
.with_raw(raw)])
|
||||
}
|
||||
schema::ServerNotification::ItemReasoningTextDelta(params) => {
|
||||
Ok(vec![EventConversion::new(
|
||||
UniversalEventType::ItemDelta,
|
||||
UniversalEventData::ItemDelta(ItemDeltaData {
|
||||
item_id: String::new(),
|
||||
|
|
@ -119,10 +100,10 @@ pub fn notification_to_universal(
|
|||
}),
|
||||
)
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw),
|
||||
]),
|
||||
schema::ServerNotification::ItemReasoningSummaryTextDelta(params) => Ok(vec![
|
||||
EventConversion::new(
|
||||
.with_raw(raw)])
|
||||
}
|
||||
schema::ServerNotification::ItemReasoningSummaryTextDelta(params) => {
|
||||
Ok(vec![EventConversion::new(
|
||||
UniversalEventType::ItemDelta,
|
||||
UniversalEventData::ItemDelta(ItemDeltaData {
|
||||
item_id: String::new(),
|
||||
|
|
@ -131,10 +112,10 @@ pub fn notification_to_universal(
|
|||
}),
|
||||
)
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw),
|
||||
]),
|
||||
schema::ServerNotification::ItemCommandExecutionOutputDelta(params) => Ok(vec![
|
||||
EventConversion::new(
|
||||
.with_raw(raw)])
|
||||
}
|
||||
schema::ServerNotification::ItemCommandExecutionOutputDelta(params) => {
|
||||
Ok(vec![EventConversion::new(
|
||||
UniversalEventType::ItemDelta,
|
||||
UniversalEventData::ItemDelta(ItemDeltaData {
|
||||
item_id: String::new(),
|
||||
|
|
@ -143,10 +124,10 @@ pub fn notification_to_universal(
|
|||
}),
|
||||
)
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw),
|
||||
]),
|
||||
schema::ServerNotification::ItemFileChangeOutputDelta(params) => Ok(vec![
|
||||
EventConversion::new(
|
||||
.with_raw(raw)])
|
||||
}
|
||||
schema::ServerNotification::ItemFileChangeOutputDelta(params) => {
|
||||
Ok(vec![EventConversion::new(
|
||||
UniversalEventType::ItemDelta,
|
||||
UniversalEventData::ItemDelta(ItemDeltaData {
|
||||
item_id: String::new(),
|
||||
|
|
@ -155,10 +136,10 @@ pub fn notification_to_universal(
|
|||
}),
|
||||
)
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw),
|
||||
]),
|
||||
schema::ServerNotification::ItemCommandExecutionTerminalInteraction(params) => Ok(vec![
|
||||
EventConversion::new(
|
||||
.with_raw(raw)])
|
||||
}
|
||||
schema::ServerNotification::ItemCommandExecutionTerminalInteraction(params) => {
|
||||
Ok(vec![EventConversion::new(
|
||||
UniversalEventType::ItemDelta,
|
||||
UniversalEventData::ItemDelta(ItemDeltaData {
|
||||
item_id: String::new(),
|
||||
|
|
@ -167,33 +148,34 @@ pub fn notification_to_universal(
|
|||
}),
|
||||
)
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw),
|
||||
]),
|
||||
.with_raw(raw)])
|
||||
}
|
||||
schema::ServerNotification::ItemMcpToolCallProgress(params) => Ok(vec![status_event(
|
||||
"mcp.progress",
|
||||
serde_json::to_string(params).ok(),
|
||||
Some(params.thread_id.clone()),
|
||||
raw,
|
||||
)]),
|
||||
schema::ServerNotification::ItemReasoningSummaryPartAdded(params) => Ok(vec![
|
||||
status_event(
|
||||
schema::ServerNotification::ItemReasoningSummaryPartAdded(params) => {
|
||||
Ok(vec![status_event(
|
||||
"reasoning.summary.part_added",
|
||||
serde_json::to_string(params).ok(),
|
||||
Some(params.thread_id.clone()),
|
||||
raw,
|
||||
),
|
||||
]),
|
||||
)])
|
||||
}
|
||||
schema::ServerNotification::Error(params) => {
|
||||
let data = ErrorData {
|
||||
message: params.error.message.clone(),
|
||||
code: None,
|
||||
details: serde_json::to_value(params).ok(),
|
||||
};
|
||||
Ok(vec![
|
||||
EventConversion::new(UniversalEventType::Error, UniversalEventData::Error(data))
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw),
|
||||
])
|
||||
Ok(vec![EventConversion::new(
|
||||
UniversalEventType::Error,
|
||||
UniversalEventData::Error(data),
|
||||
)
|
||||
.with_native_session(Some(params.thread_id.clone()))
|
||||
.with_raw(raw)])
|
||||
}
|
||||
schema::ServerNotification::RawResponseItemCompleted(params) => Ok(vec![status_event(
|
||||
"raw.item.completed",
|
||||
|
|
@ -239,7 +221,11 @@ fn thread_item_to_item(item: &schema::ThreadItem, status: ItemStatus) -> Univers
|
|||
content: vec![ContentPart::Text { text: text.clone() }],
|
||||
status,
|
||||
},
|
||||
schema::ThreadItem::Reasoning { content, id, summary } => {
|
||||
schema::ThreadItem::Reasoning {
|
||||
content,
|
||||
id,
|
||||
summary,
|
||||
} => {
|
||||
let mut parts = Vec::new();
|
||||
for line in content {
|
||||
parts.push(ContentPart::Reasoning {
|
||||
|
|
@ -295,7 +281,11 @@ fn thread_item_to_item(item: &schema::ThreadItem, status: ItemStatus) -> Univers
|
|||
status,
|
||||
}
|
||||
}
|
||||
schema::ThreadItem::FileChange { changes, id, status: file_status } => UniversalItem {
|
||||
schema::ThreadItem::FileChange {
|
||||
changes,
|
||||
id,
|
||||
status: file_status,
|
||||
} => UniversalItem {
|
||||
item_id: String::new(),
|
||||
native_item_id: Some(id.clone()),
|
||||
parent_id: None,
|
||||
|
|
@ -339,7 +329,8 @@ fn thread_item_to_item(item: &schema::ThreadItem, status: ItemStatus) -> Univers
|
|||
output,
|
||||
});
|
||||
} else {
|
||||
let arguments = serde_json::to_string(arguments).unwrap_or_else(|_| "{}".to_string());
|
||||
let arguments =
|
||||
serde_json::to_string(arguments).unwrap_or_else(|_| "{}".to_string());
|
||||
parts.push(ContentPart::ToolCall {
|
||||
name: format!("{server}.{tool}"),
|
||||
arguments,
|
||||
|
|
@ -433,18 +424,12 @@ fn thread_item_to_item(item: &schema::ThreadItem, status: ItemStatus) -> Univers
|
|||
}],
|
||||
status,
|
||||
},
|
||||
schema::ThreadItem::EnteredReviewMode { id, review } => status_item_internal(
|
||||
id,
|
||||
"review.entered",
|
||||
Some(review.clone()),
|
||||
status,
|
||||
),
|
||||
schema::ThreadItem::ExitedReviewMode { id, review } => status_item_internal(
|
||||
id,
|
||||
"review.exited",
|
||||
Some(review.clone()),
|
||||
status,
|
||||
),
|
||||
schema::ThreadItem::EnteredReviewMode { id, review } => {
|
||||
status_item_internal(id, "review.entered", Some(review.clone()), status)
|
||||
}
|
||||
schema::ThreadItem::ExitedReviewMode { id, review } => {
|
||||
status_item_internal(id, "review.exited", Some(review.clone()), status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -463,7 +448,12 @@ fn status_item(label: &str, detail: Option<String>) -> UniversalItem {
|
|||
}
|
||||
}
|
||||
|
||||
fn status_item_internal(id: &str, label: &str, detail: Option<String>, status: ItemStatus) -> UniversalItem {
|
||||
fn status_item_internal(
|
||||
id: &str,
|
||||
label: &str,
|
||||
detail: Option<String>,
|
||||
status: ItemStatus,
|
||||
) -> UniversalItem {
|
||||
UniversalItem {
|
||||
item_id: String::new(),
|
||||
native_item_id: Some(id.to_string()),
|
||||
|
|
|
|||
|
|
@ -2,46 +2,42 @@ use serde_json::Value;
|
|||
|
||||
use crate::opencode as schema;
|
||||
use crate::{
|
||||
ContentPart,
|
||||
EventConversion,
|
||||
ItemDeltaData,
|
||||
ItemEventData,
|
||||
ItemKind,
|
||||
ItemRole,
|
||||
ItemStatus,
|
||||
PermissionEventData,
|
||||
PermissionStatus,
|
||||
QuestionEventData,
|
||||
QuestionStatus,
|
||||
SessionStartedData,
|
||||
UniversalEventData,
|
||||
UniversalEventType,
|
||||
UniversalItem,
|
||||
ContentPart, EventConversion, ItemDeltaData, ItemEventData, ItemKind, ItemRole, ItemStatus,
|
||||
PermissionEventData, PermissionStatus, QuestionEventData, QuestionStatus, SessionStartedData,
|
||||
UniversalEventData, UniversalEventType, UniversalItem,
|
||||
};
|
||||
|
||||
pub fn event_to_universal(event: &schema::Event) -> Result<Vec<EventConversion>, String> {
|
||||
let raw = serde_json::to_value(event).ok();
|
||||
match event {
|
||||
schema::Event::MessageUpdated(updated) => {
|
||||
let schema::EventMessageUpdated { properties, type_: _ } = updated;
|
||||
let schema::EventMessageUpdated {
|
||||
properties,
|
||||
type_: _,
|
||||
} = updated;
|
||||
let schema::EventMessageUpdatedProperties { info } = properties;
|
||||
let (mut item, completed, session_id) = message_to_item(info);
|
||||
item.status = if completed { ItemStatus::Completed } else { ItemStatus::InProgress };
|
||||
item.status = if completed {
|
||||
ItemStatus::Completed
|
||||
} else {
|
||||
ItemStatus::InProgress
|
||||
};
|
||||
let event_type = if completed {
|
||||
UniversalEventType::ItemCompleted
|
||||
} else {
|
||||
UniversalEventType::ItemStarted
|
||||
};
|
||||
let conversion = EventConversion::new(
|
||||
event_type,
|
||||
UniversalEventData::Item(ItemEventData { item }),
|
||||
)
|
||||
.with_native_session(session_id)
|
||||
.with_raw(raw);
|
||||
let conversion =
|
||||
EventConversion::new(event_type, UniversalEventData::Item(ItemEventData { item }))
|
||||
.with_native_session(session_id)
|
||||
.with_raw(raw);
|
||||
Ok(vec![conversion])
|
||||
}
|
||||
schema::Event::MessagePartUpdated(updated) => {
|
||||
let schema::EventMessagePartUpdated { properties, type_: _ } = updated;
|
||||
let schema::EventMessagePartUpdated {
|
||||
properties,
|
||||
type_: _,
|
||||
} = updated;
|
||||
let schema::EventMessagePartUpdatedProperties { part, delta } = properties;
|
||||
let mut events = Vec::new();
|
||||
let (session_id, message_id) = part_session_message(part);
|
||||
|
|
@ -122,11 +118,16 @@ pub fn event_to_universal(event: &schema::Event) -> Result<Vec<EventConversion>,
|
|||
schema::Part::Variant4(tool_part) => {
|
||||
let tool_events = tool_part_to_events(&tool_part, &message_id);
|
||||
for event in tool_events {
|
||||
events.push(event.with_native_session(session_id.clone()).with_raw(raw.clone()));
|
||||
events.push(
|
||||
event
|
||||
.with_native_session(session_id.clone())
|
||||
.with_raw(raw.clone()),
|
||||
);
|
||||
}
|
||||
}
|
||||
schema::Part::Variant1 { .. } => {
|
||||
let detail = serde_json::to_string(part).unwrap_or_else(|_| "subtask".to_string());
|
||||
let detail =
|
||||
serde_json::to_string(part).unwrap_or_else(|_| "subtask".to_string());
|
||||
let item = status_item("subtask", Some(detail));
|
||||
events.push(
|
||||
EventConversion::new(
|
||||
|
|
@ -160,7 +161,10 @@ pub fn event_to_universal(event: &schema::Event) -> Result<Vec<EventConversion>,
|
|||
Ok(events)
|
||||
}
|
||||
schema::Event::QuestionAsked(asked) => {
|
||||
let schema::EventQuestionAsked { properties, type_: _ } = asked;
|
||||
let schema::EventQuestionAsked {
|
||||
properties,
|
||||
type_: _,
|
||||
} = asked;
|
||||
let question = question_from_opencode(properties);
|
||||
let conversion = EventConversion::new(
|
||||
UniversalEventType::QuestionRequested,
|
||||
|
|
@ -171,7 +175,10 @@ pub fn event_to_universal(event: &schema::Event) -> Result<Vec<EventConversion>,
|
|||
Ok(vec![conversion])
|
||||
}
|
||||
schema::Event::PermissionAsked(asked) => {
|
||||
let schema::EventPermissionAsked { properties, type_: _ } = asked;
|
||||
let schema::EventPermissionAsked {
|
||||
properties,
|
||||
type_: _,
|
||||
} = asked;
|
||||
let permission = permission_from_opencode(properties);
|
||||
let conversion = EventConversion::new(
|
||||
UniversalEventType::PermissionRequested,
|
||||
|
|
@ -182,7 +189,10 @@ pub fn event_to_universal(event: &schema::Event) -> Result<Vec<EventConversion>,
|
|||
Ok(vec![conversion])
|
||||
}
|
||||
schema::Event::SessionCreated(created) => {
|
||||
let schema::EventSessionCreated { properties, type_: _ } = created;
|
||||
let schema::EventSessionCreated {
|
||||
properties,
|
||||
type_: _,
|
||||
} = created;
|
||||
let metadata = serde_json::to_value(&properties.info).ok();
|
||||
let conversion = EventConversion::new(
|
||||
UniversalEventType::SessionStarted,
|
||||
|
|
@ -193,8 +203,12 @@ pub fn event_to_universal(event: &schema::Event) -> Result<Vec<EventConversion>,
|
|||
Ok(vec![conversion])
|
||||
}
|
||||
schema::Event::SessionStatus(status) => {
|
||||
let schema::EventSessionStatus { properties, type_: _ } = status;
|
||||
let detail = serde_json::to_string(&properties.status).unwrap_or_else(|_| "status".to_string());
|
||||
let schema::EventSessionStatus {
|
||||
properties,
|
||||
type_: _,
|
||||
} = status;
|
||||
let detail =
|
||||
serde_json::to_string(&properties.status).unwrap_or_else(|_| "status".to_string());
|
||||
let item = status_item("session.status", Some(detail));
|
||||
let conversion = EventConversion::new(
|
||||
UniversalEventType::ItemCompleted,
|
||||
|
|
@ -205,7 +219,10 @@ pub fn event_to_universal(event: &schema::Event) -> Result<Vec<EventConversion>,
|
|||
Ok(vec![conversion])
|
||||
}
|
||||
schema::Event::SessionIdle(idle) => {
|
||||
let schema::EventSessionIdle { properties, type_: _ } = idle;
|
||||
let schema::EventSessionIdle {
|
||||
properties,
|
||||
type_: _,
|
||||
} = idle;
|
||||
let item = status_item("session.idle", None);
|
||||
let conversion = EventConversion::new(
|
||||
UniversalEventType::ItemCompleted,
|
||||
|
|
@ -216,8 +233,12 @@ pub fn event_to_universal(event: &schema::Event) -> Result<Vec<EventConversion>,
|
|||
Ok(vec![conversion])
|
||||
}
|
||||
schema::Event::SessionError(error) => {
|
||||
let schema::EventSessionError { properties, type_: _ } = error;
|
||||
let detail = serde_json::to_string(&properties.error).unwrap_or_else(|_| "session error".to_string());
|
||||
let schema::EventSessionError {
|
||||
properties,
|
||||
type_: _,
|
||||
} = error;
|
||||
let detail = serde_json::to_string(&properties.error)
|
||||
.unwrap_or_else(|_| "session error".to_string());
|
||||
let item = status_item("session.error", Some(detail));
|
||||
let conversion = EventConversion::new(
|
||||
UniversalEventType::ItemCompleted,
|
||||
|
|
@ -270,7 +291,11 @@ fn message_to_item(message: &schema::Message) -> (UniversalItem, bool, Option<St
|
|||
kind: ItemKind::Message,
|
||||
role: Some(ItemRole::Assistant),
|
||||
content: Vec::new(),
|
||||
status: if completed { ItemStatus::Completed } else { ItemStatus::InProgress },
|
||||
status: if completed {
|
||||
ItemStatus::Completed
|
||||
} else {
|
||||
ItemStatus::InProgress
|
||||
},
|
||||
},
|
||||
completed,
|
||||
Some(session_id.clone()),
|
||||
|
|
@ -281,9 +306,10 @@ fn message_to_item(message: &schema::Message) -> (UniversalItem, bool, Option<St
|
|||
|
||||
fn part_session_message(part: &schema::Part) -> (Option<String>, String) {
|
||||
match part {
|
||||
schema::Part::Variant0(text_part) => {
|
||||
(Some(text_part.session_id.clone()), text_part.message_id.clone())
|
||||
}
|
||||
schema::Part::Variant0(text_part) => (
|
||||
Some(text_part.session_id.clone()),
|
||||
text_part.message_id.clone(),
|
||||
),
|
||||
schema::Part::Variant1 {
|
||||
session_id,
|
||||
message_id,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use schemars::JsonSchema;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub use sandbox_agent_extracted_agent_schemas::{amp, claude, codex, opencode};
|
||||
|
||||
pub mod agents;
|
||||
|
||||
pub use agents::{amp as convert_amp, claude as convert_claude, codex as convert_codex, opencode as convert_opencode};
|
||||
pub use agents::{
|
||||
amp as convert_amp, claude as convert_claude, codex as convert_codex,
|
||||
opencode as convert_opencode,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct UniversalEvent {
|
||||
|
|
@ -221,14 +224,38 @@ pub enum ItemStatus {
|
|||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum ContentPart {
|
||||
Text { text: String },
|
||||
Json { json: Value },
|
||||
ToolCall { name: String, arguments: String, call_id: String },
|
||||
ToolResult { call_id: String, output: String },
|
||||
FileRef { path: String, action: FileAction, diff: Option<String> },
|
||||
Reasoning { text: String, visibility: ReasoningVisibility },
|
||||
Image { path: String, mime: Option<String> },
|
||||
Status { label: String, detail: Option<String> },
|
||||
Text {
|
||||
text: String,
|
||||
},
|
||||
Json {
|
||||
json: Value,
|
||||
},
|
||||
ToolCall {
|
||||
name: String,
|
||||
arguments: String,
|
||||
call_id: String,
|
||||
},
|
||||
ToolResult {
|
||||
call_id: String,
|
||||
output: String,
|
||||
},
|
||||
FileRef {
|
||||
path: String,
|
||||
action: FileAction,
|
||||
diff: Option<String>,
|
||||
},
|
||||
Reasoning {
|
||||
text: String,
|
||||
visibility: ReasoningVisibility,
|
||||
},
|
||||
Image {
|
||||
path: String,
|
||||
mime: Option<String>,
|
||||
},
|
||||
Status {
|
||||
label: String,
|
||||
detail: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue