use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::ContextProviderId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PromptAuthority {
Kernel,
Organization,
Product,
Workspace,
Tool,
Skill,
Session,
UserAddition,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TrustLevel {
Trusted,
Delegated,
Untrusted,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CacheScope {
None,
Run,
Session,
Profile,
Global,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PromptProvenance {
provider_id: ContextProviderId,
source_kind: String,
#[serde(skip_serializing_if = "Option::is_none")]
locator: Option<String>,
}
impl PromptProvenance {
pub fn new(
provider_id: ContextProviderId,
source_kind: impl Into<String>,
locator: Option<String>,
) -> Result<Self, ProvenanceError> {
let source_kind = source_kind.into();
if !valid_source_kind(&source_kind)
|| locator.as_ref().is_some_and(|value| {
value.is_empty() || value.len() > 2048 || value.chars().any(char::is_control)
})
{
return Err(ProvenanceError);
}
Ok(Self {
provider_id,
source_kind,
locator,
})
}
#[must_use]
pub const fn provider_id(&self) -> &ContextProviderId {
&self.provider_id
}
#[must_use]
pub fn source_kind(&self) -> &str {
&self.source_kind
}
#[must_use]
pub fn locator(&self) -> Option<&str> {
self.locator.as_deref()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
#[error("prompt provenance is invalid")]
pub struct ProvenanceError;
fn valid_source_kind(value: &str) -> bool {
let mut bytes = value.bytes();
value.len() <= 128
&& bytes.next().is_some_and(|byte| byte.is_ascii_lowercase())
&& bytes.all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'_')
}