Consolidate the browser task runtime around the callback path, add safer artifact opening for Zhihu exports, and cover the new service/browser flows with focused tests and supporting docs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
119 lines
3.9 KiB
Rust
119 lines
3.9 KiB
Rust
use sgclaw::pipe::{
|
|
Action, AgentMessage, BrowserMessage, ExecutionSurfaceKind, SecurityFields, Timing,
|
|
};
|
|
|
|
#[test]
|
|
fn browser_init_round_trip_uses_frozen_wire_format() {
|
|
let raw = r#"{"type":"init","version":"1.0","hmac_seed":"0123456789abcdef","capabilities":["browser_action"]}"#;
|
|
let message: BrowserMessage = serde_json::from_str(raw).unwrap();
|
|
|
|
assert!(matches!(
|
|
message,
|
|
BrowserMessage::Init {
|
|
ref version,
|
|
ref hmac_seed,
|
|
ref capabilities
|
|
} if version == "1.0"
|
|
&& hmac_seed == "0123456789abcdef"
|
|
&& *capabilities == vec!["browser_action".to_string()]
|
|
));
|
|
|
|
assert_eq!(serde_json::to_string(&message).unwrap(), raw);
|
|
}
|
|
|
|
#[test]
|
|
fn browser_lifecycle_messages_use_frozen_wire_tags() {
|
|
let connect_raw = r#"{"type":"connect"}"#;
|
|
let start_raw = r#"{"type":"start"}"#;
|
|
let stop_raw = r#"{"type":"stop"}"#;
|
|
|
|
let connect: BrowserMessage = serde_json::from_str(connect_raw).unwrap();
|
|
let start: BrowserMessage = serde_json::from_str(start_raw).unwrap();
|
|
let stop: BrowserMessage = serde_json::from_str(stop_raw).unwrap();
|
|
|
|
assert_eq!(connect, BrowserMessage::Connect);
|
|
assert_eq!(start, BrowserMessage::Start);
|
|
assert_eq!(stop, BrowserMessage::Stop);
|
|
assert_eq!(serde_json::to_string(&connect).unwrap(), connect_raw);
|
|
assert_eq!(serde_json::to_string(&start).unwrap(), start_raw);
|
|
assert_eq!(serde_json::to_string(&stop).unwrap(), stop_raw);
|
|
}
|
|
|
|
#[test]
|
|
fn command_serializes_action_and_security_fields() {
|
|
let message = AgentMessage::Command {
|
|
seq: 1,
|
|
action: Action::GetText,
|
|
params: serde_json::json!({ "selector": "#submit" }),
|
|
security: SecurityFields {
|
|
expected_domain: "oa.example.com".to_string(),
|
|
hmac: "abc123".to_string(),
|
|
},
|
|
};
|
|
|
|
let raw = serde_json::to_string(&message).unwrap();
|
|
|
|
assert!(raw.contains(r#""type":"command""#));
|
|
assert!(raw.contains(r#""action":"getText""#));
|
|
assert!(raw.contains(r#""expected_domain":"oa.example.com""#));
|
|
}
|
|
|
|
#[test]
|
|
fn agent_status_changed_serializes_with_expected_tag() {
|
|
let raw = serde_json::to_string(&AgentMessage::StatusChanged {
|
|
state: "started".to_string(),
|
|
})
|
|
.unwrap();
|
|
|
|
assert_eq!(raw, r#"{"type":"status_changed","state":"started"}"#);
|
|
}
|
|
|
|
#[test]
|
|
fn response_deserializes_timing_and_payload() {
|
|
let raw = r#"{"type":"response","seq":7,"success":true,"data":{"text":"提交成功"},"aom_snapshot":[],"timing":{"queue_ms":2,"exec_ms":38}}"#;
|
|
let message: BrowserMessage = serde_json::from_str(raw).unwrap();
|
|
|
|
assert_eq!(
|
|
message,
|
|
BrowserMessage::Response {
|
|
seq: 7,
|
|
success: true,
|
|
data: serde_json::json!({"text": "提交成功"}),
|
|
aom_snapshot: vec![],
|
|
timing: Timing {
|
|
queue_ms: 2,
|
|
exec_ms: 38,
|
|
},
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn submit_task_exposes_browser_context_without_implying_browser_only_runtime() {
|
|
let message = BrowserMessage::SubmitTask {
|
|
instruction: "统计一下知乎热榜".to_string(),
|
|
conversation_id: "conversation-1".to_string(),
|
|
messages: vec![],
|
|
page_url: "https://www.zhihu.com/hot".to_string(),
|
|
page_title: "知乎热榜".to_string(),
|
|
};
|
|
|
|
let context = message.browser_context().expect("browser context");
|
|
let surface = message
|
|
.requested_surface_metadata()
|
|
.expect("surface metadata");
|
|
|
|
assert_eq!(context.page_url, "https://www.zhihu.com/hot");
|
|
assert_eq!(context.page_title, "知乎热榜");
|
|
assert_eq!(surface.kind, ExecutionSurfaceKind::PrivilegedBrowserPipe);
|
|
assert!(surface.privileged);
|
|
assert!(!surface.defines_runtime_identity);
|
|
}
|
|
|
|
#[test]
|
|
fn supported_actions_include_browser_script_execution() {
|
|
let supported = sgclaw::pipe::supported_actions();
|
|
|
|
assert!(supported.iter().any(|action| action.as_str() == "eval"));
|
|
}
|