Define file ref contract for Code Mode

This commit is contained in:
Liang-Ting Jiang
2026-05-13 10:31:54 -07:00
parent 83decfa300
commit 6fd7c23dca
2 changed files with 138 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
use std::fmt;
/// Fully qualified reference to a file-like asset known to Code Mode.
///
/// The scheme tells the file broker which provider owns the asset. The broker
/// should keep provider-specific credentials and bytes out of model-visible
/// arguments while still letting Code Mode pass stable refs between tools.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FileRef {
raw: String,
scheme: FileScheme,
body: String,
}
impl FileRef {
pub fn parse(raw: impl Into<String>) -> Result<Self, FileRefParseError> {
let raw = raw.into();
let Some((scheme, body)) = raw.split_once("://") else {
return Err(FileRefParseError::MissingScheme);
};
if body.is_empty() {
return Err(FileRefParseError::MissingBody);
}
let scheme = FileScheme::parse(scheme)?;
let body = body.to_string();
Ok(Self { raw, scheme, body })
}
pub fn raw(&self) -> &str {
&self.raw
}
pub fn scheme(&self) -> FileScheme {
self.scheme
}
pub fn body(&self) -> &str {
&self.body
}
}
/// Provider family that owns a file ref.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FileScheme {
Env,
Library,
Connector,
Other,
}
impl FileScheme {
fn parse(scheme: &str) -> Result<Self, FileRefParseError> {
if scheme.is_empty() {
return Err(FileRefParseError::MissingScheme);
}
if !scheme
.chars()
.all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '_' || ch == '-')
{
return Err(FileRefParseError::InvalidScheme(scheme.to_string()));
}
Ok(match scheme {
"env" => Self::Env,
"oai_library" => Self::Library,
"connector" => Self::Connector,
_ => Self::Other,
})
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum FileRefParseError {
MissingScheme,
InvalidScheme(String),
MissingBody,
}
impl fmt::Display for FileRefParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::MissingScheme => write!(f, "file ref must start with a provider scheme"),
Self::InvalidScheme(scheme) => write!(f, "invalid file ref scheme `{scheme}`"),
Self::MissingBody => write!(f, "file ref must include a provider-owned path or id"),
}
}
}
impl std::error::Error for FileRefParseError {}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn parses_env_file_ref() {
assert_eq!(
FileRef::parse("env://current/work/report.pdf"),
Ok(FileRef {
raw: "env://current/work/report.pdf".to_string(),
scheme: FileScheme::Env,
body: "current/work/report.pdf".to_string(),
})
);
}
#[test]
fn classifies_known_provider_schemes() {
assert_eq!(
FileRef::parse("oai_library://file_123")
.expect("library ref should parse")
.scheme(),
FileScheme::Library
);
assert_eq!(
FileRef::parse("connector://google_drive/file_123")
.expect("connector ref should parse")
.scheme(),
FileScheme::Connector
);
}
#[test]
fn rejects_ambiguous_refs() {
assert_eq!(
FileRef::parse("report.pdf"),
Err(FileRefParseError::MissingScheme)
);
assert_eq!(
FileRef::parse("env://"),
Err(FileRefParseError::MissingBody)
);
}
}

View File

@@ -3,6 +3,7 @@
mod code_mode;
mod dynamic_tool;
mod file_ref;
mod function_call_error;
mod image_detail;
mod json_schema;
@@ -25,6 +26,9 @@ pub use code_mode::collect_code_mode_tool_definitions;
pub use code_mode::tool_spec_to_code_mode_tool_definition;
pub use codex_protocol::ToolName;
pub use dynamic_tool::parse_dynamic_tool;
pub use file_ref::FileRef;
pub use file_ref::FileRefParseError;
pub use file_ref::FileScheme;
pub use function_call_error::FunctionCallError;
pub use image_detail::can_request_original_image_detail;
pub use image_detail::normalize_output_image_detail;