sim-lib-openai-server 0.1.0

OpenAI-compatible gateway skeleton for SIM.
Documentation
use sim_kernel::Expr;
use sim_lib_agent_runner_core::ModelResponse;

use crate::plan::{fixtures::response_text, shape::plan_parts};

pub(super) fn child_args(args: &[Expr]) -> Vec<&Expr> {
    args.iter()
        .filter(|arg| keyword_name(arg).is_none())
        .collect()
}

pub(super) fn keyword_atom<'a>(args: &'a [Expr], name: &str) -> Option<&'a str> {
    keyword_value(args, name).and_then(atom_address)
}

pub(super) fn keyword_value<'a>(args: &'a [Expr], name: &str) -> Option<&'a Expr> {
    args.iter().find_map(|arg| {
        let Expr::Map(entries) = arg else {
            return None;
        };
        let found_name = entries.iter().find_map(|(key, value)| match (key, value) {
            (Expr::Symbol(key), Expr::Symbol(value))
                if key.namespace.is_none() && key.name.as_ref() == "keyword" =>
            {
                Some(value.name.as_ref())
            }
            _ => None,
        })?;
        if found_name != name {
            return None;
        }
        entries.iter().find_map(|(key, value)| match key {
            Expr::Symbol(key) if key.namespace.is_none() && key.name.as_ref() == "value" => {
                Some(value)
            }
            _ => None,
        })
    })
}

pub(super) fn is_slow_fixture(plan: &Expr) -> bool {
    atom_address(plan) == Some("fixture/slow-echo")
}

pub(super) fn verifier_accepts(response: &ModelResponse) -> bool {
    let text = response_text(response);
    text.contains("ok") || text.contains("accept")
}

pub(super) fn request_field_text(expr: &Expr, name: &str) -> Option<String> {
    request_field(expr, name).and_then(|value| match value {
        Expr::String(value) => Some(value.clone()),
        Expr::Symbol(value) => Some(value.name.as_ref().to_owned()),
        _ => None,
    })
}

pub(super) fn request_field<'a>(expr: &'a Expr, name: &str) -> Option<&'a Expr> {
    let Expr::Map(entries) = expr else {
        return None;
    };
    entries.iter().find_map(|(key, value)| match (key, value) {
        (Expr::Symbol(key), value) if key.namespace.is_none() && key.name.as_ref() == name => {
            Some(value)
        }
        _ => None,
    })
}

pub(super) fn branch_id(branch: u64) -> Expr {
    Expr::String(format!("branch-{branch}"))
}

pub(super) use sim_value::build::entry as field;

fn keyword_name(expr: &Expr) -> Option<&str> {
    let Expr::Map(entries) = expr else {
        return None;
    };
    entries.iter().find_map(|(key, value)| match (key, value) {
        (Expr::Symbol(key), Expr::Symbol(name))
            if key.namespace.is_none() && key.name.as_ref() == "keyword" =>
        {
            Some(name.name.as_ref())
        }
        _ => None,
    })
}

fn atom_address(plan: &Expr) -> Option<&str> {
    let Ok(("atom", [Expr::String(address)])) = plan_parts(plan) else {
        return None;
    };
    Some(address)
}