use serde::{Deserialize, Serialize};
use crate::JsonObject;
use crate::output::OutputField;
use crate::schema::{NonEmptyString, RunxSchema};
use std::collections::BTreeMap;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
pub enum ContextEntryVersion {
#[serde(rename = "1")]
V1,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ContextArtifactProducer {
pub skill: NonEmptyString,
pub runner: NonEmptyString,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ContextArtifactMeta {
pub artifact_id: NonEmptyString,
pub run_id: NonEmptyString,
pub step_id: Option<NonEmptyString>,
pub producer: ContextArtifactProducer,
pub created_at: NonEmptyString,
pub hash: NonEmptyString,
pub size_bytes: u64,
pub parent_artifact_id: Option<NonEmptyString>,
pub receipt_id: Option<NonEmptyString>,
pub redacted: bool,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ContextEntry {
#[serde(rename = "type")]
pub entry_type: Option<NonEmptyString>,
pub version: ContextEntryVersion,
pub data: JsonObject,
pub meta: ContextArtifactMeta,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ProvenanceEntry {
pub input: NonEmptyString,
pub output: NonEmptyString,
#[serde(skip_serializing_if = "Option::is_none")]
pub from_step: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub artifact_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub receipt_id: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ProfileFile {
pub root_path: NonEmptyString,
pub path: NonEmptyString,
pub sha256: NonEmptyString,
pub content: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct AgentContextProfiles {
#[serde(skip_serializing_if = "Option::is_none")]
pub memory: Option<ProfileFile>,
#[serde(skip_serializing_if = "Option::is_none")]
pub conventions: Option<ProfileFile>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
pub enum QualityProfileSource {
#[serde(rename = "SKILL.md#quality-profile")]
SkillMd,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct QualityProfile {
pub source: QualityProfileSource,
pub sha256: NonEmptyString,
pub content: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ExecutionLocation {
pub skill_directory: NonEmptyString,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_roots: Option<Vec<NonEmptyString>>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
#[runx_schema(spec_id = "https://runx.ai/spec/agent-context-envelope.schema.json")]
pub struct AgentContextEnvelope {
pub run_id: NonEmptyString,
#[serde(skip_serializing_if = "Option::is_none")]
pub step_id: Option<NonEmptyString>,
pub skill: NonEmptyString,
pub instructions: NonEmptyString,
pub inputs: JsonObject,
pub allowed_tools: Vec<NonEmptyString>,
pub current_context: Vec<ContextEntry>,
pub historical_context: Vec<ContextEntry>,
pub provenance: Vec<ProvenanceEntry>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context: Option<AgentContextProfiles>,
#[serde(skip_serializing_if = "Option::is_none")]
pub voice_profile: Option<ProfileFile>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quality_profile: Option<QualityProfile>,
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_location: Option<ExecutionLocation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output: Option<BTreeMap<String, OutputField>>,
pub trust_boundary: NonEmptyString,
}