use super::*;
#[test]
fn timeline_entry_from_thread_item_infers_low_confidence_semantics_for_responses_calls() {
let shell_entry = timeline_entry_from_thread_item(
PRIMARY_RUNTIME_ID,
"thread-1",
Some("turn-3"),
&json!({
"id": "item-shell",
"type": "shell_call",
"call_id": "call-shell",
"command": "bash -lc 'sed -n \"1,20p\" bridge/src/state/timeline.rs'"
}),
"thread_item",
false,
true,
)
.expect("应创建 shell_call 时间线条目");
assert_eq!(
Some("explored"),
shell_entry
.metadata
.get("semantic")
.and_then(|value| value.get("kind"))
.and_then(Value::as_str),
);
assert_eq!(
Some("read"),
shell_entry
.metadata
.get("semantic")
.and_then(|value| value.get("detail"))
.and_then(Value::as_str),
);
assert_eq!(
Some("low"),
shell_entry
.metadata
.get("semantic")
.and_then(|value| value.get("confidence"))
.and_then(Value::as_str),
);
let web_search_entry = timeline_entry_from_thread_item(
PRIMARY_RUNTIME_ID,
"thread-1",
Some("turn-3"),
&json!({
"id": "item-web-search",
"type": "web_search_call",
"call_id": "call-search",
"query": "Codex CLI TUI"
}),
"thread_item",
false,
true,
)
.expect("应创建 web_search_call 时间线条目");
assert_eq!(
Some("explored"),
web_search_entry
.metadata
.get("semantic")
.and_then(|value| value.get("kind"))
.and_then(Value::as_str),
);
assert_eq!(
Some("search"),
web_search_entry
.metadata
.get("semantic")
.and_then(|value| value.get("detail"))
.and_then(Value::as_str),
);
assert_eq!(
Some("Codex CLI TUI"),
web_search_entry
.metadata
.get("summary")
.and_then(|value| value.get("query"))
.and_then(Value::as_str),
);
let patch_entry = timeline_entry_from_thread_item(
PRIMARY_RUNTIME_ID,
"thread-1",
Some("turn-3"),
&json!({
"id": "item-patch",
"type": "apply_patch_call",
"call_id": "call-patch",
"operation": "*** Begin Patch\n*** Update File: android/app/src/main/java/com/agguy/codexmobile/app/WorkbenchTimeline.kt\n@@\n-old\n+new\n*** End Patch\n"
}),
"thread_item",
false,
true,
)
.expect("应创建 apply_patch_call 时间线条目");
assert_eq!(
Some("edited"),
patch_entry
.metadata
.get("semantic")
.and_then(|value| value.get("kind"))
.and_then(Value::as_str),
);
assert_eq!(
Some("low"),
patch_entry
.metadata
.get("semantic")
.and_then(|value| value.get("confidence"))
.and_then(Value::as_str),
);
assert_eq!(
Some("android/app/src/main/java/com/agguy/codexmobile/app/WorkbenchTimeline.kt"),
patch_entry
.metadata
.get("summary")
.and_then(|value| value.get("primaryPath"))
.and_then(Value::as_str),
);
}
#[test]
fn timeline_entries_from_thread_inherit_semantic_summary_for_output_calls() {
let thread = json!({
"id": "thread-1",
"turns": [
{
"id": "turn-4",
"items": [
{
"id": "item-shell",
"type": "shell_call",
"call_id": "call-shell",
"command": "bash -lc 'sed -n \"1,20p\" bridge/src/state/timeline.rs'",
"status": "completed"
},
{
"id": "item-shell-output",
"type": "shell_call_output",
"call_id": "call-shell",
"output": "line-1\nline-2",
"status": "completed"
},
{
"id": "item-patch",
"type": "apply_patch_call",
"call_id": "call-patch",
"operation": "*** Begin Patch\n*** Update File: docs/timeline.md\n@@\n-old\n+new\n*** End Patch\n",
"status": "completed"
},
{
"id": "item-patch-output",
"type": "apply_patch_call_output",
"call_id": "call-patch",
"output": "*** Begin Patch\n*** Update File: docs/timeline.md\n@@\n-old\n+new\n*** End Patch\n",
"status": "completed"
}
]
}
]
});
let entries = timeline_entries_from_thread(PRIMARY_RUNTIME_ID, &thread)
.expect("应从 thread 构建时间线条目");
let shell_output = entries
.iter()
.find(|entry| entry.entry_type == "shell_call_output")
.expect("应存在 shell_call_output");
assert_eq!(
Some("explored"),
shell_output
.metadata
.get("semantic")
.and_then(|value| value.get("kind"))
.and_then(Value::as_str),
);
assert_eq!(
Some("output"),
shell_output
.metadata
.get("semantic")
.and_then(|value| value.get("role"))
.and_then(Value::as_str),
);
assert_eq!(
Some("bash -lc 'sed -n \"1,20p\" bridge/src/state/timeline.rs'"),
shell_output
.metadata
.get("summary")
.and_then(|value| value.get("command"))
.and_then(Value::as_str),
);
let patch_output = entries
.iter()
.find(|entry| entry.entry_type == "apply_patch_call_output")
.expect("应存在 apply_patch_call_output");
assert_eq!(
Some("edited"),
patch_output
.metadata
.get("semantic")
.and_then(|value| value.get("kind"))
.and_then(Value::as_str),
);
assert_eq!(
Some("output"),
patch_output
.metadata
.get("semantic")
.and_then(|value| value.get("role"))
.and_then(Value::as_str),
);
assert_eq!(
Some("docs/timeline.md"),
patch_output
.metadata
.get("summary")
.and_then(|value| value.get("primaryPath"))
.and_then(Value::as_str),
);
}