73 lines
2.6 KiB
Rust
73 lines
2.6 KiB
Rust
//! Phase 1 sub-Worker への入力テキスト組み立て。
|
||
//!
|
||
//! `crates/pod/src/pod.rs::build_summary_prompt` と同じ方針で
|
||
//! Item 列を flat な行に落とす(reasoning は省く、tool call は名前のみ、
|
||
//! tool result は summary のみ)。conversation 全体を Markdown の単一
|
||
//! セクションとして渡し、抽出指示は system prompt 側に寄せる。
|
||
|
||
use llm_worker::Item;
|
||
|
||
/// 与えられた `items` を Phase 1 sub-Worker の最初の user 入力に整形する。
|
||
pub fn build_extract_input(items: &[Item]) -> String {
|
||
let mut out = String::new();
|
||
out.push_str(
|
||
"Extract activity logs from the conversation slice below. \
|
||
Follow the system prompt's schema strictly and call `write_extracted` once.\n\n",
|
||
);
|
||
out.push_str("## Conversation slice\n");
|
||
out.push_str(&render_items(items));
|
||
out.push_str("\n\nWhen you are done, call `write_extracted` and end the turn.");
|
||
out
|
||
}
|
||
|
||
fn render_items(items: &[Item]) -> String {
|
||
let mut lines: Vec<String> = Vec::new();
|
||
for item in items {
|
||
match item {
|
||
Item::Message { role, content, .. } => {
|
||
let role_label = match role {
|
||
llm_worker::Role::User => "User",
|
||
llm_worker::Role::Assistant => "Assistant",
|
||
llm_worker::Role::System => "System",
|
||
};
|
||
let text: String = content
|
||
.iter()
|
||
.map(|p| p.as_text())
|
||
.collect::<Vec<_>>()
|
||
.join("");
|
||
lines.push(format!("[{role_label}] {text}"));
|
||
}
|
||
Item::ToolCall { name, .. } => {
|
||
lines.push(format!("[ToolCall] {name}"));
|
||
}
|
||
Item::ToolResult { summary, .. } => {
|
||
lines.push(format!("[ToolResult] {summary}"));
|
||
}
|
||
Item::Reasoning { .. } => {}
|
||
}
|
||
}
|
||
lines.join("\n\n")
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn renders_user_assistant_pair_and_tool_calls() {
|
||
let items = vec![
|
||
Item::user_message("hello"),
|
||
Item::assistant_message("hi"),
|
||
Item::tool_call("c1", "read_file", "{}"),
|
||
Item::tool_result("c1", "ok"),
|
||
Item::reasoning("internal scratch — should be skipped"),
|
||
];
|
||
let s = build_extract_input(&items);
|
||
assert!(s.contains("[User] hello"));
|
||
assert!(s.contains("[Assistant] hi"));
|
||
assert!(s.contains("[ToolCall] read_file"));
|
||
assert!(s.contains("[ToolResult] ok"));
|
||
assert!(!s.contains("scratch"));
|
||
}
|
||
}
|