nanocodex-agent 0.3.0

Owned OpenAI agent lifecycle for Nanocodex
Documentation
use std::{
    path::{Path, PathBuf},
    sync::Arc,
};

use super::agents_md::{load_global_instructions, load_instructions};
use crate::{NanocodexError, Result};

#[derive(Clone, Default)]
pub(crate) struct ContextSourceConfig {
    codex_home: Option<PathBuf>,
}

impl ContextSourceConfig {
    pub(crate) fn set_codex_home(&mut self, codex_home: PathBuf) {
        self.codex_home = Some(codex_home);
    }

    pub(crate) fn codex_home(&self) -> Option<&Path> {
        self.codex_home.as_deref()
    }

    pub(crate) fn build(&self) -> ContextSource {
        ContextSource {
            global_instructions: load_global_instructions(self.codex_home()),
        }
    }
}

#[derive(Clone)]
pub(crate) struct ContextSource {
    global_instructions: Option<Arc<str>>,
}

impl ContextSource {
    pub(crate) fn resolve_workspace(&self, requested: Option<&str>) -> Result<String> {
        let requested = PathBuf::from(requested.unwrap_or("."));
        let resolved = std::fs::canonicalize(&requested).map_err(|source| {
            NanocodexError::ResolveWorkspace {
                path: requested,
                source,
            }
        })?;
        if !resolved.is_dir() {
            return Err(NanocodexError::WorkspaceNotDirectory { path: resolved });
        }
        resolved
            .into_os_string()
            .into_string()
            .map_err(|path| NanocodexError::WorkspaceNotUtf8 {
                path: PathBuf::from(path),
            })
    }

    pub(crate) fn project_instructions(&self, workspace: &str) -> Option<String> {
        load_instructions(Path::new(workspace), self.global_instructions.as_deref())
    }

    pub(crate) fn global_instructions(&self) -> Option<Arc<str>> {
        self.global_instructions.as_ref().map(Arc::clone)
    }

    pub(crate) fn with_fallback_global(mut self, fallback: Option<Arc<str>>) -> Self {
        if self.global_instructions.is_none() {
            self.global_instructions = fallback;
        }
        self
    }
}