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:
Adam Perry @ OpenAI
2026-08-20 06:43:50 +00:00
committed by copyberry
parent da6e68951b
commit f1e06b3865
2 changed files with 40 additions and 77 deletions
@@ -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) => {