mirror of
https://github.com/openai/codex.git
synced 2026-08-23 13:09:46 +00:00
Stream executor capability and skill file reads (#39620)
## What changed - Use `ExecutorFileSystem::read_file_stream` for capability files and executor skill resources regardless of whether filesystem sandboxing is active. - Enforce per-file and bundle size limits incrementally as chunks arrive. - Preserve the existing error for Windows resources when the required filesystem sandbox is unavailable. GitOrigin-RevId: 1a40602a8f913588ec9a6ad7edd2d62eb82436e1
This commit is contained in:
committed by
copyberry
parent
da6e68951b
commit
f1e06b3865
@@ -354,49 +354,32 @@ async fn read_optional_text_file(
|
||||
));
|
||||
return None;
|
||||
}
|
||||
let contents = if sandbox.is_some_and(FileSystemSandboxContext::should_run_in_sandbox) {
|
||||
match file_system.read_file(&path, sandbox).await {
|
||||
Ok(contents) if contents.len() <= MAX_FILE_BYTES && budget.can_add(contents.len()) => {
|
||||
contents
|
||||
}
|
||||
Ok(_) => {
|
||||
warnings.push(format!("capability file {path} exceeded its read limit"));
|
||||
return None;
|
||||
}
|
||||
Err(error) => {
|
||||
warnings.push(format!("failed to read capability file {path}: {error}"));
|
||||
return None;
|
||||
}
|
||||
let mut stream = match file_system.read_file_stream(&path, sandbox).await {
|
||||
Ok(stream) => stream,
|
||||
Err(error) => {
|
||||
warnings.push(format!("failed to read capability file {path}: {error}"));
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
let mut stream = match file_system.read_file_stream(&path, sandbox).await {
|
||||
Ok(stream) => stream,
|
||||
};
|
||||
let mut contents = Vec::with_capacity(size);
|
||||
while let Some(chunk) = stream.next().await {
|
||||
let chunk = match chunk {
|
||||
Ok(chunk) => chunk,
|
||||
Err(error) => {
|
||||
warnings.push(format!("failed to read capability file {path}: {error}"));
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let mut contents = Vec::with_capacity(size);
|
||||
while let Some(chunk) = stream.next().await {
|
||||
let chunk = match chunk {
|
||||
Ok(chunk) => chunk,
|
||||
Err(error) => {
|
||||
warnings.push(format!("failed to read capability file {path}: {error}"));
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let Some(new_len) = contents.len().checked_add(chunk.len()) else {
|
||||
warnings.push(format!("capability file {path} exceeded its read limit"));
|
||||
return None;
|
||||
};
|
||||
if new_len > MAX_FILE_BYTES || !budget.can_add(new_len) {
|
||||
warnings.push(format!("capability file {path} exceeded its read limit"));
|
||||
return None;
|
||||
}
|
||||
contents.extend_from_slice(&chunk);
|
||||
let Some(new_len) = contents.len().checked_add(chunk.len()) else {
|
||||
warnings.push(format!("capability file {path} exceeded its read limit"));
|
||||
return None;
|
||||
};
|
||||
if new_len > MAX_FILE_BYTES || !budget.can_add(new_len) {
|
||||
warnings.push(format!("capability file {path} exceeded its read limit"));
|
||||
return None;
|
||||
}
|
||||
contents
|
||||
};
|
||||
contents.extend_from_slice(&chunk);
|
||||
}
|
||||
let contents = match String::from_utf8(contents) {
|
||||
Ok(contents) => contents,
|
||||
Err(error) => {
|
||||
|
||||
@@ -302,51 +302,31 @@ async fn read_bounded_text(
|
||||
"failed to read executor skill resource {resource}: {err}"
|
||||
))
|
||||
};
|
||||
let contents = if sandbox.is_some_and(FileSystemSandboxContext::should_run_in_sandbox) {
|
||||
if path.infer_path_convention() == Some(PathConvention::Windows)
|
||||
&& sandbox.is_some_and(|context| {
|
||||
context.windows_sandbox_level
|
||||
== codex_protocol::config_types::WindowsSandboxLevel::Disabled
|
||||
})
|
||||
{
|
||||
return Err(SkillProviderError::new(
|
||||
"executor skill resource requires an unavailable filesystem sandbox",
|
||||
));
|
||||
}
|
||||
let metadata = file_system
|
||||
.get_metadata(path, sandbox)
|
||||
.await
|
||||
.map_err(&read_error)?;
|
||||
if metadata.size > MAX_SKILL_RESOURCE_CONTENT_BYTES as u64 {
|
||||
if sandbox.is_some_and(FileSystemSandboxContext::should_run_in_sandbox)
|
||||
&& path.infer_path_convention() == Some(PathConvention::Windows)
|
||||
&& sandbox.is_some_and(|context| {
|
||||
context.windows_sandbox_level
|
||||
== codex_protocol::config_types::WindowsSandboxLevel::Disabled
|
||||
})
|
||||
{
|
||||
return Err(SkillProviderError::new(
|
||||
"executor skill resource requires an unavailable filesystem sandbox",
|
||||
));
|
||||
}
|
||||
|
||||
let mut stream = file_system
|
||||
.read_file_stream(path, sandbox)
|
||||
.await
|
||||
.map_err(&read_error)?;
|
||||
let mut contents = Vec::new();
|
||||
while let Some(chunk) = stream.next().await {
|
||||
let chunk = chunk.map_err(&read_error)?;
|
||||
if contents.len().saturating_add(chunk.len()) > MAX_SKILL_RESOURCE_CONTENT_BYTES {
|
||||
return Err(SkillProviderError::new(format!(
|
||||
"executor skill resource {resource} exceeds {MAX_SKILL_RESOURCE_CONTENT_BYTES} bytes"
|
||||
)));
|
||||
}
|
||||
file_system
|
||||
.read_file(path, sandbox)
|
||||
.await
|
||||
.map_err(&read_error)?
|
||||
} else {
|
||||
let mut stream = file_system
|
||||
.read_file_stream(path, sandbox)
|
||||
.await
|
||||
.map_err(&read_error)?;
|
||||
let mut contents = Vec::new();
|
||||
while let Some(chunk) = stream.next().await {
|
||||
let chunk = chunk.map_err(&read_error)?;
|
||||
if contents.len().saturating_add(chunk.len()) > MAX_SKILL_RESOURCE_CONTENT_BYTES {
|
||||
return Err(SkillProviderError::new(format!(
|
||||
"executor skill resource {resource} exceeds {MAX_SKILL_RESOURCE_CONTENT_BYTES} bytes"
|
||||
)));
|
||||
}
|
||||
contents.extend_from_slice(&chunk);
|
||||
}
|
||||
contents
|
||||
};
|
||||
if contents.len() > MAX_SKILL_RESOURCE_CONTENT_BYTES {
|
||||
return Err(SkillProviderError::new(format!(
|
||||
"executor skill resource {resource} exceeds {MAX_SKILL_RESOURCE_CONTENT_BYTES} bytes"
|
||||
)));
|
||||
contents.extend_from_slice(&chunk);
|
||||
}
|
||||
String::from_utf8(contents).map_err(|_| {
|
||||
SkillProviderError::new(format!(
|
||||
|
||||
Reference in New Issue
Block a user