#![warn(missing_docs)]
mod canonical;
mod composition;
mod delta;
mod parse;
mod policy;
mod render;
mod validate;
pub use canonical::{CanonicalError, canonical_json, profile_digest, profile_digests, spec_digest};
pub use composition::{
CompositionError, ProfileReference, merge_profile_values, resolve_composition,
};
pub use delta::{
ApplyError, ApplyOptions, ConflictError, apply_delta, serialize, write_atomically,
};
pub use parse::{OapFormat, ParseError, load, parse};
pub use policy::{
EffectiveTools, PermissionDecision, intersect_tools, narrow_decision, narrow_permission_map,
};
pub use render::{RenderError, RenderOptions, render_system_prompt, substitute_variables};
pub use validate::{escapes_workspace, validate, validate_path};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
pub const OAP_VERSION: &str = "1.0";
pub const SUPPORT_VERSION: &str = "1.0.4";
pub type Document = Map<String, Value>;
pub type AgentProfile = Document;
pub type AgentStateDelta = Document;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Issue {
pub pointer: String,
pub message: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Digests {
pub profile: String,
pub spec: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationReport {
pub kind: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub document: Option<Document>,
pub errors: Vec<Issue>,
pub warnings: Vec<Issue>,
#[serde(skip_serializing_if = "Option::is_none")]
pub digests: Option<Digests>,
pub ok: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Adjustment {
pub field: String,
pub requested: Value,
pub effective: Value,
pub reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeltaApplication {
pub profile: AgentProfile,
pub warnings: Vec<String>,
pub pending_proposals: Vec<Document>,
}
pub(crate) fn object(value: Option<&Value>) -> &Map<String, Value> {
value.and_then(Value::as_object).unwrap_or_else(|| {
static EMPTY: std::sync::LazyLock<Map<String, Value>> = std::sync::LazyLock::new(Map::new);
&EMPTY
})
}
pub(crate) fn strings(value: Option<&Value>) -> Vec<String> {
value
.and_then(Value::as_array)
.into_iter()
.flatten()
.filter_map(Value::as_str)
.map(str::to_owned)
.collect()
}