Add a provider for thread-scoped instructions (#44701)

## What changed

- Expose `ThreadInstructionsProvider` through `StartThreadOptions`. Load its snapshot at startup and model-request boundaries, composing it after global instructions and before repository instructions. Empty or blank output clears only the thread contribution.
- Reject thread instructions exceeding 10,000 estimated tokens independently of the repository instruction budget. Allow host-provided instructions without a filesystem source and rename the shared future type to `LoadInstructionsFuture`.
- Retain the provider across warm resumes; require hosts to supply it again for cold resumes and offline forks. Live forks and subagents inherit applied snapshots without inheriting the source thread's provider, including when the parent is unloaded during setup or reload.
- Include thread instructions in guardian reviewer inheritance and reuse decisions.

## Testing

Add coverage for composition and clearing, refresh within an active turn, size rejection before sampling, cancellation-safe refresh, fork and resume behavior, parent eviction, and reviewer reuse invalidation.

GitOrigin-RevId: 7be9a523cbbfd67704067dfd526188dad89a3c88
This commit is contained in:
vkg-oai
2026-09-10 20:09:21 -07:00
committed by Benjamin Carlsson
parent dc55274818
commit a231f681b8
21 changed files with 1303 additions and 153 deletions
+2 -1
View File
@@ -104,6 +104,7 @@ pub use state::ExtensionData;
pub use state::ExtensionDataInit;
pub use turn_admission::TurnStartAdmission;
pub use user_instructions::Instructions;
pub use user_instructions::LoadUserInstructionsFuture;
pub use user_instructions::LoadInstructionsFuture;
pub use user_instructions::LoadedUserInstructions;
pub use user_instructions::ThreadInstructionsProvider;
pub use user_instructions::UserInstructionsProvider;
@@ -5,17 +5,17 @@ use codex_utils_absolute_path::AbsolutePathBuf;
/// Instructions supplied by the host.
///
/// `source` must be an absolute filesystem path because the app-server
/// `instructionSources` API currently exposes instruction sources as
/// `AbsolutePathBuf` values.
/// Filesystem-backed instructions retain their absolute source path for the
/// app-server `instructionSources` API. Other host-provided instructions do
/// not report a filesystem source.
// TODO(anp): Replace the absolute path with a more general instruction-source
// abstraction when non-filesystem providers need first-class attribution.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Instructions {
/// Model-visible instruction text.
pub text: String,
/// Absolute filesystem path reported through `instructionSources`.
pub source: AbsolutePathBuf,
/// Absolute filesystem path reported through `instructionSources`, if any.
pub source: Option<AbsolutePathBuf>,
}
/// Result of loading host-provided user instructions.
@@ -28,10 +28,24 @@ pub struct LoadedUserInstructions {
pub warnings: Vec<String>,
}
/// Future returned by a [`UserInstructionsProvider`].
pub type LoadUserInstructionsFuture<'a> =
/// Future returned by an instruction provider.
pub type LoadInstructionsFuture<'a> =
Pin<Box<dyn Future<Output = LoadedUserInstructions> + Send + 'a>>;
/// Loads host-provided instructions that apply to one root thread.
///
/// These instructions follow the global [`UserInstructionsProvider`] snapshot
/// and precede repository instructions. A result with no instructions or
/// blank instructions clears only the thread-scoped contribution. Core retains
/// the provider and reads it at startup and when capturing model-request context.
/// Implementations own fetching and caching; repeated reads should be cheap and
/// return a coherent snapshot. On a recoverable fetch failure, return the last
/// usable snapshot with warnings rather than an empty result that clears it.
pub trait ThreadInstructionsProvider: Send + Sync {
/// Loads the current snapshot for the provider's root thread.
fn load_thread_instructions(&self) -> LoadInstructionsFuture<'_>;
}
/// Loads global user instructions shared across root threads.
///
/// Core reads this provider at startup and when capturing model-request context.
@@ -40,5 +54,5 @@ pub type LoadUserInstructionsFuture<'a> =
/// while still returning usable fallback instructions when available.
pub trait UserInstructionsProvider: Send + Sync {
/// Loads the current global snapshot for a root runtime.
fn load_user_instructions(&self) -> LoadUserInstructionsFuture<'_>;
fn load_user_instructions(&self) -> LoadInstructionsFuture<'_>;
}