poe2-agent 0.5.0

AI agent for Path of Exile 2 build analysis
Documentation
//! Single-turn query agent: takes parsed build data + user question,
//! streams an LLM response with the build as context.

use futures_core::Stream;

use crate::llm::{input_message, ChatGptClient, LlmError, ResponseStreamEvent};

const SYSTEM_PROMPT: &str = "\
You are a Path of Exile 2 build analysis assistant. The user has uploaded \
their Path of Building export and you have access to their parsed build stats.\n\
\n\
Answer the user's questions about their build. Be specific and reference \
actual numbers from the build data when relevant. If the data doesn't contain \
enough information to answer, say so.\n\
\n\
Here is the parsed build data:\n";

/// Answers questions about a PoB build using an LLM with injected context.
pub struct QueryAgent {
    llm: ChatGptClient,
}

impl QueryAgent {
    pub fn new(llm: ChatGptClient) -> Self {
        Self { llm }
    }

    /// Stream a response to a user question about the given build.
    ///
    /// `build_json` is the JSON output from `PobParser::parse`.
    pub fn respond(
        &self,
        build_json: &[u8],
        message: &str,
    ) -> impl Stream<Item = Result<String, LlmError>> + Send {
        let instructions = format!(
            "{SYSTEM_PROMPT}```json\n{}\n```",
            String::from_utf8_lossy(build_json),
        );

        let input = vec![input_message("user", message)];
        let stream = self
            .llm
            .create_response_stream(&input, Some(&instructions), None, None);

        async_stream::stream! {
            tokio::pin!(stream);
            while let Some(event) = futures_lite::StreamExt::next(&mut stream).await {
                match event {
                    Ok(ResponseStreamEvent::TextDelta(t)) => yield Ok(t),
                    Err(e) => { yield Err(e); return; }
                    _ => {} // ignore function calls, usage
                }
            }
        }
    }
}